FN-9003: reconcile approval audit events with project schema

Align approval audit event declarations and reads with PostgreSQL project ownership.

- Model composite project-scoped audit event identities in the schema
- Scope public audit history reads and cover project isolation behavior
- Document the storage contract and add a patch changeset

Files changed:
 .changeset/fn-9003-approval-audit-project-scope.md |   7 +
 docs/storage.md                                    |   2 +-
 ...oval-request-audit-project-isolation.pg.test.ts | 183 +++++++++++++++++++++
 .../async-stores/async-approval-request-store.ts   |   5 +-
 packages/core/src/postgres/schema/project.ts       |   9 +-
 5 files changed, 202 insertions(+), 4 deletions(-)

Fusion-Task-Id: FN-9003

Fusion-Task-Lineage: 5a9caac3-7c2f-4584-8844-4ac711cc48bb

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-08-12 08:38:35 -07:00
parent 52facd1461
commit b1dad5c9be
5 changed files with 202 additions and 4 deletions

View File

@@ -510,7 +510,7 @@ The `tasks.cumulativeActiveMs` and `tasks.executionCompletedAt` columns are the
| `agents` | Agent registry/state/task assignment metadata. |
| `agentHeartbeats` | Heartbeat run events linked to agents (`agentId` FK cascade). |
| `approval_requests` | Durable approval request records: requester actor snapshot, target action payload (category/action/resource/context), lifecycle status (`pending`/`approved`/`denied`/`completed`), optional task/run context, and requested/decided/completed timestamps. |
| `approval_request_audit_events` | Append-only audit trail for approval requests. Each row stores event type (`created`/`approved`/`denied`/`completed`), immutable actor snapshot, optional note, and deterministic per-request ordering by `(createdAt, rowid)`. |
| `approval_request_audit_events` | Append-only audit trail for approval requests. PostgreSQL uses the physical `(project_id, id)` identity, while public `ApprovalRequestStore.getAuditHistory` scopes bound audit-history reads; Command Center analytics remains intentionally unbound-tolerant. The ownership trigger normalizes only NULL/exact `''`, so a whitespace-only binding is stored literally. Rows store event type (`created`/`approved`/`denied`/`completed`), immutable actor snapshot, optional note, and deterministic per-request ordering by `(createdAt, rowid)`. |
| `secrets` | Encrypted secret KV rows (`key` unique) with raw BLOB `value_ciphertext` + per-row random `nonce` (AES-256-GCM), per-secret `access_policy` CHECK (`auto`/`prompt`/`deny`), env-materialization metadata (`env_exportable`, `env_export_key`), and read-audit fields (`last_read_at`, `last_read_by`). Plaintext is never written to the database. |
| `task_documents` | Task-scoped document metadata/content keyed by `(taskId, key)` with current revision pointer. |
| `task_document_revisions` | Immutable revision history for task documents (content snapshots by revision). |