mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
ci/probe-cloud-combined
4320
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8c7c95e7d8 | Merge branch 'ci/release-chat-test-shards' into ci/probe-cloud-combined | ||
|
|
dd0e0ac59d |
fix(ci): split release chat verification into test shards
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
4919824b93 | Merge branch 'ci/docker-rust-stage' into ci/probe-cloud-combined | ||
|
|
f06005ef27 |
ci: compile the isolated Docker Runner target in pull requests
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
dc9e479448 | Merge branch 'ci/release-runner-rust-cache' into ci/probe-cloud-combined | ||
|
|
cb6e885cc5 | Merge branch 'ci/cloud-readiness' into ci/probe-cloud-combined | ||
|
|
ebc359757e | Merge branch 'ci/cloud-migrator-on-merge' into ci/probe-cloud-combined | ||
|
|
1718f4dbe8 | Merge branch 'ci/cloud-disk-headroom' into ci/probe-cloud-combined | ||
|
|
860d15aa22 | Merge branch 'ci/cloud-image-independent' into ci/probe-cloud-combined | ||
|
|
a919539049 | Merge branch 'ci/docker-tool-cache' into ci/probe-cloud-combined | ||
|
|
e8e9177335 | Merge branch 'ci/cloud-image-full-sha' into ci/probe-cloud-combined | ||
|
|
5b0417c88c |
ci: align Rust cache comments with master-only access
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c0ed4b8e45 |
ci: cache the native Runner in a separate Docker stage
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
a41b759f47 |
ci: restrict Rust cache restores to trusted master pushes
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
b5c4ba554d |
ci: cache Rust dependencies in release Runner verification
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
a84d73098c |
test: require the automatic exact-source migrator producer
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
89a01b9408 |
ci: bind readiness to successful cloud image verification
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
d8f0506d64 |
ci: add a source and artifact cloud readiness gate
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
7f8a7b644e |
ci: publish exact-source cloud migrators on merge
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
d5a0ec58fc |
test: retain independent cloud caller coverage
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
9e505b29c0 |
ci: skip cloud runner cleanup when disk headroom is ample
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
02b68fc74b |
test: follow the extracted cloud workflow in image guards
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
672da3f079 |
test: guard production metadata cache ordering
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3d3cc4941a |
ci: preserve weekly Docker tool cache across commits
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ca83970d79 |
ci: isolate concurrent cloud build cache exports
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
276f0e5c52 |
ci: pin cloud build actions to verified releases
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c6050e2e27 |
ci: build cloud images independently for each merge
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
01c9dbcd83 |
ci: publish verified full-SHA cloud image tags
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c5c80e1feb |
ci(release-verify): split server tests five ways like pr-trusted (#13185)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every master push publishes a canary through release.yml, gated by release-verify.yml — the fleet's staging deploys and the nightly/beta/stable chain all start from those canaries > - release-verify splits the server test suite across three shards with a 20-minute job cap, while pr-trusted splits the same suite across five > - The server suite grew on 2026-09-10 and the three shards moved to 17-19 minutes; that evening every push-triggered canary run was cancelled by the 20-minute cap mid-verify, and no canary published after 18:50 UTC > - This pull request mirrors pr-trusted's five-way server split in release-verify, putting shards back at the 10-15 minute range with real headroom > - The benefit is a canary lane that reports test verdicts instead of dying on an infrastructure cap ## Linked Issues or Issue Description **What happened?** Push-triggered Release runs stopped publishing canaries on 2026-09-10. Runs at 19:34, 22:30, and 22:37 UTC were all cancelled by "The job has exceeded the maximum execution time of 20m0s" on a `verify_canary / General tests (server (N/3))` shard. No canary published after 18:50 UTC, which also starves the staging fleet's continuous deploys. **Expected behavior** release-verify's server shards finish well inside the 20-minute cap and runs conclude with a test verdict, as pr-trusted's five-way split of the same suite does (10-15 minutes per shard). **Steps to reproduce** 1. Compare server shard durations in the `verify_canary` job across 2026-09-10: 11-14 minutes in the morning, 17-19 minutes from 15:06 UTC, over 20 minutes by evening. 2. Observe runs 34521169020, 34537798488, and 34538332689 cancelled at the cap. **Paperclip version or commit** `master` at `d1ba17eec` (current tip; its canary run was one of the cancelled ones). ## What Changed - `release-verify.yml`: the `general-server` matrix goes from three shards to five, byte-for-byte the shape `pr-trusted.yml` already runs, with a comment recording why. ## Verification - The identical five-way split runs green on every pr-trusted run (10-15 minutes per shard today, including on PRs merged this evening). - The suite's own growth (slower chat-connector tests) is being addressed separately; this PR only removes the artificial cliff. ## Risks - Low risk: two more runners per verify run; no test content changes. If shard durations regress further, the cap fires again — which is the correct signal once shards have honest headroom. ## Model Used - Claude (Anthropic), model ID `claude-fable-5` (Claude Fable 5), extended thinking, tool use via Claude Code CLI. ## 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 mergecanary/v2026.911.0-canary.1 |
||
|
|
2585ed0550 |
test(server): settle three contention flakes that killed canary verifies (#13186)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every master push publishes a canary through release-verify; the staging fleet and the nightly/beta/stable chain start from those canaries > - The server suite grew substantially on 2026-09-10 and now runs under real contention in CI, where three tests assert timing properties that only hold on an idle machine > - Each of the three failed a release-verify canary run that day (runs 34497348802 and 34517515849), and together with the shard timeouts (#13185) they kept any canary from publishing after 18:50 UTC > - This pull request makes the three assertions contention-tolerant without weakening the invariants they prove > - The benefit is a canary lane whose verdicts reflect the code, not the load on the runner ## Linked Issues or Issue Description **What happened?** Three server tests failed release-verify canary runs on 2026-09-10 under CI load: 1. `chat-channels.integration.test.ts › returns a retryable webhook failure when the delivery insert fails before durable receipt` — the duplicate-redelivery request drew the retryable 503 instead of an immediate 200 (run 34517515849). 2. `chat-channels.integration.test.ts › returns ephemeral guidance for exact Slack controls in channels without creating tasks or actions` — a `provider_effect` row was read before its async settlement reached `processed` (run 34497348802). 3. `runner-connection-eval-fixtures.test.ts › resets paired attempts…` — the fixture's `TRUNCATE companies CASCADE` was chosen as a deadlock victim (40P01) against the helper app's own background sweeps (run 34497348802). **Expected behavior** Verify runs fail only for real regressions. A momentary-contention 503 on a duplicate redelivery, an in-flight settlement row, and a deadlock-victim reset are all recoverable states the code handles by design. **Steps to reproduce** Run the three tests under a loaded 3-shard release-verify split; the timing assertions flake. Under `pr-trusted`'s lighter shards they usually pass, which is why the PRs that introduced them were green. **Paperclip version or commit** `master` at `d1ba17eec`. ## What Changed - The duplicate-redelivery assertion retries on 503 the way Slack itself would (bounded, 250 ms apart), then asserts the 200 and the unchanged dedup invariants: duplicate count increments, still exactly one issue. - The channel-controls settlement read is wrapped in a bounded `vi.waitFor`, the same pattern the file's durable-receipt paths already use. - The runner eval fixture retries its TRUNCATE on Postgres error 40P01, bounded at five attempts, and rethrows anything else. ## Verification - All three run green locally: the two chat tests via `-t` filters, the eval fixtures file in full (6 tests). - Each change is assertion-shape only; no product code is touched. - Observation for a follow-up, not this PR: the chat integration file costs ~15 s transform + ~28 s import per vitest worker before any test executes — splitting it would give back real shard time. ## Risks - Low risk: the retries and waits are bounded, so a genuine regression (permanent 503, settlement that never lands, persistent deadlock) still fails within the same timeouts as before. ## Model Used - Claude (Anthropic), model ID `claude-fable-5` (Claude Fable 5), extended thinking, tool use via Claude Code CLI. ## 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 |
||
|
|
d1ba17eeca |
fix(adapter-utils): fail fast when the sandbox control channel is lost mid-turn (#13158)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Adapter utilities run agent turns and report their results to the control plane > - A lost sandbox control channel can leave an agent turn without a result > - The host then waits for the full adapter timeout instead of reporting the loss > - This pull request adds a push loss signal and a bounded host wait > - The benefit is a prompt failure terminal when the agent stops answering ## Linked Issues or Issue Description **What happened?** A sandbox control channel loss during an Agent Client Protocol turn left the host waiting for the four-hour adapter execution timeout. **Expected behavior** The host should detect the terminal channel loss, stop the turn, and report a safe failure without waiting for the agent. **Steps to reproduce** 1. Start an Agent Client Protocol turn through a sandbox adapter. 2. Close the duplex control channel while the turn remains active. 3. Observe the host response before the adapter timeout expires. **Paperclip version or commit** Test the pull request commit set at `10b6bbc5525a79fd575298607dd5a25ae448fc8a`. **Deployment mode** The change applies to sandbox-backed adapter execution. ## What Changed - Add `onLoss(listener)` to the duplex bridge handle. - Register the loss listener at turn start and read losses latched before turn start. - Cancel the turn on loss and arm a 30-second host deadline. - Close the stream locally when the deadline wins and create a host terminal. - Derive the public error from the closed `DuplexLossReason` enum. - Add tests for loss order, cancellation, timeout, and safe error output. ## Verification - Run `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit`. - Run `pnpm --filter @paperclipai/adapter-utils exec vitest run src/acpx-engine/execute.test.ts -t "run-disposition seam"`. - Confirm that the full pull request workflow passes. ## Risks The new deadline changes a lost-channel path from a long wait to a host-built failure after 30 seconds. Orderly completion keeps its existing behavior. The deadline race against a pending `turn.result` has no direct test. ## Model Used OpenAI Codex, GPT-5, with tool use and code execution. The runtime does not expose a more specific deployment version 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> |
||
|
|
60ee13a0f7 |
feat: allow operator UI snippets on Cloud instances (#13168)
Adds an optional Cloud-only HTML snippet so operators can load Plain’s standard chat bubble. **6 files, 16 implementation lines added; 102 additions including tests and docs.** ## Thinking Path > - Paperclip serves Cloud and self-hosted users. > - Closed beta users need a way to report problems. > - Plain provides a ready-made chat widget. > - Cloud operators can load it through a generic deployment setting. > - Self-hosted instances ignore that setting. ## Linked Issues or Issue Description **Subsystem affected** Server-served UI HTML. **Problem or motivation** Enable a chat bubble in Cloud without adding a support feature to the React app. **Proposed solution** Insert trusted `PAPERCLIP_CLOUD_UI_SNIPPET` HTML before `</body>` when the existing Cloud-managed predicate is true. The setting is off by default. Related Cloud-gated integration: #12190. ## What Changed Review the [final diff](https://github.com/paperclipai/paperclip/pull/13168/files) in this order: 1. `server/src/cloud-ui-snippet.ts`: the eight-line Cloud gate and HTML insertion. 2. `server/src/static-index-html.ts` and `server/src/app.ts`: apply it to static root/index, SPA routes, and Vite HTML. 3. Two test files and `doc/cloud-ui-snippet.md`: boundary checks and setup instructions. React UI, customer identity, and database behavior are unchanged. The existing feedback flag remains. Plain chat is anonymous; no Paperclip name, email, or organization is supplied. ## Verification - **Greptile: 5/5**, no actionable findings, reviewed commit `04bb44515`. - **[CI passed](https://github.com/paperclipai/paperclip/actions/runs/34535763243)**, including build, typecheck, server tests, and end-to-end tests. - Local: six focused tests, full typecheck, and build passed. The full local suite has not produced a final result; CI is the completed full verification. - Staging deployment and live chat testing remain to be done. ### Staging setup Set **one server environment variable**, `PAPERCLIP_CLOUD_UI_SNIPPET`, to: ```html <script> (function(d) { var script = d.createElement('script'); script.src = 'https://chat.cdn-plain.com/index.js'; script.onload = function() { Plain.init({ appId: 'liveChatApp_01M26J213F6RR53YRARZVAFCZZ' }); }; d.head.appendChild(script); })(document); </script> ``` This is the public staging app ID. **No API key or signing secret is needed.** Deploy to staging and restart the app with this setting. Test `/`, `/index.html`, and an organization dashboard; send a message and confirm a support reply returns. Production rollout is separate. [Plain embed docs](https://www.plain.com/docs/product/channels/chat) · [Configuration and rollback](https://github.com/paperclipai/paperclip/blob/04bb4451510b124f21b6771b7a8163faad61d8ec/doc/cloud-ui-snippet.md) ## Risks Only trusted operators should set this value. The HTML is public and scripts execute in the app origin; do not include secrets or user-provided HTML. Plain owns the anonymous browser session, with no Paperclip account-switch integration. To roll back, unset the variable, restart, and refresh open tabs. ## Model Used OpenAI Codex (GPT-6), with repository inspection and code execution. Exact runtime model identifier and context 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 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> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4042eb1c48 |
test(release-smoke): follow the connect-step source question and the first-task chat (#13166)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release pipeline promotes canary → nightly → beta → stable, and the nightly lane is gated by the Docker release smoke, a Playwright walk of first-run onboarding against the exact published artifact > - Onboarding changed twice since the smoke was last updated: the connect step now opens as a model-source question (#12796, #12801), and the seeded first task now opens as a chat with the lead that deliberately creates no run until the user answers (#13068) > - The smoke still waited for an immediate "Connect" button and then polled for an assignment-triggered heartbeat run, so it failed every scheduled nightly since 2026-09-03 and blocked all nightly and beta promotions > - This pull request updates the smoke to follow the current arc: pick the Claude source tile, press Connect, launch, then assert the seeded chat greeting, the opening question card, and the absence of heartbeat runs > - The benefit is a release pipeline that can promote current master again, with the smoke asserting the product's current contract instead of a removed one ## Linked Issues or Issue Description **What happened?** The scheduled nightly lane of `release.yml` has failed every night since 2026-09-03. The `smoke_nightly / smoke` job fails in `tests/release-smoke/docker-auth-onboarding.spec.ts` at `expect(connectButton).toBeVisible()`. No nightly has published since `2026.902.0-nightly.0`, so no beta can promote recent master. **Expected behavior** The release smoke follows the current onboarding arc and passes against a healthy published artifact. The nightly lane promotes the newest green canary each night. **Steps to reproduce** 1. Run `PAPERCLIPAI_VERSION=2026.910.0-canary.5 SMOKE_DETACH=true ./scripts/docker-onboard-smoke.sh`. 2. Run `pnpm run test:release-smoke` against the container with the previous spec. 3. The spec times out waiting for a "Connect" button. The step now shows a model-source tile row first, and after launch the seeded task is a chat with no heartbeat run. **Paperclip version or commit** Reproduced against published `paperclipai@2026.910.0-canary.5`; spec updated on current `master`. ## What Changed - The spec answers the connect step's model-source question: it asserts the "Connect a model" heading, picks the Claude tile from the "Model source" radiogroup, and only then waits for the "Connect" footer button (#12796, #12801 rebuilt the step around that question). - The spec replaces the assignment-run poll with the first-task chat contract from #13068: it asserts the deterministic greeting ("Welcome to Paperclip!"), the opening question card ("What would you like to do?"), and that the lead has zero heartbeat runs, because launch must not wake the assignee before the user answers. ## Verification - Launched the CI harness locally: `scripts/docker-onboard-smoke.sh` with `PAPERCLIPAI_VERSION=2026.910.0-canary.5` (the newest canary, the one the next nightly would promote). - `pnpm run test:release-smoke` against that container: 1 passed. - The previous spec against the same container reproduces the CI failure mode first (Connect-button wait), and after the connect-step fix, the run-poll failure — both match the nightly logs. ## Risks - Low risk: the change touches only the release smoke spec. If onboarding's copy for the greeting or the question card changes, the smoke fails loudly at that assertion, which is this suite's job. ## Model Used - Claude Fable 5 (`claude-fable-5`), via Claude Code CLI, extended thinking and tool use enabled. ## 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 |
||
|
|
6728e133f8 |
chore(lockfile): refresh pnpm-lock.yaml (#13165)
Auto-generated lockfile refresh after dependencies changed on master. This PR only updates pnpm-lock.yaml. Co-authored-by: lockfile-bot <lockfile-bot@users.noreply.github.com> |
||
|
|
daea92b647 |
feat(server): accept a Cloud control assertion on the task-drain endpoint (#13125)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server has a task-drain admission hold so operators can stop new agent work and wait for quiescence before maintenance > - Cloud deploys restart tenant containers, but the Cloud control plane has no sanctioned credential for the drain routes, so agent runs are killed mid-restart > - The only Cloud credential this server trusts is the runtime identity assertion, deliberately scoped to the one-time bootstrap health call > - This pull request adds a disjoint, action-bound Cloud control assertion accepted only on the task-drain endpoint > - The benefit is that Cloud can hold new work and drain a stack before it restarts the container, through the same authorization and audit paths a human operator uses ## Linked Issues or Issue Description Refs #12485 (the task-drain admission hold this makes reachable for the Cloud control plane). **Problem or motivation** Cloud deploys restart the container without stopping agent work first. The task-drain hold from #12485 exists for exactly this, but its routes require instance-admin board authority. The Cloud control plane holds no such credential: the runtime identity assertion is accepted only on `GET /api/health`, by design. So in-flight runs die at every deploy. **Proposed solution** A second, deliberately disjoint use of the same Cloud signing key (`PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS`): a control assertion with its own JWS type (`paperclip-cloud-control+jwt`), its own audience, an `action` claim, a request id, and a short maximum lifetime. A new middleware accepts the `x-paperclip-cloud-control` header only on `/api/instance/task-drain`, binds each method to one exact action (`task-drain:read` / `task-drain:start` / `task-drain:stop`), verifies the assertion against the configured JWKS and `PAPERCLIP_CLOUD_STACK_ID`, and installs a synthetic instance-admin board actor so the existing route authorization, validation, transactional audit, and activity publishing run unchanged (audit rows record actor id `paperclip-cloud`). The header is rejected with 400 anywhere else, so it can never become an ambient credential. The board mutation guard exempts the new `cloud_control` source exactly like the other non-browser lanes. **Alternatives considered** Widening the existing runtime identity middleware would conflate a one-time bootstrap claim with a repeatable management credential and weaken both. A per-stack minted instance-admin API key would work with no auth change but adds a long-lived privileged credential per tenant to store and rotate. The action-bound short-lived assertion keeps authorization per-call and stateless. **Additional context** Self-hosted instances have no `PAPERCLIP_CLOUD_STACK_ID` and reject every assertion — the feature is inert off Cloud. A runtime identity token cannot replay as a control token or vice versa (disjoint `typ` and `aud`, covered by tests). The Cloud-side caller (drain before deploy, bounded quiescence wait) lands separately in the Cloud control plane. ## What Changed - `server/src/services/cloud-runtime-identity.ts`: `verifyCloudControlAssertion` plus the control header/audience/type/action constants, reusing the existing JWKS resolution, JWS parsing, and lifetime discipline. - `server/src/middleware/cloud-control.ts` (new): accepts the header only on the task-drain endpoint, per-method action binding, installs the synthetic instance-admin actor on success, 401 on invalid assertions, 400 anywhere else. - `server/src/app.ts`: mounts the middleware directly after the actor middleware, so a valid assertion replaces whatever actor the request otherwise resolved to. - `server/src/middleware/board-mutation-guard.ts`: `cloud_control` joins the non-browser exemptions. - `server/src/types/express.d.ts`, `server/src/services/authorization.ts`: `"cloud_control"` added to the actor source unions. ## Verification - `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/cloud-control-task-drain.test.ts server/src/__tests__/instance-settings-routes.test.ts server/src/__tests__/heartbeat-task-drain.test.ts server/src/__tests__/heartbeat-scheduling-suppression.test.ts server/src/__tests__/cloud-runtime-identity.test.ts` — 87 tests, all passing. - `pnpm --filter @paperclipai/server exec tsc --noEmit` reports no new errors against the base commit's known pre-existing set. - The new suite covers: acceptance per method, cross-action rejection, unknown-action rejection, runtime-identity-token replay rejection, wrong-audience rejection, wrong-stack and self-hosted rejection, expiry and oversized-lifetime rejection, unknown-key rejection, request id validation, endpoint containment (400 elsewhere, 400 on unbound methods), pass-through without the header, and the mutation-guard exemption. ## Risks Low risk, additive. No behavior changes without the header; the header grants nothing outside the one endpoint; each assertion authorizes one action for at most five minutes; the existing route-level validation, queued transitions, and audit writes are unchanged. The browser-facing Cloud proxy strips Cloud headers, and possession of the shared tenant-session token cannot mint an assertion (signing key never leaves Cloud). ## Model Used Claude (Anthropic) — Fable 5 (`claude-fable-5`), extended thinking, agentic tool use via Claude Code. ## 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 (module doc comments carry the contract) - [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 |
||
|
|
c1b55537ba |
fix(paperclip-runner): bump claude-agent-acp pin to 0.73.0 (#13162)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Claude local adapter can run agent turns through an ACP (Agent Client Protocol) server, `claude-agent-acp`, instead of the plain CLI > - Two separate packages each pin their own copy of that dependency: `packages/adapters/claude-local` (the server-side adapter) and `packages/paperclip-runner` (which builds the provider pack baked into every managed sandbox image) > - `claude-local` moved to `^0.73.0` in #12730, but `paperclip-runner` was never bumped past `0.70.0` — nothing keeps the two in sync when only one changes > - That split means a sandbox image built from `paperclip-runner`'s provider pack ships a `claude-agent-acp` the server-side adapter was never actually compatible with > - This pull request bumps `paperclip-runner`'s pin to `0.73.0`, the only version that satisfies both packages' declared ranges at once, and fixes the matching hardcoded version assertion in `docker/daytona-runner/Dockerfile` > - The benefit is one consistent, compatible `claude-agent-acp` version across both the server host and every sandbox image built from this source, instead of a silent split that only surfaces as a runtime failure ## Linked Issues or Issue Description No public issue exists for this specific split; opening directly per CONTRIBUTING.md path B, following the bug report template fields. **What happened?** `packages/paperclip-runner/package.json` pins `@agentclientprotocol/claude-agent-acp` at an exact `0.70.0`. `packages/adapters/claude-local/package.json` requires `^0.73.0` (added in #12730, 2026-09-02). Nobody re-synced `paperclip-runner`'s pin after that change — the two packages' dependency graphs are independent, so a bump in one doesn't propagate to the other. `paperclip-runner`'s copy is what the fleet sandbox image's provider pack actually ships, so every managed sandbox built from current source carries a `claude-agent-acp` version the server-side adapter's own declared compatibility range excludes. **Expected behavior** The two packages' `claude-agent-acp` pins should stay within a mutually compatible range, so a sandbox image built from this source always ships a version the server-side adapter actually supports. **Steps to reproduce** 1. Check `packages/adapters/claude-local/package.json`'s `@agentclientprotocol/claude-agent-acp` range (`^0.73.0`). 2. Check `packages/paperclip-runner/package.json`'s pin for the same package (`0.70.0` before this PR). 3. Note that `^0.73.0` on a `0.x` version only admits patch releases (`>=0.73.0 <0.74.0` per semver caret rules), so `0.70.0` falls outside it. **Paperclip version or commit** `master` as of this PR (paperclip-runner still at `0.70.0` prior to this change; claude-local's `^0.73.0` requirement landed in #12730). **Deployment mode** Any deployment that runs `claude_local` agents through the ACP engine against a sandbox image built from `packages/paperclip-runner`'s provider pack (managed cloud sandboxes in particular). Related PRs for context (not duplicates — none of these touch `paperclip-runner`'s pin): - #12730 — introduced the `^0.73.0` requirement in `claude-local` - #11873 — the last time `paperclip-runner`'s pin moved (`0.69.0` → `0.70.0`) - #13105 — separately made an unavailable ACP engine a hard failure instead of a silent CLI fallback, which is what turned this version split into a visible, run-blocking error rather than a quiet downgrade ## What Changed - Bump `@agentclientprotocol/claude-agent-acp` from `0.70.0` to `0.73.0` (exact pin, matching this package's existing pin style for its other agent-CLI dependencies) in `packages/paperclip-runner/package.json`. - Update the corresponding hardcoded version assertion (`test "$(claude-agent-acp --version)" = "0.70.0"`) in `docker/daytona-runner/Dockerfile` to `0.73.0`, so its own build-time check stays accurate instead of failing on the next build for an unrelated reason. - `pnpm-lock.yaml` is intentionally **not** included — `pr-trusted.yml`'s `Validate dependency resolution and regenerate stale lockfile` step already regenerates it for the merge tree and hands it to downstream `--frozen-lockfile` jobs as an artifact, so a manual lockfile commit here would just be stale the moment CI runs. ## Verification - `0.73.0` is a real published version on npm (confirmed via `npm view @agentclientprotocol/claude-agent-acp versions`), and it's the *only* version satisfying claude-local's `^0.73.0` range, so this isn't a guess at compatibility — it's the unique intersection of both packages' declared ranges. - `grep -rn "0\.70\.0" docker/ packages/paperclip-runner/package.json` after this change shows no remaining stale references to the old pin. - I did not run a full local install/test pass against a hand-updated lockfile, since regenerating one locally would conflict with leaving `pnpm-lock.yaml` untouched per the note above; CI's own lockfile-regeneration step is the intended verification path for a manifest-only dependency bump like this one. - Downstream/full verification (does a sandbox image actually built with this pin work end-to-end) is tracked separately in `paperclip-cloud` — an unrelated internal-only repo, so not linked here — where a sibling fix restores the ACP servers to the runtime `PATH` in the fleet sandbox image itself; both fixes are needed together for a working sandbox, but this PR is scoped to the version pin alone. ## Risks - Low risk: single-line dependency version bump plus a matching test-assertion update, no code changes. `0.73.0` is a patch release within claude-local's own already-declared-safe range, so there's no reason to expect it changes behavior tenants depend on. - The main risk is unknown breaking changes between `claude-agent-acp` 0.70.0 and 0.73.0 that aren't caught by the version-string assertion alone (that check only confirms the binary reports the right version, not that its behavior is unchanged). I have not audited that package's own changelog between those versions. - `docker/daytona-runner/Dockerfile` is a parallel/reference image (per its own header comment, meant to stay aligned with the private `paperclip-cloud/fleet-sandbox-image/Dockerfile`, which is out of scope here) — this PR does not touch that other Dockerfile. ## Model Used Claude Sonnet 5 (`claude-sonnet-5`), via Claude Code, with tool use (file edits, shell/git, `gh` CLI, `npm view` for version verification). No extended-thinking mode. Standard Claude Code 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 — see Verification: a manifest-only bump with the lockfile intentionally left to CI's own regeneration step; no local test run applicable - [x] I have added or updated tests where applicable — version-pin bump only, no new behavior to test - [x] I have updated relevant documentation to reflect my changes — none applicable - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green — pending CI run on this PR - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups — pending review - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
e9828f8bf4 |
fix: reuse saved model connections during agent setup (#13161)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agent setup connects each agent to a model provider. > - The organization can already hold subscription logins and API keys. > - The simplified setup flow did not consistently offer those saved credentials. > - This pull request restores reuse and selects a saved connection by default. > - Agents keep secret references, so reuse does not copy or rotate credentials. ## Linked Issues or Issue Description Related change: #13011. Searched public issues and PRs; no duplicate fix found. **What happened?** Onboarding and new-agent setup could ask for a new API key or sign-in despite an existing saved connection. A general environment auth signal could also be mistaken for the owner's saved Claude subscription. **Expected behavior** Offer saved credentials from the selected organization. Default to a saved subscription when one exists. Otherwise select a saved API key. Keep the option to enter a new key or sign in to another account. **Steps to reproduce** 1. Save a Claude or OpenAI API key, or complete a supported subscription login. 2. Add another agent with the same provider. 3. Open the provider connection step. 4. Check whether the saved credential is available and selected. **Paperclip version or commit** Reproduced on |
||
|
|
86c2e0ac4a |
feat(server): log an activity row for each queued-comment queue mutation (#13159)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server records actions that change issues and their queued comments > - The queued-comment edit, reorder, and discard routes changed queue state without activity rows > - Operators could not inspect these queue mutations in the activity feed > - This pull request adds one identifier-only activity row for each successful queue mutation > - The benefit is a durable audit trail with no comment text in the activity log ## Linked Issues or Issue Description **What existing behavior does this improve?** The queued-comment edit, reorder, and discard routes now record their successful mutations in the activity feed. **Subsystem affected** Cross-cutting (server and ui). **Current behavior** The three queue mutation routes change queued comments but do not write an activity row. The activity feed has no label for these actions. **Proposed behavior** Each successful route writes one activity row with the actor fields, entity fields, queue identifiers, and queue revision. The discard row also includes the cancelled run identifier. The activity feed shows a label for each action. **Reason and benefit** Operators need a durable record of queue changes. Identifier-only details support audit and troubleshooting without storing comment text. **Breaking changes** None. The routes keep their existing response and authorization behavior. **Additional context** Each mutation writes its activity row on the same locked transaction that applies the mutation, so the two commit or roll back together. The route publishes the live activity event only after that transaction commits. The separate comment-cancel route opts out of this write and keeps its existing single activity row. ## What Changed - Add activity rows for queued-comment edit, reorder, and discard mutations. - Include queue identifiers, revisions, ordered comment identifiers, and cancelled run identifiers as applicable. - Add activity-feed labels for the three new actions. - Add route and activity-format tests for the new behavior. - Write each activity row on the same transaction as the mutation it records, through a new port method that the adapter implements. - Keep the comment-delete route opted out of that write, so a cancellation does not log two rows. ## Verification - [x] `npx vitest run server/src/__tests__/issue-queued-comments-routes.test.ts` passes. - [x] `npx vitest run ui/src/lib/activity-format.test.ts` passes. - [x] `pnpm --filter @paperclipai/server typecheck` exits 0. - [x] `pnpm --filter @paperclipai/ui typecheck` exits 0. - [x] `node scripts/check-module-boundaries.mjs` passes. - [x] The full CI suite is green. ## Risks Low risk. The change adds activity rows after successful mutations and does not change route responses, authorization, or stored comment text. ## Model Used OpenAI Codex, GPT-5 Codex. The model used repository inspection, Git operations, and command execution. The context window and reasoning mode are not exposed by this 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 - [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>nightly/v2026.910.0-nightly.0 canary/v2026.910.0-canary.6 beta/v2026.910.0-beta.0 |
||
|
|
0d8bbf7cf4 |
refactor(server): move the queued-comment queue mutations into the wake-queue module (#13145)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server coordinates issue execution and agent wake events > - Queued comment mutations belong to the wake queue that owns their state > - Route-local database writes split queue rules across two layers > - This pull request moves those mutations into the wake-queue module and keeps route authorization and response mapping > - The benefit is one transaction boundary with company-scoped writes and a shared checked response contract ## Linked Issues or Issue Description **What existing behavior does this improve?** The queued-comment edit, reorder, and discard endpoints write queue state directly from the route layer. **Subsystem affected** server/ — REST API and orchestration services. **Current behavior** The route layer owns database transactions, locks, queue writes, and wake-row writes for queued comments. **Proposed behavior** The wake-queue module owns these operations. The routes keep authorization, input checks, error mapping, and response mapping. **Reason and benefit** The module gives all queued-comment callers one transaction boundary and applies company predicates to every adapter read and write. **Breaking changes** None. The endpoints keep their existing paths and response behavior. ## What Changed - Move queued-comment edit, reorder, and discard operations into the wake-queue module. - Add company predicates to seven queue writes. - Use the shared queue contract type for mutation responses. - Add module tests and route tests for the moved operations. ## Verification - `server/src/modules/wake-queue`: 128 tests pass across 6 files. - `server/src/__tests__/issue-queued-comments-routes.test.ts`: 19 tests pass. - The server TypeScript check reports the same 141 pre-existing errors before and after this change. - GitHub Actions must pass the required pull-request checks. ## Risks The change moves transaction and lock ownership across module boundaries. The new adapter, use-case, and route tests cover the moved behavior. No database schema changes occur. ## Model Used OpenAI Codex, GPT-5, current agent runtime, tool use and code review support. ## 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> |
||
|
|
889947c238 |
feat: add experimental native chat connectors (#13038)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - People also ask agents for work in their existing chat tools. > - Each external conversation needs one task and a current authorized source. > - Retries, Stop, and provider failures must not duplicate work or expose private data. > - The first chat PR establishes the opt-in provider and data contracts. > - This PR adds experimental channel integration and its durable control plane. > - Users can request work from connected channels and inspect delivery in Paperclip. ## Linked Issues or Issue Description Refs #13100 and #13092. This is the second of exactly two chat PRs. Foundation #13100 is merged and changed 143 files. Runner prerequisite #13092 is also merged. This PR changes 400 files against master, below the 500-file review limit. It contains no wireframe images or HTML galleries. ## What Changed - Add native Slack, GitHub, Microsoft Teams, Telegram, and Discord chat connections. Keep chat disabled unless the operator enables experimental chat connectors. Preserve the production GitHub tool connection and its normal setup path. - Bind each provider bot identity to one immutable Paperclip agent. Bind each admitted external conversation to one task. Paperclip owns tasks, runs, permissions, and audit records. - Add durable admission, per-conversation queues, questions, task controls, progress, final replies, images, files, and delivery receipts. Board comments remain internal unless explicitly sent to the channel. - Check current identity, provider reach, resource access, credentials, runtime generation, and exact source before provider effects. Keep private responses private. Never send raw reasoning, private logs, credentials, or tool arguments. - Hold uncertain sends for explicit audited resolution. Make Board Send-to-channel atomic and idempotent. Keep reconnect and setup credentials in Paperclip secret storage. - Preserve current native-runner authority across retries, lost acknowledgements, and recovery. Keep immutable input and completion contracts separate from newer user input. Receipt reconciliation cannot launch a provider. - Reconcile chat close/new ordering and provider-effect lock order. Audit resource access changes in the same transaction. Submit only the selected resource from each UI toggle so stale pages cannot undo unrelated access changes. - Drain Codex stdout before certifying process exit. Bound the drain with the existing shutdown grace. Preserve observed terminal authority without treating an undrained process as successful or reusable. - Incorporate master `018ca5da` with its ACP Stop, mobile task layout, runner packaging, and official lock changes. Preserve dedicated chat-answer continuations in both directions when ordinary queued comments are adopted after Stop. - Fence late adapter readiness behind an earlier Stop for the same run. Preserve verified cleanup for registered adapters. Handle single Stop, agent pause, duplicate Stops, and failure release without creating a false cancellation receipt. - Incorporate master's `6dd48cad4` wake-queue extraction. Preserve exact failed-chat retry authorization and lineage, retired question-source suppression, and the block on generic recovery that would discard the admitted source. Fresh deferred input retains its separate promotion path. - Incorporate master `2a05b5ed3` and its queue-admission extraction, simplified transaction ports, and separate runner CI job. Preserve exact durable receipts, actor separation, and dedicated-answer isolation through the new module. A failed receipt insert rolls back the accompanying deferred-wake merge. ## Verification Current head: `afe19299d06253cb628eb398e91d1200ea9f412a`, incorporating master `2a05b5ed3457ea33efd6895520447d1d97fe98d8`. The conflicts are resolved. This successor fixes two test-harness boundaries exposed by CI: per-case route-module preparation and actual durable-save completion before intentional runner termination. Production code and all existing test/turn deadlines are unchanged. [Exact-head Greptile review](https://github.com/paperclipai/paperclip/pull/13038#issuecomment-5587250594) is **5/5**, completed September 10 at 13:20:55 UTC, with no actionable findings or open review threads. [Fresh exact-head CI](https://github.com/paperclipai/paperclip/actions/runs/34481724341) passes **all 24 jobs**, including Build and both required aggregates. Normal exact-head guarded merge was attempted and rejected by the remaining branch approval policy: CODEOWNER review is required and no human approval is present. Normal **squash auto-merge is enabled** as of September 10 at 13:36:26 UTC. Requested CODEOWNERS have been notified; no approval bypass or self-approval was used. Earlier-head results below remain historical evidence, not qualification of this successor. - Final exact-head Linux evidence: 995/995 chat integration cases; 36/36 agent-skills routes; 35/35 runner live-session cases, including real process kill/resume; 1948 runner Vitest cases with three existing benchmark/platform guards; 870/870 API-authority cases; and 104 browser cases with four existing optional skips. Rust, conformance/replay, full repository build, typecheck, canary, all server/workspace shards, and both required aggregates pass with normal CI concurrency. Earlier failed attempts remain recorded below. - Latest test-only qualification: 141/141 route/permissions/authentication cases pass in separate cold forks, with plain server types and independent review clear. The real-runner suite passes 35/35, with plain runner types and independent review clear. A controlled premature-save acknowledgement fails as expected; matching ownership/effect/process evidence, rejected saves, real turn outcome, test abort, and pre-kill liveness are covered. No local reproduction of the original CI scheduling failure is claimed. The preceding [CI run](https://github.com/paperclipai/paperclip/actions/runs/34479680858) passes 21/24 jobs, including all 995 Linux chat cases and browser aggregate (104 passed, four existing optional skips); only Build, the skills serialized shard, and the required verification aggregate fail. Its exact-head Greptile review was 5/5. Both failed job logs are retained. - Final fixture qualification: all eight focused Discord cases and all 995 chat integration cases pass. The exact modal statement/PID is observed before taking the real connection lock; the test then proves its actual blocking relationship before mutation. Original SQL execution, provider behavior, negative assertions, and 1s/15s timeouts remain unchanged. Independent review is clear and test/production hashes remain frozen. The preceding [CI attempt](https://github.com/paperclipai/paperclip/actions/runs/34477184777) passed 22 jobs, including Build/runner, typecheck, canary, all other test shards, and browser aggregate (104 passed, four existing optional skips); the two fixture failures and failed verification aggregate remain recorded, not relabeled as a pass. - Current queue-module composition: 308/308 recovery/batching/queue/Stop tests; 995/995 full chat integration; 89/89 module tests, including real PostgreSQL receipt-insert rollback; 24/24 workflow/module-boundary tests; plain server and UI types. All four actual local process/ACP browser paths pass in 1.4 minutes. Fresh databases, no skips or retries, stable reviewed source hashes. The initial boundary failure is retained; its no-op service wrapper was removed without changing recovery context or weakening the check. An exploratory standalone test-directory typecheck fails because its new upstream transformation config is not a standalone typechecking project; standard CI/build does not invoke it, and no configuration was weakened to suppress those diagnostics. - The preceding head `e02a63d462ce5d47433b0aeb632bb6fd20aab1ba` passed [all 24 CI jobs](https://github.com/paperclipai/paperclip/actions/runs/34436462958) and exact-head Greptile review at 5/5. Required CODEOWNER review prevented its normal merge before master advanced again. - Final extracted-module composition: 307/307 recovery, batching, queue and Stop-control tests; 995/995 full chat integration; 49/49 module tests including eight PostgreSQL adapter cases; and 19/19 issue-update tests. Plain server types pass. All four actual local process/ACP browser paths pass in 1.3 minutes. Fresh databases, no skips or retries in these cohorts, frozen source hashes, and independent review clear. - The preceding head `3e4e1c1c` passes [all PR CI jobs](https://github.com/paperclipai/paperclip/actions/runs/34415826820), including Build and required `ci / verify` and `ci / e2e`. Both the original Rust failure and the previously load-sensitive lineage fixture pass with unchanged Linux concurrency. Master advanced afterward and required this reconciliation. - Final master composition: 448/448 focused UI tests, 186/186 adapter tests, 24/24 queue/control tests, and 11/11 packaging tests. Plain UI, server, shared, and adapter types pass. Token gates and diff checks pass. Independent server and UI reviews are clear. - Stop-registration regression: both real-service cases fail against exact `a95` source and pass with the fix. The full corrected recovery/control suite passes 265/265. Duplicate-owner and failed-Stop controls also pass. Plain server types pass. The readiness barrier prevents provider startup without adding an acknowledgment to an already terminal run. - Final qualification strengthens terminal-field equality and repeats both affected cases successfully on a fresh database. All four actual local process/ACP browser paths pass again in 1.3 minutes, without skips or retries. The final screenshot shows Cancelled, a paused subtree, retained input, and no error toast. - Two new actual-service regressions fail before the merge fix. They prove that queued-comment adoption could consume a dedicated chat answer or add unrelated input to that answer. The fixed four-case cohort passes, including ordinary upstream continuation and adapter Stop controls. Full recovery passes 257/257. All four actual local process/ACP Stop browser flows pass in 1.4 minutes, without skips or retries, on a fresh database. - The unchanged runner artifact was qualified with 171/171 transport tests, 870/870 API-authority tests, conformance 1/1, and replay 11/11. Six controlled reader tests prove the exit/drain repair. Its local serial Rust workspace passed 546 top-level cases plus two invoked helpers; the later passing Linux CI supplies default-concurrency evidence. - Prior exact-source full chat integration passes 995/995. Settings regressions cover concurrent stale pages, 501 destinations, pending state, rejected updates, and explicit retry. These deterministic tests do not prove live provider behavior. - Retained failed attempts and their causes are in the [qualification log](https://github.com/paperclipai/paperclip/blob/afe19299d06253cb628eb398e91d1200ea9f412a/doc/plans/chat-adapters/2026-09-08-chat-queue-and-webhook-repair.md). The first merge adapter run timed out while macOS slept for 290 seconds. Its unchanged repeat passed with a temporary sleep guard. No assertion, deadline, or CI gate was weakened. Review commands include `pnpm --filter @paperclipai/server exec vitest run src/__tests__/heartbeat-process-recovery.test.ts src/__tests__/issue-queued-comments-routes.test.ts` and `pnpm exec playwright test --config tests/e2e/playwright.config.ts tests/e2e/acp-stop-continuation.spec.ts`. Database suites require fresh disposable databases. See the [browser runbook](https://github.com/paperclipai/paperclip/blob/afe19299d06253cb628eb398e91d1200ea9f412a/doc/plans/chat-adapters/2026-09-04-chat-adapters-browser-e2e-runbook.md) for provider setup and separate live acceptance steps. ## Risks - This remains experimental. Deterministic tests and bounded live evidence do not establish every provider feature, tenant, permission layout, or media shape. Teams work-tenant qualification is still open. - Failed and uncertain provider effects remain visible and can require operator action. A transport receipt does not prove recipient visibility. - Native controller and runner artifacts must remain compatible. Preserve lease ownership, terminal authority, source binding, and quarantine during future changes. - Access and audit rows commit together, but activity notifications remain best-effort. This is not a new durable event outbox. - The PR operation does not deploy a live server, replace its runner, or change provider permissions. Remaining live qualification is documented in the [temporary handoff](https://github.com/paperclipai/paperclip/blob/afe19299d06253cb628eb398e91d1200ea9f412a/doc/plans/chat-adapters/2026-09-08-open-qualification-followups.md). ## Model Used OpenAI Codex assisted with implementation, tool execution, testing, and review. The work records `gpt-6-astra` assistance. The environment does not report a context-window size. No private reasoning traces are included. ## 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>canary/v2026.910.0-canary.5 |
||
|
|
bce976d60d |
feat: bind an agent to a Codex login whose account differs from the company default (#13067)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `codex_local` adapter signs agents in to OpenAI, and a company keeps one default Codex identity in its shared company home > - A login with a DIFFERENT account than the company default is deliberately kept out of the shared home — one agent's sign-in must not switch every unbound agent's credentials — but that left the cross-account login inert: nothing connected the agent the operator was configuring to the credential the login stored > - The stored credential and its company secret already exist; only the last mile — an agent actually using them — was missing > - This pull request reports a non-secret binding claim on the authenticated login and lets the agent page bind that one agent's `CODEX_HOME` to the account's secret, exactly and only when the identities differ > - The benefit is that multi-account Codex becomes one click on the agent that needs it, with company-wide identity untouched ## Linked Issues or Issue Description **What happened?** On an agent's detail page, "Sign in with Codex" using a different OpenAI account than the company default succeeds but changes nothing for that agent. The credential lands in the per-identity store and a company secret names it, but the agent keeps using the company default. The Test keeps reporting that authentication is needed, and no repeat login helps. **Expected behavior** When the operator deliberately signs an agent's page in with a different account, that agent starts using that account. Agents that were not part of the action keep the company default. A same-account login keeps working through the shared company home with no per-agent pinning. **Steps to reproduce** 1. Configure a company whose Codex home holds account A. 2. Open a `codex_local` agent's detail page with a sandbox environment and complete "Sign in with Codex" using account B. 3. Press Test. Before this change the agent still resolves account A and the authentication-needed check returns. ## What Changed - `packages/adapters/codex-local` — the prerequisite shield: `isCodexAuthCachePath` recognizes per-identity credential-store entries, and `seedManagedCodexHome` refuses to symlink, heal, or API-key-overwrite an entry's `auth.json`. The seeding pass runs before every probe and execute; without the shield, an agent bound to an entry would have its stored login silently swapped for the host credential. Static shared config files still copy in. Rotation already survives binding: the sandbox copy-back writes rotated credentials into the identity-keyed store slot. - `server` — the promotion records whether the company default home ended on a different account than the login (any read failure degrades to `false`, so the client can never be told to bind wrongly). After the terminal commit, the routes layer remembers a non-secret claim — the opaque account-home secret id plus that verdict — in a bounded in-memory map, and merges it into the owner read of an `authenticated` `codex_local` session. A restart drops the claim; the panel then shows plain success. - `packages/shared` — `CodexAccountBindingClaim` on the owner session response. It carries no account identifier and no credential byte. - `ui` — the login panel reports the claim upward once. The edit-mode form binds the agent's `CODEX_HOME` to the secret and saves in one step, only when `companyIdentityDiffers` is true. Same-account logins bind nothing on purpose: the company-home refresh already carried them, and an unbound agent keeps following the company default across rotations. Create mode is unchanged. ## Verification - Adapter suite: 381 passed, 1 skipped (includes the new store-entry shield tests and the path-predicate cases). - Server suites (8 files): 130 passed, 15 skipped — including two new route tests that drive a login to `authenticated` and assert the claim with both identity verdicts. - UI render suite: 85 passed — including a panel test that the claim is reported upward exactly once. - `tsc --noEmit` clean in `packages/shared`, the adapter package, and `ui`; `server` clean for the touched file. ## Risks - The bind changes one agent's configuration through the normal agent-update patch, initiated by the operator's own login on that agent's page. The failure direction of every fallback is "offer nothing": a missing claim, a restart, or an unreadable company home all degrade to no bind. - The seed shield narrows what the seeding pass may touch; homes outside the credential store behave exactly as before, covered by the existing seed tests. - Builds on the sign-in credential-resolution fix (#13064), now merged; this branch is rebased onto master and the diff contains only the binding feature. Supersedes #13066, which GitHub auto-closed when its stacked base branch was deleted on merge. ## Model Used Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended thinking, agentic tool use in Claude Code (terminal). **Related PRs (searched; no duplicates found):** #12740, #12082, and #9621 touch adjacent Codex credential sync paths; #8495 is the standing hardening effort for probe auth seeding. ## 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 (no standalone docs cover this flow; the behavioral contracts are documented in-line at each changed site) - [x] I have considered and documented any risks abovecanary/v2026.910.0-canary.4 |
||
|
|
e25a6b797f |
fix(runner): close two timing windows in the capability-live suspend path (#13143)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The Paperclip Runner manages live agent sessions and their suspend path. > - A turn-timeout promise could reject before `reconcileActiveTurn()` attached its handler. > - A short provider-drain budget could reject a valid suspend on a loaded continuous-integration host. > - This pull request closes both timing windows and adds deterministic regression tests. > - The benefit is a fail-closed suspend path that does not report false failures under load. ## Linked Issues or Issue Description **What happened?** Capability-live tests failed under load. A turn-timeout promise could raise an unhandled rejection during a slow interrupt round trip. An idle provider drain could also exceed its one-second proof budget during suspend. **Expected behavior** The suspend path must observe turn-timeout rejections and allow enough time for one provider command round trip. It must still fail closed when the runner does not prove durable suspension. **Steps to reproduce** 1. Run the capability-live tests on a loaded four-vCPU continuous-integration host. 2. Delay a `turn/interrupt` reply beyond the turn timeout. 3. Close a live session and observe the suspend barrier. **Paperclip version or commit** `01b442b2926ac2010a2fcfbda6592802472ef07f` **Deployment mode** Built from source with the Paperclip Runner test suite. ## What Changed - Attach the turn-timeout rejection handler inside `armTurnWaiter()` at promise creation. - Remove the redundant per-call-site guard in `sendMessage()`. - Use a uniform five-second provider-drain proof budget, capped by the outer preparation deadline. - Remove the unused boolean return from the provider-turn-stop helper. - Add deterministic tests for the delayed interrupt and the short close grace period. ## Verification - `npx vitest run packages/paperclip-runner/src/live/live-session.test.ts` passed locally with zero skipped tests. - `npx vitest run packages/paperclip-runner/src/live/runnerd-codex-transport.test.ts` passed locally with zero skipped tests. - The two new tests appeared in the local run output and were not skipped. - The package type-check passed locally. - GitHub Actions must confirm the full continuous-integration suite, including `Verify Paperclip Runner`. ## Risks - The provider-drain wait now allows up to five seconds before the outer deadline caps it. - The fail-closed suspend barrier remains unchanged. - The test suite still depends on the Rust runner binary for capability-live tests. ## Model Used OpenAI Codex, GPT-5. The runtime provided tool use and code execution. The runtime did not provide a context-window value. ## 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> |
||
|
|
2a05b5ed34 |
ci: split runner verification from build (#13142)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip uses GitHub Actions to verify changes before release. > - The Paperclip Runner has a separate verification boundary. > - The build job currently runs this verification before the workspace build. > - This pull request moves runner verification into its own parallel job. > - The benefit is clearer CI results and less wait time for independent work. ## Linked Issues or Issue Description **What existing behavior does this improve?** The trusted PR and release verification workflows run Paperclip Runner verification inside the Build job. **Subsystem affected** Cross-cutting (GitHub Actions CI workflows). **Current behavior** The Build job runs `pnpm --filter @paperclipai/paperclip-runner check:all` before it builds the workspace. A runner verification failure appears as a Build failure. The workspace build cannot run in parallel with runner verification. **Proposed behavior** Each workflow has a `Verify Paperclip Runner` job with the same checkout, dependency install, and command. The Build job only builds its required outputs. Both jobs run after the same gate and policy jobs. **Reason and benefit** The runner command is an independent verification boundary. A dedicated job gives it a clear status and allows it to run in parallel with Build. **Breaking changes** None. The same runner verification command still runs in both workflows. ## What Changed - Added a dedicated `Verify Paperclip Runner` job to the trusted PR workflow. - Added a dedicated `Verify Paperclip Runner` job to the release verification workflow. - Kept the Build jobs independent and retained their existing build commands. - Updated the trusted-workflow policy test for the additional dependency-install job. ## Verification - Ran `git diff --check`. - Ran `node --test ./scripts/__tests__/e2e-shard.test.mjs`. - Ran `pnpm exec prettier --check .github/workflows/pr-trusted.yml .github/workflows/release-verify.yml`. - Confirmed both jobs retain their prior runner, dependency, and policy prerequisites. ## Risks Low risk. The runner verification job repeats the existing setup. It adds one parallel GitHub Actions runner to each affected workflow. ## Model Used OpenAI Codex, GPT-5.6, 128k context window, reasoning and tool-use capabilities. ## 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> |
||
|
|
92c5c1ac3d |
fix(build): give two orphaned test setup files a governing tsconfig (#13141)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip uses separate server and UI TypeScript projects to build and test the app > - The test transform tool finds the nearest tsconfig that includes each test file > - Two test setup files had no governing tsconfig inside the repository > - The lookup then read a tsconfig outside the repository and stopped test runs when that file was invalid > - This pull request adds a server test tsconfig and includes the UI setup file in the UI tsconfig > - The benefit is stable test configuration in every repository worktree ## Linked Issues or Issue Description **What happened?** The test transform tool walked outside the repository because two test setup files had no tsconfig that included them. A stale or invalid parent checkout then stopped server and UI test runs with `TSCONFIG_ERROR`. **Expected behavior** Each test setup file must use a governing tsconfig inside the repository. Test runs must not depend on a tsconfig outside the repository. **Steps to reproduce** 1. Run the server test command in a clean worktree. 2. Run the UI test command in the same worktree. 3. Observe that the transform tool searches above the repository for the setup files when no local tsconfig includes them. **Paperclip version or commit** `04eb274fa12007392e468fc808d3ad12fbdcb02e` **Deployment mode** Built from source with the local test commands. **Installation method** Built from source with pnpm. **Agent adapter(s) involved** Not adapter-specific (core bug). **Database mode** Not database-related. ## What Changed - Add `server/src/__tests__/tsconfig.json` for the server test setup directory. - Add `vitest.setup.ts` to the `include` array in `ui/tsconfig.json`. - Keep `server/tsconfig.json` unchanged, so the build graph does not change. ## Verification - Run `pnpm exec vitest run --project @paperclipai/server server/src/modules/wake-queue/domain/policy.test.ts`. - Run `pnpm exec vitest run --project @paperclipai/ui ui/src/adapters/adapter-display-registry.test.ts`. - Run `pnpm --filter @paperclipai/server run typecheck`. - Run `pnpm --filter @paperclipai/ui run typecheck`. - Confirm that the test commands report no `TSCONFIG_ERROR`. - Confirm that the full pull request workflow passes. ## Risks This change adds one scoped server tsconfig and expands one UI tsconfig include list. It does not change application runtime code, database schema, or production build settings. Risk is low. ## Model Used OpenAI Codex, GPT-5, accessed through the Codex agent with tool use and repository execution. The model used reasoning and code inspection to assist this change. ## 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> |
||
|
|
ae0c1fbbd5 |
refactor(server): move the admission half of the deferred wake state machine into the wake-queue module (#13136)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The heartbeat service admits wake requests while an issue has an active execution run. > - That admission branch mixes wake policy, database reads, and database writes in one service. > - This structure makes the wake-queue boundary hard to test and extend. > - This pull request moves the admission policy and its database adapter into the wake-queue module. > - The result keeps heartbeat orchestration small and makes the admission behavior testable in isolation. ## Linked Issues or Issue Description **What existing behavior does this improve?** The heartbeat service now delegates deferred wake admission to the wake-queue module. The module keeps the existing merge, defer, and ordinary-wake outcomes. **Subsystem affected** server/ — REST API and orchestration services. **Current behavior** The heartbeat service contains a 146-line branch that reads wake state, chooses an outcome, and writes the result. **Proposed behavior** The wake-queue module owns the pure admission decision and the adapter reads and writes. The heartbeat service calls one module method. **Reason and benefit** This boundary reduces service coupling and lets module tests cover the admission policy. The change keeps the existing reason strings and outcomes. **Breaking changes** None. The change preserves the current behavior and public API. **Additional context** This pull request follows [PR #13132](https://github.com/paperclipai/paperclip/pull/13132), which merged the first slice of this refactor. I searched GitHub for duplicate and related pull requests before opening this pull request. ## What Changed - Move deferred wake admission policy into `server/src/modules/wake-queue`. - Add module ports and a PostgreSQL adapter for the admission reads and writes. - Keep the existing wake outcomes and stored reason strings. - Extend the module boundary check to reject service imports from the application layer. - Add unit and adapter tests for the moved behavior. ## Verification - `node --test scripts/check-module-boundaries.test.mjs` passes. - The `server/src/modules/wake-queue` suite passes 58 tests. - The eight pinned heartbeat and queued-comment tests remain unchanged and require CI verification. - Every continuous-integration check must reach a terminal green state before merge. ## Risks The refactor changes the location of wake admission logic. A missed adapter condition could change deferred wake behavior. The tests cover the policy outcomes and the adapter writes. The residual tenant-scope risk remains documented in the review record. ## Model Used OpenAI Codex, GPT-5, tool use and code execution. The implementation author ran the tests and prepared the commit set. ## 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> |
||
|
|
0bff1d5cb6 |
refactor(server): simplify the wake-queue module (#13139)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server uses a deferred wake queue to release work at the correct time > - The wake queue had repeated decisions, helpers, queries, and recovery data > - This repetition made the module harder to read and left a drain invariant implicit > - This pull request moves pure decisions into the policy layer and simplifies the queue flow > - The benefit is a smaller, clearer module with the same behavior and direct test coverage ## Linked Issues or Issue Description Refs #13136 **Problem:** The deferred wake queue carried repeated logic across the application and database layers. **Expected behavior:** The queue keeps the same wake, release, recovery, and escalation behavior after the refactor. **Solution:** Move pure decisions into the policy layer, share repeated data and predicates, and state the drain invariant in the application layer. ## What Changed - Remove the unused database port method and carry the blocked release notice kind as a typed field. - Move four pre-drain decisions into pure policy functions with table-driven tests. - Resolve the responsible user once in the application layer. - Use the canonical helper for agent invokability checks. - Share string helpers and run predicates across the module. - Split the deferred-wake decision flow and share recovery facts with a discriminator. - Bound the drain loop and throw when it processes a wake identifier twice. - Rename queue ports to describe their behavior. - Share row-loading code between stranded-issue escalation adapters. - Restore the interaction-continuation integration test case. ## Verification - Run the three wake-queue module test files. They pass 61 cases locally. - Run `pnpm check:module-boundaries`. It passes locally. - Run the `server/` type-check and confirm that no error names the changed wake-queue module or `heartbeat.ts`. - Run continuous integration and confirm that `promotes an interaction continuation after removing a coalesced self-authored comment` passes. ## Risks The change refactors queue control flow and database adapter boundaries. The main risk is a behavior change in deferred wake release or recovery. The new policy tests and the restored integration case cover these paths. The local environment cannot run the integration test because the same dependency failure occurs on the base branch. ## Model Used OpenAI Codex, GPT-5, context window not exposed by the runtime, with reasoning, tool use, and code 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>canary/v2026.910.0-canary.3 |
||
|
|
6dd48cad43 |
refactor(server): move the release half of the deferred wake state machine into a wake-queue module (#13132)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The heartbeat service releases deferred issue wakes and promotes the next run > - The release logic sat in a large service function, which made its decisions and database effects hard to test > - A promotion race could reopen an issue without creating the promoted run > - Company checks did not protect every read and write, and some readers used a second transaction connection > - This pull request moves the release logic into a layered wake-queue module and closes these race and company-scope defects > - The benefit is clearer decisions, safer writes, and focused tests while existing callers keep the same entry point ## Linked Issues or Issue Description Refs: #10195 ## What Changed - Move the release half of deferred issue execution from `heartbeat.ts` into `server/src/modules/wake-queue/`. - Add pure policy decisions with table-driven tests. - Claim a wake before the reopen write and advance to the next wake when the claim fails. - Add company predicates to guarded reads and writes. - Pass the transaction-scoped issue snapshot to reader ports. - Keep `releaseIssueExecutionAndPromote` as the public wrapper. ## Verification - Run `pnpm check:module-boundaries`. - Run `pnpm exec tsc --noEmit` inside `server/` and compare the result with the known baseline. - Run the wake-queue unit and adapter tests in continuous integration. - Check the promotion-claim ordering, guarded writes, transaction-scoped reads, and cross-company outcomes. - Search the pull request diff for internal issue identifiers. ## Risks - The refactor changes the transaction path for deferred wake release. - A stale or lost wake claim now skips that wake and continues with the next queued wake. - The public wrapper keeps its name and signature, which limits caller risk. - Continuous integration must confirm the full server test suite and build. ## Model Used OpenAI Codex, GPT-5, exact runtime model version not exposed, context window not exposed, with shell, Git, and GitHub tool use. ## 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>canary/v2026.910.0-canary.2 |
||
|
|
018ca5daaf |
fix: verify ACP Stop and preserve safe continuation (#13119)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Task controls coordinate provider execution and queued user messages. > - Stop could finish before an embedded ACP provider stopped its tools. > - A later request could be held for reconciliation without a clear task response. > - A restored provider could also retain the stopped run's API credential. > - This pull request verifies provider termination and preserves safe session continuation. > - Operators can continue known-safe work and see why uncertain work cannot start. ## Linked Issues or Issue Description **What happened?** Stop could leave an embedded ACP provider running. A queued follow-up followed by “go” could fail before it reached the provider. Task chat could show a generic missing-response message. Even a restored session could use the previous run's credential and fail its task update. **Expected behavior** Stop waits for confirmed provider termination. A later explicit wake continues the same compatible session only when recorded actions have known outcomes. It carries pending comments and the current run's environment. Uncertain actions retain a visible reconciliation hold. Composer Stop preserves the existing pause rule: conversation can continue while paused, but task work requires Resume. **Steps to reproduce** 1. Start an embedded ACP task. 2. Send a second request while the provider is running. 3. Interrupt the run, then send “go”. Also test composer Stop followed by Resume work. 4. Check that the request is delivered once and that the provider can complete the task through the current run's API credential. 5. Repeat with an unfinished write. Confirm that the write stops and that further execution stays blocked with a visible reason. **Paperclip version or commit** Built from source on master at `3bc60dd8b` plus this branch. **Deployment mode** Local source build with an isolated embedded PostgreSQL instance. Refs #11183. Refs #12552. Those changes address recovery after operator cancellation. This change also covers embedded ACP termination, session proof, pending-comment delivery, and task feedback. ## What Changed - Propagate Stop into embedded ACP and wait for bounded adapter cleanup and provider exit. Retain the actual ChildProcess object for forced termination on all platforms; never signal a recycled numeric PID. - Preserve interrupted checkpoints only for acknowledged, local, persistent sessions with settled reads or no tools. Keep writes, incomplete actions, and forced termination blocked. - Restore the same compatible provider session with the current run's environment. Reject fresh-session fallback for an interrupted checkpoint. - Adopt pending comments on the next explicit wake. Stop alone does not dispatch them. - Share the execution-blocker rule across dispatch, Resume, and task detail. Show Stopped or Couldn't start with the recorded reason. Resolve the stopped agent for the run link, including reviewer runs. - Keep execution reconciliation holds intact when generic recovery sees queued comments or healthy child tasks. - Add process, service, component, and browser regression coverage. Fix disposable database cleanup and React test settling exposed by the full suite. ## Verification - Passed `pnpm -r typecheck`, `pnpm build`, and `pnpm check:token-gates`. - Passed all three `acp-stop-continuation.spec.ts` browser journeys. They use an actual ACP child process and require task completion through the agent API. - Passed 165 adapter execution, operator-stop, and child-process control tests, 17 queued-comment route tests, and 65 tests in the two adjusted UI suites. Earlier focused recovery, heartbeat, and task-control tests also passed. - Manually used the browser to queue a request, Stop, send “go” while paused, and Resume. The same session answered once and moved the task to Done with the current run's credential. - Manually interrupted an unfinished write. Its file size stayed fixed for five seconds. “Go” showed the reconciliation reason and did not start another provider prompt. - Separate live Claude ACP smoke checks confirmed that Stop ended a disposable local write and that a no-tool interruption could resume the exact provider session. The browser fixture does not call Drive or another external app. - Passed all 5,615 UI tests and 3,090 other workspace tests. The CLI and general server groups pass with targeted retries: two transient server failures passed together on retry, and two embedded-database startup failures passed after removing abandoned shared-memory segments from this task's completed browser fixtures. All 144 serialized server suites completed, with 2,189 tests passing after two transient HTTP socket failures passed on retry. - Passed all 135 heartbeat process/recovery tests, including a deterministic regression that failed before the recovery-sweep fix. - Passed 18 dispatch integration tests, including stopped-reviewer links, company boundaries, and malformed run IDs. - Greptile is 5/5 on `7dd170d83`, with zero unresolved review threads. The security scan and all required CI gates pass for the same commit. ## Risks - Safe continuation depends on complete tool reporting and a restorable local provider session. Unknown outcomes remain blocked and require reconciliation. - Provider cleanup can take time. A timeout does not grant replay permission. - The change adds optional adapter context fields and an optional issue projection. It does not change the database schema or require a migration. - Test cleanup truncates company data only in a disposable test database. ## Model Used OpenAI GPT-6, running as Codex with repository tools, code execution, and browser interaction. The runtime does not expose a more specific model deployment 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>canary/v2026.910.0-canary.1 |
||
|
|
bd1fdc2887 |
chore(lockfile): refresh pnpm-lock.yaml (#13128)
Auto-generated lockfile refresh after dependencies changed on master. This PR only updates pnpm-lock.yaml. Co-authored-by: lockfile-bot <lockfile-bot@users.noreply.github.com>canary/v2026.910.0-canary.0 |
||
|
|
04a9f89ede |
fix(server): bundle the vendored paperclip-runner instead of hand-mirroring its deps (#13121)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server package is published to npm, but its native-runtime driver code lives in `packages/paperclip-runner`, a private workspace package that is never published > - So the server build vendors the runner's compiled code by copying it in directly, instead of taking it as a normal npm dependency > - But `cp -R` only copies code, not `node_modules`, so every npm package the runner imports has to be re-declared by hand in `server/package.json` to stay resolvable once vendored > - That hand mirroring step is silent and easy to forget: it missed `smol-toml` in #13110, and CI stayed green while production crash-looped 3 seconds into every start (#13116) > - This pull request keeps the proven `cp -R` vendor step exactly as it was, and adds a build check that derives the required dependency set from an esbuild scan of the vendored entry points, failing loudly and precisely if any package the runner actually needs isn't declared in `server/package.json` > - The benefit is the dependency list is now verified against the real module graph instead of hand-copied, so this exact class of bug cannot pass a green build again -- without changing how the runner's code is laid out on disk, which several of its modules depend on for unrelated filesystem lookups ## Linked Issues or Issue Description Refs: #13110 (introduced the `smol-toml` import that the vendor step could not resolve), #13116 (the follow-up fix for a different oversight in the same PR), #11813 (the same "vendored package installed outside the monorepo dependency graph loses a runtime dependency" failure shape, in the Kubernetes plugin installer instead of the server build) No issue exists yet for this specific incident, so per CONTRIBUTING.md option (B): **What happened?** `packages/paperclip-runner/package.json` added `smol-toml` as a runtime dependency in #13110. `server/package.json`'s existing convention (see `acpx`, `ajv`) requires mirroring every runtime dependency the vendored runner imports into `server/package.json` too, because the server build copies the runner's compiled `dist/` tree with `cp -R` -- code only, no `node_modules`. That mirroring step was missed. CI never runs the compiled server (`node dist/index.js`); it only builds it, type-checks it, and boots the app in dev mode via `tsx` against source, which never touches the vendored path. So the PR merged green, and the deployed server crash-looped in production: ``` Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'smol-toml' imported from /srv/paperclip/app/server/dist/vendor/paperclip-runner/drivers/codex/codex-startup-trust.js ``` **Expected behavior** Any npm package the vendored runner code needs at runtime should either be guaranteed present by construction, or the build should fail with a clear, actionable error before the change ever reaches a PR -- not silently pass CI and fail only once deployed. **Steps to reproduce (the original incident)** 1. Add a new runtime dependency to `packages/paperclip-runner/package.json` (e.g. a TOML parser) and use it from a module reachable from the runner's `index.ts` export graph. 2. Do not add the same dependency to `server/package.json`. 3. Run `pnpm build` in `server/` -- it succeeds. 4. Run `node dist/index.js` -- it crashes with `ERR_MODULE_NOT_FOUND` for the new package. ## What Changed - **Revision note:** the first version of this PR replaced the `cp -R` vendor step with an esbuild bundle of the runner's entry points. Greptile's review correctly caught that this broke packaged ACPX/OpenCode provider startup: several runner modules resolve sibling build artifacts via `import.meta.url`-relative filesystem paths (not JS imports) at whatever depth their source file sits at, and bundling collapses/rearranges that layout. The current version keeps the file layout untouched and only adds verification. See the second commit's message for the full explanation. - `server/scripts/verify-runner-vendor-dependencies.mjs`: a new build step that runs esbuild with `write: false` (a pure module-graph scan -- nothing is written to disk) against the runner's two entry points server actually imports (`index.js`, `testing.js`), with `packages: "external"` so its metafile reports exactly which npm packages the code needs at runtime. It fails with a precise, actionable error if any of them isn't declared in `server/package.json`'s `dependencies`. This is deliberately more precise than "mirror every dependency the runner declares": running it against this repo's real manifests shows `packages/paperclip-runner/package.json` declares dependencies (`react-markdown`, the codex/opencode CLI packages, ...) that only its unrelated `./react` and `./browser` export subpaths use -- server never imports those, so a blanket mirror rule would demand dependencies server doesn't actually need. - `server/package.json`: added the new check into the `build` script (right after the runner is built, before the expensive `tsc`/copy steps, so it fails fast), and added `smol-toml` (`^1.4.2`, matching `packages/paperclip-runner/package.json`) to `dependencies` -- the actual missing piece from #13110. The vendor step (`cp -R ../packages/paperclip-runner/dist/. dist/vendor/paperclip-runner/`) is unchanged from before this PR. - Widened `server/vitest.config.ts`'s `include` to also run `scripts/**/*.test.mjs`, and added `server/scripts/verify-runner-vendor-dependencies.test.mjs` unit-testing the pure dependency-diff function (`findMissingVendorDependencies`) against the exact shape of the `smol-toml` incident, plus a case proving an unreachable dependency (like `react-markdown`) is correctly never flagged. - Updated `server/src/__tests__/server-package-build-script.test.ts`'s existing build-script assertions to match. ## Verification - `node --check` on the new script -- syntax OK. `node -e` JSON-parsed the edited `package.json` files after every edit. - Unit-verified `findMissingVendorDependencies` directly against: nothing missing, one missing (the `smol-toml` shape), and multiple missing with stable sort order. - Ran the actual check against this repo's real `packages/paperclip-runner/package.json` and `server/package.json` (via a standalone `node` invocation, since `pnpm build` needs a Rust toolchain this sandbox doesn't have -- see below) to see its real output. It correctly reported `smol-toml`, `acpx`, and `ajv` as already satisfied, and did **not** flag `react-markdown`, `remark-gfm`, `json-schema-to-ts`, `opencode-ai`, `@openai/codex`, or the `@agentclientprotocol/*` packages -- confirming the "reachable from index.js/testing.js" scoping works as intended and doesn't demand dependencies server doesn't need. - Built a fixture tree at a real filesystem location (not just in-process) mimicking `packages/paperclip-runner`: a manifest declaring both a reachable dependency (`smol-toml`, actually imported by the fixture's `dist/index.js`/`testing.js`) and an unreachable one (`react-markdown`, declared but never imported). Copied the real script next to a fixture `server/package.json` and ran it as its own process (`node server/scripts/verify-runner-vendor-dependencies.mjs`), twice: - `smol-toml` missing from the fixture's server dependencies → the script throws with the exact intended message and exits 1. - `smol-toml` present, `react-markdown` absent → the script exits 0, proving the unreachable dependency is correctly never flagged. - Not verified locally: the real `packages/paperclip-runner` build, and therefore the check running end-to-end against its true `dist/index.js`/`dist/testing.js`. This sandbox has no Rust toolchain (the runner's own build compiles a Cargo binary) and an incomplete workspace install. CI's `Build` job (`.github/workflows/pr-trusted.yml`) runs the real thing; I'll watch it on this PR. ## Risks - The check's precision (scoping to what's reachable from `index.js`/`testing.js`, rather than every declared runner dependency) means a dependency that becomes reachable through some *other* export subpath server starts importing later would need this check's entry-point list updated too. That list is a 2-line array in the script with a comment explaining why, and matches the only two paths server/src actually imports today (verified by a repo-wide search). - This only changes a build-time check; the actual vendored file layout (`cp -R` of the runner's whole compiled tree) is byte-for-byte the same as before this PR, so there's no behavioral change to the running server beyond `smol-toml` now being present as intended. - I could not exercise the real Rust-backed build locally (no Cargo in this sandbox); see Verification. I am relying on CI's `Build` job to confirm this end to end and will fix forward if it surfaces something the fixture-based testing didn't. ## Model Used Claude Sonnet 5 (`claude-sonnet-5`), via Claude Code. Standard (non-extended) reasoning mode, with tool use (Bash, Read, Edit/Write, `gh`) for repository exploration, local esbuild-based verification against hand-built fixtures, and PR authoring. No extended thinking mode. ## 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 — see Verification: full local verification was not possible (no Rust toolchain, incomplete workspace install in this sandbox); watching CI's `Build` job on this PR to confirm. - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes — no user-facing docs describe this internal build step; none needed updating. - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green — pending, will monitor. - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups — addressed the first review round; watching for re-review. - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> |