## Approval Desk\:&#32;ordered shell rules

Nia now reviews a shell\-policy list\.&#32;She expects a deny anywhere in the list to win\.&#32;The implementation instead chooses the&#32;**first applicable rule**\.&#32;Whether a rule is applicable depends partly on its approval value\.

This makes ordering part of the policy\,&#32;not merely its formatting\.

### Inspect strings without running them

The following is a complete fictional classification input from&#32;`bash-first-applicable-rule`\.&#32;It is not a shell exercise and is not a configuration recommendation\.

~~~json
{
  "command": "printf seed-card",
  "patterns": [
    { "match": "printf *", "approval": "allow" },
    { "match": "*", "approval": "deny" }
  ],
  "mode": "always-ask"
}
~~~

**Prediction\:**&#32;does the final catch\-all deny block this string\?

**Recorded answer\:**&#32;no\.&#32;The first rule applies\.&#32;`BashTool.approval()`&#32;returns an explicit tool allow at write tier\,&#32;and the resolver returns allow from tool policy\.&#32;No shell command was executed by this scenario\.

The existing&#32;`approval.test.ts`&#32;also covers a broad early&#32;`*`&#32;allow shadowing a later matching deny\.&#32;Therefore “there is a deny later” is not sufficient evidence of an effective denial\.

### Understand what matching means

`bash.patterns`&#32;is an ordered array of objects with&#32;`match`&#32;and&#32;`approval`\.&#32;In the supplied implementation\:

- Only&#32;`*`&#32;is a wildcard\.&#32;Other regular\-expression\-looking punctuation is escaped\.
- Pattern and command whitespace is normalized before matching\.
- Policy values are normalized\;&#32;malformed rule entries are discarded by the rule reader\.
- An allow must match the whole command and pass the shell\-control heuristic\.
- A deny or prompt may match the whole command or a tokenized segment of a compound command\.
- The first rule that applies under those semantics is selected\.

The matching is not a shell security parser\.&#32;It does not certify executable identity\,&#32;the behavior of scripts or binaries\,&#32;environment\-dependent behavior\,&#32;or every form of shell interpretation\.

The allow heuristic does distinguish some literal quoted metacharacters from active shell control\.&#32;The existing tests cover a quoted literal pattern that remains allowable\,&#32;as well as expansion\,&#32;redirection\,&#32;compound syntax\,&#32;and arguments reinterpreted through command\/eval options that do not ride a narrow allow\.&#32;Those are useful classification contracts\,&#32;not an exhaustive shell\-language proof\.

### Change the command shape\,&#32;not the rule order

Now read&#32;`bash-compound-deny-segment`\:

~~~json
{
  "command": "printf seed-card && printf closed",
  "patterns": [
    { "match": "printf *", "approval": "allow" },
    { "match": "printf closed", "approval": "deny" }
  ],
  "mode": "yolo"
}
~~~

**Prediction\:**&#32;does the first allow still apply because the text begins with&#32;`printf`\?

**Recorded answer\:**&#32;no\.&#32;The compound line cannot use that allow\.&#32;The second rule matches a segment\,&#32;so the decision is tool\-owned deny with reason&#32;`Blocked by bash pattern: printf closed`\.&#32;Yolo does not remove the selected explicit denial\.

This explains why “first matching” must include the rule’s semantics\.&#32;It does not mean “first textual prefix\.”

### Critical heuristics have another ordering boundary

After selecting a rule\,&#32;`BashTool.approval()`&#32;does the following\:

1. If the selected rule says deny\,&#32;return explicit deny immediately\.
2. Otherwise\,&#32;check&#32;`CRITICAL_BASH_PATTERNS`\.
3. If a critical pattern matches\,&#32;return exec with&#32;`override: true`&#32;and reason&#32;`Critical pattern detected`\,&#32;but no explicit prompt policy\.
4. Only then return the selected allow or prompt\,&#32;if any\.
5. With none of those decisions\,&#32;return exec\.

For the next three cases\,&#32;the command field is the inert string&#32;`chmod -R 700 /fictional-seed-library`\.&#32;It is included to classify a recursive absolute\-path permission change\.&#32;**Never execute it\.**

| Case | Rule and mode | Recorded resolution |
| --- | ---: | --- |
| `bash-critical-before-allow` | `chmod *`&#32;allow\;&#32;write mode\;&#32;user bash allow | prompt\,&#32;exec\,&#32;override true\,&#32;source tool |
| `bash-critical-yolo` | Same allow rule\;&#32;yolo | allow\,&#32;exec\,&#32;override false\,&#32;source mode |
| `bash-selected-deny-before-critical` | `chmod *`&#32;deny\;&#32;yolo | deny\,&#32;exec\,&#32;override true\,&#32;source tool |

The critical result in the first two rows is an override\-only decision\.&#32;That is why yolo can bypass it\.&#32;The third row is an explicit denial returned before the heuristic and remains denied\.

There is a further consequence worth predicting from source\:&#32;a selected prompt rule does not necessarily survive as an explicit prompt decision when the critical branch returns first\.&#32;The selected rule is found first\,&#32;but the critical branch is evaluated before selected allow\/prompt is returned\.&#32;Do not turn a catch\-all prompt rule into a guarantee that every critical string will prompt in yolo\.

For comparison\,&#32;`bash-explicit-prompt-yolo`&#32;uses the noncritical&#32;`printf seed-card`&#32;string and a&#32;`printf *`&#32;prompt rule\.&#32;**Recorded\:**&#32;it remains a tool\-sourced prompt in yolo\,&#32;even with user bash allow\.&#32;Here the explicit prompt branch was actually reached\.

### Repair an explanation before repairing a policy

When a result surprises you\,&#32;write down the selected rule and the branch reached after selection\.&#32;If you cannot identify the first applicable rule\,&#32;rearranging or broadening the list is premature\.&#32;Keep approval patterns separate from&#32;`bashInterceptor`&#32;rules\:&#32;the latter are another execution\-time mechanism for directing work toward dedicated tools\,&#32;not the same ordered approval array\.

**Paper checkpoint\:**&#32;why does a selected deny survive yolo while the critical override\-only result can be allowed\?&#32;**Worked answer\:**&#32;explicit denial is resolved before the yolo branch\;&#32;an override flag without an explicit policy is ignored by that branch\.

**Failure boundary\:**&#32;the six private bash cases called the real declaration and resolver only\.&#32;They did not call&#32;`BashTool.execute()`\.&#32;Neither their passing classifications nor the existing pattern tests establish a shell sandbox\.

**Source anchors\:**&#32;`packages/coding-agent/src/tools/bash.ts`&#32;—&#32;`getBashApprovalPatternRules`\,&#32;`bashApprovalRuleMatches`\,&#32;`findBashApprovalPatternRule`\,&#32;`hasBashApprovalShellControl`\,&#32;`CRITICAL_BASH_PATTERNS`\,&#32;`BashTool.approval`\;&#32;`packages/coding-agent/src/tools/approval.ts`&#32;—&#32;`resolveApproval`\;&#32;`packages/coding-agent/test/tools/approval.test.ts`&#32;— ordered\-pattern\,&#32;compound\-command\,&#32;and critical\-pattern tests\.
