Commit graph

14 commits

Author SHA1 Message Date
880f00f305 docs(brief): the plan reference must not be a link only this machine can follow
The repo-standard gate SKIPs a link that leaves the repository — and a SKIP is
"not measured", never a pass. This one left it into `/Users/ktg/repos/...`, so
for every reader but the operator it was a dead click dressed as a citation.

The reference itself is correct and stays: the programme plans deliberately
live in the sibling repo (CLAUDE.md). Only the link form goes, replaced by the
repo name plus the path inside it — which a stranger can act on and this
machine's layout can no longer invalidate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gu3n2PVVnb9fZDCe2wnU1h
2026-08-04 11:55:17 +02:00
ffb0503da3 docs(portfolio): A5 premise corrected — the quantisation POINT is the live divergence
MAF measured their own tree and corrected our claim that they "round one
monetary figure": their projection rounds nothing (value_report.py:48,
0 hits for round()); the one operation is a NOK->ore quantisation at the
ledger edge (ledger.py:204-214, Decimal + ROUND_HALF_UP). Rule 1 as we
wrote it therefore solved a divergence that did not exist and opened one
that did not — it condemned their deliberate, documented quantisation as
"rendering". Adopted their proposed split as rules 1a/1b.

Then measured here, which REFUTED our own first hypothesis: we assumed
float accumulation was the divergence. It is not — 0 of 20 000 random
portfolios diverge on 2-decimal NOK input. The real mechanism is where
quantisation sits relative to summation, and it only wakes on sub-ore
input: 66.4% of totals diverge, worst 6 ore over 28 rows, and a designed
100 x 0.005 case diverges by a factor of 2.

Sub-ore input is reachable in BOTH stacks — neither ir.py:42
(claimed_saving_nok) nor ledger.py:42 (amount_nok) constrains decimals;
both are float = Field(gt=0, allow_inf_nan=False). So two stacks that
both obey 1a+1b can still return different totals on identical input,
which is exactly what A5 exists to close. Hence new rule 1c: the
amendment MUST fix one quantisation point — reject finer-than-ore claims
at the contract edge, or quantise once on the total — and both stacks
must land on the same choice.

Doc-only; no source touched. Suite 627 passed. Nothing patched
unilaterally: shared/ is pull-only and the amendment is not in commons.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 19:58:04 +02:00
457a0f4e91 docs(portfolio): D-A approved in full — D7's proposed amendment text with measured anchors
The operator approved the whole D-A bundle on 2026-07-25: the four spec
corrections (C-F2/C-F3/C-F4/C-F5), brief §7 (the projection contract over the
ledger), and the C-P1 collision resolved by RE-SCOPING semantic retrieval
rather than amending the frozen "structural, never textual" rule.

This is D7's contribution to the text, not the decision itself (that is
protocolled in the main repo's shared queue) and not the amendment (shared/ is
a PULL-ONLY subtree — the text must land in commons and be pulled by both
siblings). Each point carries the verbatim spec anchor it changes, proposed
RFC 2119 wording, and what we MEASURED about compatibility rather than what we
assume.

Two things are stated as open rather than settled, because they are:
- A2 (cost baseline): the golden bundle has no cost-baseline.json, so an
  unconditional requirement would change the fasit bytes for both stacks. Our
  wording requires a baseline only for runs that can spend; if the amendment
  chooses otherwise, the fasit change must be planned in both repos.
- A5 (rounding): the divergence is live — our monetary figures are unrounded,
  MAF rounds one. The proposed rule lands on our current behaviour, which is
  exactly why it cannot be decided here. Neither side patches unilaterally.

Code anchors re-verified against the working tree this session (the ledger fix
earlier today shifted valuereport line numbers), not copied from STATE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 15:38:51 +02:00
3529299335 docs(portfolio): mark the parity table's D7 column as a frozen 2026-07-16 measurement
The "D7-status i dag" column was measured in Steg 0 on 2026-07-16 and never
updated. Twelve build sessions have landed since, so twelve rows still read
"MANGLER" for capabilities that now exist — a later session reading the column
as current would rebuild something already built.

