Mirrors the form already solved in test_method_spec_loadbearing.py: every
predicate now takes the spec TEXT as an argument, so last session's four
manual detach measurements become tests in the suite instead of a one-off
spot-check that died with the session.
Red-proofs (mutated COPY in tmp_path, never shared/):
- M1 row removed from §12 -> the field reads as undocumented
- M2 row renamed -> detach-proof is not a value-proof
- M3 §12 heading renamed -> ValueError, fail-closed (no wider fallback)
- M4 anchor degenerates -> the slice guard is red on the whole spec
Measured, not asserted: mutating _cross_check_table to return the whole
text turns 2 tests red; reverting the row assertion to substring-anywhere
turns 14 red. 16 -> 61 tests in this file; suite 638 -> 683.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011t6M7qfsYgpZyNvRySixNj
`assert field in text` over the whole spec was green-but-dead: prose saturates
every field name (§1's honesty rule alone carries `generated: true` twice,
independent of the §12 table), so no amendment dropping a row could turn it red.
Measured: deleting the `generated` row from §12 left the file 15/15 green.
The spec appoints its own anchor — §12 says "completeness is enforced by the
spec-integrity test", and this is that test. The comment above _CONTRACT_FIELDS
already claimed §12; only the assertion did not. Each field must now appear as a
row's FIRST column, so a field named only inside another row's prose fails.
A slice guard comes with it: a `_cross_check_table()` that degenerated into the
full text would restore the dead state silently, so it is asserted to be a slice.
Detach proofs (mutate, run, restore from copy):
M1 §12 `generated` row removed -> RED [generated] only
M2 row renamed to `generated_x` -> RED [generated] only (value proof)
M3 §12 heading renamed -> RED 14/16 (anchor gone, fail-closed)
M4 slice returns whole spec -> RED slice guard; [generated] goes GREEN
again under M1 — the guard is what binds it
Control green, 637 -> 638.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWrLqjkDvUtrGL5VXXe2ip
Speiler MAF I2 fra shared/ingest-spec.md alene: manifest → CSV-konnektor →
materialisert OKF-bundle, byte-identisk med den delte golden-fasiten.
- ingest.py: ManifestContract (pydantic, fail-fast, file-kilde, verdict-reservasjon
§3, id-grammatikk, max_rows), CSV-konnektor (boundary-checked fail-closed),
materialisering (§5-frontmatter eksakt rekkefølge, markdown-tabell m/ escaping,
LF-only, SHA-256 manifest-stamp), index-generering (§6), replacement §3/§5.
- okf.py: _parse_index_entry — tolererer frontmatterløs index (method-spec §3:
index rendres via body = summary, ikke som typet concept-fil). Golden var
spec-konform; D7-okf var strengere enn standarden. Scoped: non-index concept-
filer krever fortsatt type (honesty-test).
- examples/ingest-golden-file/: repo-lokal golden (byte-frossen kopi av I2s fasit).
- Speiltester (I2s load-bearing-sett, alle detach-bevist røde): golden byte-fasit
+ mutasjonskontroller · provenance/navigability/verdict-reservasjon/re-ingest-safety
· kontrakt fail-fast/max_rows/boundary/kollisjon · spec-integritet §11.
- docs/2026-07-04-I3-brief.md: brief + de to operatør-avgjorte beslutningene.
Suite 239 passed uten nøkkel/nettverk (189 + 50 nye) · ruff + mypy --strict rene.
[skip-docs] README + docs/extending.md er bevisst utsatt til I7 per sesjonsplan
(programmet batcher ingest-doc der, avgrenset til det D7 faktisk har — CSV nå,
SQL/HTTP senere). Endringen er dokumentert i docs/2026-07-04-I3-brief.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MM6BWb1hWmJZuXFZ7rjxT