Hooks: a substitution's own quotes are read as the shell reads them, and a printer's name is searched once (#605)
Merged
DO
1d ago+145+145+012345678901234567890123456789-21-21-01234567890123456789
Part of #605, "Hooks: two readings left from #604 that match main's existing behaviour". It fixes items (a), (b) and (c). Items (d), (e), (f) and the new (g) stay open there.
Hooks are mistake guards (decision 0038's triage rule), so this is held to that standard.
What changes
| Item | Before | Now |
|---|---|---|
(a), (c): shell._inside | Counted every " since a held substitution opened, a " in a nested substitution, a comment or single quotes among them | Reads a substitution's own quotes as the shell does: one in a nested substitution is that one's own; a comment or single quotes outside its double quotes hold none. A comment begins where _held begins one: not in a ${...}, not after a substitution's ), not after a character a backslash holds, and at a backtick's start; in a backtick it ends at the backtick |
(b): identity._defined | Searched the whole command once for each command that prints: quadratic, refused at about 4,000 short commands | Keeps each name's answer for the reading: linear. The whole check is now timed on that spelling, beside the reader |
The spellings from the issue that hide an rm are now asked about; main read three of them and let them through. The spellings the reviewers found on the first head are asked about too.
Checks
tests/test_hooks.py::test_a_substitutions_own_quotes_are_read_as_the_shell_reads_them: eleven spellings that are asked about, and two that read as before.tests/test_hooks.py::test_whether_a_command_defines_a_printers_name_is_searched_once_a_name, and a linear-time entry for the whole check.- Decision 0032 gains two rows, naming 12 new mutants; 4 older mutants follow the code.
- At bc8d9867:
make verifypasses;check_decisionsis clean; all 314 mutants oftools/hooks/shell.pyandtools/hooks/identity.pyare killed.
Reviews
All read the first head, e6902c4e. The fixes are in the later commits.
| Reader | Findings | Disposition |
|---|---|---|
| Argon (gemini-4-argon-high) | 2 major, 5 spellings | Fixed in abc691f8 and bc8d9867. The " nested in a double-quoted ${...} is asked about at the head |
| Muse | Not run (quota: 429 until 2026-11-09T00:00Z), owed | ā |
| Astra, standing in for Muse | 1 major: # in ${x:- #} | Fixed in abc691f8 |
| Claude review | 1 major: an untested nested branch; 1 minor | Test and mutants added in 73c6e686. The minor, a gap that is the same on main, is filed as item (g) of #605 |
| Claude security pass | 1 major: $(date)# read as a comment | Fixed in abc691f8 |
š¤ Generated with Claude Code