Files
my-pi/pi-permission-system/docs/retro/0056-unify-rule-normalize-config.md
T

3.7 KiB
Raw Blame History

issue, issue_title
issue issue_title
56 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.