Development record
2026-10-17 — The headless approver refuses arithmetic on anything but written numbers. Bash evaluates a name it meets in an arithmetic context as arithmetic in turn, so a value the line does not fix can hold an array index that runs a command the line never names. The approver reads the whole command text, quotes and here-documents included, and refuses a name, a quote or an expansion in (( )), $(( )), $[ ] and a for (( )) header, the number tests and -v of [[ ]], let and integer or name-reference declarations, a non-numeric array index or substring offset, ${!name}, and a variable name not written in the line handed to read, unset, printf -v, wait -p, test -v or a declaration. [ and test compare numbers without evaluating them and stay approved. Reading the text whole over-refuses a script that only quotes such a construct, which the agent can write another way; a reader that tracked quoting could be misled by what a quote hides. This refines dcn-2610170937000859.
2026-10-17 — The headless approver refuses arithmetic on anything but written numbers. Bash evaluates a name it meets in an arithmetic context as arithmetic in turn, so a value the line does not fix can hold an array index that runs a command the line never names. The approver reads the whole command text, quotes and here-documents included, and refuses a name, a quote or an expansion in (( )), $(( )), $[ ] and a for (( )) header, the number tests and -v of [[ ]], let and integer or name-reference declarations, a non-numeric array index or substring offset, ${!name}, and a variable name not written in the line handed to read, unset, printf -v, wait -p, test -v or a declaration. [ and test compare numbers without evaluating them and stay approved. Reading the text whole over-refuses a script that only quotes such a construct, which the agent can write another way; a reader that tracked quoting could be misled by what a quote hides. This refines dcn-2610170937000859.
Frontmatter
| id | dcn-2610170944153720 |
|---|---|
| type | decision |
| date | 2026-10-17 |
.abcd/work/decisions/dcn-2610170944153720-the-headless-approver-refuses-arithmetic.md
open on GitHub ↗ · commit history ↗
mentions2
- dcn-26101709370008592026-10-17 — Refines dcn-2610170805446355: the text an approval hands back is cd -- '<dir>' && /bin/bash --noprofile --norc -p -c '<command>'. It drops exec, because the host joins its own text after the approved one (&& pwd -P >| <file>, its record of the shell's working directory), which must still run, and exec guards nothing the agent controls. It adds -p after the long options, since bash 3.2 refuses a long option after a short one, so bash ignores BASH_ENV, functions exported as BASH_FUNC_* and SHELLOPTS from the environment, and the approved command runs under /bin/bash with its profile, rc and environment start-up files ignored. The check of the text handed back accepts exactly that shape and nothing else. And a command holding a NUL byte is refused under the new id command-holds-nul before the guard reads it, since the guard's reading removes a NUL before it reads a word, so the command it would judge is not the one sent.
- dcn-26101711123847122026-10-17 — The headless approver closes the arithmetic routes a review found by reading the text as bash will read it where that is cheap: it joins a backslash-newline before scanning, refuses an alias or alias expansion turned on, a $'…' string that writes a byte by its code, and a builtin whose operands bash may read as arithmetic spelled with a quote or a backslash in its name; it reads a substring offset on any parameter and an array index only in an assignment, an expansion or a name a builtin is handed, so a regular expression's character class is no longer refused. It stops there by decision, not by oversight: on the default branch a launched role is granted the shell with no approver at all, so every route the approver misses is one the run has today; reading a shell line well enough to refuse every hidden command is not finite; and the approver stays a mistake filter (adr-42), with the boundary for launched agents the OS sandbox spec (spc-2610161751056096). Grounds: the default branch grants Bash in the implementer and reviewer roles (internal/core/implement/loop/drive.go). Refines dcn-2610170944153720.