core/docs/adr/INDEX-by-domain.md
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

138 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ADR index, keyed by domain
`docs/adr/` holds 312 files under a flat, purely sequential numbering. Sequence
records *when* a decision was made and nothing about *what it governs*, so
answering "which ADRs constrain the serving flag contract?" or "what governs
the register axis?" currently means grepping. Past ~300 files that is how a
decision corpus becomes a write-only archive.
This index is the lightweight fix: a maintained table keyed by capability
domain and cross-referenced by the files each ADR actually governs. It is **not**
a renumbering, and it does not replace `README.md` (which owns the
Master-Blueprint collision reconciliation and the binding non-ADR notes).
## Scope, stated honestly
This index covers the **live serving, telemetry, and governance surfaces** — the
domains a Phase 5 / next-arc session needs to query. It is not a complete index
of all 312 ADRs, and it does not pretend to be: an index asserting coverage it
does not have is worse than none, because it converts "I should grep" into "I
already checked."
**Maintenance rule: index on mint.** Adding a row when you write an ADR is
cheap; back-filling 300 is not. Rows below carry the files each ADR governs so
a reader can jump from a decision to its enforcement site.
---
## Deduction serving (the deduction-serve arc)
| ADR | Decision | Governs |
|---|---|---|
| [0256](./ADR-0256-deduction-serve-earned-license.md) | Deduction serving governed by an **earned** reliability license; flag ratified ON 2026-07-24 | `chat/deduction_serve_license.py`, `chat/data/deduction_serve_ledger.json`, `core/config.py::deduction_serving_enabled` |
| [0257](./ADR-0257-english-clause-argument-band.md) | Band v2-EN — English-clause opaque-atom propositional serving; realizer-guard exemption for quoted templates | `generate/proof_chain/english.py`, `chat/runtime.py` (guard exemption sites) |
| [0258](./ADR-0258-member-chain-band.md) | Band v3-MEM — singular membership + universal premises | `generate/proof_chain/categorical.py` |
| [0259](./ADR-0259-conditional-membership-fusion-band.md) | Band v4-CM — conditional-membership fusion | `generate/proof_chain/cond_member.py` |
| [0260](./ADR-0260-verb-predicate-band.md) | Band v5-VP — verb-predicate arguments | `generate/proof_chain/verb.py` |
| [0261](./ADR-0261-existential-witness-band.md) | Band v6-EX — existential witnesses; anonymous witness never transfers to a named individual | `generate/proof_chain/exist.py` |
Engine underneath all six: `generate/proof_chain/entail.py` (ROBDD tautology
check). Surfaces: `generate/proof_chain/render.py`, `chat/deduction_surface.py`.
## Curriculum serving
| ADR | Decision | Governs |
|---|---|---|
| [0262](./ADR-0262-curriculum-grounded-serving.md) | Exams answered from the ratified curriculum, read OPEN-world; §5 records that curriculum **volume** is the binding constraint (~25× gap) — **conclusion amended by 0264 §4.1** | `chat/curriculum_surface.py`, `chat/curriculum_serve_license.py`, `evals/curriculum_serve/runner.py` |
| [0264](./ADR-0264-negative-curriculum-and-premise-scope.md) | Negatives via a row-level `polarity` field reusing the affirmative connective; premise compilation is query-scoped (superset of the query-atom rows ⇒ verdict-identical). §4.1: the 16-premise cap holds a band to ≤16 entailed cases, so **no curriculum band can earn SERVE** until scoping lands — the blocker is engineering, not content | `teaching/curriculum_premises.py`, `teaching/ratification.py`, `evals/curriculum_serve/oracle.py`, `teaching/domain_chains/*.jsonl` |
| [0265](./ADR-0265-negation-in-the-proposition-graph.md) | A proposition graph must be able to represent **denial**: `GraphNode.negated` threaded intent → graph → step → surface, and clause grammar delegated to its one owner (`render_step`). Fixes a live truth defect — under `realizer_grounded_authority`, "evidence does not support truth" and "evidence supports truth" served **byte-identical** surfaces. Serialized only when True, so no `trace_hash` and no lane pin moves | `generate/graph_planner.py`, `generate/semantic_templates.py`, `generate/realizer.py`, `generate/intent_bridge.py`, `core/cognition/pipeline.py` |
## Reliability licensing and the ledger bridge
| ADR | Decision | Governs |
|---|---|---|
| [0175](./ADR-0175-calibrated-attempt-and-eliminate-learning.md) | Two regimes under wrong=0; θ_SERVE Wilson floor; an engine cannot raise its own bar | `core/reliability_gate.py`, `generate/determine/estimation_license.py` |
| [0263](./ADR-0263-ratified-ledger-bridge.md) | Seal → ratify → SHA-verify → serve-gate, extracted from three instances. **Rule 5** (2026-07-25): absence policy is declared in `CAPABILITY_LEDGERS`, not passed at the call site | `core/ratified_ledger.py`, all three license adapters |
| [0206](./ADR-0206-response-governance-bridge.md) | Response governance bridge (`govern_response` / `shape_surface`) | `generate/determine/` |
## Grounding sources and the epistemic taxonomy
| ADR | Decision | Governs |
|---|---|---|
| [0142](./ADR-0142-epistemic-state-taxonomy.md) | Epistemic state as first-class vocabulary | `core/epistemic_state.py` |
| [0048](./ADR-0048-pack-grounded-surface.md) / [0050](./ADR-0050-pack-grounded-comparison.md) | Pack-grounded cold-start DEFINITION / RECALL / COMPARISON | `chat/pack_grounding.py` |
| [0052](./ADR-0052-teaching-grounded-surface.md) | Teaching-grounded cold-start CAUSE / VERIFICATION | `chat/teaching_grounding.py` |
| [0064](./ADR-0064-cross-pack-teaching-chains.md) | Cross-pack residency + cross-corpus chain lookup for the discovery gate | `teaching/discovery.py` |
The closed set itself lives at `core/epistemic_state.py::GroundingSource`.
Registration is a three-part cross-stack change — see
`docs/specs/runtime_contracts.md` § "Grounding-source registration".
## Register axis and the realizer guard
| ADR | Decision | Governs |
|---|---|---|
| [0069](./ADR-0069-realizer-register-parameter.md) | Realizer register parameter; **invariant C** — register must not move `trace_hash` | `core/cognition/surface_resolution.py`, `core/cognition/pipeline.py` |
| [0071](./ADR-0071-seeded-surface-variation.md) | Seeded surface variation + discourse markers; `pre_decoration_surface` | `chat/register_variation.py` |
| [0075](./ADR-0075-realizer-slot-type-guard.md) | Realizer slot-type guard (C1 coherence floor). Deduction surfaces are **exempt** — quoted templates are not slot-composed articulations (rationale documented at both guard sites) | `chat/runtime.py` (stub + main guard sites) |
| [0077](./ADR-0077-substantive-register-knobs.md) | Substantive register knobs (R6); `register_canonical_surface` | `chat/register_substantive.py` |
## Telemetry, trace, and audit
| ADR | Decision | Governs |
|---|---|---|
| [0039](./ADR-0039-audit-completeness.md) | `TurnVerdicts` bundle, stub-path `TurnEvent`, `hedge_injected` | `chat/runtime.py` |
| [0153](./ADR-0153-turn-event-trace-hash-backstamp.md) | `TurnEvent` `trace_hash` back-stamp (W-020a) | `core/cognition/pipeline.py`, `chat/runtime.py` |
| [0255](./ADR-0255-discovery-yield-baseline-telemetry.md) | Discovery-yield-per-served-turn baseline; fail-closed on a missing baseline | `teaching/discovery_yield.py` |
| [0018](./ADR-0018-tool-use-scope.md) | Typed deterministic operators folded into `trace_hash` | `core/cognition/trace.py` |
`trace_hash` is **not** reconstructable from `TurnEvent` — see
`docs/specs/runtime_contracts.md`. Audit-ledger **R7** (telemetry sink receives
the pre-override event) is open and recorded there.
## Workbench and the cross-stack UI contract
| ADR | Decision | Governs |
|---|---|---|
| [0160](./ADR-0160-core-workbench-v1.md) | Operator/auditor UI before public chat | `workbench/` |
| [0161](./ADR-0161-hitl-async-queue.md) | HITL async queue | `teaching/proposals.py`, `core proposal-queue` CLI |
| [0162](./ADR-0162-workbench-design-system.md) | Design system v1; **§3d** — engine enums bind to UI badges, enforced by a build-time coverage test | `workbench-ui/src/design/`, `workbench-ui/enum-snapshot.json` |
## Teaching, proposals, and review
| ADR | Decision | Governs |
|---|---|---|
| [0057](./ADR-0057-teaching-chain-proposal-review.md) | Teaching-chain proposal + review + replay-equivalence gate | `teaching/proposals.py`, `teaching/review.py`, `teaching/store.py` |
| [0254](./ADR-0254-grounded-open-hedge-arm.md) | Grounded-open hedge arm for the shadow-coherence gate | `chat/runtime.py` |
## Reader arc / math capability
| ADR | Decision | Governs |
|---|---|---|
| [0251](./ADR-0251-reader-arc-recalibration-geometric-normalization-spike-proposal.md) | **Halt bespoke per-case regex work**; clean-base reset. The prohibition that governs every math reader increment | `generate/math_roundtrip.py`, `generate/math_candidate_parser.py` |
Companion evidence: `docs/research/reader-arc-overfit-inventory-2026-07-19.md`,
`docs/research/math-reader-phase-4-1-status-2026-07-24.md` (Phase 4.1 =
complete-with-null-yield).
## Substrate, field, and packs
| ADR | Decision | Governs |
|---|---|---|
| [0180](./ADR-0180-crdt-sharded-vault-concurrency.md) | Delta-CRDT sharded substrate | `core-rs/src/vault.rs`, `engine_state/` |
| [0243](./ADR-0243-wave-field-cognitive-lifecycle-comprehension-reasoning-and-resonant-learning.md) | Wave-field cognitive lifecycle | `field/` |
| [0244](./ADR-0244-wave-field-identity-manifold-and-inalienable-geometric-alignment.md) | Wave-field identity manifold | `persona/`, `chat/runtime.py` |
| [0253](./ADR-0253-master-blueprint-adr-collision-and-dual-pack-boundary.md) | Blueprint collision resolution + dual-pack serve boundary (INV-33) | `packs/` |
---
## Numbering note
The corpus is at ADR-0263 and minted eight ADRs in roughly 48 hours during the
generalization arc. Sequential numbering is fine and should stay — the cost it
imposes is discoverability, which is what this file pays down. ADR-0300 is a
near-term milestone with no structural meaning; do not treat it as one.
The ADR-0206/ADR-0256 numbering collision that had to be resolved in doc form
is the concrete failure this index is meant to make less likely: a domain-keyed
view shows an in-flight number before it is minted twice.