portfolio-optimiser-claude/tests
Kjell Tore Guttormsen c08d92a358 feat(portfolio): K7 — SDK/API preflight, offline pre-spend boundary (parity row 20) [skip-docs]
Everything that CAN be validated WITHOUT a model call is validated BEFORE the
operator pays for one (S4.1-analog, SDK-native — Foundry-auth is MAF-specific,
not mirrored). The preflight IS the boundary: it never calls query(), never
validates a credential VALUE online, never touches the network. It returns a
list of structured, actionable Refusals; the CLI exits non-zero on any, so a
broken config stops cheaply instead of on the first billed call.

- preflight.py: run_preflight + `python -m …preflight --profile anthropic`.
  Four offline checks:
  * credential — ANTHROPIC_API_KEY set + not a placeholder form (the value is
    NEVER checked online, only presence, §1); the bundled CLI's own
    CLAUDE_CODE_OAUTH_TOKEN also satisfies it (run_s10 relies on it — refusing
    would be a false alarm).
  * model_map — the requested profile exists and every id it resolves to,
    THROUGH resolve_model (so the default fall-through is covered), is real,
    not a placeholder left in config.
  * sdk — claude_agent_sdk imports (a missing install is a structured refusal
    naming `uv sync`, never an ImportError out of the preflight), the run-path
    symbols exist, and the bundled Claude Code CLI is present on disk — located
    OFFLINE via the SDK package's own files, mirroring the SDK's _find_cli
    order (bundled first, then a claude on PATH). Verified against installed
    0.2.120 (bundled binary present; the STATE 0.2.110 note was stale).
  * termination — the §8 stop contract constructs with positive caps and the
    per-call USD belt is positive.
- tests/test_preflight.py: credential contract, placeholder detector, model_map
  incl. unknown-profile-without-raising, SDK + bundled-CLI offline probe (with a
  monkeypatched missing-SDK refusal), termination, run_preflight aggregation,
  CLI both paths, and the offline guards (no network import, no query() call —
  AST-based so prose stays green). THREE seams detach-proven RED: credential
  branch, placeholder model-id guard, no-network grep-guard.

