# Plugin Separation-of-Duties Approval Implementation Plan > **For agentic workers:** Implement task-by-task with tests first. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace the execution operator's inline approval assertion with persistent, independently approved, expiring, revocable, single-use evidence. **Architecture:** A Transition-scoped approval journal freezes requester roles and routing identity. Decisions and executions share one Transition-first lock order. Execution copies a complete audit snapshot, atomically consumes the approved row, and only then creates receipts and Outbox work. **Tech Stack:** Java 8, Spring Boot 2.5, Spring Security, MyBatis, MySQL 5.7-compatible SQL, JUnit 4, Vue 2, Element UI. ### Task 1: Policy And Identity **Files:** - Modify: `PluginExecutionProperties.java` - Create: `PluginApprovalPolicy.java` - Modify: `PluginExecutionRoutingPolicy.java` - Test: approval and routing policy tests - [x] Add bounded request and approved-evidence TTLs, separation switch, and role allowlists. - [x] Canonicalize and freeze actor role snapshots. - [x] Reject self-approval and disallowed roles. - [x] Include all approval policy settings in routing identity. - [x] Remove the direct execution-request approval shortcut. ### Task 2: Persistent Lifecycle **Files:** - Create: approval domain and request models - Modify: execution domain audit snapshot - Modify: `PluginTransitionExecutionMapper.java` and XML - Modify: Factory full and upgrade SQL scripts - [x] Add PENDING, APPROVED, REVOKED, CONSUMED, and EXPIRED states. - [x] Persist request, decision, revocation, consumption, and expiry evidence. - [x] Add immutable requester/approver snapshots to execution rows. - [x] Add guarded lifecycle updates and single-execution uniqueness. - [x] Keep schema upgrades compatible with MySQL 5.7. ### Task 3: Service And Concurrency **Files:** - Modify: `PluginTransitionExecutionService.java` - Test: `PluginTransitionExecutionServiceTest.java` - [x] Implement request, list, approve, and revoke operations under the Transition lock. - [x] Bind approval to exact mode, Transition, routing, environment, and Executor. - [x] Apply lazy request and evidence expiry. - [x] Consume exactly one approved row before receipts and Outbox creation. - [x] Expire sibling requests after consumption and reject post-consumption revocation. - [x] Test expiry, self-approval, revocation, consumption races, and immutable audit snapshots. ### Task 4: API And Permissions **Files:** - Modify: `FeaturePluginController.java` - Modify: Registry and delivery status models - Modify: `sql/plugin_registry_menu.sql` - Test: `FeaturePluginControllerTest.java` - [x] Add Transition approval request, list, approve, and revoke endpoints. - [x] Pass authenticated role keys into the policy layer. - [x] Separate execute/request permission from approve/revoke permission. - [x] Expose non-secret policy status without target credentials. - [x] Add a reflection contract test for permission separation. ### Task 5: Dual-Person UI **Files:** - Modify: `ruoyi-ui/src/api/generator/plugin.js` - Modify: Plugin and delivery verification views - Modify: `ruoyi-ui/test/pluginRegistryView.test.mjs` - [x] Add approval lifecycle API functions. - [x] Add a Transition approval table with request, approve, revoke, expiry, and audit details. - [x] Select only matching approved evidence for real execution. - [x] Preserve dry-run confirmation without approval evidence. - [x] Show consumed requester/approver evidence in execution history. ### Task 6: Documentation And Regression **Files:** - Create: this implementation plan and the matching design document - Modify: AI Software Factory roadmap - [x] Document identity, locks, expiry, revocation, consumption, and boundaries. - [x] Run 162 focused Plugin tests. - [x] Run 805 generator tests: 787 pass and the exact 18 known baseline failures remain. - [x] Run 38 admin tests, four frontend static tests, and the production build. - [x] Confirm the existing development endpoints return HTTP 200.