feat(run): stamp the drill's SDK build in the dry-run run-config [skip-docs]

The K8 drill captured a run-config that described the rig it rehearsed —
model ids, parameters, caps — without saying which SDK build would drive it.
The SDK's reported USD figure is computed against a price table frozen at build
time, so a rig record without the build is not traceable, and the drill exists
precisely to rig a future live run.

build_dry_run_config now takes the client the drill constructed and reads the
build from it, the same seam rule the provenance stamp follows: a drill driven
by the scripted stand-in stamps null rather than the installed version, because
reading the environment would describe a rig that never existed (§1).

Load-bearing (§11): the two new tests went RED before the change (no such key),
and the detach point is named in the class docstring — read importlib.metadata
instead of the client and the scripted drill claims a build it never used. The
existing dry-run tests assert individual keys rather than a key set, so the
additive field leaves them untouched, and byte-determinism still holds.

624 -> 627 passed, ruff + mypy --strict clean. README states the new field.
STATE post 2a, approved by the operator this session.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
This commit is contained in:
Kjell Tore Guttormsen 2026-07-25 15:35:16 +02:00
commit f300c64b0e
3 changed files with 80 additions and 2 deletions

View file

@ -116,8 +116,9 @@ description, never from its code)
same orchestration with a scripted client; only the CLI's default constructs the SDK
client. `--live-dry-run` is the **live-run drill** (K8): it builds everything a real run
would (contracts → compose → client construction → preflight) and captures a `run_id`-named
`runconfig` + `preflight` pair to the outbox (model-id, parameters, caps — no wall-clock, so
the bytes stay deterministic), then **stops before the first model call**. It exits 0 when
`runconfig` + `preflight` pair to the outbox (model-id, parameters, caps, and the SDK build
read from the client the drill constructed — no wall-clock, so the bytes stay
deterministic), then **stops before the first model call**. It exits 0 when
the preflight is clear and non-zero when it refused, but captures the artifacts and makes
zero model calls either way — a future operator-gated live run is rigged and rehearsed
offline, with no spend.