The note names each landed row with its commit (verified against git, not
against STATE's claim), and points at git history + STATE.md as the ground
truth for what exists today. The MAF column and the gate statuses are NOT
stale and remain valid planning input; only the D7 column is pinned to its
measurement date.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 15:27:52 +02:00
bf50d2c977 docs(portfolio): pin parity row 25 to MAF's S5.4 span 878c989..7dab2df
MAF supplied the commit hash we had queued as an open coord question. The row
recorded "hash IKKE oppgitt — spurt"; it now carries the span rather than the
single point so the row stays diffable, per their own suggestion.

Recorded honestly: the hash is verified by MAF against their git and is NOT
independently checkable from here — we do not read MAF src, and a convenient
hash does not lapse that constraint.

The rounding divergence (they round one krone amount, we round none) is now
stated as live-not-disagreement: neither side patches unilaterally before the
commons amendment lands.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 15:09:37 +02:00
8d5554ba3f docs(portfolio): spec-gap §7 i operatør-køen + paritetsrad 24/25 rettet
Coord-runde 2026-07-25, ingen kodeendring (gate urørt: 603 passed, ruff+mypy rene).

- brief §7: projeksjons-kontrakten over hovedboken som spec-gap, meldt uavhengig
  fra BEGGE stacker. MAF-søskenets ordlyd bevart verbatim; våre tre skjønnsvalg
  målt mot kode (runding av kronebeløp: ingen hos oss, én hos dem — reell
  divergens på identiske inndata). Anbefalt inn i D-A-bolken.
- paritetsplan rad 24/25: STALE «Gjenstår i MAF» rettet etter at MAF eksplisitt
  frigav vårt planverk. Rad 25 merket «hash ikke oppgitt — spurt» framfor antatt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 07:41:52 +02:00
da93a68ce7 feat(portfolio): K12 — CLI parity, doc sync, knowledge-base recipe (parity row 24) [skip-docs]
The last ungated build session: the operator now drives the whole build from the
command line, and the documents claim exactly what the code does (§1).

run.py becomes the collecting entrance. Exactly one of --bundle (one project) or
--portfolio (N projects from a schema-validated reference config, with
--verdict-dir as the portfolio-level expert inbox) is required; both and neither
are refused. --goals loads a goal contract and checks it against --ledger's
realized sum BEFORE the first model call: the §8 caps bound spend, the goal bounds
achievement, so a hard target the book already meets stops the run at exit 4
without constructing a client. A soft target reached is a flag and the run
continues; an absent ledger is an empty book, so the goal is still evaluated,
never skipped. The one declared goal also drives --value-report's goal progress —
one contract, never two figures that can disagree.

The portfolio path persists nothing (K3 returns typed results; the outbox names
pairs by run_id, which a portfolio pass has none of). Rather than accept
--out/--outbox/--run-id/--value-report/--inbox/--live-dry-run there and silently
ignore them, the entrance refuses them and says why. run_portfolio is imported
lazily — portfolio.py imports this module, so a module-level import is circular.

Three seams, each detach-proven RED:
- unwire the goal check → the run proceeds and spends → red
- unwire the portfolio branch → the configured projects never run → red
- document a flag no CLI offers → the README honesty grep goes red

That last one is the doc-sync made load-bearing: the test reads README.md,
collects every --flag it documents (excluding third-party dev-tooling lines) and
asserts each exists in the --help of a CLI the README names. The drift it exists
to close was real — README claimed 562 tests, CHANGELOG claimed 265, actual 597.

Docs synced to the code: README gains an operator-CLI section and honest goal/
portfolio descriptions, CHANGELOG is rewritten to what actually shipped, and
docs/oppskrift-kunnskapsbase.md delivers D-H point 1 — the documented team
process for building a knowledge base, with the honest 1–2 week expectation and
every factory-dependent step (verdict translation, demo path) marked NOT BUILT.

597 passed · ruff clean · mypy strict clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
2026-07-25 06:42:52 +02:00
a7e8ffecb8 chore(deps): re-pin llm-ingestion-okf to v0.3.1 + migrate tests to stable error codes
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
2026-07-20 07:22:09 +02:00
d746891f06 docs(review): full-paritet review + sesjonsplanverk + beslutningsbrief (Fable 5 + 6 Opus-agenter)
Operatør-mandat 2026-07-16: full MAF-paritet (D-G pkt. 2). Review-økt, ingen kildekode.

- review-paritet.md: C-serien re-verifisert (alle åpne), 10 nye R-funn. Kjørt-bevist av
  orkestrator: R-2 (Infinity → validates=True, NaN avvist), R-3 (tom CSV krasjer ingest →
  delvis bundle). R-1 = §11-raden «Closed loop» ubundet. 4/4 detach røde i throwaway-kopi;
  SDK-premisser holder mot 0.2.110→0.2.120; model-id gyldig+billigst; docs §1-ærlige.
- sesjonsplan-paritet.md: ERSTATTER 2026-07-10-planen. 35-raders paritetsmatrise (opphevet
  «Overføres IKKE»-lista, re-klassifisert rad for rad). 16 ugatede sesjoner + gatede med
  eksakte utløsere + avhengighetsgraf + binær leveringsklar-sjekkliste.
- beslutningsbrief.md: operatør-køen i klarspråk (D-A+C-P1, amendment, toolkit-§8, D-B,
  + nytt foreslått delt punkt).
- 2026-07-10-sesjonsplan-d7.md: superseded-merket med peker.

Steg 0 verifisert: commons-amendment IKKE landet, okf-toolkit-repo finnes IKKE.
STATE.md er local-only (gitignored) — ikke committet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:36:07 +02:00
b46f32c682 docs(security): llm-ingestion-guard adopsjonsplan — trust-grense-kartlegging + status planned
Fulgte guard-repoets inclusion/adoption-brief. Kartla repoets ingest-flater mot
briefens §7-checklist: ingest file/sql = førstepart (verbatim render, 0 modellkall,
0 egress-call-sites i src); http = dormant untrusted (avvist fail-fast, extending.md);
inbox = kjørt-bevist injeksjonsflate men førstepart + uwiret (C-F7/C-N2). Status: planned.
Ingen wiring/dep lagt til — kun plan + maskinlesbar markørlinje i STATE.md (local-only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 07:40:24 +02:00
3f106fcfd1 docs(review): kryssmodell-review + sesjonsplan-synk mot delt beslutnings-kø D-A–D-E
Fable 5-review av D7-søskenet, speil av MAF-reviewen 2026-07-09: baseline
re-verifisert (265/ruff/mypy), F2/F3/F5/F7-analoger kjørt-bevist, F1/F11
avkreftet i MAF-form, egne funn (method-spec-vakt mangler, Steg-7-inngang,
SDK-versjonsvakt, D-C↔spec-kollisjon), 11/11 detach-eksperimenter røde i
throwaway-kopi. Sesjonsplan: byggbare-nå C1.1/C2.5/C2.0 + D-A-gatede speil
C2.7/C2.8/C3.2/C4.0.
2026-07-10 07:29:35 +02:00
0c42cebf90 docs(ingest): I7 — programavslutning, D7-docs avgrenset til CSV + SQL
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
2026-07-04 20:08:06 +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