mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 00:05:49 +02:00
ea4aa185b0f3bc30be1c5fc160cdfd0eb433fe41
1055
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ea4aa185b0 |
perf: batch retained-reader authorization reads (#16424)
Batch retained-reader project checks through the existing multi-actor read API. Share raw database reads within one call, retain actor-specific privacy and supplied membership data, and avoid loading large saved-run payloads for identity checks. Keep current-reader writes, distinct saved-run policies, company root fences and later-call revocation checks. Add query-count and access-control regressions. All 255 affected cases and full repository typecheck/build pass. Hosted response-time acceptance remains separate. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
7f9d3d1929 |
fix(grok): avoid routine wakes for proactive admission (#16422)
## Thinking Path > - Paperclip lets people manage AI agents and their work. > - Grok Bot can request governed work from its own conversation. > - Managed Runner admission can take longer than the initial MCP response. > - The dispatcher treated a delayed offer as a reason to start another routine. > - The original conversation was already waiting for that same work. > - This pull request keeps admission in its original request and cancels old prepared echoes. > - Users get one task interaction while normal assigned-task wakes remain available. ## Linked Issues or Issue Description Refs #16219 and #16394. The duplicate search found no other proactive Grok correction. **What happened?** A real idle Grok conversation created one Paperclip task and reached accepted completion. During admission, the dispatcher also sent a routine webhook after the offer was ten seconds old. Two acceptance requests and two title writes were recorded. The extra routine can compete with the original conversation. **Expected behavior** Immediate and delayed Bot-initiated admission stay with the original request. The Bot checks the same request ID and arguments until admission succeeds or fails. A new routine must not echo that work back to the Bot. **Steps to reproduce** 1. Ask an idle Grok Bot to create and complete a Paperclip task. 2. Let managed admission return pending. 3. Leave its offered assignment unaccepted for more than ten seconds. 4. Run the dispatcher. It sends another routine webhook for that proactive offer. **Paperclip version or commit** Observed through the actual Grok client on Core |
||
|
|
6acec4266e |
feat(ci): profile full CODEOWNER PR suites in Honeycomb (#16378)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Its PR workflow runs dozens of parallel build and test jobs. > - Individual job durations do not show the elapsed cost of the whole suite. > - Maintainers need one shared timeline to find slow work and repeated setup. > - This pull request adds full-suite profiles for selected CI CODEOWNER PRs. > - Honeycomb shows each job, step, test file, and supported test on that timeline. > - The benefit is evidence for changes that reduce total CI time. ## Linked Issues or Issue Description **What existing behavior does this improve?** The main PR workflow has about 48 jobs. Maintainers need to compare their overlapping work and find which jobs delay completion. **Current behavior** GitHub shows job and step durations separately. Test files and tests are not joined to a full workflow trace. **Proposed behavior** A CI CODEOWNER adds `profile-ci` to a PR. The tested code stays on that PR branch. All main PR lanes run, including lanes normally skipped for stack position or release notes. A trusted post-run exporter sends one wall-clock trace to Honeycomb. **Reason and benefit** The trace supports decisions about which CI work to speed up or remove. Ordinary PRs do not export traces. The roadmap and related-PR search found no duplicate CI profiling work. ## What Changed - Add label selection and a full-suite override. Verify the PR author, original actor, and rerun actors against the trusted `.github/**` CODEOWNERS rule. - Record Vitest, Playwright, and Node test file/test timings in local artifacts. Keep ordinary reporter behavior and failing exit codes. - Add a trusted `workflow_run` exporter. Use actual GitHub timestamps for all jobs, setup, steps, waiting, and teardown. Mark missing test data and partial reruns. - Keep the ingest key out of PR jobs. Store it only in the `ci-profiling` environment, restricted to `master`. The exporter reads bounded JSON and never executes artifact code. - Record expected test invocations outside reporters so a missing invocation cannot appear complete. Preserve `node --test` on older PR checkouts. Flush large shard inventories before exit. - Add security, timing, routing, and real-reporter checks. Document operation and activation. Protect the exporter with CODEOWNERS. ## Verification - 509 focused workflow/reporter/shard checks passed. They include outside authors, outside rerun actors, bots, stale revisions, malicious ZIP paths, incomplete reports, and partial ingestion failures. - Final revision `3bf5d9017d` adds multi-file qualification and fixes short-file step parenting and duplicate Node file-wrapper events. Greptile reviewed this exact revision at 5/5 with no unresolved threads. [Main PR CI run](https://github.com/paperclipai/paperclip/actions/runs/38728040302): the initial attempt had 54 successful checks, 3 intentional skips, and one serialized-shard failure from an unchanged workspace-authorization test exceeding its 15-second timeout. The single failed-shard retry passed: the final result is 55 successful checks and 3 intentional skips. The same timeout reproduces locally with profiling disabled; both assertions pass with a diagnostic 60-second timeout override (about 23 seconds total). No source or CI timeout was changed. - A dry run against real GitHub attempt 2 of run `38677445871` produced exactly 3 executed jobs, 40 spans, and 510 seconds, excluding 45 carried-over jobs. The partial trace remains explicitly incomplete; this validation did not upload data. - `actionlint` passed for all four changed workflows. `git diff --check` passed. - Full Node 24 `pnpm -r typecheck` and `pnpm build` passed. The local full `pnpm test:run` was stopped after it reported a setup-token timeout and a distribution-plugin-catalog fixture failure. The 30 setup-token tests passed on focused rerun. The plugin fixture fails at `rmSync` of a directory symlink on this macOS/Node 24.11.0 host; the same failure reproduces with the unchanged base Vitest configuration and unchanged test/service files (10 other tests pass). The local full test suite is therefore not claimed green. - A real root-config Vitest probe passed 13 tests with profiling both off and on. Multi-file Vitest, Playwright, and Node probes each verify two distinct filename rows and four correctly parented tests, including repeated test names across files. Separate passing probes exercise the full exporter hierarchy `workflow → job → step → filename → tests`. Intentional failing probes preserve failing exit status. - Verified all 48 measured jobs in latest-head run `38728040302` used AWS: one `paperclip-ci-routing-x64` gate and 47 `paperclip-public-pr-x64` jobs. Profiling preserves AWS authorization and its GitHub-hosted fallback. The separate privileged exporter runs on `ubuntu-latest` outside the measured suite. - [Live Honeycomb baseline](https://ui.honeycomb.io/paperclip/environments/test/datasets/paperclip-ci/trace/oaPMzw8zGwG): 48 jobs, 731 spans, 479 seconds. It matches [GitHub run 38671274294](https://github.com/paperclipai/paperclip/actions/runs/38671274294). This historical trace has job/step data only; it is not proof of the future label-triggered test-reporting journey. - Verified the dedicated Honeycomb key is ingest-only with dataset creation disabled. Verified the GitHub environment allows only the `master` branch. No repository-level secret of that name exists. Both credential values were scanned absent from source and branch history. After merge, add `profile-ci` to a CI CODEOWNER PR, wait for the entire PR run and exporter, then follow the run-summary link. Collapse job children to compare parallel lanes; expand a job to inspect its steps and tests. ## Risks - Activation requires merging the trusted workflow definitions to `master`. This PR continues using the current trusted reusable workflows until then. - Selected runs produce many spans and artifacts. Oversized artifacts fail export instead of truncating data. Missing or cancelled reporters are marked incomplete. - GitHub timings have second precision. Node test times use reporter receipt time. Rust retains job/step timing but lacks per-test wall timestamps. - CI CODEOWNERS are individual users in the explicit `.github/**` rule. Unsupported team rules and identity lookup failures disable profiling. - An interrupted upload can leave partial data. Retrying uses the same span IDs, but the Events API does not promise deduplication. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, code execution, repository tools, and browser verification. The runtime does not expose the exact serving 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 - [ ] 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> |
||
|
|
7fc2dc8b32 |
fix: isolate workspace snapshots from controller work (#16414)
Move native sandbox snapshot captures off the controller callback queue while preserving the existing capture and restore contract. Keep legacy adapters inline, bound captures to two workers, and verify cleanup and reordered worker completion. Validation: 461 affected cases, full typecheck/build, exact-head CI/E2E/Superagent and Apex 5/5. The full local canonical suite remains running; no full local pass or under-30-second staging response is claimed. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8365872743 |
fix(codex-local): retry ACP model capacity failures as transient upstream (#16407)
Classify typed Codex ACP `service` failures about model capacity or server overload as `codex_transient_upstream` / `transient_upstream`, so the existing bounded transient retry and continuation recovery apply. In `unexpected` Sentry mode, skip only runs carrying that full classified evidence; `all` mode still reports them. |
||
|
|
11d69d04c7 |
fix(native-runtime): report remote recovery labels thrown before coordinator save (#16406)
Restart reattachment can fail in the executor before the native coordinator saves its result. The run failure report now reads the closed remote recovery stage and reason from the caught error when the saved result lacks them. The saved result keeps priority and the same closed-vocabulary validation applies. Add a regression for thrown, wrapped-transport, saved-priority, and out-of-vocabulary cases. Full current-head CI and Greptile 5/5 passed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
307c27e3d8 |
fix(native): reclaim task execution before same-run recovery
Restore the original task execution binding atomically during native same-run recovery. Preserve current owners, stops, pauses, assignments, and dependency waits. Isolate candidate failures, bound deferral writes, prioritize undated retries, and allow recovery ahead of queued waiters without premature queue promotion. Add PostgreSQL attachment, ownership, contention, fairness, and queue regressions. Verification: 99 focused tests, workspace typecheck, build, full current-head CI, and Apex 5/5. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
af4191f45e |
fix: keep workspace notices from suppressing final replies (#16400)
Keep stored system notices visible without letting them occupy the final reply slot. Read presentation metadata in live and recovery selection, and cover explicit replies, progress receipts, company boundaries, and native replay. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8d9d2f9ddf |
fix(recovery): preserve deliberate stops and dependency waits
Preserve deliberate assignee blocks and operator stops during dependency and run-release recovery. Attribute native waits to their bound owner. Ignore unrelated edits and shared-workspace exports from another issue. Continue after genuine dependency changes while preserving independently authorized user input. Keep the original contributor's implementation and review history. Add native ownership, unrelated-edit, later readiness, and shared-workspace regressions. The shared-workspace loop was reproduced before the fix. Co-Authored-By: Devin Foley <devin@paperclip.ing> Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c68a483cd9 |
fix: replay prepared warm seeds when generation caching is unavailable (#16399)
Replay this preparation’s verified private workspace seed after failed warm validation, including when the generation cache refuses publication. Preserve host-current semantics and rebuild if the private seed is missing or changed. Verified 89 focused cases, full typecheck/build, exact-head CI/E2E/security and Apex 5/5. Live PAP latency acceptance remains separate. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5bc4e878e7 |
fix: reuse verified seeds after warm workspace fallback (#16398)
Preserve the verified company/workspace seed-cache scope when a warm sandbox requires host-current staging. Keep remote identity checks, archive digests and rebuilding for missing or corrupt cache generations. 85 focused cases and full repository typecheck/build pass. Exact-head full CI/E2E, Superagent, legacy Snyk and Apex 5/5 pass with no unresolved findings. No staging response-time claim is made. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
79c34058cd |
fix(native): retain unexported workspaces after execution failure (#16397)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Native agents can edit files in a remote sandbox before they submit a result. > - A process identity or startup failure can end the run before file export. > - Cleanup can then delete the sandbox and its unpublished files. > - This pull request retains the exact source and records a file repair action before cleanup. > - Operators can recover the files without replaying the failed turn or changing the task owner. ## Linked Issues or Issue Description **What happened?** A native remote process had completed local edits when process identity recovery failed. The run still had a prepared workspace reference and no accepted result. Cleanup deleted the source sandbox. No file recovery card appeared. A restarted run can hit the same path during setup, before the native executor starts. **Expected behavior** Retain the exact unexported source. Show the existing file recovery card. Require source stop and file recovery evidence. Keep task ownership, status, and external action reconciliation separate from file repair. **Steps to reproduce** 1. Run a native agent in a remote ephemeral workspace and make unpublished edits. 2. Fail process identity recovery before result acceptance or file export. 3. Allow failure handling and lease cleanup to run. 4. Before this change, cleanup can destroy the source without a file repair action. Refs: #16341 for related process identity diagnostics. Refs: #16349 for startup ownership fencing. This change addresses file retention after failure. ## What Changed - Record source retention and a file recovery action in the terminal native failure transaction. - Cover restarted preparation failures before the terminal setup writer and cleanup run. - Require the exact company, run, lease, provider allocation, and workspace binding. Require the exact live recovery claim to settle an owned preparation failure. Refuse stale or competing claims. - Reuse the existing stop-only cleanup and file-only reconciliation path. Leave accepted results and scheduled same-run recovery on their existing paths. - Document the retention rule and add database and runtime boundary regressions. ## Verification - All 1,242 tests passed across the full heartbeat recovery suite, native executor, native source retention, runtime teardown, run completion, and legacy file recovery. - The integrated missing-descriptor regression fails before the inner-handler fix and passes after it. The runtime retention and owned restart regressions also reproduce their prior failures. - The tests cover exact source identity, current and stale claims, atomic rollback, cancellation, idempotence, and file-only repair on a completed task. - `pnpm -r typecheck` passed on the final code. - `pnpm build` passed on the final code. - Full repository CI passed on `3945eb2ba5c228c5d4992da02b765dcf2e634cb8`: 54 successful checks and two skipped Storybook checks. - Apex scored 5/5 on that exact commit. Both earlier findings are fixed and all review threads are resolved. - The unsharded local `pnpm test:run` is still in progress. It is not counted as a local full-suite pass; complete suite coverage is verified in CI. ## Risks - Failed runs can retain a sandbox that needs operator cleanup after file recovery. This uses the existing retention policy and recovery controls. - This does not recover files from allocations that were already deleted. - No schema migration, UI change, or telemetry change is required. ## Model Used - OpenAI GPT-6 through Codex. Tool use, code execution, and reasoning assisted this change. The environment identifies the model as GPT-6; it does not expose a more specific serving snapshot 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> |
||
|
|
074c67fea8 |
fix(grok): avoid routine wakes for accepted work (#16394)
## Thinking Path
> - Paperclip lets people manage AI agents and their work.
> - Grok Bot receives assignments through routine webhooks and uses
agent MCP tools.
> - Each accepted assignment belongs to the current external
interaction.
> - A pending tool result or comment could start another routine while
that work was still active.
> - Quiet MCP traffic cannot prove that Grok has stopped working.
> - This pull request keeps receipts and feedback durable for the
current interaction to read.
> - New task routines start only for offers that the Bot has not
accepted.
## Linked Issues or Issue Description
Refs #16219 and #16305. The duplicate search also found #12991, which
covers instruction files for local Grok runs.
**What happened?**
The dispatcher could start another routine for an unread result after a
period without a routine reply. It could also wake accepted work for a
task comment. A queued delivery could still start after the Bot had
claimed the offer.
**Expected behavior**
Accepted work stays in its current interaction. The Bot polls the
original operation receipt and reads queued feedback at a safe boundary.
Acknowledgements of a sent wake remain valid after acceptance.
**Steps to reproduce**
1. Accept a Grok assignment and leave it active.
2. Add an unread comment, or complete a tool operation whose call
returned pending.
3. Run the dispatcher after its quiet period.
4. Observe another webhook call. Also queue an offer wake, accept the
offer before sending, and observe that delivery still starts.
**Paperclip version or commit**
Observed during real-client qualification on Core
|
||
|
|
854ab294cc |
fix: restore repository admission and Claude startup on Linux ARM64 (#16372)
Batch retained workspace admission reads while preserving individual privacy and trust decisions. Preserve bounded saved-policy projections when integrating current master, and qualify the pinned Claude executable on Linux ARM64.
Verified exact head
|
||
|
|
444d5854b0 |
test(adapter-utils): consolidate outbound restore span coverage (#16115)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
a15798e752 |
test(server): reuse seeded delivery workspace fixture (#16114)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
1315aa22c2 |
test(ui): retire duplicate company settings checks (#16113)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
86816ff965 |
test(adapters): consolidate Grok stale-auth promotion coverage (#16112)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
982ff62949 |
test(shared): consolidate ZIP conversion observations (#16118)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5e62927a8f |
test(adapters): consolidate Codex staging permission guards (#16111)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
1897080a6d |
test(scripts): retire duplicate provisioning fallback launch (#16110)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5c65525219 |
test(scripts): consolidate stable shard selection cases (#16109)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
a05052f77d |
test: retire duplicate heartbeat disposition recovery executions (#16102)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
67e45e869e |
test(ui): retire duplicate CompanyExport render checks (#16108)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
662a20281d |
test(cli): retire duplicate ZIP codec owner tests (#16116)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
0de90e25bf |
test(adapter-utils): share pre-READY work-bound bridge execution (#16098)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
1ff08a53cb |
test(tailscale): retire duplicate substituted-listener withdrawal (#16106)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
522619744b |
test(ui): retire duplicate IssueChatThread render cases (#16092)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ae6e701821 |
test(ui): share repeated IssueDetail render proofs (#16091)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
997ea5fd17 |
test(server): retire duplicate process-loss recovery execution (#16088)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
aa6910939b |
test(runtime): share the projectless local lease acquisition (#16086)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
d6e4b36c8c |
test(server): move Git redaction proof to its owner (#16081)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
76164b53cb |
fix(heartbeat): retry a legacy run that lost its lease before dispatch (#16358)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The heartbeat runner executes legacy agent runs. A controller lease watchdog keeps durable ownership of each legacy run, and it aborts the run when it loses the lease. > - #16084 records a lease loss as a `controller_lease` cancellation when the adapter returns or throws. It does not cover a lease loss during setup, before the adapter starts. > - In setup, the abort reason goes to the setup catch. The catch records an opaque `setup_failed` and sends the raw `LegacyControllerLeaseLostError` to Sentry with no cause label. > - Issue continuation recovery treats `setup_failed` as non-retryable. The task moves to `blocked`, but no provider work started. > - This pull request records a lease loss before dispatch as `controller_lease_lost`, with the same `controller_lease` evidence. Recovery retries it as transient infrastructure, and so does the accepted-interaction (plan approval) continuation retry. > - The benefit is that a host lease loss during setup no longer strands the task, and the next Sentry event shows which renewal failure caused the loss. ## Linked Issues or Issue Description Refs #16084 Refs #16355 Refs #16359 **What happened?** A staging server reported `LegacyControllerLeaseLostError: Legacy controller lease lost` from the heartbeat. The run failed during setup with `setup_failed`. Continuation recovery then said "non-retryable failure on this issue's continuation run (`setup_failed`)" and moved the task to `blocked`. A scanner had to move the task back to `in_progress` by hand. **Expected behavior** A lease loss before adapter dispatch is a host infrastructure stop. The run records the `controller_lease` cause, like the adapter-phase path. The run keeps `providerWorkStarted: false`. Recovery retries the continuation with its bounded transient budget, and it does not block the task. **Steps to reproduce** 1. Start a legacy run that has a controller lease. 2. Before the adapter dispatch, make the lease renewal fail: the update matches no row, the query errors, or the lease deadline passes. 3. `controllerLease.assertOwned()` throws the abort reason in workspace preparation or before dispatch. 4. Before this change: the run is `failed`/`setup_failed`, `resultJson` has no `cancellation`, and continuation recovery blocks the task. After this change: the run is `failed`/`controller_lease_lost` with `cancellation.source: "controller_lease"` and a closed cause, and continuation recovery classifies it as `transient_infra`. **Additional context** #16355 handles a different path: a restart orphan that the next boot reaps as `process_lost`. This change handles a live controller that loses its own lease during setup. This change does not find the root cause of the lease loss. The closed cause label in the next Sentry event gives that fact. ## What Changed - `server/src/services/heartbeat/run-completion.ts`: `failRunSetup` receives the execution abort signal. When the abort reason is a `LegacyControllerLeaseLostError`, it writes error code `controller_lease_lost`, adds the `controller_lease` cancellation evidence, and keeps the existing bootstrap recovery facts. The agent goes back to idle, not `error`, because the stop is a host fault. This applies only before provider dispatch: `failRunSetup` also receives `providerDispatchStarted`, and a setup-path error after a legacy adapter or native dispatch began keeps `setup_failed`, so started work is never retried. - `server/src/services/legacy-controller-lease.ts`: add the `CONTROLLER_LEASE_LOST_FAILURE_CODE` constant. - Merged with #16359 (lease-loss timings): the setup failure keeps its `resultJson.controllerLeaseLoss` timings and adds this PR's `controller_lease` cancellation from the abort signal. #16359's setup test now aborts the signal first, as `assertOwned()` does, and expects `controller_lease_lost`. - `server/src/services/heartbeat.ts`: pass the execution abort signal and `providerDispatchStarted` (`legacyAdapterEntered || nativeDispatchStarted`) to `failRunSetup`. - `server/src/services/recovery/service.ts`: add `controller_lease_lost` to the transient-infrastructure continuation codes (3 bounded attempts with backoff). - `server/src/services/heartbeat/retries.ts`: add `controller_lease_lost` to the accepted-interaction continuation retry allowlist, next to `process_lost`. Without it, a plan-approval continuation that lost its lease before dispatch was escalated and blocked before generic recovery could see it. - `server/src/services/heartbeat/run-lifecycle.ts`: add `controller_lease_lost` to the pre-adapter setup codes, so the comment policy does not queue a missing-comment retry. - `doc/run-log-events.md`: document the new error code. - Tests: setup lease loss when the abort reason is thrown, and when a setup step throws a different error after the abort. A unit test shows a lease loss after dispatch keeps `setup_failed`. A classifier test shows `controller_lease_lost` is transient and `setup_failed` stays non-retryable. Two assembled heartbeat tests (`heartbeat-process-recovery.test.ts`) lose the real lease during workspace preparation: one for a plain issue continuation (one `transient_failure` retry) and one for an accepted plan-approval interaction continuation (one `interaction_continuation_infra_retry` retry). Both check the saved run, no adapter dispatch, and the issue still `in_progress`. ## Verification - `cd server && npx vitest run src/services/heartbeat/run-completion.test.ts`: 25 passed (embedded Postgres), including the new post-dispatch test. - `cd server && npx vitest run src/services/run-cancellation.test.ts src/services/recovery/provider-failure-classification.test.ts`: passed on the first head (29 with run-completion; 25 classifier). - `cd server && npx vitest run src/services/legacy-controller-lease.test.ts`: 13 passed (needs `pnpm --filter @paperclipai/plugin-sdk... build` first). - After merging master (head `2148b27`): `run-completion`, `legacy-controller-lease`, `run-cancellation`, `provider-failure-classification` and `run-failure-report` suites, 310 passed; `heartbeat-process-recovery.test.ts -t "lease|dispatch"`, 31 passed. - Head `c52825c`: `retries`, `run-completion`, `heartbeat-retry-scheduling`, `legacy-controller-lease` and `provider-failure-classification` suites, 134 passed; `heartbeat-process-recovery.test.ts -t "lease|dispatch|interaction"`, 41 passed. - Negative controls: with the lease-loss branch in `run-completion.ts` disabled, the plain-continuation assembled test fails (`setup_failed` instead of `controller_lease_lost`). With the `retries.ts` allowlist change reverted, the accepted-interaction assembled test fails because no retry is scheduled. - Not run locally: full `tsc` and `pnpm build`. The sandbox has a 4 GB memory limit and the OOM killer stops `tsc`. CI is the typecheck and build gate. ## Risks - Low risk. The change applies only when the execution abort reason is a `LegacyControllerLeaseLostError` in the setup catch before dispatch. Other setup failures keep their current codes. - The retry uses the existing continuation recovery budgets and admission checks (agent state, budget, pause). The interaction-continuation retry keeps its existing 2-attempt budget. The retry is a new run. The revoked controller cannot dispatch, because its renewal compare-and-set fails. - A run that the reaper settles first keeps the reaper outcome. `setRunStatusIfRunning` makes the first terminal write win. - Sentry still gets this unexpected stop, with the closed `controllerLeaseLossCause` label. If the lease loss is frequent, the event volume does not change. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edits, test runs). ## 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 - [ ] I have run tests locally and they pass (targeted suites pass; typecheck/build not possible in this sandbox, see Verification) - [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: Devin Foley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3ea39f75c1 |
test: consolidate duplicate owner proofs (#16075)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
9076329149 |
test: consolidate duplicate runtime credential proofs (#16079)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5f160421e3 |
test(server): run status corpus fixtures once (#16078)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
0e1bb3748b |
test(db): retain owner nullability in the active-slot keeper (#16076)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ccbfefef5f |
test(ui): retire 33 duplicate executions and share render setup (#16072)
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8b27af77db |
fix(heartbeat): wait for a live holder of a reused shared execution workspace (#16371)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The heartbeat pre-dispatch gate decides if a run can use a shared workspace in its execution environment. > - A child task can inherit the shared execution workspace of its parent. The parent run is often still live when the child run starts. > - On a sandbox environment, the gate failed the child run with `configuration_incomplete`. It did this for every concurrency policy, also for the default `auto` policy. > - Recovery then blocked the task and told the operator to bind missing secrets. That was not the real cause. An operator had to select a different workspace by hand. > - Shared project workspaces already use the `auto`/`serialize` policy to wait through the `workspace_busy` retry path. > - This pull request applies the same policy to a reused shared execution workspace. > - The benefit: the child task waits for the parent run and then continues automatically. It does not fail and become blocked. ## Linked Issues or Issue Description **What happened?** A parent agent created a child task. The child inherited the parent's shared execution workspace. The child agent used a sandbox environment. The child run started about 1.5 seconds after the parent created the task, while the parent run was still live. The run failed before the adapter started with this error: "This environment cannot place concurrent agents in one physical shared folder. Use local/SSH sharing or isolated task workspaces." Recovery set the task to `blocked` with the message "required secret/env bindings are missing". **Expected behavior** With the default `auto` policy, the child run waits for the parent run (`workspace_busy`) and then continues automatically. This is the same behavior as for a shared project workspace on a sandbox. **Paperclip version or commit** Staging release `8ffc5748`. The same code is on `master`. **Deployment mode** Hosted cloud (staging), agent on a sandbox execution environment. **Steps to reproduce** 1. Use an agent with a sandbox environment. 2. Bind two issues to the same `shared_workspace` execution workspace. Set `executionWorkspacePreference: reuse_existing` on the second issue. 3. Keep a live run on the first issue. 4. Wake the agent on the second issue. Before this change, the run fails with `configuration_incomplete`. After this change, the run is deferred with `workspace_busy`. ## What Changed - `environment-selection.ts`: When a reused shared execution workspace has a live holder on a non-local/non-SSH environment, the gate now reads `sharedWorkspaceConcurrency`. With `auto` or `serialize`, it throws `WorkspaceBusyDeferral`. Only `allow` still fails with `shared_realization_unsupported`. - `retries.ts`: Added `findExecutionWorkspaceHolder` next to `findSharedWorkspaceHolder`. It keeps the old match rule. A running holder that has had no output for more than one hour (the existing staleness cutoff) is still returned, with `stale: true`. A live holder is preferred over a stale one. - `environment-selection.ts`: A stale holder still owns the folder, because silence does not prove that the run stopped. The child run therefore fails with `configuration_incomplete` (`shared_realization_unsupported`, `holderStale: true`). It does not share the folder with the holder, and it does not wait without limit. This is the same result as before this pull request, with a more specific message. - `retries.ts`: `WorkspaceBusyDeferral` can now carry an `executionWorkspaceId`. The run result, the run event, and the cancellation reason name the execution workspace when it applies. - `stranded-notice.ts`: Added a specific recovery notice for `shared_realization_unsupported`, and a second notice for a stale holder. They no longer tell the operator to bind missing secrets. - `doc/experimental/issue-worktree-support.md`: Documented that `allow` is only concurrent on local/SSH, and that a reused shared execution workspace follows the same rules. ## Verification - `cd server && npx vitest run src/__tests__/heartbeat-workspace-busy.test.ts -t "reused shared execution workspace"` covers 4 tests: - `auto` on a sandbox with a live holder: the run is cancelled with `workspace_busy`, a retry is scheduled, no Sentry run failure is reported, and the issue does not become blocked. - After the holder finishes, the scheduled retry is promoted and runs. The adapter gets the inherited shared folder, and the issue keeps its execution workspace. - `allow` on a sandbox: the run still fails with the shared-folder message and no retry is scheduled. - A holder that is still running but silent past the staleness cutoff: the run fails with `holderStale: true`, the adapter does not start, no retry is scheduled, and the holder is not touched. - `npx vitest run src/services/recovery/stranded-notice.test.ts src/services/heartbeat/environment-selection.test.ts src/services/heartbeat/retries.test.ts` covers the notice and the selection unit tests. - First commit (`d0b7a092`): the 3 original integration tests and the unit suites passed locally, and all CI checks passed. - Follow-up commit (`3c7e515`, which addresses the Greptile review): these tests were **not** run locally. Dependency install was killed twice by the sandbox's 4 GB memory limit. CI is the first run of the new and changed tests. - Known local failure: `does not hide ambiguous, malformed, provider, or transport cancellations behind workspace_busy` fails in this sandbox also on unchanged `master` (checked with `git stash`). This change does not cause it. - Not run locally: the full server `tsc --noEmit`, for the same memory reason. CI runs the typecheck. ## Risks - Behavior change: before, a run with a live holder of a reused shared execution workspace on a sandbox failed at once. Now it waits with `auto`/`serialize`. A long parent run can delay the child. If the holder has no output for more than one hour, the child fails as before instead of waiting without limit. - An explicit `allow` policy keeps the old failure. - Local and SSH environments do not change. - No schema or migration change. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`), with tool use and code execution in the Paperclip agent runtime. ## 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 - [ ] I have run tests locally and they pass (first commit only; see Verification) - [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: Devin Foley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
66724b8ce0 |
perf(auth): project only required run context fields (#16380)
Project only the required JSON fields for saved-run policy and direct-parent report authorization. Preserve current reads, JSON types, identity checks, permission decisions and legacy task-key precedence. Validation: 186 affected cases; 17 database transfer-budget cases after the shared startup-timeout correction; full typecheck/build; exact-head full CI, E2E, Superagent and Apex 5/5. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
d73d7a8651 |
perf(skills): batch repository dependency reads (#16377)
Batch dependency Markdown reads through the bounded Git snapshot reader and queue newly discovered dependencies once. Preserve package contents, limits, authorization, audits, and reference order. Validation: 63 affected cases; full typecheck/build; exact-head full CI, E2E, Superagent and Apex 5/5. Local Git comparison: 502 individual reads reduced to three batches with identical entries. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
32ede08918 |
fix(grok): copy pairing codes during agent reconnect (#16373)
Grok Bot reconnect showed a masked one-use code without a copy action. Add the shared Copy code control, preserve masking and copy-error feedback, and keep the code out of Bot instructions. Cover the reconnect flow and readiness wait in tests and Storybook, and update the user guide.
Verified head
|
||
|
|
ccc77c5b5e |
fix(server): record legacy controller lease-loss timings (#16359)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The heartbeat runner executes legacy agent runs, and a controller lease watchdog keeps durable ownership of each run > - The watchdog renews the lease every 10 seconds and stops the run when a renewal does not finish within the 60-second lease > - A staging run failed in setup with `LegacyControllerLeaseLostError` and the `renewal_deadline` cause, after about eight minutes of preparation and with no server restart > - The setup failure path did not record the cause, and no evidence showed why the renewal did not finish: a stalled database query or a blocked event loop > - This pull request records bounded watchdog timings with each lease loss, on the setup failure path and on the cancellation path > - The benefit is that the next event shows which of the two causes stops renewal, which is the missing fact to fix the root cause ## Linked Issues or Issue Description Refs #16084 (added the closed lease-loss cause for cancelled runs) Refs #16355 (retries a run that a restart stopped before dispatch; a different path) **What happened?** A legacy `paperclip_runner` run on staging failed with `setup_failed` and the message "Legacy controller lease lost". The stack shows the watchdog deadline timer (`renewal_deadline`). The run was in `executionStage: "preparing"` for about 467 seconds. The server started about 11 minutes before the run, so this was not a restart. The run record and the Sentry event do not show the lease-loss cause, because the setup failure path does not read it. Nothing shows if a renewal query was in flight at the deadline, or if the deadline callback ran late. **Expected behavior** When the watchdog loses the lease, the run records the closed cause and the watchdog timings. This applies when the loss fails setup and when it stops the adapter. The failure report contains only the closed cause and bounded numbers. **Steps to reproduce** 1. Start a legacy run with a controller lease. 2. During setup, make a lease renewal query hang for more than 60 seconds, or block the event loop past the deadline. 3. Let the watchdog abort the run. 4. Read `resultJson` on the failed run. Before this change, it has no lease-loss evidence. ## What Changed - `legacy-controller-lease.ts`: The watchdog tracks the last successful renewal, the renewals in flight, the scheduled deadline, and the renewal count. `LegacyControllerLeaseLostError` now carries `leaseLossTiming`: `sinceRenewalMs`, `renewalPendingMs` (or `null`), `deadlineLateMs` (only for `renewal_deadline`), and `renewalCount`. Ownership behavior does not change. - `run-cancellation.ts`: Add the `LegacyControllerLeaseLossTiming` type and `readControllerLeaseLoss()`. The reader accepts only a closed cause and non-negative finite numbers, and clamps each value to 24 hours. - `heartbeat/run-completion.ts`: Persist `resultJson.controllerLeaseLoss` with the cause and timings. This applies to a lease loss that stops the adapter and to a lease loss that fails setup (the thrown abort reason). - `run-failure-diagnostics.ts`: Report `controllerLeaseLossCause` and the four bounded timing fields from `controllerLeaseLoss`. A setup failure now gets the cause label too. - `doc/run-log-events.md`: Document the new record and how to read the timings. - Tests: watchdog timings for a stalled query, a blocked event loop, and a failing query; completion records the evidence for an adapter stop and for a setup failure; the failure report clamps values, drops unknown keys, and drops a record without a closed cause. ## Verification - `pnpm --filter @paperclipai/server exec vitest run src/services/legacy-controller-lease.test.ts src/services/heartbeat/run-completion.test.ts src/services/__tests__/run-failure-report.test.ts src/services/run-cancellation.test.ts` - I could not run these tests locally. The sandbox has a 4 GB memory limit, and `pnpm install` was stopped by the out-of-memory killer during lockfile resolution. CI is the test run for this change. - After deployment, a new lease loss shows `controllerLeaseRenewalPendingMs` and `controllerLeaseDeadlineLateMs` in the Sentry execution context. A pending time near 50 seconds or more points at the database. A large deadline lateness points at the event loop. ## Risks - Low risk. This change adds diagnostics. It does not change when the watchdog stops a run, and it does not prevent the lease loss. - The new `resultJson.controllerLeaseLoss` field is server-written. Readers ignore unknown values. Old rows do not have it. - The failure report gets five closed or numeric fields. It gets no reason text, IDs, or user content. - The event-loop test blocks the loop for about 80 ms to make the deadline late. It uses real timers, so a very slow CI host makes the lateness larger, not smaller. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use (shell, file edits, Sentry and GitHub connectors). The exact context-window size is 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 - [ ] I have run tests locally and they pass (not possible in this sandbox; see Verification) - [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: Devin Foley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3dffd2197d |
test: consolidate owner fixtures and retain real regression proof (#16047)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Tests protect sandbox execution, run recovery, credentials and the board UI. > - Several owner suites repeat the same setup and prove the same result more than once. > - These copies add maintenance work and can hide weak assertions. > - Each cut needs a retained test that proves every distinct contract. > - This pull request consolidates repeated setup and removes twelve redundant executions. > - It also replaces two weak assertions with checks of real outputs. > - The benefit is 2,831 fewer test lines with clearer regression proof. ## Linked Issues or Issue Description **What existing behavior does this improve?** The maintenance and regression strength of the existing Vitest owner suites. **Subsystem affected** Sandbox adapter utilities, server heartbeat recovery and environment capabilities, and the board UI. **Current behavior** Tests copy database rows, query builders, render calls and runtime inputs. Some cases repeat an existing contract. One token test omits a real bridge credential. A PostHog host comparison can compare absent controls. **Proposed behavior** Use small local helpers with fresh values and the same action order. Keep each distinct contract in an owner test. Check real bridge credentials and fixed PostHog method states. Carry the exact persisted first-run success assertion into the stronger cancellation keeper. **Reason and benefit** The ten test files shrink by 2,831 net lines. Twelve redundant executions retire. All other case tables, inputs, security boundaries, timeouts and cleanup rules remain. **Breaking changes** None. This round changes tests and audit evidence only. **Additional context** Refs: #15978, the merged first cleanup. Refs: #16022, the merged prior cleanup. Its squash merge is `dabb8c5daf430a1987af611e2e7ca4c7b23ef7d4`. Related open work: #14634 repairs feedback fixture completion; #14477 supplies explicit sandbox fixture tools; #14198 changes cleanup retry behavior in another heartbeat file. This audit preserves those separate action and cleanup contracts. It does not apply their changes. This PR was first stacked on `codex/test-audit-followup`. After #16022 was squash merged, only the two Round 6 commits were replayed onto merged master `dabb8c5daf430a1987af611e2e7ca4c7b23ef7d4`. The original stack head is preserved in a local snapshot branch. The current diff contains only ten test files and two evidence files. No merge is requested. ## What Changed - Consolidate repeated setup in three sandbox adapter suites. Remove seven redundant executions and retain the real protocol, cleanup and scratch-file checks. Save 875 lines. - Consolidate heartbeat database fixtures and read queries. Retain exact wake cancellation, total run count and the actual first-run success receipt. Remove one duplicate execution. Save 1,372 lines. - Remove two repeated rejected-capability cases. Carry the absent snapshot assertion into the retained runner case. Save 22 lines. - Consolidate UI fixtures and render calls. Remove two repeated connection cases. Replace the weak PostHog comparison with fixed method and required-key checks in both real hosts. Save 562 lines. - Record audit scope, decision and expansion counts, all twelve keeper mappings and deliberate mutation results in the [audit report](https://github.com/paperclipai/paperclip/blob/codex/test-audit-round-six-delivery/doc/plans/2026-10-12-test-audit-round6.md) and [controls evidence](https://github.com/paperclipai/paperclip/blob/codex/test-audit-round-six-delivery/doc/plans/2026-10-12-test-audit-round6-controls.json). ## Verification Source baseline: `a090035cafb29c06f6fca2dbe43561ad866b7c1b`. All ten original test programs are byte-identical at the stacked base `58c5c4aa241c85f4665a3159c192888bbb2a5cfa`. - Baseline: 1,841/1,841 cases passed in the main thirty-file owner/sibling run. Another 219/219 cases passed in nine extra files. - Preservation: all four proposal packages passed independent review. Whole-program helper expansion retains ordered inputs, callbacks, awaits, queries, fresh allocations and hooks outside the declared assertion migrations and repairs. - Candidate: all 2,048 cases passed across 39 complete owner/sibling files. The main run passed 1,831 cases. The extra run passed 217 cases. Both runs had zero failures and zero skips. - PostHog control: the repaired positive case passed. The original weak case passed with authentication choices removed. The repaired case failed at its fixed OAuth aria-checked assertion under the same mutation. - Eight accepted mutations failed at their intended assertions. They cover bridge-token exclusion, fallback cleanup, READY bytes, real scratch-file preservation, exact wake cancellation, the persisted first-run success receipt, rejected capability snapshots and reachable PostHog method controls. Two original weak cases passed with the same defects. All production source bytes were restored. - Rejected control: changing run status before legacy release timed out before wake cancellation. This result is not counted as assertion proof. Its replacement changed only the persisted receipt after real drain in the existing transaction. It failed at the direct fixed succeeded-row assertion. - No new code comments or 1,000-line threshold crossings were introduced. No production, schema, lockfile or workflow changes are included. On the exact final test sources, later committed as `d8de9422f0703d4508a9dc880b67a07f13e0f110`, `pnpm -r typecheck`, `pnpm check:token-gates` and `pnpm build` passed. The required full `pnpm test:run` completed with **exit 1** after **52.14 minutes** on clean, immutable `d8de9422f0703d4508a9dc880b67a07f13e0f110`. HEAD and tracked sources remained unchanged. The first general-server group ran 889 files: **882 passed, one failed and six skipped**. Its 18,032 cases were **17,925 passed, two failed and 105 skipped**. The only failing file was `server/src/__tests__/remove-test-home.test.ts`. On macOS, the read-only runtime bundle and symlink cleanup cases returned `ENOTEMPTY`. The permission-error case expects `EACCES` or `EPERM`. Four reported failure entries cover these two cases, including their cleanup errors. The test and helper are byte-identical to previous master `4b766b872993045a2e787404f0475503683e5ded` and audit master `e364b92c82`. The default wrapper stopped after that group failed. **Later local groups did not run.** The earlier public-MCP, HTTP log redaction and workspace snapshot failures did not recur. The 39 focused owner/sibling files and all 48 remote CI jobs completed independently. This result is an unresolved macOS cleanup limitation, not full local success. No test, skip, retry, timeout or cleanup rule was changed to hide it. The three adapter files received a whitespace tidy after focused execution. Full runtime AST and string/template/regex byte equality link those tested sources to the final sources. All 134 adapter helper calls were checked again. Replayed code commit `3d3defd2a60595a623045d9e2c6c586f4acb3452` has the exact final test bytes. Evidence commit `e868e6645ce0d598d756d3458f0b3d71afd6db4a` adds the report and controls JSON, with one historical ancestry clarification. All ten accepted test hashes and all seven production-owner source guards match. No package, lockfile, workspace, TypeScript, Rust or Vitest dependency manifest changed since the audit snapshot. The [original stack CI workflow](https://github.com/paperclipai/paperclip/actions/runs/38312876910) passed all 48 jobs on head `c171d6c0d603d22bb997c1f9a9bdcd5bcc5d22aa`. Those results are historical stack proof. The [fresh master-context CI workflow](https://github.com/paperclipai/paperclip/actions/runs/38318223856) completed successfully with **all 48 jobs passed** on current head `e868e6645ce0d598d756d3458f0b3d71afd6db4a`. Its tested merge commit was `41292af60c6eb60d477637d23822bb17b08dc07e`, combining workflow base `88bf4c6c1d222f818faa56257efe79207c892a6c` with that head. The delivery commits remain based on pinned master `dabb8c5daf430a1987af611e2e7ca4c7b23ef7d4`. Both required master checks, `ci / verify` and `ci / e2e`, passed. Two separate optional Storybook checks were skipped by their scope gate. [Fresh Greptile review](https://github.com/paperclipai/paperclip/pull/16047#issuecomment-6133323165) gives the current head **5/5**, with no findings, inline comments or unresolved review threads. The [current-head commitperclip review](https://github.com/paperclipai/paperclip/actions/runs/38318223666) also completed successfully. This PR remains open and draft; no merge is requested. The local macOS failure above remains unresolved. ## Risks - A helper could share a value or capture the wrong binding. Independent expansion and lexical binding checks guard the actual helper calls. - A retired case could contain a distinct assertion. Each cut has an exact keeper map and carried observations. - A mutation could fail before the intended assertion. Controls reject timeouts and earlier failures. The rejected receipt mutation remains in the evidence. - The delivery ancestry changed after the parent squash merge. Exact source hashes preserve the audited tests and producer receipts. Fresh CI and review passed in the current master context; the broad local run remains evidence from its immutable audit snapshot. - The complete local default failed in two unchanged macOS cleanup cases. Later local groups were not run. This limitation remains visible even though focused checks and remote CI passed. ## Model Used OpenAI Codex, based on GPT-6, assisted with this work. The exact served model ID and context window are not exposed in this session. It used repository tools, code execution, AST analysis and parallel audit agents. ## 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 - [ ] 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> |
||
|
|
cafa25029c |
fix(native-runtime): recover unclaimed remote startup (#16349)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The native runtime preserves task execution across server restarts. > - Remote workspace preparation can finish before the executor claims its first provider attempt. > - The recovery classifier required a provider checkpoint even when the durable coordinator proved that execution had never started. > - A deployment during this interval therefore left safe startup work on a permanent recovery hold. > - This pull request admits that narrow startup state to the existing same-run bootstrap path. Existing execution and ownership checks remain in force. > - The original preparation yields when recovery owns the coordinator. It cannot fail or clean up the recovered run. > - Tasks can continue after this interruption without an operator retry or a duplicate provider turn. ## Linked Issues or Issue Description **What happened?** A server deployment interrupted a prepared remote workspace before the native executor's first claim. The coordinator had attempt zero, controller generation zero, and no owner, process, provider event, or checkpoint. Restart classification returned `ambiguous_remote_recovery_evidence` and blocked the task. **Expected behavior** The server should recognize this durable never-claimed state and continue the original run through normal execution admission. A prior claim, uncertain ownership, or contradictory execution evidence must retain the recovery hold. **Steps to reproduce** 1. Prepare a remote workspace for a native run. 2. Stop the controller before the executor commits its first claim. 3. Restart the controller and classify the running native task. 4. Observe that the old classifier blocks it because no provider checkpoint exists. Related: #16341 preserves remote recovery failure reasons. #16344 strengthens remote restart qualification. Neither changes admission for an untouched remote startup. ## What Changed - Require a server-owned fencing version written only with fresh native identities. Older unmarked preparations stay held during rolling upgrades; caller profile data cannot add that marker to an existing run. - Leave the current server's active preparation with its existing execution. - Yield through the controller-detachment path when a different execution owns the coordinator lease. Lease expiry does not grant takeover authority. - Preserve run-scoped gateway tokens during detachment so stale preparation cannot revoke the recovered worker's tools. - Admit a valid prepared remote workspace only when the locked coordinator proves attempt and controller generation zero, no owner, and no prior session or execution evidence. - Check launch receipts and provider source events before granting bootstrap recovery. - Keep the original run and session. Preserve atomic recovery claims, executor durable-state checks, and normal admission gates. - Add real PostgreSQL regression tests for competing controllers and seven contradictory evidence cases. - Update recovery documentation, the run-log reason, and both capability maps. ## Verification - The competing-controller regressions failed before the ownership fix and pass for both live and expired foreign leases. - On the final revision, 77 runtime-selection, restart recovery, real PostgreSQL, and heartbeat boundary tests pass with no skips, including all local runner process fixtures. The full native executor file passes all 698 tests. - Another 91 live-run route tests pass locally. An earlier CI timeout in that unrelated file passed on retry; the complete final-head CI passed without that failure. - `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and `git diff --check`: passed locally. The map check verifies structure only. - Local `pnpm test:run` did not finish: an early attempt had build-related collection failures, and later full-suite execution was stopped after complete CI passed. Targeted suites passed after build preparation. This is not a local full-suite pass. - The complete [PR workflow](https://github.com/paperclipai/paperclip/actions/runs/38669996667) passed on `2baffb3652bfeb4705a30ca3706fbda6c3d72aa4`, including all test shards, build/typecheck, runner verification, and browser E2E. All 55 applicable review/security/CI checks succeeded; two Storybook checks were skipped. - [Greptile Apex](https://github.com/paperclipai/paperclip/pull/16349#issuecomment-6180848957): 5/5 on the same final head, with no unresolved findings. - No live remote provider restart is claimed by the database regression. ## Risks - A bare executor can no longer take a foreign coordinator lease after expiry. A verified recovery claim must transfer authority first. - Existing preparations without the server-owned fencing marker retain their recovery hold during rolling upgrades. - Incorrect admission could duplicate provider work. This path requires a positive durable never-claimed receipt, rejects contradictory launch evidence, and keeps the executor's existing durable-root verification. - Previously claimed or incomplete remote recovery evidence remains blocked. This change does not clear historical terminal holds. - No schema, API, dependency, or UI changes. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, code execution, and browser inspection. The exact serving snapshot ID and context window size 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> Co-authored-by: Devin Foley <devin@paperclip.ing> |
||
|
|
ecc0ab8174 |
test(e2e): require remote restart identity and copyback receipts (#16344)
Require original remote run identity, sandbox lease continuity, native receipt continuity and successful workspace finalization in the Codex Daytona controller-restart cell. Add positive and negative calibrations, including immediate rejection when the original run ends before fault injection. All current-head CI checks pass and Greptile is 5/5. Live Daytona qualification remains separate. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ff0f976de1 |
fix(native-runtime): retain remote recovery failure reasons (#16341)
Preserve closed marker-read and process-verification reasons through native recovery failures and operator reports. Keep existing transport errors and reattachment ownership checks. Add shell, process-probe, persistence and privacy regression coverage. All current-head CI checks pass and Greptile is 5/5. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3935e300dd |
fix(acpx): bound Claude MCP tool calls when runtime MCP servers attach (#16360)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Hosted `claude_local` runs use the ACPX engine. Paperclip gives each
run its runtime MCP servers (for example the `paperclip-assigned` tool
gateway) as ACP `mcpServers` entries.
> - Claude's default MCP tool timeout is far longer than a run. ACP
`mcpServers` entries have no per-server timeout field. So the agent
waits on an MCP call until the call answers.
> - Hosted error reports show runs that end with "Run exceeded the
adapter execution timeout (sandbox)". The stop-time diagnostics from
#15962 show the problem: the agent went silent about 50 seconds into the
run, three tool calls of ACP kind `other` stayed pending, and nothing
ended them until the 4h sandbox backstop.
> - The gateway bounds the remote provider call (10s default, 60s max).
But other steps on the gateway `tools/call` path have no deadline: DB
queries, row locks and pool acquisition, the credential steps before the
provider timer starts, and the stdio child exit wait. One stuck step
holds the agent turn for hours.
> - This pull request gives the agent's MCP client a deadline:
`MCP_TOOL_TIMEOUT` for ACP Claude runs that receive runtime MCP servers.
> - The benefit is that a stalled gateway call becomes an MCP error that
the model can see. The turn continues and does not spend the full 4h
execution budget.
## Linked Issues or Issue Description
- Refs #15962 (diagnostics that identified the silent turn with pending
tools)
- Refs #15448, #15456, #15850 (related gateway timeout and
connection-health work; this PR does not overlap with them)
**What happened?**
A hosted `claude_local` run sent parallel MCP tool calls. No call
answered. The run stayed silent for about 4 hours. Then the sandbox
execution timeout ended it with "Run exceeded the adapter execution
timeout (sandbox)".
**Expected behavior**
A stalled MCP call ends with an error after a bounded time. The agent
sees the error and continues.
**Steps to reproduce**
1. Start an ACP `claude_local` run that has runtime MCP servers.
2. Make the gateway `tools/call` request stall (for example, hold a lock
that the request needs).
3. See that the run stays silent until the adapter execution timeout.
**Paperclip version or commit**
`master` at
|
||
|
|
6fae6f2cb8 |
fix(wake-queue): preserve pending work when a queued run is stopped (#16357)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The wake queue releases task locks and can promote saved follow-up work when a run ends. > - An operator can stop a queued run before dispatch selects its runtime. > - The legacy release path can promote the old follow-up after that Stop. > - For an obsolete routine cycle, this can conflict with the current active cycle after cancellation has already committed. > - This pull request preserves the deferred input without promoting it at that release boundary. > - The benefit is that a queued Stop stays stopped and does not return an error from starting an obsolete follow-up. ## Linked Issues or Issue Description Related: Refs #14300 and Refs #16339 describe other pre-dispatch cancellation paths. Related PR #16238 changes former-owner wake selection. This change addresses expected operator cancellation before legacy runtime selection, without changing those contracts. **What happened?** Stopping an unstarted legacy run committed its cancellation, then tried to promote a deferred wake. When another cycle of the same routine was already active, the issue lock update failed against `issues_open_routine_execution_uq`. The cancel request returned HTTP 500 even though the run was cancelled. Without a competing cycle, the Stop launched the old follow-up. **What did you expect to happen?** Release the stopped run's own locks and preserve deferred input for a later eligible instruction. Do not start the old queue as a side effect of Stop. **Steps to reproduce** Create two cycles of the same routine. Keep the current cycle active. Give the old cycle an unstarted legacy run with a verified bootstrap record and a deferred wake. Cancel that run as a board operator, then release its issue execution. The added database regression reproduces the failed lock update before the fix. **Paperclip version / commit** Reproduced on parent commit `976cdc77ed564dc3e014621505890b647e554a7f`. **Deployment mode** A remote runtime exposed the symptom. The regression uses embedded PostgreSQL and the real wake-queue adapter. ## What Changed - Recognize an expected operator Stop only when the legacy run has no runtime-selection time, start time, process-start time, or process identity. - Use the existing release boundary to preserve deferred input without promoting it. - Add database regressions for ordinary Stop, a competing routine cycle, repeated release, provider cancellation, runtime selection, and dispatched-run reconciliation. - Document the behavior and update both recovery maps. ## Verification - Before the fix, both queued Stop cases failed. The competing-cycle case raised `issues_open_routine_execution_uq`. The three control cases passed. - `node node_modules/vitest/vitest.mjs run --project @paperclipai/server server/src/modules/wake-queue`: 7 files and 214 tests passed, including all five new database cases. - `node scripts/check-maps.mjs` and `git diff --check` passed. - `pnpm -r typecheck`, `pnpm build`, and all 10 map-script tests passed locally. The complete CI suite is green on `8e204eef87f1a593df5c183abef764e4b9eb5fd1`. The remaining serial local full-suite run was stopped once that unchanged-head CI verification passed; a local full-suite pass is not claimed. Apex review passed at 5/5 on the same head with no review threads. ## Risks - The change is limited to recorded operator cancellation before legacy runtime selection. Selected runtimes, dispatched work, provider cancellation, and native stop acknowledgement keep their existing paths. - Deferred work is retained. A later eligible instruction must still use normal admission and all current gates. - No schema migration or new authority is required. This regression is not proof of a live provider stop. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The exact serving snapshot ID and context window size 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> |
||
|
|
976cdc77ed |
fix(recovery): expose settled holds and their preserved decisions (#16169)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Task recovery preserves work when execution or tool outcomes are uncertain. > - Automatic recovery can settle its record while keeping replay blocked. > - The recovery-actions API omitted those records unless they held workspace files. > - Operators and agent tools could therefore see an empty recovery history for a task that still had an execution hold. > - This pull request lists those holds and shows their matching decision in the existing stopped-run notice. > - Existing stop verification, continuation, and file repair gates remain in force. ## Linked Issues or Issue Description **What happened?** A cancelled or failed task can retain a settled recovery record with `automaticRecovery.replay: blocked`. The task remains held, but the recovery-actions API returns no action. The board notice also lacks that record's decision. **Expected behavior** List settled execution holds that still block replay. Let an authorized board user inspect the current action and run in Recovery details. Preserve the existing guarded continuation and required-file repair paths. **Steps to reproduce** 1. Stop a run whose outcome requires inspection. 2. Let automatic recovery settle its record with replay blocked. 3. Read the task's recovery actions and open its stopped-run notice. 4. Before this change, the action list is empty unless workspace recovery is required. **Paperclip version or commit** This PR includes current master through `66424362a85`. **Deployment mode** Authenticated and local deployments with persisted execution recovery holds. The original API correction and route regression are by Tao Xie (@TaoXieSZ). This update preserves those commits and adds the board inspection path, current documentation, and regression coverage. Related: #14840 describes controller lease loss. This change exposes recovery records; it does not change controller lease renewal. ## What Changed - Include settled execution reconciliation holds with replay blocked in the company-scoped recovery-actions response. - Read the matching action from the existing stopped-run notice. Show its decision under Recovery details, including when active recovery is empty. - Reject mismatched historical records in the notice. Bind history to the current action/run and refresh visible decisions every five seconds. Keep history read errors visible beside the current guidance. - Preserve existing run inspection, new-message continuation, and required-file repair controls. No new reconciliation form is added. - Update the execution documentation and both recovery capability maps. ## Verification - Recovery route suite with real embedded PostgreSQL: 80 passed, none skipped. - Notice and retry-client suites: 36 passed. - `pnpm -r typecheck`: passed. - `pnpm build`: passed. - `pnpm check:token-gates`: passed. - `node scripts/check-maps.mjs`: passed. This checks structure only. - `git diff --check`: passed. - Full `pnpm test:run` was started. It is not yet a full local pass. Initial database tests were affected by missing packaged macOS library aliases; the aliases were restored in this worktree's dependencies, and the complete recovery route suite then passed. - All CI checks passed on `09e4461e4d3a0960a4dc8bc270a2a10c628bf524`, including the full test matrix, typecheck, build and browser checks. Optional Storybook jobs were skipped. - Apex: 5/5 on the same head. Both review threads are resolved; the reviewer confirmed the existing guarded continuation design. ## Risks - The API response now includes settled records that still block replay. Consumers must distinguish a settled record from permission to continue. - Recovery history is supplemental. A failed history read keeps the current blocker and guidance visible. - The UI binds the decision to both the current action and run. It does not certify tool outcomes or grant execution authority. - No schema, dependency, telemetry, or runtime admission changes. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution, assisted with the board inspection and verification follow-up. The exact serving snapshot ID and context window size are not exposed in this session. The original API work is retained from Tao Xie's contribution. ## 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 (targeted suites; full-suite limits 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: Devin Foley <devin@paperclip.ing> Co-authored-by: Paperclip <noreply@paperclip.ing> |