feat: vendor permission system source

This commit is contained in:
云服务部-叶林立
2026-08-19 14:35:19 +08:00
parent 198584daf8
commit 410c50a3e5
809 changed files with 157793 additions and 139 deletions
@@ -0,0 +1,46 @@
---
issue: 65
issue_title: "Synthesize defaults into ruleset and unify the evaluate path"
---
# Retro: #65 — Synthesize defaults into ruleset and unify the evaluate path
## Final Retrospective (2026-05-04T09:50:00-04:00)
### Session summary
Synthesized `defaultPolicy` and `tools.bash`/`tools.mcp` overrides as `Rule` objects in a composed array, eliminating the `bashDefault`, `mcpToolLevel`, and `hasAnyMcpAllowRule` side-channel values from `ResolvedPermissions`.
`checkPermission()` now passes all decisions through `evaluate()` and accepts an optional `sessionRules` parameter, removing the separate session pre-check from `tool-call.ts`.
Nine commits landed across three phases (plan, TDD, docs); released as v3.11.0 with no user-visible behavior change.
### Observations
#### What went well
- Pre-implementation analysis caught two plan errors before any code was written: the `source` field derivation table incorrectly mapped `tools.bash` override to `source: "tool"` (actual: `source: "bash"`), and the composed ruleset ordering needed to be defaults → baseline → overrides → config (not defaults → overrides → baseline → config) to preserve `tools.mcp` precedence over MCP baseline.
Both were corrected during implementation without rework.
- The full 80-test `permission-system.test.ts` suite passed on the first run after the `checkPermission()` rewrite (`dac47c1`), confirming the behavioral equivalence claim.
- The `Rule.layer` metadata approach cleanly separated evaluation (unchanged `evaluate()`) from presentation (`source` derivation) without positional index arithmetic.
#### What caused friction (agent side)
1. `instruction-violation` — Used `cat >> tests/permission-system.test.ts << 'EOF'` via `Bash` instead of the `Edit` tool to append integration tests.
This triggered the permission system's own bash gate, requiring user approval.
Root cause: the `Edit` tool's `oldText` matched 3 occurrences of `});` at the end of the file; instead of reading more trailing context to find a unique match, I fell back to bash.
Impact: added friction (user had to approve the bash command) but no rework.
User-caught (user asked "Is that expected?").
2. `wrong-abstraction` — The plan listed 13 TDD steps, but steps 25 (synthesize module) and steps 810 (`ResolvedPermissions` + `checkPermission` + `getToolPermission`) shared types so tightly that they could not be split into independent red→green→commit cycles without leaving the suite broken between commits.
Both clusters were committed as single logical units with a deviation note.
The existing `AGENTS.md` testing rule about shared type definitions correctly predicted this, but the plan still listed them separately.
Impact: added friction during commit organization but no rework.
Self-identified.
#### What caused friction (user side)
- The `cat >>` bash command approval was the only user intervention beyond autoformat hooks.
If the agent had widened `oldText` context instead of switching tools, this would not have occurred.
### Changes made
1. Updated `AGENTS.md` lines 2931: replaced stale `tools.bash`/`tools.mcp` warning ("Do not normalize them into the Ruleset") with current description referencing `synthesizeOverrides()` in `src/synthesize.ts`.