feat(ledger): K1 — savings ledger + goal contract (parity rows 2-3)

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>
This commit is contained in:
Kjell Tore Guttormsen 2026-07-17 04:00:14 +02:00
commit 698e8f21dd
5 changed files with 445 additions and 2 deletions

View file

@ -13,7 +13,7 @@ human-in-the-loop, and the system learns from the verdicts.
> **Status:** the D7 build (S5S10) 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 (400 tests, all running offline without an API
> seam, each proven by load-bearing tests (426 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).
@ -73,6 +73,16 @@ offline. Module by module:
[`shared/skills/expert-reviewer/`](shared/skills/expert-reviewer/) at call time, so the
shared persona is genuinely consumed and cannot rot silently.
**Value layer** (stack-local contract — mirrored from the sibling plan's capability
description, never from its code)
- `ledger.py` — the typed savings ledger: realized savings enter the book **only** through
the fail-closed expert gate (an approved verdict + a named expert + an explicit
timestamp), and the sum key is dimension-free, so the same realized saving surfaced via
two dimensions is never double-counted. Persistence is deterministic JSON.
- `goals.py` — the goal contract: absolute savings target, hard/soft. A hard goal reached
raises a structured stop event, never a silent stop; the percent-goal baseline is
D-E-gated and refused explicitly.
**Run layer** (the only part that touches the network)
- `sdk_client.py` — the Claude Agent SDK client, isolated from local configuration
(`setting_sources=[]`) so no user/project config can leak into a run.
@ -158,7 +168,7 @@ Python ≥3.10 · [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk
```bash
uv sync # install dependencies
uv run pytest # 400 tests — run without any API key and without network
uv run pytest # 426 tests — run without any API key and without network
uv run ruff check . && uv run ruff format --check .
uv run mypy src # strict
```