portfolio-optimiser-claude/tests
Kjell Tore Guttormsen 7d8de32543 feat(okf): navigate hierarchy — escape, not depth, is forbidden
The pulled method-spec (commons 9801d35) retires the "a target containing a
path separator is out-of-bundle" heuristic, which conflated depth with escape
and forbade valid hierarchy. Triage of the pull found FIVE contradictions in
okf.py, not the two STATE had measured on line 127 alone:

1. the separator ban skipped every legal nested target;
2. de-duplication keyed on the RAW target (`resolved` was computed a line
   later), not on the resolved path;
3. navigation never recursed — only the root index's links were read;
4. a leading `/` became filesystem-absolute via pathlib rather than denoting
   the bundle root (safe, because the boundary check caught it, but the right
   outcome for the wrong reason — and wrong the moment `/a/index.md` must be
   FOLLOWED);
5. rendering excluded only `verdict`, so a nested index body would render as
   content.

navigate_bundle is now depth-first in first-seen link order, de-duplicating on
the resolved path (so `./a.md` and `a.md` are one entry and cycles terminate);
resolution and the fail-closed boundary check move to _resolve_target, the sole
in-/out-of-bundle test. The missing-index rule binds the bundle root alone.
bundle_context renders flat regardless of depth and drops nested index bodies:
only the root index is the summary.

The gate is the commons-owned nav-golden pair that arrived with the same pull —
bundle in, expected-read-context out. Its negative case exists so the gate can
go red at all, and carries a real decoy one level up plus a `/etc/passwd` trap.

Detach-proved (mutate, run, restore from copy) — each new seam goes RED:
  D1 reinstate the separator heuristic -> RED
  D2 re-key dedup on the raw target   -> RED
  D3 read a leading `/` as absolute   -> RED
  D4 render nested index bodies       -> RED
Control after restore: 24 passed. Suite 631 -> 637, ruff + mypy --strict clean.

Comments asserting the retired doctrine were corrected rather than left to
document a rule the code no longer follows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M1zp3BxCuzRnUtJPzvEFTQ
2026-07-31 18:13:20 +02:00
..
data feat(portfolio): K11 — per-run value report, pure projection over the three layers (parity row 25) [skip-docs] 2026-07-25 06:25:02 +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_cli_paritet_loadbearing.py fix(run): classify portfolio-mode flags by allowlist so a new flag fails closed 2026-07-25 15:33:30 +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_dry_run_loadbearing.py feat(portfolio): K8 — live-run drill, pre-call artifact capture (parity row 21) [skip-docs] 2026-07-24 06:54:58 +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_hitl_loadbearing.py feat(portfolio): K9 — HITL verdict routing + pending tracking (parity row 22) [skip-docs] 2026-07-24 19:58:29 +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 fix(ledger): normalize every load rejection to ValueError at the ledger's own entrance 2026-07-25 15:29:27 +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_notify_loadbearing.py feat(portfolio): K10 — notification/notifier seam, opt-in webhook egress (parity row 23) [skip-docs] 2026-07-24 20:16:56 +02:00
test_notify_seam_loadbearing.py feat(portfolio): K10 — notification/notifier seam, opt-in webhook egress (parity row 23) [skip-docs] 2026-07-24 20:16:56 +02:00
test_okf.py feat(okf): navigate hierarchy — escape, not depth, is forbidden 2026-07-31 18:13:20 +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_provenance_sdk_version_loadbearing.py feat(run): stamp the drill's SDK build in the dry-run run-config [skip-docs] 2026-07-25 15:35:16 +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
test_valuereport_loadbearing.py test(valuereport): bind _SHARE_DIGITS to its MEASURED band, not to itself 2026-07-26 15:28:20 +02:00
test_valuereport_seam_loadbearing.py feat(portfolio): K11 — per-run value report, pure projection over the three layers (parity row 25) [skip-docs] 2026-07-25 06:25:02 +02:00