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,183 @@
---
issue: 559
issue_title: "pi-permission-system: complete the authority/ directory migration"
---
# Complete the `authority/` directory migration
## Release Recommendation
**Release:** ship independently
This is Phase 9 Step 5 — a pure directory move tagged `Release: independent` in the roadmap.
It lands as a `refactor:` commit (hidden changelog type), so it does not cut a release on its own; it auto-batches into the next `feat:`/`fix:`/unhidden-`docs:` release.
Phase 9 declares no multi-step release batch — every step leaves the package consistent on its own — so there is nothing to defer or coordinate.
## Problem Statement
Phase 8's forward-looking `src/` directory sketch places the whole escalation/forwarding/subagent domain under `src/authority/`: the subagent machinery is the cross-session edge of the authority domain, not a peer domain.
Phase 9 Steps 14 rewrote most of those modules into `src/authority/` as they were reworked (tidy-first — a file reaches its final home as it is rewritten).
Five modules never needed a rewrite, so they still sit in the flat `src/` root.
This step moves that mechanical remainder so the domain is closed, the flat root shrinks, and each file has moved exactly once across Phase 9.
## Goals
- Relocate the five remaining escalation/forwarding/subagent modules into `src/authority/`.
- Rewrite every import of the moved modules (parent-relative imports become `#src/authority/…` aliases; same-directory refs stay `./`).
- Mirror the established `src/authority/foo.ts``test/authority/foo.test.ts` layout by moving the five modules' test files into `test/authority/`.
- Mark Phase 9 Step 5 complete in `docs/architecture/architecture.md` (module tree, step heading, Mermaid node) in the same commit as the move.
- Preserve behavior exactly — this is a directory move, not a logic change.
Non-breaking: no exported symbol, config default, or observable behavior changes.
The moved modules are all internal (no `package.json` `exports` re-export among them), so no consumer outside the package is affected.
## Non-Goals
- No logic, signature, or behavior changes to any moved module.
- No renaming of any exported symbol — only file locations and import specifiers change.
- No rework of the `authority/` subtree's existing residents (Steps 14 modules).
- No update to `docs/architecture/v3-architecture.md` — it is a frozen pre-`authority/` snapshot (last touched at #314, before the `authority/` subtree existed) and is not maintained as current state.
Touching two of its stale tree lines would leave it internally inconsistent; leave it as the historical artifact it is.
- No changes to `docs/plans/*`, `docs/retro/*`, or `docs/architecture/history/*` — those are frozen per-issue records.
## Background
Relevant modules and their current relationships (verified against `src/`):
| Module | Imports (relative) | Imported by |
| ---------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `src/permission-dialog.ts` | none (leaf) | 9 `authority/` files, `handlers/gates/runner.ts` |
| `src/subagent-registry.ts` | none (leaf) | 5 `authority/` files |
| `src/subagent-lifecycle-events.ts` | `./subagent-registry` | `index.ts`, tests |
| `src/permission-forwarding.ts` | `./permission-dialog`, `./permission-events`, `./subagent-registry` | 5 `authority/` files, test helpers |
| `src/forwarding-manager.ts` | `./authority/forwarded-request-server`, `./authority/subagent-detection`, `./permission-forwarding` | `index.ts`, test helpers |
`src/authority/` already holds the Phase 8/9 residents (`authorizer.ts`, `local-user-authorizer.ts`, `authorizer-selection.ts`, `permission-prompter.ts`, `approval-escalator.ts`, `forwarded-request-server.ts`, `forwarding-io.ts`, `subagent-context.ts`, `subagent-detection.ts`, `forwarder-context.ts`, `denying-authorizer.ts`).
AGENTS.md / eslint constraints that shape the move:
- The root `eslint.config.js` `local-rules/no-parent-relative-imports` rule flags any `../…` import in `packages/*/src|test/` and auto-fixes it to the package's `#src/`/`#test/` alias.
Same-directory `./…` imports are permitted (that is why `index.ts` and these modules use `./sibling` today).
So after the move, `eslint --fix` mechanically rewrites the parent-relative cases; `tsc` catches any missed path.
- `#src/…` aliases are package-root-absolute: an importer's `#src/permission-dialog` becomes `#src/authority/permission-dialog` because the target moved, regardless of the importer's own location.
- The package skill requires the architecture step-complete marker to land in the implementation commit, not a deferred ship commit.
## Design Overview
Pure relocation.
Five files move from `src/` root into `src/authority/`; their five test files move from `test/` root into `test/authority/`.
The `authority/` subtree already imports four of the five via `#src/…` aliases, so the dependency direction is unchanged — the modules are already logical `authority/` residents, only their physical location is stale.
Import-rewrite rules by category (mechanically enforced by `tsc` + `eslint --fix`):
1. Moved modules that reference each other stay `./sibling` (all five land in the same `authority/` directory):
`permission-forwarding.ts` keeps `./permission-dialog` and `./subagent-registry`; `subagent-lifecycle-events.ts` keeps `./subagent-registry`; `forwarding-manager.ts` keeps `./permission-forwarding`.
2. Moved modules that reference an existing `authority/` resident lose the `authority/` path segment:
`forwarding-manager.ts`'s `./authority/forwarded-request-server``./forwarded-request-server`, `./authority/subagent-detection``./subagent-detection`.
3. Moved modules that reference a module staying in `src/` root gain a `#src/` alias (was same-dir `./`, now parent-relative):
`permission-forwarding.ts`'s `./permission-events``#src/permission-events`.
4. Existing `authority/` importers of a moved module gain the `authority/` segment:
`#src/permission-dialog``#src/authority/permission-dialog`, `#src/subagent-registry``#src/authority/subagent-registry`, `#src/permission-forwarding``#src/authority/permission-forwarding`.
5. `handlers/gates/runner.ts` and test files/helpers: same `#src/…``#src/authority/…` rewrite as (4).
6. `index.ts` (composition root, same-dir `./` style): `./forwarding-manager``./authority/forwarding-manager`, `./permission-dialog``./authority/permission-dialog`, `./subagent-lifecycle-events``./authority/subagent-lifecycle-events`, `./subagent-registry``./authority/subagent-registry`.
No collaborator is introduced, no signature changes, no state moves — this is not an extraction, so the anti-procedure-splitting and Tell-Don't-Ask reviews do not apply.
The existing test suite plus `tsc` and `eslint` are the full correctness proof: a green suite after the move demonstrates behavior preservation.
## Module-Level Changes
Source moves (`git mv`, no content change beyond import specifiers):
1. `src/permission-dialog.ts``src/authority/permission-dialog.ts` (leaf; no import edits in the file itself).
2. `src/subagent-registry.ts``src/authority/subagent-registry.ts` (leaf; no import edits).
3. `src/subagent-lifecycle-events.ts``src/authority/subagent-lifecycle-events.ts` (`./subagent-registry` unchanged — same dir).
4. `src/permission-forwarding.ts``src/authority/permission-forwarding.ts` (`./permission-events``#src/permission-events`; `./permission-dialog` and `./subagent-registry` unchanged).
5. `src/forwarding-manager.ts``src/authority/forwarding-manager.ts` (`./authority/forwarded-request-server``./forwarded-request-server`; `./authority/subagent-detection``./subagent-detection`; `./permission-forwarding` unchanged).
Importer updates (`#src/…``#src/authority/…` for the moved symbols):
6. `src/authority/authorizer-selection.ts`, `approval-escalator.ts`, `forwarded-request-server.ts`, `forwarder-context.ts`, `denying-authorizer.ts`, `permission-prompter.ts`, `local-user-authorizer.ts`, `forwarding-io.ts`, `authorizer.ts`, `subagent-context.ts`, `subagent-detection.ts` — update their `#src/permission-dialog` / `#src/subagent-registry` / `#src/permission-forwarding` imports to the `#src/authority/…` form (11 files; some import two of the moved modules).
7. `src/handlers/gates/runner.ts``#src/permission-dialog``#src/authority/permission-dialog`.
8. `src/index.ts` — the four `./…` imports of `forwarding-manager`, `permission-dialog`, `subagent-lifecycle-events`, `subagent-registry``./authority/…`.
Test moves (mirror the `test/authority/` layout) + import updates:
9. `test/permission-dialog.test.ts``test/authority/permission-dialog.test.ts`.
10. `test/subagent-registry.test.ts``test/authority/subagent-registry.test.ts`.
11. `test/subagent-lifecycle-events.test.ts``test/authority/subagent-lifecycle-events.test.ts`.
12. `test/permission-forwarding.test.ts``test/authority/permission-forwarding.test.ts`.
13. `test/forwarding-manager.test.ts``test/authority/forwarding-manager.test.ts`.
Each moved test updates its `#src/<module>` import to `#src/authority/<module>` (the `#src/`/`#test/` aliases are absolute, so the test's own new location needs no other edits).
Test-helper importer updates (helpers stay in `test/helpers/`):
14. `test/helpers/forwarding-fixtures.ts``#src/permission-forwarding``#src/authority/permission-forwarding`; `#src/subagent-registry``#src/authority/subagent-registry`.
15. `test/helpers/session-fixtures.ts``#src/forwarding-manager``#src/authority/forwarding-manager`.
16. `test/composition-root.test.ts` and any remaining test importers (`test/authority/*.test.ts` already using `#src/permission-forwarding` / `#src/subagent-registry`) — same `#src/…``#src/authority/…` rewrite (caught by `tsc`).
Documentation updates (current-state docs only; land in the same commit):
17. `docs/architecture/architecture.md`:
- Move the five module descriptions out of the flat-root listing (lines for `permission-dialog.ts`, `subagent-registry.ts`, `subagent-lifecycle-events.ts`, `permission-forwarding.ts`, `forwarding-manager.ts`) into the `authority/` subtree block, preserving their descriptions and fixing the tree connector glyphs (`├──`/`└──`) so the subtree's last child is the only `└──`.
- Mark Step 5 complete: prefix the `**Complete the `authority/` migration.**` step heading with `✅` and update the Mermaid `S5` node label to `"✅ Step 5 (#559)<br/>Complete authority/ migration"`.
- The Phase 9 target table's `Flat `src/` root modules ~67 → ~62` row is a target/exit table and needs no edit — the move realizes the already-stated target.
18. `docs/subagent-integration.md` — update the two prose path references `src/subagent-lifecycle-events.ts``src/authority/subagent-lifecycle-events.ts` and `src/subagent-registry.ts``src/authority/subagent-registry.ts`.
19. `.pi/skills/package-pi-permission-system/SKILL.md` — update the two prose path references (`src/subagent-lifecycle-events.ts`, `src/subagent-registry.ts`) to their `src/authority/…` forms.
No moved module has a `package.json` `exports` re-export, `Symbol.for()` cross-extension surface, or event-channel name that changes — the `getSubagentSessionRegistry()` accessor and its `Symbol.for("@gotgenes/pi-permission-system:subagent-registry")` key are unchanged; only `subagent-registry.ts`'s file location moves.
So no wider `docs/` grep beyond the three current-state files above is warranted (the remaining hits are frozen plans/retros/history).
## Test Impact Analysis
This is a move, not an extraction, so the three extraction questions resolve trivially:
1. No new unit tests are enabled — no new seam or collaborator is created.
2. No existing tests become redundant — every test still exercises the same module at the same granularity; only the file path and one import line change.
3. All five moved test files must stay as-is (content-wise) — they genuinely exercise the moved modules.
They relocate to `test/authority/` for layout consistency, keeping their assertions intact.
The full existing suite (`pnpm --filter @gotgenes/pi-permission-system run test`) staying green after the move is the behavior-preservation proof.
## Invariants at risk
The move touches modules that Steps 14 wired into the `authority/` spine, so the relevant invariants are those steps' documented outcomes:
- Step 3's pinned invariant — the forwarded `permissions:ui_prompt` broadcast stays non-degraded (original `source`, `surface`/`value` projection, populated `forwarding` context) — is exercised by the composition-root round-trip and `test/authority/forwarded-request-server.test.ts`.
A pure file move cannot regress it; the same code runs.
The green suite (including `test/composition-root.test.ts`'s subagent-registry-sharing and forwarding round-trip) confirms it.
- Step 4's whole-session-grant round-trip (composition-root test) likewise rides on unchanged logic.
No invariant lives only in prose here — each is pinned by an existing test that runs unchanged after the move.
## TDD Order
This is a behavior-preserving move; there is no red phase.
The proof is `tsc` + `eslint` + the unchanged green suite.
One atomic commit (the moves and importer rewrites must land together — `tsc` rejects a half-moved state).
1. **Move + rewrite + doc-mark (single commit).**
- `git mv` the five source files into `src/authority/` and the five test files into `test/authority/`.
- Run `pnpm --filter @gotgenes/pi-permission-system exec eslint . --fix` to auto-rewrite parent-relative imports to `#src/authority/…` aliases, then hand-fix the same-dir cases per the Design Overview rules (`forwarding-manager.ts`'s `./authority/*``./*`; `permission-forwarding.ts`'s `./permission-events``#src/permission-events`).
- Update `index.ts`'s four `./…` imports to `./authority/…`.
- Apply the three documentation edits (architecture tree + Step 5 `✅` + Mermaid node; `subagent-integration.md`; SKILL.md).
- Verify: `pnpm --filter @gotgenes/pi-permission-system run check` (tsc), `pnpm --filter @gotgenes/pi-permission-system run lint`, `pnpm --filter @gotgenes/pi-permission-system run test`, and `pnpm fallow dead-code` all pass; `git status` shows only renames + import-line/doc diffs.
- Commit: `refactor(pi-permission-system): move escalation/forwarding/subagent modules into authority/ (#559)`.
Folding the doc updates into the `refactor:` commit keeps the change hidden-changelog (no stray `docs:` release) and satisfies the package skill's "mark the roadmap step complete in the implementation commit" rule.
## Risks and Mitigations
- **A missed importer.**
Mitigation: `tsc` (`pnpm run check`) fails on any unresolved specifier; `eslint`'s `no-parent-relative-imports` fails on a stray `../`.
The suite will not go green until every reference is updated.
- **`git mv` recorded as delete+add, losing history.**
Mitigation: use `git mv` (not delete+rewrite) so Git records renames; the content change per file is one or two import lines, well within rename-detection thresholds.
- **Tree-glyph corruption in the architecture listing.**
Mitigation: after editing, re-read the `authority/` subtree block to confirm exactly one `└──` (the last child) and correct `├──` connectors — per the AGENTS decorative-rule caution.
- **Stale prose path in an unsearched current-state doc.**
Mitigation: the `src/`-symbol grep was widened to the three current-state docs (`architecture.md`, `subagent-integration.md`, SKILL.md); remaining hits are frozen plans/retros/history, explicitly out of scope.
## Open Questions
None.
The scope is fully mechanical and enumerated; no follow-up issues are filed.