mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 21:59:38 +01:00
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:
1 parent
a2d26a83fe
commit
4145b5048a
8 files changed
+1715
-622
No files matched your search
@@ -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
@@ -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.
|
||||
@@ -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
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user