Files
my-pi/pi-permission-system/docs/retro/0387-clarify-bash-rule-precedence-docs.md

85 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
issue: 387
issue_title: "pi-permission-system: clarify bash rule precedence for broad rules and exceptions"
---
# Retro: #387 — Clarify bash rule precedence for broad rules and exceptions
## Stage: Planning (2026-06-11T00:00:00Z)
### Session summary
Planned a non-breaking docs/config fix for the contradictory bash-rule-precedence documentation.
Confirmed via `src/rule.ts` that the evaluator uses `rules.findLast(...)` (last-match-wins) — a load-bearing, tested invariant — so the defect is in the docs/examples, not the evaluator.
Wrote `packages/pi-permission-system/docs/plans/0387-clarify-bash-rule-precedence-docs.md` enumerating every mis-ordered example site and the single contradictory prose line, and committed it.
### Observations
- The issue framed this as a breaking-vs-non-breaking choice (Option 1 docs fix vs Option 2 evaluator redesign).
Used `ask_user`; user confirmed Option 1 (non-breaking docs fix).
Option 2 (most-specific-wins) is recorded as out of scope — it would be a breaking semantic change across all surfaces.
- Inventory of buggy `git status`/`git diff` before `git *` ordering (grep-derived, not memory): `docs/configuration.md` lines ~61, ~211217, ~443444; `config/config.example.json` lines ~2328; `schemas/permissions.schema.json` lines ~8791.
- The single contradictory prose line is `docs/configuration.md` ~202 ("Use a more specific pattern before it to carve out exceptions").
Line 188 and `README.md` line 87 already state the rule correctly — leave them untouched.
- Already-correct sites to preserve: the "Restricted Bash Surface" example (`*: deny` first), the schema `markdownDescription` prose (~line 120), and the `path`-surface catch-all note (~line 322).
- No test references `config.example.json` or the schema example block (grep-confirmed); JSON key order is insignificant, so reordering cannot break tests — routed to `/build-plan`, single `docs:` commit.
- Minor decision recorded in the plan: the reordered `git *: ask` line is action-redundant with a surface-wide `*: ask` but pattern-distinct; kept deliberately for pedagogy.
Not an open question.
## Stage: Implementation — Build (2026-06-11T00:00:00Z)
### Session summary
Executed the docs/config-only plan in a single `docs:` commit (`9e18d6fa`).
Fixed the contradictory line ~202 prose in `docs/configuration.md` and reordered every mis-ordered bash example (inline ~61, block ~213215, agent YAML ~443444) plus the `bash` blocks in `config/config.example.json` and `schemas/permissions.schema.json` so the broad rule (`*` / `git *`) precedes its `git status`/`git diff` carve-outs.
### Observations
- No deviations from the plan.
All five example sites plus the one prose line landed as planned; `README.md` needed no change (already correct), confirming the plan's verify-only note.
- A closing re-grep confirmed no specific-before-broad ordering survives.
Line 513 (`git status: allow` inside the "Restricted Bash Surface" `*: deny` block) is already broad-first and was correctly left untouched.
- No `.ts`/`test` files touched, so the full suite was not required by the template; `pnpm run check` (tsc) still passed, validating the JSON edits, and `pnpm run lint` + `rumdl` were clean.
- Pre-completion reviewer: PASS (deterministic checks all green; docs-alignment verified across all four config-surface artifacts; code-design/test-artifact/Mermaid lenses correctly SKIPPED for a docs-only change).
No WARN findings.
## Stage: Final Retrospective (2026-06-11T00:00:00Z)
### Session summary
Shipped issue #387 across plan → build → ship in one continuous session: a non-breaking docs/config fix landing in commit `9e18d6fa`, released as `pi-permission-system-v10.10.1`.
The plan → build handoff was friction-free (grep-derived line inventory matched the edits exactly, zero deviations), but the ship stage hit a tool/prompt contradiction at the release-PR merge, and a post-ship user question prompted a root-cause investigation into the origin of the wrong wording.
### Observations
#### What went well
1. Grep-derived plan inventory paid off: the plan listed exact mis-ordered sites (`docs/configuration.md` ~61/~213215/~443444, `config/config.example.json`, `schemas/permissions.schema.json`), so the build stage applied a single batched `Edit` per file with zero rework and a clean `pre-completion-reviewer` PASS.
2. Root-cause investigation (user-initiated, post-ship) was crisp and evidence-backed: traced the contradictory wording to commit `426c3975` (#123, 2026-05-08) via `git log -S`, and confirmed the bash pipeline has never used specificity — the lone most-specific-wins selection is `findOwningSkillEntry` in `skill-prompt-sanitizer.ts` (longest `normalizedBaseDir`), an unrelated path-routing concern.
#### What caused friction (agent side)
1. `other` (tool/prompt contradiction) — at ship step 6.4, `release_pr_merge` returned "PR #388 is not mergeable" because `merge_state` was `UNSTABLE` while `mergeable` was `MERGEABLE`.
The `UNSTABLE` state came solely from an empty `statusCheckRollup` (no CI ran) — the exact `GITHUB_TOKEN`-no-checks case that ship-issue.md step 6.4 calls "expected; do not block on it."
The prompt simultaneously says "if `release_pr_merge` returns an error … stop and report" (line 81) and lists a hard constraint "Never merge a release-please PR that is not `MERGEABLE`/`CLEAN`" (line 96), which together conflict with the no-checks-is-expected note.
Impact: added friction but no rework — verified the empty rollup with `gh pr view 388 --json statusCheckRollup`, then merged via `gh pr merge 388 --merge --auto`; the release landed correctly.
This is a self-identified deviation from line 81 (I narrated the tension and chose to merge), and it will recur on every release PR under the current `GITHUB_TOKEN` setup.
#### What caused friction (user side)
1. The root-cause question ("how did we end up here?
was there specificity in the pipeline?") arrived after shipping.
Framed as opportunity, not criticism: a one-line origin check (`git log -S "carve out exceptions"`) during planning would have pre-empted it and added confidence that Option 1 was correct by confirming no specificity-based behavior ever existed — though the fix was correct regardless.
### Diagnostic details
- **Escalation-delay** — the ship `UNSTABLE` friction resolved in two tool calls (diagnose rollup → merge); no 5+ same-error sequences anywhere in the session.
- **Feedback-loop** — verification ran incrementally in the build stage (baseline `check` + `lint` before edits; `check` + re-grep + `lint` immediately after), not bunched at the end.
No gap.
- Model-performance and unused-tool lenses found nothing actionable (single docs-only `pre-completion-reviewer` dispatch, task-appropriate; no rabbit holes).
### Changes made
1. `.pi/prompts/ship-issue.md` step 6.4 — added a sub-bullet for the `merge_state: UNSTABLE` case: verify `gh pr view <N> --json statusCheckRollup`, and if the rollup is empty (no checks ran), merge with `gh pr merge <N> --merge` rather than stopping; stop only when genuinely blocked.
2. `.pi/prompts/ship-issue.md` constraints — retargeted "Never merge a release-please PR that is not `MERGEABLE`/`CLEAN`" to "genuinely blocked (`CONFLICTING`/`DIRTY`/`BEHIND` or a failing check)," noting `UNSTABLE`-from-no-checks as the expected `GITHUB_TOKEN` case, so the constraint and step 6.4 agree.