feat(portfolio): stamp the producing SDK build in provenance (wiki-advisory F1) [skip-docs]
The advisory finding: provenance.py/artifacts.py stamped no SDK version, while the SDK's total_cost_usd is a client-side ESTIMATE computed against a price table frozen when the SDK was built. An untraceable estimate is a figure nobody can check later, so the run now records which build produced it. Provenance gains sdk_version: str | None. The value comes from the PRODUCING CLIENT — getattr(client, "sdk_version", None) — exactly as model and cost_usd already do, never from importlib.metadata at stamp time. That distinction is the seam: a run driven by the scripted stand-in used no SDK at all, and stamping the installed version there would attribute a build to a run that never touched it (§1). SdkModelClient reads the installed build once from package metadata (offline: no key, no network); every other client reports null. A blank string is refused by the schema — null is the one way to say "not produced by the SDK". Scope note: this traceability covers OUR run cost only. The savings the framework recommends are settled by the deterministic validator against the golden suite, and no SDK estimate touches them. Two seams, both detach-proven RED: - make the stamp read importlib.metadata instead of the client → a scripted run claims a build it never used → red - back-fill runs/s10/provenance.json → red That second guard is the point of the change as much as the first. runs/s10/ is the byte-frozen record of the ONE live run (2026-07-03), executed before this field existed; the suite reads it nowhere else, so nothing would have caught a retro-stamp. Adding a build id to it now would be a guess presented as provenance. It stays without one, and the README says why. run_s10.py is deliberately untouched (byte-frozen fasit script), and the field defaults to None, so every existing caller and artifact shape is unchanged. 603 passed · ruff clean · mypy strict clean · runs/s10/ byte-identical. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MQu2xxwedckjU56byu1aUG
This commit is contained in:
parent
da93a68ce7
commit
bf87776bb3
6 changed files with 193 additions and 3 deletions
|
|
@ -159,6 +159,15 @@ def _client_cost_usd(client: ModelClient) -> float | None:
|
|||
return None if cost is None else round(float(cost), 6)
|
||||
|
||||
|
||||
def _client_sdk_version(client: ModelClient) -> str | None:
|
||||
# The build is read from the PRODUCING CLIENT, never from the environment:
|
||||
# a run driven by the scripted stand-in used no SDK at all, and stamping
|
||||
# the installed version there would attribute a build to a run that never
|
||||
# touched it (§1). Same seam rule as the cost and the model id above.
|
||||
version = getattr(client, "sdk_version", None)
|
||||
return None if version is None else str(version)
|
||||
|
||||
|
||||
def execute_run(
|
||||
client: ModelClient,
|
||||
composed: ComposedRunContext,
|
||||
|
|
@ -225,6 +234,7 @@ def execute_run(
|
|||
role=_PROPOSER_ROLE,
|
||||
validator_decision=result.validator_decision,
|
||||
tokens_used=meter.tokens_used,
|
||||
sdk_version=_client_sdk_version(client),
|
||||
)
|
||||
paths = persist_run_artifacts(
|
||||
out_dir,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue