Commit graph

5 commits

Author SHA1 Message Date
fae5b22578 test(loadbearing): positive controls for the static-guard half of the sibling-vacuity class
Point 2 of the sweep, enumerated rather than assumed. STATE's total was right and
its distribution was not: 86 hits confirmed (`assert not X` 41 / `== []` 42 /
`== {}` 2 / `== set()` 1), but per file measured `test_cli_paritet` 13 (STATE said
19), `test_preflight` 10 (11), `test_step7` 4 (6).

AST triage split the 86: 55 hits sit in 50 tests whose assertions are ALL
negative; the other 31 already have a positive sibling assert in the same test.

Two negative results worth recording, because they bound the remaining work:

- The `test_preflight` "clears" family (`_check_credentials(...) == []` and
  friends) is NOT vacuous. Each sits beside a sibling in the same class that
  asserts refusals are non-empty, so a no-op checker turns the sibling red.
  Class-level pairing is a real control; these need no change.
- `test_method_spec_loadbearing.py` already models the right pattern for
  detectors — explicit `test_guard_red_when_*` red-proofs against a mutated COPY.

This commit fixes the class that had no control at all: static/AST guards that
assert an absence without ever showing the scanner can detect a presence.

1. TAUTOLOGICAL RED-PROOFS (both spec guards). `test_guard_red_when_spec_missing`
   asserted a file is absent from a fresh `tmp_path` — true by construction of the
   fixture, and it never called the guard it is named for. It would have stayed
   green with `test_spec_is_present` deleted outright. Both now exercise the same
   `_spec_is_present` predicate the guard calls, in both directions.

2. MISSING RED-PROOF. `test_spec_keeps_structure_markers` had none, unlike its
   toolkit and contract-field siblings: with `_STRUCTURE_MARKERS` emptied or
   `_missing_markers` stubbed to `[]` it reported green forever. Added
   `test_guard_red_when_marker_removed`, parametrized over all 21 markers.

3. BLIND IMPORT SCANNERS (costsim x2, okf, preflight, notify). Every one asserted
   `not names & {forbidden}` or `outside == set()` with nothing showing `names`
   was non-empty — an empty scan satisfies them exactly as well as real purity.
   `test_okf_is_pure_stdlib`'s subset check is likewise trivially true of the
   empty set, so it did not guard its neighbour either. Each now asserts a
   known-present module first. The notify guard gets the strongest form
   available: it proves the detector DOES match a network import inside the seam,
   so the matcher itself is shown to work rather than only its silence.

Value-proved, not merely detach-proved. Seven vacuity mutations run against the
NEW tests: all seven RED, each dying on the intended control line. The same
mutations run against the PRE-CHANGE tests (session edits stashed): all five
applicable ones GREEN — blind to the vacuity they were meant to catch. Green
before, red after, same mutation, is the value-proof.

Harness held original bytes in memory, restored in `finally`, sha256-verified
every restore, and checked each run ACTUALLY RAN (a wrong test id yields rc!=0
and mimics red). `git status` clean before and after.

Remaining in the class and NOT closed here: ~45 all-negative tests, mostly CLI
refusal (`calls == []` after a refused invocation) and empty-default
(`missing dir -> []`). Listed in STATE, not silently dropped.

Suite 690 -> 711.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJmse16bEkaSBtvXhncEUc
2026-08-01 20:01:21 +02:00
e70de95afb test(ingest-spec): make the §12 detach-proofs permanent tests
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
2026-07-31 18:35:41 +02:00
e2eb31675d test(ingest-spec): anchor the contract-field rows to §12, not to prose
`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
2026-07-31 18:26:35 +02:00
32640deffc feat(ingest): I5 — SQL D7-speil, bygget fra commons-spec alene
Speiler MAF I4 fra shared/ingest-spec.md alene: manifest → SQL-konnektor →
materialisert OKF-bundle, byte-identisk med den delte golden-fasiten. Gaten
I4→I5 verifisert løst mot ground truth (MAF-commits d7e5f2f/4f45fe6/1b7612b)
før arbeidet startet. Spec byte-identisk delt, ingen spec-endring (I4).

- ingest.py: SqlSource (type: sql, id, connection_ref); ManifestContract.source
  er nå diskriminert union FileSource | SqlSource på type (http/ukjent tag →
  fail-fast). _render_sql_cell (§5 typed: NULL→"", int→decimal, float→korteste
  round-trip, str→verbatim m/ delt _escape_cell, annet→fail — aldri stille
  coercion). _resolve_connection_ref (env-oppslag §4/§8, usatt → fail-fast).
  _read_sql (read-only sqlite file:?mode=ro, ett SELECT, max_rows §8).
  _read_extraction dispatcher på source.type; materialisering/index/replacement
  uendret fra I3.
- examples/ingest-golden-sql/: repo-lokal golden (byte-frossen kopi av I4s fasit).
- Speiltester (I4s load-bearing-sett, gjennom SQL-konnektoren, detach-bevist røde):
  sql-golden byte-fasit + mutasjonskontroller · typed-cell/NULL (NY §I5-søm) ·
  provenance/navigability/verdict-reservasjon/re-ingest-safety · SqlSource-kontrakt/
  typed-rendering/connection_ref/max_rows/read-only · spec-integritet utvidet med
  connection_ref. Stale type:"sql"-avvisningscase erstattet (sql er gyldig post-I5).
- docs/2026-07-04-I5-brief.md: brief + premiss-verifisering.

Suite 265 passed uten nøkkel/nettverk (239 + 26 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 + SQL nå,
HTTP/MCP kun pekere). Dokumentert i docs/2026-07-04-I5-brief.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MM6BWb1hWmJZuXFZ7rjxT
2026-07-04 07:18:59 +02:00
e03bd79876 feat(ingest): I3 — D7-speil av ingest (filkatalog/CSV), bygget fra commons-spec alene
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
2026-07-04 06:12:43 +02:00