Summary
internal/observerstore.WriteSnapshot is defined (internal/observerstore/capability_snapshots_writer.go:80) and unit-tested, but no non-test code in the loom repo calls it. So the capability_snapshots observer table is never populated in a real run, even though driver.dry_run_contract computes the hash on every call.
Discovered during smoke rerun of PR #80 (agentserver-stub L4 verification).
Base checked: paper/v3-integration @ 1748802.
Repro
cd multi-agent
grep -rn 'WriteSnapshot\b' internal/ cmd/ tools/ | grep -v _test | grep -v 'internal/observerstore/capability_snapshots_writer.go'
# → no matches
Compare with the design: docs/superpowers/specs/2026-06-*capability-snapshot*.md mandates snapshot persistence for E1/E6 metric extraction and Phase 1 acceptance test §L4 (see PR #61 §Data collection).
Observed effect
Live smoke run against deploy.sh --stub:
codex → fix-driver.dry_run_contract → 200 OK { runnable:true, recommended_target:eval-slave, ... }
sqlite3 $LOOM_HOME/observer/observer.db 'SELECT count(*) FROM capability_snapshots;'
0
The dry-run handler at internal/driver/capability_tools.go:275 computes capability.ComputeHash(snap) and stores the string in a local snapHash variable, embedded into the returned DryRunReport.CapabilitySnapshotHash. But that hash is never sent to observerstore.WriteSnapshot. The snapshot itself (JSON body) is never persisted, so capability_snapshot_usages (per-agent-usage log added in PR #61) also stays empty.
Impact
Any Phase 1/2/3 evaluator that queries capability_snapshots / capability_snapshot_usages — including the D2 metric-extract path introduced by PR #68 — gets 0 rows. The Phase 1 close-out memo (docs/intermediate/14_phase1_closeout.md) claims per-agent capability attribution works; that guarantee only holds for the direct unit-test path.
Suggested fix
Wire observerstore.WriteSnapshot(ctx, db, snap) from internal/driver/capability_tools.go inside dryRunContractTool.Call, right after snapHash = capability.ComputeHash(snap). Also record a capability_snapshot_usages row per (workspace_id, agent_id, hash) at that point.
Alternatively, thread the write into inspect_capabilities (internal/driver/capability_tools.go:29) — but that path only stores contract.ResourceSnapshot, not capability.Snapshot, so dry_run_contract remains the natural home.
Environment
Related: PR #80, #61, #68.
Summary
internal/observerstore.WriteSnapshotis defined (internal/observerstore/capability_snapshots_writer.go:80) and unit-tested, but no non-test code in the loom repo calls it. So thecapability_snapshotsobserver table is never populated in a real run, even thoughdriver.dry_run_contractcomputes the hash on every call.Discovered during smoke rerun of PR #80 (agentserver-stub L4 verification).
Base checked:
paper/v3-integration@1748802.Repro
Compare with the design:
docs/superpowers/specs/2026-06-*capability-snapshot*.mdmandates snapshot persistence for E1/E6 metric extraction and Phase 1 acceptance test §L4 (see PR #61 §Data collection).Observed effect
Live smoke run against
deploy.sh --stub:The dry-run handler at
internal/driver/capability_tools.go:275computescapability.ComputeHash(snap)and stores the string in a localsnapHashvariable, embedded into the returnedDryRunReport.CapabilitySnapshotHash. But that hash is never sent toobserverstore.WriteSnapshot. The snapshot itself (JSON body) is never persisted, socapability_snapshot_usages(per-agent-usage log added in PR #61) also stays empty.Impact
Any Phase 1/2/3 evaluator that queries
capability_snapshots/capability_snapshot_usages— including the D2 metric-extract path introduced by PR #68 — gets 0 rows. The Phase 1 close-out memo (docs/intermediate/14_phase1_closeout.md) claims per-agent capability attribution works; that guarantee only holds for the direct unit-test path.Suggested fix
Wire
observerstore.WriteSnapshot(ctx, db, snap)frominternal/driver/capability_tools.goinsidedryRunContractTool.Call, right aftersnapHash = capability.ComputeHash(snap). Also record acapability_snapshot_usagesrow per(workspace_id, agent_id, hash)at that point.Alternatively, thread the write into
inspect_capabilities(internal/driver/capability_tools.go:29) — but that path only storescontract.ResourceSnapshot, notcapability.Snapshot, sodry_run_contractremains the natural home.Environment
Related: PR #80, #61, #68.