# ADR-0142: Epistemic State Taxonomy — First-Class Vocabulary **Status:** Accepted (integration deferred pending ADR-0144) **Date:** 2026-05-24 **Supersedes:** none **Related:** [epistemic-state-taxonomy-scope](./epistemic-state-taxonomy-scope.md), ADR-0021 (teaching safety), ADR-0024 (refusal materialisation), ADR-0144 (PropositionGraph integration — gate for full cross-subsystem wiring) --- ## Context CORE's thesis commits the engine to *decoding* a reality that already is, not generating plausible continuations. Decoding requires the engine to hold propositions in varying degrees of grounding — not "true" vs "false" but a richer vocabulary describing *how* a proposition is currently known and *what evidence* supports that knowing. Without an explicit vocabulary, the engine implicitly caps its epistemic scope at binary admit/refuse. Six subsystem audits (math, vault, language packs, runtime packs, teaching pipeline, cognition pipeline, and chat runtime — 136 total decision points) confirm that the engine already makes implicit epistemic distinctions across all of these subsystems: it distinguishes exact recall from decomposed recall, curated pack data from dynamically composed units, reviewed teaching chains from speculative candidates, and refusals caused by evidence absence from refusals caused by safety/ethics violations. The audits show these distinctions are consistent enough to unify under a single taxonomy. ## Decision Ratify the following 14-state epistemic vocabulary as the engine's first-class epistemic axis. Every proposition the engine reasons about carries exactly one of these states, plus structured provenance (see Provenance Requirements below). | State | Meaning | Primary source | |---|---|---| | **PERCEIVED** | Token/span observed in input; not yet committed to meaning | Raw ingestion | | **EVIDENCED** | Feature lifts from specific input spans bind a proposition | Recognition layer | | **EVIDENCED-INCOMPLETE** | Feature lift succeeded for a sub-span but the proposition is structurally partial — lift did not fail, but no consuming proposition exists yet | Recognition layer — partial structural match | | **VERIFIED** | Cross-checked against ratified knowledge (pack / vault / teaching); consistent | Substrate cross-reference | | **DECODED** | VERIFIED plus replay-equality from input (trace-hash invariant) | Replay machinery | | **DECODED-UNARTICULATED** | Proposition is DECODED internally but surface realization path broke; the answer is correct but cannot be communicated. Must not be classified as `wrong` | Verifier pass + Realizer failure | | **INFERRED** | Derived from DECODED components by a ratified deterministic rule; composite not itself curated | Rule application over DECODED primitives | | **UNVERIFIED-POSSIBLE** | Consistent with verified knowledge but not directly verified; usable provisionally | Default for non-contradicting novel propositions | | **UNVERIFIED-NOVEL** | Not contradicted; introduces structure the engine has not decoded yet; candidate for teaching expansion | OOV refusal pointing at expansion need | | **CONTRADICTED** | Conflicts with verified knowledge; refuse unless this is a ratified correction | Verification failure | | **AMBIGUOUS** | Input could support multiple incompatible propositions; engine cannot choose without more context | Multi-evidence-binding conflict at recognition | | **UNDETERMINED** | Feature lifts could not complete; specific dimensions missing | Recognition-layer refusal | | **SCOPE_BOUNDARY** | Proposition type recognized but outside current capability envelope. Distinct from UNDETERMINED (lift succeeded) and CONTRADICTED (no conflict — engine cannot decode yet) | Capability-envelope check | | **COMPUTATIONALLY_BOUNDED** | Engine cannot determine epistemic status within resource envelope; not AMBIGUOUS, not UNDETERMINED | Search/enumeration resource-limit hit | Plus one meta-state: | **EPISTEMIC_STATE_NEEDED** | None of the existing states fit; engine refuses and surfaces the gap for teaching expansion | Recursive refusal | The meta-state is what makes the vocabulary non-capping. When no existing state fits, the engine refuses with a structured description of the gap; the teaching loop either ratifies a new state or determines an existing one covers the case. ## Companion axis: Normative clearance (orthogonal) Safety and ethics verdicts are **not epistemic states**. They answer a different question: *has this turn's behavior complied with the active constraints?* The two axes are orthogonal — a VERIFIED proposition can violate a safety boundary; an UNDETERMINED proposition can pass every ethics predicate. Every proposition reaching `ChatResponse` or `TurnEvent` carries both axes: | Clearance state | Meaning | |---|---| | **CLEARED** | All active normative constraints (safety + ethics) passed | | **VIOLATED** | At least one constraint breached; audit record written | | **UNASSESSABLE** | Constraint exists but cannot be evaluated at runtime | | **SUPPRESSED** | A refusal commitment fired; proposition replaced with typed refusal before reaching the surface | `normative_detail` carries the violated boundary/commitment IDs when clearance is VIOLATED or SUPPRESSED; empty string otherwise. ## Provenance requirements Every assignment of a state to a proposition must carry structured provenance: - **Source:** which subsystem assigned this state - **Evidence span(s):** which input or knowledge spans supported the assignment - **Transition history:** if the proposition was previously in another state, what evidence caused the transition Provenance is what distinguishes thesis-aligned epistemic tracking from confidence scores. A confidence score is a number; provenance is a trace the engine can replay, audit, and correct. *Full provenance enforcement is deferred to ADR-0144 integration. Phase 3 (this ADR) establishes the vocabulary and wires state labels onto runtime artifacts. Phase 4 (post ADR-0144) adds structured provenance records.* ## What Phase 3 delivers (already landed) The following is implemented and merged: - `core/epistemic_state.py` — `EpistemicState` and `NormativeClearance` enums, `clearance_from_verdicts()`, `epistemic_state_for_grounding_source()`, `normative_detail_from_verdicts()`, `coerce_*` helpers. - `core/physics/identity.py` — `TurnEvent` carries `epistemic_state`, `normative_clearance`, `normative_detail`. - `chat/runtime.py` — `ChatResponse` carries all three fields; both stub and main paths populate them from verdicts and grounding source. - `chat/telemetry.py` — serializes state axes into JSONL turn events. - `language_packs/loader.py` — `UnitEntry` carries `epistemic_state`; curated entries tagged DECODED, composition-rule entries tagged INFERRED. - `vocab/manifold.py` — `add()` accepts `epistemic_state`; `add_transient()` tags words UNVERIFIED_NOVEL; `epistemic_state_for_word()` exposed. - `language_packs/compiler.py` — passes `epistemic_state` through compile, clone, and cached-load paths. - `vault/store.py` — `epistemic_state_for_vault_status()` mapping; `epistemic_state` stamped into metadata on `store()`; recall results expose the field. - Phase 2 bug fixes (PR #219): FALSIFIED/SPECULATIVE explicitly distinguished in `_status_admits`; `mean_pair_score([])` returns NaN; `RealizerError` on verified trace routes to `decoded_unarticulated` outcome; domain contract `present=False` is `valid=True`; `domain_id:unknown` routes to `scope_boundary`. ## What remains gated on ADR-0144 - **Cross-subsystem transition machinery.** How a proposition carries its state and provenance as it moves between subsystems (recognition → verifier → vault) requires the `PropositionGraph` as the carrier. ADR-0144 defines that graph. - **Structured provenance records.** Per-assignment provenance objects (source, span, transition history) add overhead that needs the PropositionGraph as a home before they can be allocated. - **`CognitiveTurnResult.refusal_reason` materialisation.** The field is populated by ChatRuntime (PR #222) but the cognition pipeline does not yet read it back for trace folding. Full wiring is post-ADR-0144. - **State storage layer.** Where states are persisted per-session vs. per-proposition vs. in the vault is an open question (see scope doc Q2). ## Implementation debts to resolve before full cross-subsystem integration From the six-subsystem audit: 1. **Cognition pipeline cold-start PASSTHROUGH** (`pipeline.py:_ratify_intent`) collapses three distinct conditions (no field_state, no vocab, no prompt_versor) into one indistinguishable `PASSTHROUGH` outcome. Extend `RatificationOutcome` to distinguish them. 2. **Chat runtime grounding-source dispatcher** (`runtime.py:831–1012`) does not record which sources were attempted or why each fell through. Six provenance gaps cluster around this site. Add an explicit dispatch trace structure once the PropositionGraph carrier exists. 3. **Teaching pipeline watched-metrics tuple** (`replay.py`) should be a named, versioned `MetricSet` dataclass to survive future metric additions without breaking trace byte-identity. ## Consequences - The vocabulary is non-negotiable going forward. New subsystem work must assign one of these states (or emit EPISTEMIC_STATE_NEEDED) to every proposition it handles. - The normative clearance axis is orthogonal. Safety/ethics machinery must not modify epistemic state and must not be expressed as an epistemic state. - DECODED is the strongest positive state the engine can assign. VERIFIED is one step below it (cross-checked but not yet replay-equal). Nothing stronger than DECODED is defined; the engine does not claim certainty beyond replay equality. - EPISTEMIC_STATE_NEEDED is the escape hatch that keeps the taxonomy from capping the engine's scope. Every EPISTEMIC_STATE_NEEDED emission is a teaching opportunity.