feat: freshness engine Phase 2 — foreground surface (read-only) - #3
Merged
Merged
Conversation
A resolving anchor whose span can't be hashed right now (unreadable file or resolver error) now yields state:'unknown' instead of a false 'fresh', so the foreground can flag it as unverifiable rather than vouch for it. A missing baseline alone (readable span, no stored hash) stays fresh. Structural/content drift still take precedence.
New anchor-fingerprints module: indexFingerprintsByClaim groups stored rows by claim (O(1) lookup after one batched read), and freshnessChecks builds the AnchorCheck[] for a claim's resolved anchors with a cache-aside stat prefilter — reuse the stored hash when mtime+size are unchanged, otherwise re-hash the span live.
Add freshness: FreshnessVerdict to ClaimContextResult and a new attachFreshness step in the builder: one batched fingerprint read for all selected claims (no N+1), then stat-prefiltered checks -> classifyFreshness per claim. Returns new objects; the query path performs no graph writes.
Every claim line now shows its truth. Stale claims are quarantined into a new '## Needs re-verification' section (a distrust signal, omitted when nothing drifted); unknown-freshness claims stay in Best Claims with an 'unverifiable' caveat.
divo12
force-pushed
the
feat/freshness-foreground
branch
from
July 5, 2026 10:33
5f3b403 to
5dd425f
Compare
- anchor-fingerprints: collision-free JSON key (was a space-joined string), named StoredByAnchor type, and self-describing helpers (currentSpanHash, fileUntouched). - render: use the named FreshnessVerdict type; replace the emoji caveats with plain ASCII [STALE]/[UNVERIFIABLE] markers consistent with the rest of the packet. - context-builder: unnest the attachFreshness call into a named step. No behavior change; all checks pass.
There was a problem hiding this comment.
3 issues found and verified against the latest diff
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
When a claim mixes structurally-broken anchors with undeterminable ones, classifyFreshness returned state:'unknown' with broken:[], silently dropping the broken anchors — inconsistent with the content branch and losing info Phase 3's healer needs. Now the unknown verdict surfaces them too. Also harden the foreground content/structural assertions to check state, not just reason.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Phase 2 of the freshness engine: every
graph contextquery now labels eachcode_verifiedclaim fresh / stale / unknown and quarantines stale ones into a## Needs re-verificationsection — computed live against the working tree, zero graph writes. Builds on the merged Phase 1 fingerprint foundation (#2).Why
Phase 1 stores a per-anchor content fingerprint but nothing surfaces it. Until the agent actually sees that a
code_verifiedfact has drifted, the fingerprint is inert. This is the agent-facing win: the read path distrusts stale facts on every query, without paying to write.How (backend layering)
classifyFreshness— added an explicitunknownstate: a resolving anchor whose span can't be hashed right now (unreadable file / resolver error) is flagged unverifiable instead of falselyfresh. Structural/content drift still take precedence; a missing baseline alone stays fresh.anchor-fingerprints.ts(new) —indexFingerprintsByClaim(O(1) lookup after one batched read) +freshnessCheckswith a cache-aside stat prefilter (reuse the stored hash when mtime+size are unchanged, else re-hash the span).claim-freshness.ts/ context-builder —attachFreshnessdoes one batchedfingerprintsForClaimsfor all selected claims (no N+1), returns new objects (immutable, read-only).render.ts— every claim line shows itstruth; stale claims move to## Needs re-verification(omitted when nothing drifted);unknownclaims stay in Best Claims with an unverifiable caveat.Test plan
npm testgreen across all 8 suites, incl. the feat: freshness engine — keep code_verified claims honest as code changes Autoloops/greplica#96check-anchor-driftregression;tsc --noEmitclean.attachFreshness/renderseams.greplica graph contextCLI (real local embedder) through all four verdicts —(missing symbol),unknownviachmod 000, and back to fresh on restore;graph readstill shows the claimcode_verifiedandgraph audit anchorsreports no invalidation.Scope
Phase 2 only. Deferred: Phase 3 background heal (heal-only first), Phase 4 agent re-verify. No doc commits in this PR.
Summary by cubic
Labels each
code_verifiedclaim as fresh, stale, or unknown in graph context, shows truth inline, and moves stale items to a “Needs re-verification” section. Computed live against the working tree with zero graph writes.New Features
attachFreshnessto the context builder: one batchedfingerprintsForClaimsread per packet, stat-prefiltered checks, immutable outputs.classifyFreshnesswithunknown; structural/content drift take precedence; a readable span with no baseline stays fresh.truth; quarantine stale claims under “## Needs re-verification”;[STALE]/[UNVERIFIABLE]markers for clarity.anchor-fingerprintshelpers (indexFingerprintsByClaim,freshnessChecks) to reuse stored hashes when mtime+size match.scripts/check-freshness-foreground.jstonpm test; set defaultfreshness: { state: "fresh" }in eval outputs.Bug Fixes
unknownverdict now carries structurally-broken anchors instead of dropping them; strengthened assertions in foreground tests.Written for commit 9ba971b. Summary will update on new commits.