W-006 (operator decision: delete): - Remove dormant packs/en/el/grc/he/readback_rules.py (4 files, 0 live production callers). generate/realizer.py superseded the per-language readback path; per [[feedback-cleanup-as-you-find]], superseded code is removed rather than preserved. - Remove _gate_readback from packs/common/validator.py and drop it from the validate_pack_dir gate sequence. Add language to the report dict so the param remains non-vacuous. W-010 (operator decision: intentional token-level): - Amend ADR-0143 with "Vocabulary isolation is intentional" section. Token-level anti-unification derives its own structural vocabulary; importing VocabManifold adds no information at that level. Confirmed intentional by operator review 2026-05-25. W-014 (operator decision: evals-only): - Add deployment-scope note to core/cognition/provenance.py docstring: evals-only infrastructure, no live runtime caller. Confirmed evals-only by operator review 2026-05-25.
172 lines
7.6 KiB
Markdown
172 lines
7.6 KiB
Markdown
# ADR-0143: Teaching-Derived Structural Recognition via Multi-Resolution Anti-Unification
|
|
|
|
**Status:** Accepted
|
|
**Date:** 2026-05-24
|
|
**Scope doc:** [teaching-derived-recognition-scope](./teaching-derived-recognition-scope.md)
|
|
**Related:** ADR-0142 (epistemic state taxonomy), ADR-0144 (PropositionGraph — integration gate)
|
|
|
|
---
|
|
|
|
## Context
|
|
|
|
CORE's recognition path currently uses hand-coded regex patterns that the engine
|
|
neither derived nor can introspect. These patterns store finds rather than
|
|
teaching finding. The thesis requires the engine's capacity to recognize
|
|
proposition structure to emerge from reviewed teaching examples — not from
|
|
hand-authored scaffolding.
|
|
|
|
The recognition scope document (v2, 2026-05-24) evaluated four candidate
|
|
mechanisms and selected **Mechanism D: multi-resolution anti-unification over
|
|
token sequences** as the only option that is simultaneously deterministic,
|
|
exact, structural, introspectable, and well-defined on token sequences. The
|
|
scope committed the spike to a two-phase acceptance test.
|
|
|
|
This ADR records the decision to implement Mechanism D and defines the output
|
|
contract that all recognition work must conform to.
|
|
|
|
## Decision
|
|
|
|
**Adopt multi-resolution anti-unification over token sequences as the
|
|
recognition mechanism.**
|
|
|
|
The recognizer is derived deterministically from a reviewed teaching example
|
|
set. It operates at two resolutions:
|
|
|
|
1. **Chunk level** — anti-unify at noun-phrase / verb-phrase / quantifier-phrase
|
|
chunks. If every chunk resolves with complete feature evidence, emit the
|
|
bundle.
|
|
2. **Word-level fallback** — for any chunk that fails at chunk level, drop to
|
|
word-by-word anti-unification on just that chunk and attempt to lift the
|
|
relevant feature slot.
|
|
|
|
At both resolutions, the recognizer refuses rather than guesses when evidence
|
|
is absent or contradictory. Refusal is the primary signal for what to learn
|
|
next.
|
|
|
|
## Output contract
|
|
|
|
Every recognition output is a `RecognitionOutcome` (defined in
|
|
`recognition/outcome.py`). The contract is frozen; implementers must not
|
|
add alternative output types.
|
|
|
|
```
|
|
RecognitionOutcome:
|
|
state: EVIDENCED | UNDETERMINED | CONTRADICTED | AMBIGUOUS
|
|
proposition: FeatureBundle | None
|
|
refusal_reason: ShapeRefusal | FeatureEvidenceRefusal | FeatureConsistencyRefusal | None
|
|
provenance: RecognitionProvenance
|
|
```
|
|
|
|
**Invariants:**
|
|
- `state == EVIDENCED` → `proposition` is a complete `FeatureBundle` with
|
|
evidence on every feature; `refusal_reason` is `None`.
|
|
- Any refusal state → `proposition` is `None`; `refusal_reason` is a typed
|
|
instance naming exactly what is missing or contradictory.
|
|
- `provenance` is always present. It carries `mechanism`, `teaching_set_id`
|
|
(SHA-256 of the canonical example set), and `resolution_level`.
|
|
|
|
**Epistemic states emitted.** Recognition produces only this subset of the
|
|
ADR-0142 taxonomy: EVIDENCED (admitted), UNDETERMINED (shape refused),
|
|
CONTRADICTED (feature contradiction), AMBIGUOUS (unresolvable ambiguity).
|
|
VERIFIED and DECODED are downstream of substrate cross-reference work and are
|
|
never emitted by the recognizer itself.
|
|
|
|
## Three-layer refusal
|
|
|
|
| Layer | Class | Trigger |
|
|
|---|---|---|
|
|
| 1 — Shape | `ShapeRefusal` | Input does not match any derived pattern |
|
|
| 2 — Feature evidence | `FeatureEvidenceRefusal` | Shape matched; a required feature has no evidence span |
|
|
| 3 — Feature consistency | `FeatureConsistencyRefusal` | Two evidence spans contradict each other on the same feature |
|
|
|
|
Every layer produces a deterministic, typed, introspectable refusal. The engine
|
|
does not approximate or default — it points at exactly which substrate is
|
|
missing.
|
|
|
|
## Feature bundle requirements
|
|
|
|
Every `BoundFeature` in an admitted bundle carries:
|
|
- `name`: the feature dimension (agent, relation, count, unit, polarity,
|
|
modality, tense, intentionality, ...)
|
|
- `value`: the typed feature value (str | int | float)
|
|
- `evidence`: an `EvidenceSpan` (token indices + verbatim text) or a
|
|
`NegativeEvidence` record (for features established by absence, e.g.
|
|
`polarity=affirmative` from the absence of a negator)
|
|
|
|
No silent defaults. If a feature cannot be evidenced, the recognizer refuses
|
|
at Layer 2.
|
|
|
|
## Determinism requirements
|
|
|
|
- `derive_recognizer(examples)` → byte-identical `DerivedRecognizer` on the
|
|
same input across runs.
|
|
- `recognize(recognizer, tokens)` → byte-identical `RecognitionOutcome` on
|
|
the same recognizer and input across runs.
|
|
- `DerivedRecognizer` must be serializable to/from JSON for replay.
|
|
- `teaching_set_id` is SHA-256 of the sorted canonical example token sequences;
|
|
it must be byte-identical across runs on the same examples.
|
|
|
|
## Acceptance test (two-phase spike)
|
|
|
|
### Phase 1 — Mechanism on uniform examples
|
|
|
|
Four teaching examples (all `has`-relation, all affirmative, all actual-
|
|
modality — see scope doc). Derived recognizer must:
|
|
|
|
1. Admit `"A baker has 24 loaves"` with full feature bundle and evidence spans.
|
|
2. Refuse `"John gave 5 apples to Mary"` with `ShapeRefusal` (Layer 1).
|
|
3. Produce byte-identical output on both cases across two runs.
|
|
4. Every feature in the admitted bundle has non-None evidence.
|
|
|
|
Phase 1 pass → Phase 2 is warranted. Phase 1 fail → mechanism is wrong.
|
|
|
|
### Phase 2 — Variation lifting and adversarial robustness
|
|
|
|
Eight teaching examples (varying polarity / modality / tense / intentionality).
|
|
Derived recognizer must:
|
|
|
|
1. Admit three positive variation cases with correct feature bundles.
|
|
2. Refuse five adversarial cases at the correct refusal layer (Layer 2 or 3).
|
|
3. Produce byte-identical output across two runs.
|
|
|
|
Full test cases in scope doc.
|
|
|
|
## What this ADR does NOT commit
|
|
|
|
- **Storage layer.** Where derived recognizers live (pack / vault / substrate
|
|
state) is deferred to the ADR that follows the spike.
|
|
- **Integration into Engine A.** Gated on ADR-0144 (PropositionGraph). Until
|
|
then, the recognizer is a standalone module.
|
|
- **Parsing framework.** Token-sequence anti-unification is the starting point;
|
|
syntactic parse trees are a fallback if token-level fails.
|
|
|
|
## Vocabulary isolation is intentional (W-010)
|
|
|
|
`derive_recognizer()` and `recognize()` operate on raw token sequences and
|
|
taught `FeatureBundle` evidence without consuming `VocabManifold`, pack
|
|
lexicons, or domain namespaces. This is a deliberate design choice, not a
|
|
gap. Anti-unification derives its own structural vocabulary from the teaching
|
|
set; importing pack-resident vocabulary would create a dependency on L3 that
|
|
adds no information at the anti-unification level — the feature bundle carries
|
|
the semantically relevant structure. If a future scope requires
|
|
pack-vocabulary-typed slots (e.g. "subject must be a `logos.*` domain atom"),
|
|
that is a new ADR, not a retrofit of this one.
|
|
|
|
Confirmed intentional by operator review 2026-05-25 (W-010 closure).
|
|
- **Counter-evidence vocabulary.** `"Alleged"`, `"claimed"`, `"(this is a lie)"`
|
|
are refused at Layer 2/3 on first encounter. Teaching-loop consumption of
|
|
those refusals as correction candidates is its own future scope.
|
|
- **Lens-conditional recognition.** How different anchor lenses interact with
|
|
derived recognizers is deferred.
|
|
|
|
## Consequences
|
|
|
|
- All future recognition work targets `RecognitionOutcome`. No alternative
|
|
output contract is permitted without a new ADR.
|
|
- Refusal is first-class. Every refusal carries a typed reason consumable by
|
|
the teaching loop. Silent failure is a bug.
|
|
- The recognizer is not a classifier. It does not assign a proposition type
|
|
directly — type emerges from the feature bundle via a downstream mapping
|
|
that is itself derived from teaching.
|
|
- Integration into the runtime is gated on ADR-0144. Until then, the spike
|
|
lives in `recognition/` as a standalone testable module.
|