portfolio-optimiser-claude/CHANGELOG.md
Kjell Tore Guttormsen 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

3.3 KiB
Raw Blame History

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

Added

The method, implemented (D7). Sibling implementation of the portfolio-optimiser method on the Claude Agent SDK, built from the shared frozen spec + golden suite alone — never by reverse-engineering the MAF sibling.

  • Deterministic backbone — the typed cost-IR, the mandatory blocking validator (frozen by the shared golden suite, its only oracle), first-class provenance, and fail-fast startup contracts including the role → model map.
  • Agentic loop — bounded generation, makerchecker debate, the validator gate, and informed refinement; the budget meter admits no unbounded loop anywhere, and carries an optional pre-call run-total USD belt on top of the post-charge token/round caps.
  • Learning loop — the OKF context seam (navigation, never chunk-stuffing), the ExpeL-style experience fold, the async expert-verdict inbox, and the fail-closed promotion gate.
  • Ingest layer — deterministic CSV (file) and SQLite (sql) connectors in front of the loop, materializing OKF bundles the unchanged loop consumes; frozen by byte-identical golden extractions. http/MCP is an extension point this repo does not build, and a manifest naming it is rejected fail-fast.
  • Value layer — the fail-closed savings ledger (dimension-free sum, no double-counting), the hard/soft goal contract, the outbox output layer, the HITL pending/routing view, the pre-run cost simulation over schema-validated pricing config, the SDK/API preflight, opt-in notification sinks (webhook egress only behind an explicit per-run flag), and the per-run value report (modelled → expert-corrected → realized, goal progress, quantified learning effect, cost against value).
  • Operator CLI — one collecting entrance (run.py) for a single project (--bundle) or a portfolio (--portfolio, --verdict-dir), with --goals + --ledger stopping a run before any model call when the target is already met, and --value-report projecting what the run delivered. Standalone entrances for valuereport, hitl, costsim and preflight. Every flag the README documents is checked against the actual --help output by a load-bearing test.
  • Knowledge-base recipe — the documented team process for building the OKF bundles the framework reads (docs/oppskrift-kunnskapsbase.md), with an honest 12 week expectation.
  • The programme's one live model run (S10) — executed and validated at a documented $0.127514, its four artifacts committed as fixed reference output under runs/s10/.
  • Load-bearing tests — every seam is proven by a test that goes red when the seam is detached; the whole suite runs offline, with no API key and no network.

Notes

  • Honesty rule (method spec §1): no artifact in this repo claims more than the implementation does. Scripted stand-ins are labelled as such, unbuilt extension points are named as unbuilt, and a figure the data does not carry is reported unmarked rather than back-filled.
  • Licensed under the MIT License (see LICENSE).