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,52 @@
---
issue: 56
issue_title: "Unify Rule type and normalize config into flat Ruleset"
---
# Retro: #56 — Unify Rule type and normalize config into flat Ruleset
## Final Retrospective (2026-05-03T20:00:00-04:00)
### Session summary
Implemented `normalizeConfig()` in `src/normalize.ts` and `getSurfaceDefault()`/`mergeDefaults()` in `src/defaults.ts`, then refactored `PermissionManager` to store a flat `Ruleset` instead of per-surface compiled pattern arrays.
Removed `BashFilter`, six per-surface type aliases, and `AgentPermissions`/`GlobalPermissionConfig` — replaced by `ScopeConfig`.
Released as v3.9.0 with no user-visible behavior change.
### Observations
#### What went well
- The plan's decision to keep `defaultPolicy` separate from the `Ruleset` was validated by the MCP baseline auto-allow tests — if `defaultPolicy.mcp` had been a catch-all rule, the heuristic would have been bypassed.
The analysis during planning correctly identified this constraint.
- Combining plan steps 1214 into a single commit was the right call.
Attempting separate commits would have introduced intermediate broken states for no reviewability benefit.
#### What caused friction (agent side)
1. `premature-convergence` — The plan confidently stated that `tools.bash: "allow"` normalizes to `{ surface: "bash", pattern: "*", action: "allow" }` and "naturally preserves both tool exposure and command fallback."
This was wrong: `tools.bash` in the old model was a **fallback default** (consulted only when no bash pattern matches), not a **catch-all rule** (always matches and competes with specific patterns from other scopes).
Six tests failed on the first run of the refactored `checkPermission()`.
Impact: required reworking both `src/normalize.ts` (adding `TOOL_SURFACE_OVERRIDE_KEYS` to exclude `tools.bash`/`tools.mcp`) and `src/permission-manager.ts` (adding `bashDefault`/`mcpToolLevel` extraction), plus updating 3 normalize tests.
The `bashDefault` cascade in the old `resolvePermissions()` was visible during planning but its semantic implications were not fully traced.
Self-identified during the implementation phase.
2. `wrong-abstraction` — The plan listed steps 12, 13, and 14 as separate refactoring commits, but all three depend on the shared `ResolvedPermissions` type.
Changing the type in step 12 immediately breaks `checkPermission()` (step 13) and `getToolPermission()` (step 14).
Impact: added ~5 minutes of re-reading to determine they must be combined.
No rework — the combination was straightforward — but the plan was misleading about commit granularity.
3. `instruction-violation` — The pre-commit biome hook rejected the type-alias removal commit due to an unused `getSurfaceDefault` import and a formatting inconsistency.
Running `git commit --amend` after the fix silently folded the type-alias removal into the BashFilter removal commit instead of creating a separate commit.
Impact: two logically distinct changes (BashFilter removal + type alias removal) landed in one commit.
Self-identified via `git log` immediately after.
#### What caused friction (user side)
- The biome warnings in `src/index.ts` and `tests/handlers/before-agent-start.test.ts` were pre-existing but only flagged after the user asked to fix them.
Proactively cleaning lint warnings during the "final verification" step (rather than noting them as pre-existing and moving on) would have avoided the extra round-trip.
### Changes made
1. Added `AGENTS.md` § Implementation Priorities bullet documenting `tools.bash`/`tools.mcp` as fallback overrides excluded from `Ruleset` normalization.
2. Added `AGENTS.md` § Testing bullet about folding tightly coupled TDD steps that share a type definition.