Repository navigation
block-hook-bypass: echo the concrete Write call for the blocked target (option B from #4261) #5668
Description
Scope (owner decision 2026-10-12, recorded 2026-10-13): measure which tool follows each denial first, then choose between accept and briefing. This issue builds the measurement field only. It does not build option B or change the denial message. The run and the choice are split to #8986.
Follow-up to #4261, filed under its owner decision: file option B only if block-hook-bypass rejections are still followed by failed retries.
Evidence
Post-release transcript join (records after 2026-09-30T02:17Z, 129 sessions, this WSL machine's local transcripts only). Attribution is by message string, not guard name.
block-hook-bypassrejections: 2039 by message string (2041 in the retry scan).- 1422 of 2041 were followed by a successful Write/Edit with no failure in the next 2 tool calls (one correction).
- 86 of 2041 (4.2%) had another failed or blocked call in the next 2 tool calls; 55 kept retrying; 23 immediately repeated the same bypass block.
- Overall blocked/denied
tool_resultrecords: 2466, median 0 per session, mean 19.12, max 1227; excluding the 3 largest sessions mean 0.54, max 39 (baseline 17).
Option B
The block-hook-bypass message echoes the concrete Write call for the blocked target instead of only naming the Write/Edit remedy. This grows the message #4679 shortened, and the guard parses shell strings heuristically, so reconstructing the target path and content may be unreliable.
Decision needed
The owner chose option A on #4261 (keep the existing remedy). Whether a 4.2% failed-retry tail justifies option B is the owner's call; nothing is implemented.
The owner's later decision (2026-10-12) is to measure first; see the scope line above and #8986.
Split to #8986: run /session-flow:audit-friction on both machines over post-2026-10-04 denials, the owner's accept-or-briefing choice, and the re-measure after any change.
Done when (this issue: the next-tool field)
-
plugins/session-flow/skills/audit-sessions/scripts/friction_scan.pyaddsnext_tool(and whether that call succeeded) to each hook-block denial event, derived from the nexttool_use/tool_resultin the same transcript file (the scanner already walks records in order:add,_assistant,_tool_result, :190-274). Check: the PR's CI runsplugins/session-flow/skills/audit-sessions/scripts/tests/test_friction_scan.py(pytest) and it passes. -
plugins/session-flow/skills/audit-friction/scripts/friction.py mineaggregatesnext_toolper event key and side, in both JSON and md output. Check: the PR's CI runsplugins/session-flow/skills/audit-friction/scripts/tests/test_friction.pyand it passes. -
test_friction_scan.pycovers three cases: next call is Write/Edit, next call repeats the shell form, and no next call. Check: as above. - A
.changes/session-flow/fragment exists. Check:scripts/new-changelog-fragment.sh, and the PR's CI runsscripts/check-changelog-fragments.sh --checkand it passes.
Activity
kyle-sexton commentedon Oct 3, 2026
A second machine's transcripts (Windows 11, Git Bash, 764 sessions plus 4,041 subagent transcripts, 2026-08-28 to 2026-10-03, Claude Code 2.1.241 to 2.1.288) add data for this decision. Counts come from a finder pass re-derived by an independent verifier; where they differed, the verifier's number is used.
Volume. block-hook-bypass is the first
BLOCKED:reason on 1,620 of 2,948 denials (55%). By ISO week: W38 433, W39 578, W40 353 in about 5.2 days, so the volume has not fallen since the #4679 message cut (merged as #4711).Rate per caller. 1,265 of the 1,620 came from subagents, which also made 76.3% of shell calls. Per 1,000 shell calls: main 10.33, subagents 11.42. Subagents are not worse per call; they make most of the calls.
Retries. Of the denials not user-rejected, cancelled or interrupted, 314 of 1,654 block-hook-bypass denials (19%) were followed within two assistant messages by a same-tool call at least 60% similar, 22 of them repeated loops. So about 81% change approach after one denial, consistent with this issue's WSL figure (1,422 of 2,041 followed by a successful Write/Edit).
The remedy line is already there. All 1,643 block-hook-bypass denials on disk carried "Use the Write or Edit tool instead of a shell file-write workaround." On current
origin/mainit isplugins/guardrails/hooks/block-hook-bypass.sh:1376, present since the guard's first commit (303d0ba, #118) and kept by #4711.What this suggests for the decision (inferred, not verified). The denial text is not the gap; option B would grow a message the model already acts on. The steady rate of about 10 attempts per 1,000 shell calls in both main and subagent contexts points at how agents are briefed. A third option beside A and B: where plugins brief workers (subagent dispatch templates), state that files are written with the Write or Edit tool, then re-measure the per-1,000 rate. #5993 step 1 (measure which denials lanes hit, by source) overlaps and could carry the measurement: for each block-hook-bypass denial, which tool the next call in the same transcript used.
Options as the producing session framed them, for the owner: (1) accept the volume as the guard working as designed; (2) address briefing first, as above; (3) recommended by that session: measure the next tool after each denial first, then choose between 1 and 2.
kyle-sexton commentedon Oct 3, 2026
Corrects the per-caller rate in the second-machine comment above.
"Subagents are not worse per call" is wrong. The verifier's counts give 355 block-hook-bypass denials in 34,357 main-context shell calls (10.33 per 1,000) and 1,265 in 110,781 subagent shell calls (11.42 per 1,000), so subagents hit the guard about 10.5% more often per shell call. Subagents still account for most of the volume because they make 76.3% of shell calls, but the rate is not equal. The later sentence "about 10 attempts per 1,000 shell calls in both main and subagent contexts" should read: about 10 per 1,000 in main contexts and about 11 per 1,000 in subagents. The inferred point that briefing, not the denial text, drives the volume is unchanged; if the briefing option is tried, re-measure both rates separately.
Anchor, for the code citation. On
origin/mainthe remedy line is echoed insideblock_bypass(), which starts atplugins/guardrails/hooks/block-hook-bypass.sh:1372; the line itself is at:1376as already cited, and is skipped only for thepowershell-computed-positionalform (:1375).Source: local handoff item 20261003-101457-corrections-to-6073-and-6074-6080 (retired into these comments).
kyle-sexton commentedon Oct 4, 2026
This was generated by AI during triage.
Agent Brief
Type: Feature
Summary: The owner decides how to respond to the
block-hook-bypassfailed-retry tail: echo the concrete Write call in the denial (option B), fix how agents are briefed, or accept the current volume.Current behavior:
Every
block-hook-bypassdenial already tells the model to use the Write or Edit tool instead of a shell file-write workaround. Measurements on two machines show about 81% of denials change approach after one denial, and 4.2% (one machine) to 19% (the other) are followed by a similar retry. There are about 10 denials per 1,000 main-context shell calls and about 11 per 1,000 subagent shell calls. Volume has not fallen since the message was shortened.Desired behavior:
Depends on the decision:
Acceptance criteria:
Out of scope:
block-hook-bypassblocksRouting: human-gated (needs decision)
The owner chose option A on #4261, and this issue asks whether the new evidence changes that ruling. That is a product call. Recommended: measure first. For each denial, record which tool the next call used, then choose between options 1 and 2. Option B has the weakest evidence: the denial text already names the remedy, and most agents act on it.
Overlap: #5993 (already triaged,
work-class: read-only) has step 1, "measure which denials lanes hit, by source", which could carry that measurement. It is not the same decision, so I did not cluster it.Basis: verified. The remedy line is echoed in
block_bypass()at plugins/guardrails/hooks/block-hook-bypass.sh:1376, per the second-machine comment and its correction. #5993's labels were read this session.kyle-sexton commentedon Oct 13, 2026
Decision recorded. The owner approved applying independently verified recommendations on 2026-10-12.
Basis: block-hook-bypass: echo the concrete Write call for the blocked target (option B from #4261) #5668 comments 2026-10-03 (1,643 of 1,643 denials carried the remedy; ~81% change approach; 10.33 vs 11.42 per 1,000); plugins/guardrails/hooks/block-hook-bypass.sh:1368 (echo 'BLOCKED: $reason. Use the Write or Edit tool.'); fix(guardrails): cut block-hook-bypass messages to what the agent can act on (#4679) #4711 merged; feat(autonomy): cut permission prompts and guard denials that interrupt autonomous lanes #5993 open
Asks whether the block-hook-bypass denial should echo a concrete Write call (option B) given a failed-retry tail after denials. Two machines show about 81% of agents change approach after one denial and every denial already names the Write/Edit remedy, so the open choice is accept, fix worker briefing, option B, or measure first.
Verification notes:
Verified by an independent fresh-context check (confirmed, risk low): gh issue view 5668 (3 comments; owner option A on #4261 is cited, no new owner decision); origin/main plugins/guardrails/hooks/block-hook-bypass.sh:1364-1369 (block_bypass, remedy echo at :1368); git log block-hook-bypass.sh (#6303, #7261, #5997); gh pr view 6303 (body: message cut, Closes #4679), 6710 (merged), 6708 (CLOSED 2026-10-10, owner option A keeps main's guard); gh issue view 5993 (OPEN, one triage comment, step 1 read-only); gh pr view 6692 body (audit-friction, Related #5993)
Admission to an agent lane stays with the work-class rules and owner ratification.
melodic-automation-lanes commentedon Oct 22, 2026
The lanes App's pull request #9174 links this issue with
Refs:, notCloses, so the merge lane never merges it. report-outcome addedneeds-humanso a person merges or closes it. When it merges, work-unblock removes thisneeds-humanandagent-readyand addsneeds-triage, so triage decides what work is left. To keep the issue held after the merge, addneeds-owner-decision.melodic-automation-lanes commentedon Oct 23, 2026
The lanes App's pull request #9174 merged with
Refs:, so this issue stays open and nothing starts the lane on it again. work-unblock addedneeds-triageand removedagent-ready, so triage decides what work is left.kyle-sexton commentedon Oct 23, 2026
Done in #9174:
friction_scan.py:242,298recordsnext_tool/next_okon each hook-block denial;friction.py minetallies them per side and key in JSON and markdown (friction.py:173-193,234-240); tests cover Write-next, repeated shell form and no next call (test_friction_scan.py:229-245); the changelog entry shipped (plugins/session-flow/CHANGELOG.md:13). The measurement run, the accept-or-briefing choice and the re-measure continue in #8986.