diff --git a/maps/agent-access-map/questions-and-approvals.md b/maps/agent-access-map/questions-and-approvals.md index 30bf493c72e..495385b669f 100644 --- a/maps/agent-access-map/questions-and-approvals.md +++ b/maps/agent-access-map/questions-and-approvals.md @@ -4,227 +4,616 @@ Product map: [Questions and approvals](../feature-map/questions-and-approvals.md Feature ID: `questions-and-approvals`. -Review date: 2026-10-12. Source commit: `f981fa3cc10cb8663a87dec60345fbff46d54d0a`. +Source revision: `3bbc2104b65caf9f7763938a01260a5673e12f7a`. -This is a source-reviewed baseline of representative operations and known gaps. -Each capability needs operation-level review before its entire scope can be -qualified. No live agent execution is claimed. Follow the [map contract](../README.md) -for format, permission checks, evidence and maintenance. +Review depth and executed proof are separate. The operation records enumerate the named behavior and access boundaries. Their evidence states describe the reviewed sources; run results and environment limits belong in the PR or verification artifacts. A listed API or source test does not establish a live authorized journey. Follow the [map contract](../README.md). + +Source review of meaningful operations at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. Operation review records contract depth; evidence remains source-only and proposed live checks remain not-run. Native REST, dedicated native tools, legacy/CLI clients, human sessions and public assistant MCP have distinct authority. Preserve existing host/provider caveats and link actual executed proof separately. ## `questions` Capability ID: `questions-and-approvals/questions`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Read/create questions, record permitted answers, and distinguish cancellation/withdrawal from presentation dismissal. -- `POST /api/issues/{id}/interactions`. -- `POST /api/issues/{id}/interactions/{interactionId}/respond`. +### `read` -Agent access: `partial` — Native request_human_input; REST / MCP forms; authorized -responder endpoint. +API: `present` — GET /api/issues/{id}/interactions. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — agent REST, CLI issue interactions, native get_task_context or admitted call_api reads; each actual runtime needs its binding. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Company/issue read authorization, private-task and responsible-user visibility. GET does not persist lifecycle expiration. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Agent creates questions. It cannot fabricate a human answer; answering follows -resolver policy. +Verification: `not-run` — Read as permitted human/agent; deny foreign/private issue; compare pending and terminal saved receipts after reload. + +Gaps: Run context read is not provider receipt or live answer delivery proof. + +### `create` + +API: `present` — POST /api/issues/{id}/interactions, kind ask_user_questions. + +Agent access: `available` — native request_human_input(interactionKind=questions) in standard/planning/ask/skill_test when advertised; permitted legacy REST/CLI interaction:create. Muse closed native profile omits this tool. + +Policy: Agent mutation requires authenticated source run and low-trust/issue boundaries; sourceRunId is server-stamped. Chat addressee defaults to immutable owner. User/agent addressee mutually exclusive; agent cannot address self, foreign or uninvokable agent. Company kind governance clamps policy. Native dedicated input does not expose arbitrary addressee/policy fields. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Create complete canonical mixed form; same idempotency key/payload returns same card; changed payload conflicts. Reload exact IDs/audience; deny spoofed source/governed metadata/foreign addressee. + +Gaps: Legacy wrappers and native dedicated tool have different fields; source availability does not establish every harness. + +### `answer` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/respond. + +Agent access: `partial` — eligible responder REST; CLI interaction:respond; admitted native call_api standard/skill_test; request_human_input creates requests rather than answers. + +Policy: Same company/readable issue and current effective audience; agents need matching authenticated run/company/agent/responsible user, issue mutation or admitted watchdog containment, no low-trust boundary violation and cross-issue influence allowance. Current review policy can narrow audience; service rechecks cancellation/write authority under lock. Board chat responder must own the conversation. Only pending ask_user_questions; normalize/validate question and option IDs, required single/multi/custom/text constraints. Save answer/actor/run and durable outbox atomically. Human-only does not permit agent resolution. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts), [answer delivery](../../server/src/services/question-response-delivery.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Submit paged edited answers; invalid IDs/limits leave pending. Reload exact saved answers/actor and one eligible continuation. Competing response loses without second delivery; denied audience/run leaves card unchanged. + +Gaps: Provider/runtime delivery requires its own actual waiting input or continuation evidence. + +### `cancel` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/cancel. + +Agent access: `restricted` — board-only cancellation, including the CLI interaction:cancel client. An ordinary agent cannot use this route. + +Policy: Only a pending question on an eligible task can be cancelled. Record cancellation and empty answers with attribution. Persist any waiting native-run cancellation intent before attempting shutdown; a deferred shutdown remains recoverable. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Cancel a disposable question, reload the cancelled receipt and cancellation intent, and reject an agent or repeated terminal decision. Confirm no answer was invented; cancellation intent alone does not prove provider termination. + +Gaps: No dedicated CLI withdraw command found. Cancellation request is not confirmed provider termination. + +### `withdraw` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/withdraw. + +Agent access: `partial` — board or permitted creator/current-assignee agent with valid authenticated run and containment. No dedicated CLI withdraw command. + +Policy: Validate task visibility, creator/current-assignee authority, run context and current review restrictions. Reject an executing linked tool request. Persist native-question cancellation intent before shutdown. Withdrawal by the current assignee does not self-wake; other callers retain ordinary eligible continuation rules. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Withdraw as creator/current assignee and board in separate fixtures. Reject unrelated agent, forged/missing run, executing linked action and repeated terminal resolution. Reload receipt and verify cancellation/continuation without losing a stop obligation. + +Gaps: No dedicated CLI withdraw command found. Cancellation request is not confirmed provider termination. + +### `historical-answer` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/respond for recognized historical pending question on Done task. + +Agent access: `restricted` — pure human responder only; ordinary agent/native responder cannot use the terminal-history exception. + +Policy: Only service-recognized historical question, Done task and human actor without agent/run/system identity; record conversation history only, no response outbox/new work. Other terminal task paths remain denied. + +Evidence: `source-only` — [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Answer eligible historical Done question, reload history and verify no task reopen/run/outbox. Reject cancelled task/nonhistorical/agent cases. + +Gaps: Special historical compatibility path is not permission to reopen completed work. ## `dismiss-and-reopen` Capability ID: `questions-and-approvals/dismiss-and-reopen`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Local presentation and drafts remain distinct from server response state. -- `GET /api/issues/{id}/interactions`. +### `read-pending` -Agent access: `partial` — Persisted question API plus browser card state. +API: `present` — GET /api/issues/{id}/interactions. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — permitted REST/native API/CLI interaction reads under current task/company/privacy authority. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Shared interaction reads retain domain authorization. Reading a pending question does not answer it or change its stored status. -Verification: `not-run` — use the product recipe for the local/developer surface. Verify -listed shared-resource reads separately; local presentation alone is not agent API -evidence. +Evidence: `source-only` — [dismissal state](../../ui/src/hooks/useDismissedTaskQuestions.ts), [task thread](../../ui/src/components/TaskChatThread.tsx), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Presentation dismissal/reopening does not resolve the question and does not -require a new mutation API. +Verification: `not-run` — Read the same pending question before and after browser dismissal; compare its ID, pending status and absence of a response-delivery record. Reject inaccessible task/company reads. +Gaps: No server/account-wide synchronization promised for presentation state. + +### `dismiss-locally` + +API: `not-applicable` — browser-only presentation through the task thread and useDismissedTaskQuestions localStorage; no domain write is needed. + +Agent access: `not-applicable` — the browser owns this presentation preference. Agents can read the shared interaction separately. + +Policy: Scope dismissal by browser user and task. It hides the composer form without creating an answer, approval or wake. A new ordinary comment can hide the composer while the default question remains pending. + +Evidence: `source-only` — [dismissal state](../../ui/src/hooks/useDismissedTaskQuestions.ts), [task thread](../../ui/src/components/TaskChatThread.tsx), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Dismiss without submitting, reload in the same browser, and inspect the still-pending shared request. Another user/task must not reuse the preference; unavailable local storage must not alter server state. + +Gaps: No server/account-wide synchronization promised for presentation state. + +### `reopen-draft` + +API: `not-applicable` — browser history and QuestionForm draft storage keyed to the request; submission uses the separate response API. + +Agent access: `not-applicable` — local page, answer and custom-text drafts are browser presentation. There is no agent draft-control API. + +Policy: QuestionForm saves page/answers/custom state by draftKey and clears on successful submit/cancel. Settled card from competing tab is authoritative; local draft cannot revive it. Explicit supersession is lifecycle rather than dismissal. + +Evidence: `source-only` — [question drafts](../../ui/src/components/task-chat/QuestionForm.tsx), [reopening](../../ui/src/components/TaskChatThread.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Reopen an edited paged draft after reload, verify its own saved selections/text, and ensure a new request cannot inherit another request’s draft. Clear the draft only after the supported successful submission/cancellation path. + +Gaps: Cross-browser drafts and every alternate host remain separate verification scope. + +### `observe-resolution` + +API: `present` — GET /api/issues/{id}/interactions. + +Agent access: `available` — permitted shared receipt reads; the browser reconciles its stale form with that record. + +Policy: The persisted terminal receipt wins over local draft state. Explicit supersession is a server lifecycle decision, separate from browser dismissal. + +Evidence: `source-only` — [question drafts](../../ui/src/components/task-chat/QuestionForm.tsx), [reopening](../../ui/src/components/TaskChatThread.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Resolve in another tab and refresh/reopen the old form. Show the saved receipt, preserve attribution, and offer no second answer or revived pending request. + +Gaps: Cross-browser drafts and every alternate host remain separate verification scope. ## `confirmations` Capability ID: `questions-and-approvals/confirmations`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Resolve ordinary confirmations, selections and partial item verdicts with explicit policy and retry semantics. -- `POST /api/issues/{id}/interactions`. -- `POST /api/issues/{id}/interactions/{interactionId}/resolve-from-comment`. +### `create-and-read` -Agent access: `partial` — Native request_human_input and call_api resolve-from-comment; -authorized REST resolver. +API: `present` — GET /api/issues/{id}/interactions; POST /api/issues/{id}/interactions for ordinary confirmation, checkbox, suggested-task or item-verdict requests. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — permitted REST/CLI create/read; native request_human_input supports corresponding kinds under its actual mode/profile. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Creation authority/source/audience as questions. Server-owned governed metadata cannot be forged. Target-bound request validates exact document revision atomically; same create key changed content conflicts. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Conversational confirmation is supported under resolver policy; generic -acceptance/response controls remain restricted. +Verification: `not-run` — Create/read each relevant kind with exact target; repeat key unchanged/changed; deny forged toolAction/secretProposal and stale document target. +Gaps: Native dedicated field set is narrower than direct REST. + +### `accept-or-reject` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/accept or /reject. + +Agent access: `partial` — eligible human/agent resolver REST, CLI interaction:accept/reject and native call_api in standard/skill_test; board-only governed callback remains separate. + +Policy: Same company/readable issue and current effective audience; agents need matching authenticated run/company/agent/responsible user, issue mutation or admitted watchdog containment, no low-trust boundary violation and cross-issue influence allowance. Current review policy can narrow audience; service rechecks cancellation/write authority under lock. Board chat responder must own the conversation. Pending/open/current target required; request-confirmation acceptance checks source workspace readiness. Reject reason follows payload requirement. Generic repeated terminal resolution conflicts rather than universally deduplicating. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Fresh accept/reject records exact actor/result. Competing opposite decisions yield one winner. Stale/closed/expired/withdrawn target, missing reason and human-only agent fail without repeated task/provider/wake. + +Gaps: Tool/secret/connection authorization uses dedicated governed controls; ordinary confirmation is not equivalent. + +### `checkbox-and-suggested-task-selection` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/accept with selectedOptionIds or selectedClientKeys. + +Agent access: `partial` — permitted resolver REST/CLI/native call_api; agent task effects require independent task creation/assignment authority. + +Policy: Same company/readable issue and current effective audience; agents need matching authenticated run/company/agent/responsible user, issue mutation or admitted watchdog containment, no low-trust boundary violation and cross-issue influence allowance. Current review policy can narrow audience; service rechecks cancellation/write authority under lock. Board chat responder must own the conversation. Checkbox IDs/min/max validated; direct accept may use documented defaults if field absent. Suggested tasks require rooted selected tree, same-company parent/project and independent task-bridge/assignment checks for every created task. Persist selected/skipped/created IDs. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Accept subset and explicit empty checkbox selection; reload exact result. Reject unknown/bounded IDs and selected child missing selected parent; verify no partial child creation on denial and no duplicates. + +Gaps: Task-tree details also belong to task-coordination; default selection is not conversational user provenance. + +### `item-verdicts` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/verdicts. + +Agent access: `partial` — authorized REST/native call_api standard/skill_test; no dedicated CLI verdict wrapper found. + +Policy: Same company/readable issue and current effective audience; agents need matching authenticated run/company/agent/responsible user, issue mutation or admitted watchdog containment, no low-trust boundary violation and cross-issue influence allowance. Current review policy can narrow audience; service rechecks cancellation/write authority under lock. Board chat responder must own the conversation. Only request_item_verdicts; enabled verdicts/IDs/required reason checked. First decision retained for repeated item IDs; partial result persists, complete after all items. New item IDs trigger continuation; replay same items does not. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Submit partial/repeated/final subsets; reload retained first verdicts. Invalid IDs/verdict/reasons leave state unchanged; later expiry preserves already resolved items. + +Gaps: Live partial-verdict continuation remains separate evidence. + +### `resolve-from-comment` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/resolve-from-comment. + +Agent access: `partial` — active responding agent REST or native call_api standard/planning/skill_test; denied in Ask; no dedicated CLI wrapper. + +Policy: Agent's authority retained. Exact running source task assignment/executionRunId, valid write/run/responsible-user identity and resolver policy. Latest nondeleted unquarantined human comment after card from expected user, no /new or prior session boundary. Only confirmation/checkbox; governed metadata denied. Checkbox accept needs explicit selectedOptionIds. Same comment/decision/selection/reason replay deduplicates; conflicting replay fails; no self-wake. + +Evidence: `source-only` — [comment provenance](../../server/src/services/confirmation-comment-resolution.ts), [interaction routes](../../server/src/routes/issues.ts), [native REST modes](../../server/src/services/native-runtime/runner-api-catalog.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Record legitimate reply, repeat -> deduplicated and one activity. Reject foreign/older/newer-superseded message, wrong user/session/run, human-only/governed card, missing explicit selection and Ask-mode invocation. + +Gaps: Server validates provenance and authority, not semantic certainty of arbitrary human text. + +### `withdraw` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/withdraw. + +Agent access: `partial` — board or permitted creator/current-assignee agent with valid run, containment and review authority. + +Policy: Withdrawal is a stored lifecycle change, separate from local dismissal. Validate current pending task/card and creator/assignee authority; an executing linked tool request cannot be withdrawn. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Withdraw through each permitted actor, reload terminal state, and reject unrelated agent, stale/closed card, invalid run or executing tool. Repeated withdrawal must not cause another effect. + +Gaps: No agent skip authority or generic manual expiry API. + +### `skip` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/skip. + +Agent access: `restricted` — board-only; no agent skip authority. + +Policy: Require an eligible open task and pending interaction. Save cancelled status with the skipped result and retain any partial item verdicts. Linked pending/approved requests follow their cancellation/withdrawal rules; executing tool work cannot be skipped. This route deliberately queues no continuation. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Skip a pending disposable request and inspect the saved skipped receipt, retained partial verdicts, linked request state and unchanged run count. Reject agent, repeated decision and already-executing tool. A later ordinary message is separate steering. + +Gaps: No agent skip authority or generic manual expiry API. + +### `observe-expiry` + +API: `present` — GET /api/issues/{id}/interactions; lifecycle writes are server-owned. + +Agent access: `partial` — permitted receipt reads only; no generic agent manual-expiry endpoint. + +Policy: Closed tasks, stale target revisions, a newer same-creator/kind request or explicit opt-in comment supersession invalidate the applicable pending request. Default ordinary comments do not. GET can derive legacy expiration without a persistence write. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Compare default pending-after-comment, opt-in supersession, stale revision and independent sibling cases. Expired cards reject later decisions; the read must not invent activity, a wake or repeated side effects. + +Gaps: No agent skip authority or generic manual expiry API. ## `plan-review` Capability ID: `questions-and-approvals/plan-review`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Review exact saved plan, then distinguish ordinary execution from Agent Chat handoff. -- `PUT /api/issues/{id}/documents/{key}`. -- `POST /api/issues/{id}/interactions`. +### `publish-and-revise` -Agent access: `partial` — Native write_document/request_human_input; explicit review -recipient. +API: `present` — GET /api/issues/{id}/documents/plan; PUT /api/issues/{id}/documents/plan with the current base revision; POST /api/issues/{id}/interactions with the exact saved plan revision. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — native list/read/write_document + request_human_input when actual mode/profile admits; direct REST/CLI supported fields. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Document ACL/version gates; request insert validates current target revision atomically. Native supplied targetRevisionId infers own plan target only for planning confirmation; otherwise full target required. Stable revision-specific key. Product Chat Ask discussion does not authorize plan/task writes. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [interaction service](../../server/src/services/issue-thread-interactions.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [chat directive](../../server/src/services/agent-conversations.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Plan revision and confirmation work. Accepting as a human is not a generic agent -capability. +Verification: `not-run` — Save plan and request exact returned revision; reload, edit and reject old base/card. No project/execution tasks merely from drafting. Ask discussion must not become handoff. + +Gaps: Historical revision/view/edit races need explicit proof; dedicated native schema is not arbitrary REST. + +### `accept-current-or-request-changes` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/accept; POST /api/issues/{id}/interactions/{interactionId}/reject. Agent conversational resolution has its own operation below. + +Agent access: `partial` — eligible human or agent resolver under the ordinary audience, run and readiness policy; server-bound native completion review is a separate operation below. + +Policy: Locks revalidate current target, reviewer and eligible task. Own-plan acceptance can change planning to standard and return the exact creator ownership; non-plan/checkbox acceptance cannot. Rejection retains planning and carries the reason. Live-source finalization readiness can block acceptance; failed/stale finalization after an ended source has different rules. Accepted-plan continuation retains the exact revision and fresh workspace-aware session. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Accept a current plan and reject a separate request; inspect mode, owner, reason, accepted revision and useful continuation. Reject stale/foreign revision or excluded resolver. Compare repeated/conflicting generic decisions without assuming native-review deduplication. + +Gaps: Acceptance alone is not linked task creation or provider execution. + +### `resolve-assigned-native-review` + +API: `present` — production resolve_review calls POST /api/issues/{id}/interactions/{interactionId}/accept or POST /api/issues/{id}/interactions/{interactionId}/reject for its one server-bound review. + +Agent access: `available` — the actual bound native completion-review run exposes resolve_review. It cannot choose an arbitrary issue/review or take over the worker task. + +Policy: Recheck the current server-issued review assignment and independent reviewer policy. Reject requires a reason. Same decision already resolved by the admitted review run returns a deduplicated receipt; a different or stale decision fails. Record the verdict without changing task ownership; task completion still waits for every required reviewer. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Inspect submitted work through a real bound reviewer, accept or reject with a reason, replay the exact decision, and reject retargeting, missing/stale binding, creator exclusion and conflicting verdict. Compare reviewer receipt, task ownership and all required review outcomes. + +Gaps: A declared scenario review tool is not an admitted review run. Review verdict and the reviewer’s own paperclip_finish report are separate obligations. + +### `resolve-chat-plan-continuation` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/accept or POST /api/issues/{id}/interactions/{interactionId}/reject; eligible agent-only POST /api/issues/{id}/interactions/{interactionId}/resolve-from-comment. Subsequent continuation is server-owned. + +Agent access: `partial` — conversation owner human controls; responding agent must retain its own resolver authority. No separate chat-plan approval API. + +Policy: Immutable conversation owner, exact accepted/rejected request context and acceptedTargetRevision. Chat directive authorizes handoff only when person requested approval and current accepted plan continuation has no newer wake comment; unrelated/history/new-session card cannot become fresh approval. Accept doesn't create project/tasks itself. + +Evidence: `source-only` — [chat workflow](../../server/src/services/agent-conversations.ts), [review context](../../server/src/services/heartbeat/run-preparation.ts), [continuation prompts](../../server/src/services/heartbeat/task-markdown.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Owner accepts/rejects; inspect fresh and resumed prompt identity/revision/reason. Reject wrong owner, newer-comment or unrelated historical context; chat remains reusable. + +Gaps: Prompt/source contract requires actual agent handoff outcome; scripted browser fixture is not real model proof. + +### `chat-project-and-task-handoff` + +API: `present` — GET /api/companies/{companyId}/projects; GET /api/companies/{companyId}/project-repositories; POST /api/companies/{companyId}/projects; POST /api/companies/{companyId}/issues with the intended project, assignee, initialPlan and stable creation key. + +Agent access: `partial` — advertised native list_projects/list_project_repositories/create_project/create_task; admitted legacy project-MCP wrapper or direct REST. Actual client binding required. + +Policy: After accepted scope, reauthorize run/task/generation/standard-or-skill_test project write, same-company project/repository, responsible user and assignment/trust. Native conversation create_task fixes parentId null/standard mode and persists initialPlan atomically before wake. Project/task receipts prevent duplicates and compare fingerprints. Legacy wrapper fixes todo/blocked, omits person-assignee/status parity. Generic schema does not guarantee suitable project/copied plan; verify result. + +Evidence: `source-only` — [legacy wrappers](../../server/src/services/project-tools.ts), [project authority](../../server/src/services/project-tool-context.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [project receipts](../../server/src/routes/projects.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Inspect suitable project, standalone assigned tasks and relevant persisted plan before first execution; source plan unchanged. Replay/concurrent exact key -> one task/project, changed payload conflicts. Deny stale generation/project/repository/assignee/company and restricted mode. + +Gaps: Native/legacy field differences persist. Real model choosing project/plan subset remains live gap; cross-link agent-chat/handoff. + +### `source-plan-approval-evidence` + +API: `present` — GET /api/issues/{id}/interactions and GET /api/issues/{id}/documents/plan are source reads under their own visibility. GET /api/issues/{id}/documents/plan/revisions returns saved revision bodies; the unsuffixed document route returns the current body. Neither computes sourcePlanApproval. Native get_task_context exposes sourcePlanApproval; there is no standalone handoff-approval REST endpoint. + +Agent access: `partial` — bound native task context; legacy description/context may carry explicit source IDs. No universal source browsing guarantee. + +Policy: Same-company originRunId points to conversation; newest eligible accepted plan resolved before task creation joins exact stored revision with source privacy. Pending/later/foreign/nonconversation gives no approval; Muse additionally filters trust. This informs source scope, not approval of new task plan/changed work. No atomic copied-plan equality or current-generation guarantee. + +Evidence: `source-only` — [source approval selector](../../server/src/services/native-runtime/handoff-plan-context.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Read worker source approval after newer unapproved draft; exact historical accepted revision only. Foreign/private/no-origin/pending/later evidence absent; new plan has no fabricated own acceptance. + +Gaps: Historical selection/generation and edit-race limitations remain explicit; actual useful worker execution not proven by context alone. ## `audience` Capability ID: `questions-and-approvals/audience`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Persisted audience and current authority govern every operation, including permitted agent reviewers. -- `GET /api/issues/{id}/interactions`. +### `requested-and-effective-policy` -Agent access: `available` — API resolver checks; assigned review context/resolve_review -for a native review run. +API: `present` — GET /api/issues/{id}/interactions; POST /api/issues/{id}/interactions accepts permitted policy/addressee fields. There is no independent audience-override endpoint. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `partial` — permitted REST create/read; native dedicated producer lacks arbitrary audience fields. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Company kind cap/default, server-owned governed clamp, immutable chat user and valid same-company addressee. human_only and not_creator independent constraints; legacy provenance preserves creator/source-run exclusion. Binding review policy may narrow, never widen persisted audience. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [resolver audience](../../server/src/services/issue-thread-interaction-resolution.ts), [interaction service](../../server/src/services/issue-thread-interactions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Audience is a permission boundary to test, not an endpoint that creates new -authority. +Verification: `not-run` — Compare requested/effective/source provenance; attempt self/foreign/both addressees, forged governed policy or legacy widening -> deny/retain restriction. + +Gaps: No resolution-time permission grant can be inferred from a displayed label. + +### `eligible-human-or-agent-resolution` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/respond, POST /api/issues/{id}/interactions/{interactionId}/accept, POST /api/issues/{id}/interactions/{interactionId}/reject and POST /api/issues/{id}/interactions/{interactionId}/verdicts. Assigned native review resolves through its bound route. + +Agent access: `partial` — eligible human or authenticated agent resolver; native resolve_review only server-bound exact completion review, no arbitrary target. + +Policy: Shared read/mutation/run/responsible-user/containment/cross-issue gates plus named addressee, creator/source-run and independent requester exclusion. Authorized human may override agent addressee, never another named user or creator exclusion. Board chat owner restriction. Missing independent requester fails closed. Governed tool/secret approval always human. + +Evidence: `source-only` — [interaction routes](../../server/src/routes/issues.ts), [resolver audience](../../server/src/services/issue-thread-interaction-resolution.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Run matrix named user/agent, different actor, creator/source run, no/mismatched run, human-only+not_creator, unknown review requester, low-trust/watchdog/private/foreign. Denial leaves pending/no downstream effect. + +Gaps: Permitted agent answer is attributed agent decision, not impersonation of human. Host/provider live matrix remains not-run. ## `governance` Capability ID: `questions-and-approvals/governance`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Formal approval request/read/revision/decision operations retain independent board authority. -- `POST /api/companies/{companyId}/approvals`. -- `POST /api/approvals/{id}/approve`. -- `POST /api/approvals/{id}/reject`. +### `read-and-context` -Agent access: `restricted` — Agent REST/MCP can request/read/comment/resubmit; formal -approve/reject require board. +API: `present` — GET /api/companies/{companyId}/approvals; GET /api/approvals/{id}; GET /api/approvals/{id}/issues; GET /api/approvals/{id}/comments. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — agent REST/CLI approval list/get; native list_approvals/get_approval/get_approval_context; public MCP paperclip_pending_approvals returns links only. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Company_scope:read where route requires; every ID route hides approval unless all linked/payload tasks readable, including responsible-user/private scope. Native context filters linked tasks. Read capability doesn't grant decisions. -Verification: `not-run` — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +Evidence: `source-only` — [approval routes](../../server/src/routes/approvals.ts), [approval privacy](../../server/src/services/authorization.ts), [native authority](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [assistant pending links](../../server/src/services/public-mcp/capabilities.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Scenario decide_approval does not establish a production agent approval path. -Preserve explicit approver authority. +Verification: `not-run` — Read visible approvals/history/context; foreign/private-linked/payload task hidden and no secret values; pending link alone can't decide. + +Gaps: Different read routes have different company-scope checks; live native/MCP identity separately qualify. + +### `request-and-comment` + +API: `present` — POST /api/companies/{companyId}/approvals; POST /api/approvals/{id}/comments. + +Agent access: `available` — permitted agent REST/CLI approval create/comment, native call_api standard/skill_test; human REST. + +Policy: Company/source visibility; creation resets pending/actor attribution and deduplicates linked IDs; hire payload secret normalization/redaction. Explicit status-only recovery agent cannot create/comment. Legacy route does not require universal active run when absent. + +Evidence: `source-only` — [approval routes](../../server/src/routes/approvals.ts), [linking](../../server/src/services/issue-approvals.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Agent requests/comments with readable source, reload author/link/pending; status-only/foreign/private denies, secrets redacted. + +Gaps: Creation/linking/each payload-specific governed effect needs separate evidence; no agent decision granted. + +### `approve-reject-or-request-revision` + +API: `present` — POST /api/approvals/{id}/approve, /reject, /request-revision. + +Agent access: `restricted` — board/company/approval visibility; CLI only with board context. Agent REST/native call_api and personal assistant cannot decide. + +Policy: Auth actor supplies decidedByUserId; body cannot spoof. Approve/reject pending or revision_requested with conditional update; repeated same terminal verdict no-op/no repeated effect, opposing verdict 422. requestRevision only pending; no equal replay guarantee. Newly applied decision alone triggers reviewed lifecycle/adapter/linked continuation. + +Evidence: `source-only` — [approval routes](../../server/src/routes/approvals.ts), [conditional records](../../server/src/lib/approval-records.ts), [governed effects](../../server/src/services/approvals.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Board decisions and revision request, reload audit + actual governed effect. Duplicate same decision one effect; concurrent opposite fails; agent denied and forged actor ignored. + +Gaps: Request-revision concurrency/replay not claimed as equivalent to approve/reject; payload integrations remain explicit. + +### `resubmit` + +API: `present` — POST /api/approvals/{id}/resubmit. + +Agent access: `partial` — board or original requesting agent REST/CLI; admitted native call_api standard/skill_test. + +Policy: Only revision_requested; original requesting agent required, status-only recovery denied. Optional normalized replacement payload; returns pending and clears note/decider/time. Private linked source still required. + +Evidence: `source-only` — [approval routes](../../server/src/routes/approvals.ts), [resubmission](../../server/src/services/approvals.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Original agent resubmits revised payload -> pending/cleared decision; wrong agent/status-only/terminal request denied. Reload pending/history. + +Gaps: No generic formal cancel endpoint or broad agent approver exists. ## `tool-review` Capability ID: `questions-and-approvals/tool-review`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Human review and provider execution are independently recorded and scoped. -- `POST /api/tool-gateway/action-requests/{id}/approve`. -- `POST /api/tool-gateway/action-requests/{id}/decline`. +### `invoke-request` -Agent access: `restricted` — Agent invokes assigned ask-policy tool; board approval -executes stored request. +API: `present` — POST /api/tool-gateway/tools/call through an authorized gateway session, or the actual assigned MCP tools/call protocol. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `partial` — an actually assigned eligible tool/gateway client can invoke the governed operation. Optional/scenario client presence is not admission. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Server execution creates the signed invocation, pending action request and linked card with original argument, identity and catalog snapshots. Raw caller-supplied toolAction metadata cannot create authority. Ask first prevents the external call until the independent reviewer approves. -Verification: `not-run` — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +Evidence: `source-only` — [tool execution](../../server/src/services/tool-gateway.ts), [queue](../../server/src/routes/tool-access.ts), [interaction routes](../../server/src/routes/issues.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: The request/continuation path exists. Agent cannot grant itself once/always-allow -scope via generic API. +Verification: `not-run` — Invoke a harmless Ask first action through the actual assigned client. Inspect one pending signed request/card and no early provider effect. Reject an excluded actor, fabricated payload or revoked binding. + +Gaps: Optional MCP client/scenario declaration doesn't establish production assigned tool availability. + +### `read-task-review` + +API: `present` — GET /api/issues/{id}/interactions. + +Agent access: `available` — permitted task-local REST/native/CLI reads under task/company/privacy authorization. + +Policy: Reading a task review card does not grant approval or company-wide queue access. Preserve exact connection, tool and argument scope. + +Evidence: `source-only` — [tool execution](../../server/src/services/tool-gateway.ts), [queue](../../server/src/routes/tool-access.ts), [interaction routes](../../server/src/routes/issues.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Reload a permitted task card and compare signed request identity/context. Reject private/foreign task access; a reader without decision authority must not gain it from the visible card. + +Gaps: Optional MCP client/scenario declaration doesn't establish production assigned tool availability. + +### `read-board-queue` + +API: `present` — GET /api/companies/{companyId}/tools/action-requests with the supported status filter. + +Agent access: `restricted` — board company queue; ordinary agents use their permitted task-local context. + +Policy: The queue enforces board identity and company access independently of task-local card reads. Queue visibility does not approve an action or imply provider execution. + +Evidence: `source-only` — [tool execution](../../server/src/services/tool-gateway.ts), [queue](../../server/src/routes/tool-access.ts), [interaction routes](../../server/src/routes/issues.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Read the queue as a permitted board person and match the task card/request after reload. Reject ordinary agent and foreign-company queue reads; inspect decision affordances separately. + +Gaps: Optional MCP client/scenario declaration doesn't establish production assigned tool availability. + +### `approve-once-or-decline` + +API: `present` — POST /api/tool-gateway/action-requests/{id}/approve or /decline with companyId; task accept/reject dispatches same callback. + +Agent access: `restricted` — board nonviewer active company membership (local implicit/instance-admin exceptions); service rejects agent actor; native fallback preserves denial. + +Policy: Exact task/card/request/invocation signed binding, open/unexpired pending state, resolver addressee/human policy. Definition/connection/identity/current policy rechecked; required formal approval must be approved. Same settled decision returns current state; conflicting decision fails. Approval may execute stored request; decline never does. + +Evidence: `source-only` — [review route](../../server/src/routes/tool-gateway.ts), [review transaction](../../server/src/services/tool-action-review.ts), [execution checks](../../server/src/services/tool-gateway.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Decide concurrently from task/queue, reload synchronized one receipt/provider call. Reject wrong context/company/agent/viewer/stale/expired/revoked/snapshot/formal-gate request. Provider failure remains approved+failed. + +Gaps: Decision acceptance isn't provider delivery/termination proof; uncertain action never replayed automatically. + +### `approve-and-remember` + +API: `present` — POST /api/tool-gateway/action-requests/{id}/approve with rememberAction. Separate administration uses POST /api/companies/{companyId}/tools/action-requests/{actionRequestId}/trust-rule and POST /api/companies/{companyId}/tools/trust-rules/{policyId}/revoke. + +Agent access: `restricted` — human review authority; trust administration active board tool membership; no agent self-allow. + +Policy: Approval and displayed action-wide trust rule atomic. Only reviewed approved/executed ask-required source, bounded selectors/definition; rule failure rolls approval back. Changed arguments may be allowed within scope, but Off/deny and changed catalog still win. Formal-gated source cannot gain action-wide permission. + +Evidence: `source-only` — [remember transaction](../../server/src/services/tool-action-review.ts), [rule scope](../../server/src/services/tool-access-policy.ts), [rule administration](../../server/src/routes/tool-access.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Approve remember then safe changed args obey rule; Off/definition change still blocks/reviews. Failed rule save leaves pending/no execution. Revoke rule then next action follows current policy. + +Gaps: Cross-link app-permissions for full trust administration; not company-wide blanket trust. + +### `execution-and-continuation` + +API: `present` — GET /api/companies/{companyId}/tools/action-requests and GET /api/issues/{id}/interactions expose saved decision/outcome. Delivery workers process the accepted signed request and eligible continuation. + +Agent access: `partial` — agent receives own settled tool result/continuation, board inspects; no authority from local dismissal. + +Policy: Decision status distinct from executed/failed/expired/unknown. Test-tab has no agent so approval runs stored test call; agent executionOnApprove uses exact stored operation and current authority. Durable settled/outbox receipts avoid duplicate provider calls/wakes on retry/restart; uncertain write not blindly retried. + +Evidence: `source-only` — [tool result delivery](../../server/src/services/tool-action-delivery.ts), [settlement](../../server/src/services/tool-gateway.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Failure after approval stays accepted with useful failure context; lost response/restart retains one call/continuation; dismissing doesn't decide; inspect actual useful provider result. + +Gaps: Scripted process/local MCP E2E isn't live provider/model qualification. ## `continuation` Capability ID: `questions-and-approvals/continuation`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +A durable response feeds the eligible source input or continuation without repeating work. -- `GET /api/issues/{id}/interactions`. -- `GET /api/heartbeat-runs/{runId}`. +### `read-and-deliver-answer` -Agent access: `available` — Server delivery and resumed assigned agent context. +API: `present` — GET /api/issues/{id}/interactions; GET /api/heartbeat-runs/{runId}. The response routes atomically write the delivery outbox; delivery is server-owned. -Policy: Current task/run and named audience/resolver policy; governed approval decisions -require board independently of an ordinary interaction. +Agent access: `available` — permitted reads/native task context; actual bound waiting-input bridge or server continuation receives response, not an arbitrary model-created wake. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L16638) at -the reviewed commit above. +Policy: Exact interaction/source/payload digest and current task/assignee. Waiting native/PRP input first; unavailable session remains pending. Running successor answer queues rather than auto-steers; never steer into source solely because alive. No target/terminal task fails safely; historical Done answer has no outbox. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [answer delivery](../../server/src/services/question-response-delivery.ts), [interaction routes](../../server/src/routes/issues.ts), [native bridge](../../server/src/services/native-runtime/native-interaction-bridge.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. -Gaps: Continuation is server-owned; prove exactly one wake/no duplicate action after -resolution with existing integration fixtures. +Verification: `not-run` — Save answer, inspect exact delivery/run/source and useful next answer. Hold input session unavailable -> durable pending, recover once. Reassign/terminal/pause/budget/privacy deny stale execution. + +Gaps: Answered status not proof provider consumed it; each real runtime must qualify. + +### `recover-and-deduplicate` + +API: `present` — GET /api/issues/{id}/interactions; GET /api/heartbeat-runs/{runId}. Existing decision APIs and durable delivery/wake receipts govern server retries; no agent bypass API exists. + +Agent access: `available` — eligible resumed agent context; control owned by server, operators observe supported reads. + +Policy: Generation-fenced lease, bounded actual-error retry and separate suppressed-wake retry; reuse committed wake after lost acknowledgment/restart. Queued successor coalesces. New verdict IDs only; skip no wake; cancel/withdraw durable cancellation first. Plan/rejection continuation obeys policy and exact source; native completion waits all reviewers. + +Evidence: `source-only` — [answer delivery](../../server/src/services/question-response-delivery.ts), [action outbox](../../server/src/services/tool-action-delivery.ts), [interaction routes](../../server/src/routes/issues.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Concurrent delivery/restart reuses one wake/side effect; stale worker cannot fallback; suppressed retry doesn't exhaust actual error budget or ignore gates. Check rejection reason/fresh plan session. + +Gaps: Exactly-once provider outcome is not inferred from DB uniqueness; inspect external effects separately. + +### `external-channel-isolation` + +API: `present` — POST /api/issues/{id}/interactions/{interactionId}/respond records the normalized response; GET /api/issues/{id}/interactions exposes its persisted result. Provider identity/callback transport remains a separate channel-specific protocol. + +Agent access: `partial` — configured provider-linked sender; assigned channel tools/runtime receive server-bound response. Browser response isn't external-provider proof. + +Policy: External chat source cannot steer/coalesce into unrelated provider turn. Source waiting process must retire before isolated continuation; preserve original company/task/provider/message provenance and identity grants; failed/unknown retirement stays visible. + +Evidence: `source-only` — [answer delivery](../../server/src/services/question-response-delivery.ts), [channel authority](../../server/src/services/chat-channels.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live proof. + +Verification: `not-run` — Answer in actual configured channel -> one persisted result/useful originating reply; wrong/unlinked/expired sender denied. Overlap two conversations and verify no cross-delivery/replay. + +Gaps: Slack/Discord/Telegram/email/iMessage and runtime paths independently not-run until driven. diff --git a/maps/agent-access-map/recovery.md b/maps/agent-access-map/recovery.md index 5eadaf0c3d2..8824b6a3454 100644 --- a/maps/agent-access-map/recovery.md +++ b/maps/agent-access-map/recovery.md @@ -4,352 +4,436 @@ Product map: [Recovery](../feature-map/recovery.md). Feature ID: `recovery`. -Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`. -Native REST transport reconciled in this change; see the -[shared transport contract](README.md#native-rest-transport). +Source revision: `3bbc2104b65caf9f7763938a01260a5673e12f7a`. -This is a source-reviewed baseline of representative operations and known gaps. -Each capability needs operation-level review before its entire scope can be -qualified. No live agent execution is claimed. Follow the [map contract](../README.md) -for format, permission checks, evidence and maintenance. +Review depth and executed proof are separate. The operation records enumerate the named behavior and access boundaries. Their evidence states describe the reviewed sources; run results and environment limits belong in the PR or verification artifacts. A listed API or source test does not establish a live authorized journey. Follow the [map contract](../README.md). + +Source-reviewed operation contracts at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; proposed checks remain not-run. Preserve existing native/legacy ownership, retained-source and historical failed-evidence caveats. Automatic classification is server work, not an agent retry API. REST, native binding, operator, provider and WebSocket clients have distinct authority. ## `diagnosis` Capability ID: `recovery/diagnosis`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Read causes, owner/attempt state and retained obligations without claiming successful recovery. -- `GET /api/issues/{id}/diagnostics/blockers`. -- `GET /api/issues/{id}/recovery-actions`. +### `read-action-and-source` -Agent access: `available` — REST / native call_api; CLI issue diagnostics. +API: `present` — GET /api/issues/{id}/recovery-actions, GET /api/issues/{id}, GET /api/heartbeat-runs/{runId}. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. -Graceful legacy shutdown retains the exact sandbox until its owned adapter -settles, including after the first shutdown wait. A renewed settlement fence -protects cleanup by other controllers. Loss of the owner retains the source -for repair after expiry. This automatic protection grants no agent operation, -execution permission, or bypass of workspace repair gates. -The server can recover a prepared remote bootstrap only with a durable -never-claimed executor receipt and no contradictory execution evidence. This -automatic classification grants no new agent action or permission; normal -execution admission and durable runner-state verification still apply. -The current server's active preparation remains with its existing execution. -A preparation that loses the coordinator lease cannot fail the shared run or -revoke the new owner's gateway tokens, even after lease expiry. Only normal -recovery can establish a takeover claim; no agent permission is added. -Older unmarked preparations do not qualify for this automatic path during an -upgrade. The fencing marker comes from fresh server-owned identity creation; -caller profile data cannot upgrade an existing preparation. +Agent access: `available` — permitted agent REST/native call_api reads and CLI issue recovery-actions for that operation; actual native rollout/run binding required. -Remote process-health reads retry within a bounded budget. An unavailable probe -cannot authorize replacement or erase the original ownership marker. This is -internal supervision; it grants no new agent recovery action. Existing task, -company, process-identity and workspace-recovery checks remain required. +Policy: Same-company task read authorization, private-task/responsible-user scope and run privacy where run detail is used. Related diagnostics omit unauthorized resource details. Recovery action response includes active plus supported retained settled replay-blocked/native export holds, not unrestricted history. Read revalidation may retire stale action through system lifecycle; no reader participation/physical copyback. -An execution-hold denial before legacy runtime selection is not a provider -attempt. The server verifies the dispatch receipt and task identity against -persisted execution, lease and coordinator evidence. The same proof excludes -historical false incidents from effective holds while retaining audit history. -This internal classification grants no new agent API or resolution authority. -The original hold, file recovery, company scope and normal admission gates stay -effective. Local [database regressions](../../server/src/__tests__/heartbeat-undispatched-execution-wait.test.ts) -cover automatic saved-message admission and denied cases; live provider recovery -remains a separate verification step. +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [source actions](../../server/src/services/issue-recovery-actions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Verification: `not-run` — Compare exact company/task/action/source run/owner/attempts/next-action across views and reload. Private/foreign read denied. Repeated Done/cancelled read retains exact unresolved physical owner hold. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Gaps: Recorded cause or successful GET isn't a running retry or restored files. -Gaps: Diagnostics expose recorded cause and boundaries; source-backed reading does not -prove successful recovery. +### `read-blocker-wake-and-subtree-diagnostics` + +API: `present` — GET /api/issues/{id}/diagnostics/blockers, /diagnostics/wakes, /diagnostics/subtree. + +Agent access: `available` — permitted REST or native call_api; no dedicated CLI issue diagnostics command confirmed. + +Policy: Same-company task read authorization, private-task/responsible-user scope and run privacy where run detail is used. Related diagnostics omit unauthorized resource details. Wake internal IDs depend on company-scope read; linked blocker/child/wake detail filtered. Diagnostics bounded/read-only. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [diagnostic discovery](../../server/src/services/native-runtime/runner-api-reference.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Read source diagnosis and compare visible blockers/wakes/subtree; unauthorized linked nodes omitted and no mutation/new attempt on repeat. + +Gaps: CLI recovery-actions is supported; don't invent diagnostics subcommands. Coverage of every diagnostic inference remains separate. + +### `inspect-run-recovery-host` + +API: `present` — GET /api/issues/{id}/recovery-actions; GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}. The run UI host adds no separate recovery API. + +Agent access: `available` — permitted agent REST/native call_api reads and CLI issue recovery-actions for that operation; actual native rollout/run binding required. + +Policy: Same-company task read authorization, private-task/responsible-user scope and run privacy where run detail is used. Related diagnostics omit unauthorized resource details. Run workspace controls only for failed workspace_validation_failed run linked to source task with live workspace_validation action; other failures use source task. + +Evidence: `source-only` — [run host](../../ui/src/components/RunWorkspaceRecoverySurface.tsx), [recovery routes](../../server/src/routes/issues.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Exact eligible run and task agree; deny missing authority and hide stale/other-code controls; reload same persisted action. + +Gaps: Component host test doesn't prove actual filesystem/provider repair. ## `bounded-continuation` Capability ID: `recovery/bounded-continuation`. -Controller recovery can restore the exact active turn's saved completion proposal -before reconnecting its provider. It requires matching run/session/source/turn -identity and subsequent provider termination. This adds no agent retry, completion, -or recovery-resolution authority. The -[runtime regressions](../../packages/paperclip-runner/src/native-session-runtime.test.ts) -cover the driver boundary with simulated transport; live hosted recovery remains -separate qualification. +Review: `operation-reviewed`. -Review: `baseline`. +Supported restoration and automatic attempts retain source/owner/attempt authority. -API: `present` — representative operation IDs: +### `observe-automatic-attempt` -- `POST /api/issues/{id}/recovery-actions/resolve`. +API: `present` — GET /api/issues/{id}/recovery-actions; GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}. Automatic recovery has no generic agent-enqueue endpoint. -Agent access: `partial` — Eligible agent REST / native `call_api` / CLI under -source-bound recovery authority. +Agent access: `available` — permitted agent REST/native call_api reads and CLI issue recovery-actions for that operation; actual native rollout/run binding required. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. +Policy: Server-owned bounded continuation uses exact run/source identity, current owner/normal admission and durable episode limits. Stop, pause, budget, durable wait, owned lifecycle and existing execution remain gates; native exact completion proposal requires source/session/turn+termination proof, not just terminal row. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Evidence: `source-only` — [source actions](../../server/src/services/issue-recovery-actions.ts), [legacy bounded decision](../../server/src/services/recovery/legacy-continuation.ts), [native recovery](../../server/src/services/native-runtime/native-restart-recovery.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Verification: `not-run` — Observe attempts/retry timing and actual useful result; concurrent sweeps don't reset budget or duplicate turn. Operator Stop/chat idle must not trigger unwanted recovery. -Gaps: Eligible resolutions use native `call_api`. The route retains owner and -management authority, active-run/source-trust checks, board-only outcomes and -reconciliation controls. +Gaps: Native/Legacy and live provider takeover need separate proof; preserve existing failed callback evidence. -Scoped source review: 2026-10-13, recovery correction against -`ea6c8eb5e16d61111968f633a66748b397b64a3e`. The -[recovery service](../../server/src/services/recovery/service.ts) reuses the -existing completed-onboarding handoff validator. It checks the source company, -onboarding origin, Done parent, assignee and Done child, with no unfinished -siblings, before exempting the report from the issue-terminal backstop. Other -terminal work and process-death/controller ownership checks remain enforced. -This internal wake handling adds no recovery-resolution or cross-company agent -authority. Real PostgreSQL regressions cover allowed and rejected bindings; -revised live agent authorization and callback delivery remain `not-run`. +### `resolve-permitted-source-action` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with exact actionId/outcome/sourceIssueStatus/resolutionNote. + +Agent access: `partial` — eligible REST/CLI issue recovery:resolve; native call_api standard/skill_test. false_positive/cancelled and special reconciliation/workspace paths board-only. + +Policy: Agent needs issue:mutate, authenticated run, low-trust exclusion and cross-issue allowance; source assignee/action owner or admitted active-checkout management override. Action ownership does not itself grant source-task mutation rights. Board and agent route policies remain distinct. Status changes separately require source owner/current execution participant/management grant or guarded exact-owner handback. blocked needs unresolved first-class blocker. Restored todo cannot bypass task/project/subtree/budget/review/approval/competing-run gates. Dedicated workspace causes reject generic retry. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [resolution schema](../../packages/shared/src/validators/issue.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Eligible owner resolves fresh action, reload recorded outcome/state and useful continuation. Peer/recovery-owner source completion, stale target, no blocker, pause/budget/review gates denied without side effects. + +Gaps: CLI body lacks executionReconciliation/workspaceBaseRef; no generic agent permission for operator source repair. + +### `replay-and-deliver-resolution` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve; GET /api/issues/{id}/recovery-actions. Server wake, reconciliation and chat outboxes own delivery. + +Agent access: `partial` — permitted resolution followed by current eligible agent context; no arbitrary client self-wake. + +Policy: Lock exact source/action. Same settled actionId returns retained receipt/no repeated log/wake. Todo wake only when required state/owner changed; reconciled executions use own durable delivery, restricted chat uses exact authorized failed request and real board user/current channel authority. No generic duplicate wake alongside durable owner. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [reconciliation outbox](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Repeat/concurrent same action and lost acknowledgment -> one recorded resolution/eligible continuation. Changed/new action/source never overwritten; restricted chat either retains exact provenance or stays unresolved. + +Gaps: Receipt success isn't provider execution; actual retry may remain gated/pending. ## `source-action` Capability ID: `recovery/source-action`. -The recovery-actions read API includes settled execution reconciliation holds -with an automatic `replay: blocked` receipt, as well as retained workspace holds. -The existing company and task-read checks remain in force. The board notice -reads this history to explain its current hold; this adds no agent mutation -authority. Route and notice regressions cover the source contract, without -claiming live agent or provider qualification. +Review: `operation-reviewed`. -Review: `baseline`. +Source-scoped repair ownership and retained files survive task status changes. -API: `present` — representative operation IDs: +### `read-and-follow-owner` -- `GET /api/issues/{id}/recovery-actions`. -- `POST /api/issues/{id}/recovery-actions/resolve`. +API: `present` — GET /api/issues/{id}/recovery-actions; GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}. Linked repair tasks retain their own access checks. -Agent access: `partial` — Eligible agent REST / native `call_api` / CLI; source-bound -recovery state. +Agent access: `available` — permitted agent REST/native call_api reads and CLI issue recovery-actions for that operation; actual native rollout/run binding required. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. Completion or cancellation of a -task does not clear its exact unresolved native workspace owner hold. Physical -owner release still requires the [operator stop-verification procedure](../../doc/native-workspace-finalization-recovery.md). +Policy: Same-company task read authorization, private-task/responsible-user scope and run privacy where run detail is used. Related diagnostics omit unauthorized resource details. Original assignee, recovery owner and return owner remain distinct. Completion/cancellation doesn't remove physical workspace hold; retired notices shouldn't hide retained obligation. -For a resolved legacy or native action that retains a file hold, the same resolution API -supports source-only file repair. Board runtime management and recovery-resolution -authority are required. The request identifies the exact source action/run and -records recovered-file evidence; the server verifies the original stop receipt. -It preserves the current task status and does not wake or replay the agent. The -task notice does not expose a file-certification form. The API still fails closed -without permission or source bindings. Agent Chat retains the file diagnosis -while this hold exists and suppresses the warning only for a verified durable -recovery path. The -[repair route regressions](../../server/src/__tests__/workspace-restore-repair-route.test.ts) -and [task notice](../../ui/src/components/ExecutionBlockerNotice.test.tsx) cover the -local contract; they do not independently recover files or qualify a live provider. +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [source actions](../../server/src/services/issue-recovery-actions.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. Exact owner hold retention in the -[recovery state helper](../../server/src/services/native-runtime/native-workspace-finalization-recovery-state.ts) -was reviewed at `89770ba707fb1ebd4cabd184eec2e7fee226e0c3`. +Verification: `not-run` — Follow source/repair/return owner, reload exact IDs; foreign/mismatched source hidden. Unresolved file hold persists after Done/cancelled. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. Local -[recovery route regressions](../../server/src/__tests__/issue-recovery-actions.test.ts) -verify one unchanged hold across reads and sweeps on done/cancelled tasks, no -physical copyback, and cleanup after the receipt is cleared. Exercise this -sequence in a disposable instance; automatic cleanup must use the system actor -and must not create reader participation. No live recovery proof is claimed. +Gaps: Repair task existence does not authorize source mutation or prove recovery. -Gaps: Permitted resolutions use native `call_api` under existing eligibility -and ownership checks. Source/action policy determines whether continuation is allowed. +### `record-retained-file-repair` -A recorded operator Stop before legacy runtime selection releases only that -run's task locks and preserves deferred input for normal later admission. This -does not grant an agent a new retry or provider-stop authority. Local -[database regressions](../../server/src/modules/wake-queue/adapters/queued-operator-stop-postgres.test.ts) -cover the release boundary and a competing active routine cycle; they are not -live provider-stop proof. +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with exact actionId, restored outcome, unchanged source status and workspace repair evidence. + +Agent access: `restricted` — board with accessible source and exact file/stop evidence. Current branch does not additionally enforce runtime:manage; agent REST/native denied. + +Policy: Original terminal retained source validated independently: exact issue/run/lease receipt, stop/process/coordinator/no unreleased authority. Successful legacy source may record files only without changing its result. Preserve current status/owner/newer active action; no replay/wake. Same repair evidence receipt dedupes. Do not document stronger runtime grant than route enforces. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [source/stop validation](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Repair exact historical files, reload unchanged current owner/status/newer action and source result; no wake. Deny agent/foreign/run mismatch/running source/no stop evidence. Duplicate returns saved repair. + +Gaps: Existing desired runtime-manager wording is stronger than implementation; product policy decision separate from map edits. Actual files/artifact must be verified before attestation. + +### `add-new-execution-evidence` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with executionReconciliation on the exact settled automatic replay-blocked action. + +Agent access: `restricted` — board; exact source read, restoration/status and independent execution evidence. + +Policy: Can reopen matching settled no-replay disposition only restored/todo with no competing active action and new accepted source proof; plain repeat returns receipt. Active coordinator/newer turn/retained uncertain authority disallows blind replay. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [reconciliation proof](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — New verified evidence permits one eligible delivery; duplicate safe. Competing current action or missing/mismatched evidence denied and audit history preserved. + +Gaps: Elapsed timeout/client providerStopped flag alone is not proof. ## `exhaustion` Capability ID: `recovery/exhaustion`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Exhausted and overdue recovery advertises only the current eligible operator action. -- `GET /api/issues/{id}/recovery-actions`. -- `GET /api/heartbeat-runs/{runId}`. +### `read-attempt-budget` -Agent access: `partial` — REST / native call_api reads; operator escalation flow. +API: `present` — GET /api/issues/{id}/recovery-actions; GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. +Agent access: `available` — permitted agent REST/native call_api reads and CLI issue recovery-actions for that operation; actual native rollout/run binding required. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Policy: Durable maxAttempts is execution budget; exhaustion retires automatic wake/monitor/timeout paths. Due-but-not-started retry differs from live retry. Same episode identity persists through equivalent ref spellings/new run IDs/classifier upgrades. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [source actions](../../server/src/services/issue-recovery-actions.ts), [attempt display](../../ui/src/components/IssueRecoveryActionCard.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Gaps: Reading exhaustion is supported. Continuing past the recorded gate requires the -specified owner/action. +Verification: `not-run` — Exhaust episode, reload count/gate/no additional automatic wake; overdue retry remains visible as missed rather than working. + +Gaps: Reading attempts isn't qualification of every provider retry lane. + +### `request-explicit-retry` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with exact actionId, restored outcome and todo source status, or the separately authorized workspace operation below. + +Agent access: `partial` — source-permitted resolution; board-escalated/reconciliation/workspace decisions keep their explicit board gates. + +Policy: Exhausted disposition still blocked, exact board-owned deliberate wait/board-escalation action and recorded return owner assigned/invokable; no blockers/pending interaction; normal handback pause/project/budget/approval/run gates. Cannot reset attempts from client. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [retry control](../../ui/src/components/DispositionRecoveryNotice.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — One click waits real acknowledgment, reload one continuation; repeated click stale-owner/paused/blocker/question/budget cases rejected. No new episode budget from repeated request. + +Gaps: An acknowledged retry can remain pending or fail; report actual useful result separately. ## `workspace` Capability ID: `recovery/workspace`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Each workspace repair/export/reconstruction/physical-owner operation has its own proof and authority. -- `POST /api/issues/{id}/recovery-actions/retry-workspace-export`. -- `POST /api/issues/{id}/recovery-actions/recover-workspace`. -- `POST /api/issues/{id}/recovery-actions/reconstruct-workspace`. -- `POST /api/issues/{id}/recovery-actions/resume-workspace-finalization`. -- `POST /api/issues/{id}/recovery-actions/resolve` for retained-source file repair. -- `POST /api/execution-workspaces/{id}/reconcile-branch`. +### `recover-retained-files` -Agent access: `restricted` — Board/runtime management APIs; agent reads diagnosis and -performs permitted workspace work. +API: `present` — POST /api/issues/{id}/recovery-actions/recover-workspace with actionId/runId/idempotencyKey. -Policy: Export retry and branch reconciliation require board runtime management. -The retained-workspace recovery request instead requires an authenticated board -actor with task mutation access. Agents cannot call it. It accepts only the exact -source action/run and an idempotency key. Internal recovery verifies stop and file -receipts; the request certifies neither. Recovery itself starts no agent turn. -Saved human input remains subject to normal admission and cannot replay an old -run. Local PostgreSQL/filesystem tests cover this maintenance and admission path; -live hosted recovery and agent denial must be verified separately. -Reconstruction also requires board runtime management. It verifies exact source -destruction and same-task attachment hashes, records lost work and external action -outcomes, and admits one fresh continuation through normal execution gates. The -old failed export remains failed. A retained or uncertain source cannot use it. -An intervening native run-only cancellation requires its own acknowledged Stop, -confirmed stopped leases, board file repair and `not_performed` action outcome. -The reconstruction records and rechecks that exact proof; other later runs stay denied. -Retained legacy file-only repair requires the board, exact stopped-source receipts, -and recovered-file evidence. It can record repair for a successful legacy turn -without changing its result or authorizing replay. Queued and running sources -remain denied. Source-only reconciliation regressions cover this boundary. -Physical-owner stop confirmation uses the separate `runtime:confirm_owner_stop` -action. It requires active company owner/admin membership, trusted local board -access, or instance administration. Agents and ordinary runtime managers are denied. -The exact source task, running native run, accepted result and owner receipt must -match; active copyback locks, live local writers, and newer runs prevent admission. -An authorized administrator must first verify through the deployment platform that -the exact controller and all copyback children stopped, then attest that evidence. -Elapsed time, an expired coordinator lease or a lost advisory connection is not proof. -Only the exact owner receipt is released; normal reconciliation performs export and -commitment without another provider turn or bypassing existing task waits. +Agent access: `restricted` — board task-read and issue:mutate; not runtime:manage. Agents denied through REST/native fallback. -Evidence: `source-only` — [route](../../server/src/routes/issues.ts), -[administrator authorization](../../server/src/services/authorization.ts), and -[owner admission](../../server/src/services/native-runtime/native-workspace-owner-recovery.ts) -reviewed for this change. Local authorization, route, UI and finalization regressions -cover member/agent denial, exact-owner admission and the real reconciler preserving -monitor and approval waits. This is not live provider-stop proof. +Policy: Exact terminal retained source/lease/reference; independent stop and physical ownership checks; no newer writer. Bounded queued repair preserves newer files and has retry state. Matching key/recovered state dedupes; permanent blocked source refuses. Recovery starts no provider turn. -Verification: `not-run` for live agent/deployment execution — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [retained recovery](../../server/src/services/workspace-recovery.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Gaps: Export retry and branch reconciliation require board runtime:manage at -their HTTP routes. The exact-owner operator fallback additionally requires -runtime:confirm_owner_stop. Native call_api preserves these agent denials. -Automatic managed-cloud recovery uses independently verified, signed platform -proof through the finalization reconciler; agents cannot attest owner shutdown. +Verification: `not-run` — Allowed board requests exact source, inspect persisted copied files/artifact and cleanup. Repeat key/transient retry bounded. Agent/wrong company/newer writer/uncertain owner/no stop denied. + +Gaps: Client never certifies recovered files by posting this request; hosted recovery separately not-run. + +### `retry-accepted-result-export` + +API: `present` — POST /api/issues/{id}/recovery-actions/retry-workspace-export with exact actionId/runId/repairNote. + +Agent access: `restricted` — board task read + runtime:manage; native agent call_api preserves denial. + +Policy: Eligible native export-repair cause, saved result/coordinator/retained source and independent stop-only proof. Reuses original result/lease and bounded finalization, not provider execution. Pending duplicate audits once. Unsafe-export automatic path/manual admission and active exporter/new owner rejected. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [export retry](../../server/src/services/native-runtime/native-workspace-export-retry.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Repaired sandbox export commits original accepted result without new provider turn; repeated click one audit/intent. Deny mismatched source/cause, active writer and unprivileged actor. + +Gaps: Provider stop/probe/export must be actual evidence, not inferred from 202. + +### `resume-after-owner-stop` + +API: `present` — POST /api/issues/{id}/recovery-actions/resume-workspace-finalization with actionId/runId/ownerToken/stopped flag/stopEvidence. + +Agent access: `restricted` — board task read + runtime:confirm_owner_stop; active company owner/admin, trusted local board or current instance admin. Ordinary runtime manager/agent denied. + +Policy: Exact native owner/result/task/run; independent platform verification all controller+copyback children stopped. Lease expiry/advisory disconnect not proof. Active lock/local writer/newer run blocks. Exact replay dedupes; reconciler exports/commits saved result and retains approval/monitor waits without fresh provider turn. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [owner proof](../../server/src/services/native-runtime/native-workspace-owner-recovery.ts), [administrator gate](../../server/src/services/authorization.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — After actual platform stop proof permitted admin records exact owner; inspect original saved result/files/holds and no fresh turn. Deny wrong owner/member/runtime manager/agent/live writer/stale Cloud admin. + +Gaps: Automatic managed-cloud signed stop proof is separate; never invent platform attestation for local acceptance. + +### `reconstruct-destroyed-source` + +API: `present` — POST /api/issues/{id}/recovery-actions/reconstruct-workspace with action/run/statusVersion/task attachments/lost-work acknowledgement/outcome evidence. + +Agent access: `restricted` — board task read + runtime:manage. + +Policy: Server confirms original source destruction, hashes same-task saved attachments, exact current status/source/no contradictory execution. Retained/uncertain source denied. Same request hash dedupes, changed request/state conflicts. Preserve failed old export/history/budget; one fresh normal-admission continuation from recorded sources. Intervening run cancellation proof remains exact. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [reconstruction](../../server/src/services/native-runtime/native-workspace-reconstruction.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Inspect acknowledged lost edits/selected hashes and actual reconstructed files. Retry/concurrent same request one continuation; wrong/private attachment, retained source/status change/false destruction denied. + +Gaps: Original unexported edits remain lost; fresh reconstruction isn't successful original export or permission to replay completed external effects. + +### `source-files-only-repair` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with unchanged source status and exact file-repair evidence. + +Agent access: `restricted` — board with readable source and exact source/action/run proof. This branch does not independently check runtime:manage. + +Policy: Record recovered-file evidence only after independent stopped-source validation. Keep the original result and current task status, owner and execution unchanged; do not reopen or wake work. No invented runtime grant can be inferred from the map. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [file evidence](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Repair a matching retained-file obligation and reload its evidence. Reject missing/stale stop/source proof and agent identity. Compare unchanged task status, accepted result, owner and run count. + +Gaps: This is the actual route boundary. The stronger runtime:manage requirement on dedicated workspace operations must not be imputed to generic file-only resolution. + +### `repair-starting-branch` + +API: `present` — POST /api/issues/{id}/recovery-actions/resolve with the matching workspaceBaseRef repair shape. + +Agent access: `restricted` — board with runtime:manage, readable source, exact recovery action and eligible source mutation authority. + +Policy: Require the current blocked configuration_incomplete/base_ref_unresolved failure, matching assignee/project/requested ref and effective git-worktree strategy. Replacement branch differs from the failed ref. Reject stale configuration, incompatible reconciliation evidence or mismatched source; normal retry admission remains required. + +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [file evidence](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Repair a matching failed starting ref, reload the saved effective strategy and observe one eligible retry. Reject ordinary non-manager, agent, changed ref/project/owner/configuration and stale action. + +Gaps: The simple CLI resolve wrapper does not express this branch-repair shape. Source-file-only repair above has different authority and effects. + +### `reconcile-branch` + +API: `present` — POST /api/execution-workspaces/{id}/reconcile-branch modes forward, override or quarantine_restore. + +Agent access: `restricted` — board + workspace privacy + runtime:manage; agent/native fallback denied. + +Policy: Source task required. Forward re-inspects ancestry or confirmed missing recorded ref+clean resolved target. Override requires reason and current inspection. Quarantine_restore preserves dirty work on rescue ref, respects physical/runtime contention. No browser ancestry hint substitutes source check. + +Evidence: `source-only` — [branch route](../../server/src/routes/execution-workspaces.ts), [branch/filesystem checks](../../server/src/services/execution-workspaces.ts), [mode schema](../../packages/shared/src/validators/execution-workspace.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Exercise offered mode on disposable branches, preserve before/after files/rescue ref and audit. Deny unrelated workspace/private/agent/no grant, wrong ancestry/no reason/live writer. Reload binding and actual files. + +Gaps: No dedicated CLI reconciliation wrapper found; 202/toast isn't filesystem integrity proof. ## `unknown-outcome` Capability ID: `recovery/unknown-outcome`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Inspect actual side effects before explicit source-specific operator resolution. -- `POST /api/chat-endpoints/{endpointId}/publications/{publicationId}/resolve`. +### `inspect-and-reconcile-execution` -Agent access: `restricted` — Board provider-outcome resolution; agent may inspect -assigned provider tools. +API: `present` — GET /api/issues/{id}/recovery-actions; GET /api/heartbeat-runs/{runId}; POST /api/issues/{id}/recovery-actions/resolve with exact run and executionReconciliation evidence. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. +Agent access: `restricted` — source read plus board execution-reconciliation decision; agent may inspect own permitted context, not attest provider state. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Policy: Server independently checks terminal source/task/owner or reviewer, stopped leases/process, no coordinator/successor/unreleased authority and workspace evidence. Outcome completed/not_performed/mixed informs continuation without repeating completed effects. Matching source-only file repair requests do not enqueue work. -Verification: `not-run` — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [execution proof](../../server/src/services/execution-recovery-resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Gaps: Uncertain-side-effect resolution is operator/source-specific; do not replay to -obtain apparent parity. +Verification: `not-run` — Inspect external provider first; wrong source/flag without stop evidence/live owner denied. Record truthful outcome -> one eligible continuation or retained hold; duplicate doesn't replay. + +Gaps: Unknown stays unknown until corroborated. Evidence text alone can't override independent fences. + +### `resolve-chat-publication` + +API: `present` — POST /api/chat-endpoints/{endpointId}/publications/{publicationId}/resolve action mark_delivered/retry_anyway/cancel, optional fileTransfer phase/version. + +Agent access: `restricted` — board endpoint/company + tools:manage_connections (local implicit/instance-admin exceptions) and board user ID. + +Policy: Only current delivery_unknown; credential lease/exact publication; stage-specific Teams/Slack/Photon rules and current phase apply. mark delivered/cancel settle; retry_anyway explicitly records duplicate risk and schedules bounded send. Terminal interaction prompt can't retry stale actions. + +Evidence: `source-only` — [channel management](../../server/src/routes/chat-channels.ts), [publication resolution](../../server/src/services/chat-channels/publications/resolution.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Inspect real provider, choose truthful resolution, reload/audit exact source/result. Agent/no connection grant/wrong endpoint/stale phase/nonunknown state denied. Retry must not silently duplicate. + +Gaps: Accepted send request isn't recipient receipt; per-provider live proof required. + +### `replay-failed-publication-or-resolve-action` + +API: `present` — POST /api/chat-endpoints/{endpointId}/publications/{publicationId}/replay; POST /api/chat-endpoints/{endpointId}/actions/{actionId}/resolve. + +Agent access: `restricted` — endpoint-management board/company/tools:manage_connections; resolve requires board user ID. + +Policy: Replay only failed state, expected attempt generation, live pending interaction prompt; delivery_unknown and stage-owned file transfer reject generic replay. Action resolution dispatches authoritative provider_effect or Slack task-start contract with mark_delivered/retry_anyway/cancel; no arbitrary execution retry. + +Evidence: `source-only` — [replay and effects](../../server/src/services/chat-channels/publications/resolution.ts), [action kind dispatch](../../server/src/services/chat-channels.ts), [route gates](../../server/src/routes/chat-channels.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Blind uncertain replay denied, failed eligible replay one generation. Resolve actual provider effect/task-start after inspection; races/wrong source/stale action no extra effect. + +Gaps: No dedicated agent/CLI decision path; provider-specific stage semantics remain explicit gaps. + +### `resolve-uncertain-email` + +API: `present` — POST /api/companies/{companyId}/email/deliveries/{publicationId}/resolve outcome sent/failed plus providerMessageId. + +Agent access: `restricted` — board company + tools:manage_connections (local implicit/instance-admin exceptions). + +Policy: Only current uncertain send under endpoint/thread lease. sent requires live provider read proving exact inbox, x-paperclip-publication-id and sent label; failed marks provider-not-sent and requires new explicit send. Repeat settled request conflicts; never auto-resend unknown email. + +Evidence: `source-only` — [email manager](../../server/src/routes/email.ts), [provider proof](../../server/src/services/email-channels.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Use actual uncertain disposable send; wrong inbox/header/label/message ID rejected, truthful sent/failed persists. Failed resolution emits no new send; competing decisions one outcome. + +Gaps: Fixture AgentMail response isn't live provider inspection; public assistant/native agent cannot approve unknown outcome. ## `user-continuation` Capability ID: `recovery/user-continuation`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Saved post-stop instructions wait for real cleanup and normal execution authority. -- `POST /api/issues/{id}/comments`. +### `save-and-observe-wait` -Agent access: `partial` — User comment API and server-owned wake reconsideration; native -agent consumes bound wake. +API: `present` — POST /api/issues/{id}/comments; GET /api/issues/{id}; GET /api/issues/{id}/comments; GET /api/issues/{id}/queued-comments; GET /api/heartbeat-runs/{runId}. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. +Agent access: `partial` — human author creates own instruction; agent REST/CLI/native report_progress creates attributed agent content, never human identity. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Policy: Ordinary source-task comment/steering company/privacy/responsible-user policy; saved message independent of provider stop. Existing operator Stop with no new instruction respected. No new client API to manufacture saved-human provenance. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [recovery routes](../../server/src/routes/issues.ts), [saved continuation](../../server/src/services/conversation-continuation.ts), [waiting messages](../../ui/src/components/task-chat/TaskChatQueuedMessages.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Gaps: Receiving the continuation is supported; impersonating a saved user message or -retry control is not. +Verification: `not-run` — Stop disposable owned run, submit distinct follow-ups during cleanup; reload sees ordered waiting messages without premature turn. Deny foreign/private/wrong identity. + +Gaps: Comment acknowledgment isn't agent answer or cleanup completion. + +### `admit-once-after-stop` + +API: `present` — GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}. Server reconsideration uses normal admission; there is no unrestricted retry endpoint. + +Agent access: `partial` — eligible admitted agent/native bound wake receives saved input; delivery remains server-owned. + +Policy: Exact prior run/lease/workspace stop proof, no competing execution, current owner/responsible user, normal subtree/project pause/budget/review gates. Durable ordered message/wake receipts avoid duplicates; never borrow authority from stale callback/other routine. Unused hold-denied admission needs no-execution/dispatch evidence before automatic reconsideration. + +Evidence: `source-only` — [legacy gates](../../server/src/services/recovery/legacy-continuation.ts), [native ownership](../../server/src/services/native-runtime/native-restart-recovery.ts), [queued Stop](../../server/src/modules/wake-queue/adapters/postgres.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — After confirmed cleanup one useful continuation consumes saved order; repeat sweep/reload no duplicate. Pause/budget/approval/unknown external outcome and reassignment prevent stale admission. Queued Stop leaves another routine cycle intact. + +Gaps: Legacy/native/channel runtimes separately qualify; preserve original undispatched-hold and callback regressions. ## `reconnect` Capability ID: `recovery/reconnect`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Browser transport recovery refetches persisted state without implying runner recovery. -- `GET /api/companies/{companyId}/events/ws`. -- `GET /api/issues/{id}`. +### `subscribe-and-filter` -Agent access: `partial` — Existing event protocol; REST refresh of persisted task state. +API: `present` — GET /api/companies/{companyId}/events/ws with WebSocket Upgrade; GET /api/issues/{id} and GET /api/heartbeat-runs/{runId} remain separate REST reads. -Policy: Task/run visibility, run ownership and source/action policy; workspace export -retry and some operator controls require board. +Agent access: `partial` — browser session/trusted Cloud identity or local implicit board; standard unrevoked same-company agent API key via actual WS client. Native call_api cannot Upgrade; scoped keys/native JWT/personal MCP bearer not this path. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts#L9478) at -the reviewed commit above. +Policy: Upgrade membership/company checks; scoped key scopeConfig rejected. Delivery-time key/member and issue/project/run/skill/case privacy rechecks; redacted invalidation payload doesn't confer detail read. Personal MCP Events is a distinct protocol/authority. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — [WS admission/filter](../../server/src/realtime/live-events-ws.ts); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. -Gaps: Streaming reconnect needs its protocol client. Polling/read APIs remain available; -replay is not proof of a fresh successful action. +Verification: `not-run` — Permitted browser/key gets only authorized events; foreign/scoped/revoked key/member/private resource denied/filtered after subscription. REST details still enforce own ACL. + +Gaps: Actual WS client isn't automatically present in native run; avoid query tokens in evidence despite source compatibility. + +### `disconnect-poll-and-refresh` + +API: `present` — GET /api/issues/{id}; GET /api/heartbeat-runs/{runId}; reconnect through the same WebSocket protocol. No event-replay API is implied. + +Agent access: `partial` — LiveUpdatesProvider browser recovery; agents can poll permitted reads or use actual installed protocol client. + +Policy: Bounded reconnect backoff; failed socket fallback polling, healthy open stops polling and invalidates active queries including initial-subscription gap. Events aren't replayed. Hidden/unmounted stops relevant loops; stale socket ignored; reconnect toast suppression distinct from content delivery. + +Evidence: `source-only` — [browser recovery](../../ui/src/context/LiveUpdatesProvider.tsx); reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. No live provider proof. + +Verification: `not-run` — Disconnect while server changes task/run/decision; reconnect/visibility return/refetch matches reload without duplicate comments/decisions/toasts. Initial-open gap and hidden/unmount loops checked. + +Gaps: Healthy socket proves transport only, not provider restart or successful failed task. Mocks not deployed network proof. diff --git a/maps/agent-access-map/secrets.md b/maps/agent-access-map/secrets.md index a31d497c445..aab1faa0ee7 100644 --- a/maps/agent-access-map/secrets.md +++ b/maps/agent-access-map/secrets.md @@ -4,157 +4,459 @@ Product map: [Secrets, personal credentials, and proposals](../feature-map/secre Feature ID: `secrets`. -Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`. -Native REST transport reconciled in this change; see the -[shared transport contract](README.md#native-rest-transport). +Source revision: `3bbc2104b65caf9f7763938a01260a5673e12f7a`. -This is a source-reviewed baseline of representative operations and known gaps. -Each capability needs operation-level review before its entire scope can be -qualified. No live agent execution is claimed. Follow the [map contract](../README.md) -for format, permission checks, evidence and maintenance. +Review depth and executed proof are separate. The operation records enumerate the named behavior and access boundaries. Their evidence states describe the reviewed sources; run results and environment limits belong in the PR or verification artifacts. A listed API or source test does not establish a live authorized journey. Follow the [map contract](../README.md). + +- UI: `/company/settings/secrets` ([ui/src/App.tsx:187](../../ui/src/App.tsx)), company/personal Secrets, My secrets, Vaults, Proposals tabs in [ui/src/pages/Secrets.tsx:657](../../ui/src/pages/Secrets.tsx); `?secret=`/`?definition=` opens inspectable detail sheets (`Secrets.tsx:673`). Hidden tabs are presentation only: APIs stay live. Relevant UI sources: `ui/src/pages/secrets/{MyUserSecretsTab,SetMyUserSecretDialog,ProposalsTab,ImportFromVaultDialog}.tsx`; agent env/API-access editing in [ui/src/components/AgentConfigForm.tsx:536](../../ui/src/components/AgentConfigForm.tsx) and [ui/src/lib/secret-delivery.ts](../../ui/src/lib/secret-delivery.ts). +- All board route operations require board identity and company/resource access, plus ordinary viewer-write protection. Company secret CRUD and vault administration use their own board checks. Definition administration and direct secret-proposal resolution require definition-admin authority; binding-proposal resolution instead checks target agent_config:update authority. The binding dependency cascade has a separate enforcement gap recorded under approve. Source [secret routes](../../server/src/routes/secrets.ts) and each handler. There is no board endpoint that returns arbitrary stored plaintext values. +- Native production agent path is admitted `search_api`/`call_api` over the exact REST operation, not the declared `read_secret_value`/`list_secret_metadata` scenario names. Production authority does not bind those two dedicated scenario actions ([server/src/services/native-runtime/paperclip-runner-tool-authority.ts:124,501,616,641](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts); catalog [runner-api-catalog.ts:43-123](../../server/src/services/native-runtime/runner-api-catalog.ts)). Native fallback needs rollout admission, running authorized bound agent/task/run, current assignment/execution and budget/company/privacy authority. GETs are available in Ask/Plan; POST/DELETE secret operations are not, including POST value retrieval even though its business meaning is reading. Skill-test may appear in catalog allowedModes but secret authorization denies its JWT scope. Actual run scope survives restart/task mode edits. See [runner-api-client.ts:50-61](../../server/src/services/native-runtime/runner-api-client.ts), [runner-api-catalog.ts:117-123](../../server/src/services/native-runtime/runner-api-catalog.ts), [paperclip-runner-tool-authority.ts:1190-1230,2440-2485](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts). +- Legacy shell/REST uses actual bearer actor and signed JWT run context, not merely an X-Paperclip-Run-Id. `secrets` CLI wraps company/vault operations; it has no personal-secret/proposal/value command family. Direct REST remains necessary for those. CLI installation/working shell must be separately established for a given runtime; do not assume remote/native CLI presence. +- Public personal-assistant MCP is a bounded named capability catalog, not arbitrary native call_api: no secret/vault/proposal operation is exposed in `server/src/services/public-mcp/{capabilities,expanded-capabilities}.ts`. An assistant can request human action through a task/comment, but no secret-specific administrative delegation was found. +- `secrets:read`/`secrets:propose` use the shared access evaluator. Standard same-company agent visibility is default-allowed, but effective low trust, task_bridge and skill_test scopes deny these actions ([authorization.ts:1313,1492,1563,2451](../../server/src/services/authorization.ts)). A recorded responsible/authorizing user adds the current user ceiling; responsible-user intersection has an operator shadow-mode setting, so record mode instead of claiming unconditional enforcement ([authorization.ts:2650-2795](../../server/src/services/authorization.ts)). Run JWT source/claims, header mismatch, responsible identity and canceled-write fencing: [middleware/auth.ts:395-480](../../server/src/middleware/auth.ts), [agent-run-cancellation.ts:6](../../server/src/agent-run-cancellation.ts). +- Redaction/persistence: run value reads register dynamic secret redaction before returning and fail closed if registration cannot persist. Activity/access manifests contain IDs, versions, paths and outcomes, not values. Native credential value replies stay inline, capped at 10 MiB, with encrypted mutation receipts; they are not plaintext saved API-result assets. Histories omit bodies. Same native call ID replays the stored encrypted result without rereading/side effects. Source [runner-api-sensitive-response.ts:1](../../server/src/services/native-runtime/runner-api-sensitive-response.ts), [runner-api-client.ts](../../server/src/services/native-runtime/runner-api-client.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts) API receipt path, [runner-api-log-redaction.ts](../../server/src/services/native-runtime/runner-api-log-redaction.ts), [run-secret-redaction.ts](../../server/src/services/run-secret-redaction.ts). A fresh call is necessary to prove current revocation/rotation; replay intentionally returns the original receipt. +- Important precision: proposals require a verified run JWT and a matching existing run, but **the direct proposal service does not independently require run.status=running** ([secret-proposals.ts:42-53](../../server/src/services/secret-proposals.ts)). Native fallback does require a running authorized binding; value-list/read service explicitly requires running. Do not turn the broader prose “active run” into a claim that every legacy proposal handler has a live-status check. Cancellation still fences non-GET REST writes in auth middleware. ## `company-secrets` Capability ID: `secrets/company-secrets`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Discover safe company metadata; administer, rotate, inspect, delete and bind company secret references. Direct administration stays board-restricted; catalog and governed proposals are separate agent paths. -- `GET /api/companies/{companyId}/secrets/catalog`. -- `POST /api/companies/{companyId}/secrets`. +### `catalog` -Agent access: `partial` — Agent REST / native `call_api` metadata catalog and secret -proposals; company secret administration remains board-only. +API: `present` — `GET /api/companies/{companyId}/secrets/catalog`. -Policy: Board secret administration, active-run/self/report proposal policy, and scoped -secret broker bindings; personal secret values belong to their user. +Agent access: `available` through permitted same-company legacy REST or admitted native GET call_api. No dedicated secrets CLI catalog command. -Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at -the reviewed commit above. +Policy: board_or_agent, company access and `secrets:read`. Returns only `{id,name,key,status}` for nondeleted company-scope secrets; user/instance scopes and values/material are excluded. Board full metadata listing below is a different route. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:585](../../server/src/routes/secrets.ts); [services/secrets.ts:3793](../../server/src/services/secrets.ts). -Gaps: Native transport preserves board-only administration. Bound value retrieval -is a separate scoped operation described under runtime-delivery. +Verification: `not-run` — compare exact projected fields; deny unauthenticated/other-company/low-trust/task-bridge/skill-test contexts and responsible-user ceiling; create user/instance controls and confirm absent. Test source [__tests__/secrets-routes.test.ts:1066-1135](../../server/src/__tests__/secrets-routes.test.ts), [agent-secrets-routes.test.ts:270](../../server/src/__tests__/agent-secrets-routes.test.ts). + +Gaps: no live/native catalog evidence from this wave; do not label whole company secret management agent-available. + +### `list-metadata-and-audit` + +API: `present` — `GET /api/companies/{companyId}/secrets`; `GET /api/secrets/{id}/usage`; `GET /api/secrets/{id}/access-events`. + +Agent access: `restricted`, board API/CLI `secrets list -C`, `secrets usage `, `secrets access-events `; native agent call_api remains board-denied. + +Policy: company-scope only; user/instance IDs are hidden. Cross-company usage/audit returns same 404 shape as missing ID. List returns metadata/reference counts, usage resolves consumer labels, access events are value-free. No generic GET secret-value API. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:594,1076,1091](../../server/src/routes/secrets.ts); [services/secrets.ts:3793-3851](../../server/src/services/secrets.ts); [cli/src/commands/client/secrets.ts:372,506,521](../../cli/src/commands/client/secrets.ts). + +Verification: `not-run` — known binding reference/count and success/failure event persist/reload; value absent; other-company/user/instance ID and agent denied. Tests [secrets-routes.test.ts:904-1010](../../server/src/__tests__/secrets-routes.test.ts), [secrets-service.test.ts:1489,1530](../../server/src/__tests__/secrets-service.test.ts). + +Gaps: board-only inspection has no agent-specific delegation beyond requesting human action. + +### `create-managed-or-link-reference` + +API: `present` — `POST /api/companies/{companyId}/secrets`. + +Agent access: `restricted`; board API/CLI `secrets create -C ... --name ... --value-env ` or `secrets link -C ... --name ... --provider ... --external-ref ...`. Agent alternative is proposed secret creation, not direct write. + +Policy: same company, same-provider selectable vault, valid unique path/name/key. Managed values require value and prohibit externalRef; external_reference requires supported provider/ref and stores provider reference metadata without fetching plaintext. Defaults use configured provider; GCP/Vault placeholders are not operational providers. New remote writes reserve/persist provider material with cleanup on DB failure; do not describe failed remote create as necessarily having no external effect. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:887](../../server/src/routes/secrets.ts); [services/secrets.ts:2176-2395](../../server/src/services/secrets.ts); [cli/.../secrets.ts:415,443](../../cli/src/commands/client/secrets.ts). + +Verification: `not-run` — create managed dummy and link known test reference; reload metadata and bind/use separately. Assert duplicate/cross-company provider/mode/coming-soon failures, sanitized errors, ciphertext rather than plaintext at rest. Inspect provider cleanup and retained cleanup handle after failure. Tests [secrets-service.test.ts:2627,2923,2943,3007-3135](../../server/src/__tests__/secrets-service.test.ts); [secrets-routes.test.ts:158,171](../../server/src/__tests__/secrets-routes.test.ts); [aws-secrets-manager-provider.test.ts:33,340](../../server/src/__tests__/aws-secrets-manager-provider.test.ts). Retry: create has no application idempotency key; repeated REST creation should conflict by name/key, not promise replay. Inspect state after uncertain outcomes; native same-call receipts provide their own replay. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `edit-lifecycle` + +API: `present` — `PATCH /api/secrets/{id}`. + +Agent access: `restricted`; board UI/CLI `secrets update --payload-json ...`. + +Policy: company-scope, nondeleted existing secret. Edit name/key/description and active/disabled/archived states; name/key uniqueness preserved. Generic PATCH cannot retarget externalRef/change external vault or reassign managed vault; managed deletion must use DELETE. External refs can be soft-deleted through PATCH (names/keys renamed), while full cleanup uses DELETE. Disabled/archived values stop resolving on fresh delivery/read. This does not erase values already issued to a process/model. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:1032](../../server/src/routes/secrets.ts); [services/secrets.ts:2619-2720](../../server/src/services/secrets.ts). + +Verification: `not-run` — rename without breaking stable secret ID binding; disable/archive and show fresh delivery denied; reactivate and retry; reject retarget/vault/managed soft-delete, foreign/user/instance/deleted IDs; verify no value in activity. Tests [secrets-service.test.ts:3210,3968-4015,4215](../../server/src/__tests__/secrets-service.test.ts); [secrets-routes.test.ts:873](../../server/src/__tests__/secrets-routes.test.ts). Retry: repeated same metadata patch is state-setting; do not repeat a value rotation under this operation. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `rotate-and-reference-version` + +API: `present` — `POST /api/secrets/{id}/rotate`. + +Agent access: `restricted`; board API/CLI `secrets rotate --value-env ...` (CLI value wrapper is narrower than API ref/vault options). + +Policy: active company secret. Managed mode requires new value; rotation creates a new latest version, marks old as previous, and can migrate managed vault through this route. Latest versus explicitly pinned consumer version matters: previous is not automatically revoked. For external_reference, API can rotate reference/version, or write new value through a provider that supports it; value-write cannot also retarget/pin providerVersionRef. External value updates are actual provider writes (AWS AWSCURRENT), not just local metadata. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:992](../../server/src/routes/secrets.ts); [services/secrets.ts:2397-2615](../../server/src/services/secrets.ts); [secrets/aws-secrets-manager-provider.ts:1120+](../../server/src/secrets/aws-secrets-manager-provider.ts). + +Verification: `not-run` — bind one latest and one explicit version; rotate, reload latestVersion, verify new/latest and prior pinned behavior using harmless equality proof only; reject inactive/foreign/user/instance/provider mismatch. Controlled persistence failure must leave original current state or explicit cleanup evidence; external AWSCURRENT rollback is separate. Tests [secrets-service.test.ts:3135,3170,3239,3596-3734](../../server/src/__tests__/secrets-service.test.ts); [aws-secrets-manager-provider.test.ts:389,486](../../server/src/__tests__/aws-secrets-manager-provider.test.ts). Retry: repeated fresh rotation increments versions; the public rotation schema has no general idempotency token or compare-and-swap field. Inspect metadata/provider state before retrying an uncertain response. Verify ordinary native agent denial; encrypted native replay applies to permitted value retrieval below. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `delete-and-cleanup` + +API: `present` — `DELETE /api/secrets/{id}`. + +Agent access: `restricted`; board UI/CLI `secrets delete --yes --confirm `. + +Policy: company scope only; marks deleted/renames before provider cleanup, then removes DB rows. Retry can continue cleanup from soft-deleted state; after complete deletion returns missing. AWS provider deletes only Paperclip-managed remote material; deleting an external reference does not delete the externally owned AWS secret. Removing a disabled-vault local reference need not contact the unavailable vault. Instance/user values use separate paths. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:1106](../../server/src/routes/secrets.ts); [services/secrets.ts:3379-3455](../../server/src/services/secrets.ts); [secrets/aws-secrets-manager-provider.ts:1313-1360](../../server/src/secrets/aws-secrets-manager-provider.ts). + +Verification: `not-run` — remove disposable managed+external references; old catalog/binding/fresh read unavailable; external provider resource remains for linked reference; provider failure leaves nonresolvable cleanup state, retry succeeds without restoring authority. Tests [secrets-routes.test.ts:1010](../../server/src/__tests__/secrets-routes.test.ts), [secrets-service.test.ts:4032-4171](../../server/src/__tests__/secrets-service.test.ts), [aws-secrets-manager-provider.test.ts:917](../../server/src/__tests__/aws-secrets-manager-provider.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `bind-unbind-and-migrate` + +API: `present` — ordinary target configuration API, concrete agent path `PATCH /api/agents/{id}` with adapterConfig env secret_ref or top-level `access.` ref. Project/routine/environment consumer bindings follow their own configuration APIs and policy; do not invent a universal secret-binding CRUD route. `secrets declarations -C ...` uses `POST /api/companies/{companyId}/exports/preview` for portability declarations (not live value grants). + +Agent access: `partial`—direct config edit only where actual `agent_config:update`/target policy permits; creating/changing another agent credential is not implied by catalog read. Binding proposal is explicit self/report human approval route. CLI `secrets migrate-inline-env -C ...` dry-run; `--apply` creates/rotates secrets then PATCHes agents under board authority. + +Policy: same-company reference and target, target config grants, env path versus access alias validation, no instance/user secret_id treated as company ref; user_secret_ref declaration separately. API-access top-level aliases are only for agent target. Low-trust allowed binding IDs and class-3 static-lease allowlist must remain enforced. Unbinding is removing config ref plus persisted binding sync; aliases dropped by Secret access editor need replacement config semantics. Migration is a multi-request workflow, not atomic. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/agents.ts:1774,5262-5490](../../server/src/routes/agents.ts); [services/secrets.ts:4720-5184](../../server/src/services/secrets.ts); [AgentConfigForm.tsx:536](../../ui/src/components/AgentConfigForm.tsx); [cli/.../secrets.ts:283-365](../../cli/src/commands/client/secrets.ts); [ui/src/lib/secret-delivery.ts](../../ui/src/lib/secret-delivery.ts). + +Verification: `not-run` — bind env-only, API-only, both, unbind, reload config+usage and verify fresh delivery changes; alias rename and unrelated binding survive; cross-company/unknown/deleted refs denied before deleting existing bindings. Dry-run migration must not write; apply removes inline values and uses secret refs; failure/retry inspect partial state. Tests [agents-service-secret-bindings.test.ts](../../server/src/__tests__/agents-service-secret-bindings.test.ts), [secrets-service.test.ts:293,489,1450,1607,1647,2555](../../server/src/__tests__/secrets-service.test.ts), [cli/src/__tests__/secrets.test.ts](../../cli/src/__tests__/secrets.test.ts). + +Gaps: full policy of every non-agent binding target is outside this secrets-only source wave; link existing owning feature maps rather than mark all targets qualified. ## `user-secrets` Capability ID: `secrets/user-secrets`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Separate company-admin definitions and aggregate coverage from each authenticated person’s private value lifecycle; runtime resolves only the captured responsible user’s value. -- `GET /api/companies/{companyId}/me/user-secrets`. -- `POST /api/companies/{companyId}/me/user-secrets`. +### `definitions-list-create-edit-disable-delete` -Agent access: `restricted` — Current board user's personal-secret API; agent receives -only authorized run binding. +API: `present` — `GET|POST /api/companies/{companyId}/user-secret-definitions`; `PATCH|DELETE /api/companies/{companyId}/user-secret-definitions/{definitionId}`. -Policy: Board secret administration, active-run/self/report proposal policy, and scoped -secret broker bindings; personal secret values belong to their user. +Agent access: `restricted`—company owner/admin (or existing local implicit/instance admin) with company access; no ordinary agent/native/CLI secret command for personal definitions. Direct user API/browser is real path. -Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at -the reviewed commit above. +Policy: definition != personal value. Definition owns key/name/provider/mode/guidance; company uniqueness/provider/vault checks. Disabling blocks required resolution. Definition deletion (DELETE or PATCH deleted) removes all owners' values/provider material then tombstones/renames definition; a required dangling declaration gives actionable definition/field/consumer error without value. Optional missing declarations resolve to absent. -Verification: `not-run` — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:68,602-720](../../server/src/routes/secrets.ts); [services/secrets.ts:3456,3853-3974](../../server/src/services/secrets.ts). -Gaps: Agent cannot edit a person's private credential value through their ordinary agent -key. +Verification: `not-run` — admin creates, edits/disable/reactivate, then deletes disposable definition after two users set different dummy values; ensure owners/values gone and required stale ref fails clearly; member/agent/foreign denied, implicit board attribution system-safe. Tests [secrets-routes.test.ts:219-306](../../server/src/__tests__/secrets-routes.test.ts); [secrets-service.test.ts:2163-2313](../../server/src/__tests__/secrets-service.test.ts); [secrets-service-dangling-user-secret.test.ts](../../server/src/__tests__/secrets-service-dangling-user-secret.test.ts). Retry: duplicate key ->409, mutation/reload verifies persistence; deletion may have provider partial cleanup so inspect/retry rather than claim transaction across vault writes. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `coverage` + +API: `present` — `GET /api/companies/{companyId}/user-secret-definitions/{definitionId}/coverage`. + +Agent access: `restricted` to same definition-admin authority. + +Policy: aggregate configured/inactive/missing counts across active human members; no values or arbitrary owner's credential read. Does not make every member's personal secret visible in company catalog. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:720](../../server/src/routes/secrets.ts); [services/secrets.ts:3975-4010](../../server/src/services/secrets.ts). + +Verification: `not-run` — two active members, one configured then disabled; counts change after reload; inactive/nonmember values do not count; nonadmin/agent/foreign denied. No dedicated live proof in review. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `owner-values-list-create` + +API: `present` — `GET|POST /api/companies/{companyId}/me/user-secrets`. + +Agent access: `restricted`—concrete authenticated board user only, company access; local implicit board with no userId fails `User identity required`. No ordinary agent impersonation or ownerId parameter allowed. + +Policy: list pairs eligible definitions with current user's metadata or missing value. One value per definition+owner, active definition required, managed/external mode guards; provider config belongs to company. Value stored in user scope with derived unique key; no plaintext readback. User B cannot inspect/edit A by guessing ID; legacy company-secret endpoints hide user-scoped IDs. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:86,727-773](../../server/src/routes/secrets.ts); [services/secrets.ts:1068-1095,2985-3160,4011-4037](../../server/src/services/secrets.ts). + +Verification: `not-run` — A/B set distinct values, switch sessions and see only own state; duplicate value 409 including race; absent user/company/definition/inactive mode denied; metadata never returns value. Tests [secrets-routes.test.ts:306-383](../../server/src/__tests__/secrets-routes.test.ts); [secrets-service.test.ts:1783,2023,2061,2119](../../server/src/__tests__/secrets-service.test.ts); owner-scoped tests concern runtime mediation, not proof of this browser session flow. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `owner-values-edit-rotate-disable-delete` + +API: `present` — `PATCH|DELETE /api/companies/{companyId}/me/user-secrets/{secretId}`; `POST .../{secretId}/rotate`. + +Agent access: `restricted` to owner board user, company scoped; even definition-admin/instance-admin status is not an alternate owner's value API. + +Policy: owner/scope/company lookup returns 404 on another owner's ID. PATCH nonnull value/ref/version/vault fields goes through rotation; status-only PATCH sets state; nullable value patches are not rotation. DELETE or PATCH deleted removes owner value/provider material. Explicit rotate rejects empty payload, uses same mode/version/provider guards. Definitions remain intact when an owner removes a value. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:774-886](../../server/src/routes/secrets.ts); [services/secrets.ts:1086,4054-4119](../../server/src/services/secrets.ts). + +Verification: `not-run` — rotate increments latest, disable fresh runtime resolution, reactivate, remove only A value and keep definition/B value. Try B's value and company API mutation route ->404; confirm no value in success/error/activity. Tests [secrets-routes.test.ts:356-383](../../server/src/__tests__/secrets-routes.test.ts); [secrets-service.test.ts:2313](../../server/src/__tests__/secrets-service.test.ts); shared mode/provider tests as company rotation. Retry: fresh rotation is version-creating, no idempotency claim. Inspect current version on uncertain result; repeated completed DELETE missing is expected. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. ## `proposals` Capability ID: `secrets/proposals`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Run-JWT agents propose new secrets or self/report bindings, inspect and withdraw permitted requests; authorized humans resolve them and the server expires them with durable redaction and linked-card state. -- `POST /api/agents/me/secret-proposals`. -- `GET /api/agents/me/secret-proposals`. +Shared boundary: request creation/list/withdraw uses `/agents/me`, verified agent_jwt with company/agent/run, not long-lived agent_key; task_bridge and skill_test denied; `secrets:propose` effective trust/responsible-user policy. [Secret routes](../../server/src/routes/secrets.ts). Proposal service [secret-proposals.ts](../../server/src/services/secret-proposals.ts). Direct service checks matching run existence, not independently running status (native adds its binding check). Responses strip ciphertext; agent view also strips fingerprint/length; board metadata may include fingerprint/length. 20 pending per agent + 20 creations/minute, value <=64 KiB, expiry 14 days, default page 100, maximum 200. Do not claim direct POST idempotency: it can create duplicate requests on retry; native same-call receipt replay is the dedup layer. -Agent access: `partial` — Active-run agent REST / native `call_api` with redaction; -approval/rejection remains board-only. +### `propose-secret` -Policy: Board secret administration, active-run/self/report proposal policy, and scoped -secret broker bindings; personal secret values belong to their user. +API: `present` — `POST /api/agents/me/secret-proposals` kind=secret. -Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at -the reviewed commit above. +Agent access: `available` via eligible run JWT REST/admitted native standard call_api; no dedicated CLI or admitted secret-specific production tool. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Policy: Apply the capability boundary above. name valid slash path, normalized key, nonempty justification/value; encrypted local pending ciphertext, value registered for run redaction, quota checked; no direct active company secret created before approval. Origin task inferred by execution/checkout run binding, can be null. -Gaps: No dedicated production proposal tool is required for the REST path. -Native calls retain active-run, scope and skill-test JWT restrictions. +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — pending proposal exists with origin agent/run/task, catalog lacks active secret, neither response/list/history/activity nor run logs disclose dummy; quota/oversize/untrusted/forged header/agent_key/scope denied. Failed redaction registration fails closed. Source [secret-proposals.ts:316](../../server/src/services/secret-proposals.ts); tests [secret-proposals-routes.test.ts:338,860](../../server/src/__tests__/secret-proposals-routes.test.ts); native actual-route [runner-api.integration.test.ts:449](../../server/src/services/native-runtime/runner-api.integration.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `propose-binding` + +API: `present` — POST /api/agents/me/secret-proposals with kind=binding. + +Agent access: `partial` — eligible run JWT REST/native; human governance remains intact. + +Policy: Apply the capability boundary above. exactly one `secretId`, own `sourceConfigPath`, or pending same-company `secretProposalId`; `configPath` env.KEY or access.ALIAS. Target only self or downstream reports, source path owned by proposer. Direct secretId only company scope; own existing user-secret source declaration may be forwarded as a user_secret_ref preserving each future responsible user's personal value semantics. Store proposal-time organization snapshot and recheck current graph at approval. Quota and justification guard; creates linked binding confirmation interaction when origin task exists. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — self/report allowed, peer/manager/foreign/missing source/direct user secret forbidden; existing path differing binding conflicts on approval. Required dependency and source label survive reload, one source selector rule enforced; safe UI card does not contain value. Source [secret-proposals.ts:360-479,553,657](../../server/src/services/secret-proposals.ts); tests [secret-proposals-routes.test.ts:566-860,1288,1326,1489](../../server/src/__tests__/secret-proposals-routes.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `list-own-or-targeted` + +API: `present` — `GET /api/agents/me/secret-proposals` with limit/offset. + +Agent access: `partial` — same verified run JWT gate even though GET; includes own proposals or binding proposals targeting caller, not all company proposals. Native GET Ask/Plan still route JWT/trust policy governed. + +Policy: Apply the capability boundary above. returns `{proposals,nextOffset}` with bounded pagination headers; value ciphertext/fingerprint/length stripped. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — owner/target versus unrelated peer list isolation; >one page, no duplicates/hidden value; invalid limits rejected. Source [routes/secrets.ts:219](../../server/src/routes/secrets.ts); [secret-proposals.ts:521](../../server/src/services/secret-proposals.ts); tests pagination [secret-proposals-routes.test.ts:860](../../server/src/__tests__/secret-proposals-routes.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `withdraw` + +API: `present` — `DELETE /api/agents/me/secret-proposals/{id}`. + +Agent access: `partial` — verified proposer JWT only, own pending same-company proposal. + +Policy: Apply the capability boundary above. terminal proposal ->409, other proposer forbidden. Withdraw scrubs pending ciphertext and cascade-rejects pending binding dependents; linked card state mirrors withdrawn. Native Ask/Plan denies DELETE. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — withdraw pending secret+binding dependent; list/card reflect durable terminal state and no material; peer/foreign/second terminal transition denied. Source [routes/secrets.ts:234](../../server/src/routes/secrets.ts); [secret-proposals.ts:785](../../server/src/services/secret-proposals.ts); tests [secret-proposals-routes.test.ts:942,1455](../../server/src/__tests__/secret-proposals-routes.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `board-list-and-resolution-authority` + +API: `present` — `GET /api/companies/{companyId}/secret-proposals` optional status/limit/offset. + +Agent access: `restricted` board company read; no secret-proposal board list through public personal assistant catalog. + +Policy: Apply the capability boundary above. bounded company list; calculated viewerCanApprove and block reason reflect pending status, secret-kind company-admin policy, binding target `agent_config:update` decision with `requiresChangeGrant:true`. Approval affordance is separate from permission to enumerate metadata. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — board list redacted metadata, member can inspect but cannot secret-approve, binding user without grant sees blocked reason; other company/agent denied. Source [routes/secrets.ts:165-192,240](../../server/src/routes/secrets.ts); [secret-proposal-authorization.ts](../../server/src/services/secret-proposal-authorization.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `approve` + +API: `present` — `POST /api/companies/{companyId}/secret-proposals/{id}/approve`, optional cascade and overrides(name,description,providerConfigId). + +Agent access: `restricted` — board. Direct secret approval requires company definition-admin authority; binding approval requires target agent config change authority. The current binding cascade does not independently enforce the dependency's secret-admin check; see Gaps below. + +Policy: Apply the capability boundary above. only pending, unexpired, current self/report chain and authority rechecked after locks; chosen provider vault same company. Secret approval creates reference/material and scrubs pending ciphertext. Binding can cascade pending secret dependency with cascade=true; already approved dependency reused. Applying user source preserves user-secret declaration semantics. Existing different target config path conflicts. Approved secret retained if later binding apply fails; retry reuses it. Resolved state ->409, not repeated active secret creation. Linked card and dual secret/agent activity update; best-effort origin comment/wake failure does not turn committed approval into failure. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — approve secret then binding, both direct and cascade; selected vault persists. Wrong target grant/company/admin/mode, expired, changed org graph, duplicate resolution denied. Force binding failure after dependency commit and retry without creating second secret; assert ciphertext scrub + metadata-only audits and notification failure does not 500 committed state. Tests [secret-proposals-routes.test.ts:239,290,338,478,518,710,1168,1220,1254,1288,1489](../../server/src/__tests__/secret-proposals-routes.test.ts); sources [routes/secrets.ts:255](../../server/src/routes/secrets.ts), [secret-proposals.ts:718](../../server/src/services/secret-proposals.ts), [secret-proposal-notifications.ts](../../server/src/services/secret-proposal-notifications.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. `approve()` cascades pending dependency via `applySecretApproval()` but only invokes assertCanResolve on the binding in loadForApproval; it does not separately call it for the secret dependency ([secret-proposals.ts:729-762](../../server/src/services/secret-proposals.ts)). Do not claim independent secret-admin recheck on a binding cascade without explicit evidence. Record this observed gap; map maintenance must not widen/fix governance implementation. + +### `reject-and-expire` + +API: `present` — `POST /api/companies/{companyId}/secret-proposals/{id}/reject` requires reason; no external expire endpoint (server bounded expiry sweeper). + +Agent access: `partial` — reject restricted board with same kind/target resolution policy; expiration system-only. + +Policy: Apply the capability boundary above. pending terminal transition, secret-kind reject also requires admin; scrub ciphertext, cascade-reject pending secret-dependent bindings, synchronize card rejection/withdrawal/expiry. At expiry approval rejects even before sweeper marks terminal. Concurrent card/proposal races serialize; no stale accepted card after resolved proposal. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — reject then repeat ->409; empty reason invalid; unauthorized reviewer/peer/foreign denied; time-controlled expiry and dependency/card state; no new runtime authority from rejected/expired proposal. Source [routes/secrets.ts:284](../../server/src/routes/secrets.ts), [secret-proposals.ts:785-891](../../server/src/services/secret-proposals.ts); tests [secret-proposals-routes.test.ts:224,906,942,995,1031,1080,1120,1168,1220](../../server/src/__tests__/secret-proposals-routes.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. ## `vault-import` Capability ID: `secrets/vault-import`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Board operators manage nonsecret provider-vault configuration and health, preview metadata, and import external references with per-row outcomes and canonical duplicate checks. -- `POST /api/companies/{companyId}/secrets/remote-import/preview`. -- `POST /api/companies/{companyId}/secrets/remote-import`. +### `provider-descriptor-and-health` -Agent access: `restricted` — Board authorized vault import API / CLI provider -operations. +API: `present` — `GET /api/companies/{companyId}/secret-providers`; `GET .../secret-providers/health`; `POST /api/secret-provider-configs/{id}/health`. -Policy: Board secret administration, active-run/self/report proposal policy, and scoped -secret broker bindings; personal secret values belong to their user. +Agent access: `restricted` board API/CLI `secrets providers -C`, `secrets doctor -C`, `secrets provider-config:health `. -Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at -the reviewed commit above. +Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. [routes/secrets.ts:361-585,921-990](../../server/src/routes/secrets.ts); provider [secrets/aws-secrets-manager-provider.ts](../../server/src/secrets/aws-secrets-manager-provider.ts). -Verification: `not-run` — assert the documented agent denial with an owned test fixture; -verify any listed agent request/result path separately. A delegated operation needs its -own policy and access review. +deployment provider descriptors/health differ from selected company vault health. Selected config state readiness and provider-returned sanitized health; persisted healthCheckedAt/message/details, safe activity. A health result is not secret resolution/import proof. -Gaps: Vault import is not implied by having a secret binding or the ability to propose a -secret. +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — owned configured/unconfigured/disabled/coming-soon vault health; persist timestamp/reload, no raw credential/provider body; nonboard/foreign denied. Tests [secrets-routes.test.ts:133,383](../../server/src/__tests__/secrets-routes.test.ts); [secret-provider-registry.test.ts](../../server/src/__tests__/secret-provider-registry.test.ts), [aws-secrets-manager-provider.test.ts:877](../../server/src/__tests__/aws-secrets-manager-provider.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `vault-list-get-create-update-disable` + +API: `present` — `GET|POST /api/companies/{companyId}/secret-provider-configs`; `GET|PATCH /api/secret-provider-configs/{id}`. + +Agent access: `restricted` board UI/API/CLI `provider-configs`, `provider-config:create/get/update` under `paperclipai secrets`; JSON mutations use `--payload-json`, company routes `-C`. + +Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. [routes/secrets.ts:361-585,921-990](../../server/src/routes/secrets.ts); provider [secrets/aws-secrets-manager-provider.ts](../../server/src/secrets/aws-secrets-manager-provider.ts). + +company-scoped provider/config, status ready/warning/disabled/coming_soon, display name and nonsecret provider options. GCP/Vault cannot be promoted to ready; disabled/coming-soon cannot be default/selected for new secret runtime resolution. Disable clears default. Configuration existence does not grant remote vault credentials/access. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — create/update dummy config, reload; reject sensitive fields, unsafe address, cross-company/agent, coming-soon promotion/default; disable then fresh resolution fails visibly while reference metadata remains. Tests [secrets-routes.test.ts:383-682](../../server/src/__tests__/secrets-routes.test.ts), [secrets-service.test.ts:2923-3007](../../server/src/__tests__/secrets-service.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `vault-default-and-remove` + +API: `present` — `POST /api/secret-provider-configs/{id}/default`; `DELETE /api/secret-provider-configs/{id}`. + +Agent access: `restricted` board UI/CLI `provider-config:default/delete `. + +Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. [routes/secrets.ts:361-585,921-990](../../server/src/routes/secrets.ts); provider [secrets/aws-secrets-manager-provider.ts](../../server/src/secrets/aws-secrets-manager-provider.ts). + +only ready/warning default, one default per company+provider, transaction rechecks status. Removal removes local provider config, logs remoteDeleted:false; it does not delete remote provider data. Distinguish disabled metadata from removed config and inspect referencing secrets afterward rather than claiming migration. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — two vaults switch default/reload, wrong company/status denied, remove disposable config and verify provider secret survives, reconcile remaining references/health. Tests [secrets-service.test.ts:2691,2713,2728](../../server/src/__tests__/secrets-service.test.ts), [secrets-routes.test.ts:682](../../server/src/__tests__/secrets-routes.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `discover-config-and-preview-import` + +API: `present` — `POST /api/companies/{companyId}/secret-provider-configs/discovery/preview` (draft config); `POST .../secrets/remote-import/preview` (saved providerConfigId). + +Agent access: `restricted` board UI/CLI `provider-config:discovery-preview`, `remote-import:preview -C --payload-json ...`. + +Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. [routes/secrets.ts:361-585,921-990](../../server/src/routes/secrets.ts); provider [secrets/aws-secrets-manager-provider.ts](../../server/src/secrets/aws-secrets-manager-provider.ts). + +draft discovery does not persist vault; lists/samples metadata, query/page token/page size. Saved vault must be selectable in company, provider supports listing. Preview derives names/keys, canonical references, duplicate/name/key/provider-guardrail conflicts; does not read plaintext or import/create secret. AWS Paperclip-managed namespace cannot be imported as externally owned. Activity aggregate counts; provider failures sanitized. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — preview pagination, select ready versus duplicate/conflict, change draft without persistence, company/disabled/coming-soon/provider invalid; no GetSecretValue/plaintext during listing, no secret/vault row mutation. Tests [secrets-routes.test.ts:407-524,724-811](../../server/src/__tests__/secrets-routes.test.ts), [secrets-service.test.ts:3261-3369,3478-3596,3846](../../server/src/__tests__/secrets-service.test.ts), [aws-secrets-manager-provider.test.ts:536,617,714](../../server/src/__tests__/aws-secrets-manager-provider.test.ts). + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `commit-reference-import` + +API: `present` — `POST /api/companies/{companyId}/secrets/remote-import`. + +Agent access: `restricted` board UI/CLI `secrets remote-import -C ... --payload-json ...`. + +Policy: Common board/company read/write policy (not definition-admin policy). Agent REST/native remains restricted; CLI commands are board wrappers, not delegated agent authority. AWS implementation is operational; GCP/Vault are coming-soon/draft metadata. Config schemas reject credential-bearing keys/unsafe Vault addresses: credential values do not belong in provider config JSON. AWS credentials come from supported operator deployment/runtime source. [routes/secrets.ts:361-585,921-990](../../server/src/routes/secrets.ts); provider [secrets/aws-secrets-manager-provider.ts](../../server/src/secrets/aws-secrets-manager-provider.ts). + +same selectable saved vault; selected rows validated/canonicalized again, reference versions persisted, no plaintext fetched. Import operates row-by-row with imported/skipped/error counts, not atomic all-or-nothing. Exact canonical vault/reference duplicate skipped, name/key conflict skipped, remote guardrail/provider failure row error. Soft-deleted reference can be reimported; instance-secret same name/key does not collide with company ref. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — import two owned refs with one collision; reload metadata, expected imported/skipped/error, reference-only material. Repeat and confirm no second canonical ref; cross-company/disabled vault and Paperclip-managed namespace denied at commit even if preview old; change selection between preview/commit and inspect real outcomes. Tests [secrets-service.test.ts:3734-3968](../../server/src/__tests__/secrets-service.test.ts), [secrets-routes.test.ts:811](../../server/src/__tests__/secrets-routes.test.ts), [agent-instance-secrets.test.ts:222](../../server/src/__tests__/agent-instance-secrets.test.ts); source [services/secrets.ts:4403-4608](../../server/src/services/secrets.ts). + +Gaps: only controlled AWS provider tests were inspected; live AWS identity, IAM, network, data ownership and actual import/rotation/deletion remain not-run. GCP/Vault do not get a live working path because draft config exists. ## `runtime-delivery` Capability ID: `secrets/runtime-delivery`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Authorize env/config projection, responsible-user personal values, run-bound company value retrieval, and the deliberately server-only instance lifecycle boundary. -- `GET /api/agents/me/secrets`. -- `POST /api/agents/me/secrets/{key}/value`. +### `env-and-config-projection` -Agent access: `available` — Authorized environment/broker delivery and scoped agent -REST / native `call_api` value retrieval. +API: `present` — configure bound consumer via its own API, then normal run/test lifecycle; no public arbitrary resolve-value endpoint for board. Concrete agent config `PATCH /api/agents/{id}`; normal task execution resolves saved bindings. User-perspective account/setup validation is separately scoped. -Policy: Board secret administration, active-run/self/report proposal policy, and scoped -secret broker bindings; personal secret values belong to their user. +Agent access: `available` only for admitted authorized consumer projection; fresh model code sees its allowed env/config, not all company secret inventory. Environment injection is not blanket value-read API permission. -Evidence: `source-only` — [implementation](../../server/src/routes/secrets.ts#L194) at -the reviewed commit above. +Policy: company secret binding must match consumer type/id/configPath and allowedBindingIds (when supplied), same company, active secret/version/vault. env.KEY -> env at run start; generic schema secret field -> adapter config; access.ALIAS -> API access and not env. latest versus pinned version recorded in value-free manifest, deleted/disabled/archived/version-disabled/revoked/provider-unavailable fail. Class-3 static lease needs exact approved target/path allowlist key. Missing required bindings block setup with diagnostic fields, optional absent personal ref skips. Audit writes best-effort in resolver, so a successful secret resolution alone does not prove every event persisted. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [services/secrets.ts:1132,1353-1455,5214,5282,5441,5598](../../server/src/services/secrets.ts); [ui/src/lib/secret-delivery.ts](../../ui/src/lib/secret-delivery.ts); tests [secrets-service.test.ts:1530,1567,1607,1647,1738,2345,2442,2490,2596,2662](../../server/src/__tests__/secrets-service.test.ts). -Server-only instance secrets are excluded from this path. They belong to the -company, owning agent, and installed lifecycle plugin. The existing local lifecycle -callback can save them through the native secret service; there is no agent API -for their values. Source: [native secret coordinator](../../server/src/services/agent-instance-secrets.ts) -and [scope/denial tests](../../server/src/__tests__/agent-instance-secrets.test.ts). -No live agent execution is claimed for this exclusion. +Verification: `not-run` — env-only/API-only/both plus generic secret field on eligible adapter, compare harmless equality/length result without returning dummy, manifest IDs/version/outcome and redacted logs/errors; unbind/disable/rotate and fresh run behavior; denied consumer/path/foreign/allowlist/version. Do not claim rotation/removal retracts already projected process/model bytes. -Gaps: Values remain restricted to the bound agent and active run. Credential -responses stay inline and use encrypted mutation receipts; they are not saved as -plaintext response assets. Dedicated scenario read_secret_value remains unbound. +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `responsible-user-personal-projection` + +API: `present` — PATCH /api/agents/{id} declares user_secret_ref in consumer configuration. Normal run/test projection then uses the captured responsible user; there is no arbitrary-agent personal-value endpoint. Owner value changes use the /me/user-secrets operations above. + +Agent access: `partial` runtime projection only; user values are excluded from GET /agents/me/secrets and POST key/value direct company access. + +Policy: definition active and declaration matching company/consumer/configPath, captured responsible user, exactly that user's personal value and optional/required semantics; missing responsible_user_missing/user_secret_missing/binding_missing actionable. Current identity capture should be used rather than caller-supplied user override. New execution's responsible user changes which value is used, not a copied owner's secret ID. Local pre-save adapter test has an explicit owner_scoped mediation exception: resolves only authenticated user's own values without saved declarations, rejects any allowedBindingIds array, and still requires responsible user. This exception is not general run/API bypass. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [services/secrets.ts:4212-4307,5598](../../server/src/services/secrets.ts); [routes/authz.ts:251+](../../server/src/routes/authz.ts); [routes/agents.ts:3277](../../server/src/routes/agents.ts); tests [secrets-service-user-secret-owner-scoped.test.ts](../../server/src/__tests__/secrets-service-user-secret-owner-scoped.test.ts) and [secrets-service-dangling-user-secret.test.ts](../../server/src/__tests__/secrets-service-dangling-user-secret.test.ts), [secrets-service.test.ts:1688,1783](../../server/src/__tests__/secrets-service.test.ts); [authz-secret-context.test.ts](../../server/src/__tests__/authz-secret-context.test.ts). + +Verification: `not-run` — use the same saved agent configuration with separate runs capturing responsible users A and B; each gets its own harmless equality result. Missing/removed/inactive user or definition blocks a required value or skips an optional one; B must never fall back to A's value. Direct company resolver/catalog/API excludes personal values. Pre-save owner tests and persisted runtime require separate proof. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `api-list-bound-metadata` + +API: `present` — `GET /api/agents/me/secrets`. + +Agent access: `available` with verified run-bound agent JWT via legacy REST or admitted native GET call_api; long-lived agent key plus fabricated run header denied, board denied. + +Policy: explicit service running/company/agent/run check and `secrets:read`; low-trust/task_bridge/skill_test denied; only active company-scope bound secrets, direct agent env/access grants or IDs admitted in run secret manifest for other consumers. Returns key/name/description/delivery/projection/version plus opaque secretRef; hides internal bindingId/configPath and all values. It does not list user/instance or arbitrary unbound secret. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [routes/secrets.ts:314](../../server/src/routes/secrets.ts); [services/secrets.ts:1756](../../server/src/services/secrets.ts); tests [secrets-routes.test.ts:91](../../server/src/__tests__/secrets-routes.test.ts); [agent-secrets-routes.test.ts:122,270](../../server/src/__tests__/agent-secrets-routes.test.ts). + +Verification: `not-run` — env-only/API-only/both and run-manifest project ref listed, unbound/user/instance absent; metadata exact projection; foreign peer run/ended run/non-JWT/scope/company denied; activity secret.access.listed count value-free. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. + +### `api-read-bound-value` + +API: `present` — `POST /api/agents/me/secrets/{key}/value` (key is secret key from list, not access alias). + +Agent access: `available` with same verified running JWT REST. Native POST call_api only admitted standard mode; Ask/Plan reject transport POST even though this reads a value. No admitted dedicated read_secret_value binding. + +Policy: list eligibility rechecked then exact grant/configPath/version; direct agent target or manifest-bound other consumer; only env/access namespace, active company/version/vault. Register redaction before response; Cache-Control:no-store, response key/value/version. Value-free access and secret.value.read success/failure audits. User/instance excluded. Credential replay encryption/history omission/10MiB applies to native surface; direct REST has no native replay receipt. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. See the route/service and test references in this operation and the shared source/surface contract. Cited controls were inspected, not executed. + +Verification: `not-run` — allowed caller compares dummy securely, different/unbound peer and fake/ended/mismatched JWT/header/company/mode/scope denied. Remove grant/disable/rotate then issue a fresh call to prove current authority; same native call ID replays original response without re-dispatch and without plaintext stored receipt/response assets/history. Fail redaction registration ->no value response. Tests [agent-secrets-routes.test.ts:122,230,270](../../server/src/__tests__/agent-secrets-routes.test.ts), [secrets-service.test.ts:1271,1336,1414](../../server/src/__tests__/secrets-service.test.ts); real authenticated HTTP native authority tests [services/native-runtime/runner-api.integration.test.ts:349-372](../../server/src/services/native-runtime/runner-api.integration.test.ts), [runner-api.test.ts:323-350](../../server/src/services/native-runtime/runner-api.test.ts), [runner-api-log-redaction.test.ts](../../server/src/services/native-runtime/runner-api-log-redaction.test.ts). + +Gaps: fresh local source test is not actual provider/tool-model execution; native rollout and eligible target must be evidenced by coordinator. + +### `server-only-instance-lifecycle` + +API: `not-applicable` — trusted server lifecycle plugin callback/coordinator is the concrete existing path, not a new route or missing permission grant. `agentInstanceSecretService.apply/read` and native secret service `agentInstance`. + +Agent access: `restricted`—never delivered to ordinary agent env/config/API catalog/value path. Owning installed lifecycle plugin server callback receives its scoped instance data. Agent cannot authorize itself into this owner scope. + +Policy: company+owner agent+installed plugin, operation/version/phase/attempt lease owner and unexpired lease rechecked; nonnull writes only preparing/resuming. Encrypted local versions, isolated company/user names, removal/cascade on owning agent/plugin deletion; stale attempts fail. Lifecycle storage error must not be acknowledged as saved. Activity only key/action, not value. + +Evidence: `source-only` — Reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. [services/agent-instance-secrets.ts:10-38](../../server/src/services/agent-instance-secrets.ts); [services/secrets.ts:3494-3543](../../server/src/services/secrets.ts); tests [agent-instance-secrets.test.ts:49,107,118,134,148,174,190,206,247,266](../../server/src/__tests__/agent-instance-secrets.test.ts) (real DB/local encrypted storage/lifecycle callback controls, not hosted provider acceptance). + +Verification: `not-run` — trusted lifecycle fixture save/rotate/restart/read in owner plugin only, stale version/phase/lease/company/plugin/agent denied, remove/cascade; ordinary binding/catalog/value read cannot access it; no value in logs/activity/evidence. This is a deliberate server custody restriction, not ordinary agent delivery. + +Gaps: The enumerated source contract is reviewed; live verification remains not-run for the named actors, surfaces and dependencies. No broader provider/runtime qualification is claimed. diff --git a/maps/agent-access-map/tasks.md b/maps/agent-access-map/tasks.md index b755a157da5..8b5f3176bcc 100644 --- a/maps/agent-access-map/tasks.md +++ b/maps/agent-access-map/tasks.md @@ -4,241 +4,504 @@ Product map: [Task creation and lifecycle](../feature-map/tasks.md). Feature ID: `tasks`. -Review date: 2026-10-12. Source commit: `58e16dbddfc9c8d0cf60867f9d9847f0feda055b`. -Native REST transport reconciled in this change; see the -[shared transport contract](README.md#native-rest-transport). +Source revision: `3bbc2104b65caf9f7763938a01260a5673e12f7a`. -This is a source-reviewed baseline of representative operations and known gaps. -Each capability needs operation-level review before its entire scope can be -qualified. No live agent execution is claimed. Follow the [map contract](../README.md) -for format, permission checks, evidence and maintenance. +Review depth and executed proof are separate. The operation records enumerate the named behavior and access boundaries. Their evidence states describe the reviewed sources; run results and environment limits belong in the PR or verification artifacts. A listed API or source test does not establish a live authorized journey. Follow the [map contract](../README.md). + +Operation review of the six existing task capabilities at `3bbc2104b65caf9f7763938a01260a5673e12f7a`. Evidence remains source-only and live verification not-run. Legacy agent REST/CLI require the actual issued identity, company and run context. Native tools require their advertised binding, running native run, current assignment/executionRunId, company/budget/actor authority and responsible-user privacy intersection. Generic native search_api/call_api additionally requires operator rollout admission and a permitted current mode; ordinary mutations are restricted in Ask/Plan, and Muse excludes generic API. GET/HEAD and title PUT are separate mode exceptions. See [native transport](README.md#native-rest-transport), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [runner-api-rollout.ts](../../server/src/services/native-runtime/runner-api-rollout.ts) and [runner-api-catalog.ts](../../server/src/services/native-runtime/runner-api-catalog.ts). Declared scenario tools are not production admission. Detailed coordination, questions, steering, documents, goals, workspaces and recovery subflows retain their own maps; the following records enumerate their task-facing entry points without claiming those engines are completely qualified. ## `create` Capability ID: `tasks/create`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Create ordinary work, retry safely, and create child/accepted-plan work with the correct parent and attribution. -- `POST /api/companies/{companyId}/issues`. +### `create-task` -Agent access: `available` — Native create_task; REST / CLI / MCP. +API: `present` — POST /api/companies/{companyId}/issues. -Policy: Company/task visibility, assignment/change policy, active-run checkout ownership -and lifecycle rules. Ordinary Board comments preserve queued/running retries; -only a parked retry can be superseded. Explicit Stop/Interrupt retain their -existing actor and execution authority. Agent comment tools do not acquire Board -identity or cancellation authority through this behavior. +Agent access: `partial` — legacy agent REST; CLI issue create; admitted native create_task for its narrow advertised fields, call_api for other permitted fields. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) at the -reviewed commit above. +Policy: Title OR nonblank description; assigned omission defaults todo, unassigned omission backlog. Same-company readable parent/project/origin run, tasks:assign and eligible agent/active company person. Agent responsibleUserId rejected; creator attribution server-derived. Skill-test creation forbidden; trust/watchdog/task-bridge ceilings, delegation cycles and host-command denials remain. Native title required, maximum 500 characters, backlog|todo only, standard mode, fixed active-task parent (standalone project work in conversation), default caller assignee; no advertised privacy/labels/mode/workspace/review config. CLI requires title, supports --standalone/--parent-id but lacks many rich fields. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-assigned-backlog-contract-routes.test.ts](../../server/src/__tests__/issue-assigned-backlog-contract-routes.test.ts), [issue-agent-mutation-ownership-routes.test.ts](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts), [task-creation-backlog.test.ts](../../server/src/services/native-runtime/task-creation-backlog.test.ts). No live execution claimed. -Gaps: Creation is implemented; agent/user assignment and attachments may need -narrower/different APIs. +Verification: `not-run` — Create unassigned backlog and assigned todo; reload saved content/context/attribution and verify no backlog wake vs one eligible todo wake. Reject foreign/inaccessible parent/project, unavailable assignee, spoofed responsible user, skill-test create and agent host commands. Compare actual native and REST paths. + +Gaps: Native/CLI field parity is incomplete. Rich fields require an actually admitted REST fallback; no native/remote CLI availability assumed. + +### `retry-create` + +API: `present` — POST /api/companies/{companyId}/issues with a stable idempotencyKey, duplicate policy and optional initialPlan. + +Agent access: `partial` — REST/call_api and native create_task stable key; CLI create has no idempotency-key flag. + +Policy: REST deduplicated reuse responds 200 with reason; new task 201. allowDuplicate skips recent-title guard but not key replay. Native durable child origin/fingerprint rejects changed arguments and repairs one durable dispatch on replay. Replays retain current authorization. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue-create-deduplication-routes.test.ts](../../server/src/__tests__/issue-create-deduplication-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Repeat identical key after uncertain response; assert same task/plan and one wake. Changed native input/key conflicts. Test recent-title reuse and explicit duplicate separately. + +Gaps: No exactly-once external execution inferred from a receipt or single returned ID. + +### `create-child-or-plan-batch` + +API: `present` — POST /api/issues/{id}/children; GET/POST /api/issues/{id}/accepted-plan-decompositions. + +Agent access: `partial` — agent REST/call_api; CLI issue child:create --payload-json; dedicated create_task is one current-task child, not arbitrary-parent/batch. + +Policy: Readable same-company parent and write influence, tasks:assign, normal creation restrictions. Child API fixes parent/inheritance; acceptanceCriteria maximum 20 entries, 500 characters each; blockParentUntilDone. Batch binds acceptedPlanRevisionId and 1..25 child definitions, with no stale/unaccepted-plan substitution. Source privacy follows child/handoff. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-agent-mutation-ownership-routes.test.ts](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Create child and accepted-plan batch; reload parent/children/criteria/blockers, reject foreign parent/stale plan and verify retry adds no duplicate work. Follow [coordination](../feature-map/task-coordination.md) and [plan review](../feature-map/questions-and-approvals.md) for their engines. + +Gaps: Accepted-plan approval/decomposition engine remains owned by its detailed companion review; this record covers task creation entry/limits. ## `organize` Capability ID: `tasks/organize`. -`GET /api/companies/{companyId}/issues/summaries?ids=...` reads up to five exact -UUIDs and returns only navigation summaries. Normal company and task-read -permissions apply to ordinary agent REST calls; task-bridge keys are denied. -Hidden, missing, foreign and private inaccessible IDs are omitted without an -existence disclosure. No dedicated CLI/native tool is added. Embedded database -route tests cover same-company agent access and company/task-bridge denials; -this does not establish a live native `call_api` journey. +Review: `operation-reviewed`. -The issue-list API accepts optional `includeAgentCreatedTasks`; false restricts -independent results to human creation before search/pagination. Omission retains -existing agent/API behavior. `includeParticipatedTasks=true` requires a board user -and retains only that authenticated user's existing participation as a creation -visibility exception. Company/private-task access checks still apply. Collection -preferences and hierarchy presentation are browser state, not additional authority. -Source-reviewed behavior; live agent access verification remains separate. +Read task collections, navigation projections and blocked counts; distinguish domain reads from browser layout state. -All `chat_channel` origins count as bot-created for creation visibility, including -human-initiated conversations. Existing inbox participation remains independent. +### `list-filter-page` -Review: `baseline`. +API: `present` — GET /api/companies/{companyId}/issues; optional view=compact. -API: `present` — representative operation IDs: +Agent access: `partial` — REST/call_api full query; CLI issue list exposes status/agent/project and local --match on one fetched page; native search_tasks query up to 500 characters, statuses, and a declared limit 1..200; production clamps the limit to 1..100 (default 50), without full paging/project/label/workspace knobs. -- `GET /api/companies/{companyId}/issues`. +Policy: Company/read privacy filtering and inaccessible edge redaction; task-bridge company list denied. Default 500, maximum 1000, offset>=0, sortField updated|id, sortDir asc|desc, afterId. Supports status/assignee/participant/project/workspace/parent/descendant/label/origin/text/date and routine/plugin/blocker query groups. includeAgentCreatedTasks=false filters independent roots before search/pagination; omission retains agent/API behavior. includeParticipatedTasks and user me filters require board identity. Compact ETag is actor-private; 429 is not empty results. -Agent access: `available` — Native search_tasks; REST / CLI; UI grouping/navigation -state separately. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issues-list-query-parsing.test.ts](../../server/src/__tests__/issues-list-query-parsing.test.ts), [issues-creation-visibility.test.ts](../../server/src/__tests__/issues-creation-visibility.test.ts), [issue-list-assignee-filter-routes.test.ts](../../server/src/__tests__/issue-list-assignee-filter-routes.test.ts), [private-json-etag.test.ts](../../server/src/__tests__/private-json-etag.test.ts). No live execution claimed. -Policy: Company/task visibility, assignment/change policy, active-run checkout ownership -and lifecycle rules. +Verification: `not-run` — Compare human/agent/routine/channel tasks, list/compact/full filters and ID pagination without duplicates or inaccessible rows. Reject invalid boolean/date/sort/limit and agent human-only/task-bridge query. Preserve failed/429 result visibly. Request native limit 200 and confirm the production result contains at most 100 tasks. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) at the -reviewed commit above. +Gaps: Bounded native search and one-page CLI local match are not complete company-search substitutes. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +### `read-task-and-summaries` -Gaps: Search/filter API exists; sorting/grouping/presentation defaults are not -necessarily shared server preferences. +API: `present` — GET /api/issues/{id}; GET /api/companies/{companyId}/issues/summaries?ids=... . + +Agent access: `partial` — REST/CLI issue get; native get_task_context reads CURRENT task only; call_api for eligible arbitrary task/summaries. No dedicated summaries CLI/tool. + +Policy: Company/task issue:read; exact identifiers resolved in company context. Summary strict query 1..5 UUIDs/no extra parameters, no-store, omits missing/hidden/private/foreign IDs; task-bridge denied. Locked/redacted parent/project/blocker context does not grant read. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-summaries-routes.test.ts](../../server/src/__tests__/issue-summaries-routes.test.ts), [issue-identifier-routes.test.ts](../../server/src/__tests__/issue-identifier-routes.test.ts), [issue-access-grants-routes.test.ts](../../server/src/__tests__/issue-access-grants-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Cold-open current task/identifier, reload after rename, batch own/private/missing/foreign IDs and compare exact navigation fields. Switch company/account, reject private/full read and ensure no stale actor content. + +Gaps: A summary result proves neither workspace inspection nor full task/comment access. + +### `blocked-count` + +API: `present` — GET /api/companies/{companyId}/issues/count?attention=blocked. + +Agent access: `available` — agent REST/admitted call_api; no dedicated CLI/native count. + +Policy: Company/actor/read filters and low-trust boundaries apply. Task-bridge denied; attention=blocked required, limit/offset rejected; supported collection filters shape visible count. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue-blocker-attention.test.ts](../../server/src/__tests__/issue-blocker-attention.test.ts). No live execution claimed. + +Verification: `not-run` — Compare count to accessible filtered blocked tasks, including inaccessible fixtures; reject other attention/pagination and foreign company. + +Gaps: A count is not proof the underlying blocker can be resolved. + +### `collection-presentation` + +API: `not-applicable` — list/board, grouping/sort/columns/hierarchy/expanded rows and saved collection preference are browser presentation; resource reads use listed APIs. + +Agent access: `not-applicable` — no agent layout API; permitted underlying task data is separate. + +Policy: IssuesList loads/saves browser preferences by company/collection, with separate agent-created visibility. Contextual ancestors/descendants do not become unrelated independent results. No shared server view preference inferred. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [IssuesList.tsx](../../ui/src/components/IssuesList.tsx), [Issues.tsx](../../ui/src/pages/Issues.tsx), [Issues.test.tsx](../../ui/src/pages/Issues.test.tsx). No live execution claimed. + +Verification: `not-run` — Set list/board/grouping/columns, hide/show automation, search child, open task/back and reload. Verify company/collection scope and Clear filters hidden-automation default; failed read stays visible. + +Gaps: Issues.test.tsx covers helpers/URL/paging/constants, not a mounted real-browser list journey. Full shell permutations remain live scope. ## `properties` Capability ID: `tasks/properties`. -Review: `baseline`. +Review: `operation-reviewed`. -Agent REST callers can promote a prepared backlog task with -`PATCH /api/issues/{id}` and exactly `{ "status": "todo", "expectedStatusVersion": N }`. -The optional nonnegative integer version comes from the current task response. -The server checks both the version and backlog state under the task row lock; -status or ownership changes, including changes back to their earlier values, -return `409` without promoting or waking the task. Mixed mutation fields return -`422`. Existing company, task, assignment and run authority still apply. -Route and real-PostgreSQL service tests cover the contract; no live agent journey -or dedicated native tool is claimed. +Separate rename, generic metadata, company labels, assignment, blockers, execution configuration, monitor and watchdog contracts. -API: `present` — representative operation IDs: +### `rename` -- `PATCH /api/issues/{id}`. -- `PUT /api/issues/{id}/title`. +API: `present` — PUT /api/issues/{id}/title; PATCH /api/issues/{id} title is a distinct metadata path. -Agent access: `available` — Native set_task_title/reassign_task/set_dependencies and -set_task_monitor; `call_api` for REST-authorized fields; agent REST. Monitor -scheduling is a dedicated native tool, not a generic `call_api` operation. +Agent access: `partial` — native set_task_title is active/current-task-only; REST/call_api dedicated PUT; CLI issue update --title uses PATCH and lacks provisional/retry-key fields. -Policy: Company/task visibility, assignment/change policy, active-run checkout ownership -and lifecycle rules. A legacy run can assign its own task to a human without -cancelling itself only with its signed run token and matching active run, agent, -company and task. The outgoing run cannot mutate its human-owned task afterward, -including through a late update already admitted before the handoff. Agent keys, -native runs, board reassignment and transfers to -another agent retain verified-stop requirements. +Policy: The dedicated title path validates trimmed input, supports onlyIfProvisional, and accepts an optional retry key. Agent must be assigned active RUNNING run bound to exact task/current execution/checkout and chat generation. Board cannot supply run retry key. The per-run receipt limit applies; same-key replay never overwrites later human edit, changed arguments409. Generic PATCH has different policy. -Native monitors require standard work mode and an agent-owned task in progress -or review. The responsible user's current permissions also apply. A malformed -request is rejected before mutation; bounded schema guidance lets the provider -correct it without exposing submitted values. Receipt replay never re-arms a -consumed schedule. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue-title.ts](../../server/src/services/issue-title.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [task-title-routes.test.ts](../../server/src/__tests__/task-title-routes.test.ts). No live execution claimed. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) at the -reviewed commit above. +Verification: `not-run` — Rename/reload references; onlyIfProvisional no-op after human rename. Replay accepted key after later human edit preserves edit. Reject stale/nonowner/idle run, changed key arguments and blank title. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. Focused route -regressions in [ownership tests](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts) -cover a human handoff and stop enforcement for other actors, runtimes and targets; -they use mocked services and do not claim live execution proof. +Gaps: Do not claim visible peer PATCH authority grants dedicated title authority. -Queue and HTTP/2 sandbox callbacks admit `GET /api/issues/{id}/diagnostics/wakes` -and `POST /api/issues/{id}/monitor/check-now`. The controller still checks task -read access or monitor-management permission and assignment ownership. Recovery -resolution and scheduled-retry controls remain outside this bridge surface. +### `edit-metadata-context` -Monitor verification: submit flat scheduling fields, observe the schema rejection -and unchanged task, then retry with the nested `monitor` object and the same -idempotency key. Inspect the saved schedule and audit, yield, and verify exactly -one `issue_monitor_due` wake. [Scheduler integration coverage](../../server/src/__tests__/issue-monitor-scheduler.test.ts) -uses real PostgreSQL, the native tool authority, and the heartbeat scheduler with -a no-op process agent. It does not prove live model recovery. +API: `present` — PATCH /api/issues/{id}: description, priority, billing/request depth, labels, goal/project/parent and supported metadata. -Monitor deferral diagnostics: an unresolved execution-recovery hold keeps a due -schedule intact and prevents execution. Read `issue.monitor_deferred` activity -for the safe blocker cause; unexpected dispatch failures record -`issue.monitor_dispatch_failed`. Repeated identical diagnostics are throttled for -five minutes. The scheduler regression proves that a held source does not replay -and that clearing the hold permits one later wake. This is local PostgreSQL -evidence, not live provider recovery. -Native timer dispatch also waits for unfinished finalization after a terminal -provider run. Recovery may use that run's scheduling receipt and the matching -admitted successor as historical delivery evidence. It does not grant new -execution authority or clear a successor's ownership. Missing receipts, -unadmitted wakes, and unfinished workspace persistence remain held. -An accepted result may settle into a schedule that expired during recovery; -the scheduler applies its existing expiry policy afterward. This does not -authorize a new provider result to wait on an expired or exhausted monitor. +Agent access: `partial` — REST/call_api; CLI update exposes a subset, lacking human assignment, label IDs, mode/review/adapter/workspace configuration and CAS flags; no dedicated generic native editor. -Gaps: Dedicated tools differ in scope and fields. Generic `call_api` forwards -status, assignment and dependency fields to existing route authorization. +Policy: PATCH uses issue:read and issue:mutate with visible-idle-peer writes; another assignee active lock requires management override, own in-progress writes current checkout/run. Same-company readable parent/project and service-valid goals/relations; reject cycles, forged onBehalfOfUserId and agent host commands. Priority API exists but ordinary priority UI editing is hidden. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [issues.ts](../../server/src/services/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [IssueProperties.tsx](../../ui/src/components/issue-properties/IssueProperties.tsx), [issue-agent-mutation-ownership-routes.test.ts](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts), [issue-workspace-command-authz.test.ts](../../server/src/__tests__/issue-workspace-command-authz.test.ts). No live execution claimed. + +Verification: `not-run` — Persist each property group after reload; verify context/ref/count changes without gratuitous execution restart. Reject foreign/private project/parent/goal, cycles, spoof attribution and agent host commands. + +Gaps: Goal/workspace engines and configuration variants retain their owning maps; metadata persistence is not usable runtime evidence. + +### `manage-labels` + +API: `present` — GET/POST /api/companies/{companyId}/labels; DELETE /api/labels/{labelId}; PATCH task labelIds for attach/detach. + +Agent access: `available` — agent REST/call_api; CLI issue label:list/create/delete for catalog, task labelIds via REST; no dedicated native labels tool. + +Policy: Actual catalog routes use company access/resource lookup, without added board role gate. Name trim1..48, color#RRGGBB. Task label attach/detach retains task mutation rules; deleting label affects catalog, not just one task. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [IssueProperties.tsx](../../ui/src/components/issue-properties/IssueProperties.tsx). No live execution claimed. + +Verification: `not-run` — Create/attach label, filter tasks, reload, detach and delete disposable label. Reject invalid name/color, foreign company and denied task write. + +Gaps: No live label workflow claimed; do not confuse catalog delete with per-task detach. + +### `assign-reassign` + +API: `present` — PATCH /api/issues/{id} assigneeAgentId/assigneeUserId. + +Agent access: `partial` — REST/call_api; CLI agent assignment only; native reassign_task for another eligible task, never own active task. + +Policy: tasks:assign with exact target/project/parent; eligible agent or active person, single assignee. Stop old run before transfer; unconfirmed stop409. Narrow signed legacy current-run self→human handoff can finish; late outgoing edits denied; board/native/key/agent transfer keeps stop rules. Native reassignment requires a retry key, reason, expected owner and status version, denies current task/conversations/terminal/in_review/pending review; preserves blocked/backlog and durable wake replay. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [reassign-task.ts](../../packages/paperclip-runner/src/protocol-actions/reassign-task.ts), [issue-agent-mutation-ownership-routes.test.ts](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts), [task-reassignment.test.ts](../../server/src/services/native-runtime/task-reassignment.test.ts). No live execution claimed. + +Verification: `not-run` — Reload recipient/ownership, race expected-version reassignments and inspect single handoff/wake. Compare legacy self→human final report with board stop; reject late write, stale owner/version and foreign/unavailable recipient. + +Gaps: Detailed delegation and governed review handoffs remain [task coordination](task-coordination.md). + +### `set-dependencies` + +API: `present` — PATCH /api/issues/{id} blockedByIssueIds replaces whole set. + +Agent access: `partial` — native set_dependencies CURRENT task/standard mode/key+array; REST/call_api arbitrary permitted target; CLI update lacks blocker-set flag. + +Policy: Task mutation and valid same-company, nonself/noncycle dependencies. Preserve existing blockers explicitly when replacing. Native Muse additionally checks blocker read. Eligible continuation retains pause/budget/responsible-user/finalization authority. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue-dependency-wakeups-routes.test.ts](../../server/src/__tests__/issue-dependency-wakeups-routes.test.ts), [issue-dependency-restore-wake-policy.test.ts](../../server/src/__tests__/issue-dependency-restore-wake-policy.test.ts). No live execution claimed. + +Verification: `not-run` — Add/replace/remove blockers and reload; reject self/foreign/cycle. Finish prerequisite and verify one eligible dependent continuation, not inferred business success from cancelled status. + +Gaps: Detailed readiness and wake variants belong [dependencies](task-coordination.md#dependencies). + +### `configure-execution` + +API: `present` — PATCH /api/issues/{id}: workMode/harnessKind, reviewPolicy/executionPolicy, assigneeAdapterOverrides and supported workspace settings. + +Agent access: `partial` — permitted REST/call_api fields; no general CLI/native configuration tool. Native mode restrictions apply to current call, regardless of requested future mode. + +Policy: Policy CAS expectedExecutionPolicy must accompany policy-only write; stale conflict, no smuggled owner/status. Existing governed stage actor/resolver remains authoritative. MCP OAuth cannot participate in review/pending stage or active execution (MCP_REVIEW_REQUIRED/MCP_ACTIVE_EXECUTION). Same-company supported environment; no agent host commands. Saved override is not proof authorized account/runtime. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [runner-api-catalog.ts](../../server/src/services/native-runtime/runner-api-catalog.ts), [issue-execution-policy-routes.test.ts](../../server/src/__tests__/issue-execution-policy-routes.test.ts), [issue-execution-policy-persistence.test.ts](../../server/src/__tests__/issue-execution-policy-persistence.test.ts), [issue-workspace-command-authz.test.ts](../../server/src/__tests__/issue-workspace-command-authz.test.ts). No live execution claimed. + +Verification: `not-run` — Persist config then inspect subsequent actual run mode/model. Reject stale/mixed CAS, foreign environment, agent host commands and restricted-mode mutation; verify no denied request stops existing execution. + +Gaps: Review/workspace/runtime engines remain separately reviewed; broad account/provider/config permutations not claimed. + +### `manage-monitor` + +API: `present` — PATCH /api/issues/{id} with executionPolicy.monitor; POST /api/issues/{id}/monitor/check-now; GET /api/issues/{id}/diagnostics/wakes. + +Agent access: `partial` — native set_task_monitor standard-mode binding; permitted agent REST/call_api policy PATCH/check-now; no CLI monitor flags. No REST operation named set_task_monitor. Queue and HTTP/2 sandbox callbacks admit the wake-diagnostics read and monitor check-now request. Controller task-read, monitor-management and assignment checks still apply. Recovery resolution and scheduled-retry controls are outside this callback allowance. See the [callback bridge](../../packages/adapter-utils/src/sandbox-callback-bridge.ts) and [callback boundary tests](../../packages/adapter-utils/src/sandbox-callback-context-routes.test.ts). + +Policy: Native nested monitor|null, optional OWNED target taskId, key<=240, notes1..500, future check/timeouts/attempts<=100; reserved quota service denied, externalRef sanitized. Target assigned same agent/no human, in_progress|in_review; issue:read,runtime:manage,responsible-user authority. REST monitor changes require runtime:manage+current assignee for agent; board role gate differs. Receipt replay returns current schedule without rearming consumed monitor. Check-now cannot bypass recovery/finalization/eligibility. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue-monitors.ts](../../server/src/services/issue-monitors.ts), [issue-monitor-scheduler.test.ts](../../server/src/__tests__/issue-monitor-scheduler.test.ts), [task-monitor.integration.test.ts](../../server/src/services/native-runtime/task-monitor.integration.test.ts), [scheduling.test.ts](../../server/src/services/heartbeat/scheduling.test.ts). No live execution claimed. + +Verification: `not-run` — Schedule/reload/yield monitor wait→one wake and consumption; replace/clear, malformed schema correction and consumed-key replay. Deny mode/owner/time/reserved service. Recovery/finalization hold retains due schedule and throttled issue.monitor_deferred; settle/clear then one wake; expiry uses recorded policy with no duplicate escalation or successor ownership change. + +Gaps: Retain existing detailed PostgreSQL scheduler/native-monitor/late-result regression boundaries; scripted/no-op execution is not live model recovery. + +### `manage-watchdog` + +API: `present` — GET/PUT/DELETE /api/issues/{id}/watchdog; PUT{agentId,instructions?}; create can attach watchdog. + +Agent access: `partial` — agent REST/call_api with exact issue authority; no dedicated native/CLI watchdog editor. + +Policy: Read task; mutations stricter task helper, low-trust denial and eligible company watchdog agent. Watchdog-scoped run cannot change watchdog configuration even in watched subtree. Remove disables active config and queues evaluation; repeated disable returnsok. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [task-watchdogs.ts](../../server/src/services/task-watchdogs.ts), [issue-watchdogs-routes.test.ts](../../server/src/__tests__/issue-watchdogs-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Set/update/remove, reload config/activity; retry no duplicate active watcher. Deny wrong company, active peer ownership, low-trust and watchdog self-configuration. + +Gaps: Watchdog execution/recovery acceptance remains [recovery](recovery.md), beyond this config operation. ## `discussion` Capability ID: `tasks/discussion`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Read, append/retry, author-delete or queued-cancel messages, attach allowed files, and distinguish human feedback from agent reporting. -- `POST /api/issues/{id}/comments`. -- `POST /api/companies/{companyId}/issues/{issueId}/attachments`. +### `read-history-comment` -Agent access: `available` — Native report_progress/comment_on_task/register_deliverable; -REST / CLI / MCP. +API: `present` — GET /api/issues/{id}/comments and /comments/{commentId}. -Policy: Company/task visibility, assignment/change policy, active-run checkout ownership -and lifecycle rules. +Agent access: `available` — REST/call_api, CLI issue comments/comment:get; native get_task_history CURRENT task only, declared limit 1..200 but production clamps to 1..100 (default 50). -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) at the -reviewed commit above. +Policy: Company/task issue:read, exact task/comment binding, run/trust redaction. API supports after/afterCommentId, asc|desc, limit cap500. Locked mention edge is not comment read authority. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-comment-redaction.test.ts](../../server/src/__tests__/issue-comment-redaction.test.ts), [issue-agent-mutation-ownership-routes.test.ts](../../server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts). No live execution claimed. -Gaps: Other-task comments and active-task progress have separate scopes. Generic -`call_api` forwards explicit reopen/resume/interrupt fields to the existing route -checks; it cannot impersonate a user. +Verification: `not-run` — Read multipage history and exact comment, reload same content; reject inaccessible task, foreign/mismatched comment and inspect trust redaction. Request native limit 200 and confirm at most 100 comments. + +Gaps: Native bounded history is not an arbitrary-task/paginated API substitute. + +### `append-retry-comment` + +API: `present` — POST /api/issues/{id}/comments; PATCH task with comment. + +Agent access: `partial` — REST/call_api, CLI issue comment/update--comment; native report_progress plain CURRENT-task body+stable key only. answer_status_question is declared but not production-admitted. + +Policy: issue:comment/responsible-user/influence ceilings may allow peer/direct-parent reporting without disposition authority. body nonempty, clientRequestId UUID, maximum 20 unique attachment IDs. Agent onBehalfOfUserId rejected; presentation/metadata board-only; authorType cannot gain board wake. Board paused task returns 409. Board Agent Chat additionally flag/owner/clientRequestId. Pending/running retries preserved by ordinary board comments; explicit control separate. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../packages/shared/src/validators/issue.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-comment-attribution-audit-routes.test.ts](../../server/src/__tests__/issue-comment-attribution-audit-routes.test.ts), [issue-comment-reopen-routes.test.ts](../../server/src/__tests__/issue-comment-reopen-routes.test.ts), [cross-issue-influence-limit-postgres.test.ts](../../server/src/__tests__/cross-issue-influence-limit-postgres.test.ts). No live execution claimed. + +Verification: `not-run` — Append/mention/reference/file, reload actor/content. Retry same request/key after uncertain response→single message; changed native args conflict. Deny spoof/structured agent fields, foreign task and pause-gated board message; closed peer report stays inert. + +Gaps: Conversation, queued delivery, steering, human question continuation and artifacts retain owning recipes; saved message is not delivery/continuation proof. + +### `delete-own-or-cancel-queued` + +API: `present` — DELETE /api/issues/{id}/comments/{commentId}; mode=cancel is distinct legacy queued-cancel path. + +Agent access: `partial` — REST/call_api and CLI issue comment:delete; no dedicated native delete. + +Policy: Stricter task mutation before author check; only own comment normal deletion. Tombstones and scrubbed references/annotations/training snapshots; repeated deleted result stable. Queued cancel must still own cancelable queue; delivery race409. No general delivered-comment editor. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-comment-cancel-routes.test.ts](../../server/src/__tests__/issue-comment-cancel-routes.test.ts), [issue-queued-comments-routes.test.ts](../../server/src/__tests__/issue-queued-comments-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Delete own/reload tombstone/derived cleanup and retry; reject other-author/foreign task. Race queued cancel vs dispatch and inspect persisted winner. + +Gaps: Modern queue edit/order/steer/interrupt/discard contract remains [steering](steering.md). + +### `attach-reference` + +API: `present` — GET task attachments; POST /api/companies/{companyId}/issues/{issueId}/attachments multipart; GET /api/attachments/{attachmentId}/content; DELETE /api/attachments/{attachmentId}. + +Agent access: `partial` — REST/CLI attachments/upload/download/delete; admitted native multipart call_api or scoped register_deliverable/current-task attachment tools according to actual binding. report_progress is not upload. + +Policy: Company/task binding, stricter mutation and deliverable run-context gates. Nonempty permitted bytes, default 10 MiB deployment ceiling via PAPERCLIP_ATTACHMENT_MAX_BYTES; bound conversation owner/flag. In-progress agent requires run; CLI multipart forwards header. Content reads enforce retained task/run privacy including removed records. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [attachment-types.ts](../../server/src/attachment-types.ts), [issue-attachment-routes.test.ts](../../server/src/__tests__/issue-attachment-routes.test.ts), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts). No live execution claimed. + +Verification: `not-run` — Upload/read/download compare bytes/reload, reject foreign comment/task/wrong run and missing/empty/disallowed/oversize file; delete disposable attachment and verify no read disclosure. + +Gaps: Document/work-product/annotation detail and live upload journey belong [documents/artifacts](documents-artifacts.md); pathname alone is not uploaded deliverable. + +### `human-feedback-vote` + +API: `present` — GET/POST /api/issues/{id}/feedback-votes; POST targetType,targetId,vote,reason<=1000,allowSharing. + +Agent access: `restricted` — board identity only; CLI issue feedback:votes/feedback:vote still requires board context; no delegated/native agent voting tool. Human-input request can ask, not impersonate. + +Policy: Actual handlers require company-accessible issue lookup and board; GET own user votes. Explicit selected sharing may persist preference/queue export;201 does not wait for remote upload. Do not infer private-task read guard absent from these handlers. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [feedback.ts](../../packages/shared/src/validators/feedback.ts), [feedback.ts](../../server/src/services/feedback.ts), [issue-feedback-routes.test.ts](../../server/src/__tests__/issue-feedback-routes.test.ts), [feedback-service.test.ts](../../server/src/__tests__/feedback-service.test.ts). No live execution claimed. + +Verification: `not-run` — Vote disposable AI target, reload same-user preference and another user separately; reject agent/foreign company; inspect selected consent and queued state without claiming export completion. + +Gaps: Private-task denial must be proved, not invented. Trace/report/export belongs [feedback export](cli-operations.md#feedback-export). ## `completion` Capability ID: `tasks/completion`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — representative operation IDs: +Separate status/report acceptance, versioned start, follow-up, checkout/release and deletion; accepted provider report is not final task state. -- `PATCH /api/issues/{id}`. +### `transition-report-review` -Agent access: `available` — Native paperclip_finish/paperclip_block through runner -protocol; agent REST / native `call_api` disposition under route permissions. +API: `present` — PATCH /api/issues/{id}; POST /api/issues/{id}/stalled-review-decision for board; native paperclip_finish/paperclip_block uses admitted PRP protocol, not a REST endpoint. -Policy: Company/task visibility, assignment/change policy, active-run checkout ownership -and lifecycle rules. +Agent access: `partial` — authorized REST/call_api and CLI status updates; native actual PRP completion/block tools. finish_task/block_task/request_review declarations are excluded from production IMPLEMENTED_OPERATIONS. -Evidence: `source-only` — [implementation](../../server/src/routes/issues.ts) at the -reviewed commit above. +Policy: Task mutation/run/assignment/recovery/resolver gates. Blocked requires unresolved blocker/pending input/approval or unblockDescriptor; agent can name only SELF unblock owner. In_review requires actionable path. Native bound completion contract/criterion revision, deliverable evidence and verification must agree; done rejects unfinished work; needs_review names valid different reviewer. Pending input/approval/review/blocker can keep task open. Final state commits after provider turn/workspace finalization; report never overwrites successor/already terminal state. -Verification: `not-run` — exercise a listed permitted operation with actual agent -credentials/run context; inspect its result and applicable persistence/attribution. -Assert the relevant denied actor, owner, company or mode from Policy. Review the -remaining operations before qualifying the whole capability. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [native-completion-feedback.ts](../../server/src/services/native-runtime/native-completion-feedback.ts), [native-completion-feedback.test.ts](../../server/src/services/native-runtime/native-completion-feedback.test.ts), [native-deliverable-feedback.test.ts](../../server/src/services/native-runtime/native-deliverable-feedback.test.ts), [paperclip-runner-tool-authority.test.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts), [issue-stalled-review-decision-routes.test.ts](../../server/src/__tests__/issue-stalled-review-decision-routes.test.ts). No live execution claimed. -Gaps: The server governs whether a reported result becomes done/review/blocked. -Generic lifecycle PATCH uses existing REST authorization, checkout and approval rules. +Verification: `not-run` — Actual native accepted report→provider stop→workspace finalization→persisted status/output; stale/failed report correction without repeating work. Test blocked/review/done, pending question/blocker, invalid/self/foreign reviewer, missing output and duplicate report. + +Gaps: Governed review/approval engines remain [questions/approvals](questions-and-approvals.md); protocol report acceptance is not immediate status commit. + +### `start-backlog-cas` + +API: `present` — PATCH /api/issues/{id} exactly{status:todo,expectedStatusVersion:N}, N>=0. + +Agent access: `partial` — agent REST/admitted call_api; CLI update has no expectedStatusVersion; native create_task creates backlog but does not promote existing task. + +Policy: Status-only backlog→todo compare under row lock. Intervening status/assignment version including ABA409/no wake; mixed fields422. Existing assignment/run/responsible-user/eligibility gates remain. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [issue-status-version-route-service.test.ts](../../server/src/__tests__/issue-status-version-route-service.test.ts). No live execution claimed. + +Verification: `not-run` — Fresh version start→one eligible wake; race another change and replay old version→unchanged conflict, no second wake; mixed field denial. + +Gaps: Use fresh authoritative response; a matching displayed status is not matching version. + +### `follow-up-reopen-restore` + +API: `present` — POST /api/issues/{id}/comments or PATCH /api/issues/{id} with a comment and explicit resume/reopen where permitted; tree restore is a separate operation in the coordination map. + +Agent access: `partial` — REST/call_api and CLI comment--resume/--reopen; report_progress alone is not resume authority; no generic dedicated native reopen tool. + +Policy: Resume requires comment, eligible assignee, no unresolved blockers/pause and current actor/responsible-user/control authority. Bare cancelled status/reopen uses dedicated restore; structured resume has separate branch. Closed peer reporting inert. Ordinary board comment preserves active/queued retry; parked retry may supersede. Closed workspace restores only after authority gates. MCP pending review/active execution stays blocked. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-comment-reopen-routes.test.ts](../../server/src/__tests__/issue-comment-reopen-routes.test.ts), [issue-update-comment-wakeup-routes.test.ts](../../server/src/__tests__/issue-update-comment-wakeup-routes.test.ts), [issue-scheduled-retry-routes.test.ts](../../server/src/__tests__/issue-scheduled-retry-routes.test.ts), [issue-closed-workspace-routes.test.ts](../../server/src/__tests__/issue-closed-workspace-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Finish then authorized follow-up→same-task one continuation; plain terminal assignee note stays terminal. Reject paused/blocked/cancelled invalid path/wrong owner. Board message during running retry keeps same executor; parked retry supersedes once. + +Gaps: Steering/tree control/recovery recipes own pause/restore/stop and retry repair; do not broaden comment authority. + +### `checkout` + +API: `present` — POST /api/issues/{id}/checkout{agentId,expectedStatuses}. + +Agent access: `partial` — REST/CLI issue checkout; agent must claim itself with run ID. Native call_api only where actual admitted run needs it; native is normally already bound. + +Policy: Company lookup, tasks:assign when changing assignee, assignability, project pause/budget, subtree pause, dependency readiness and atomic expected status/assignee/execution locks. Same-run retry differs from competing run. Run-id gate before closed workspace reopen. Exact handler differs from generic read/mutation helper; do not invent blanket guard. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issues-checkout-wakeup.test.ts](../../server/src/__tests__/issues-checkout-wakeup.test.ts), [issue-stale-execution-lock-routes.test.ts](../../server/src/__tests__/issue-stale-execution-lock-routes.test.ts), [issue-closed-workspace-routes.test.ts](../../server/src/__tests__/issue-closed-workspace-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Race two claimants: one owner/executor; same-run retry no duplicate wake. Deny wrong agent/missing run, blocked dependencies, paused project and foreign company; inspect persisted locks. + +Gaps: Private-target admission requires negative proof because checkout does not mirror generic issue-read guard placement. + +### `release-force-release` + +API: `present` — POST /api/issues/{id}/release; POST /api/issues/{id}/admin/force-release?clearAssignee=true(optional). + +Agent access: `partial` — REST/call_api/CLI issue release permitted owner path; force-release requires board user (CLI command does not confer role); no dedicated native release. + +Policy: Normal release stricter mutation, agent run+assignee/matching live checkout; stale missing/terminal lock handled safely. In_progress→todo clears assignee/locks; terminal keeps historic assignee while clearing locks. Force-release explicit clearAssignee and audit, not verified process stop. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-stale-execution-lock-routes.test.ts](../../server/src/__tests__/issue-stale-execution-lock-routes.test.ts), [issues-service.test.ts](../../server/src/__tests__/issues-service.test.ts). No live execution claimed. + +Verification: `not-run` — Owner release/reload, wrong live agent/run denied, stale lock handling; terminal assignment preserved; agent force-release denied and board prior-lock audit retained. + +Gaps: Use [recovery](recovery.md) for verified termination; clearing locks alone is not provider-stop evidence. + +### `delete-task` + +API: `present` — DELETE /api/issues/{id}. + +Agent access: `partial` — permitted REST/call_api and CLI issue delete--yes; no dedicated native deletion. + +Policy: Stricter task mutation including active ownership/run constraints; company/task boundaries. Service removes task-owned rows; attachment object cleanup best effort with logged failures. Delete differs from complete/hide/archive; never imply unrelated child erasure. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [issue.ts](../../cli/src/commands/client/issue.ts), [issue-remove-cascade.test.ts](../../server/src/__tests__/issue-remove-cascade.test.ts). No live execution claimed. + +Verification: `not-run` — Delete disposable task/files, inspect list/direct reads/cascades and inaccessible orphan content; reject wrong actor/company, repeat404. Preserve unrelated records per actual service behavior. + +Gaps: Storage cleanup failure and retention are distinct from returned task removal; parent removal is not proof all children vanished. ## `privacy` Capability ID: `tasks/privacy`. -Review: `baseline`. +Review: `operation-reviewed`. -API: `present` — POST /api/companies/{companyId}/issues and PATCH /api/issues/{id} accept permitted visibility changes; GET /api/issues/{id}/privacy-constraints; GET and POST /api/issues/{id}/access-grants; POST /api/issues/{id}/access-grants/{grantId}/revoke. +Treat restriction, audience inspection, direct sharing/revocation, publishing and explicit emergency read as distinct operations. -Agent access: `partial` — eligible task reads and a permitted restriction to private are available through agent REST/native `call_api`, subject to current mutation and run authority. Grant inspection/management and widening task access require the authorized board identity; catalog actor labels do not override those route checks. +### `create-restrict-private` -Policy: Company access and issue:read precede management checks; inaccessible tasks return not found. Grant/privacy management requires the responsible user, creator, human assignee, active company owner/admin, instance admin, or local implicit board. Grant targets must be active company users or company agents. A shared reader is not a grant manager. Private inheritance flows down descendants, not upward or across siblings. Agent access intersects the responsible user’s authority. Publishing obeys parent/project constraints; a private standalone task needs a responsible user. Mutations retain activity and task lifecycle checks. +API: `present` — POST scoped issues visibility=private; PATCH /api/issues/{id} visibility=private. -Evidence: `source-only` — reviewed at `9ef434fe79c57d976b8b03b14c5242db270b8320`. [Privacy actions](../../ui/src/components/IssuePrivacyActions.tsx), [share sheet](../../ui/src/components/IssueShareSheet.tsx), [issue routes](../../server/src/routes/issues.ts), and [authorization](../../server/src/services/authorization.ts). +Agent access: `partial` — authorized agent REST/call_api restriction; native create_task has no privacy field but inherits source privacy; CLI create/update lacks visibility. -Verification: `not-run` — Create private fixtures as ordinary authenticated people, then compare discovery, direct reads, inherited child access, and inaccessible metadata before sharing and after revocation. Reject a shared reader’s grant management, cross-company or invalid targets, grants on open tasks, and agent publishing/sharing. Assert the permitted agent restriction using its actual current run and responsible-user context. +Policy: Read/mutation/current authority; standalone private requires responsible user/personal private project. Parent/private project/source-run privacy provenance protects descendants and standalone handoffs. Server derives responsible identity; management authority is exact task, never privacy-root authority. -Gaps: The native API fallback must be admitted in the tested run and mode. Full descendant, personal-project, race, and responsible-user combinations need live acceptance; source-reviewed permission branches do not establish all variants. +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [paperclip-runner-tool-authority.ts](../../server/src/services/native-runtime/paperclip-runner-tool-authority.ts), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts), [issue-access-grants-routes.test.ts](../../server/src/__tests__/issue-access-grants-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Private create/restrict→reload; protect existing/new descendants and private-run standalone handoff. Ordinary other user cannot discover/open; wrong actor/spoof responsible identity denied. + +Gaps: App-record privacy is not filesystem isolation or memory erasure. + +### `inspect-constraints-grants` + +API: `present` — GET /api/issues/{id}/privacy-constraints; GET /api/issues/{id}/access-grants. + +Agent access: `restricted` — authorized BOARD manager; agents/shared readers can read eligible task but cannot inspect grants/action hints. Catalog GET label does not override route. + +Policy: Issue read then board responsible user/creator/human assignee, active company owner/admin, instance admin/local implicit. Safe publicBlockedBy/leavesPersonalProject hints omit inaccessible scope identity. Lists direct/inherited owner/assignment/project sources; inherited rows no local revoke. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [authorization.ts](../../server/src/services/authorization.ts), [IssueShareSheet.tsx](../../ui/src/components/IssueShareSheet.tsx), [PrivateTaskPrivacyControls.test.tsx](../../ui/src/components/PrivateTaskPrivacyControls.test.tsx), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts). No live execution claimed. + +Verification: `not-run` — Manager sees correct audience/hints after reload; reader/agent403 and inaccessible404. No unreadable parent/project names. + +Gaps: Management role does not automatically grant normal private task read; use actual actor/read branch. + +### `share-directly` + +API: `present` — POST /api/issues/{id}/access-grants{subjectType:user|agent,subjectId}. + +Agent access: `restricted` — authorized board manager; no CLI/dedicated native grant tool or delegated agent share. Human-input request can ask responsible person. + +Policy: Exact readable managed task; active company user/company agent only(422 invalid); open task returns 409. Created201/existing active200. Read flows downward descendants, never parent/sibling/private project metadata. Shared agent access intersects responsible/authorizing user; memory warning cannot promise unlearning. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [authorization.ts](../../server/src/services/authorization.ts), [issue-access-grants-routes.test.ts](../../server/src/__tests__/issue-access-grants-routes.test.ts), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts). No live execution claimed. + +Verification: `not-run` — Share child/reload both people: child+descendants visible, parent/sibling/project hidden. Repeat share one grant. Reject open/foreign/nonmember and shared-reader/agent mutation. + +Gaps: A grant alone does not authorize shared agent acting for another unauthorized person. + +### `revoke-direct-inherited` + +API: `present` — POST /api/issues/{id}/access-grants/{grantId}/revoke; inherited source edits use ancestor grant/project membership APIs. + +Agent access: `restricted` — authorized board manager; no agent delegation established. + +Policy: Grant must belong to EXACT managed task, active matching grant else404; child manager cannot revoke ancestor/sibling. Other assignment/project/ancestor grants remain; assignment grants sticky after unassignment until revoked. Implicit owner access changes via role not local revoke. Live reads reauthorize; memory cannot be erased. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [authorization.ts](../../server/src/services/authorization.ts), [IssueShareSheet.tsx](../../ui/src/components/IssueShareSheet.tsx), [issue-access-grants-routes.test.ts](../../server/src/__tests__/issue-access-grants-routes.test.ts), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts). No live execution claimed. + +Verification: `not-run` — Revoke/reload/retry cold/direct/socket access with no independent source→denied. Source-edit inherited access separately, independent source retained. Reject wrong ancestor/sibling grant and repeat404. + +Gaps: A successful direct revoke does not prove complete audience removal if independent sources remain. + +### `publish-private` + +API: `present` — PATCH /api/issues/{id} visibility=open. + +Agent access: `restricted` — authorized board manager; agent call_api cannot publish. + +Policy: Private parent/nonpersonal private project blocks; personal-project task may leave personal project. Confirmation discloses task/comments/docs/history; private children stay private. Current constraints rechecked under privacy-tree lock, not just optimistic hints. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issues.ts](../../server/src/services/issues.ts), [IssuePrivacyActions.tsx](../../ui/src/components/IssuePrivacyActions.tsx), [PrivateTaskPrivacyControls.test.tsx](../../ui/src/components/PrivateTaskPrivacyControls.test.tsx), [privacy-production-review.test.ts](../../server/src/__tests__/privacy-production-review.test.ts). No live execution claimed. + +Verification: `not-run` — Cancel confirmation leaves private; valid publish visible after reload/private child remains denied. Reject private parent/project and raced stale constraint; deny agent widening. + +Gaps: Do not infer existing private descendants became public from parent or project discovery. + +### `break-glass-read` + +API: `present` — GET /api/issues/{id}?breakGlass=true. + +Agent access: `restricted` — eligible board company owner/admin explicit read, no agent path; instance/local normal admin bypass separate. + +Policy: Private-read denial plus eligible explicit owner/admin gate; emits audit and owner-visible issue notice, not persistent share or arbitrary grant mutation. Ordinary member flag still404. + +Evidence: `source-only` — reviewed at `3bbc2104b65caf9f7763938a01260a5673e12f7a`; [issues.ts](../../server/src/routes/issues.ts), [issue-access-grants-routes.test.ts](../../server/src/__tests__/issue-access-grants-routes.test.ts). No live execution claimed. + +Verification: `not-run` — Compare eligible owner/admin ordinary denied with explicit read/audit+notice; ordinary operator/agent/foreign denied, grants unchanged. + +Gaps: Local implicit/instance admin bypass cannot establish ordinary two-user private isolation. diff --git a/maps/feature-map/questions-and-approvals.md b/maps/feature-map/questions-and-approvals.md index 72842ba3b6b..7a1d9aa1a92 100644 --- a/maps/feature-map/questions-and-approvals.md +++ b/maps/feature-map/questions-and-approvals.md @@ -84,6 +84,21 @@ Use separate disposable requests for accept, decline, and revision paths. Record the actor and request revision. Prepare a waiting question through a test agent; a component fixture alone cannot prove live response delivery. +**Operation checkpoints** + +Use these checks alongside the entry-point recipes below and the operation records in the [access companion](../agent-access-map/questions-and-approvals.md). Record the actual actor, surface, saved result and denial separately. Source review and linked tests do not establish a live pass. + +| Capability ID | Action and persisted result | Denial, race and retry checks | +| --- | --- | --- | +| `questions-and-approvals/questions` | Create fixed-ID single/multiple/custom/text questions; move between pages, submit, and reload the saved answer and responder. | Reject missing/invalid answers without resolving. Competing answers settle once. Distinguish cancel, withdraw, historical Done-task answers, and local dismissal; historical answers must not restart work. | +| `questions-and-approvals/dismiss-and-reopen` | Dismiss without submitting, reopen from history, edit the retained draft, and reload in the same browser. | Confirm the server request remains pending and a new ordinary comment does not answer it. Resolve in another tab and refresh the old form. Browser draft/dismissal state is not account-wide state. | +| `questions-and-approvals/confirmations` | Use separate accept, decline/change-request, checkbox subset, suggested-task selection, and partial item-verdict requests. Inspect the actual selected items and created task IDs. | Test invalid selections, child-without-parent selection, expiry, supersession, withdrawal, and repeated/conflicting decisions. Partial verdicts persist; skip must not start a continuation. | +| `questions-and-approvals/plan-review` | Open the exact requested plan revision; reject one request and accept another. Inspect saved revision, work mode, owner, and the resulting continuation. | Edit after requesting review and reject stale acceptance. Test finalization readiness and bound completion review separately. In Agent Chat, inspect the later project/task creation and its source-plan provenance; acceptance alone is not a completed handoff. | +| `questions-and-approvals/audience` | Repeat a request for a named person, named agent, human-only resolver, and independent reviewer. Inspect actionability and final attribution. | Test creator exclusion, wrong audience/company, private task, missing or cancelled run, and changed responsible-user access. A human comment used by an agent remains subject to that agent’s resolver authority. | +| `questions-and-approvals/governance` | Create and inspect a formal request, comment, request revision, resubmit, then approve or reject distinct requests. Reload history and linked task state. | Test board decision authority separately from agent request/comment/resubmit authority. A repeated decision cannot repeat activation. Current pending status, payload revision, and governed side effects must agree. | +| `questions-and-approvals/tool-review` | Invoke a harmless Ask first action, compare task and Apps review surfaces, then exercise Approve once, Always allow, and Decline separately. | No provider call before approval. Repeat decisions and compare invocation count. Change the tool definition, revoke access, or set Off before a decision. Record the approval decision and provider outcome independently. | +| `questions-and-approvals/continuation` | After answering, inspect the saved response, delivery receipt, eligible run, and useful result in the original task/thread. | Reload, race two tabs, and interrupt delivery after saving. Require one continuation without repeated external actions. Reassignment, Stop, pause, budget, and external-thread boundaries remain effective. | + ### `task-thread` Automated: [interaction cards](../../ui/src/components/IssueThreadInteractionCard.test.tsx), diff --git a/maps/feature-map/recovery.md b/maps/feature-map/recovery.md index 42427349414..dbb7ea7c623 100644 --- a/maps/feature-map/recovery.md +++ b/maps/feature-map/recovery.md @@ -98,6 +98,21 @@ adapter/runtime mode, cause, attempt count, current owner, and verified stop evidence. Do not kill an unrelated server or induce provider side effects just to get a failure screen. Use the existing deterministic recovery suite first. +**Operation checkpoints** + +Use these checks alongside the entry-point recipes below and the operation records in the [access companion](../agent-access-map/recovery.md). Record the actual actor, surface, saved result and denial separately. Source review and linked tests do not establish a live pass. + +| Capability ID | Action and persisted result | Denial, race and retry checks | +| --- | --- | --- | +| `recovery/diagnosis` | Open the source task and exact run; compare cause, source action, original owner, recovery owner, attempt bounds and next action after reload. | Test an unrelated/private task and a stale run notice. Read-side retirement of a stale action must not create a new attempt, participant, or permission to replay. | +| `recovery/bounded-continuation` | Use a deterministic recoverable interruption and inspect the original run/session, attempt receipts, saved result and eventual useful output. | Repeat restart/receipt delivery, race Stop or a new owner, and retain unknown external outcomes. Accepted completion/finalization recovery must not start a new provider turn or repeat its side effect. | +| `recovery/source-action` | Inspect active and retained actions, follow the repair owner, and resolve one eligible source-bound action with its exact ID. | Retry the settled resolution and reject a stale/foreign action. Recovery ownership alone cannot mutate the source task; inspect source status, audit and wake independently. | +| `recovery/exhaustion` | Exhaust or age a bounded fixture; use the currently offered retry once, then inspect its durable acknowledgement and actual continuation. | Reassign, pause, stop, close, add an unresolved dependency, or impose a budget hold before retry. The old notice must not reopen terminal work or run the wrong owner. | +| `recovery/workspace` | Exercise retained-file recovery, export retry, reconstruction, branch repair/reconciliation and exact-owner finalization as distinct authorized operator paths. | Use exact source/action/run/receipt bindings and preserve existing files. Reject stale source, live/uncertain writers, unsafe archives and insufficient authority. Verify actual files and accepted result separately from queued acknowledgement. | +| `recovery/unknown-outcome` | Inspect the provider and saved intent before recording a source-specific chat, email or governed-provider outcome. | Use performed, not-performed and unresolved cases. Wrong company/request, stale state and unauthorized resolution must fail. Unknown effects must not replay automatically. An explicit retry must record the operator’s duplicate-risk acceptance and dispatch only the authorized attempt. | +| `recovery/user-continuation` | Save a distinguishable instruction while Stop cleanup is pending; after verified stop, inspect exactly one eligible continuation and its useful response. | Keep the message waiting under task/ancestor pause, budget or retained-file holds. Do not impersonate a human message or infer delivery from a queued wake. | +| `recovery/reconnect` | Disconnect the browser, let the server change persisted task/run state, reconnect, then reload and compare. | Inspect duplicate comments/decisions and private/company boundaries after access changes. Browser transport recovery and agent execution recovery require separate results. | + ### `source-task` Automated: [recovery actions](../../server/src/__tests__/issue-recovery-actions.test.ts) diff --git a/maps/feature-map/secrets.md b/maps/feature-map/secrets.md index c3e566c63e4..36bb8f13d04 100644 --- a/maps/feature-map/secrets.md +++ b/maps/feature-map/secrets.md @@ -34,6 +34,18 @@ Use the Proposals tab or Import from vault where available. Preconditions: follow the [baseline](./README.md#before-driving-a-journey). Use dummy credentials in an isolated company, two user identities, and a test agent. Never print actual secret values in evidence. +**Operation checkpoints** + +Use these checks alongside the entry-point recipes below and the operation records in the [access companion](../agent-access-map/secrets.md). Record the actual actor, surface, saved result and denial separately. Source review and linked tests do not establish a live pass. + +| Capability ID | Action and persisted result | Denial, race and retry checks | +| --- | --- | --- | +| `secrets/company-secrets` | Create a dummy company reference; inspect metadata, usage and access history; update, rotate, bind, and remove separate disposable references. | Reload each change and test read versus manage authority, foreign IDs, stale bindings and in-use deletion. Metadata, errors and audit must omit values. Rotation and metadata edits have different effects. | +| `secrets/user-secrets` | Manage a credential definition and inspect coverage as an authorized operator; create, update, rotate and remove the current person’s dummy value. | Use two signed-in people. Definition/coverage authority does not grant another person’s value. Check missing values, wrong definitions, cross-company references and owner-scoped persistence. | +| `secrets/proposals` | Use an actual permitted run to propose a new secret or binding; inspect its redacted preview, withdraw one, reject one, and approve a fresh one. | Check target/value authority before applying. Test expiry, duplicate/conflicting decisions, revoked context and malformed run attribution. Inspect created reference/binding and audit once, without displaying the dummy value. | +| `secrets/vault-import` | Manage a disposable provider configuration, default and health check; preview eligible AWS references and import only selected test entries. | Check provider/admin authority, unsupported vaults, failed discovery/health, duplicate imports and foreign IDs. Imported references still need permitted value resolution; provider registration does not prove a working vault. | +| `secrets/runtime-delivery` | Bind a dummy reference to a permitted environment/config path and use the actual run to check delivery without printing the value. Inspect the agent’s permitted metadata catalog separately. | Deny ordinary agent-key value reads, user/instance-scope reads through the agent value API, and missing/wrong run or binding. Check Stop/revocation, redacted logs/errors and isolation of another person’s value. | + ### `secret-management` Automated: [secrets service](../../server/src/__tests__/secrets-service.test.ts) and [user ownership](../../server/src/__tests__/secrets-service-user-secret-owner-scoped.test.ts) cover storage/access contracts. [Instance-secret tests](../../server/src/__tests__/agent-instance-secrets.test.ts) cover local encrypted storage, owner isolation, and exclusion from ordinary bindings. diff --git a/maps/feature-map/tasks.md b/maps/feature-map/tasks.md index f51a519e938..c4712c78c04 100644 --- a/maps/feature-map/tasks.md +++ b/maps/feature-map/tasks.md @@ -46,6 +46,19 @@ disposable project. Persistence checks can assign work to Me or leave it unassigned; execution checks additionally need an invokable test agent. Record whether a real or simulated harness handles execution. +**Operation checkpoints** + +Use these checks alongside the entry-point recipes below and the operation records in the [access companion](../agent-access-map/tasks.md). Record the actual actor, surface, saved result and denial separately. Source review and linked tests do not establish a live pass. + +| Capability ID | Action and persisted result | Denial, race and retry checks | +| --- | --- | --- | +| `tasks/create` | Create an unassigned task or assign it to Me; save its description and context, then reopen and reload the exact task. | Exercise required fields, inaccessible parents/projects, and the same API creation key with identical and changed input. Compare task IDs and run counts; saving a draft is not creation. | +| `tasks/organize` | Find the saved task through list, project, filter, and direct-link surfaces; change supported labels separately. | Compare another actor’s private results and another company. Distinguish browser sorting/grouping preferences from saved task data. | +| `tasks/properties` | Change title, metadata, assignee, dependencies, work mode, execution settings, and monitor/watchdog configuration as separate operations. Reload each saved change. | Use an occupied checkout, stale status version, invalid dependency, stopped run, and disallowed mode. Check the specific rejection and unchanged fields; a successful title edit does not establish assignment authority. | +| `tasks/discussion` | Post a unique comment, reload, and inspect attribution. Read history, inspect a queued message, and delete only an owned disposable comment where allowed. | Separate an ordinary comment from steering or a wake. Check inaccessible task history, author-only deletion, queued cancellation, and duplicate delivery. Feedback votes have their own human authority. | +| `tasks/completion` | Complete, block, request review, reopen, and cancel separate disposable tasks through offered controls. Inspect the saved outcome, review gates, and execution state. | Test pending dependencies/reviews, a stale or active checkout, and late writes after handoff. Terminal status does not prove provider stop or saved files. Verify checkout/release and destructive deletion separately from completion. | +| `tasks/privacy` | Create private work with a responsible person; share a child, inspect direct/inherited rows, revoke a direct grant, and check publication constraints. | Use separate ordinary people and an actual agent. Shared readers cannot manage grants; ancestor/project access changes at its source. Reload and retry discovery/direct reads after revocation; keep unrelated direct grants. | + ### `new-task` Automated: [creation dialog](../../ui/src/components/NewIssueDialog.test.tsx) is component coverage with mocked requests.