Skip to content

Session Handoff [auto-1998]: Keep the Guard's Quote Mask When an Escape Sits Outside the Loop Condition (#1998) #2057

Closed

Description

@ptr727

Next steps

  1. 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.
  2. 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.

What not to repeat

Nothing yet.

New learnings

None yet.

Activity

  1. added
    handoffA link in the session handoff chain, one open issue per track
    on Sep 29, 2026
  2. ptr727 commented on Sep 29, 2026

    @ptr727
    OwnerAuthor

    Parked: waiting on decision #2060

    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 #.

    Self-test rows:

    --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.

  3. added
    blockedBlocked on another issue: one in another repository, or a decision issue here for a parked handoff
    on Sep 29, 2026
  4. ptr727 commented on Sep 29, 2026

    @ptr727
    OwnerAuthor

    Continued in #2073, round 2 on track auto-1998.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    blockedBlocked on another issue: one in another repository, or a decision issue here for a parked handoffhandoffA link in the session handoff chain, one open issue per track

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions