portfolio-optimiser-claude/src/portfolio_optimiser_claude
Kjell Tore Guttormsen a926e4ad46 feat(portfolio): K5 — outbox persistence, run_id-named pairs (parity row 7) [skip-docs]
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
2026-07-23 22:31:18 +02:00
..
data feat(portfolio): K2 — sequential multi-project run (parity row 4) 2026-07-23 21:39:39 +02:00
__init__.py feat(scaffold): S5 — D7 sibling scaffold: SDK dep, fail-fast startup contracts, CLAUDE.md 2026-07-03 06:06:03 +02:00
artifacts.py fix(run): S10 del 2 — post-mortem: stopp-artefakt, SDK-isolasjon, raw-JSON-direktiv 2026-07-03 10:49:51 +02:00
budget.py feat(loop): S8 — D7 agentic loop: budget meter, maker-checker gate, informed refinement 2026-07-03 07:21:02 +02:00
contracts.py feat(portfolio): K2 — sequential multi-project run (parity row 4) 2026-07-23 21:39:39 +02:00
experience.py feat(learning): S9 — D7 læringssløyfe: verdict-inbox, fail-closed promoteringsgate, artefakt-sourced persona 2026-07-03 07:36:15 +02:00
goals.py feat(ledger): K1 — savings ledger + goal contract (parity rows 2-3) 2026-07-17 04:00:14 +02:00
inbox.py feat(ingest): adopt llm-ingestion-okf as Door A implementation (first consumer) 2026-07-16 20:46:51 +02:00
ingest.py feat(ingest): adopt llm-ingestion-okf as Door A implementation (first consumer) 2026-07-16 20:46:51 +02:00
ir.py fix(validator): C2.6 — finiteness hardening, Infinity can no longer vacuously clear the gate (closes R-2) 2026-07-16 20:10:12 +02:00
ledger.py feat(ledger): K1 — savings ledger + goal contract (parity rows 2-3) 2026-07-17 04:00:14 +02:00
loop.py fix(validator): C2.6 — finiteness hardening, Infinity can no longer vacuously clear the gate (closes R-2) 2026-07-16 20:10:12 +02:00
okf.py fix(okf): tolerate embedded-NUL cross-link target — skip, never raise 2026-07-23 22:20:50 +02:00
outbox.py feat(portfolio): K5 — outbox persistence, run_id-named pairs (parity row 7) [skip-docs] 2026-07-23 22:31:18 +02:00
persona.py feat(learning): S9 — D7 læringssløyfe: verdict-inbox, fail-closed promoteringsgate, artefakt-sourced persona 2026-07-03 07:36:15 +02:00
portfolio.py feat(portfolio): K3 — portfolio learning loop (shared verdict store, parity row 5) [skip-docs] 2026-07-23 22:08:02 +02:00
promotion.py feat(inbox): C2.5 — inbox hardening + SDK version guard (closes C-F7, C-N3, R-6) 2026-07-16 20:26:41 +02:00
provenance.py feat(validator): S6 — deterministic backbone: typed IR, golden-frozen validator, provenance stamp 2026-07-03 06:27:40 +02:00
run.py feat(portfolio): K5 — outbox persistence, run_id-named pairs (parity row 7) [skip-docs] 2026-07-23 22:31:18 +02:00
run_s10.py fix(run): S10 del 2 — post-mortem: stopp-artefakt, SDK-isolasjon, raw-JSON-direktiv 2026-07-03 10:49:51 +02:00
sdk_client.py feat(inbox): C2.5 — inbox hardening + SDK version guard (closes C-F7, C-N3, R-6) 2026-07-16 20:26:41 +02:00
simulation.py feat(simulation): K4 — closed-loop two-run simulation binds §11 'Closed loop' (closes R-1) 2026-07-17 03:47:05 +02:00
validator.py feat(validator): S6 — deterministic backbone: typed IR, golden-frozen validator, provenance stamp 2026-07-03 06:27:40 +02:00