Commit graph

8 commits

Author SHA1 Message Date
Shay
dccce6a7b9 fix(generate): a proposition graph must be able to represent denial (ADR-0265)
CORE served the affirmative of propositions the user denied. Measured live on
main @ 536d6e55 with realizer_grounded_authority=True:

    "evidence does not support truth" -> 'Evidence is verified: what supports truth.'
    "evidence supports truth"         -> 'Evidence is verified: what supports truth.'

Byte-identical.

Phase 4 (#136) pinned "render_semantic has no negated parameter" as a defect.
Sizing the exposure before acting on it -- the step §7 requires -- showed the
pin was correct and INCOMPLETE. The defect is two drops in series, and the
first is in the graph:

  intent.negated      parsed from the user's words, always has been
  GraphNode           NO FIELD FOR IT  <-- first drop
  ground_graph        rebuilds nodes field-by-field; nothing to carry
  depth enrichment    rebuilds nodes field-by-field; nothing to carry
  plan_articulation   cannot carry what the node does not hold
  realize_semantic    never read step.negated
  render_semantic     no parameter for it                <-- second drop

Five separate constructors, each silently defaulting to the affirmative.

Why every gate was green
------------------------
On the default config the ungrounded realizer emits "...", _is_useful_surface
rejects it, and the runtime echo wins the resolver -- and the echo contains the
user's own "does not". The truth path was correct BY ACCIDENT. ADR-0088 Phase B
grounds the graph first, which is exactly when the realizer's surface becomes
useful enough to win. So the defect sat behind a shipped flag, invisible to
every property-of-one-surface test, because nothing compared a denial to its
assertion.

Delivered
---------
- GraphNode.negated, threaded intent -> graph -> ground -> enrich -> step ->
  surface. Serialized ONLY when True, so every pre-existing as_dict and every
  trace_hash folded from one stays byte-identical -- which is why no lane pin
  moves.
- Clause grammar delegated to its one owner. Four of the eight intent
  "templates" were never frames; they were plain clauses. They now call
  render_step. Writing a second negation implementation in semantic_templates
  was the tempting fix and is rejected: Phase 2A spent a unit giving every
  linguistic fact one owner, and that design rebuilds the disease one level up.
- Frames that keep a finite verb (VERIFICATION, PROCEDURE, COMPARISON) get an
  explicit negated form. RECALL is a speech act with no proposition to deny, so
  it falls back to the clause path rather than drop the denial (ADR-0261 §5.1).

Measured
--------
    delegation on affirmatives          192/192 byte-identical
    serving realizer, all corpora       85/347 -> 109/347   (+24 = the denials)
    feature-bearing bucket              49/214 -> 73/214
    CONTROL (nothing droppable)         33/33  -> 33/33     unchanged
    multi-node (clause joining)         3/100  -> 3/100     unchanged, out of scope
    lane pins                           11/11 byte-identical, none edited

The control staying 33/33 and multi-node staying 3/100 is the evidence that
this moved the denials and nothing else.

The exhaustive control earned its keep immediately
--------------------------------------------------
It found FIVE more intents serving a denial as its own assertion --
TRANSITIVE_QUERY, FRAME_TRANSFER, NARRATIVE, EXAMPLE, DEDUCTION -- because an
intent with no frame fell back to the UNKNOWN *template* (which cannot say
"not") rather than the UNKNOWN *clause* (which can). The default is now the
capable path, so the next intent added inherits correctness. Found by the
control, not by inspection.

Mutation -- every link reverted individually
--------------------------------------------
    baseline                                        19 pass
    graph_from_intent drops intent.negated           8 FAIL
    plan_articulation drops node.negated             6 FAIL
    ground_graph drops it on rebuild                 2 FAIL
    realize_semantic stops passing step.negated      6 FAIL
    unframed intents fall back to the template       1 FAIL
    pipeline depth-enrichment drops it               1 FAIL

The last row was GREEN on the first run -- my fix there was unguarded. That is
what added the structural invariant: every GraphNode(...) built on the serving
path must NAME `negated` or be recorded in an allowlist with a reason. The
defect was five constructors; a per-site test must be written per site, and a
site added without one is invisible. Only recognition/connector.py is exempt
(an EpistemicNode has no polarity to carry).

Four Phase 4 pins are revised, not relaxed -- #136's M2 mutation ("render_semantic
GAINS a negated parameter -> FAIL") has now happened for real, and forced the
deliberate revision it was built to force.

Registered in `smoke` in the same PR that creates it, per the #136 finding that
an unregistered pin runs nowhere.

Still unexpressed, deliberately: quantifier, tense, aspect. NO PRODUCER sets
them anywhere on the serving path, so threading them would be machinery with no
caller. render_step already handles all three the moment a producer exists.

[Verification]: in-worktree on CPython 3.12.13 with `uv sync --locked` --
smoke 641 (was 621), deductive 503, lane pins 11/11 with no pin edited.
2026-07-27 13:08:17 -07:00
Shay
05348e5a79 refactor: consolidate duplicate depth extraction — graph_planner.get_node_depths now delegates to build_node_depths (single source)
Addresses MEDIUM from code-review: eliminates duplication risk between GraphNode method and pure canonical func.
Tests (graph_anti / node_depths) remain green.
2026-07-08 07:21:17 -07:00
Shay
0dbcd63d63 feat: 3lang depth PropGraph unification - phase refinements, wiring, tests + session pickup cleanups/governance
- Complete depth canonical, pack resolver DEPTH_PACKS, pipeline attrs+node_depths+graph_anti, contemplate/pass_manager/contracts propagation (immutable).
- Polish anti_unifier, tests (oov, construction, percent), runtime/chat integration.
- Governance: AGENTS.md updates, docs/README/handoff_template, skills bootstrap, retire handoff.
- Leaves pickup seeds (NEW_SESSION_PROMPT, plan.md, compact) for continuity.
- Spine tests green, 3lang depth visible in ctx for he.

Refs: plan.md, 2026-07-06-compact.md
2026-07-08 07:07:11 -07:00
Shay
c1e723f185 feat: integrate 3-core-language depth into PropositionGraph spine for bidirectional unification
- Add LexicalResolution dataclass + resolve_entry() in chat/pack_resolver.py
  that returns language, root, morphology_id, gloss, semantic_domains from
  he/grc/en packs (lru-cached, first-match, full depth support).

- Extend GraphNode (generate/graph_planner.py) with optional language/root/
  morphology_id fields (defaults preserve all call sites). Update as_dict()
  to include them conditionally. ground_graph() now propagates depth.

- Generalize enrichment in core/cognition/pipeline.py:
  - Per-subject resolution map using depth packs.
  - Enrich all matching nodes before ground (subject→node map).
  - Pass depth alongside recalled_words to ground_graph().

- Consume depth on articulation side:
  - realize_semantic() and render_semantic() now accept/use language+root
    for etymological/Logos framing on Hebrew/Greek nodes (e.g. "אמת (Hebrew
    root: א-מ-ן) is defined as..."). English unchanged.

- Enrich oov_geometric_context with node_depths for future geometric
  anti-unification using roots.

- Extend recognition/connector.py to forward depth from EpistemicNode
  paths into GraphNode.

- Add full Hebrew turn test under realizer_grounded_authority flag.
- Update related tests (semantic realizer, OOV context, surface resolution).
- Cleaned legacy type() hack immediately on discovery (hard-stop rule).

All targeted tests green (52+ in slices), broad relevant suite 581 passed.
Invariants preserved: versor only at owned boundaries, exact recall,
immutable updates, no new legacy parsers. 3 pillars upheld.

Work continues tomorrow from this checkpoint.
2026-07-06 09:01:43 -07:00
Shay
548282fadc
perf(graph): PropositionGraph.topo_order — Kahn's O(N+E) instead of O(N×E) (#92)
Comb pass 2026-05-21 (item 4).

Pre-fix the topological-sort implementation in
``PropositionGraph.topo_order`` had two compounding inefficiencies:

  * ``queue.pop(0)`` on a list is O(N) per pop → O(N²) total
  * The inner ``for e in self.edges`` rescanned all edges on every
    iteration → O(N × E) overall

This is invisible on today's 1–2 node production graphs but would
become a real regression the moment compound-intent multi-node
dispatch (ADR-0089 Phase C2) or the grounded realizer's multi-clause
output (ADR-0088 Phase B follow-up) lands.

Fix: standard Kahn's with a precomputed out-edge adjacency map and
a ``deque`` for the work queue.  O(N + E) overall.  Deterministic
output preserved — the queue is seeded with sorted zero-in-degree
nodes (identical to the pre-fix list sort), and direct-successor
order matches edge-iteration order (identical when edges retain
insertion order).

Pinned by 6 new tests in ``tests/test_graph_topo_order_perf.py``:

  * single-node graph (today's production shape) byte-identical to
    pre-fix output
  * empty graph returns empty tuple
  * chain (A→B→C→D) orders root → leaf
  * diamond (A→B, A→C, B→D, C→D) keeps A first, D last, B/C between
  * three disjoint roots emit in sorted order
  * 100-node chain returns correct full order (would have been
    visibly slow under the O(N²) pre-fix algorithm)

Validation:

  * ``core eval cognition`` byte-identical (public 100/100/91.7/100)
  * ``core test --suite cognition`` 120/0/1
  * ``core test --suite smoke`` 67/0

Comb-pass note: item 15 (GenerationResult.tokens typed tuple but
assigned list) was investigated and turned out to be a Pyright
false positive — ``GenerationResult.__post_init__`` already coerces
to tuple via ``object.__setattr__``.  Contract is enforced at
runtime; only Pyright's static analyser misses the coercion site.
No fix needed.
2026-05-20 20:37:21 -07:00
Shay
fa2712ebd7 feat(realizer): extend to all 13 English v1 constructions
Engineer the deterministic realizer to handle negation, conjunction,
disjunction, embedded clauses, relative clauses, quantification, tense,
and aspect — covering all 13 grammatical-coverage v1 constructions.

- generate/morphology.py: rule-based English inflection (past, participle,
  base form) for seed vocabulary predicates
- generate/templates.py: match-case inflection dispatch for tense/aspect/negation
- generate/graph_planner.py: add CONJUNCTION, DISJUNCTION, COMPLEMENT, RELATIVE
  relations; add grammatical feature fields to ArticulationStep
- generate/realizer.py: compound construction handling via graph edge traversal

grammatical-coverage eval: dev=100%, public v1=100% (from baseline of 24%/19%).
2026-05-16 05:55:49 -07:00
Shay
eb30c75810 feat: Full Proof — surface realizer join, Rust diffusion parity, benchmark harness
Surface realizer join: pulse output_versor → vault recall → ground_graph fills
<pending> obj slots with recalled words → realize_semantic produces deterministic
sentences. PulseResult replaces bare word list. Every intent type surfaces.

Rust backend parity: unitize_f32 (exponential-map with boost/rotation blade
distinction) and graph_diffusion_step now in core-rs. Python dispatches through
algebra.backend, falls back transparently. 37x speedup on 200-step diffusion.

Benchmark harness (core bench): determinism (100% trace stability), latency
(~150ms median), backend speedup, versor closure audit (0 violations across all
intermediate states), convergence proof (41/45 exact, 4 bounded oscillation),
realizer coverage (8/8 intent types).

Proof property tests (31 tests): Rust/Python parity, pulse determinism across
prompts, V3 convergence for 10+ topologies, coupled V4 output validity, realizer
coverage per intent, versor closure at every intermediate step.

CLI: core pulse, core bench, core test --suite pulse, core test --suite proof.
Fix test_correction_pulls_toward_target (diffuse first, then correct).
2026-05-15 17:39:14 -07:00
Shay
8dcc26581a feat: add intent-proposition graph comprehension layer
Implements the dialogue understanding pipeline:
  prompt -> dialogue intent -> proposition graph -> articulation target

New modules:
  - generate/intent.py: rule-based classifier (7 intent tags + UNKNOWN)
  - generate/graph_planner.py: immutable PropositionGraph DAG, topological
    walk to ArticulationTarget with rhetorical moves

Tests cover definition, cause, comparison, correction with prior-turn
linking, and deterministic serialization.
2026-05-14 19:52:57 -07:00