pub fn phase_verification_fingerprint(
evidence_root: &Path,
phase: PhaseId,
) -> Option<u64>Expand description
A content fingerprint of the phase’s {phase:02}-VERIFICATION.md, or None
when no such artifact exists under evidence_root (999.79, 35-05).
What it is for. Nothing deletes, dates or invalidates the artifact, and
devflow start --phase N --force checks out a branch that still carries the
PREVIOUS run’s committed copy. That re-run is mid-arc by construction, so its
first Validate failure would find the stale artifact, read it as a verdict,
and dispatch a --gaps-only pass against zero matching plans — gating
unresolvably. Comparing this value against the one recorded at the start of
the run distinguishes “the Validate agent authored this during this run”
from “this was inherited”.
Why the algorithm is written out rather than borrowed from std. This
value is persisted by one process (devflow start) and compared by a later
one (devflow advance), so it must mean the same thing in both.
std::collections::hash_map::DefaultHasher explicitly does NOT guarantee a
stable output across toolchain versions, so an operator who upgraded Rust
mid-phase would see every artifact read as “changed” — which is the
fail-OPEN direction, dispatching gaps-only exactly where a full execute was
correct. This is FNV-1a/64, fixed by these two constants and nothing else.
No security property is claimed. This is change detection over a planning document that is already committed to the repository. It is not collision-resistant and must never be used to authenticate anything; an adversary who can write the artifact can already write whatever verdict they like into it.
§Companion: phase_verification_mtime_nanos
Content alone cannot see an IDEMPOTENT rewrite (WR-06, 35-REVIEW): a
Validate agent that re-authors byte-identical content on a later cycle
produces the same fingerprint as an artifact nobody touched, and the
consumer then classifies its own agent’s work as inherited. The mtime is
the second input that separates “unchanged because inherited” from
“unchanged because idempotent”; it is read from the same resolved path and
returns None on exactly the same “no artifact” condition, so the two are
always consistent about whether an artifact exists.