fix(guard-commit,doctor): scope the decision-file predicate to the two real layouts; report absent enforcement gates as DRIFT - #357
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Panel verdict: BLOCK from both lensesTwo independent reviewers, disjoint scopes. Both blocked. Fix lane running. Lens B1 — the commit-gate predicateBinaries: subject CONFIRMED — over-blocking, product-breaking
End-to-end on the first, with the hook installed: control The reviewer's own caveat, kept: with CONFIRMED — the "exact image" claim is false where it mattersI wrote that the predicate is the exact image of So 2 of 3 constants are genuinely shared, and the docs-dir half — precisely the half failing above — RefutedNested Non-ASCII branch ( Lens B3 —
|
1a26541 to
cabc0ec
Compare
…eal layouts; doctor: report absent enforcement gates as DRIFT
…gate route through; ask git where hooks live; treat inert gates as absent
cabc0ec to
842e7bb
Compare
Two independent holes in the enforcement layer. Both fixed, both mutation-tested (18 mutants, all
compiled, all killed), full suite green from an isolated worktree.
B1 — the commit gate accepted a decision file anywhere in the tree
isDecisionFilematched any path ending/decisions.md, so a well-formed entry written tointernal/x/decisions.mdsatisfied the gate. It is now the exact image ofresolveDecisionsPath,built from shared layout constants in
internal/decisions:docs/decisions.md, or a single.mddirectly under
docs/decisions-branches/.Verified independently by me, not taken from the lane's report — two binaries, one built from
origin/dev(0f78a04), one from this branch, run against freshly-scaffolded repos:docs/decisions-branches/main.md+ 302 Go lines — must passinternal/x/decisions.md+ 302 Go lines — decoyThe must-pass row is the control: it stays green on both binaries, so the fix blocks the decoy without
over-blocking the legitimate layout. (Two earlier harness attempts of mine were invalid — one built
both binaries from the same tree, one omitted
--msg-fileso every run died on argument parsingbefore reaching the gate. Recording that so the matrix is read as the third, working harness.)
check-decisionsagrees on both scopes — the decoy was exit 0 in range mode pre-fix, exit 1 now, sothe §6.2 merge gate was open to the same decoy.
Explicitly NOT closed by this PR
A staged rename or copy of an existing decision file still clears the gate (#335). This predicate
cannot close it: a pathspec limits git's tree walk before rename detection, so a rename renders as
new file modewith every line added, and no path rule ever sees it. Documented in situ with bothcandidate mechanisms and their costs —
--name-statusis cheap for renames, but--find-copies-hardersilently disables pastdiff.renameLimit, i.e. fails open under load, which§3.4 forbids. Named as a design fork rather than picked.
B3 —
doctorreported OK with every enforcement gate deletedmissingandmarkerlesswere excluded from DRIFT, so deleting all three enforcement surfacesproduced
Stack status: OK, exit 0. SPEC §3.4: "Failing open MUST NOT be silent."New
StatusReport.GateAbsences(json:"gate_absences") is the only non-advisory list and flipsOverall. Scoped to three surfaces, reported only when the repo is initialised, is a git repo, andgit.enforce_commitsis true.Suppressed for
agents.claude:false, for no sibling workflow installed, and in linked worktrees —there
.gitis a file,probeHookcannot see the shared hooks dir, and this repo's own worktrees weremeasured reporting a hook that is in fact installed and firing. Escalating that would flip every
worktree to exit 1 over a present gate, unfixable by
--fix.Opt-out is
git.enforce_commits: false, which already means "logmind does not gate commits here" toguard-commit, the config template and AGENTS.md. A second key would be a second owner for one fact.
Accepted cost: local-off/CI-on is not expressible.
Notes for review
internal/decisions/decisions.gois one additive hunk — 46 insertions, 0 deletions, 0 modifiedlines. Three further literal-routings were reverted because they sat on lines PR fix(config): refuse an agent's attempt to weaken a blocking setting — closes #330 #346's lane is
editing; the deferral is noted in the const doc.
GateAbsences(drift) vsGateAdvisories(advisory) — different names, different semantics, mechanical reconcile.go test ./... -count=1 -timeout 45m→ exit 0 from isolatedwt-b13;go vetclean;gofmt -l .empty. Source sha identical start→end of the run.Filed separately from this lane's out-of-brief findings: #353 (hooks resolve the default branch in
shell, hard-fallback
main) and #270 (bare-name engine resolution).