Commit graph

3 commits

Author SHA1 Message Date
Shay
d7499c80b3
feat(intent): normalize confirmation-tag propositions (#45) 2026-05-19 22:55:28 -07:00
Shay
c6b4f1d21e fix(runtime): config-replace + thin API wrappers + stale docstring
Three independent hygiene fixes named in the 2026-05-19 design review.
All small, all observable, none architectural.

1. ``RuntimeConfig`` flag drop on pack_id / frame_pack override
   chat/runtime.py:306-320 used to enumerate fields by hand when
   reconstructing RuntimeConfig under the pack_id / frame_pack
   override path.  The list stopped at ``admissibility_margin`` and
   silently dropped FIVE newer flags: identity_pack, ethics_pack,
   forward_graph_constraint, composed_surface, thread_anaphora.
   Caller side-effect:

     ChatRuntime(pack_id="x", config=RuntimeConfig(composed_surface=True))
       .config.composed_surface == False  # silently lost

   Fix: ``dataclasses.replace(config, input_packs=..., frame_pack=...)``.
   Every field on the dataclass survives by construction; future
   additions never need a synchronized edit on this path.

2. Stale CAUSE / VERIFICATION docstring
   tests/test_intent_classification_extensions.py described a sixth
   runtime-side fix (pack_grounded_surface fallback for
   CAUSE/VERIFICATION) that was considered, reverted, and the file's
   own test classes pin the opposite contract.  Docstring now states
   the doctrine correctly: no fallback, deliberately, so the discovery
   layer can log the teaching-gap signal.

3. Thin convenience wrappers: respond / achat / arespond
   tests/test_achat.py and tests/test_language_pack_runtime.py
   referenced these public methods since 2026-05-14, but they were
   never implemented on ChatRuntime — those 12 tests had been red on
   every full-lane run since the rebase.  Added as thin wrappers:

     respond(text) -> ChatResponse.surface
     achat(text)   -> async wrapper around chat()
     arespond(text)-> async wrapper around respond()

   The async wrappers are deliberately NOT genuinely non-blocking —
   the underlying CPU-bound walk/recall/composition remains sync.
   Docstrings say so explicitly.  Callers needing real concurrency
   should wrap in asyncio.to_thread at the call site; promoting the
   wrappers to true async event-loop integration is a future change
   gated by an actual concurrent caller.

Regression coverage:
  tests/test_runtime_config_passthrough.py — 4 tests
    - all 19 RuntimeConfig fields survive a pack_id override
    - all five newer flags survive a frame_pack override
    - no-override path preserves caller config by identity (no rebuild)
    - the four public methods exist and are callable

Verification:
  44/44 affected tests green (was 12 red pre-fix).
  Cognition eval byte-identical on both splits.
  No surface-format change; this commit is pure plumbing.
2026-05-19 07:04:10 -07:00
Shay
b52e04a72f fix(intent): five conversational definition patterns + polarity-stopword
The 2026-05-19 cumulative live probe surfaced a stark gap: ~52% of
realistic conversational definition prompts ("Define X", "What does
X mean?", "What is to V?", "How does X work?", "What causes X?")
returned ``grounding_source="none"`` *even though every subject
lemma was pack-resident* across the 9 mounted English packs.

Root cause: the bottleneck was intent classification + subject
extraction, not lexicon coverage.  Five patterns either had no rule
or routed to an intent the runtime dispatcher couldn't handle.  The
fluency assessment at
``/Users/kaizenpro/.codex/worktrees/6533/core/notes/fluency_assessment_2026-05-19.md``
named these as Root Cause #1 ("public chat path does not use the
cognitive spine") and Root Cause #3 ("proposition graphs are too
thin").  This commit closes the surface-level half of that gap;
the deeper answer-plan layer (gloss propositions, P3 in the
assessment) is the next step.

Patterns fixed in ``generate/intent.py``:

  1. ``Define X``        — added ``^define\s+`` rule mapping to
                           DEFINITION (placed after ``^what is/are``
                           so multi-word DEFINITION patterns still
                           prefer the question form).
  2. ``What does X mean?`` — was matching TRANSITIVE_QUERY with
                            relation=``mean``.  Now re-routes to
                            DEFINITION inside ``classify_intent`` so
                            ``pack_grounded_surface`` fires on X.
                            Other transitive relations (precede,
                            ground, etc.) remain TRANSITIVE_QUERY.
  3. ``What is to V?``   — added infinitive-marker strip to
                           ``_normalize_subject`` for DEFINITION /
                           RECALL.  ``to`` is gated on intent tag so
                           it never strips a transfer preposition
                           from CAUSE / VERIFICATION.
  4. ``How does X work?`` — added ``_HOW_DOES_X_RE`` (third-person
                            mechanistic-cause).  Distinct from the
                            first-person PROCEDURE rule ("How do I
                            X?").  Verbs: work / function / operate /
                            happen / exist / behave / act / emerge.
  5. ``What causes X?``   — added causative-verb rule (causes /
                            triggers / enables / prevents / drives /
                            produces / induces / yields) routing to
                            CAUSE with X as subject.

Deliberate NON-fix: I considered adding a ``pack_grounded_surface``
fallback in the CAUSE / VERIFICATION dispatcher when no teaching
chain matches the subject.  Reverted on review — that masks the
"would_have_grounded" discovery-candidate signal the teaching
pipeline uses to identify teaching-content gaps (see
``tests/test_discovery_candidates``).  CAUSE on a pack-resident
lemma without a teaching chain stays ``grounding_source=='none'``
so the discovery layer can log the gap honestly.

``chat/pack_grounding.py``:
  Extended ``_CORRECTION_TOPIC_STOPWORDS`` to include polarity
  markers (no / yes / maybe / perhaps / hardly / indeed / surely /
  definitely).  Without this the CORRECTION composer would
  short-circuit on ``no`` from "No, my parent disagrees" and miss
  the topical lemma ``parent``.

Cumulative probe lift (44 realistic conversational prompts):
  BEFORE: pack=16  none=23  oov=4  teaching=1  (52% NONE)
  AFTER:  pack=37  none=2   oov=4  teaching=1   ( 5% NONE)

  The remaining 2 NONE responses are CAUSE-shaped prompts with no
  teaching chain — deliberately preserved as the discovery-gap
  signal described above.

Tests: tests/test_intent_classification_extensions.py — 23 new
tests covering each pattern + the lift invariant.

Verification:
  Cognition eval byte-identical on both splits (100/100/91.7/100
  public, 100/100/83.3/100 holdout).
  All 111 intent-affected tests green:
    test_intent_classification_extensions.py (23)
    test_intent_proposition_graph.py / test_intent_ratifier.py /
    test_intent_subject_extraction.py / test_narrative_example_intents.py
    test_procedure_surface.py
    test_correction_topic_lemma.py
    test_cross_pack_grounding.py (including the polarity-stopword fix)
    test_discovery_candidates.py
    test_contemplation_wiring.py
    test_en_core_polarity_v1_pack.py
2026-05-19 06:12:05 -07:00