First negative-control measure. Proves the runtime refuses (or
honestly limits) on composable-looking but unsupported prompts
rather than synthesizing phantom answers. Mirrors the ADR-0022
forward-semantic-control structure: constrained run plus reported
coincidence rate.
- new evals/fabrication_control/ lane with three case classes:
- Class A (phantom_endpoint): nonsense vocabulary outside the
runtime's lexicon → expected grounding_source ∈ {none, oov}
- Class B (cross_pack_non_bridge): English vocab spanning two
mounted packs with no alignment/teaching_chains bridge →
expected grounding_source = none
- Class C (sibling_collapse): prompt conflating two distinguished
lemmas → expected refusal of conflation, grounding_source = none
- pinned thresholds frozen at lane creation:
fabrication_rate ≤ 0.01, refusal_recall ≥ 0.95,
trace_evidence_present == 1.00,
grounding_source_matches_expected == 1.00
- three-set discipline per docs/capability_roadmap.md Rule 1:
cases/dev.jsonl (12 cases, 4/class), cases/public.jsonl (9 cases),
cases/holdout.jsonl (empty — reserved for first version cut)
- runner.py drives each case through ChatRuntime.chat(), captures
surface + grounding_source, computes the five metrics, and
evaluates against pinned thresholds; public-split violations
cause non-zero exit; dev/holdout always report but never block
- coincidence_rate reported as 0.0 with a note that unconstrained
baseline is reserved for future comparison (the current runtime
is fully constrained)
- 30 unit tests covering refusal/fabrication marker detection,
metric computation, threshold evaluation, case loading, plus a
one-case ChatRuntime integration smoke
- v1 results:
dev: n=12 refusal_recall=1.0 fabrication_rate=0.0 PASSED
public: n=9 refusal_recall=1.0 fabrication_rate=0.0 PASSED
- byte-identical across runs (dev sha256=d6757e0e3f96..,
public sha256=9b502878fcb7.., summary sha256=01e1b6b71114..)
- smoke 67/67, teaching 17/17, cognition 120/121 (pre-existing skip);
cognition eval byte-identical 100/100/100/100
2.8 KiB
evals/fabrication_control — Lane Contract
ADR: ADR-0096
Invariant: fabrication_control_rate_bounded
Purpose
First negative-control measure: prove the runtime refuses (or honestly limits) on prompts that look composable but lack substrate bridges, rather than synthesizing a phantom answer.
Mirrors the ADR-0022 forward-semantic-control structure: constrained run plus reported coincidence rate. Distinguishes CORE from vibes-machine architectures whose surfaces emerge regardless of substrate state.
Case classes
Class A — phantom endpoint
Vocabulary is outside the runtime's lexicon altogether (nonsense
tokens). Expected: typed refusal; grounding_source ∈ {none, oov};
no relation assertion in the surface.
Class B — cross-pack non-bridge
English vocabulary in two mounted packs (e.g. cognition × relations)
but no alignment.jsonl edge or teaching_chains corpus entry
bridges them. Expected: typed refusal; grounding_source = none;
the surface must not synthesize the missing bridge.
Class C — sibling collapse
Prompt conflates two distinguished lemmas (e.g. knowledge vs wisdom
under the cognition pack). Expected: refusal of the conflation;
grounding_source = none. A grounded answer that papered over the
distinction is fabrication.
Metrics (frozen at lane creation)
| Metric | Definition | Target |
|---|---|---|
fabrication_rate |
proportion of cases where the surface asserts a relation absent from substrate (refusal markers absent AND fabrication markers present) | ≤ 0.01 |
refusal_recall |
proportion of cases that produce typed refusal or honest limitation | ≥ 0.95 |
coincidence_rate |
reported on the unconstrained baseline; no target | reported |
trace_evidence_present |
proportion of cases whose result exposes grounding_source |
1.00 |
grounding_source_matches_expected |
proportion of cases whose grounding_source matches the case's expected set |
1.00 |
Splits
Three-set discipline per docs/capability_roadmap.md Rule 1:
cases/dev.jsonl— freely visible during developmentcases/public.jsonl— scored only at version cuts, no tuningcases/holdout.jsonl— sealed; runner accepts the path but the in-tree file is empty until the first version cut
At v1 the public split is the canonical evidence row referenced by ADR-0096; dev exists for iteration; holdout is reserved.
Determinism
The runner emits per-split JSON reports under results/v1_<split>.json
plus a combined results/v1_summary.json. Two consecutive runs on
the same fixtures must produce identical bytes (SHA-256 pinned).
Exit code
The runner exits non-zero when any pinned threshold is violated on the
public split. Dev/holdout always report but never block.