docs: deepen task, approval, secret, and recovery maps (#16994)

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Its feature map describes user journeys. Its access map describes
the matching agent paths.
> - The recent index and capability additions improved discovery and
breadth.
> - Broad baseline records still combined operations with different
actors, permissions, and retry behavior.
> - This pull request reviews the existing task, approval, secret, and
recovery capabilities at operation level.
> - Each operation now has its own access boundary, source evidence, and
verification recipe. Source review remains separate from live proof.

## Linked Issues or Issue Description

Refs: #16987, #16990, #16025. These related pull requests are merged.
The search found no open duplicate or matching issue.

**Issue type**

Missing documentation.

**Where is the issue?**

The paired task, questions-and-approvals, secrets, and recovery files
under `maps/feature-map/` and `maps/agent-access-map/`.

**What's wrong?**

Baseline records do not show enough detail to verify who can perform
each action, which state must persist, or what happens after a denial,
race, or retry. A declared scenario tool can also be mistaken for an
admitted production tool.

**Suggested fix**

Split the four areas into source-reviewed operation records. Add compact
checkpoints to their user recipes. Preserve existing capability IDs and
the map schema.

## What Changed

- Promote 27 existing capability records to `operation-reviewed`, with
125 operation records: tasks 32, questions and approvals 39, secrets 28,
recovery 26.
- Give each operation its own API, agent surface, policy, source
evidence, verification recipe, and remaining gap.
- Separate human, legacy agent, run JWT, native binding, mode, and
resource authority. Split operations where those rules differ.
- Correct production completion paths, plan acceptance and handoff,
question dismissal and withdrawal, secret proposal authority, runtime
recovery grants, and explicit duplicate-risk decisions.
- Preserve access gaps found in source, including the binding-proposal
dependency cascade and narrower native/CLI fields.
- Add one checkpoint table per product recipe for saved results, denial,
races, and retries.
- Keep all 191 existing capability IDs. Change only eight Markdown
files. Keep every operation's evidence `source-only` and verification
`not-run`; the subset below does not prove an entire operation across
its actors and surfaces.

## Verification

Source review uses revision `3bbc2104b65caf9f7763938a01260a5673e12f7a`.
Read-only area reviews and a second source review covered the changed
pairs.

Passed:

- `node scripts/check-maps.mjs`: 35 paired areas, 191 capability IDs,
valid references and fields. This is structural verification.
- `node --test scripts/check-maps.test.mjs
scripts/storybook-feature-index.test.mjs`: 17 passed.
- `node scripts/storybook-catalog.mjs`: 308 files, 2,899 stories.
Generated outputs remain ignored.
- Capability comparison with the base: all 191 IDs unchanged; the four
reviewed areas contain 27 capabilities and 125 source-only operation
records.
- `pnpm -r typecheck` and `pnpm build`.
- `git diff --check`.
- Focused existing interaction and proposal route tests: 80 passed. The
two selected DB-backed suites skipped 119 tests because local embedded
PostgreSQL could not start. These skipped tests are not passes.

Live subset on a fresh local instance with a disposable PostgreSQL
container:

- Created the company and an unassigned task through the browser. Added
a comment and completed the task. The saved status and comment survived
reload.
- Created a managed secret with inert dummy data through the browser.
Its metadata and version survived reload. The metadata response did not
contain the dummy value.
- Created a question fixture through board REST. Invalid input returned
422 and left it pending. Browser dismissal kept it pending and preserved
the draft. Reopening restored the choice. Submission survived reload. A
duplicate response returned 409 and left the saved answer unchanged.
- Used a real issued legacy agent API key. Task read and safe
company-secret catalog returned 200. Full secret listing and run-only
secret list/value routes returned 403. Revoked the key after the checks.
- Read an empty recovery projection. Resolving a nonexistent action
returned 404 and left the task unchanged. This did not execute recovery.
- Closed the owned browser tab and stopped only the verified test
runtime and labelled database container. Evidence survived cleanup. No
provider or model ran.

Limits and retained failures:

- Native embedded PostgreSQL launch failed because the host could not
allocate semaphores. The container-backed app was the successful
alternate environment.
- Full `pnpm test:run` was attempted. Fifteen DB-dependent
native-session cases failed at database startup, and several DB suites
skipped. The run was stopped after repeated failures of that
prerequisite. The full local suite did not pass.
- The sandboxed build attempt failed at the local tsx IPC socket. The
required build passed outside the sandbox.
- The first CI build job passed compilation and production boot, then
its npm-install check was interrupted when the runner received a
shutdown signal. The corrected head passed the full CI run, including
the build and public-install checks.
- Initial Greptile review found the recovery note field and native
search/history limits were inaccurate. Corrected `resolutionNote` and
the production cap of 100, then reran the map checks. Greptile reviewed
the corrected head at 5/5; both earlier threads are resolved.
- An initial harness used a nonexistent generic secret-value URL and
received 404. The actual mapped agent routes were then checked
separately. An initial recovery assertion expected 409; the actual
missing-action contract returned 404. These were harness corrections,
not product fixes.
- Native run bindings, two-person ownership, secret delivery/rotation,
external vaults, provider-stop proof, workspace repair, and actual
recovery execution remain unexecuted. The map does not claim those
journeys passed.

The separate external **Paperclip Review** check is still in progress on
`904509df80cc6de16d36906a410a66786f619b20`. The reviewer reports that
its full changed-file request is pending. CI is green and Greptile is
5/5, but this external review has not published a final assessment. Its
review service must finish that request and assessment.

## Risks

Documentation can become stale as policy and runtime bindings change.
Each operation cites source and retains its verification gaps. The
records describe observed enforcement; they do not authorize broader
access or certify live behavior. This pull request changes no product
code, schema, or permission enforcement.

## Model Used

OpenAI Codex, `gpt-6.1-sol`; 475,000-token context window; xhigh
reasoning; tool use and code execution. Read-only source agents assisted
the area reviews.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused map and route
checks; full-suite host blocker recorded above)
- [x] I have added or updated tests where applicable (existing map
regression tests cover this documentation-only change)
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip authored and GitHub committed 2026-10-20 13:59:25 -05:00
1 parent a2d26a83fe
commit 4145b5048a
8 files changed
+1715 -622

No files matched your search

+516 -127
View File
@@ -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.
+329 -245
View File
@@ -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.
+394 -92
View File
@@ -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=<id>`/`?definition=<id>` 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 <id>`, `secrets access-events <id>`; 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 <env-name>` 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 <id> --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 <id> --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 <id> --yes --confirm <same-id>`.
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.<ALIAS>` 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 <id>`.
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 <id>`.
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.
+421 -158
View File
@@ -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.
@@ -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),
+15
View File
@@ -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)
+12
View File
@@ -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.
+13
View File
@@ -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.