cairn: distinguish git-invocation failures from confirmed-negative freshness checks#54
Merged
Conversation
quad341
enabled auto-merge (squash)
July 25, 2026 05:35
… (crn-fdjc.1.1) Add Incomplete status constant and new tests at the stable Check/Sweep entry points asserting the FR-5 failure-class distinction from crn-fdjc.1's design: a genuine git invocation failure (PATH unreachable, canceled context) must classify as Incomplete, never collapse into the same Unknown verdict as a confirmed negative (missing repo, no commits yet, unmatched glob, staged-but-uncommitted path). New tests fail against the current implementation, which still folds every failure into Unknown/"?" — expected RED. Confirmed-negative regression tests pass unmodified, confirming FR-2 (today's behavior for those classes is preserved). ComputeFingerprint/objectHash/expand/ untrackedPaths keep their current signatures for now; direct tests of their error-returning form land in the GREEN commit since they can't compile until the signatures change.
ComputeFingerprint/objectHash/expand now return an explicit error for a
genuine git invocation failure, distinct from a confirmed negative
(untracked path, no anchor, etc.) which still returns ("", nil). Check
surfaces invocation failures as a new Incomplete status; Sweep's
untrackedPaths enrichment leaves status/detail untouched when the
underlying check was itself incomplete, instead of misreporting it as
a confirmed Unknown. cmd/commands.go: freshnessCmd/verifyCmd now hard-error
on Incomplete/invocation failure; statusCmd adds an "!X " flag; getCmd
needed no change (already prints any status generically).
Implements crn-fdjc.1.1 per architect design in crn-fdjc.1.
…et gate Rebasing crn-fdjc.1.1 (git-invocation-failure -> Incomplete propagation) onto crn-0vqk.2's already-merged Check() reorder (never-verified short-circuit before the git shell-out, for performance) produced a textual, mechanically-resolvable conflict -- but the obvious resolution (keep the never-verified check first) silently defeated crn-fdjc.1.1's own pinning tests: a files anchor that has never been fingerprinted yet still needs its git invocation attempted, so a genuine failure (broken PATH, canceled context) surfaces as Incomplete instead of being masked behind "never verified". Reordered Check() to attempt ComputeFingerprint (surfacing Incomplete on error) before the never-verified check, which now runs only after a successful call -- preserving crn-0vqk.2's original fix against a false Fresh/Stale null-comparison for a never-verified anchor, while letting crn-fdjc.1.1's error propagation win first. freshnessBudget.classify (prime.go) gated its shell-out cap on `a.Fingerprint != ""`, which was only ever correct under the old ordering where a never-verified anchor short-circuited for free. Now that Check unconditionally shells out for any shape-verifiable files anchor, that clause under-metered the exact cost FR-5's budget cap exists to bound -- dropped it so every files anchor that will actually invoke git counts against the cap, never-verified or not. Also fixes a stale call site in prime_test.go: ComputeFingerprint's pre-crn-fdjc.1.1 signature returned a single value; the two-return form landed via this same rebase but prime_test.go (merged to main earlier, unrelated to this branch) wasn't touched by the rebased commits, so the break was invisible to git's textual merge.
quad341
force-pushed
the
deploy/crn-jrhz-gate
branch
from
July 25, 2026 10:03
ba1ad43 to
b66f81a
Compare
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 this changes
When cairn checks an anchor's freshness (
cairn freshness,verify,status,get) and the underlyinggitinvocation itself fails to run — a transient error, a canceled context — that failure was previously indistinguishable from a confirmed negative result (e.g. "this path really isn't tracked at HEAD"). Both cases silently fell into the same stale/unknown bucket.This adds a new
Incompletestatus that's reported only when the freshness check genuinely couldn't complete, so a transient git hiccup is no longer conflated with a real negative finding:cairn freshness/cairn verifynow hard-error with a message distinct from today's "nothing to verify" wording when the check is incomplete.cairn statusgains a new marker (alongsideOK/!!/??) for incomplete entries.cairn getreports the incomplete status honestly in its output but does not fail the command — freshness is incidental toget's job of returning the entry body.All previously-confirmed-negative outcomes (missing repo, no commits yet, deleted path, unmatched glob, invalid revision) are unaffected and still classify as
Unknownexactly as before.Review notes
Check()'s public signature is unchanged; the new status only affects what value it can return.git()error is threaded through the call stack instead of being discarded.internal/critic's freshness scenario gained a 4th sub-check using a pre-canceledcontext.Context(not PATH-tampering, since that file runs against live, possibly-concurrent state).Test plan
go test ./... -race -count=1— all packages green, no regressionsgolangci-lint run ./...— 0 issuesrelease-gates/freshness-invocation-incomplete-status-gate.md