feat(FN-3712): document approval policy runtime and architecture contracts

Adds documentation for the approval architecture and runtime policy contract to `docs/architecture.md` and `docs/agents.md` (FN-3712).

Fusion-Task-Id: FN-3712
This commit is contained in:
Fusion
2026-05-07 14:03:51 -07:00
committed by gsxdsm
parent 669fba501a
commit a67d715219
2 changed files with 45 additions and 0 deletions

View File

@@ -89,6 +89,21 @@ Intentionally exempt in v1 (remain normal execution plumbing):
For `require-approval` dispositions, execution is intercepted before side effects; the engine creates/reuses a pending approval request keyed by a deterministic dedupe key (`agentId + taskId + toolName + category + resourceType + resourceId + operation`).
Approval-request runtime/storage contract (current implementation):
- The `approval-required` preset normalizes **every** v1 action category (`git-write`, `file-write-delete`, `shell-command`, `network-api`, `task-agent-management`) to `require-approval`.
- Gated actions persist durable request rows (`approval_requests`) with:
- `requester` actor snapshot (`actorId`, `actorType`, `actorName`)
- target action payload (`category`, `action`, `summary`, `resourceType`, `resourceId`, optional `context`)
- optional execution linkage (`taskId`, `runId`)
- Lifecycle updates append immutable audit rows (`approval_request_audit_events`) with actor snapshot + optional note (`created`, `approved`, `denied`, `completed`).
Current boundary vs forthcoming UX/runtime pieces:
- **Implemented now:** durable approval request + append-only audit persistence used by runtime action-gating paths.
- **Not complete yet:** broader pause/resume execution workflow and dashboard mailbox/inbox approval-review surfaces.
- Treat operator review UI/inbox flow as forthcoming follow-up work; do not assume a finished approval inbox surface in current deployments.
Default and legacy fallback behavior:
- New **non-ephemeral/permanent** agents persist a normalized `permissionPolicy` using preset `unrestricted` when not explicitly provided.

View File

@@ -179,6 +179,36 @@ Concrete references:
- `TodoStore` (`todo-store.ts`) — project-scoped todo lists/items with completion, reorder, and composite list+items queries
- `EvalStore` (`eval-store.ts`) — eval run persistence, per-task eval results with durable snapshots, and append-only run event trails
### Approval request system (`ApprovalRequestStore`)
Schema (migration 68 in `db.ts`) adds two tables:
- `approval_requests`
- Identity/lifecycle: `id`, `status`, `requestedAt`, `decidedAt`, `completedAt`, `createdAt`, `updatedAt`
- Requester snapshot: `requesterActorId`, `requesterActorType`, `requesterActorName`
- Target action payload: `targetActionCategory`, `targetActionOperation`, `targetActionSummary`, `targetResourceType`, `targetResourceId`, `targetContext` (JSON text)
- Optional runtime linkage: `taskId`, `runId`
- Indexes: `idxApprovalRequestsStatusCreatedAt (status, createdAt)`, `idxApprovalRequestsRequesterCreatedAt (requesterActorId, createdAt)`, `idxApprovalRequestsTaskCreatedAt (taskId, createdAt)`
- `approval_request_audit_events`
- `id`, `requestId`, `eventType`, actor snapshot (`actorId`, `actorType`, `actorName`), optional `note`, `createdAt`
- `requestId` is a foreign key to `approval_requests(id)` with `ON DELETE CASCADE`
- Index: `idxApprovalRequestAuditRequestCreatedAt (requestId, createdAt, id)`
Store API (`packages/core/src/approval-request-store.ts`):
- `create(input: ApprovalRequestCreateInput)` — inserts a `pending` request and appends a `created` audit event
- `get(id)` — returns one request or `null`
- `list(input?: ApprovalRequestListInput)` — filters by `status`, `requesterActorId`, `taskId`, `runId`; ordered `createdAt DESC, id DESC`; paginated by `limit`/`offset`
- `decide(requestId, status, input: ApprovalRequestDecisionInput)` — applies `pending -> approved|denied`, stamps `decidedAt`, appends `approved`/`denied` audit event
- `markCompleted(requestId, input: ApprovalRequestCompletionInput)` — applies `approved -> completed`, stamps `completedAt`, appends `completed` audit event
- `getAuditHistory(requestId)` — returns append-only audit rows ordered `createdAt ASC, rowid ASC`
Lifecycle contract (`types.ts` `isValidApprovalRequestTransition`):
- Primary forward paths: `pending -> approved -> completed` and `pending -> denied`
- Direct `pending -> completed` and all transitions from `denied`/`completed` (except no-op self-transition) are rejected
- Same-state transitions (`from === to`) are treated as valid by the helper even though the intended lifecycle is forward-only
### Shared mesh-state snapshot helpers
`packages/core/src/shared-mesh-state.ts` defines a common snapshot envelope for non-task mesh state export/apply: