forked from bchanot/claude
GATE 1 is an LLM dispatch and the verifier's mandatory PROOF: line is a line the verifier writes — nothing structurally stops it being produced without anything being executed. Nothing deterministic sat between the executor and that dispatch. An acceptance criterion can now carry an oracle: indented CHECK: (command), EXPECT: (success-only marker), EVIDENCE: (slot). lib/gates.sh runs them fail-closed — MET requires exit 0 AND the marker, so a nonzero process never passes on its error text carrying the token — and writes the outcome back into the contract, so the fresh verifier reads evidence as fact rather than trusting the executor's report. GATE 0 runs that floor before any verifier is dispatched; a red build sends the executor back for free, on its own iteration budget. ABANDON: <id> <reason> turns an impossible criterion into a visible handoff that blocks CONFORME and routes to the human gate, via the new ABANDONED(n) verdict — a distinct token because it routes distinctly, never a dev loop. feater and bugfixer gain a four-pass completion discipline, scoped so a pass can never widen the contract. The runner's parse fails closed on partial oracles, duplicate ids, unindented attributes and runnable criteria with no EVIDENCE: line, and executes nothing at all when the ledger is malformed. status never executes and never writes; run always re-executes, since trusting written evidence is the failure being closed. Adapted from the unlazy skill (Leonxlnx/unlazy, MIT). Its Stop hook, approval store, .unlazy/ tree, depth-tree arithmetic and Node checker were deliberately refused — BDR-083 records each reason. 64 assertions in lib/tests/gates.test.sh, non-execution proved by sentinel with its own positive control asserted first.
88 lines
3.7 KiB
Bash
88 lines
3.7 KiB
Bash
#!/usr/bin/env bash
|
|
# ============================================================
|
|
# Structure locks — contract/verifier pair (verify-loops lot 2)
|
|
# Deterministic greps on load-bearing doctrine clauses: an edit
|
|
# that silently drops one (blind verifier, PROOF mandatory,
|
|
# immutable REQUEST, micro-gate scope enrichment…) reds here.
|
|
# ============================================================
|
|
set -u
|
|
|
|
REPO="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
LIB="$REPO/lib/contract-interview.md"
|
|
AGT="$REPO/agents/verifier.md"
|
|
PASS=0; FAIL=0
|
|
|
|
# Fixed-string lock (UTF-8 punctuation safe)
|
|
tf() { # tf <label> <file> <fixed-string>
|
|
if grep -qF -- "$3" "$2" 2>/dev/null; then
|
|
echo " PASS $1"; PASS=$((PASS+1))
|
|
else
|
|
echo " FAIL $1 — missing: $3"; FAIL=$((FAIL+1))
|
|
fi
|
|
}
|
|
|
|
# Regex lock
|
|
tr_() { # tr_ <label> <file> <ERE>
|
|
if grep -qE -- "$3" "$2" 2>/dev/null; then
|
|
echo " PASS $1"; PASS=$((PASS+1))
|
|
else
|
|
echo " FAIL $1 — no match: $3"; FAIL=$((FAIL+1))
|
|
fi
|
|
}
|
|
|
|
# Negative lock — pattern must NOT match
|
|
tn() { # tn <label> <file> <ERE>
|
|
if grep -qE -- "$3" "$2" 2>/dev/null; then
|
|
echo " FAIL $1 — forbidden match: $3"; FAIL=$((FAIL+1))
|
|
else
|
|
echo " PASS $1"; PASS=$((PASS+1))
|
|
fi
|
|
}
|
|
|
|
echo "── contract-interview.md locks ──"
|
|
if [ -f "$LIB" ]; then
|
|
echo " PASS lib exists"; PASS=$((PASS+1))
|
|
else
|
|
echo " FAIL lib missing: $LIB"; FAIL=$((FAIL+1))
|
|
fi
|
|
tf "verbatim request immutable" "$LIB" "REQUEST (verbatim — IMMUTABLE)"
|
|
tf "contracts dir committed path" "$LIB" ".claude/tasks/contracts/"
|
|
tf "unique per-run slug" "$LIB" "<YYYY-MM-DD>-<slug>-<HHMM>"
|
|
tf "silent when complete" "$LIB" "ZERO questions"
|
|
tf "question budget" "$LIB" "max 3 questions"
|
|
tf "aborted status" "$LIB" "status: aborted"
|
|
tf "never left dirty" "$LIB" "NEVER left dirty"
|
|
tf "scope enrichment micro-gate" "$LIB" "micro-gate"
|
|
tf "gated marker" "$LIB" "[gated <YYYY-MM-DD>]"
|
|
tf "main-loop only" "$LIB" "ORCHESTRATOR MAIN LOOP"
|
|
tf "re-scope supersedes" "$LIB" "supersedes:"
|
|
tf "hand-off = path not content" "$LIB" "contract PATH, not a restatement"
|
|
|
|
echo "── verifier.md locks ──"
|
|
if [ -f "$AGT" ]; then
|
|
echo " PASS agent exists"; PASS=$((PASS+1))
|
|
else
|
|
echo " FAIL agent missing: $AGT"; FAIL=$((FAIL+1))
|
|
fi
|
|
tr_ "frontmatter name" "$AGT" "^name: verifier$"
|
|
tr_ "tools read-only set" "$AGT" "^tools: Read, Grep, Glob, Bash$"
|
|
tn "no write-capable tools" "$AGT" "^tools:.*(Edit|Write|NotebookEdit)"
|
|
tf "verdict grammar" "$AGT" "VERIFY — VERDICT: CONFORME | ECARTS(n) | ABANDONED(n) | ERROR(<reason>)"
|
|
tf "blind — no iteration history" "$AGT" "NEVER receive iteration history"
|
|
tf "blind — complete every time" "$AGT" "every verification is complete and blind"
|
|
tf "unverifiable is not met" "$AGT" "\`UNVERIFIABLE\` ≠ \`MET\`"
|
|
tf "proof mandatory" "$AGT" "\`PROOF\` is MANDATORY"
|
|
tf "contract read from disk" "$AGT" "READ it from disk"
|
|
tf "checked count equality" "$AGT" "checked count in"
|
|
tf "report-only" "$AGT" "Report-only. Never edit"
|
|
tf "bash observation only" "$AGT" "OBSERVATION ONLY"
|
|
tf "loop bound" "$AGT" "Max 3 iterations"
|
|
tf "structural retry then escalate" "$AGT" "2nd structural failure"
|
|
tf "mute never a pass" "$AGT" "A mute verifier is NEVER a PASS"
|
|
tf "conforme first pass no loop" "$AGT" "proceed straight to the security gate"
|
|
tf "reverify order request first" "$AGT" "re-verify the request FIRST"
|
|
|
|
echo ""
|
|
echo "contract-verifier structure locks: $PASS pass, $FAIL fail"
|
|
[ "$FAIL" -eq 0 ]
|