Commit graph

1 commit

Author SHA1 Message Date
Shay
133a1a3e1c
feat(cognition): compound-intent observability substrate (ADR-0089 Phase C1) (#89)
Closes audit Finding 4 (2026-05-20) — Phase C1.

Pre-fix ``CognitiveTurnPipeline.run()`` called only the single-intent
``classify_intent`` and silently dropped every secondary clause of a
compound prompt like *"What is X and how does it relate to Y?"*.
The graph never saw the second subject, the resolver never saw the
second clause, and the trace recorded only the dominant clause —
with no operator-visible evidence that anything was dropped.

Phase C1 is the **observability substrate** for ADR-0089: the
pipeline now also runs ``classify_compound_intent`` at step 1b and
records every dropped secondary clause on
``CognitiveTurnResult.dropped_compound_clauses``.  The dominant
clause continues to route through the existing single-intent path
exactly as before — surfaces, trace_hashes, and every existing test
remain byte-identical.

Changes:

  * ``CognitiveTurnPipeline.run()`` calls ``classify_compound_intent``
    alongside the existing ``classify_intent`` and computes
    ``dropped_compound_clauses = compound.parts[1:]`` when the
    compound is multi-part.
  * ``CognitiveTurnResult.dropped_compound_clauses:
    tuple[DialogueIntent, ...] = ()`` — empty tuple == single-clause
    turn; len > 0 == operator-visible evidence of dropped secondary
    clauses.

Out of scope (per ADR-0089):

  * Phase C2 (opt-in multi-node graph dispatch + widened trace_hash
    + multi-clause surface) is deliberately scoped to a separate
    PR because it widens ``compute_trace_hash``, the surface
    resolver contract, and ``plan_articulation``.
  * The dominant-clause routing path is unchanged: the audit's
    broken-subject case ("truth, and why does it matter") is *not*
    fixed here — that improvement is Phase C2 scope.

Verification:

  * 4 new tests in ``tests/test_compound_intent_substrate.py``:
      - single-clause prompts record empty
        ``dropped_compound_clauses``
      - AND-joined compound surfaces the secondary clause as a
        DialogueIntent with the right tag (CAUSE for "why does ...")
      - the user-visible surface and trace_hash for a compound prompt
        are byte-identical across two independent runs (no behavior
        change at the truth-path layer)
      - prompts without a recognised connector do not invent a
        secondary clause
  * ``core eval cognition`` — public 100/100/91.7/100, byte-identical
    to the MEMORY baseline.
  * ``core test --suite cognition`` — 120/0/1.
  * ``core test --suite smoke`` — 67/0.
  * ``core test --suite runtime`` — 19/0.
2026-05-20 19:59:38 -07:00