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
This commit is contained in:
parent
613b00f882
commit
a926e4ad46
4 changed files with 378 additions and 3 deletions
14
README.md
14
README.md
|
|
@ -13,7 +13,7 @@ human-in-the-loop, and the system learns from the verdicts.
|
|||
> **Status:** the D7 build (S5–S10) is complete, and the deterministic **ingest layer**
|
||||
> (CSV and SQL source types) has since been added in front of the loop. The deterministic
|
||||
> backbone, the agentic loop, the learning loop, and the ingest connectors are wired seam by
|
||||
> seam, each proven by load-bearing tests (442 tests, all running offline without an API
|
||||
> seam, each proven by load-bearing tests (457 tests, all running offline without an API
|
||||
> key). The programme's single budgeted **live model run has been executed and validated** —
|
||||
> its artifacts are committed under [`runs/s10/`](runs/s10/) (see below).
|
||||
|
||||
|
|
@ -88,6 +88,12 @@ description, never from its code)
|
|||
(`setting_sources=[]`) so no user/project config can leak into a run.
|
||||
- `artifacts.py` — §9 citations plus deterministic run-artifact persistence, including on
|
||||
structured stops (a budget stop still leaves artifacts behind).
|
||||
- `outbox.py` — the outbox output layer (S2.1): each completed run persists a `run_id`-named
|
||||
proposal/outcome pair — the system's own output, which it writes freely (the role split
|
||||
governs the inbox and wiki, not this). The outcome carries the inbox join key (`verdict_id`,
|
||||
minted the same way the inbox mints an expert verdict's id) so outstanding verdicts can be
|
||||
tracked and live artifacts captured; bytes reuse the deterministic house JSON writer, and
|
||||
the S10 artifact formats are untouched.
|
||||
- `run.py` — the generic run entrance: composes merge-inbox → seed → fold (§5) and drives
|
||||
the loop under the budget meter, persisting artifacts on both outcomes — a structured
|
||||
budget stop included. The model client is injected, so the offline suite proves the
|
||||
|
|
@ -115,7 +121,9 @@ retry prompt, and the loop still stops at the cap), `test_step7_async_loop_loadb
|
|||
empty-inbox control), `test_step8_promotion_loadbearing.py` (the gate refuses non-approved
|
||||
verdicts; the promoted signal stays out of the read-context),
|
||||
`test_portfolio_learning_loadbearing.py` (a verdict available at project k survives into
|
||||
project k+1's fold via the shared store, with a marker-absent control), and
|
||||
project k+1's fold via the shared store, with a marker-absent control),
|
||||
`test_outbox_loadbearing.py` (a completed run's `run_id`-named outbox pair is written on the
|
||||
entrance path, with a no-outbox control, and the outcome carries the inbox join key), and
|
||||
`test_sdk_isolation.py` (local config cannot capture the checker).
|
||||
|
||||
## The ingest layer — CSV and SQL, in front of the loop
|
||||
|
|
@ -178,7 +186,7 @@ Python ≥3.10 · [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk
|
|||
|
||||
```bash
|
||||
uv sync # install dependencies
|
||||
uv run pytest # 442 tests — run without any API key and without network
|
||||
uv run pytest # 457 tests — run without any API key and without network
|
||||
uv run ruff check . && uv run ruff format --check .
|
||||
uv run mypy src # strict
|
||||
```
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue