Commit Graph
98 Commits
Author SHA1 Message Date
DottaandPaperclip cbfaab918a fix(server): wake failed retry notices from receipt changes
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 14:10:02 -05:00
DottaandPaperclip 7c0246893f refactor(server): isolate bounded failed retry notice projection
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 13:43:30 -05:00
DottaandPaperclip fee07f3fa8 fix(server): bound inbound notice authorization passes
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 13:30:08 -05:00
DottaandPaperclip d4f7426bb4 fix(server): wake inbound queue notices from committed changes
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 13:16:10 -05:00
DottaandPaperclip 2c348b30ae refactor(server): isolate inbound notice reconciliation and committed triggers
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 12:47:55 -05:00
DottaandPaperclip d6dfbb495d fix(chat): preserve inbound notice cursor precision
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 12:30:20 -05:00
DottaandPaperclip bcf2f38ff5 fix(server): wake native chat progress from committed work
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 12:19:41 -05:00
DottaandPaperclip b212886949 fix(server): preserve native progress cursor precision and isolate projection
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 11:58:53 -05:00
DottaandPaperclip ed76256b97 fix(server): close milestone identity and recovery wake gaps
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 11:52:03 -05:00
DottaandPaperclip 1b0bec0b25 fix(server): replace lifecycle milestone polling with scoped work
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 11:39:02 -05:00
DottaandPaperclip d2ae1655c8 fix(server): wake chat milestones after Cloud and board authority restoration
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 11:25:52 -05:00
DottaandPaperclip 0f38d1079d fix(server): wake chat milestones when publication authority returns
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 11:14:49 -05:00
DottaandPaperclip 1ed9309b34 fix(server): wake milestones after inbound receipt recovery
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 10:46:32 -05:00
DottaandPaperclip f582d65f66 fix(server): wake chat milestones from inbound admission
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 10:38:24 -05:00
DottaandPaperclip 36cf01b4b5 fix(server): wake chat milestones from recovered prompt receipts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 09:35:51 -05:00
DottaandPaperclip 41cc717572 fix(server): wake chat milestones after review retirement and reset
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 09:30:27 -05:00
DottaandPaperclip 883d45fbc3 fix(server): signal native milestone projection changes
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 07:08:13 -05:00
DottaandPaperclip 362bf75b8f refactor(server): separate chat lifecycle and native progress projection
Preserve combined reconciliation and its shared budget. Retain PostgreSQL timestamp precision so rejected lifecycle candidates cannot pin pagination.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 06:37:14 -05:00
DottaandPaperclip 6f2f3951ca fix(server): recover Teams attempts from saved claim deadlines
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 06:11:06 -05:00
DottaandPaperclip 5ddb4543ed fix(server): schedule Teams consent expiry from saved deadlines
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 06:01:32 -05:00
DottaandPaperclip 1604a9fcba fix(server): coalesce receiver recovery without redundant stop wakes
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 03:05:04 -05:00
DottaandPaperclip f45969454c fix(server): wake chat receiver discovery from configuration and lease deadlines
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 02:44:00 -05:00
DottaandPaperclip d3187f76a4 fix(server): preserve backlog deadlines after partial failure
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 02:11:08 -05:00
DottaandPaperclip 8df31d46c0 fix(server): preserve Discord backlog and queued scopes
Retain the real company-deletion regression pending its prerequisite dependency-order repair.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 01:38:33 -05:00
DottaandPaperclip 3755d7cace fix(server): wake Discord registration from committed changes and deadlines
Replace command maintenance inside runtime polling with scoped producer wakes, saved verification deadlines, and fair bounded dispatch. Preserve current credential and namespace authority, foreground setup, runtime continuity, and shutdown settlement.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 01:13:08 -05:00
DottaandPaperclip 9c442cf48e feat(connections): deploy and configure Supabase and Vercel (#17217)
Add governed Supabase and Vercel deployment/configuration connectors with vaulted credentials, agent access policies, approvals, audit, and bounded provider operations.

Deliver reviewed REST actions to native agents and guard Vercel preview intent on empty projects. Preserve secret-safe request identity and durable retry behavior.

Verified by current-head CI, fresh Greptile 5/5 review, and real-agent deployment/configuration walkthroughs on disposable provider resources. Test resources and temporary provider tokens were removed after verification.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-23 11:37:29 -07:00
DottaandPaperclip 3f1ad6b25b fix(chat): resume task Retry after retained-source containment (#17317)
## Thinking Path

> - Paperclip manages agent work through task and execution ownership.
> - A task Retry must retain the user's request while the system
verifies an old executor.
> - Connected conversations also retain their external principal and
accepted source batch.
> - Chat Retry admission required containment before it could save a
wait for that recovery.
> - A saved chat receipt could also remain deferred after containment
became available.
> - This pull request lets the exact recovery-bound request wait and
resume through its chat owner.
> - Normal admission still checks containment, current access and policy
before one successor starts.

## Linked Issues or Issue Description

**What happened?**

An ordinary task Retry on a connected conversation failed with
`failed_chat_retry_not_authorized` while its retained remote executor
still needed verification. The new recovery generation existed, but the
chat action failed before it could save a dispatch wait. This occurred
after the repairs in #17267 were confirmed live.

The local regression found a second gap. A processed chat action with a
deferred wake was not reconsidered after containment. Re-entering normal
admission also tried to insert its existing durable receipt again. A
historical hold for the same failed run could also hide the current
Retry's workspace strategy, so the request still waited after the old
executor was contained. Preparation could then read that sibling instead
of the recovery record that owned the fresh successor, losing the
fresh-workspace decision.

**Expected behavior**

Save the exact authorized Retry while its matching recovery generation
verifies the executor. Once containment is recorded, reconsider the same
chat receipt through normal admission. Start one successor with the
original source batch. Keep publication, principal, pause and budget
checks.

**Steps to reproduce**

1. Admit a GitHub or Telegram request and record a failed native run
with a retained remote lease.
2. Leave the executor's termination unconfirmed and exhaust its prior
recovery generation.
3. Use ordinary task Retry to create a new recovery generation.
4. Process the connected Retry. The old admission code fails instead of
retaining a wait.
5. With a deferred receipt, record exact containment and reconcile
again. The old dispatch path leaves it stranded.

**Paperclip version or commit**

Reproduced from `412914cfa78d5abefcc34d3eb8d4bb86e461caac`. The branch
is rebased onto current master.

**Deployment mode**

Hosted tenant for the reported failure. Isolated local PostgreSQL and
the assembled heartbeat/chat services for the regression.

Refs #17267 and #16965. This change does not add a Cloud dependency or
change the absence protocol.

## What Changed

- Permit a saved admission wait only for the exact current task Retry
and active source recovery generation.
- Keep promotion and execution dependent on independent containment
proof.
- Bind a Retry to active automatic recovery without replacing its
generation, attempt count or deadline.
- Share the current exact Retry strategy across historical holds for the
same run. Retain each hold's stop and effect checks.
- Select the canonical recovery record that proves the committed fresh
successor during workspace preparation.
- Let task receipt reconciliation return the same deferred action to its
chat owner.
- Recheck current board and external authority, then update the existing
wake atomically with its successor.
- Preserve the exact chat source batch. Keep generic board-comment
filtering unchanged.
- Add GitHub and Telegram cases for waiting, containment, one successor,
stale generations, source edits, endpoint pause and supersession.
- Update recovery documentation and capability maps.

## Verification

- Red: real PostgreSQL tests reproduced the admission rejection for
GitHub and Telegram. Six active-recovery cases then failed on the
generation-ID assumption. Two same-run historical-hold cases remained
deferred after containment on the old strategy lookup. A preparation
regression then returned no readiness when the historical hold was
stored first.
- Green: 73 selected chat integration tests and 394 continuation, task
Retry, workspace recovery, recovery-state and workspace-preparation
tests passed. The chat tests use the real chat admission and heartbeat
queue. Unrelated capacity stays occupied so no real provider starts.
They assert no executor before containment, one successor afterward,
unchanged source leases while waiting, preserved recovery budgets, and
denial after authority changes. A separate source hold still blocks
work. Both sibling insertion orders pass through the committed-readiness
lookup and real workspace preparation: the new directory has independent
Git storage and files, and unpublished old work remains intact.
- `pnpm -r typecheck`, `node scripts/check-maps.mjs` and `git diff
--check` passed after the review fixes. The source build passed on
`f6660efa48e37a80cd9857217a537606de85b5c8`.
- The local host reached its PostgreSQL semaphore limit. Successful runs
used a test-only loader to reduce disposable cluster connection and
worker limits. No repository database helper or application setting
changed.
- The full local `pnpm test:run` began before the final review edits,
failed in its first server phase and was stopped after those failures.
Later phases did not run. This is not a full local pass. The transient
Retry-notice case passes after fixture isolation; the four Discord
close-owned publication cases also pass in isolation. Other broad-run
failure causes are not established.
- Exact-head CI and security checks pass on
`f6660efa48e37a80cd9857217a537606de85b5c8`; Greptile is 5/5 with zero
unresolved review threads. Optional Paperclip Review completed neutral
with a 5/5 static assessment of all 11 changed files and no findings; it
did not run tests or hosted acceptance. All 57 current-head checks are
terminal: 54 success, two skipped and the optional neutral review, with
no failures or pending checks.
- The real hosted workflow confirmed that the deployed absence repair
recorded containment. A later ordinary UI Retry was accepted and saved a
durable request, but it remains behind the historical source hold. The
useful existing review remains unchanged. This follow-up is not
deployed; a live successful successor and final task disposition remain
unverified. No missing files are claimed recovered.

## Risks

- The existing task reconciliation sweep can restage a deferred chat
action. This reuses its receipt and generation; it does not grant new
execution or publication authority.
- Dispatch must keep the board Retry identity separate from the
connected request's principal. The regression checks these bindings and
preserves current chat authorization at each phase.
- Historical holds reuse a strategy only from the locked same-run
recovery that names the current Retry intent. A different run, malformed
recovery record or independent source hold remains fenced.
- Unknown executors without a matching active recovery still fail
admission. Promotion and execution require containment even when
admission saved a wait.
- No schema or API shape changes. No credential changes, manual
deployment or service restart.

## Model Used

OpenAI GPT-6 through Codex, with repository tools, code execution and
browser verification. The exact served model variant and context window
are not exposed in this session.

## 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
- [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>
2026-10-23 07:51:34 -07:00
DottaandPaperclip 4c57da3708 fix(recovery): continue Retry after verified sandbox absence (#17267)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Task Retry must reconcile a stopped native execution before starting
another one.
> - A retained sandbox can disappear while workspace preservation is
pending.
> - A tenant-key error does not prove absence, especially after
credential rotation.
> - This pull request accepts only a short-lived Cloud observation bound
to the exact source and current preservation owner.
> - Normal Retry admission can then continue in a fresh workspace
without claiming that missing files were recovered.

## Linked Issues or Issue Description

**What happened?**

A native run stops with workspace preservation pending. Its Daytona
allocation no longer exists. Recovery tries to reopen it, then cannot
confirm a stop. The ordinary Retry remains deferred behind cleanup and
repeats a transient failure.

**Expected behavior**

Cloud must independently confirm absence in the recorded provider
organization. Core must verify that proof and settle executor
containment under the current physical owner. Normal Retry admission
must enforce all existing gates and create at most one successor. The
old run must remain failed and missing files must remain unavailable.

**Steps to reproduce**

1. Persist a failed native run with a retained Daytona lease and an
exhausted workspace-recovery generation.
2. Remove the exact provider allocation so reopen and stop cannot
confirm it.
3. Request ordinary task Retry.
4. Observe that recovery reports `provider_unavailable` and leaves the
Retry deferred.

**Paperclip version/commit**

Reproduced on source based on `6d44b80a5edbcc9f69bfc3d520994e70aa9fab6d`
with the prior preservation and Retry repairs present.

**Deployment mode**

Cloud tenant with native Runner and a retained Daytona source. The local
acceptance uses real Core, Cloud, PostgreSQL, signatures, native Runner
and UI, with deterministic model and provider HTTP boundaries.

Refs #16962, #16965, #17053. These repairs cover completion proposals,
durable Retry and retained-source reopening. They do not establish
absence of a missing provider allocation. Related #16809 preserves
orphan sandbox leases; this change requires independent proof before
settling an absent allocation.

## What Changed

- Add an HTTPS client for a purpose-separated, host-bound Cloud
sandbox-absence capability.
- Verify signature, audience, stack, expiry, source identities and
current physical-owner token.
- Settle only executor absence with a metadata and owner
compare-and-set. Preserve source protection and record that workspace
contents are unavailable.
- Leave successor creation, approval, pause, budget and uncertain-effect
checks to normal Retry admission.
- Document the protocol and update the recovery maps.

## Verification

- Red: the new persisted-state regression returned
`provider_unavailable` and scheduled recovery on the unfixed code.
Expected: `source_unavailable` with a contained old execution.
- Green: 384 focused tests pass across workspace recovery, signed
absence, explicit continuation, ordinary Retry, workspace preparation
and provider-owned fresh workspaces.
- Signature tests reject forged, expired and mismatched proofs. HTTP
failures or missing configuration grant no authority.
- Two missing allocations are both reconciled before Retry. A simulated
interruption reuses the first durable absence receipt.
- Concurrent Retry admission produces one queued fresh successor. It
records no successful old result and no recovered-file claim.
- Browser acceptance at this change: one ordinary Retry, two provider
absence reads for two retained sources, one fresh native execution,
useful confirmation and Done after reload. The old run remains failed.
Existing saved review and newer local file bytes remain unchanged. The
deterministic model does not perform external publication; this is local
protocol acceptance, not live provider recovery.
- `pnpm typecheck`, `pnpm build`, and `node scripts/check-maps.mjs`
pass.
- A complete local `pnpm test:run` pass was not obtained. The first run
hit a 15-second timeout in an unchanged status-card test. It was stopped
to apply review fixes before the remaining phases ran. The unchanged
status-card suite then passed 25/25 in isolation with the repository
short temporary-path convention.
- CI exposed a chat nonduplication assertion that compared unordered
database rows. The assertion now sorts both complete row sets by run ID.
Its focused test passes.
- All 58 current-head checks are terminal on
`1e2e881f6b6b1ae1fbfe1f2b2922657ce46e1470`: 55 success, two unaffected
Storybook skips, and one neutral advisory review. Required CI, build,
E2E and security checks pass. Greptile is 5/5 with no unresolved
threads. The optional Paperclip review is neutral advisory 5/5 with
nine-file source coverage and no findings; it did not independently run
tests.
- One unchanged native-runtime test timed out at five seconds on its
first CI attempt. Its suite passed 33/33 in isolation; a single retry of
that lane passed without code changes.

## Risks

- The companion Cloud endpoint must ship before this consumer. Older or
unavailable Cloud versions return no proof and retain the current hold.
- A valid absence receipt permits a fresh workspace attempt. It cannot
restore missing remote files, establish task success or authorize
repeating an uncertain external effect.
- This PR has not been deployed. The original task remains unrecovered
pending rollout and reconciliation of its existing Retry.
- No schema, credential, provider-resource or fleet changes are
included.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, source inspection, code
execution and browser tools. The exact backend variant and
context-window size are not exposed by this session.

## 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 (focused scope above; full
local run limitation recorded)
- [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>
2026-10-22 22:31:52 -05:00
Devin FoleyandPaperclip 35bd7f6059 Reduce encrypted event retries and GitHub run-query transfer (#17251)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Its Cloud connector delivers encrypted GitHub events to an instance.
> - One failed inner event currently rejects the whole authenticated
batch.
> - Healthy events then remain unacknowledged and are downloaded again.
> - GitHub response and check reconciliation also reads full run records
when it needs only ownership and status.
> - This pull request isolates inner failures and narrows those run
projections.
> - Valid events can finish while failed events remain available for
recovery.

## Linked Issues or Issue Description

**What happened?**

An inner App event encrypted with an unavailable key causes
`leaseEvents` to reject the complete batch. No sibling can finish or
acknowledge. Repeated retries download the same encrypted payloads.
Separately, GitHub response and check reads load prompts, runtime
profiles, results, and log excerpts that their callers do not use.

**Expected behavior**

Authenticate the outer batch and lease before handling individual
events. Process valid siblings independently. Retain failed events
without acknowledging them. Read only the current run fields needed for
response ownership and status checks.

**Steps to reproduce**

1. Seal one event for an old instance key and another for the current
key.
2. Put both events in a correctly authenticated outer lease.
3. Observe that the old client rejects the whole lease.
4. With this change, the valid event processes, the failed ID is
reported locally, and only completed events acknowledge.

No public issue exists. The change does not add a provider integration
or duplicate a roadmap feature.

## What Changed

- Keep outer authentication, environment checks, and lease binding
strict.
- Isolate inner decryption and route-binding failures. Return their
authenticated IDs only to the local poller and count them as failures.
- Leave failed events unacknowledged in the broker. Continue processing
and acknowledging healthy and duplicate siblings.
- Read only run identity, status, and required request context for
GitHub responses. Read only run ID and status for check reconciliation.
- Cover stale keys, swapped routes, invalid outer bindings, all-failed
batches, large unused run payloads, and cross-company/task refusals.

## Verification

- Connector cryptography suite: 47 tests passed.
- Final connector suite: 50 tests passed, including cryptography and
three real PostgreSQL connection-event tests. These cover acknowledgment
isolation, all-failed batches, and the exact safe warning fields.
- GitHub workflow regression suite after the master refresh: 307 tests
passed, including the large-payload/company/task test (1,084 unrelated
tests skipped by the selection).
- Server typecheck passed after the final source changes.
- `pnpm -r typecheck` and `pnpm build` passed after the latest
conflict-free master refresh.
- The broad local `pnpm test:run` was stopped when the branch was
refreshed; it has no complete passing result. All CI gates passed on the
final commit, including general and serialized server suites, runner
verification, build, typecheck, and end-to-end tests. Apex is 5/5 with
all review comments resolved. The last change removes source comments
and expands docs; both edited TypeScript files emit identical JavaScript
before and after that change.
- A read-only sample compared full run records with the new field sets:
response data decreased by about 96%, and check data by over 99%. This
is serialized query output, not a claim of realized billing savings or
CPU reduction.
- An initial database test setup failed because the local dependency
install omitted native-library symlinks. The package's standard setup
script repaired them. The unchanged test timeout then passed.
- Added lines checked for credentials, customer data, private links, and
internal issue references.

## Risks

Failed inner events remain pending and retry under the broker's existing
lease and retention policy. This change does not recover a lost original
private key or introduce a dead-letter deletion path. Outer
authentication failures still reject the complete batch.

Run projections must retain request provenance and task binding fields.
Existing predicates, ordering, identity validation, and publication
authority remain unchanged. The change has no schema migration and adds
no background timer or new provider call.

## Model Used

OpenAI GPT-6 through Codex, with reasoning and shell/GitHub CLI tools.

## 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
- [x] I have described the issue in-PR following the bug report template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
ticket ID
- [x] Focused local regressions and all CI gates pass
- [x] I have added and updated tests
- [x] I have updated relevant documentation
- [x] I have documented risks
- [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>
2026-10-22 17:40:29 -07:00
f3af9887ca fix(chat): keep each chat conversation in its own wake batch (#17054)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat channels let a linked user talk to an agent from Slack, GitHub
and other platforms. Each external thread is a chat conversation that is
bound to one issue.
> - One issue can have many conversations. A GitHub pull request review
makes one conversation for each inline finding thread.
> - When replies arrive behind an active run, the wake queue merges them
into one deferred wake. The merge did not look at the conversation.
> - A reviewed chat run can attest only one conversation. A merged batch
from two threads always failed attestation with `setup_failed` /
`reviewed_chat_execution_binding_not_authorized`, so no reply got an
answer.
> - This pull request keeps each chat conversation in its own wake
batch. The single-conversation attestation check stays the same.
> - The benefit is that replies in different review threads each get
their own attested run, one after the other.

## Linked Issues or Issue Description

Refs #16793 (related: chat origin during coalescing). No public issue
exists, so the bug report follows.

**What happened?**
A linked user replied in three different inline review-finding threads
of one pull request while the agent's review run was still active. The
three wakes merged into one deferred wake. The promoted run failed in
about 2 seconds with `setup_failed` /
`reviewed_chat_execution_binding_not_authorized` and
`providerWorkStarted=false`. None of the three replies got an answer.
The failed-chat retry cannot recover this batch, because a retry source
holds one conversation.

**Steps to reproduce**
1. Bind two chat conversations (two GitHub finding threads) to one
`in_review` issue.
2. Start a run for the assigned agent on that issue.
3. As the linked user, reply once in each thread.
4. Finish the active run.
5. See one promoted run that fails with
`reviewed_chat_execution_binding_not_authorized`.

**Expected behavior**
Each thread gets its own run. Each run attests its one conversation and
answers its reply.

**Cause**
`findExistingDeferredWake` matched on company, agent, issue and actor
only. The active-run coalesce path had the same gap.
`authorizeChatConversationForBoundRun` correctly denies a batch with
more than one conversation.

## What Changed

- `run-dispatch/domain/wake-context.ts`: add the `chatConversationId`
wake-context key, a reader, and `wakeChatConversationsConflict`. A
conflict means that both wakes have a conversation and the two
conversations are different.
- `issue-assignment-wakeup.ts` and `chat-channels/inbound/wakeups.ts`:
stamp the conversation ID on each inbound chat wake.
- `chat-channels/failed-run-retry.ts`: stamp the conversation ID on
failed-chat retry wakes, so later replies do not merge into a retry from
another conversation.
- `wake-queue` admission: do not coalesce into an active run of another
conversation. The deferred-wake lookup now matches only wakes of the
same conversation or wakes without a conversation.
- `heartbeat/queue.ts`: the same-scope queued or running coalesce target
is skipped when the conversations conflict.
- `doc/execution-semantics.md`: describe per-conversation chat wake
batching.
- Tests: an integration regression in the GitHub review block of
`chat-channels.integration.test.ts`, and unit cases for the active-run
branch in `wake-queue/application/use-cases.test.ts`.

## Verification

- Red before the fix: `pnpm --dir server exec vitest run
src/__tests__/chat-channels.integration.test.ts -t "replies in review
finding threads"`. The main case fails with one run: `{ status:
"failed", errorCode: "setup_failed", error:
"reviewed_chat_execution_binding_not_authorized" }`.
- Green after the fix, same command, 3 of 3 pass:
- Replies in two finding threads give two successive runs. Each run
succeeds, has `paperclipExternalChatExecutionBound: true`, and holds
only its own comment and conversation.
- Two replies in the same thread still give one run with both comments.
- After the linked identity is revoked, each separated run is still
denied (`setup_failed`) and the adapter does not execute.
- `vitest run src/modules/wake-queue src/modules/run-dispatch`: all
pass, with the new cases (different conversation, same conversation, run
without a conversation, non-chat wake).
- Related suites pass: `heartbeat-comment-wake-batching`,
`durable-chat-wakeup`, `chat-failed-run-retry-boundary`,
`issue-queued-comments-routes`, `heartbeat-stale-queue-invalidation`.
- Full `chat-channels.integration.test.ts`: 823 passed, 1 timed out. The
timed-out test (`GitHub terminal receipt composes pinned HTTP and
durable source authority (held_token)`) passes alone with and without
this change. The sandbox has a 4 GB memory cap.
- Not run locally: `pnpm -r typecheck` and `pnpm build`. The server
`tsc` process was killed at the 4 GB sandbox memory cap. CI runs both.
- Runtime dependency note: the deferred-wake lookup adds one JSONB
predicate to the existing deferred-wake query. It reads the same rows.
The query count does not change. The integration regression runs it
against embedded Postgres.

## Risks

- Low risk. No schema change and no migration.
- Behavior change: chat replies from different conversations on one
issue now run one after the other, not in one batch. Before this change,
such a batch always failed, so no working flow becomes slower.
- Wakes without a conversation (non-chat wakes, and wakes queued before
this deploy) keep the old coalescing. A deferred wake from before the
deploy has no conversation key, so one later reply can still merge into
it. That window closes when the queue drains.
- The check keeps the single-conversation attestation in
`authorizeChatConversationForBoundRun`. Revoked identities are still
denied.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), in Claude Code through
the Paperclip agent harness. It used tool use (shell, file editing, test
runs) and extended reasoning.

## 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
- [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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 22:47:24 -07:00
DottaandPaperclip c2daf906d9 fix: preserve task continuation and question delivery (#17045)
## Thinking Path

> - Paperclip manages agent work and delivers its results.
> - One task can need several runs and a saved workspace.
> - A run can succeed while the task waits for its next run.
> - Chat fallback treated that success as completion and dropped useful
status.
> - Monitor runs also lost their conversation origin, and text-question
cards lost their prompt.
> - This change preserves the task outcome and exact delivery authority
across those boundaries.

## Linked Issues or Issue Description

**What happened?**

A Slack task requested a repository, yielded to a scheduled
continuation, and showed only a generic completion message. The next run
could not publish through the original conversation. A later text
question showed its title and Respond button without the question
context. Workspace recovery could commit the saved monitor result
without restoring its explanation.

**Expected behavior**

The original conversation shows the accepted continuation explanation,
receives the resumed result, and displays the full question when input
is needed. A successful provider run does not claim that unfinished work
is complete. Recovery delivers saved output once without another
provider result.

**Steps to reproduce**

Start an authorized chat task, prepare a repository for a later
admission, save a monitor wait, and let that monitor resume the task.
Repeat with workspace finalization interrupted and with a free-text
question. Inspect the originating conversation and the persisted output.

Related merged work: #16806 and #16975. The open monitor and recovery
changes found during duplicate search address different status and
liveness policies.

## What Changed

- Keep committed monitor summaries visible through the shared board and
chat response resolver. Preserve interaction ownership and comment
reuse.
- Recover a saved monitor explanation after finalization, with no
repeated provider result.
- Prove monitor publication origin from the admitted wake and matching
scheduling receipt. Match company, task, agent, requester, and schedule;
reject ambiguous sources.
- Include monitor continuations in the existing publication scan and use
the canonical task binding. Keep current transport authorization.
- Suppress completion fallback for yielded results. Explain missing
final output without claiming completion.
- Include question summaries, prompts, and help text in modal-backed
cards. Keep answered text private.
- Update execution semantics, capability maps, and the bounded
reliability plan.

## Verification

- Original source fails four composed PostgreSQL regressions: monitor
origin, yielded completion, question body, and saved-summary recovery.
The shared response resolver also fails before the repair.
- Repaired focused cohort: 148 tests pass across publication, question
privacy, scheduler, and native monitor suites. These use real disposable
PostgreSQL; they do not qualify live Slack.
- Full workspace typecheck and production build pass locally. Map checks
and whitespace checks pass.
- All CI gates pass at 1701c48f17.
Greptile reports 5/5. Both review findings are resolved. The local
full-suite run remains separate.
- The added 21-admission lineage and cycle regressions pass with the
complete 11-test database suite.
- The larger live Codex/Claude qualification and deployed staging
acceptance remain in progress. This PR does not claim that milestone is
complete.

## Risks

- Incorrect lineage could disclose output to another conversation. The
resolver requires one exact receipt-backed source and the worker still
checks current delivery authority.
- Status recovery could duplicate output or compete with a question. The
source-run presentation marker, saved-comment reuse, interaction
arbitration, and replay tests protect those boundaries.
- No database migration or public task-status change is required.

## Model Used

OpenAI Codex, GPT-6 family, with repository editing, terminal tests, and
browser inspection. The runtime does not expose an exact deployment
model ID or context-window size.

## 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
- [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>
2026-10-20 20:43:17 -05:00
DottaandPaperclip d33b40a5c3 fix: recover saved work and provide reliable task Retry (#16965)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The control plane must retain work when an execution or workspace
export fails.
> - Retained-workspace holds can leave saved input waiting with no
usable Retry action.
> - Users cannot verify process ownership or repair provider
allocations.
> - This pull request gives system recovery a durable budget and gives
each deliberate Retry a durable intent.
> - Safe recovery can preserve files, settle an accepted result, or
prepare an independent workspace.
> - One task state keeps infrastructure diagnostics out of the ordinary
conversation while preserving real permission and approval gates.

## Linked Issues or Issue Description

**What happened?**

A task with a retained workspace can show recovery, failed-run and
saved-message warnings at the same time. Historical runs without native
workspace descriptors cannot use the native restore path. Old recovery
metadata can prevent a new attempt even when an independent workspace
would be safe.

**Expected behavior**

Paperclip owns bounded infrastructure retries and file preservation. A
user can request another attempt with ordinary Retry. Thinking appears
immediately. The service preserves completed effects and current user
controls. It does not claim that starting fresh recovered the old files.

**Steps to reproduce**

1. Retain a failed run and its workspace after export or process-stop
failure.
2. Save a follow-up while the recovery hold is active.
3. Open the task and try to continue without infrastructure credentials
or operator certification.

Refs #16906, #16835, #16883. This extends their recovery and receipt
contracts. Related work: #16962 and #16963.

## What Changed

- Add task-level Retry with company-scoped authorization, all-status
idempotency and durable admission before physical work. Keep exact-run
Retry compatible.
- Add typed recovery phases, finite persisted backoff, historical
adoption and durable local failure diagnostics.
- Preserve native workspaces or verified historical snapshots. Admit an
independent fresh workspace only after execution containment. Keep
old-source preservation and cleanup obligations separate.
- Carry completed publication and API receipts forward. Fence uncertain
mutation retries across replacement runs. Preserve connected-chat
identity and authorization.
- Re-enter normal dispatch for saved input. Reuse accepted results
through the existing finalizer.
- Use one task interruption projection across the thread, composer and
task list. Show optimistic Thinking, ordinary Retry and genuine user
gates.
- Add PostgreSQL, filesystem, API, browser-fixture and controlled
provider coverage. Document the behavior and update the feature/access
maps.

## Verification

- All GitHub Actions CI jobs pass on
`6d8c6d27d50586d8548b31d03b47f6d73a0ee11d`: typecheck, all
server/chat/workspace and serialized suites, Runner checks, eight
browser shards, canary and build. The required merge gate passes.
- Greptile reviewed the final commit at 5/5, with no actionable findings
or unresolved review threads. Its two earlier P1 findings are fixed.
- Full recursive typecheck and build pass locally on the final commit.
All 16 task Retry cases pass against isolated real PostgreSQL. The
unrelated-success case and both stale Retry cases fail on the previous
code and pass after the fix.
- The corrected gateway fixture passes its uncertain-mutation and
independent-read case. Four real HTTP API cases pass for definite
403/422 rejection, completed-effect reuse, and uncertain-effect fences
across deliberate and automatic retries. These focused gateway/API
checks used a temporary database lifecycle harness on an existing
healthy local PostgreSQL process. The standard repository helper is
unchanged.
- Earlier qualification covers 291 task UI cases, saved-file copyback
and ancestry, current Agent Chat ownership races, nine chat Retry API
browser cases, and six assembled browser recovery fixtures. A real
API/PostgreSQL/native-runner journey showed Thinking in 25 ms despite a
delayed response, admitted one successor in a separate workspace,
retained original files, and survived reload.
- The controlled Daytona test interrupts export, joins the controller,
restarts it in a separate process, and verifies one agent start, one
external sentinel operation, retained file contents and no premature
cleanup. It does not establish abrupt-kill or live LLM/GitHub
acceptance.
- The full local `pnpm test:run` was attempted and was not green: an
OAuth row-lock timing assertion failed, and a later suite exhausted
macOS PostgreSQL semaphores. The ten OAuth timing cases passed on rerun
against a separate database. Later embedded database initialization
failures remain recorded; the final CI matrix passes.
- Security scanning passed on production-code commit
`63953edf069b111c6becc3144dffa6deb52f68b5`. Its only successor changes
one test-fixture identity line. The final scan is neutral/inconclusive
because its pinned merge-base checkout failed or timed out. Both rerun
API requests returned 404, so no fresh successful scan is claimed.
Socket and Snyk checks pass on the final head.
- The optional Paperclip Review remains queued behind an earlier run in
workspace finalization. Its prior completed assessment was incomplete
because a comparison tool was blocked by the platform filter. It is not
counted as a completed code review. GitHub does not require this check
for merge.
- Hosted acceptance remains pending deployment. Local and CI results do
not establish recovery of a hosted task or its retained files.

## Risks

- Recovery changes span admission, physical ownership and dispatch.
Incorrect evidence could permit overlapping work. Existing physical
locks and authoritative stop requirements remain in place.
- The migration adds concurrent indexes. It requires the existing
top-level migration runner and retries incomplete index creation safely.
- A fresh attempt can complete while old-source preservation remains
unresolved. The service retains that obligation and does not report
those files as recovered.
- Unknown tool mutations remain blocked until their authoritative
receipt owner resolves them. Generic upstream tools have no universal
result-query protocol.
- Recovery and diagnostics stay inside the stack. No Cloud incident
endpoint, notification worker or new outbound reporting channel is
included.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose a more specific
model version or context-window size. The model used reasoning, shell
execution, source editing and browser tools. No model subagents were
used for this implementation.

## 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 suites; the full
local run limitation is documented above)
- [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>
2026-10-20 19:58:53 -05:00
Devin FoleyandPaperclip a2d26a83fe fix(inbox): keep automatic work out of Mine by default
Keep channel and routine attribution out of Mine unless the person participates directly, is assigned the task, or receives a current addressed request. Apply the same source rules to unread state, archives, and task notifications. Preserve direct comments and current human action requests.

Restore the two expressions damaged by redaction during the earlier master merge.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 13:46:10 -05:00
DottaandPaperclip 2c96f76780 feat(connections): add model-backed prompt injection prevention
Add opt-in OpenRouter checks at existing tool-result boundaries with regex fallback, service accounting, and settings on Connections. Make migration 0362 safe to replay over existing or partially applied schema state.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 11:32:25 -05:00
DottaandPaperclip 4b05795712 fix(github): reuse review instructions across native turns (#16971)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub events continue an ordinary task and can reuse its provider
conversation.
> - Each automatic event appended the full review policy and PR
description.
> - Native GitHub follow-ups also repeated task history because only
Slack used the compact path.
> - This pull request separates admitted review configuration from
commit updates.
> - A verified resume sends the current messages and changed
configuration. A fresh session gets full context.
> - This reduces repeated input while retaining review rules and current
tool checks.

## Linked Issues or Issue Description

Refs #13959, #16645, #16901.

**What happened?**

Opening a PR and pushing twice stored three full review prompts. A later
native turn repeated all three in a retained provider conversation.

**Expected behavior**

A new event supplies its commit and event data. The harness delivers
stable review instructions once per retained conversation and
configuration. Fresh sessions receive full instructions.

**Steps to reproduce**

1. Enable automatic GitHub reviews for a repository.
2. Open a PR, let the review finish, and push two new commits.
3. Inspect task messages and the native submitted envelopes. Before this
fix, the policy and old requests repeat.

## What Changed

- Store compact automatic event messages. Fetch the PR description
through the existing metadata tool when needed.
- Load review instructions from processed deliveries bound to the
company, task, agent, and source comments. Preserve each admitted policy
snapshot.
- Use the existing verified native continuation path for complete GitHub
text batches. Deliver configuration changes using a key over endpoint,
PR conversation, revision, and instructions.
- Keep full bootstrap input for fresh sessions and failed resume,
including board follow-ups with no new GitHub event. Retain existing
framing for incomplete batches, attachments, interactions, and recovery.
- Keep the same configuration identity across automatic review,
discussion, and automatic review. Coalesced requests use the last
accepted request's admitted policy.
- Add regression and database coverage. Update the execution contract
and verification recipe.

## Verification

- Red: the new event-size regression failed because policy and PR body
repeated. The GitHub continuation regression failed because it returned
no compact prompt.
- Green: focused policy, continuation, native input, and adapter prompt
tests passed (231 tests). Native resume/fresh-bootstrap cases passed (9
tests).
- The signed-webhook/database case passed at `6296168253`. It checks
configuration edits, queued older snapshots, coalesced policy selection,
discussion continuity, board follow-ups, and company/task/agent/comment
boundaries. The private PostgreSQL template used 12 connections because
the host reached its semaphore limit with the default settings.
- The earlier broad channel/session integration run passed 1,432 tests.
Later review fixes invalidated that run. The latest focused database
case passed after those fixes.
- Reviewer regressions failed against the previous lookup, then passed
with the fix: a mixed-revision batch delivered multiple policies, and a
discussion lost the configuration identity. The board
wake-to-rendered-prompt regression also failed before repair.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` passed on the final source.
- Full local `pnpm test:run` exposed follow-up/fixture failures during
development. Those cases are fixed and pass separately. The stale run
was stopped after source edits. Full-suite validation for the final
commit passed in CI.
- All required CI checks passed for `6296168253`, including tests,
typechecks, build, and clean public npm install checks. The two
unrelated Storybook checks were skipped.
- A live two-turn Codex smoke could not start: the local macOS sandbox
helper rejected execution of the installed Codex 0.153.4 binary. No live
GitHub/provider acceptance or deployment is claimed.

## Risks

Skipping instructions is safe only after a verified checkpoint resume
with the correct previous run. The full bootstrap remains available if
resume fails. Changed or previously unknown configuration is sent again.
Tests cover these cases. Tool authorization and publication checks still
run under the current server policy. No database migration is required.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
deployment model identifier and context window are not exposed in this
session. No delegated agents were used.

## 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
- [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>
2026-10-20 10:39:17 -05:00
DottaandPaperclip 813e808af4 Remove filesystem history authorization from workspace preparation (#16963)
Remove physical-root source/reader authorization and sticky directory classifications from workspace preparation. Preserve current task/run authority, app-record privacy, credential authorization, containment, and lifecycle/publication integrity.

Validate replacement selections against persisted new inputs and refresh verified checkout ownership so bounded reuse survives earlier workspace relocation. Add real PostgreSQL/Git regressions, a reproducible history-scaling benchmark, and documentation.

Full CI passed all 48 jobs and Greptile scored 5/5 at 3d5da6c259. Five preparation-guard medians improved from 20,512.99 ms to 52.22 ms on the 8,500-workspace fixture; these are not end-to-end startup timings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 09:19:59 -05:00
DottaandPaperclip bc091f0a21 fix(recovery): recover retained workspaces before saved messages (#16906)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A stopped run can leave useful files in its original sandbox.
> - The server keeps that sandbox when it cannot confirm file copyback.
> - The task can then save new user input but offers no safe way to
recover the files.
> - A retry of the old agent turn can repeat work that already finished.
> - This pull request recovers files through the existing workspace
owner and delivers only saved human input.
> - The user can recover a task without certifying infrastructure facts
or losing completed work.

## Linked Issues or Issue Description

Refs #16883 and #16835 for publication receipts and verified process
termination.
Related: #16478 clears stale holds after copyback already succeeded.
This change performs the missing export and records its proof. #16901
manages the main GitHub response comment and does not perform workspace
repair.

**What happened?**

A failed run retained its workspace. A later user message stayed saved
behind a file-repair hold. The task asked the user to verify process
termination and file recovery but offered no repair control. Sending a
message could show an optimistic Working state and move the task to Todo
before admission succeeded.

**Expected behavior**

The harness should recover the original files when it can prove
ownership and termination. It should preserve newer edits and completed
operations. Only waiting user input may start another turn. Missing
evidence must keep the source held with a specific explanation.

**Steps to reproduce**

1. Interrupt a sandbox run before workspace finalization succeeds.
2. Retain its exact allocation and save a user follow-up.
3. Observe the file-repair hold and missing end-user repair path.

## What Changed

- Add source-bound background recovery for native and legacy runs. An
accepted native result is not required.
- Share the physical copyback lock and durable owner. Resume only the
exact stopped allocation, export files, verify persistence and obtain a
fresh stop receipt.
- Persist retry limits and idempotent requests on the existing recovery
record. Limit each server to two background exports. Add an indexed
candidate scan and a separate cleanup obligation.
- Add a task-editor recovery endpoint. Deny agents and viewers. Reject
caller-supplied stop or repair claims.
- Deliver waiting human input once through ordinary admission. Preserve
pause, approval, budget and assignment gates. Require historical
conversational-adapter evidence for legacy-to-Runner continuation.
- Include exact GitHub publication receipts in continuation context.
Preserve unknown effects and the original failed run.
- Show observed recovery progress, a transient-failure retry action and
specific service blockers. Keep saved messages visible. Suppress false
startup feedback and implicit Todo promotion behind a file hold. Hide
unavailable workspace links.
- Update execution semantics, capability maps and production-component
stories.

## Verification

- Red: the original read model failed the new recovery-progress
assertion; the other 23 checks in that file passed.
- Passed: recovery regressions with 28 cases with real PostgreSQL,
files, tar and Git operations. Lifecycle provider calls are controlled
test boundaries. Coverage includes native/legacy export, concurrent
owners, rollback after export, interrupted archive export with a new
database connection, lost replies, historical discovery, durable retry
limits, separate cleanup and saved-input delivery. The actual candidate
query uses its partial index with 3,000 unrelated history rows. A first
automatic repair can bind verified old-controller stop proof without an
accepted native result. Review also reproduced and fixed export-only
continuation and cleanup lost after a committed repair. Cleanup remains
discoverable without waiting input and after task reconciliation.
- Passed: two GitHub integration cases verify that continuation context
carries the existing publication receipt and does not write another
response. Company and task boundaries are checked.
- Passed: 293 continuation, workspace-sync, platform-receipt and OpenAPI
checks. After file repair, actual dispatch retains pause, cancellation,
approval, real budget-policy and assignment gates.
- Passed: 174 route checks, including editor admission, agent/viewer
denial and rejection of fabricated repair claims.
- Passed: 351 task detail, workspace properties and comment-reopen
checks after updating the new read boundaries and asynchronous
workspace-link expectations. Two new route cases keep held tasks Blocked
when a comment is saved.
- Passed: 265 task-thread and recovery-notice checks. The broader
continuation suite also passed; its new legacy migration case first
exposed a gap that the focused recovery suite now covers.
- Passed after rebase: `pnpm -r typecheck` and `pnpm build`. The later
master merge adds an unrelated permission migration; recovery migration
generation and safety checks passed after the merge.
- Passed: token gates, module boundaries, map structure and migration
checks. The recovery index is migration 0360 after current master.
- Browser: inspected the production recovery component and its
retry-to-queued transition with fixture data. The first dev dependency
load failed; a reload after optimization resolved it. This is UI
evidence, not a live provider recovery claim.
- Every test shard passed on final commit `bbbc09efb4`. The older local
`pnpm test:run` was stopped after the complete CI test matrix passed.
Local full typecheck and production build passed. The first CI build
compiled and booted, then lost its runner during the clean public
npm-install check. An isolated retry passed the build, production boot
and clean public npm-install verification.
- Greptile reviewed final commit `bbbc09efb4` at 5/5. All review threads
are resolved.
- The change is not deployed. Hosted recovery remains unverified until
the served revision includes this change.

## Risks

- Recovery crosses process, provider and persistence boundaries. Missing
or mismatched ownership, stop, descriptor or file evidence keeps the
hold. It never selects a replacement allocation or silently starts over.
- File recovery does not certify external action outcomes or authorize
replay. New input still uses normal execution admission.
- Historical sources without sufficient durable evidence can remain
blocked. Destructive reconstruction stays separate.
- The index migration is idempotent. It changes no task data. Snapshot
pruning follows repository policy.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, with code execution and browser tools.
`gpt-6-astra` assisted earlier investigation. The runtime does not
expose the context-window size.

## 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
- [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>
2026-10-19 21:51:46 -05:00
DottaandPaperclip 3b8324a233 fix(github): keep one main PR review comment and reconcile stopped work (#16901)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub connections send review requests to an assigned agent.
> - A PR needs one main comment that shows its current review state.
> - The response ledger used one comment per incoming request. Pushes
and follow-up messages created more placeholders.
> - Thread subscriptions also accepted requests addressed to external
bots. Recovery could leave an acknowledged request without a final
notice.
> - This pull request shares the main PR comment, filters other
recipients, and reconciles stopped work.

## Linked Issues or Issue Description

Related: #16874 showed the repeated placeholders. #15416 introduced the
per-request response path. The prior summary path used one PR-level
marker.

**What happened?**

Repeated pushes created new main PR comments. A subscribed `@greptile
review` message also woke the Paperclip bot. If execution stopped before
staging a milestone, its comment could keep claiming that work was
active.

**Expected behavior**

One bot keeps one main comment per PR. Progress and review results
update it. A message addressed to another recipient does not wake the
bot unless it also explicitly mentions this bot. Stopped work gets an
accurate notice.

**Steps to reproduce**

1. Accept two review requests in one PR conversation.
2. Add `@greptile review` to that subscribed conversation.
3. Fail the assigned run before it stages a milestone. Run channel
maintenance.

## What Changed

- Add a durable main PR response target. Keep per-request receipts and
the existing publication lease.
- Recover the target from App-owned provider markers. Adopt older
placeholders and point verified duplicates to the current review.
- Use a queued notice before a PR run starts. Preserve version ordering
and final responses.
- Filter leading mentions addressed to another recipient. Explicit
mentions of this bot take precedence. Incidental mentions keep normal
thread behavior.
- Reconcile acknowledged requests after terminal execution. Show paused
state for saved requests on a blocked task. Preserve newer work and
confirmed or uncertain tool delivery.
- Keep a request open when its stale acknowledgement is suppressed.
Close placeholders after replies published elsewhere. Retire old
coalesced placeholders before replacing their receipts. Resolve native
request identity when legacy wake fields are absent.
- Update guidance, connection documentation, and feature/access maps.

## Verification

- Red: all three behavioral regressions failed on the original code. A
second review created a second comment; an external-bot request was
processed; stopped execution retained its working placeholder.
- Green: the same three cases passed after the fixes.
- Review regressions also failed before their repairs: a delayed
acknowledgement closed a new request; normal and stored formal-review
receipts left a live placeholder; coalesced completion lost a duplicate
receipt; native terminal work without legacy wake fields stayed queued.
All 13 combined regression and safety cases passed after repair.
- The same legacy receipt-loss bug was also reproduced in the
superseded-acknowledgement branch. Its four affected cases passed after
adding retirement before that receipt replacement.
- A further review regression reproduced paused requests rejecting
resumed progress and skipping stopped-run cleanup. Four cases failed
before repair; all eight resume and neighboring safety cases passed
afterward. Both paused-notice branches keep the request open.
- Repeated paused maintenance reproduced two needless GitHub edits. The
writer now skips an identical complete comment body. Nine affected cases
passed, covering repeated maintenance, resumption, stopped work, final
assessment preservation, and main-comment reuse.
- Safety cases cover lost receipts, legacy adoption, newer progress,
published assessments, provider-verified mention aliases, and old
replies that must not complete new requests.
- `pnpm -r typecheck`, `pnpm build`, map validation, and module
boundaries passed. The server TypeScript check passed after the final
repair. The broader local GitHub workflow and policy run passed 188
tests. Full CI passed on the final commit
(`554979d79285b68bcbf90cd639e3d2d053f4ea4b`), including all three chat
shards, server/workspace/Runner suites, typecheck, build, and E2E gates.
Greptile is 5/5 with no open review findings. One serialized job
received a runner shutdown signal mid-test; its single retry passed.
- Preserved failure evidence: the first CI run exposed an overbroad
recipient filter and an old queued-text assertion. The next commit
passed all three CI chat shards. Greptile then found the receipt
transitions covered by the new regressions above. Local full-suite runs
were stopped when those defects required source changes; no clean full
local pass is claimed.
- Tests use real PostgreSQL and controlled provider responses. They do
not establish a live GitHub App rollout. The original instance needs the
fixed server before its comments change.

## Risks

- Leading mentions now select a recipient even when that account has no
Paperclip connection. A leading human mention also selects that person.
Mid-message incidental mentions retain normal subscription behavior.
- Existing comment adoption edits only comments proven by this
endpoint's request ledger or prior summary marker and App identity.
Deleted and replaced comments remain protected.
- Failure cleanup uses current authority and does not replace newer
progress or unresolved provider writes. It does not restart failed
execution.
- No schema migration is required.

## Model Used

OpenAI Codex, GPT-6. The exact serving model ID and context-window size
are not exposed in this session. The model used reasoning, tools, code
execution, and browser inspection.

## 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
- [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>
2026-10-19 21:51:20 -05:00
DottaandPaperclip 9e8a9f28d5 fix(github): recover long publications from durable receipts (#16883)
## 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>
2026-10-19 13:54:42 -05:00
DottaandPaperclip 2cbca4ceb0 fix: retain channel tools across task continuations (#16806)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat channels give an agent tools for its assigned task.
> - Each later run must resolve the task and its accepted requester
again.
> - Some native runs store the task in a database column without the
older JSON fields.
> - Tool discovery read only the JSON fields. GitHub calls also required
a new inbound comment.
> - This pull request uses the durable task binding and accepted request
history.
> - Later runs retain their channel tools while current access checks
still apply.

## Linked Issues or Issue Description

**What happened?**

A GitHub task can find `begin_review` on its first run, then receive an
empty tool list on a later native run. If discovery is repaired alone, a
call can still fail because the later run has no new inbound comment.
Slack and voice tool access also read the older JSON task fields.

**Expected behavior**

A later run for the same task can find and call its assigned channel
tools. The current requester, task, company, agent, endpoint, and access
rules must still allow the call. Revoked access must fail.

**Steps to reproduce**

1. Start a GitHub task and accept its linked requester.
2. Confirm that the runtime can find `begin_review`.
3. Start a later native run with `nativeIssueId`, accepted parent
identity, and no JSON task ID or new wake comment.
4. Search for `begin_review` again. Before this change, the search
returns an empty list.
5. Repair discovery alone and call `read_pull_request`. Before the
request-history fix, the call fails with no active conversation
capability.

**Paperclip version or commit**

Reproduced in source tests before this patch. The branch includes master
at `fa50cab5685b9cdbb26ad9c610cc5b6c373d3ff4`.

**Additional context**

This is a core run-binding bug. The tests use PostgreSQL and synthetic
provider responses. They do not send live reviews, Slack messages, or
phone calls.

## What Changed

- Resolve run task IDs from durable columns, with legacy JSON fields as
a fallback.
- Use the same binding in the gateway, access policy, identity service,
and channel runtime preparation.
- Recover accepted channel request history across later runs. Keep
company, task, agent, and requester boundaries.
- Recover older wake sources through verified parent runs, including
after same-user board follow-ups. Clear the board message’s own legacy
wake fallback. Keep cycle checks without a fixed limit on valid task
history.
- Retain the GitHub origin after a board comment from the same accepted
user. Skip GitHub origin lookup results from other providers.
- Keep ordinary board tools available when the requester changes. Accept
legacy user comments without an author-type field. Still reject explicit
malformed task IDs.
- Prevent a later failure reply from replacing an earlier final GitHub
answer. Recheck this rule under the publication lease.
- Rotate the native tool contract to replace retained sessions with an
older tool list.
- Add continuation, publication, revocation, and boundary tests. Update
the access and feature maps.

## Verification

- Red: the later GitHub assigned-tool search returned an empty list
before the binding fix.
- Red: the later GitHub read failed with no active conversation
capability before the request-history fix.
- Green: runtime MCP discovery, GitHub read/begin/submit review, and
response publication pass for monitor and same-user board continuations.
- Green: Slack history, retained access controls, revocation, and voice
gateway continuation pass.
- Green: 35 channel, failure-publication, legacy-origin, long-history,
and provenance tests pass. Both review findings had failing tests before
their fixes.
- Green: 107 gateway, operation-credential, identity, and provenance
tests pass. These cover both first-run CI failures without changing
their tests.
- Green: 122 runtime, discovery-policy, and native-session tests pass; 2
unrelated tests are skipped.
- Map checks and whitespace checks pass.
- Updated to master in `cfcaba22628772d7fe1fb32b57ff7031c7072781`. The
sole conflict was two tests added at the same location. Both the
continuation test and the publication 403/401 test are retained.
- Current local verification: all 179 gateway, credential,
requester-identity, access-policy, runtime-context, and session-resume
tests passed. Repository typecheck and build passed. Map and whitespace
checks passed.
- The new review regression first returned no source for a same-user
board follow-up over legacy wake metadata. After the repair, all 27
provenance and channel cases passed. The combined GitHub
discovery/read/begin/submit path and revoked access are covered.
- The broader local channel run passed 176 cases and failed four
timing/setup cases: a 15-second Slack authorization timeout,
webhook-verification polling, a Slack acknowledgement deadline, and
Discord setup polling. All four passed in isolation without source,
assertion, or deadline changes. The earlier failure record is retained;
the exact load/order cause is not established. Full CI must pass on the
latest commit.
- Current head: `7b9a08dcbc7b8140b589742f136944270b0496bb`. Repository
typecheck and build pass on this commit. Greptile completed on this
exact commit with 5/5; all four review threads are resolved. The
final-head [CI
run](https://github.com/paperclipai/paperclip/actions/runs/39278921653)
passed: 55 checks passed and 2 intentionally skipped, with no failures
or pending checks. This includes the full sharded test matrix, browser
tests, typecheck, build, and Runner verification. Results were delayed
during the [GitHub Actions
incident](https://www.githubstatus.com/incidents/8tzbpcnl75jp). An
additional unsharded local full test run has not completed; the
completed full-suite evidence is CI.
- Earlier verification: the first PR commit failed two server suites.
Those failures were fixed and verified before this update. The original
4 GiB sandbox could not complete full local typechecking or tests; the
current checkout completed typechecking and build. The full test suite
runs through the CI shards. No full local test-suite pass or live
provider delivery is claimed.

## Risks

- Request history can restore the wrong authority if its scope is too
broad. The resolver checks each accepted parent against the task,
company, agent, and requester. Tests cover invalid and cyclic history.
- The native contract change starts a new provider session for older
contracts.
- No database migration or public API schema changes are required. Each
tool call still checks live access.

## Model Used

- OpenAI Codex, GPT-6 family. The runtime does not expose the exact
deployment model ID or context-window size. The agent used reasoning,
repository tools, code edits, and local test execution.

## 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
- [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>
2026-10-19 11:20:39 -05:00
DottaandPaperclip a7504784e5 perf(chat): avoid snapshot reads in native progress polls (#16845)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat connectors publish safe progress from native runs.
> - A recurring query joins each run to its conversation through JSON
context.
> - Large snapshots make repeated JSON reads expensive.
> - Issue-scoped runs already have a typed issue binding.
> - This pull request uses that binding and retains the legacy JSON
fallback.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The native chat-progress candidate query in
`enqueueSafeNativeChatProgress`.

**Subsystem affected**

`server/` database queries and chat publication.

**Current behavior**

The conversation join extracts `issueId` from each run's JSON snapshot.
A local plan probes the run repeatedly and reads a large snapshot for
each probe.

**Proposed behavior**

Use the run's typed `issue_id` when present. Read the JSON key when that
column is null. Keep the existing company, endpoint, event, publication,
cursor, and cadence conditions.

**Reason and benefit**

Avoid repeated snapshot reads for scoped runs. Related: #15802 changed
delivery queue scheduling; it left native progress projection on its
existing cadence.

## What Changed

- Change only the native-progress conversation join. Leave the separate
milestone query, which already uses its expression index, unchanged.
- Add a disposable PostgreSQL benchmark that captures the real service
SQL and compares complete rows on one shared fixture. It includes a
legacy null binding, unrelated tenants, 2,400 historical decoys, and 144
KiB of random bytes per snapshot (about 192 KiB after base64 encoding).
- Compare cardinality across independent fixtures. Their generated
conversation and event IDs are not deterministic.
- Add PostgreSQL regressions for a typed issue binding without the JSON
key and for the legacy NULL-column fallback.

## Verification

- Full-size paired local measurement: native baseline 57.67 ms median,
treatment 19.35 ms median, **2.98× faster**. Both return the same 41
complete rows. Five timed samples follow warmups, with baseline and
treatment alternated. The unchanged milestone query is a control.
- An independent full-size run also passed complete row equality and
measured 65.22 → 24.08 ms (2.71×).
- The small 1 KiB control passed the same 41-row equality check and was
neutral: 15.20 → 15.45 ms median. The improvement targets large
snapshots, not small payloads. A repeat of the final JavaScript entry
point also passed equality and measured 2.97× while the full test suite
was running; its wider timing spread is not the primary performance
result.
- Four PostgreSQL cases pass: typed issue scope without a legacy JSON
key, NULL-column JSON fallback, native-progress cadence, and
paused-endpoint no-replay behavior. The remaining tests in that file
were excluded by the name filter.
- Reproduce with `node --import ./cli/node_modules/tsx/dist/loader.mjs
scripts/benchmark-chat-native-progress.mjs --phase=baseline` before
applying the query change. Run the same command with `--phase=treatment`
after applying it. The tool stores SQL, parameters, plans, all samples,
and equality evidence under `.scratch/`.
- Full workspace typecheck and final server typecheck passed locally.
Four focused PostgreSQL cases passed. The duplicate unsharded local
full-suite run was stopped after the same commit passed all CI test
shards; the full local tests/build sequence was not completed. CI Build
and the aggregate verification gate passed on that commit.
- Current-head CI is green at `82c9ef9` (55 successful checks, two valid
skips). An unchanged runtime-supervision test failed in the first
attempt; its isolated local reproduction passed, and one failed-job
rerun passed on the same commit. The local reproduction runs on macOS
and does not exercise the Linux process-identity branch.
- Greptile reviewed `82c9ef9` at 5/5 with no unresolved threads.

## Risks

- The typed issue binding takes precedence when present; older rows
retain JSON fallback. Company and publication ownership checks remain in
the query.
- Measurements use local embedded PostgreSQL 18 with synthetic data. The
hosted motivation used PostgreSQL 17. Absolute timings and plans can
differ on other compute and data distributions.
- The milestone benchmark returns an empty candidate set and is a
performance control; the nonempty native comparison is the correctness
and performance target.
- No schema migration or provider network request is added. This PR does
not deploy a query change to a live database.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, tool
use, and code execution. The exact serving model ID and context-window
size are not exposed. Z-AI GLM 5.3 Prime through OpenRouter
(`openrouter/z-ai/glm-5.3-prime`) assisted the initial query treatment
and benchmark. Codex repaired the comparison, narrowed the production
change, and ran the full-size proof.

## 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>
2026-10-19 10:20:32 -05:00
DottaandPaperclip 9966f31bee fix(chat): keep permission failures scoped to the rejected operation (#16847)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - External channels deliver agent replies through a durable
publication queue.
> - A provider can reject one operation while other operations remain
allowed.
> - The shared error classifier treated generic 403 and permission
errors as failures of the whole connection.
> - Failure handlers then changed the user's enabled setting and removed
all assigned channel tools.
> - This pull request limits permission failures to the rejected
operation and preserves connection intent during authentication
failures.
> - Unrelated work can continue, while confirmed authentication failures
still stop endpoint traffic.

## Linked Issues or Issue Description

Refs #16137. Follows #16138, which distinguishes local authorization
errors from provider errors. This change also narrows provider
permission failures. Related #16806 handles a separate task-continuation
tool-binding defect.

A provider 403 or missing-scope response currently disables a connection
that may still support other operations. The expected behavior is a
visible operation failure with unrelated work preserved. Confirmed
authentication failures must stop sends without changing the user's
enabled setting.

## What Changed

- Classify generic 403, adapter permission errors, and Slack
missing-scope/no-permission responses as failed operations.
- Preserve rate-limit retries, known destination quarantine, and
confirmed authentication failures.
- Preserve connection status and enabled intent when publication,
provider-reply, or form-open authentication fails. The endpoint still
enters attention and its runtime stops.
- Add GitHub regressions for retained discovery and successful later
publication after 403, and no further sends after 401.
- Mark authentication health failed and fence persistent receiver
startup, background reconciliation, and receiver callbacks. Keep signed
GitHub lifecycle events available during an authentication stop. Verify
Discord reconciliation and Photon restart preserve the stop, while
transient Discord disconnects still recover.
- Update provider, publication, and modal regression expectations and
the execution contract and verification maps.

## Verification

- Red: five new classifier cases returned endpoint attention before the
repair. The signed-installation-removal regression also reproduced a
blocked lifecycle event after a 401 before narrowing the receiver guard.
- Green: all 35 classifier tests pass.
- Green: 19 PostgreSQL-backed cases pass through the production channel
services, including GitHub discovery/publication, Slack provider replies
and question modals, Telegram credential/destination failures, rate
limiting, and Discord/Photon authentication-stop persistence.
- Map structural checks and `git diff --check` pass.
- `pnpm -r typecheck` and `pnpm build` pass. All CI gates are green on
`7e379bcd98aa8363e42efe7f8a4b2589b7111ae6`; Greptile is 5/5 on that
exact commit with no unresolved findings.
- The monolithic local `pnpm test:run` was started, then stopped after
its revision passed the full CI matrix and was superseded by the
authentication-stop repair. Final full-suite verification passed in CI
shards; all 19 final local provider regressions pass.
- The tests run from this source checkout on macOS arm64 with isolated
PostgreSQL and controlled provider failures. They do not prove live
GitHub recovery or deployment. No live connection settings were changed.

## Risks

- Permission failures now leave unrelated work available. The rejected
operation remains failed and is not automatically replayed. Provider
authorization still applies to every request.
- Keeping a connection enabled must not bypass an authentication stop.
GitHub verifies blocked tool discovery and later sends; Discord and
Photon verify background reconciliation and restart cannot clear the
stop. Failed connection health is an execution gate while the endpoint
requires attention.
- Explicit disable, disconnect, signed installation revocation, and
existing destination-specific denial handling remain unchanged. No
migration or API schema change is required.
- Previously disabled connections are not automatically re-enabled
because an upgrade cannot safely infer the user's intent.

## Model Used

- OpenAI Codex, GPT-6 family. The runtime does not expose the exact
deployment model ID or context-window size. Used reasoning, shell tools,
repository edits, and test execution.

## 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
- [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>
2026-10-19 09:54:22 -05:00
DottaandPaperclip becdc3b08e perf(slack): remove delays before mention acknowledgements (#16491)
Slack mentions now start eyes reactions after the authorized task/comment commits, independently of attachments, subscription and scheduler acceptance. Omit unused optional URL-preview polling while retaining message text, links and files. Keep receipt failures and missing-file warnings independent, including terminal cleanup of older multi-line diagnostics.

Verified with full current-head CI and E2E, Superagent and legacy security checks, Apex 5/5 with no unresolved findings, 19 selected real-PostgreSQL receipt/authorization/cleanup cases, and full frozen-source typecheck/build. The first CI attempt's unchanged Cursor probe timeout is retained in the PR; the one failed-only retry passed under unchanged deadlines. Live Slack latency still requires deployed acceptance.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-15 17:36:50 -05:00
DottaandPaperclip 5ec93dae01 fix(connectors): avoid redundant run preparation discovery (#16461)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Run preparation selects connector skills and tools under current
permissions.
> - An assignment check can build an unrelated company tool catalog and
wait for a shared discovery slot.
> - Native startup repeats assignment discovery to obtain static tool
definitions.
> - Slack also locks and reconciles an unchanged catalog, then repeats
task authorization.
> - This pull request removes that redundant startup work and preserves
live checks at tool execution.
> - The benefit is less preparation work, less contention, and unchanged
permission and approval enforcement.

## Linked Issues or Issue Description

Related: #16454 (detailed preparation tracing), #16425 (workspace
preparation performance).

**What happened?**

Connector configuration added avoidable work to run preparation. Browser
Use assignment authorized the whole company catalog, including other
connector families. Four connector resolvers ran in series. Native
controller startup repeated all assignment resolution when any connector
skill was pinned. Slack reconciled an unchanged catalog under an
advisory lock and checked task authority twice.

**Expected behavior**

Prepare only the connector data needed by the run. Reuse static tool
definitions from pinned skills. Preserve current company, assignment,
identity, profile, policy, grant, and approval checks when an operation
executes.

**Steps to reproduce**

1. Configure Browser Use and an unrelated MCP catalog with 500 tools for
one company.
2. Resolve Browser Use resources for an authorized task. The old path
reads and authorizes the unrelated catalog.
3. Occupy both full discovery slots. The old assignment check waits for
those slots.
4. Resolve a linked Slack task repeatedly with an existing current
catalog. The old path still acquires a catalog lock and repeats
authority checks.

**Paperclip version or commit**

Base: `68a09dcb5f50e3fb6ceaaeac2706d96db97fc9b3`.

**Deployment mode**

Observed in hosted native runs. The local reproduction uses a source
checkout and real embedded PostgreSQL.

## What Changed

- Restrict Browser Use catalog reads and policy decisions to active
Browser Use connections. Preserve guest restrictions, reviewed catalog
filters, live grants, and deterministic resource order. Keep assignment
checks out of the full discovery queue.
- Resolve the four independent connector families concurrently. Wait for
outstanding work to settle before propagating a failure, and retain
registration order.
- Register native direct connector tool definitions from pinned
connector skills. Keep live assignment resolution and governed execution
on every tool call.
- Compare Slack catalog hashes before reconciliation. Current catalogs
skip the catalog transaction and lock. Check task authority once after
current profile checks. Initial setup and upgrades retain locked
reconciliation and checks before and after it.
- Precompute immutable bundled Slack descriptor hashes. Preserve
disabled entries, profile state, removed bindings, and review metadata.
- Document the startup paths and add focused contention, revocation,
catalog upgrade, and failure-settlement regressions.
- Repair a pre-existing CI guard false positive: the filename
`docker-compose-secrets.test.mjs` matched `secrets.`. Check GitHub
secret expressions instead, with dot, bracket, and whole-context
controls. No workflow changes.

## Verification

- Conflict resolution: merge `b1566ca494f4af6e8d4418fa37393c5caee02582`
from master into head `55140b1609ae7bd21a038eb75a48c2683299e4b4`.
Combine both secret-expression guards and regression cases. Preserve
current workspace, native recovery, and Daytona changes. All 467 policy
tests, 787 focused native/connector/Browser Use tests, and server
typecheck passed locally after integration. Fresh full CI passed all 55
checks on this head, with two optional Storybook jobs skipped. Greptile
reviewed this exact head at 5/5 with no unresolved threads.

- `pnpm -r typecheck` — passed.
- `pnpm build` — passed.
- Focused native startup, connector concurrency, and AgentMail suites —
763 tests passed.
- Complete Browser Use suite — 33 tests passed. Focused Slack catalog,
linked task, retained provenance/revocation, and pinned native tool
tests passed. The complete runner tool authority suite passed (26
tests). The 1,337-case chat suite passed 1,335 tests and had two
failures: the original new transaction-count assertion and a 15-second
timeout in the publication-batch case. Both cases passed an isolated
rerun. The publication timeout occurred during concurrent local checks;
the passing rerun does not erase it. CI must still pass the chat shards.
- The first focused run found two incorrect new assertions: policy
evaluation performs a second catalog lookup, and an explicit allow
policy overrides a profile default. The tests now distinguish the scoped
catalog query and revoke the governing policy. The focused Browser Use
rerun passed all 33 cases after these assertion fixes.
- Full-suite test verification used the CI shards of `pnpm test:run`.
Local runs focused on the changed boundaries; the complete repository
test command was not duplicated locally.
- `node --test '.github/scripts/tests/*.test.mjs'` — all 467 policy
tests passed. The CI failure reproduced on the unchanged base guard
before this correction. Actual GitHub secret expressions still match the
guard.
- CI on the final head passed all chat shards, typecheck, build, Runner
checks, browser shards, and other test lanes. One existing
workspace-runtime case hit `EADDRINUSE` for a randomly selected test
listener in server shard 1/12 (1,162 tests passed in that shard). The
shard passed its single retry on the same SHA with no source changes.
The first failure remains recorded here. Previous reviewed head
`7191ac40691ddb1ef38b86665c95cc14c57ea390`: all 55 checks passed, two
optional Storybook jobs skipped, and no pending or failed checks.
Greptile is 5/5 on this head with no unresolved review threads. The
external security scan passed.

Local before/after measurements use the old and new implementations
against the same fixture. Both paths are warmed. Seven samples alternate
execution order. The database is real embedded PostgreSQL. No latency is
injected. These measurements do not establish hosted speed.

| Local path | Before median (range) | After median (range) | Work
reduction |
| --- | --- | --- | --- |
| Browser Use assignment with 500 unrelated MCP tools | 44.020 ms
(33.994–107.328) | 26.502 ms (20.385–99.037) | 26 → 22 statements;
unrelated catalog and discovery queue removed |
| Slack assignment with current catalog and linked responsible user |
49.723 ms (43.624–80.653) | 22.141 ms (19.781–30.818) | 5 → 2 database
transactions; no catalog lock on the current path |

The contention regression fails against the old implementation after a
bounded five-second wait, then passes against the optimized
implementation. It occupies the real global discovery scheduler and
verifies that Browser Use assignment completes without releasing those
slots. It records catalog SQL to verify connection scope. Revocation
cases remove policy, catalog availability, and grants between calls.
Existing Slack integration cases exercise retained provenance, removed
profile bindings, identity revocation, approved writes, and current
responsible-user restrictions.

## Risks

- Pinned native tool definitions can remain visible after access is
revoked. They confer no authority. Invocation rechecks current
assignments and fails closed before an operation executes. Newly
available connector families still require a newly admitted skill
selection.
- Concurrent resolution can increase instantaneous database reads to
four connector families per configuration call. It is a fixed bound.
Outstanding work settles before a failed preparation returns.
- Slack skips reconciliation only when all bundled version hashes and an
existing profile match. Missing or changed definitions still use the
existing locked path. Operator revocations remain effective.
- This PR addresses connector preparation. Workspace transfer, provider
startup, copyback, and queue delay can still keep total latency above
the user's goal. Hosted improvement needs a deployed before/after trace.
- No schema, lockfile, workflow, telemetry event, or authorization cache
changes.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, repository inspection, code
execution, and GitHub tools. The runtime does not expose the exact
serving model ID or context window.

## 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
- [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>
2026-10-15 14:08:01 -05:00
DottaandPaperclip 3ea39f75c1 test: consolidate duplicate owner proofs (#16075)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-14 23:17:13 -05:00
DottaandPaperclip f69c6a8a35 fix(github): retry and recover review publication (#16284)
## Thinking Path

> - Paperclip manages agent work and its published results.
> - GitHub review bots publish task-bound assessments through governed
tools.
> - A review can survive a caller timeout because its publication intent
is durable.
> - A transient provider failure still returned a failed receipt before
recovery.
> - Gateway replay could return an empty cached result, and publication
retries had no dedicated scheduler deadline.
> - This pull request adds bounded retries, receipt recovery, and an
independent durable worker.
> - A temporary GitHub failure can recover without another review or
duplicate publication.

## Linked Issues or Issue Description

Refs #16275. That change increased the GitHub tool deadline. This change
repairs retry and recovery behavior.

**What happened?**

A one-off GitHub HTTP 503 or 429 left the caller with a failed
publication receipt. The saved retry did not have its own scheduler
worker. An identical gateway call after a timeout could return an empty
cached result instead of the saved publication receipt.

**Expected behavior**

Temporary failures should retry under current authority. Pending work
should resume at its saved deadline after restart. Exact retries should
return the current receipt. Lost responses must not create duplicate
comments, findings, or checks.

**Steps to reproduce**

1. Admit an advisory PR review request and begin its assessment.
2. Return HTTP 503 or 429 for the first summary-comment PATCH, then let
GitHub succeed.
3. Submit the assessment through the run-scoped tool gateway.
4. On master, the result says publication failed. With this change, the
same call returns the processed receipt and neutral check.
5. For receipt recovery, use a shorter caller deadline and repeat the
exact call after publication finishes.

**Paperclip version or commit**

Reproduced on master at `6cb6ac3b8e40cb90d734ba115a2f22f850ff9477`.

## What Changed

- Classify transient transport, server, and rate-limit failures. Honor
Retry-After and primary reset deadlines. Stop retries for permanent
permission and validation errors.
- Retry safe reads and installation-token issuance within a bounded call
window. Retry publication writes through the existing outbox and
provider receipt checks.
- Wait for up to three publication attempts within a 45-second retry
window. Keep the durable eight-failure cap and enforce saved deadlines
on explicit retries.
- Register an independent GitHub publication worker with
transaction-owned wake notifications, startup recovery, and per-PR lease
deadlines.
- Recover exact comment, progress, and assessment gateway calls from
their stored publication. Require the same company, agent, task, run,
connection, tool, arguments, and current policy. Clear stale timeout
errors after recovery. Approved exact retries read the current receipt
through the existing signed replay path; the worker retains the verified
approval for deferred writes and still rejects revocation.
- Add regression coverage and update the connector guide and
feature/access maps.

## Verification

- Red: both one-off HTTP 503 and 429 regressions failed on master with a
failed publication receipt.
- Green: the same tests passed after the change.
- GitHub review workflows: 133 covered against isolated PostgreSQL 18.
The final combined run passed 132 and hit one fifteen-second timeout
under concurrent build load. All three variants of that workflow passed
in isolation. The earlier combined run passed all 131 workflows before
the two approval regressions were added.
- Retry policy and delivery coordinator tests: 35 passed.
- Additional focused checks passed for the actual eight-failure cap,
exact-argument conflicts, policy revocation, and timeout receipt
recovery. The approved deferred-publication and revocation regressions
failed before the review repair and passed after it, with one approval
request preserved.
- `pnpm -r typecheck`: passed. `pnpm build`: passed. `node
scripts/check-maps.mjs`: passed.
- The broad local `pnpm test:run` path remains blocked by the host's
exhausted PostgreSQL shared-memory slots. The changed database-backed
workflows use an isolated Docker database instead. All Paperclip CI jobs
passed at a6d81b67cb, including the required verify and E2E gates.
Greptile is 5/5 at the same head, with the approval-recovery finding
resolved. The external Superagent Security Scan also passed.
- Live acceptance passed on a dedicated single-repository local test App
and native Paperclip Runner. A test-only preload returned one HTTP 503
before the final summary PATCH. One submit_review call completed in
17.305 seconds; the bot published its 3/5 advisory review and neutral
check, then automatically finished the task. [Published
review](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/pull/9#issuecomment-6168809007),
[neutral
check](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/runs/115863564014).
This live test ran at de6862072c; approval-specific recovery is covered
by the later regressions. The preload is excluded from the repository
and removed from the running local instance.

## Risks

Retries make additional bounded provider requests. A provider write with
a lost response is recovered through its existing App-owned identity
before another write is permitted. The worker rechecks authority and the
PR head; revocation and superseded work stop publication. Calls can
still exceed their deadline, and repeated failures eventually exhaust
the retry cap. A pending publication is not a completed task. The agent
still owns task completion after receiving a confirmed receipt. No
schema migration is needed.

## Model Used

OpenAI Codex (GPT-6 family), with code inspection, editing, and test
execution. The exact deployment model ID and context window are not
exposed in this session.

## 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
- [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>
2026-10-14 08:40:32 -05:00
DottaandPaperclip 1e731520bb fix(mcp): deduplicate discovered tool descriptors (#16281)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents receive governed app tools through the MCP gateway.
> - GitHub review tasks can contain a PR discussion and inline finding
threads.
> - Discovery repeated each tool for every conversation linked to the
task.
> - Native tool registration treated these repeated descriptors as a
fatal collision.
> - This pull request lists GitHub tools once and deduplicates identical
descriptors across providers.
> - Agents can continue work while conflicting definitions and normal
tool permissions remain enforced.

## Linked Issues or Issue Description

**What happened?**

A follow-up run on a GitHub review task failed with
`assigned_mcp_tool_name_collision` before the provider started. The task
had a main conversation and an inline finding thread. Discovery returned
the same seven tools twice. Repeated descriptors from other providers
could cause the same failure.

**Expected behavior**

Discovery exposes each identical tool once. Separate connection names
remain separate tools. Conflicting definitions remain an error. Every
call still passes the gateway's policy, approval, revocation, and audit
checks.

**Steps to reproduce**

1. Run a GitHub review and publish an inline finding.
2. Send a follow-up request on the same PR task.
3. Inspect the task-bound bot catalog and the next native startup.
4. Separately, return two identical descriptors from an assigned app or
plugin catalog.

Related: #13717 added the GitHub review workflow.

## What Changed

- Use a distinct GitHub discovery query across conversations that share
an endpoint and task. Keep both thread mappings.
- Deduplicate identical gateway descriptors by their full gateway name
across providers. Use this rule for MCP listings, plugin listings,
assigned-tool startup, and fresh assigned-tool discovery.
- Reject conflicting descriptors with `tool_name_collision`. Keep the
projected-name collision guard.
- Cover GitHub inline-thread discovery, repeated plugin/app tools,
direct and on-demand catalogs, revocation, conflicting bindings, and
separate connection names.
- Update the execution contract, GitHub documentation, and agent access
map.

## Verification

- Regression baseline: six new assertions failed on the original
implementation. GitHub returned fourteen entries, plugin discovery
repeated a tool, and native startup failed on repeated app tools.
- Focused verification passed: 272 GitHub cases, all 29 assigned-tool
cases, and all 88 gateway acceptance cases.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- `node scripts/check-maps.mjs` passed.
- Current-head CI passed: 55 checks passed, two inapplicable checks
skipped. Greptile scored the current head 5/5 with no unresolved
threads.
- Full local `pnpm test:run` encountered a 15-second timeout in the
existing bearer-auth throttling test, before tool discovery. That test
passed in the separate 88-case gateway run and on one isolated rerun.
The duplicate broad local run was then stopped; the complete
current-head CI matrix passed.

## Risks

- Deduplication keeps the first identical descriptor and preserves
listing order. Same-name descriptors with different definitions fail
with HTTP 409 rather than selecting an ambiguous binding.
- The GitHub query changes result cardinality. It retains the existing
task/company/agent filters and leaves conversation rows intact.
- No schema migration or credential change. Live staging recovery
requires deployment and a new authorized run.

## Model Used

OpenAI Codex, based on GPT-6, with code inspection, editing, browser
investigation, and test execution. The exact serving model ID and
context window are not exposed in this session.

## 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
- [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>
2026-10-14 07:39:54 -05:00
DottaandPaperclip e9b6c4d44c perf: remove history scans from task and chat queries (#16278)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task reads and external chat notices must remain responsive as run
history grows.
> - The chat notice sweep casts indexed UUID columns to text.
> - Run redaction and task provenance filter large JSON contexts with
expressions that lack matching indexes.
> - These queries scan history and read large stored contexts on common
requests.
> - This pull request adapts two existing fixes to current master and
adds the missing provenance index.
> - The benefit is less database work with the same query results and
access rules.

## Linked Issues or Issue Description

Refs #15927. This change adapts that chat sweep fix to the extracted
inbound notice module and retains the contributor credit.

Refs #12499. This change adds that missing nested-context index through
a current, concurrent migration. It retains the contributor credit.

This combined change replaces those older layouts for the measured query
paths. It also covers task creation provenance, which those pull
requests do not address.

**What happened?**

The chat notice sweep scans wakeup history. Issue redaction scans run
contexts because only one branch of its JSON condition has an index. The
task creation-source filter also scans contexts because its native and
legacy ID expression lacks an index.

**Expected behavior**

The queries use indexed lookups and return the same rows. Company
access, task origin precedence, secret redaction, and chat notice
ordering remain the same.

**Steps to reproduce**

Run `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-slow-queries.ts --baseline-ref=f8af817f8d`. The
benchmark creates disposable PostgreSQL data and compares the old query
with the current query on the same fixture.

## What Changed

- Compare chat UUID columns directly with safely parsed payload IDs.
Reject malformed and noncanonical IDs without a cast failure.
- Add the nested `paperclipIssue.id` run-context index and the exact
native/legacy task-provenance expression index.
- Build both indexes concurrently. Register the migration for top-level
execution and invalid-index retry repair.
- Extend chat payload and migration regression coverage.
- Add a repeatable synthetic SQL benchmark and document its scope and
command.
- Keep the five newest schema snapshots.

## Verification

- Focused local checks: 76 selected tests passed in five files. These
cover FIFO notices, malformed IDs, conversation state, redaction,
provenance, and company boundaries.
- Disposable PostgreSQL 18.1 fixture: 335 tasks, 1,400 runs, 13,000
wakeups, 377 actions, and 192 KiB synthetic contexts.
- Five warm samples per query, after two warmups. Every returned SQL
column matched before and after, compared as positional tuples so
duplicate unnamed projections are retained.

| Query | Before, median | After, median | Improvement |
| --- | ---: | ---: | ---: |
| Chat notice candidates | 26.21 ms | 6.43 ms | 4.1× |
| Task creation-source list | 159.69 ms | 6.51 ms | 24.5× |
| Issue redaction contexts | 131.88 ms | 0.34 ms | 389.1× |

The run-history context projection returned the same 200 rows and kept
the same index plan and buffer counts. Its timings were noisy (37.30 ms
before and 56.78 ms after in the last run; 34.25 ms and 34.14 ms in the
previous run). No improvement is claimed for this control. Its repeated
JSON projection remains a separate optimization opportunity.

The populated plans use the wakeup primary key, the provenance
expression index, and a BitmapOr over both redaction indexes. These are
local SQL measurements. They do not prove an equivalent change in hosted
API latency.

- `pnpm -r typecheck` and `pnpm build` passed locally.
- The full local `pnpm test:run` was started and then interrupted (exit
130) when the Mac reached its PostgreSQL shared-memory limit. It did not
complete and is not reported as passed. The final SQL benchmark passed
after its disposable database resources were released. The full general
and serialized test suites passed in CI.
- All CI checks for final head
`193acca6abaa992acad12f4b631bd31dd3234641` passed, including full Vitest
coverage, E2E checks, typecheck, build, migration order, and lifecycle
boundaries.
- Greptile reviewed that exact head at 5/5 with no actionable comments.


## Risks

- Both indexes add storage and write cost. Initial builds read stored
run contexts and can take time on large histories.
- Concurrent index builds avoid holding a write-blocking table lock for
the whole build. The existing migration retry path removes invalid
partial indexes before retrying.
- The chat parser accepts only canonical lowercase UUID text. This
preserves the prior text comparison, including rejection of uppercase
and malformed values.
- Staging has not been migrated or deployed. Local PostgreSQL and
synthetic data do not reproduce hosted load or network latency.

## Model Used

- OpenAI Codex, based on GPT-6. The exact serving model ID and context
window were not exposed in this session. Used reasoning, repository
tools, browser inspection, and local code execution. The adapted fixes
retain their original contributor credits.

## 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
- [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>
2026-10-14 07:37:51 -05:00
DottaandPaperclip 6cb6ac3b8e fix(github): allow review publication to finish before tool timeout (#16275)
## Thinking Path

> - Paperclip manages agent work and its published results.
> - GitHub review bots publish task-scoped assessments through the tool
gateway.
> - A submission saves its assessment and publication intent before it
waits for GitHub.
> - The gateway's ten-second default can expire while those provider
requests continue.
> - GitHub can then show a completed review while the agent receives a
timeout and blocks its task.
> - This pull request gives GitHub bot tools the existing sixty-second
maximum by default.
> - The caller can receive the confirmed publication result without
manual task repair for ordinary slower responses.

## Linked Issues or Issue Description

**What happened?**

A GitHub bot's `submit_review` call returned `504 tool_timeout`. Its
saved assessment continued to publish a summary and completed check
after the caller stopped waiting. The agent treated publication as
unconfirmed and blocked the task.

**Expected behavior**

A valid GitHub response that takes longer than ten seconds should return
its confirmed publication receipt within the gateway's supported
deadline.

**Steps to reproduce**

1. Configure a report-only GitHub review bot and admit a PR review
request.
2. Delay the summary-comment PATCH response by eleven seconds.
3. Submit a complete assessment through a real run-scoped tool gateway.
4. Before this fix, the caller gets a timeout while the durable action
publishes one summary and a neutral check.
5. With this fix, the caller gets `completed`, `processed`, and the
assessment score. Retrying does not add another comment.

**Paperclip version or commit**

Reproduced from master at `2c17d3ca52a7840f280f1dd87975a2ad77de3b35`.

Related changes: Refs #16259 and #16263. Those changes repaired
connection recovery. This change addresses the subsequent submission
deadline.

## What Changed

- Use a sixty-second default for `paperclip_github_chat` tools in run
execution and board tool tests.
- Preserve explicit shorter deadlines and the existing maximum.
- Add PostgreSQL-backed regressions through the real gateway for delayed
publication, explicit deadlines, neutral checks, and duplicate
prevention.
- Document the deadline and the durable publication behavior.

## Verification

- Red: the eleven-second publication regression failed with
`ToolGatewayHttpError(504, tool_timeout)` after the summary and neutral
check were published.
- Green: the same regression passed after the repair.
- GitHub review workflow suite: 122 tests passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: running; results will be recorded before handoff.
- Live local verification is running against a dedicated test App on
[the disposable test
PR](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/pull/9).
A test-only preload delays one real GitHub PATCH response by eleven
seconds. It is not part of this change.

## Risks

GitHub bot calls can occupy their execution slot for up to sixty seconds
by default. Calls that exceed that limit can still time out. Durable
publication may continue after any caller timeout, so a timeout alone is
not proof of a failed write. This change does not add automatic task
reconciliation for arbitrarily slow or unavailable providers. No schema
or credential changes are required.

## Model Used

OpenAI Codex (GPT-6), with code inspection, editing, test execution, and
browser verification. The exact deployment model ID and context window
are not exposed in this session.

## 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
- [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
- [ ] All Paperclip CI gates are green
- [ ] 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>
2026-10-14 06:52:33 -05:00
DottaandPaperclip 2c17d3ca52 fix(github): recover webhook verification in attention state (#16263)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review bots require signed webhook delivery before
activation.
> - Cloud can deduplicate an old ping after a connection repair.
> - A fresh event could verify active connections, but an
attention-state connection discarded it before authentication.
> - This pull request allows signed delivery verification while the
connection needs attention.
> - It discards ordinary work until the manager completes the existing
reconnect and activation checks.

## Linked Issues or Issue Description

Refs #16259. Related: #16138 addresses the separate classification of
local authorization failures.

**What happened?**

Live verification of #16259 found that a GitHub App already marked as
needing attention remained stuck waiting for a signed ping. The Cloud
relay had already delivered that ping. New signed events were discarded
by the attention-state ingress gate before they could verify delivery.

**Expected behavior**

A fresh valid event from the bound installation verifies delivery. It
does not activate the connection, change repository access, or start
work. The manager can then complete the normal reconnect flow.

**Steps to reproduce**

1. Put an existing App connection into attention state with webhook
verification cleared after repair.
2. Deliver a fresh signed comment event for its bound installation.
3. Continue setup. Before this fix, webhook verification remains missing
and reconnect cannot proceed.

## What Changed

- Use a content-free verification path for signed ordinary GitHub events
while the connection needs attention.
- Allow a fresh signed event from the same installation to verify
webhook delivery.
- Verify delivery even from disabled or unavailable repositories.
Discard the event before content storage, resource reconciliation, or
runtime creation.
- Keep newly verified connections in the provider-setup step. Later
installation events cannot activate them before reconnect. Preserve
normal installation recovery for existing qualified connections.
- Extend recovery regressions to cover attention state, foreign
installations, invalid signatures, missing installation IDs, unchanged
resources, no wakeups, and successful reconnect after verification.
- Document the recovery behavior.

## Verification

- The targeted regression reproduced the attention-state failure before
the change.
- All ten recovery cases pass after the change. The tests cover disabled
and unavailable repositories, content-free verification, and
installation events after verification.
- Server typecheck passed.
- All 260 GitHub integration tests passed after the review fixes. Final
server typecheck also passed.
- `pnpm -r typecheck` and `pnpm build` passed.
- The full local suite is running. One unrelated workspace-runtime
conflict-reference test failed and then passed on its isolated rerun.
Final totals and CI/review outcomes will be updated before merge.
- Live verification will use the existing advisory review bot after
deployment.

## Risks

- Attention-state ordinary events authenticate under the current
credential lease without creating a durable content record. They return
before resource reconciliation or runtime creation.
- Verification is still bound to the current credential lease, runtime
generation, valid signature, and installation ID. It does not activate
the bot or replace normal setup checks.
- Paused, revoked, archived, and unconfigured connections retain their
existing ingress rules. No schema changes or permission expansion.

## Model Used

OpenAI Codex (GPT-6), with code inspection, editing, test execution, and
browser verification. The exact deployment model ID and context window
are not exposed in this session.

## 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
- [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
- [ ] All Paperclip CI gates are green
- [ ] 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>
2026-10-14 05:23:42 +00:00