mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 19:16:16 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agents publish GitHub reviews through governed tools. > - GitHub can accept a publication before the caller receives its result. > - Exact retries must return the existing publication receipt. > - The gateway compared a shortened audit hash with a complete request hash. > - Long reviews therefore failed the retry check even when their content was unchanged. > - This pull request checks the complete saved publication and returns its current receipt. > - Agents can confirm their work without another provider write. ## Linked Issues or Issue Description Refs #16284, which added durable publication recovery. Refs #16275, which extended the GitHub tool deadline. **What happened?** An exact review retry returned an idempotency conflict after GitHub had published the review. The invocation hash uses an audit preview that shortens strings to 500 characters and arrays to 50 entries. The gateway compared that hash with the complete request hash. The earlier retry tests used short assessments. **Expected behavior** An unchanged request returns its durable receipt. Changed content, changed authority, or a missing publication must not cause another write. **Steps to reproduce** 1. Submit a review with a summary and rationale longer than 500 characters. 2. Let publication finish after a short caller deadline. 3. Repeat the exact request. Before this fix, the gateway returns an idempotency conflict. **Paperclip version or commit** Reproduced on master at `c5226daf7a37559ddc007446681717791d80a223`. ## What Changed - Use the durable publication's complete request check for GitHub retries. Keep run, agent, task, connection, tool, and current authority checks. - Return the saved receipt through normal gateway validation and bookkeeping. Leave pending provider work to the durable worker. - Refuse retries without a saved publication. Keep existing invocation keys and audit previews unchanged. - Cover long reviews, comments, progress updates, text suffix changes, nested coverage changes, pending receipts, missing publications, and revoked access. - Document the recovery contract and verification recipes. ## Verification - Red: both long-review receipt cases failed on unchanged production code with the expected idempotency conflict. - Green: all 144 GitHub review workflow tests passed on the final source. This includes long reviews, comments, progress updates, pending and missing receipts, revoked policy, and the native assigned-tool entry point. - Server and workspace typechecks passed. The production build passed. - Map checks passed. These are structural checks. - The first broad run found an incorrect new fixture assumption: its discovery query returned two review tools. The fixture now selects the exact submission tool. An existing description-edit polling test also timed out; it passed separately without a production change, then passed in the complete 144-test rerun. Both earlier failures remain recorded. - Final commit `7cdcdc3a1ac79cb4ed77510a32d795228e3315e8` passed all 55 CI checks. Two optional Storybook jobs were skipped. [Complete CI run](https://github.com/paperclipai/paperclip/actions/runs/39304187397). Greptile is 5/5 on this exact commit, with zero unresolved review threads. - The earlier local full-suite attempt was stopped after the fixture correction. The final local full-suite attempt was stopped after complete final-head CI passed. No complete local full-suite pass is claimed; full-suite acceptance uses the current-head CI matrix. - Provider responses are controlled fixtures. Native assigned-tool coverage uses the production gateway and disposable PostgreSQL. No live GitHub fault injection, deployment, or historical task recovery is claimed. ## Risks A pending receipt remains pending. It does not complete the task. Caller retries no longer dispatch provider work; the durable worker retains that responsibility. A missing durable publication returns a conflict because the gateway cannot establish the original write's outcome. Existing approval and revocation checks remain effective. No database migration or audit hash change is required. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The session does not expose a more specific serving model ID or context-window limit. ## 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 and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [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>
249 lines
12 KiB
Markdown
249 lines
12 KiB
Markdown
# External chat and email conversations — agent access
|
|
|
|
Product map: [External chat and email conversations](../feature-map/chat-channels.md).
|
|
|
|
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).
|
|
|
|
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.
|
|
|
|
## `providers`
|
|
|
|
Review: `baseline`.
|
|
|
|
API: `present` — representative operation IDs:
|
|
|
|
- `POST /api/companies/{companyId}/chat-endpoints`.
|
|
|
|
Agent access: `restricted` — Board setup APIs; native connection request can ask for
|
|
setup.
|
|
|
|
Policy: Endpoint management/identity linking requires a board user; delivery is
|
|
server-owned and agent tools use scoped assignments.
|
|
|
|
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
|
|
at the reviewed commit above.
|
|
|
|
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.
|
|
|
|
Gaps: Provider installation and account enrollment are not available to an ordinary
|
|
agent actor.
|
|
|
|
Speko UI reconciliation (2026-10-13): experimental voice setup uses the same
|
|
board-managed endpoint boundary. Source review follows the merged voice runtime
|
|
and the UI integration; live provider qualification is still separate.
|
|
|
|
## `identity`
|
|
|
|
Review: `baseline`.
|
|
|
|
API: `present` — representative operation IDs:
|
|
|
|
- `POST /api/chat-identity-links/confirm`.
|
|
|
|
Agent access: `restricted` — Human identity-link flow.
|
|
|
|
Policy: Endpoint management/identity linking requires a board user; delivery is
|
|
server-owned and agent tools use scoped assignments.
|
|
|
|
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
|
|
at the reviewed commit above.
|
|
|
|
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.
|
|
|
|
Gaps: Identity linking requires a signed-in board user, rollout admission and
|
|
provider checks at the HTTP route. Native `call_api` preserves these permissions.
|
|
|
|
## `conversation`
|
|
|
|
Review: `baseline`.
|
|
|
|
API: `present` — representative operation IDs:
|
|
|
|
- `POST /api/chat-endpoints/{endpointId}/conversations/{conversationId}/publications`.
|
|
|
|
Agent access: `partial` — Assigned-agent reply pipeline; native completion; provider
|
|
tools where assigned.
|
|
|
|
Policy: Endpoint management/identity linking requires a board user; delivery is
|
|
server-owned and agent tools use scoped assignments.
|
|
|
|
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
|
|
at the reviewed commit above.
|
|
|
|
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: Normal agent replies work through server delivery. Explicit endpoint publication
|
|
APIs are board management paths.
|
|
|
|
Publication, provider-reply, and form-open 403/permission errors fail the rejected
|
|
operation without removing unrelated assigned channel tools. Confirmed
|
|
authentication failures still put the endpoint in attention, which blocks tool
|
|
admission and provider sends; connection enabled intent is retained. Known
|
|
resource denials and explicit revocation keep their narrower or installation-wide
|
|
stops. PostgreSQL provider fixtures verify discovery after 403 and rejection after
|
|
401, including signed installation removal after a 401; they do not establish
|
|
live GitHub credential recovery.
|
|
|
|
GitHub publication recovery (2026-10-14): assigned-agent `submit_review`, `comment`,
|
|
and `update_comment` calls reuse their run-, task-, endpoint-, and argument-bound
|
|
publication on an exact retry. Identity uses the complete durable request rather
|
|
than the shortened audit preview. A changed suffix, changed nested entry, or
|
|
missing publication cannot authorize another write. Exact retries only read the
|
|
receipt; the worker owns pending provider retries. Fresh gateway policy and provider authority remain
|
|
required. The durable worker resumes transient failures after restart and stops
|
|
at its retry cap, revoked authority, or a superseded head. A pending receipt is
|
|
not task completion. Source:
|
|
[publication service](../../server/src/services/chat-github-reviews.ts) and
|
|
[gateway](../../server/src/services/tool-gateway.ts). Verification uses
|
|
PostgreSQL-backed provider fixtures; this entry does not claim live provider
|
|
qualification for the new retry path.
|
|
|
|
Speko browser sessions use `POST /api/companies/{companyId}/voice-sessions`,
|
|
with GET inspection/notification and POST `/{sessionId}/end` operations below
|
|
that collection. These routes require board identity; ordinary agent credentials
|
|
cannot start a private voice session. Start and notification also require the
|
|
experimental chat-connectors gate. Signed provider callbacks use the separate
|
|
voice-webhook routes and their session capability. Evidence: `source-only` —
|
|
[voice routes](../../server/src/routes/voice-sessions.ts). No live browser answer
|
|
retrieval or telephone playback is established by the UI fixtures.
|
|
|
|
Slack's **Require at-mention** policy applies to channel messages and channel
|
|
thread replies, including queued work. DMs are exempt from mention checks;
|
|
endpoint availability, **Allow direct messages**, and sender authorization still
|
|
apply. Top-level DM replies retain their linear conversation destination. Source:
|
|
[admission](../../server/src/services/chat-channels.ts) and
|
|
[queued run policy](../../server/src/services/durable-chat-wakeup.ts). Live Slack
|
|
verification of this exemption remains separate from provider-fixture coverage.
|
|
|
|
Slack eyes acknowledge the authorized task/comment commit before attachment
|
|
preparation or scheduler acceptance. This server-owned receipt grants no agent
|
|
authority. Generation/credential fencing, durable retries and exact-source final
|
|
cleanup still apply. PostgreSQL fixtures block attachments, subscription and
|
|
wakeup independently to verify that none gates the reaction; live Slack latency
|
|
remains a separate check. See [receipt worker](../../server/src/services/chat-channels/receipt-reactions.ts).
|
|
|
|
Controller-owned receipt reactions accept the SDK's empty thread timestamp for
|
|
linear DMs. Channel IDs and source message timestamps remain validated. This
|
|
does not add an agent tool or change sender, task, or credential authorization.
|
|
The pinned SDK transport regression is covered in
|
|
[receipt tests](../../server/src/services/chat-slack-receipts.test.ts); live
|
|
acknowledgement speed needs a separate provider test.
|
|
|
|
Slack assignment and tool discovery bound concurrent endpoint preparation to
|
|
two. Every endpoint keeps the live task, company, agent and linked-user checks;
|
|
403 denials omit only that endpoint. Preparation waits for both active checks
|
|
before it returns an ordered result or propagates an error. Tool authority reads
|
|
the current bot token without resolving unrelated webhook credentials. See the
|
|
[real-database preparation controls](../../server/src/__tests__/slack-tool-preparation.test.ts)
|
|
and [batch failure controls](../../server/src/services/connectors/slack-endpoint-preparation.test.ts).
|
|
These local controls do not establish live Slack latency or provider access.
|
|
|
|
Native tool gateways use the durable run task binding for discovery and policy
|
|
checks, with legacy JSON task fields as a fallback. GitHub and Slack follow
|
|
accepted request provenance across task continuations. GitHub can retain the
|
|
originating conversation after a board follow-up from the same accepted user.
|
|
An inherited origin cannot cross a task, agent, company, or requester boundary.
|
|
Cycle checks reject invalid history without a fixed limit on valid continuations.
|
|
Endpoint settings, linked identity, tool profiles, and invocation policy still
|
|
apply on each call. The native tool contract rotates older provider sessions so
|
|
an empty retained catalog is not reused. PostgreSQL fixtures cover discovery,
|
|
review publication, Slack reads, and revocation in
|
|
[channel integration](../../server/src/__tests__/chat-channels.integration.test.ts)
|
|
and [provenance controls](../../server/src/services/chat-channels/run-origin.test.ts).
|
|
The [voice gateway fixture](../../server/src/__tests__/voice-session-store.integration.test.ts)
|
|
also verifies durable task binding for a later personal callback invocation.
|
|
Failure replies cannot replace final answers inherited from an earlier run.
|
|
These fixtures do not prove live provider delivery.
|
|
|
|
Catalog authorization projection (2026-10-17): tool discovery uses the same live
|
|
service-owned task, company, agent, requester, endpoint and credential checks as
|
|
full authority resolution. It omits the revision digest and search-action token,
|
|
which catalog descriptors do not consume. Connector assignments and governed
|
|
operations retain full revision resolution; invocation policy is still checked
|
|
by the gateway. Registry replacement and missing-service controls are in
|
|
[authority registration tests](../../server/src/services/connectors/slack-authority.test.ts).
|
|
This is a source and local-database contract; hosted latency needs live evidence.
|
|
|
|
New conversations resolve typed project/workspace defaults from their endpoint
|
|
and destination under the task-creation transaction. Defaults do not authorize
|
|
private sources: admission checks the linked user's authority and assigned agent.
|
|
An existing conversation keeps its task binding. See
|
|
[creation service](../../server/src/services/chat-channels.ts) and
|
|
[defaults contract](../../packages/shared/src/types/chat-channels.ts).
|
|
|
|
## `attachments`
|
|
|
|
Review: `baseline`.
|
|
|
|
API: `present` — representative operation IDs:
|
|
|
|
- `GET /api/issues/{id}/attachments`.
|
|
- `POST /api/companies/{companyId}/issues/{issueId}/attachments`.
|
|
|
|
Agent access: `partial` — Native register_deliverable / attachment tools when admitted;
|
|
agent REST; server-owned delivery.
|
|
|
|
Policy: Endpoint management/identity linking requires a board user; delivery is
|
|
server-owned and agent tools use scoped assignments.
|
|
|
|
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
|
|
at the reviewed commit above.
|
|
|
|
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: Uploading/registering is supported. Provider delivery status and board replay are
|
|
separate operations.
|
|
|
|
## `lifecycle`
|
|
|
|
Review: `baseline`.
|
|
|
|
API: `present` — representative operation IDs:
|
|
|
|
- `GET /api/chat-endpoints/{endpointId}/activity`.
|
|
- `PATCH /api/chat-endpoints/{endpointId}`.
|
|
- `PUT /api/chat-endpoints/{endpointId}/resources` configures destination defaults.
|
|
|
|
Agent access: `restricted` — Board lifecycle APIs; agent requests repair when blocked.
|
|
|
|
Policy: Endpoint management/identity linking requires a board user; delivery is
|
|
server-owned and agent tools use scoped assignments.
|
|
|
|
Evidence: `source-only` — [implementation](../../server/src/routes/chat-channels.ts#L75)
|
|
at the reviewed commit above.
|
|
|
|
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.
|
|
|
|
Gaps: Activity/repair/replay/disable use board endpoint access, not the agent's ability
|
|
to reply.
|
|
|
|
Endpoint/destination execution defaults use the same board-only management
|
|
boundary. Agents select an authorized workspace for their current task through
|
|
the [workspace APIs](workspaces.md), rather than editing channel configuration.
|
|
|
|
Speko callback preferences, incoming phone configuration/approval, and call
|
|
history use the company-scoped `voice-callbacks`, `voice-phone`, and
|
|
`voice-history` routes. Their UI controls do not grant agents board authority.
|
|
See [voice routes](../../server/src/routes/voice-sessions.ts); service-level
|
|
caller/session permissions and real provider delivery need separate verification.
|
|
|
|
GitHub review summary headings use the bot display name. Checks remain
|
|
independently scoped by GitHub App and endpoint/PR/commit identity.
|