Files
stack/docs/fleet/proposals/mosaic-platform-prd/PRD-permission-relay.md
Jarvis 2708de55b9
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
docs(prd): fold 2026-07-09 debate-pass findings into Mosaic Platform PRD
All 24 panel findings (P0#1-5, P1#6-13, P2/P3#14-24) accepted and folded:
- DEBATE-FINDINGS.md: disposition record + open-disagreement judgment calls
- north-star: NS-14, J2a/J2b split, J6 wake router, K3 push pipeline,
  M1 memory subsystem, workstream L (MALS lineage), real DAG edges
- J: workspace lease J-R16, resume protocol J-R18, write-side trust,
  needs-decision lifecycle, atomic card publish
- P: CAS approval state machine, gateway-only credentials, default-closed
  gating, principal resolution + policy snapshot (Codex #2/#7)
- W: butt-in exclusive lease, structured control plane, break-glass
  doctrine, trial metric panels
- Q: external_refs table, pending-link, echo-loop guard, crash barriers
- X: storage authority (Postgres sole record), machine-generated census,
  memory retrieval-eval retirement gate, honest rollback scope,
  4 artifact-existence machine gates, bounded day-30 review
- README: Gate Zero, conflict register, DoD line, silent-roster rule

One item OPEN for Jason at ratification: gate superstructure (§3.1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RMoEx7hfdFGjUiCHuN1RRi
2026-07-09 16:29:37 -05:00

16 KiB
Raw Blame History

PRD — Permission Relay · Workstream P

Status: DRAFT for ratification · Goals: P1P3 Debate pass 2026-07-09: panel findings folded — see DEBATE-FINDINGS.md. The relay was the panel's densest target; the deltas below are normative. Design origin (historical): docs/3-architecture/guard-rails-capability-permissions.md — the "prepare freely, execute with approval" snapshot. Not present on origin/main (survives only in the stale /src/mosaic-stack clone), so its essential model is folded into this PRD below; this document is the authoritative, self-contained spec for P. Replaces: Hermes permissions_list_open / permissions_respond relay (Hermes exit prerequisite, NS-13)

Mission

A human-in-the-loop approval mechanism for agent actions: any capability listed as requires_approval is prepared by the agent, queued, and executed only after an explicit human approve — from the Matrix room or the webUI. Today this exists only as a bare applyGuardRails() method; Hermes currently fills the gap and must be replaced before decommission.

Design model (folded in — the authoritative spec, since the origin snapshot is off-main)

Doctrine — "prepare freely, execute with approval": an agent may plan, draft, and stage any action without friction; only the committing step of a requires_approval capability blocks on a human decision.

Permission levels (least→most): readorganizedraftexecuteadmin. A capability grant names a level; requires_approval gates the transition into execute/admin for the capabilities a workspace marks sensitive.

Grant shape: resource:action (e.g. email:send, git:push_main, dns:update), scoped per workspace and per agent-persona, stored as configuration (profile field) so a user tightens/loosens without a code change.

Requirements

Guard-rails engine (P1)

ID Requirement
P-R1 Capabilities are resource:action grants (e.g. email:send, git:push_main, dns:update) with permission levels (read / organize / draft / execute / admin) per the existing design doc.
P-R2 Each integration declares its requires_approval list; grants are workspace-scoped and per-agent-persona.
P-R3 Enforcement sits in the gateway/API dispatch path — an agent cannot bypass it by construction; bypass attempts are audited and denied.
P-R4 Policy is configuration (profile field), honoring the configurability pillar: a user can tighten/loosen per capability without code change.

Approval queue + chat approvals (P2)

ID Requirement
P-R5 A pending approval is a durable queue record: requesting agent, capability, human-readable intent summary, prepared payload reference, TTL.
P-R6 Approve/deny from the Matrix room (message action or reply verb); the requesting agent is notified of the outcome and proceeds/aborts.
P-R7 Timeout = deny (fail-closed), with per-capability TTLs and distinct terminal states: denied / expired_seen / expired_unseen — agents must not reason about an expiry as a human "no". Deny and timeout leave the system unchanged.
P-R8 Full audit trail: who approved what, when, from which surface (AC-NS-10).
P-R9 The main agent (Jarvis) surfaces pending approvals conversationally (J-R13) but approval authority is the human's — Jarvis never auto-approves.

webUI surface (P3)

ID Requirement
P-R10 Pending-approval queue view in apps/web with one-click approve/deny, filterable per workspace/agent (depends W3 dashboard shell).

Debate-accepted deltas (2026-07-09) — normative

State machine & delivery (extends P-R5P-R7)

ID Requirement
P-R11 Approval lifecycle is a CAS state machine on one durable row: pending → approved | denied | expired_seen | expired_unseen, all terminal. Concurrent surfaces (Matrix, webUI, CLI, TTL reaper) contend via compare-and-swap; exactly one wins.
P-R12 The prepared payload is persisted in the record at request time — never a reference to requesting-agent process state (the agent may be dead when approval lands). Outcome delivery is poll/ack, not push-only; approved_unexecuted > N min raises an alarm.
P-R13 A consumed-event dedupe table (shared substrate with bridged-message and wake-turn dedupe — built once, three consumers) makes approval consumption idempotent under Matrix at-least-once replay. Dedupe retention is checkpoint-coupled: events older than the durable sync token are dropped before lookup, so pruning never reopens the replay window.
P-R14 Each capability declares retry: safe | at-most-once; a prepare→execute staleness bound rejects execution of stale payloads. Re-surfacing an expired item re-prepares (new linked record with a rendered machine diff against the original) — never re-queues a stale payload.
P-R15 CLI approval surface (mosaic approvals list|approve|deny) ships with P2 as must-have — the newest infra (Matrix) is never the only approval path. Per-request delivered/seen tracking; TTL/2 escalation via a second path.

Identity & policy (closes Codex #2/#7)

ID Requirement
P-R16 Principal resolution: every inbound approve/deny maps to a product principal via immutable Matrix user ID + bridge provenance + workspace membership. Unlinked identities and bridged puppets without an account link converse read-only and cannot approve, butt-in, or trigger external writes. Fixtures: bridged puppet, renamed user, invited non-admin, removed-member-with-lagging-room-membership — all deny + audit with reason.
P-R17 Policy snapshot: every prepared action and card stores an immutable snapshot (profile id/version, grants evaluated). Execution revalidates against current policy or fails with explicit policy_changed. Profile changes are audited with schema validation + dry-run impact report. Delegated work (subagent, Jarvis-authored card) executes under the intersection of originator and executor grants.

Credential boundary (makes P-R3 true)

ID Requirement
P-R18 Raw provider credentials are held exclusively by the gateway; agents receive scoped capability tokens; the gateway injects secrets server-side. If the agent runtime can read the provider secret, P-R3 is decoration.
P-R19 P1 delivers a fleet-host credential inventory: every host-resident credential (SSH keys, kubeconfigs, tool tokens) classified moved-behind-gateway or explicitly-exempt(reason, owner, expiry). Enforced by a continuous scheduled scan of agent-readable paths (alert on unclassified), registered in the health floor. The clean-host install AC passes with an empty exemption list. Break-glass is one standing exempt row (owner: operator; audited post-hoc).

Gating defaults & load (closes default-open + human-overdraw)

ID Requirement
P-R20 Default-closed inversion: execute/admin capabilities on external integrations require approval unless workspace-allowlisted. Third state unclassified: a capability with no classification rejects at the gate. Classification happens at integration-version activation, scoped to the capability, not the version — a security patch bundling one new capability ships same-day; only the new capability rejects until classified. Manifest-less capabilities reject + integrity alert.
P-R21 Rate limits + max_pending_per_agent_per_capability; queue depth and human decision latency are exported metrics with thresholds (rubber-stamping guard). Capabilities carry a deferrable flag; a declared away state pauses deferrable TTLs, batches pings, and suppresses preparation of non-deferrable requests (suppressed list swept, priority-ordered and paginated, on return).
P-R22 Approval summaries render machine-extracted payload facts unconditionally (recipient, amount, target host — no tunable similarity threshold); agent prose is secondary. Canary approvals are gateway-generated, short-circuited at the gateway (never executable), immediately disclosed after decision, timing seeded outside agent-readable stores; the gated criterion is machine-flag correctness — human catch rate is reported with binomial CI, non-blocking.
P-R23 Every durable table introduced by P declares a retention class, linted in CI; pruning jobs are health-floor registered. Minimal mandatory audit envelope: ts, workspace, actor, correlation_id, stack_version, schema_version — payloads are typed free-form with pinned, checked-in queries (debate §3.2 disposition).

Acceptance criteria

  1. AC-NS-10 end-to-end: a requires_approval action executes only post-approve; deny/timeout paths verified unchanged + audited.
  2. Approval round-trip from a phone Matrix client (Element) in under 3 taps — and the same round-trip via mosaic approvals CLI with the homeserver stopped.
  3. With Hermes stopped, permission flow fully served by Mosaic (feeds AC-NS-11).
  4. Crash-consistency: kill the gateway at each named barrier (before_persist, after_approve_before_execute, after_execute_before_ack); zero double-executions, zero lost approvals across the suite.
  5. All four principal-resolution fixtures (P-R16) deny + audit; policy-change race (P-R17) fails policy_changed, never executes under stale grants.

Non-goals

  • Automated quality gates (coordinator/CI approvals) — different system, already exists.
  • Fine-grained LLM output moderation — out of scope; this governs actions.

Assumptions

  • ASSUMPTION: the durable queue rides the native Postgres storage service (same substrate as the backlog), not a new datastore.
  • ASSUMPTION: routine delivery operations already hard-gated as no-confirmation (push/merge per Mosaic contract) are NOT routed through the relay — the relay is for requires_approval capabilities only, so it does not reintroduce routine confirmation prompts.