Files
my-pi/pi-permission-system/docs/retro/0108-extract-policy-loader.md
T

3.2 KiB
Raw Blame History

issue, issue_title
issue issue_title
108 refactor: extract PolicyLoader from PermissionManager

Retro: #108 — extract PolicyLoader from PermissionManager

Final Retrospective (2026-05-07T02:00:00Z)

Session summary

Extracted all file I/O and mtime caching from PermissionManager into a new PolicyLoader interface + FilePolicyLoader class. Added 34 new tests including 25 in-memory stub tests that exercise merge and evaluation logic without touching the filesystem. Released as v5.5.0.

Observations

What went well

  • The user's intervention during planning — asking to add test impact analysis (what new tests are enabled, what existing tests become redundant) — significantly improved the plan quality. This two-question framework ("what can we now test that we couldn't before?" / "what existing tests are now redundant?") is a reusable pattern for extraction refactors.
  • The TDD cycle was notably clean for steps 13: all tests passed on first attempt. The in-memory PolicyLoader stub pattern worked exactly as designed, producing 25 tests that are faster, simpler, and more focused than their filesystem-dependent equivalents.
  • Backward compatibility was maintained seamlessly — all 1161 pre-existing tests continued to pass after the extraction without any modifications.

What caused friction (agent side)

  1. wrong-abstraction — In TDD step 2, initially used require() for lazy-importing FilePolicyLoader inside the PermissionManager constructor, citing "circular issues." There was no circular dependency risk (policy-loader.ts does not import from permission-manager.ts), and require() is inappropriate in an ESM project. Self-identified immediately; replaced with a direct static import. Impact: no rework commit needed — caught before the file was committed.

  2. missing-context — In TDD step 4, wrote three tests based on wrong assumptions:

    • Cache stamp test: assumed getCacheStamp() without an agent name would differ from getCacheStamp("missing-agent"), but both produce "missing" for the agent slot when no file exists. Fixed by creating an actual agent file so the stamps genuinely differ.
    • YAML frontmatter test: used inline JSON-in-YAML syntax (bash: { "git *": allow }) which the simple YAML parser doesn't handle. Fixed by using multi-line YAML.
    • Config issue test: assumed an invalid permission value like "invalid_value" would trigger a config issue, but normalizeUnifiedConfig silently normalizes unknown values. Fixed by using malformed JSON that triggers a file-read error. Self-identified during test run. Impact: one round of test fixes within the same step, no extra commits.

What caused friction (user side)

  • The user's request to add test impact analysis to the plan was highly valuable but came as a follow-up after the initial plan was committed. Integrating this as a standard section in the /plan-issue prompt template would avoid the extra round-trip for extraction refactors.

Changes made

  1. .pi/prompts/plan-issue.md — added Test Impact Analysis as a standard section between Module-Level Changes and TDD Order, covering new tests enabled, redundant tests, and tests that must stay.