Skip to content

hydrate-evidence-content.py has no safe standalone mode: both date paths produce a wrong file #119

Description

@PaulDuvall

Summary

scripts/hydrate-evidence-content.py updates each entry's retrieved but never updates the document's last_checked or search.checked_at. Because scripts/validate-evidence.py enforces equality across all three, every standalone invocation produces either an invalid file or a backdated one. There is no correct way to run it by hand.

The two paths, both wrong

validate-evidence.py enforces:

  • complete provenance requires 'retrieved' == 'last_checked' (line ~498)
  • search: 'checked_at' must equal 'last_checked' (line ~313)

hydrate() writes only resolved_url, content_sha256, and retrieved (lines 46-49). It never touches last_checked or search.checked_at.

Path A — default (retrieved_date = today): produces an immediately invalid file.

$ python3 scripts/hydrate-evidence-content.py verification/evidence/planned-implementation.yaml
Hydrated 4 evidence source(s) with trusted retrieval metadata

$ python3 scripts/validate-evidence.py
FAIL verification/evidence/planned-implementation.yaml
  - evidence[0]: complete provenance requires 'retrieved' == 'last_checked'
  - evidence[1]: complete provenance requires 'retrieved' == 'last_checked'
  - evidence[2]: complete provenance requires 'retrieved' == 'last_checked'
  - evidence[3]: complete provenance requires 'retrieved' == 'last_checked'
  - search: 'checked_at' must equal 'last_checked'

Path B — --retrieved-date <existing last_checked>: validates clean, and that is the dangerous one.

$ python3 scripts/hydrate-evidence-content.py verification/evidence/planned-implementation.yaml --retrieved-date 2026-07-10
$ python3 scripts/validate-evidence.py
OK   verification/evidence/planned-implementation.yaml

This passes while recording today's fetch — a fresh content_sha256 and a possibly-changed resolved_url — under a retrieved date of 2026-07-10, against a search.run_url pointing at an unrelated July Actions run. It is silently backdated provenance that no gate catches.

So the failing path is noisy and the passing path is wrong. That inverts the poka-yoke: the tool steers a user toward Path B precisely because it's the one that goes green.

Why this isn't obvious

--help reads "Populate trusted retrieval fields for one model-authored evidence file", which suggests a self-contained operation. Nothing signals that the file is only coherent as part of the full approved local-run pipeline (plan-local-verification.py → research → finalize-local-verification.py), where a new search block with a fresh run_id: codex-local:<uuid> and its local-runs/ ledger artifacts are written together. Compare PR #112, which shows what a genuine refresh actually replaces.

Repro

  1. python3 scripts/hydrate-evidence-content.py verification/evidence/planned-implementation.yaml
  2. python3 scripts/validate-evidence.py → FAIL as above
  3. git checkout -- verification/evidence/planned-implementation.yaml
  4. Repeat with --retrieved-date 2026-07-10 → OK, but now content_sha256 is today's digest labeled as a July retrieval

Suggested fix

Make the unsafe modes unrepresentable rather than documented-against:

  • Refuse to run standalone on a provenance_status: complete file. Require an explicit flag tying the run to an approved manifest (e.g. --manifest verification/local-runs/codex-local-<uuid>.yaml), and derive retrieved from that manifest instead of from today or user input.
  • Reject a --retrieved-date that is older than the current retrieved. Backdating is never legitimate; it should be an error, not the happy path.
  • If a standalone mode is genuinely wanted, have it update last_checked and search.checked_at atomically and invalidate the now-stale search block (clear run_id/run_url, or set provenance_status back to needs-refresh) so the file cannot claim a search run that did not occur.
  • Minimally, if none of the above: make --help and a startup warning state that the output is not independently valid.

Context

Found while investigating the tests/test_evidence_content.py::test_complete_evidence_quotes_still_present failure (tracked separately under #94). Five records have drifted; four have refresh PRs in flight (#109-#112). The fifth, planned-implementation.yaml[2], is a VS Code docs redirect (/docs/agents/planning -> /docs/agents/run/planning) whose quote is still live and accurate. Attempting to fix that one record by hand is what surfaced this gap.

No code changes are proposed here; scripts/ is a protected trust root, so any fix needs an owner APPROVE TRUST ROOT round.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions