A future operator-gated live run (the M2-analog) is fully rigged and rehearsed
OFFLINE — without one model call, without a key (S4.2-analog, parity row 21;
buildable after K5 + K7). `--live-dry-run` builds everything a real run would
(contracts fail-fast §10 → compose §5 → SDK-client construction → preflight)
and captures the run-config + preflight artifacts, then STOPS before the first
model call. The stop IS the boundary: the loop is never entered, so nothing is
spent (strictly offline, no D6 gate).
- run.py --live-dry-run: requires --outbox + --run-id (the drill's artifacts are
run_id-named), rejected fail-fast before any build. Writes a run_id-named PAIR
to the outbox:
* {run_id}-runconfig.json — comparison-protocol §4 pt 3: model-id per role the
loop calls (proposer/checker, THROUGH resolve_model — the run's own path),
profile, and every cap/parameter. Deliberately NO wall-clock date, so the
bytes stay deterministic (the run's date is stamped at report time, §4 pt 3).
* {run_id}-preflight.json — the captured preflight verdict (clear + refusals).
The drill CAPTURES the preflight result rather than gating the build on it:
exit 0 when clear (rig go-live-ready), non-zero when refused — artifacts
captured and ZERO model calls in EITHER case.
- The client is constructed (the verified key-free SDK premise) but never called;
a call-counting stand-in proves 0 calls. Bytes reuse the deterministic house
JSON writer; run_s10.py/runs/ byte-untouched.
- test_dry_run_loadbearing.py: 7 tests. TWO seams detach-proven RED — the
0-calls stop seam (neutralise the branch → falls to execute_run → the counting
client fires → red) and the capture seam (drop the writes → outbox lacks the
pair → red). Env monkeypatched so the preflight verdict is deterministic
regardless of the operator's ambient shell.
- 514→521 green, golden byte-exact, full gate clean (ruff+format+mypy strict,
24 src files). README: test-count sync ×2 + run.py drill note + load-bearing
mention. IKKE-scope (held): the actual live run (M2-analog, operator) and any
change to preflight/outbox.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
Everything that CAN be validated WITHOUT a model call is validated BEFORE the
operator pays for one (S4.1-analog, SDK-native — Foundry-auth is MAF-specific,
not mirrored). The preflight IS the boundary: it never calls query(), never
validates a credential VALUE online, never touches the network. It returns a
list of structured, actionable Refusals; the CLI exits non-zero on any, so a
broken config stops cheaply instead of on the first billed call.
- preflight.py: run_preflight + `python -m …preflight --profile anthropic`.
Four offline checks:
* credential — ANTHROPIC_API_KEY set + not a placeholder form (the value is
NEVER checked online, only presence, §1); the bundled CLI's own
CLAUDE_CODE_OAUTH_TOKEN also satisfies it (run_s10 relies on it — refusing
would be a false alarm).
* model_map — the requested profile exists and every id it resolves to,
THROUGH resolve_model (so the default fall-through is covered), is real,
not a placeholder left in config.
* sdk — claude_agent_sdk imports (a missing install is a structured refusal
naming `uv sync`, never an ImportError out of the preflight), the run-path
symbols exist, and the bundled Claude Code CLI is present on disk — located
OFFLINE via the SDK package's own files, mirroring the SDK's _find_cli
order (bundled first, then a claude on PATH). Verified against installed
0.2.120 (bundled binary present; the STATE 0.2.110 note was stale).
* termination — the §8 stop contract constructs with positive caps and the
per-call USD belt is positive.
- tests/test_preflight.py: credential contract, placeholder detector, model_map
incl. unknown-profile-without-raising, SDK + bundled-CLI offline probe (with a
monkeypatched missing-SDK refusal), termination, run_preflight aggregation,
CLI both paths, and the offline guards (no network import, no query() call —
AST-based so prose stays green). THREE seams detach-proven RED: credential
branch, placeholder model-id guard, no-network grep-guard.
478→514 green, golden byte-exact, full gate clean (ruff+format+mypy strict,
24 src files), run_s10.py/runs/ byte-untouched. README test-count sync ×2 +
preflight.py module note + load-bearing mention. IKKE-scope (held): the actual
API call (ALDRI — the preflight IS the boundary) and Foundry/Azure auth.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
Before ANY spend the operator sees a deterministic UPPER-BOUND USD estimate
for a (portfolio-)run — a what-if over the models in model_map.json (Claude
models) × effort levels (S3.6-analog, D-I pkt. 3 MUST-krav). No network, no
model call, no key: pure config arithmetic (bound by an import-purity test,
mirroring okf.py).
- contracts.py: ModelPriceContract (usd_per_mtok > 0 + REQUIRED source +
source_date so a stale rate is visible, never silent, §1) + PricingContract
(non-empty; no hardcoded fallback rate) + load_pricing/_bundled_pricing.
- data/pricing.example.json: per-Mtok rate per model id, each with source+date.
Example rates are Anthropic's OUTPUT price (the higher rate) so the whole cap
billed at that single rate can only overstate — the figure is marked ESTIMAT.
Covers the model model_map configures, so the default path runs green.
- costsim.py: estimate_costs (n_projects × cap × effort_factor tokens at the
per-Mtok rate; a model with no price fails fast "missing price for <id>",
never a guess) + render_estimate + `python -m …costsim`. Effort factors are
a coarse modeling weight (not prices) — max effort = full cap = the true
upper bound. No price literal anywhere (grep-guard proves it).
- tests/test_costsim.py: schema fail-fast, missing-price fail-fast, scales with
model × effort + reproducible, grep-guard, import purity, bundled-example +
CLI offline smoke. Three seams detach-proven RED (effort factor, price guard,
price literal).
462→478 green, golden byte-exact, full gate clean (ruff+format+mypy strict,
23 src files), run_s10.py/runs/ byte-untouched. README test-count sync ×2 +
costsim.py module note. CLI run-total-cap wiring stays out of scope (planen
lists 4 files); the mechanism is complete and proven load-bearing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
Add a pre-call USD belt on top of the post-charge token/round meter (§8),
so no future live run can loop past its run budget. Belt-and-braces above
the SDK's per-call max_budget_usd cap.
- budget.py: optional run-total `max_cost_usd` on BudgetMeter (fail-fast on
non-positive, §10) + `guard_before_call(spent_usd)` raising the same
structured stop event (BudgetKind widened with "cost_usd"; limit/observed
→ float). Reaching the cap exactly does not stop; crossing it does
(mirrors the token cap).
- loop.py: `_guarded_complete` helper reads the client's accumulated
total_cost_usd (0.0 for scripted clients) and guards BEFORE every
client.complete; all three call sites routed through it — one detach point.
- sdk_client.py: total_cost_usd already exposed/accumulated — untouched.
- tests/test_budget.py: meter-level cap tests + load-bearing loop-wiring
test (counting client; detach the guard → unguarded loop runs to the round
cap → kind "rounds" not "cost_usd" → red).
457→462 green, golden byte-exact, full gate clean (ruff+format+mypy strict,
22 src files), run_s10.py/runs/ byte-untouched. README test-count sync ×2 +
budget.py belt note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
S2.1-analog: each completed run persists a run_id-named proposal/outcome pair
to the outbox — the system's OWN output layer (the role split §3 Step 7 governs
the inbox and wiki, not this). The outcome carries outcome type + figures, the
two §9 falsifiers mirrored verbatim from the RunResult, the provenance stamp,
and verdict_id — minted the SAME way inbox.py mints an expert verdict's id
(mint_verdict_id over the proposal's candidate features), so a later inbox
verdict about the same candidate joins by id (the K9 key assumption, pinned
here in test and reused there).
New outbox.py reuses artifacts' deterministic house JSON writer (sorted keys /
indent 2 / LF) — same input + same run_id => byte-identical files — and never
touches the S10 artifacts.py fasit formats. run.py grows optional
--outbox/--run-id; run_id is REQUIRED when the outbox is set (no wall-clock
default — a timestamp would break determinism) and is fail-fasted at the CLI
BEFORE any client/spend. A budget stop has no proposal, so it writes no pair.
New test_outbox_loadbearing.py (14): unit (pair, verdict_id join key on both
outcome types, percentiles-vs-reason, verbatim falsifiers, provenance,
round-trip, byte-determinism, run_id fail-fast) + wiring (entrance writes the
pair; no-outbox control; --outbox-without-run-id fails fast before spend).
Detach-proved: drop the persist_outbox call in execute_run -> wiring test RED.
443->457 green, golden byte-exact (13/13), run_s10.py/runs/ untouched, full
gate clean (ruff+format+mypy strict). README synced (count + module + seam).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
navigate_bundle's out-of-bundle filter drops every '/'- and '\'-bearing
target before resolution, but a NUL-byte target carries no path separator
and slipped through to (bundle_dir / target).resolve(), which raises
ValueError: embedded null character — propagating instead of being skipped.
method-spec §72 requires a broken cross-link to be tolerated (skipped,
never raised). Wrap resolve/is_file in `except ValueError: continue`;
parse_concept_file stays outside the guard so malformed concept files
still raise.
Load-bearing test drives the first dangerous target THROUGH the filter
into resolution; detach-proved RED (ValueError propagates) when the guard
is removed. Closes the nullbyte item reported OPEN in OKF trinn E.
442→443 green, golden byte-exact, full gate clean (ruff+format+mypy strict).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
A single VerdictStore threaded through run_portfolio: a verdict available when
project k composes survives into project k+1's fold (method-spec §5 cross-project
threading). The optional verdict_dir is the portfolio-level expert inbox, read
before each fold (role split §3 Step 7 — the portfolio never writes a run's own
verdict back; §1/§6 — no self-contamination, only expert/seed verdicts cross).
compose_run_context gains an optional passed-in store (None = fresh; every
existing caller composes exactly as before).
Load-bearing (tests/test_portfolio_learning_loadbearing.py), 2 detach proofs +
control + §4.2 idempotency:
- cross-project threading: project 1's bundle seed survives into project 2's
prompt via the shared store; detach (compose ignores the passed-in store,
always fresh) -> red.
- portfolio inbox fold: a verdict_dir marker reaches the project's fold; detach
(drop the run_portfolio merge) -> red; control (no verdict_dir) -> marker absent.
- double-merge idempotency: a verdict merged before every project folds exactly
once (first-write-wins on id).
437->442 green, golden byte-exact, full gate clean (ruff + format + mypy strict).
run_s10.py and runs/ byte-untouched. README synced (test count, portfolio block,
load-bearing list). K2 re-entrancy test stays green — the shared store threads
verdict fold lines only, never bundle context markers.
[skip-docs]: no invariant changed (CLAUDE.md untouched); the run_portfolio and
compose_run_context docstrings + README carry the doc need.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
New portfolio.py: run_portfolio drives N projects sequentially from a
schema-validated reference config, composing each project's §5 context
(merge inbox -> seed -> fold) and running the loop core UNCHANGED per
project, collecting one typed result per project IN CONFIG ORDER. This is
the run path MAF got in its Fase 1 and D7 never had — the prior entrances
(run.py, run_s10.py) drive a single bundle. PortfolioResult holds
per-project results tagged with the config project_id.
Re-entrancy (§3 Step 3): each project composes its OWN context inside the
loop, never a hoisted shared one, so nothing survives one project into the
next except the explicitly shared mutable state — the §8 budget meter, a
portfolio-wide cap. Failure policy is a STACK-LOCAL choice until D-D: the
default RAISES (today everything is thrown); K18 flips it to
collect-and-continue when the D-D wave model lands.
New config contract in contracts.py: ReferenceProjectContract (project_id +
required non-empty bundle_dir + optional inbox_dir) + ReferenceProjectsContract,
loaded fail-fast by load_reference_projects (§10) — a project without a
bundle path is refused before any run. New data/reference_projects.json
example (shape-validated, never executed by the suite). New repo-local
mini-bundle fixture under tests/data/ (a distinct second project, VFD-retrofit
— ALDRI in shared/).
Two detach proofs delivered: drop the bundle_dir Field requirement -> a run
starts on the invalid config and only crashes mid-run -> the fail-fast test
goes red; hoist the per-project composition out of the loop -> project 2 runs
on project 1's context and the VFD marker never reaches its prompt -> the
re-entrancy test goes red. 11 new tests (test_portfolio.py 5 +
test_contracts.py TestReferenceProjects 6). 426 -> 437 tests, golden
byte-exact, full gate clean (ruff + format + mypy strict). README synced
(test count + a Run layer module block).
[skip-docs] — README documents the new module; CLAUDE.md holds invariants
(rules/commands) only, and K2 adds no new invariant, command, or convention.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
Pin dae0bd1a -> v0.3.1 (=692f2df) on the public Forgejo mirror; uv.lock pins
the exact commit behind the tag.
- Drop the mypy override: the library ships py.typed from v0.2.0, so strict
mode now follows its real types instead of follow_untyped_imports.
- Migrate 8 library-error assertions from pytest.raises(match=...) to
exc.value.code — message text is explicitly unstable from v0.3.0, the
codes are the stability contract.
- Fix a real breakage the bump surfaced: IngestResult gained a required
`stamp` field (d3a3bcc), which the delegation fake did not construct.
- The read-only SQL test loses resolution under the code contract
(`sql_failed` is generic), so it now proves read-onlyness by effect —
the write never lands — instead of by message wording.
- Correct the guard plan: G1's persist-gate anchor (ingest.py:372-387) died
with the 2026-07-16 adoption. Door A is ungated by the library's own
README, so gating stays our responsibility at the call site.
Verified: 426 tests green, golden output byte-exact unchanged, full gate
clean (ruff + format + mypy strict).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RmNAgbRXUgvoSKxVK4Bevv
New ledger.py: typed SavingsLedger; realize is fail-closed on an APPROVED
FeedbackContract + a named expert + an explicit timestamp (the §6 determinism
rule — no wall-clock default). The sum key is DIMENSION-FREE (the dimension
label is annotation only and never participates in the mint), so the same
realized saving surfaced via two dimensions lands in one first-write-wins
slot and is never double-counted. Deterministic JSON persistence
(sort_keys, indent 2, LF, trailing newline), schema-validated on load.
New goals.py: GoalContract (absolute target, hard/soft, fail-fast §10).
A hard goal reached raises GoalReached, a structured stop event carrying
target + observed — never a silent stop; soft flags without stopping.
The percent-goal baseline is D-E-gated: the field is reserved and
construction refuses with an explicit NotImplementedError.
Semantics are marked STACK-LOCAL in the docstrings — mirrored from the MAF
plan's capability description, never from MAF code; format shareability
stays a proposed decision point in the brief.
Two detach proofs delivered (decision gate removed -> red; dimension into
the key mint -> the double-counting test red). 400 -> 426 tests; README
synced (test count + a Value layer module block).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scripted two-run driver over the run.py composition: run A -> persona verdict
(shared skill artifact) -> §6 promotion gate -> run B on a fresh store. The
marker crosses runs via the promoted wiki layer ONLY - run B reads no inbox,
a rejected verdict is refused fail-closed and its marker never crosses.
Two detach proofs delivered (promotion step removed -> red; verdict exclusion
in bundle_context removed -> red via the '## verdict' section anchor).
Known-limitation note (C-F5, deferred to C3.2): a persona verdict over the
bundle seed's own candidate mints the seed's §4.2 id and is silently shadowed
by first-write-wins; the test has run A propose a distinct candidate.
395 -> 400 tests; README synced (test count + the S10 section now reflects
that D7 has its own scripted closed-loop proof).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- run.py: compose_run_context (§5: merge inbox -> seed -> fold, read-only on
the inbox) + execute_run (§8 meter, artifacts persisted on BOTH outcomes,
structured exit 3 on budget stop) + thin CLI (python -m ..run). The model
client is injected; only default_client_factory constructs the SDK client
(wired, never executed by the suite). The navigated docs dir comes from the
validated startup contract (resolves review OBS-2 on the shippable path;
run_s10.py stays byte-frozen fasit -> won't-fix there).
- test_run_entrance_loadbearing.py: inbox verdict reaches the composed
context (detach-proven: merge dropped -> red), empty/missing-inbox
controls, read-only inbox byte-proof, R-10 budget-stop binding via the NEW
entrance (detach-proven: stop persistence dropped -> red), happy path
through the CLI with the inbox signal surviving the chain, SDK-wiring test.
- test_ingest_adoption.py (K2.9): the two library guarantees the consumer
relies on, bound through the seam — empty CSV -> typed SourceError with NO
partial bundle on disk; non-SELECT SQL -> SourceError 'returned no columns'
(behavior verified empirically against pin dae0bd1a before binding).
- README: inbox section now points at the shippable entrance; run.py added
to the run layer; stale test count 265 -> 395.
386 -> 395 tests, full gate green (pytest, ruff check+format, mypy strict);
goldens unchanged; runs/s10 and run_s10.py untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the local 391-line ingest implementation with a thin adapter over
the shared llm-ingestion-okf library (git-pinned dae0bd1a via Forgejo,
tool.uv.sources). The materialize() signature is preserved; error types are
now the library's typed hierarchy rooted in IngestError, re-exported from
the consumer seam.
- tests/test_ingest_adoption.py: new load-bearing seam tests (delegation,
offline invariant — allow_network is never passed, error contract),
detach-proven red twice.
- Golden suites (file + sql) pass UNCHANGED — byte-exact behaviour proven
against the repo-local fixtures.
- 6 test files migrated to the library error hierarchy; escaping/typed-cell
unit tests dropped (byte-bound by the ingest-edge.md golden, unit-owned by
the library's own 189-test suite). Provenance stamp now asserted
independently from the §5 rule.
- mypy override follow_untyped_imports for llm_ingestion_okf (no py.typed
upstream yet — reported as a finding).
Suite: 386 passed; ruff + format + mypy --strict clean; shared/, examples/,
runs/s10/ and run_s10.py byte-untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- File-layer decision vocabulary (§4.2 set) with SKIP semantics — an unknown
decision never reaches the store (C-F7, the review's run proof is the fixture)
- Fail-fast caps (max_files / max_rationale_chars) via InboxLimitError raised
OUTSIDE the tolerant try — a cap breach is never swallowed as a skip
- R-6 id grammar (mirrors ingest _ID_RE) as a pydantic pattern on
VerdictDocument.id AND re-checked in write_verdict, since model_copy(update=)
bypasses model validation — traversal ids can no longer write outside the inbox
- promotion._filename_token: any sanitised id maps to a content hash — 'e/vil'
can no longer clobber the distinct id 'evil' (restarbeid-funn 2)
- SDK pinned >=0.2.111,<0.3 + version guard test naming the sdk_client.py
attribute premises; resolved 0.2.120, all premises re-verified against it
- sdk_client read loop bound offline with REAL SDK message types (R-4/R-5):
text aggregation, error fail-paths, usage/cost extraction, _total_tokens
fail-closed, non-positive budget guard
- test_sdk_isolation comment no longer claims the --system-prompt ""
serialization the test body does not bind (honesty rule §1)
Guard-G2 assessment (guard-plan §4): the allowlist + caps + id grammar landed
here are G2's necessary part; an optional scan_output depth pass over
rationale (still a verbatim prose channel into the fold prompt, R-9) remains
relevant as a later additive session — the trigger picture is unchanged.
4 detach proofs red → restored green. Full gate: 389 passed (365→389),
ruff+format+mypy clean; golden + shared/ + runs/s10/ byte-untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IR schema now refuses non-finite numbers (allow_inf_nan=False on quantity/
unit_cost/claimed_saving_nok) and non-finite or negative assumption-band
endpoints; json.loads accepts the bare Infinity literal, so the bundle seam
is tested directly. ModelMapContract rejects empty-string model ids
(min_length=1). check_turn_safety_net documented as a deliberately
unreachable belt under the range-bound debate loop.
18 new tests; detach-proven (re-allow inf/nan -> 5 red, drop min_length ->
2 red). Full gate: 365 passed, ruff/format/mypy clean; golden untouched.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Presence-only guard over shared/method-spec.md, mirroring the ingest-spec
guard: file presence, structure markers (##1–##12, Step 1–8, MUST),
framework-neutrality (same forbidden-toolkit list), and §12 coverage of
all 31 consumed contract fields — scoped to the §12 block in backticked
form so a pure table-row removal detaches (precision lesson from the
ingest guard's detach spot-check). Red-proofs (a: missing file, b:
injected toolkit name, c: removed §12 field) run parametrized against a
mutated copy in tmp_path, never against shared/.
Full gate green: 347 passed, ruff + format + mypy clean; no src changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Docs-only program-avslutning for ingest-laget (D7-stacken). Bygget fra
commons-spec + eget repo alene — MAF-koden kun eksistens-bekreftet (I6-gate),
aldri lest/reverse-engineert.
- README: ingest-seksjon (file/CSV + sql/sqlite RO) som post-S10-tillegg;
testtall 187 -> 265; HTTP/MCP kun peker (D7 har ingen HTTP-konnektor).
- docs/extending.md (ny): hvordan ingest-laget virker + hvordan legge til en
kildetype; HTTP/MCP som ærlig extension-point-peker (spec §4, MAF I6-demo,
create_sdk_mcp_server som ubygd vehikkel — brukt ingen steder i src/).
- docs/2026-07-04-I7-brief.md + -statusrapport.md: I7-brief + D7-lokal
statusrapport m/ verifiseringslogg. Kryss-stack-kriteriet peker til
MAF-programrapporten.
Ærlighetsregelen (method-spec §1): ingen artefakt påstår HTTP/MCP-støtte i D7
eller live-kilde-integrasjon. Grep-sjekk mot overpåstand ren.
Verifisering: 265 passed uten nøkkel/nettverk · ruff/mypy rene.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7nuUMUyWB9viiBjz8Bo7R
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
Status, seam-by-seam architecture, load-bearing test map, the executed S10
live run with committed artifacts, and the offline-suite invariant.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
Re-kjøring etter post-mortem-fiksene: exit 0, validator=validated,
checker=approve, 2/12 runder, 36 791/150 000 tokens, kost $0.127514
(Haiku 4.5). Artefakter (proposal, provenance med §9-citations,
run_result, usage) committet som bevis på programmets ene live-kjøring
(D6) og som input til S11.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
Transkript-analyse av den stoppede live-kjøringen (10 kall, 162 250 tokens,
$0.331506): konfig-lekkasjen (setting_sources=None laster ALLE filsystem-
settings) injiserte operatørens Claude-konfig i hvert kall — ~10-15k uncachede
tokens, en påtvunget bekreftelses-preamble som gjorde ren-JSON-svar umulige,
og en checker kapret av lekkede instrukser (debatt konvergerte aldri).
- persist_stop_artifacts: stopp-event verbatim + usage/kost persisteres ALLTID
ved BudgetExceeded (delt usage-shape med fullført-run-stien)
- build_call_options: setting_sources=[] (SDK isolation mode, verifisert mot
installert 0.2.110-kilde), system_prompt=None → tom system-prompt; detach-
bevis via monkeypatchet query
- _generation_prompt: krever ONLY the raw JSON object (fence-innpakning ga
4 fullpris parse-retries)
187/187 uten nøkkel · ruff + mypy --strict rene · tre detach-bevis RØDE → grønn
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
Spec §3 steps 2–5 + §8, TDD-ed offline (scripted, honesty-marked stand-in):
- budget.py: BudgetMeter over TerminationContract — provider-reported usage
only (missing usage fails closed), structured BudgetExceeded stop event.
- loop.py: ModelClient protocol; blind parse-retry generation (never silent
repair); round-capped debate with turn safety net and mandated VERDICT
line; opt-in-reject checker gate (explicit REJECT overrides a validated
outcome, validator rejection stands); most-recent-reason-verbatim informed
refinement under max_attempts; validator_decision stamped BEFORE override,
checker_decision as its own result field (§9, never conflated).
- 45 new tests (121 total, no API key); four detach proofs run RED and
reverted green: checker override, informed block, surfaced checker output,
stamp-before-override.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
Step 1 of the loop, built from method-spec §3 alone:
- okf.py (pure stdlib): frontmatter parse, deterministic/tolerant/boundary-checked
index navigation, bundle_context rendering with type:verdict exclusion
- experience.py: CandidateFeatures from the IR projection, §4.2 id minting,
structural ranking (0.60·Jaccard + 0.25·type + 0.15·magnitude bucket),
first-write-wins store, bundle seeding with the realization marker,
fold-before-generation (empty retrieval → base unchanged)
Load-bearing (§11), each proved RED on detach: verdict-layer exclusion, fold,
seed learning fields, agent-toolkit import guard. 76/76 without an API key;
ruff + mypy --strict clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
TDD from method-spec alone (§3 Step 4, §7, §9), golden.json as the only
ground truth: ir.py (construction invariants, fail-fast bundle loader),
validator.py (closed-form feasibility bound 0.30·Σ + Monte Carlo seed
20260624/512 samples/inclusive quantiles — reproduces every frozen golden
field; Rejection as a distinct unconsumable type), provenance.py (stamp
mirroring ONLY the deterministic validator). Mutation controls + seed-detach
proof (§11); 45/45 green without an API key; ruff + mypy --strict clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QdSfQdND84oeq2mbjueLTS
Claude Agent SDK verified against official docs + PyPI 2026-07-03 (0.2.110, CLI
bundled, offline import without API key). Contracts mirror method-spec §10/§4.1/§8:
data-source, model-map (per-profile default required), termination (positive caps),
binary feedback decision. TDD: tests written red-first; suite 14/14 green without
any API key; ruff + mypy --strict clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AaQCFnfsh3tfq1VfzdJpoi