478→514 green, golden byte-exact, full gate clean (ruff+format+mypy strict,
24 src files), run_s10.py/runs/ byte-untouched. README test-count sync ×2 +
preflight.py module note + load-bearing mention. IKKE-scope (held): the actual
API call (ALDRI — the preflight IS the boundary) and Foundry/Azure auth.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiTwaKLesgcwXx2mDviqpt
2026-07-24 01:34:18 +02:00
..
data/mini-bundle feat(portfolio): K2 — sequential multi-project run (parity row 4) 2026-07-23 21:39:39 +02:00
_scripted.py feat(loop): S8 — D7 agentic loop: budget meter, maker-checker gate, informed refinement 2026-07-03 07:21:02 +02:00
test_budget.py feat(portfolio): C3.5 — pre-call run-total USD budget belt (parity row 16/31) [skip-docs] 2026-07-23 22:45:37 +02:00
test_bygg_energi_mikro.py feat(validator): S6 — deterministic backbone: typed IR, golden-frozen validator, provenance stamp 2026-07-03 06:27:40 +02:00
test_checker_gate_loadbearing.py feat(loop): S8 — D7 agentic loop: budget meter, maker-checker gate, informed refinement 2026-07-03 07:21:02 +02:00
test_contracts.py feat(portfolio): K2 — sequential multi-project run (parity row 4) 2026-07-23 21:39:39 +02:00
test_costsim.py feat(portfolio): K6 — pre-run cost simulation, priced what-if (parity row 18) [skip-docs] 2026-07-23 23:01:01 +02:00
test_goals.py feat(ledger): K1 — savings ledger + goal contract (parity rows 2-3) 2026-07-17 04:00:14 +02:00
test_ingest.py chore(deps): re-pin llm-ingestion-okf to v0.3.1 + migrate tests to stable error codes 2026-07-20 07:22:09 +02:00
test_ingest_adoption.py chore(deps): re-pin llm-ingestion-okf to v0.3.1 + migrate tests to stable error codes 2026-07-20 07:22:09 +02:00
test_ingest_golden.py feat(ingest): I3 — D7-speil av ingest (filkatalog/CSV), bygget fra commons-spec alene 2026-07-04 06:12:43 +02:00
test_ingest_loadbearing.py feat(ingest): adopt llm-ingestion-okf as Door A implementation (first consumer) 2026-07-16 20:46:51 +02:00
test_ingest_spec_loadbearing.py feat(ingest): I5 — SQL D7-speil, bygget fra commons-spec alene 2026-07-04 07:18:59 +02:00
test_ingest_sql.py chore(deps): re-pin llm-ingestion-okf to v0.3.1 + migrate tests to stable error codes 2026-07-20 07:22:09 +02:00
test_ingest_sql_golden.py feat(ingest): I5 — SQL D7-speil, bygget fra commons-spec alene 2026-07-04 07:18:59 +02:00
test_ingest_sql_loadbearing.py feat(ingest): adopt llm-ingestion-okf as Door A implementation (first consumer) 2026-07-16 20:46:51 +02:00
test_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
test_ledger_loadbearing.py feat(ledger): K1 — savings ledger + goal contract (parity rows 2-3) 2026-07-17 04:00:14 +02:00
test_loop.py fix(run): S10 del 2 — post-mortem: stopp-artefakt, SDK-isolasjon, raw-JSON-direktiv 2026-07-03 10:49:51 +02:00
test_method_spec_loadbearing.py test(spec): C1.1 — method-spec integrity guard (§11 'Spec integrity', closes C-N1) 2026-07-16 19:59:01 +02:00
test_okf.py fix(okf): tolerate embedded-NUL cross-link target — skip, never raise 2026-07-23 22:20:50 +02:00
test_outbox_loadbearing.py feat(portfolio): K5 — outbox persistence, run_id-named pairs (parity row 7) [skip-docs] 2026-07-23 22:31:18 +02:00
test_persona_skill_loadbearing.py feat(learning): S9 — D7 læringssløyfe: verdict-inbox, fail-closed promoteringsgate, artefakt-sourced persona 2026-07-03 07:36:15 +02:00
test_portfolio.py feat(portfolio): K2 — sequential multi-project run (parity row 4) 2026-07-23 21:39:39 +02:00
test_portfolio_learning_loadbearing.py feat(portfolio): K3 — portfolio learning loop (shared verdict store, parity row 5) [skip-docs] 2026-07-23 22:08:02 +02:00
test_preflight.py feat(portfolio): K7 — SDK/API preflight, offline pre-spend boundary (parity row 20) [skip-docs] 2026-07-24 01:34:18 +02:00
test_provenance.py feat(validator): S6 — deterministic backbone: typed IR, golden-frozen validator, provenance stamp 2026-07-03 06:27:40 +02:00
test_run_entrance_loadbearing.py feat(run): C2.0 — shippable step-7 run entrance + K2.9 seam bindings (closes C-N2, R-10, K2.9) 2026-07-17 03:28:31 +02:00
test_s10_run_layer.py fix(run): S10 del 2 — post-mortem: stopp-artefakt, SDK-isolasjon, raw-JSON-direktiv 2026-07-03 10:49:51 +02:00
test_sdk_isolation.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
test_sdk_version_guard.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
test_simulation_loadbearing.py feat(simulation): K4 — closed-loop two-run simulation binds §11 'Closed loop' (closes R-1) 2026-07-17 03:47:05 +02:00
test_step1_expel_loadbearing.py feat(context): S7 — D7 context seam: OKF navigation + gated ExpeL fold 2026-07-03 06:48:13 +02:00
test_step5_refine_loadbearing.py feat(loop): S8 — D7 agentic loop: budget meter, maker-checker gate, informed refinement 2026-07-03 07:21:02 +02:00
test_step7_async_loop_loadbearing.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
test_step8_promotion_loadbearing.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
test_validator.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