mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 08:35:57 +00:00
feat: vendor permission system source
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
---
|
||||
issue: 129
|
||||
issue_title: "refactor: extract PermissionSession class to encapsulate mutable session state"
|
||||
---
|
||||
|
||||
# Retro: #129 — extract PermissionSession class
|
||||
|
||||
## Final Retrospective (2026-05-08T02:30:00Z)
|
||||
|
||||
### Session summary
|
||||
|
||||
Extracted a `PermissionSession` class that encapsulates all mutable session state (`PermissionManager`, `SessionRules`, cache keys, skill entries, runtime context) with operation-based methods replacing field access.
|
||||
Migrated all 4 handler files and 6 handler test files to use the new class, shrinking `HandlerDeps` from 18 to 7 fields.
|
||||
Released as v5.10.0 with 38 new unit tests and no behavioral change.
|
||||
|
||||
### Observations
|
||||
|
||||
#### What went well
|
||||
|
||||
- **`SkillPermissionChecker` interface extraction** — the plan didn't anticipate that `resolveSkillPromptEntries` took a concrete `PermissionManager` type.
|
||||
Rather than using a cast, extracting a narrow `SkillPermissionChecker` interface in `src/skill-prompt-sanitizer.ts` let both `PermissionManager` and `PermissionSession` satisfy it structurally.
|
||||
This "narrow interface at the callee" pattern avoided adapter objects and should be the default approach for similar migrations.
|
||||
- **Phase collapse was efficient** — the plan's strict 4-phase separation (build class → wire type → migrate handlers → cleanup) would have required updating every `makeDeps` factory twice.
|
||||
Collapsing phases 2–4 into handler-by-handler migration (each handler + its tests in one commit) was cleaner and produced smaller, reviewable diffs.
|
||||
- **Handler test simplification was dramatic** — `makeSession()` factories went from 7 nested-mock fields with `as unknown as SessionState["permissionManager"]` casts to flat `vi.fn()` stubs.
|
||||
The `tool-call-events.test.ts` file shrank from 375 to 302 lines while preserving all test cases.
|
||||
|
||||
#### What caused friction (agent side)
|
||||
|
||||
1. `premature-convergence` — initial `PermissionSession` constructor followed the plan's "4 deps" signature literally (`ExtensionPaths`, `SessionLogger`, `PermissionPrompterApi`, `ForwardingController`), then added `canPrompt()`/`prompt()` methods before realizing the prompting surface doesn't belong on the session (it depends on `ctx` + subagent detection logic the session doesn't own).
|
||||
Resulted in writing and then deleting ~30 lines of prompting code, plus adding `PermissionSessionRuntimeDeps` as the actual 4th dep.
|
||||
Impact: ~10 minutes of rework across two edits.
|
||||
|
||||
2. `missing-context` — the lifecycle handler rewrite (`src/handlers/lifecycle.ts`) was written from memory rather than referencing the original.
|
||||
`handleResourcesDiscover` used an undeclared `session` variable and `handleSessionShutdown` called a non-existent `session.clearStatus()` method.
|
||||
Caught immediately on the next read, but the file had to be rewritten.
|
||||
Impact: one extra write cycle, no commit waste.
|
||||
|
||||
3. `missing-context` — `vi.mock` paths in the initial test file used `./src/` instead of `../src/`.
|
||||
Tests run from `tests/`, so the relative paths were wrong.
|
||||
Caught on first test run.
|
||||
Impact: one extra edit, no rework.
|
||||
|
||||
4. `missing-context` — test mocks used shorthand `SkillPromptEntry` shapes like `{ name: "s", path: "/s", content: "c" }` that passed Vitest (esbuild, no type checking) but failed `tsc`.
|
||||
The real type has 6 required fields (`name`, `description`, `location`, `state`, `normalizedLocation`, `normalizedBaseDir`).
|
||||
Fixed by adding a `makeSkillEntry()` helper.
|
||||
Impact: one extra commit fixup at the end, but could have been avoided by checking the `SkillPromptEntry` type before writing mock data.
|
||||
|
||||
5. `wrong-abstraction` — the plan proposed `PermissionSession` absorb `canPrompt(ctx)` and `prompt(ctx, details)`, but these methods require `isSubagentExecutionContext()` and `canResolveAskPermissionRequest()` which depend on `subagentSessionsDir` and config — concerns the session shouldn't own.
|
||||
The correct boundary keeps prompting on `HandlerDeps` until #130 handler classes can own the `ctx`-capture pattern.
|
||||
Impact: plan deviation documented in the summary, no code waste beyond friction point #1.
|
||||
|
||||
#### What caused friction (user side)
|
||||
|
||||
- No friction observed.
|
||||
The user ran `/plan-issue`, `/tdd-plan`, and `/ship-issue` in sequence with no mid-session corrections needed.
|
||||
The autoformat hooks ran cleanly throughout.
|
||||
|
||||
### Changes made
|
||||
|
||||
1. Created `docs/retro/0129-extract-permission-session.md` (this file).
|
||||
Reference in New Issue
Block a user