Skip to content

observerstore.WriteSnapshot has no non-test caller; capability_snapshots never populated #81

Description

@yzs15

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions