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
This commit is contained in:
parent
1600c188b4
commit
c08d92a358
3 changed files with 588 additions and 3 deletions
17
README.md
17
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 (478 tests, all running offline without an API
|
||||
> seam, each proven by load-bearing tests (514 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).
|
||||
|
||||
|
|
@ -118,6 +118,15 @@ description, never from its code)
|
|||
with no price fails fast — there is no hardcoded rate anywhere (a grep-guard proves it), and
|
||||
the figure is marked `ESTIMAT` (the whole cap billed at the rate is an upper bound; real runs
|
||||
cost less). `uv run python -m portfolio_optimiser_claude.costsim`.
|
||||
- `preflight.py` — the SDK/API preflight (**offline** — the boundary the operator crosses
|
||||
*before* any spend): everything that can be validated without a model call is checked here,
|
||||
so a broken config stops cheaply instead of on the first billed call. Four checks — a
|
||||
credential is present and not a placeholder form (`ANTHROPIC_API_KEY`, or the bundled CLI's
|
||||
own `CLAUDE_CODE_OAUTH_TOKEN`; the value itself is *never* validated online), the model_map
|
||||
profile exists and every id it resolves to is real, `claude_agent_sdk` imports and its
|
||||
bundled CLI is present on disk, and the §8 stop/budget contract is set. It never calls the
|
||||
API — a green preflight implies no more than that (§1). Each deficiency is a structured,
|
||||
actionable refusal. `uv run python -m portfolio_optimiser_claude.preflight`.
|
||||
|
||||
### Load-bearing tests (§11)
|
||||
|
||||
|
|
@ -133,7 +142,9 @@ 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),
|
||||
`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
|
||||
entrance path, with a no-outbox control, and the outcome carries the inbox join key),
|
||||
`test_preflight.py` (a missing credential and a placeholder model id are each refused before
|
||||
any spend, and the preflight carries no network path of its own), and
|
||||
`test_sdk_isolation.py` (local config cannot capture the checker).
|
||||
|
||||
## The ingest layer — CSV and SQL, in front of the loop
|
||||
|
|
@ -196,7 +207,7 @@ Python ≥3.10 · [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk
|
|||
|
||||
```bash
|
||||
uv sync # install dependencies
|
||||
uv run pytest # 478 tests — run without any API key and without network
|
||||
uv run pytest # 514 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