Repository navigation
Issue #173 - #182
Issue #173#182
Conversation
…ication, agy scratch, quota-gate coverage (#173) Four independent fixes from the agy-lane incident report (claimed-unposted APPROVE, repetition-loop hang, stray root scratch files): 1. Verdict-ordering invariant: AGENTS.md gains a relay rule (no lane relays a verdict it can't see on the PR) and an explicit Gate-2 checklist step (verify the verdict is ON the PR before gh pr ready); review-protocol.md makes publish-to-PR a precondition of reporting the verdict anywhere. 2. lib/watch.sh pane_stuck_check now classifies by SHAPE, not just a screen-hash diff: idle-prompt shape (reusing dispatch.sh's own hook-independent heuristic, split into pane_tail_is_idle_shape) is noted as probable stale-BUSY (#105) instead of flagged stuck; runaway-output shape (new wsc_tail_is_runaway) flags degenerate repetition immediately instead of waiting for a hash comparison that would never fire; unchanged-screen still means looping/stuck for panes not at a prompt. 6 new canned-shape tests. 3. templates/GEMINI.md + live GEMINI.md gain an explicit .harness/scratch/agy/ convention, mirroring the Claude lanes' scratch-dir discipline. .gitignore gains pr*.diff/pr*_body.txt so stray review scratch can't ride a later commit even without agy adopting the convention. 4. Quota-gate coverage audit (lib/gatekeeper.sh): budgets.agy.failsafe_pct was read correctly but the standalone "agy over threshold" branch never wrote the shared quota-stop flag every OTHER threshold branch writes -- agy could burn quota past its own failsafe_pct with only an advisory FLAG, no actual PreToolUse enforcement. Fixed with the same ar_write_quota_stop_flag call the other branches already make (no resets_at -- human-clear-only, same as weekly). New tests/gatekeeper-quota-gate.test.sh (gatekeeper.sh's main loop had no prior unit-test seam at all). Closes #173.
|
APPROVE Probe List (Security Pass):
All requirements from the Gate-1 plan are fully and safely implemented. Good to go. |
There was a problem hiding this comment.
🟡 Not ready to approve
The new gatekeeper quota-gate test installs an EXIT trap before initializing SCRATCH under set -u, which can cause the trap to error if the script exits early or is interrupted.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Hardening changes addressing incident learnings from issue #173: enforce “verdict must exist on PR before relaying,” improve pane stuck detection to catch runaway repetition earlier (and avoid false stucks when a pane is actually idle), prevent scratch artifacts from landing in repo root, and ensure agy quota thresholds trigger the same enforcement mechanism as other pools.
Changes:
- Document and enforce verdict-ordering/verification rules in reviewer + Gate-2 protocols.
- Add shape-based stuck classification (idle-prompt note vs runaway-output immediate flag vs unchanged-screen stuck) with new tests.
- Enforce agy quota-stop via shared quota-stop flag; add a focused gatekeeper main-loop test; ignore common review scratch artifacts via
.gitignore.
File summaries
| File | Description |
|---|---|
| tests/watch.test.sh | Adds new stuck-shape classification tests (idle-prompt note, runaway-output immediate flag, false-positive probe). |
| tests/gatekeeper-quota-gate.test.sh | New regression test ensuring agy-only threshold crossing writes the shared quota-stop enforcement flag. |
| templates/review-protocol.md | Documents “publish verdict to PR before reporting it elsewhere” invariant. |
| templates/GEMINI.md | Documents agy scratch directory convention under .harness/scratch/agy/. |
| templates/AGENTS.md | Adds verdict relay rule and Gate-2 checklist step to verify verdict exists on PR before gh pr ready. |
| lib/watch.sh | Implements stuck “shape” classification including runaway repetition detection and idle-prompt note behavior. |
| lib/gatekeeper.sh | Writes quota-stop flag for agy threshold crossings (previously only alerted). |
| lib/dispatch.sh | Extracts pane_tail_is_idle_shape helper for reuse by watch stuck-check logic. |
| .gitignore | Ignores common PR diff/body scratch captures to prevent accidental commits. |
Review details
- Files reviewed: 8/9 changed files
- Comments generated: 1
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| GK_PID="" | ||
| cleanup() { | ||
| [ -n "$GK_PID" ] && kill "$GK_PID" >/dev/null 2>&1 | ||
| rm -rf "$SCRATCH" | ||
| } | ||
| trap cleanup EXIT | ||
|
|
||
| SCRATCH="$(mktemp -d)" |
Summary
Four independent hardening fixes from the agy (Reviewer)-lane incident
report: a claimed-but-unposted APPROVE, a token-repetition hang
misclassified after the fact, and stray scratch files left in the
project root.
Verdict-ordering invariant.
AGENTS.mdgains a relay rule (nolane relays a verdict it can't itself see posted on the PR) and an
explicit Gate-2 checklist step (verify the verdict is present ON the
PR via
gh pr view --json comments,reviewsbeforegh pr ready).review-protocol.mdmakes publishing to the PR a precondition ofreporting the verdict anywhere else (ack/dispatch/pane summary).
Stuck-detector shape classification (
lib/watch.shpane_stuck_check). Previously classified purely on screen-hashdiff, which is anti-correlated with the real failure: a repetition
loop's screen changes constantly (stays silent through the actual
incident) while a post-interrupt idle screen freezes (gets flagged
after the fact, once the danger has passed). Now three shapes:
dispatch.sh's own hook-independentscreen-scrape heuristic, split out as
pane_tail_is_idle_shape) →noted to orchestra as probable stale-BUSY (pane_is_idle residual false-BUSY: woz:code spinner line persists after completion, matches #104's shape-anchored busy markers #105's residual
false-BUSY class), never flagged stuck.
wsc_tail_is_runaway: line-repetition orwhitespace-stripped token-repetition) → flagged immediately, no
baseline wait (a hash comparison would never see "unchanged" here).
looping/stuck, now reached only forpanes genuinely not at a prompt.
6 new canned-shape tests in
tests/watch.test.sh, including alegitimately-repetitive-but-distinct-lines case to probe the
false-positive risk on test logs/progress bars.
agy scratch convention.
templates/GEMINI.md(+ liveGEMINI.md)documents
.harness/scratch/agy/for temporary review artifacts,mirroring the Claude lanes' scratch-dir discipline
(
souls/scribe.md)..gitignoregainspr*.diff/pr*_body.txtsostray review scratch can't ride a later commit even before agy
adopts the convention.
Quota-gate coverage audit (
lib/gatekeeper.sh). Tracedbudgets.agy.failsafe_pctend to end: the config read was alreadycorrectly wired (fallback + loud warning, same as Claude's), but the
standalone "agy over threshold" branch (Claude's own pool still
under threshold) only ever called
gk_alert_orchestra+gk_mark_alerted— it never wrote the shared
state/quota-stopflag every OTHERthreshold branch (Claude 5h, weekly, both) already writes. That flag
is the actual enforcement mechanism both
hooks/quota-stop-gate.sh(Claude) and
lib/guard-quota-stop-agy.sh(agy) gate on — so agycrossing its OWN failsafe_pct alone produced an advisory FLAG and
nothing else: no PreToolUse enforcement, unlike every other pool.
Fixed with the same
ar_write_quota_stop_flagcall the otherbranches make (no
resets_at— agy's pool has no epoch this codebasecan read, so it behaves like a "weekly" flag: human-clear-only via
lib/quota-stop-clear.sh, never silently auto-lifted).gatekeeper.sh's main loop had no prior unit-test seam at all (onlygatekeeper-supervisor.test.sh's crash-loop respawn wrapper existed);added
tests/gatekeeper-quota-gate.test.shusing the samebackground+sleep+kill pattern, with
fetch_claude_usagestubbed soit never touches the real Keychain or makes a live network call.
Test plan
bash -non everybin/*,lib/*.sh,hooks/*.sh(CI's syntax step)tests/*.test.shsuites green (CI's suite,orc-worktree.test.shexcluded per its own live-GitHub-cycle header) — includes the 6 new
shape-classification tests and the new 6-test
gatekeeper-quota-gate.test.shbin/orc-install-skillsscratch-project smoke test (CI's third step)threshold test failed against the pre-fix
gatekeeper.sh, confirmedpassing after)
Closes #173.