* docs: consolidate governance anchors and clean up test registries * refactor(cli): decompose cli into dedicated modules * test: fix broken test baselines and formatting * docs: add domain boundary READMEs for governance anchors * test: update baseline for determination lane * test: fix capability_pass expectation * test: fix CORE_SHOWCASE_SKIP_BUDGET enforcement * chore: cleanup CLI extraction and unreachable code
5.7 KiB
Cognitive-Spine Unification — Deferred RFC
Date: 2026-05-19
Status: Design proposal — NOT implemented. Deferred from the
2026-05-19 fluency push because the change crosses public-API
entrypoints and depends on the SurfaceSelector landing.
Companion RFC: notes/surface_selector_design_2026-05-19.md
Motivation
The 2026-05-19 design review's Finding P0 #2:
The live cognitive spine is fragmented across public entrypoints.
| Entrypoint | Today's spine | Affected by intent fixes? | Affected by pipeline fixes? |
|---|---|---|---|
core chat (REPL) |
ChatRuntime.chat() direct |
✓ yes | ✗ no |
core trace (single turn) |
ChatRuntime.chat() direct |
✓ yes | ✗ no |
core pulse (research) |
scripts/run_pulse.py graph diffusion + GloVe-seeded |
✗ no | ✗ no |
evals/cognition/runner.py |
CognitiveTurnPipeline.run() |
✓ yes | ✓ yes |
evals/cold_start_grounding/runner.py |
ChatRuntime.chat() direct |
✓ yes | ✗ no |
evals/warmed_session_consistency/runner.py |
CognitiveTurnPipeline.run() |
✓ yes | ✓ yes |
evals/deterministic_fluency/runner.py |
ChatRuntime.chat() direct |
✓ yes | ✗ no |
Three separate cognitive spines exist:
ChatRuntime.chat()direct — the simplest path, used bycore chatandcore trace.CognitiveTurnPipeline.run()— wrapsChatRuntime.chat()and adds a graph-realizer override step + transitive walk + frame compose.scripts/run_pulse.py— independent path with GloVe seeding, graph constraint correction, top-k recall.
Effects of fragmentation:
- A fix to the pipeline's override behaviour does not reach the
user via
core chat. - A fix to the runtime reaches the user but is masked under the pipeline-wrapped eval lanes.
- Pulse can "prove" capabilities the user never experiences.
- Tests can be green while user behaviour is broken (and vice versa).
Proposed direction
One canonical chat spine
ChatRuntime.chat() becomes the single canonical entrypoint. The
pipeline's value-add (transitive walks, frame composition) moves
INSIDE the runtime as opt-in passes consulted by the selector:
class ChatRuntime:
def chat(self, text, *, max_tokens=None, mode="full"):
# mode="full" — runtime + pipeline-equivalent passes
# mode="bridge" — runtime only (today's bridge path)
# mode="walk" — walk evidence only (research / introspection)
...
The pipeline becomes a thin convenience wrapper that selects a mode:
class CognitiveTurnPipeline:
def run(self, text, *, max_tokens=None):
# Equivalent to ChatRuntime.chat(text, mode="full").
# Retained as the API the cognition eval harness was built
# against; new code calls ChatRuntime.chat() directly.
...
Pulse demoted to research harness
scripts/run_pulse.py keeps existing for the geometry-research path
but is labeled non-canonical. It does not contribute to "fluent
chat" claims; the eval lanes that rely on it (if any) are renamed.
Single selector consumed everywhere
The SurfaceSelector (companion RFC) is the only path that emits the user-facing surface. All entrypoints route through it:
user input
─▶ ChatRuntime.chat(text, mode=…)
─▶ collect_candidates(intent, subject, field_state, mode)
─▶ SurfaceSelector.select(candidates, context)
─▶ ChatResponse(surface=chosen.surface, …)
core chat, core trace, every eval lane, and the pipeline shim
all call ChatRuntime.chat() with different modes. One emission
point, one telemetry record, one trace hash.
What this fixes
| Today | After |
|---|---|
Pipeline override invisible to core chat |
Pipeline's value-add is opt-in modes inside the runtime; visible everywhere or nowhere |
| Eval-vs-user behaviour drift | Same code path; can't drift |
| Pulse "proves" things the user doesn't see | Pulse explicitly labeled non-canonical |
Tests asserting r.surface == r.walk_surface |
Surface is the selector's output; walk_surface remains audit telemetry |
| Three places to add a fluency surface | One: register a SurfaceProvider |
Sequencing
This RFC is dependent on surface_selector_design_2026-05-19.md.
Land in this order:
- SurfaceSelector + provider registry (the companion RFC)
- Wrap each existing dispatcher branch as a provider
- Re-implement pipeline override as a provider (or remove if the selector handles it via ordering)
- Move
core chattoChatRuntime.chat(mode="full") - Move
core tracetoChatRuntime.chat(mode="full")with trace instrumentation - Audit eval lanes — every lane explicitly declares its mode
- Label
scripts/run_pulse.pyas non-canonical in its docstring and any eval lane that depends on it
What does NOT change
- Pack content (already correct authoring path)
- Teaching chains (already correct authoring path)
- Intent classification (already canonical via
generate.intent) - Telemetry schema (one emitter, one shape)
- Trace-hash stability (intra-session; hashes are still per-run)
Risk register
- Public API stability —
CognitiveTurnPipeline.run()cannot be removed without a deprecation cycle. Migration step is a wrapper, not a removal. - Mode semantics — the three modes (
full/bridge/walk) must be documented indocs/specs/runtime_contracts.mdBEFORE the refactor so users can rely on them. - Eval invariant —
cognitioneval expects pipeline-level behaviour. The wrapper preserves that; verifiable byte-identity on the eval is a hard prerequisite to commit.
When to land
After the SurfaceSelector RFC. Spine unification without the selector would just move the fragmentation; with the selector it collapses the spines onto a single, observable, replayable path.