You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Session Handoff [auto-1998]: Keep the Guard's Quote Mask When an Escape Sits Outside the Loop Condition (#1998) #2057
Fix Wait-Loop Bound Check Drops Its Quote Mask on Any Escape in the Command #1998 in host-setup/agent-safety/claude/gh-write-guard.py: requirement 7 false-denies a bounded wait loop whose test has a quoted pure-operator operand (";", ")", "|") whenever an escape (\;, \" inside double quotes, '\'') appears anywhere else in the same command, because _quoted_mask(cmd, toks) re-lexes the whole command without reading escapes, loses token alignment, and drops the mask for every loop. Compute the mask per loop condition, or teach the quote-keeping lex the escapes it misses, keeping the rule that a mask which does not align is dropped rather than trusted. Done looks like: each of the three reproduce commands in Wait-Loop Bound Check Drops Its Quote Mask on Any Escape in the Command #1998 is allowed, a quoted-operator loop with no bound is still denied with an escape elsewhere in the command, self-test rows pin both, and the allow rows fail with the fix reverted. The picker confirmed on develop that _unbounded_wait_loop still denies the first two reproduce commands and allows the same loop with no escape elsewhere.
Drive the pull request to develop per drive-pr, its body carrying Closes on promotion: #1998, then close this lane out.
External blockers
None known.
Internal dependencies
The parked lanes auto-1634 and auto-1910 (branches feature/auto-1634 and feature/auto-1910, both blocked) edit this same file's loop and token-fallback logic. Do not build on either branch or merge its work here. Base on develop and keep the change to the quote-mask path, so any lane can land first and the others rebase over a separate hunk.
State
No branch, worktree, or pull request yet. Work on feature/auto-1998 in a worktree of its own, based on develop.
Parked decisions
None.
What the last round did
Nothing yet. This lane was opened by the unattended-handoff picker.
Done. Branch feature/auto-1998 is pushed at 50fc690e and is based on develop dd4ca98e. It has three commits, and all of them touch only host-setup/agent-safety/claude/gh-write-guard.py:
_marked_lex is an escape-aware lex that matches POSIX shlex token for token (fuzzed, 0 mismatches).
_quoted_mask now uses it.
_UnmodeledSyntax makes the mask fall back to develop's own mask (_quote_kept_mask, moved verbatim) wherever the command holds a backtick outside single quotes, $(/${ inside double quotes, $', or a word-start #.
six deny rows, which pin every fail-open shape the reviews found.
--selftest passes, and ruff and mypy are clean. A local-review receipt is recorded for 50fc690e.
Not done. No pull request is open. The worktree is still standing at /home/pieter/repos/worktrees/ProjectTemplate-auto-1998, but everything in it is committed and pushed.
Why parked. The two local-review edit rounds are spent, and round 3 still raised one introduced finding. A heredoc fed to a shell with an unquoted delimiter is read twice by bash. With an escape elsewhere in the command, develop denies it and the branch allows it, although bash runs it forever. The repro and the options are in #2060. The reviewer's unfinished probe of an escaped backtick inside a bash -c "..." payload is the same double-read class, and it is unverified.
What remains depends on #2060. Under option 1, add two fallbacks to _quote_kept_mask: one for any command holding << (not <<<), and one for a loop read inside a shell-wrapper payload, at _depth > 0 in _unbounded_wait_loop. Add deny rows for both, run local-strict-review, then open the pull request with Closes on promotion: #1998 and drive it to develop.
Filed along the way:#2058 and #2059 (pre-existing false allows on develop), and #2060 (the decision). No lesson issue was filed.
Learned. Once the mask aligns on commands where it used to be None, any place where shlex and bash read the same text differently becomes reachable. The check "mask equals develop's wherever develop's aligned" says nothing about those newly aligned commands. A differential verdict fuzz against develop, with each flip judged against real bash, is what found each new shape.
Activity
ptr727 commentedon Sep 29, 2026
Parked: waiting on decision #2060
Done. Branch
feature/auto-1998is pushed at50fc690eand is based on developdd4ca98e. It has three commits, and all of them touch onlyhost-setup/agent-safety/claude/gh-write-guard.py:_marked_lexis an escape-aware lex that matches POSIXshlextoken for token (fuzzed, 0 mismatches)._quoted_masknow uses it._UnmodeledSyntaxmakes the mask fall back to develop's own mask (_quote_kept_mask, moved verbatim) wherever the command holds a backtick outside single quotes,$(/${inside double quotes,$', or a word-start#.Self-test rows:
'\''case, which fail with the fix reverted;--selftestpasses, and ruff and mypy are clean. A local-review receipt is recorded for50fc690e.Not done. No pull request is open. The worktree is still standing at
/home/pieter/repos/worktrees/ProjectTemplate-auto-1998, but everything in it is committed and pushed.Why parked. The two local-review edit rounds are spent, and round 3 still raised one
introducedfinding. A heredoc fed to a shell with an unquoted delimiter is read twice by bash. With an escape elsewhere in the command, develop denies it and the branch allows it, although bash runs it forever. The repro and the options are in #2060. The reviewer's unfinished probe of an escaped backtick inside abash -c "..."payload is the same double-read class, and it is unverified.What remains depends on #2060. Under option 1, add two fallbacks to
_quote_kept_mask: one for any command holding<<(not<<<), and one for a loop read inside a shell-wrapper payload, at_depth > 0in_unbounded_wait_loop. Add deny rows for both, runlocal-strict-review, then open the pull request withCloses on promotion: #1998and drive it to develop.Filed along the way: #2058 and #2059 (pre-existing false allows on develop), and #2060 (the decision). No lesson issue was filed.
Learned. Once the mask aligns on commands where it used to be None, any place where
shlexand bash read the same text differently becomes reachable. The check "mask equals develop's wherever develop's aligned" says nothing about those newly aligned commands. A differential verdict fuzz against develop, with each flip judged against real bash, is what found each new shape.ptr727 commentedon Sep 29, 2026
Continued in #2073, round 2 on track
auto-1998.