mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-11 23:36:51 +02:00
codex/extract-heartbeat-task-context
5005
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6bf86cfdc0 |
test(heartbeat): distinguish description section from task title
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
98b0c0a728 |
refactor(heartbeat): extract task context preparation
Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
e733bddc45 |
perf(chat): stop polling provider action and session sync queues (#15822)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Chat stores pending provider actions in durable database rows. > - Three action queues still scan every second when empty. > - These scans keep idle databases active. > - This pull request wakes those queues after a commit or at their next deadline. > - Empty queues stop querying while existing recovery rules remain in place. ## Linked Issues or Issue Description Refs #15808, #15802, #15625. Related sleep work: #15750, #15757. **What existing behavior does this improve?** Provider messages and notices, accepted GitHub webhook receipts, and Slack session status synchronization. **Current behavior** Chat maintenance scans these three queues every second. It also rechecks paused Slack sync rows every 30 seconds. **Proposed behavior** Reuse the transaction-aware action workers and existing chat_actions rows. Wake after commits. Restore unfinished work on startup. Use stored retry and stale-claim deadlines. Stop scanning when empty. Park paused Slack sync rows until an endpoint change. ## What Changed - Add three topics to the existing action worker registration. No tables, migrations, triggers, or external services. - Signal producers, claims, retry updates, terminal settlements, and operator resolution inside their owning transaction. Provider I/O remains outside transactions. - Share pending-state and deadline predicates between dispatch and scheduling. Exclude terminal history and uncertain provider sends. - Preserve GitHub receipt attempt fences and provider-send quarantine. Preserve Slack's 30-minute refresh while a session is processing. - Remove these workers from periodic app maintenance. Update the sleep inventory and add regression coverage. ## Verification - Passed: 13 focused tests across scheduler, app wiring, and real PostgreSQL integration. Covers actual commit wakes with deferred fast paths disabled, GitHub retries and startup recovery, stale-send quarantine, Slack publication-to-sync delivery, paused deadlines, and idle queues. - Passed: pnpm typecheck. - Passed: full chat integration and related coordinator suites, **1,274 tests across five files**. - Passed: pnpm build. - Greptile: **5/5**, no actionable findings, completed on `dc284cd275e5f6df624d60b27954421f2bcdbee2`. - Hosted CI: **54 checks passed**, two intentionally skipped Storybook checks, no failures or pending checks on `dc284cd275e5f6df624d60b27954421f2bcdbee2`. Provider responses are simulated. PostgreSQL, transactions, service dispatch, and scheduling are real. No live Slack or GitHub App was used. ## Risks - Writers must emit the existing process-local transaction signal. Independent database clients and direct SQL still need explicit integration or startup recovery. - Accepted GitHub receipts are covered. Finding callbacks GitHub never delivered still uses the separate provider recovery lane. - Other chat maintenance and persistent transports still run. This does not establish whole-instance sleep. - Existing claim, revision, credential, and authorization checks remain authoritative during concurrent foreground and scheduled dispatch. ## Model Used OpenAI Codex (GPT-6), with repository inspection, code execution, and automated tests. ## 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.1011.0-canary.7 |
||
|
|
30e338fba6 |
refactor(heartbeat): extract environment selection (#15825)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Heartbeat execution selects an environment before it prepares a workspace and starts an agent. > - Workspace preparation now has its own module, but its selection policy still occupies the executor. > - Environment defaults, recovery bindings, chat isolation, and workspace contention must retain their order. > - This pull request moves that selection phase behind one typed function. > - The executor keeps dispatch gates and lease cleanup. Tests cover the public path and the new boundary. ## Linked Issues or Issue Description Refs #15807. This continues the heartbeat extraction series after workspace preparation. **Current behavior** The 5,599-line heartbeat service contains a 301-line environment selection phase inside run execution. **Proposed behavior** Move that phase to `heartbeat/environment-selection.ts`. Keep the same policy, statement order, errors, and public exports. **Reason and benefit** Readers can find selection policy in one module and follow the executor's phases without reading each policy branch. ## What Changed - Add `selectHeartbeatEnvironment` with typed run, task, policy, configuration, and service inputs. Return the values needed by configuration and workspace preparation. - Preserve native recovery bindings, environment precedence, managed sandbox enforcement, Kubernetes provisioning, native chat isolation, and shared workspace contention. - Reduce `heartbeat.ts` from 5,599 lines / 234,599 bytes to 5,314 lines / 220,784 bytes. The new module is 402 lines / 18,215 bytes. - Add six public-path characterization cases before moving production code and six boundary cases. Repair plugin-test teardown to drain active execution and call the database cleanup helper. - Assert the selected local environment in the browser fixture's real worker and document the new boundary. ## Verification - Before the move: 71 tests passed, including all six new public-path cases. Three plugin tests skipped when the host could not start their database probe. - After the move: all 112 focused tests passed across eight files, with no skips. These cover environment policy, local and plugin execution, contention, recovery bindings, workspace preparation, chat isolation, and low-trust directories. - Passed `pnpm -r typecheck` and `pnpm build`. - A normalized TypeScript AST comparison confirms the 301 moved lines and remaining executor statements are unchanged, apart from the new call and imports. - Browser acceptance: the task UI recovered automatically and the worker verified its selected local environment, preserved uncommitted files, and completed the task. The persistent-failure case passed in isolation: three total runs, then a blocked task that remained blocked after reload. - The first persistent-failure browser attempt missed the retry banner within five seconds, despite a persisted scheduled retry. Its unchanged isolated rerun passed. The trace is retained; the intermittent UI failure is not yet attributed to a root cause. No assertion or timeout was relaxed. - Greptile reviewed `20953dd164decb565bc8d85081aad31a23fd33e5`: 5/5, no actionable findings. - Hosted CI passed on `20953dd164decb565bc8d85081aad31a23fd33e5`: 52 successful checks and two intentionally skipped Storybook checks, with no pending or failing checks. This includes all general and serialized test groups, Runner verification, eight browser shards, typecheck, and build. - The duplicate local `pnpm test:run` was interrupted after hosted CI completed. It is not reported as a local full-suite pass. Local completed checks are the 112 focused tests, typecheck, build, and browser cases described above. ## Risks - This selection phase enforces execution restrictions. A wrong input or import could select the wrong environment or change retry behavior. Public-path tests cover refusal, redirect, contention, and dispatch; boundary tests cover recovery and isolation. - The helper can provision a managed environment row and add concurrency notes to the supplied task context. It acquires no execution lease. The executor retains its catch/finally boundaries and resource ownership. - Kubernetes selection is tested with real database state and bootstrap settings. These checks do not claim execution against a live Kubernetes cluster or hosted sandbox provider. - No schema, migration, API contract, or intended behavior change. ## Model Used OpenAI Codex (GPT-6), with repository inspection, code editing, compiler checks, database integration tests, and browser automation. The exact serving model ID and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.1011.0-canary.6 |
||
|
|
de9ab8e7e0 |
perf(runner): compile the TypeScript surface once per build (#15853)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Pull requests to this repository run a large CI matrix. The slowest check sets the time a contributor waits for a green run. > - After #15849 hid the verifier's downloads behind package staging, the `Build` lane is still the slowest check in five of the eight fully green PR runs created after that merge (535s to 581s; the top server shard is 529s to 560s in the other three). `Build` is about 100s of setup, 160s to 176s of `pnpm build`, and 265s to 312s of the public install verifier. > - Inside `pnpm build`, every package after `@paperclipai/shared` waits on the Runner: its `build` script takes 76s to 80s, and for 65s of that it is the only job running. The chain runs `build:typescript` three times: once directly, then again inside `check:semantic-contracts` and `check:runner-workflow-traceability`, which rebuild first so they work standalone. The server's `prepare:runner-vendor` then runs the whole Runner build a second time, so the job pays for four redundant TypeScript passes. > - Each pass is two `tsc` projects, the eval-kernel rebuild, and the schema checks, 7s to 8s on the CI runner. The dist they rebuild is the dist the first pass just wrote; nothing between the passes changes it. > - This pull request calls the two check scripts directly after the chain's own `build:typescript`, the way `generate-replay-goldens.mjs --check` already does in the same line. The standalone `check:*` scripts keep their rebuild. > - The benefit is about 30s off the `Build` job's critical path, about 15s off the Typecheck job and every Docker or release build that runs the server build, with no change to what is checked. ## Linked Issues or Issue Description **Describe the enhancement** The `Build` PR check is the slowest check in most green PR runs. Its `pnpm build` step compiles the Runner's TypeScript surface four times: three passes inside one Runner `build`, and a second full Runner `build` from the server's `prepare:runner-vendor`. Only the first pass produces a dist that the later steps read; the other three rewrite the same output. **Why is this needed** The slowest check decides the wall-clock time of every PR run. In the eight fully green PR runs created after 2026-10-11 04:10Z, `Build` topped five of them at 535s to 581s. The Runner build sits alone on the `pnpm build` critical path for about 65s, and the server build repeats it. From the job logs of four of those runs, the second and third `build:typescript` passes cost 7s to 8s each, in both Runner builds, so about 30s per job. **Proposed solution** In the Runner's `build` script, replace `pnpm run check:semantic-contracts && pnpm run check:runner-workflow-traceability` with `node scripts/generate-semantic-contracts.mjs --check && node scripts/check-runner-workflow-traceability.mjs`. Both scripts read `dist/`, which `build:typescript` wrote earlier in the same chain, and the steps between them are `--check` runs that write nothing to `dist/`. Add a guard test so the chain compiles TypeScript exactly once and both checks still run after it. **Alternatives considered** - Skip the server's `prepare:runner-vendor` rebuild when `pnpm -r build` already built the Runner. That rebuild is what makes `pnpm --filter @paperclipai/server build` correct standalone (the Dockerfile uses it), and the server's build-script test pins the command. A freshness check would be a larger semantic change; this PR shrinks the rebuild instead of removing it, and the next cycle can measure what remains. - Make `tsc` incremental across the passes. It would still re-run the schema checks and the eval-kernel build each time, and would add build-info files to the package. - Change `check:semantic-contracts` and `check:runner-workflow-traceability` themselves to stop rebuilding. They are documented standalone commands (`pnpm --dir packages/paperclip-runner check:semantic-contracts` in the capability docs) and must work from a stale dist; unchanged here. ## What Changed - `packages/paperclip-runner/package.json`: the `build` script runs `node scripts/generate-semantic-contracts.mjs --check` and `node scripts/check-runner-workflow-traceability.mjs` directly, after its own `build:typescript`, instead of the `check:semantic-contracts` and `check:runner-workflow-traceability` wrappers that rebuild first. Every other step, its order, and the standalone `check:*` scripts are unchanged. - `server/src/__tests__/server-package-build-script.test.ts`: a new test in the suite that already pins the server's Runner vendoring reads the Runner's `build` script, resolves every `pnpm run` step, and asserts that exactly one step compiles TypeScript (directly or through a wrapper), that both check scripts are in the chain, and that both come after `build:typescript`. It fails against the previous script with `expected [ 'build:typescript', …(2) ] to deeply equal [ 'build:typescript' ]`. ## Verification - `pnpm --filter @paperclipai/server exec vitest run src/__tests__/server-package-build-script.test.ts`: 9 pass (1 new). With the `package.json` change stashed, the new test fails as described above and the other 8 pass. - In `packages/paperclip-runner`, the new chain without the cargo step (`check:protocol-manifest`, `build:typescript`, `check:capability-contract`, `check:capability-inventory`, `check:protocol-coverage`, `generate-semantic-contracts.mjs --check`, `check-runner-workflow-traceability.mjs`, `generate-replay-goldens.mjs --check`, `generate-semantic-action-catalog.mjs --check`) exits 0: `Runner stress traceability passed: 44 findings, 12 workflows, 1 explicit exclusion.` and `Replay golden snapshots and parity summaries are current.` Cargo is not installed on the host that produced this PR, so `build:binary` was not run locally; it is unchanged and runs in this PR's `Build` job. - `pnpm run build:typescript` alone takes 5.8s to 5.9s on this host, so each removed pass is in the range the CI logs show. - This PR's own `Build` job runs `pnpm build` from the branch checkout, so its log shows the new chain in both Runner builds. Expected on that job: `pnpm build` about 130s to 146s (was 160s to 176s on the four measured runs), `Build` about 505s to 551s (was 535s to 581s). **Measured on the four post-#15849 `master` runs that motivated this PR** (`Build` job logs): | Run | `pnpm build` | Runner build in `pnpm -r build` | Extra `build:typescript` passes in it | Runner rebuild in server build | Extra passes in it | | --- | --- | --- | --- | --- | --- | | 38112764439 | 169s | 76s | 04:51:52 and 04:52:00 (about 14s) | 04:53:12 to 04:53:41 | 04:53:26 and 04:53:34 (about 15s) | | 38111191543 | 176s | 79s | 04:22:40 and 04:22:48 (about 14s) | 04:24:04 to 04:24:34 | 04:24:18 and 04:24:26 (about 15s) | | 38110914319 | 160s | 75s | 04:19:07 and 04:19:14 (about 14s) | 04:20:25 to 04:20:53 | 04:20:39 and 04:20:46 (about 14s) | | 38110897745 | 172s | 80s | 04:15:16 and 04:15:25 (about 15s) | 04:16:41 to 04:17:11 | 04:16:55 and 04:17:03 (about 15s) | ## Risks - Low risk. The same two checks run against the same dist, in the same position in the chain. The only difference is that the dist is not rewritten twice between them. - If a future step between `build:typescript` and the two checks starts writing to `dist/`, the checks would read that output instead of a fresh rebuild. The steps there today (`check:capability-contract`, `check:capability-inventory`, `check:protocol-coverage`) are `--check` runs that only compare generated spec files. - The standalone `check:semantic-contracts` and `check:runner-workflow-traceability` scripts still rebuild first, so documented usage is unchanged. - The guard test lives in the server's suite because that suite already pins the Runner vendoring contract and runs in the server shards on every PR. ## Model Used - Claude (Anthropic), model ID `claude-fable-5-1`, running as a Paperclip agent through the Claude local adapter with tool use (shell, file edits, GitHub CLI). The agent collected the CI data, made the change, ran the tests, and wrote this description. ## 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) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>nightly/v2026.1011.0-nightly.0 canary/v2026.1011.0-canary.5 |
||
|
|
b36960b758 |
fix(server): permit verified question-delivery history to sleep (#15851)
Treat completed question-response deliveries as history only after their exact same-company handoff finishes. Preserve missing evidence, retries, accounting debt, and idle-sleep fences. Add a concurrent all-state question history index with interrupted-build repair. Keep migrations serialized without waiting snapshots that deadlock concurrent index builds. Validated by 118 focused sleep tests, six migration/snapshot tests, full repository typecheck, all CI gates, and Apex 5/5. Co-Authored-By: Paperclip <noreply@paperclip.ing>canary/v2026.1011.0-canary.4 |
||
|
|
42ecc96556 |
perf(ci): prefetch the consumer image and Grok binary during package staging (#15849)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Pull requests to this repository run a large CI matrix. The slowest check sets the time a contributor waits for a green run. > - After #15826 leveled the server shards and #15831 split `workspaces-b`, the `Build` lane is the slowest check: 634s in run 38107578322 (2026-10-11 03:11Z), ahead of the next server shard at 574s. It was 533s in run 38107430861 and 543s to 568s in earlier runs that night. > - `Build` is about 100s of setup, 148s to 195s of `pnpm build`, and 278s to 320s of `scripts/verify-grok-npm-install.mjs`. The verifier stages and packs the public packages first (84s to 100s of CPU work), and only then pulls the pinned `node:24-trixie` consumer image (8 layers, 440 MB compressed) and downloads the Grok binary (65 MB gzip, 166 MB verified). Both network waits sit after the staging work on the critical path. > - Neither download depends on the packed packages. The image is pinned by digest and the Grok binary is checked against its pinned sha256 by the provisioning script, so starting them early changes no verified property. > - This pull request starts both downloads as background children before staging and joins them where they are needed: the image before the first sandbox, the binary after the negative probe. It also prints one timing line per phase so the next slow part is visible in the CI log. > - The benefit is that the whole pull and the whole Grok download hide behind the staging phase. The verifier should shed the full pull time on a fresh runner, and the next cycle can read the phase split instead of inferring it from log gaps. ## Linked Issues or Issue Description **Describe the enhancement** The `Build` PR check is now the slowest check in the run. Its last step, the public npm install verifier, pulls the consumer Docker image and downloads the Grok binary only after it has finished staging and packing the eighteen public packages. Both downloads could run while the packages are staged. **Why is this needed** The slowest check decides the wall-clock time of every PR run. In the most recent fully green run (38107578322), `Build` took 634s: `pnpm build` 195s and the verifier 320s. The verifier's log shows the staging phase ends at +100s and the Grok result arrives at +267s. The image pull and the Grok download are inside that second window, in series with the consumer install and the probes. **Proposed solution** Start `docker pull --platform linux/amd64 <pinned image>` and `provision-grok.mjs` as background children at the top of the verifier, before the staging loop. Await the image right before the first sandbox call. Provision Grok into a prefetch directory and rename it into `native/grok` only after the "npm must not provision Grok" assertion and the negative probe, so that assertion keeps its meaning and only the positive probe sees the binary. Print a `paperclip.public-npm-install.timing.v1` line with wall time per phase and the time the main flow waited on each prefetch. **Alternatives considered** - Run the verifier as its own job in parallel with `Build`. It needs the full `pnpm build` output, so that job would be as long as `Build` is now. - Warm the consumer npm cache from an Actions cache. That changes the "clean public npm install" property the verifier reports. Not done here; the new timing line will show whether the consumer install is worth that discussion. - Pack the eighteen packages concurrently. The three bundled packages run their own npm installs in series inside `prepareBundledPackage`, which is synchronous. A larger restructure; left for a later cycle with timing data. - Overlap the Pi runtime setup with the Grok probes. Both use the same consumer directory from separate containers, and the probes after provisioning are short. Not worth the concurrency on shared state. ## What Changed - `scripts/prefetch-child.mjs` (new): `startPrefetch({ name, cmd, args, cwd, env, logPath })` spawns a background child with no inherited terminal and its stdout and stderr in a log file, and returns `{ name, child, done, durationMs }`. `done` resolves on exit 0 and otherwise rejects with the tail of the log; the rejection is observed inside the helper, so an unawaited failure never becomes an unhandled rejection. `durationMs` ends at the child's last write to its log (the exit event is observed late when the caller is blocked in synchronous work; both downloads print their final status line as they complete). `stopPrefetches(prefetches, { graceMs })` sends `SIGTERM` to every child still running, escalates to `SIGKILL` after the grace period, and resolves only once all of them have exited. - `scripts/verify-grok-npm-install.mjs`: the image pull and the Grok provisioning start through the helper inside the `try` block, before the staging loop. The main flow awaits the image before the first `npm install` sandbox and awaits Grok after the negative probe, then renames the staged binary into `native/grok` before the positive probe. The `finally` block awaits `stopPrefetches` and only then removes the scratch root, so cleanup never races a child's writes. The script prints one timing JSON line after the Pi probe, with the per-phase wall times, the two `*_wait_ms` values, and the corrected `*_prefetch_ms` values. - `scripts/__tests__/prefetch-child.test.mjs` (new): seven tests run small local Node children, with no Docker or network: a successful prefetch resolves and keeps its output; the duration ends at the download even when the parent is blocked for 1.5s; a nonzero exit rejects with the log tail; a command that cannot start rejects instead of hanging the join or the stop; stopping a running child waits for its exit; a child that ignores `SIGTERM` is killed after the grace period; an unawaited failure does not produce an unhandled rejection in a fresh process. - `scripts/__tests__/grok-public-install-sandbox.test.mjs`: the source test asserts that exactly the pinned image is pulled for `linux/amd64`, that Grok is provisioned into the prefetch directory and never straight into `native/grok`, that both prefetches start before staging, that the image is joined before the first sandbox, that the rename happens after the npm assertion and the negative probe and before the positive probe, that the verifier imports the helper, and that `stopPrefetches` is awaited before the single `rmSync(root, ...)`. - `package.json`: `test:release-registry` runs the new test file. ## Verification - `node --test scripts/__tests__/prefetch-child.test.mjs scripts/__tests__/grok-public-install-sandbox.test.mjs scripts/__tests__/cursor-public-install-sandbox.test.mjs scripts/__tests__/retain-runner-qualification-packages.test.mjs`: 22 pass (7 new in `prefetch-child.test.mjs`, 12 in the sandbox file). The new file passed on three consecutive runs. - `node --check scripts/verify-grok-npm-install.mjs` passes. - `node packages/paperclip-runner/scripts/provision-grok.mjs <scratch>/prefetch/grok` on this host: `Verified Grok 1.0.13 (linux-x64)` in 1.0s, `native/grok` absent before the move, 166079904 bytes in place after it. - Docker is not installed on the host that produced this PR, so the verifier was not run end to end locally. This PR's own `Build` job runs `node scripts/verify-grok-npm-install.mjs` from the branch checkout, so it exercises the change in full. **Measured on this PR's first CI run** ([38108964834](https://github.com/paperclipai/paperclip/actions/runs/38108964834), created 03:37Z), against two `master` runs created in the same twelve minutes: | | 38108878166 (`master`, 03:35Z) | 38108995800 (`master`, 03:37Z) | 38108964834 (this PR, 03:37Z) | | --- | --- | --- | --- | | Verifier step | 307s | 248s | 219s | | `Build` job | 555s | 484s | 459s | | Slowest check in the run | `Build` 555s | server (8/12) 535s | server (12/12) 547s | The PR run's timing line: `stage_packages_ms 84464`, `image_wait_ms 1`, `consumer_install_ms 97305`, `lifecycle_rebuild_ms 3545`, `codex_probe_ms 1211`, `grok_wait_ms 0`, `grok_probes_ms 626`, `pi_setup_ms 22194`, `pi_probe_ms 7753`. Both waits are at most 1ms, so the staging phase hid both downloads in full. The window from the end of staging to the Grok result went from 161s to 167s on the two runs that motivated this PR to 102s here, so the hidden downloads were about 60s on a fresh `runs-on` spot instance. Against the two same-window `master` runs, the verifier step is 29s to 88s shorter and `Build` is 25s to 96s shorter; the spread is runner variance in `pnpm build` and the consumer install. The `image_prefetch_ms` and `grok_prefetch_ms` values on that first run (84550 and 186696) were the parent's late observation of each exit, not download times; that is the first Greptile finding, fixed by the second commit, which measures from the download's last output instead. ## Risks - Low risk. The verifier proves the same properties in the same order. The only ordering change is that the downloads start earlier; every assertion, probe, and sandbox argument is unchanged. - The Grok binary is written under the scratch root in a `prefetch` directory during staging. That directory is never mounted into a container, and the `native/grok` assertion still runs against an absent path. - A prefetch that fails early now fails the step at its join point, where the old code would have failed at the same download a few seconds later. Same outcome, same message source. - `*_prefetch_ms` is a last-output time. A child that printed early and then kept working silently would be under-reported; neither `docker pull` nor `provision-grok.mjs` behaves that way (both print their final status as they finish), and a silent child falls back to the observed exit time. - Cleanup now waits up to 5s for a child that ignores `SIGTERM` before killing it, so a failing run can end up to 5s later than before. Both children exit promptly on `SIGTERM` in practice. - The timing line is one more stdout line. Nothing in the repository parses the verifier's stdout; the two workflows that run it write the output to the job log or to a file. ## Model Used - Claude (Anthropic), model ID `claude-fable-5-1`, running as a Paperclip agent through the Claude local adapter with tool use (shell, file edits, GitHub CLI). The agent collected the CI data, made the change, ran the tests, and wrote this description. ## 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) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>canary/v2026.1011.0-canary.3 |
||
|
|
8dd381f5dd |
perf(ci): run the db project as its own workspaces-c lane (#15831)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Pull requests to this repository run a large CI matrix. The slowest
check sets the time a contributor waits for a green run.
> - The `General tests (workspaces-b)` lane runs every non-server Vitest
project except `ui` and `cli` in one job, one project after the other.
After #15826 leveled the server shards, this lane became the slowest
check: 593s in run 38084171761, 523s in 38083084276 and 499s in
38083020834 (all 2026-10-10).
> - The `@paperclipai/db` project alone is 168s to 250s of that lane's
436s to 513s of vitest time. Its `client.test.ts` suite is 117s to 189s
and `backup-lib.test.ts` is 70s to 107s. The other seventeen projects
together are only 263s to 276s.
> - Vitest's native `--shard` does not level this lane. The db project
is already file-parallel, and a hash-ordered slice can put both slow
suites on one runner.
> - This pull request moves the db project into its own `workspaces-c`
lane in both `pr-trusted.yml` and `release-verify.yml`. The runner
script gains a `general-workspaces-c` group, and `general-workspaces-b`
drops the db project.
> - The benefit is that both lanes should finish in about 230s to 340s
instead of 499s to 593s, and `workspaces-b` leaves the critical path.
The cost is one more job per run, about 60s of setup.
## Linked Issues or Issue Description
**Describe the enhancement**
The `General tests (workspaces-b)` PR check is the slowest check in the
run. It runs seventeen Vitest projects in sequence on one runner. The
`@paperclipai/db` project is one third to one half of its vitest time.
**Why is this needed**
The slowest check decides the wall-clock time of every PR run. In the
last three fully green runs on the current server-shard manifest,
`workspaces-b` took 499s, 523s and 593s (runs 38083020834, 38083084276
and 38084171761, 2026-10-10). The next slowest lanes, `Build` and the
server shards, sit at about 480s to 570s. A split of `workspaces-b`
removes 170s to 250s from this lane.
**Proposed solution**
Run the `@paperclipai/db` project as its own lane,
`general-workspaces-c`. Keep the other seventeen projects in
`general-workspaces-b`. Add the lane to both the PR and the release
verification matrix. Extend the guard tests so the three workspace lanes
still cover the root Vitest project list exactly once, so the new group
rejects shard flags, and so both workflows carry the lane unsharded.
**Alternatives considered**
- Vitest native `--shard` on `workspaces-b`, as `workspaces-a` does. The
db project is already file-parallel and its wall time is set by two long
suites, so a hash-ordered slice does not give a predictable split.
- Move `adapter-utils` (115s to 117s) into the new lane as well. That
makes the db lane 285s to 366s of tests and the rest 147s to 160s, which
is less level than db alone (168s to 250s) against the rest (263s to
276s).
- Three lanes. Not needed now: after this split both lanes sit under the
server shards and `Build`, so a third runner would not shorten the run.
## What Changed
- `scripts/run-vitest-stable.mjs`: new `general-workspaces-c` group that
runs `@paperclipai/db` alone. `general-workspaces-b` now excludes it.
Local `--mode all` runs all four general groups, so every project still
runs once. The dry-run output reports the new group's projects.
- `.github/workflows/pr-trusted.yml`: a `workspaces-c` entry in the
general tests matrix, with a comment that records the 2026-10-10
measurements.
- `.github/workflows/release-verify.yml`: the same `workspaces-c` entry,
to keep parity with the PR workflow.
- `scripts/__tests__/run-vitest-stable-shard.test.mjs`: the coverage
test includes the new group; shard flags are rejected for both
`workspaces-b` and `workspaces-c`; a new test asserts that
`workspaces-c` runs only the db project, that `workspaces-b` no longer
carries it, and that both workflows list both lanes without shard
arguments. The workflow check parses each `- group:` matrix entry with
comment lines removed, so a comment between keys cannot hide a shard
setting, and it first confirms the parser sees the shard keys on the
`workspaces-a` entries. A small parser test covers the
comment-between-keys case (Greptile P2).
- `scripts/__tests__/release-verify-workflow.test.mjs`: the release
workflow must carry `general-workspaces-c`.
## Verification
- `GITHUB_WORKFLOW= node --test
scripts/__tests__/run-vitest-stable-shard.test.mjs`: 32 pass (was 29).
- `node --test scripts/__tests__/release-verify-workflow.test.mjs`: the
workflow parity test passes. Two unrelated tests in that file (`a
publisher lockfile lets a fresh smoke install retain validation after
... drift`) fail on my machine on pristine `master` too, because `pnpm`
is not on its PATH. They pass in CI.
- `node scripts/run-vitest-stable.mjs --mode general --group
general-workspaces-c --dry-run` reports `["@paperclipai/db"]`; `--group
general-workspaces-b` reports the other seventeen projects.
- Both workflow files parse as YAML; the general tests matrix has 19
entries in `pr-trusted.yml` and 17 in `release-verify.yml`.
- This PR's own run exercises the script change but not the workflow
change: `pr.yml` calls `pr-trusted.yml@master`, so the matrix comes from
`master` and the `workspaces-c` job appears only on PR runs created
after the merge. Because the script comes from this branch, the
`workspaces-b` job in this PR's run (38090713637) ran the seventeen
remaining projects and finished in 340s, inside the expected 325s to
340s band. No job in that run ran `@paperclipai/db`.
- To cover the gap, I ran the new lane locally with the same command CI
uses, `pnpm test:run:general -- --group general-workspaces-c`: 49 test
files, 180 tests, all passed, 111s of vitest time (
canary/v2026.1011.0-canary.2
|
||
|
|
07f3536e37 |
fix(connections): discover Sentry OAuth through its MCP resource (#15837)
Correct Sentry OAuth discovery and cover new and saved client registration. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
4f680bc85c |
fix(release): retry verified canary tarball 404s (#15768)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Canary releases test the published npm packages through a clean onboarding install. > - A package can be announced in registry metadata while a fresh install gets a tarball 404. > - The existing ETARGET retry does not cover that distinct error. > - This pull request retries only a verified public canary tarball acquisition failure. > - Permanent errors still fail, and onboarding runs once after acquisition succeeds. ## Linked Issues or Issue Description Refs: #15743 **What happened?** The [Release run](https://github.com/paperclipai/paperclip/actions/runs/37998601578) published canary `2026.1009.0-canary.17`. Its registry verification and publisher install passed. The separate fresh onboarding install then failed with a final npm E404 for that exact `@paperclipai/server` tarball. The tarball was available on a later read. This is a separate failure from ETARGET; it does not prove the cause of the registry visibility difference. **Expected behavior** Allow a bounded acquisition retry when the effective registry is public npm and fresh primary metadata announces the exact released canary tarball. Keep other E404, authentication, configuration, and onboarding errors fatal. **Steps to reproduce** 1. Run the offline helper fixture with a first-attempt E404 for an allowlisted package at the requested canary version. 2. Return canonical effective npm registry configuration and matching primary metadata. 3. Make the second install succeed. Confirm two installs and one onboarding invocation. 4. Keep the tarball unavailable. Confirm three installs, a final failure, and no onboarding invocation. **Paperclip version or commit** The observed run used commit `ce024457f3d747657501fbcfe8eac71f6772150f`. This fix builds on the merged acquisition helper and current master. **Deployment mode** Other: the published npm canary onboarding check in release CI. ## What Changed - Add a canary-only classifier for one unambiguous final E404 at the canonical tarball URL of a CI-published package from the existing release manifest. - Query effective npm registry configuration in the failed install's prefix, environment, and working directory. Keep bounded configuration output in memory without logging it. Respect scoped registry precedence. - Require fresh primary metadata to match the package, version, tarball URL, and valid SHA512 integrity syntax. Reject redirects, conflicting errors, truncated logs, other artifacts, and unknown or custom effective registries. - Share one five-second configuration and metadata deadline within the existing two-minute acquisition budget. Keep three install attempts, refreshed retry metadata, process cleanup, and one onboarding invocation. - Bound metadata header and body waits even if transport abort propagation stalls. Cancel the reader and any late response body without waiting for cancellation acknowledgements. - Preserve the existing ETARGET classifier and its character-based stderr tail. Add offline subprocess, actual npm configuration, body cancellation, budget, identity, and failure tests. Document the scope and limits. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/cloud-source-verification.test.mjs scripts/standard-image-contract.test.mjs`: 73 passed, no skips, under Node 22 on the PR head. - `pnpm test:release-registry`: 153 passed, no skips, on the PR head. This includes the existing real Playwright cleanup and startup timeout tests. - [Hosted CI](https://github.com/paperclipai/paperclip/actions/runs/38011028296) passed on this head. The rollup has 53 successful checks and two expected Storybook skips. This includes typecheck, build, the full general and serialized test suites, E2E, and Canary Dry Run. - The new tests use fixture-owned npm configuration and local HTTP servers. No published canary tarballs were downloaded or installed for this change. No release or deployment was triggered. - `pnpm test:run` was not run locally. The full split test suites passed in hosted CI. Independent source checks on this head passed 46 committed tests, 22 boundary checks, and six negative controls. Greptile scored this head 5/5 with no unresolved threads. - The source diff and PR text were checked for secrets, private identifiers, and unintended artifacts. ## Risks - The new retry is conservative. A configuration capture over 4 KiB, metadata over 64 KiB, or a check that exceeds five seconds denies retry. A persistent tarball failure still fails after three installs. - Matching primary metadata proves the announced artifact identity and integrity syntax. It does not independently verify tarball bytes. The subsequent npm install retains its integrity check. - Registry checks use npm's resolved global and applicable scope values. They do not add credentials or change npm configuration. Existing ETARGET behavior, onboarding assertions, and overall startup deadlines remain unchanged. ## Model Used OpenAI GPT-6 (Codex). The exact model variant and context window are not exposed in this session. Used reasoning, code execution, offline fixtures, and GitHub API tools. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs 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.1011.0-canary.0 |
||
|
|
9ba5569030 |
ci: refresh the general-server shard durations (#15826)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Pull requests to this repository run a large CI matrix. The slowest check sets the time a contributor waits for a green run. > - The general-server vitest lane runs with one worker per job, so it can only go faster across runners. Twelve shards share its suites, and a recorded duration manifest decides which suite goes to which shard. > - That manifest was recorded on 2026-09-15 from 646 suites. The lane now has 871 suites and about 5031s of serial vitest time. 230 suites have no record and get the median weight, so the shards drifted apart. In run 38076972444 (2026-10-10) they ran 313s to 554s of tests, and `General tests (server (2/12))` at 618s was the slowest check of the whole run. > - An unbalanced lane wastes the runner time it already spends. The total work does not change, but one shard holds the run. > - This pull request records the current duration of every suite from two recent PR runs and keeps the same twelve shards. > - The benefit is that the twelve shards level to about 415s of tests each. The slowest server shard should drop from about 618s to about 480s, and this lane leaves the critical path. ## Linked Issues or Issue Description **Describe the enhancement** The general-server PR test lane is out of balance. Its shard manifest, `scripts/general-server-shard-durations.json`, is three and a half weeks old and misses 230 of the 871 current suites. The heaviest shard runs 554s of tests while the lightest runs 313s. **Why is this needed** The slowest check decides the wall-clock time of every PR run. In the last fully green runs the slowest check was a general-server shard (618s, 562s, 585s, 646s in runs 38076972444, 38076844891, 38076844368 and 38073555316). A balanced lane removes about 135s from that shard at no extra runner cost. **Proposed solution** Re-record the per-suite durations from two recent PR runs (38076844891 and 38076972444) with the method that the manifest's `$comment` documents: diff consecutive per-suite completion timestamps in each shard log, and measure the first suite from the Vitest `RUN` banner. Average the two runs. Keep the chat and native-runner entries from the old manifest, because those suites run in their own lanes and do not appear in the shard logs. Drop the two suites that no longer exist. **Alternatives considered** More shards would also shorten the lane (fourteen shards level at about 355s, sixteen at about 311s). They are not needed now: `Build` (489-592s) and `General tests (workspaces-b)` (513-618s) already sit above the balanced twelve-shard level, so extra runners would not shorten the run. Those two checks are the next targets. ## What Changed - `scripts/general-server-shard-durations.json`: 873 recorded suites (was 646). 870 come from the two 2026-10-10 runs, 3 carry over (chat and native-runner suites), 2 obsolete entries are gone. The `$comment` names the source runs, the fleet, and the carry-over rule. - `.github/workflows/pr-trusted.yml`: a comment on the general tests matrix records the 2026-10-10 measurements and why the shard count stays at twelve. No workflow behavior changes. ## Verification - `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs`: 29 pass. This covers the manifest coverage check, the duration-balance check (spread must stay under the heaviest suite), and the complete non-overlapping partition. - `node --test .github/scripts/tests/pr-dependency-cache.test.mjs .github/scripts/tests/pr-runner-rust-cache.test.mjs .github/scripts/tests/lockfile-refresh-workflows.test.mjs`: 17 pass. - Measurement check: the per-shard sum of the recorded durations matches Vitest's own `Duration` line within 1s on all 24 shard logs. - Simulation with the real planner (`scripts/run-vitest-stable.mjs --dry-run`, `GITHUB_WORKFLOW=PR`) on the current suite list: with the old manifest the twelve shards carry 321s to 510s of recorded tests; with this manifest they carry 413s to 415s. - Expected result on the first PR run after merge: every `General tests (server (n/12))` job finishes in about 480s (415s of tests plus about 65s of setup) instead of 374s to 618s. ## Risks - Low risk. The file only sets weights for the shard planner. A wrong weight moves a suite to a different shard; it cannot drop or duplicate a suite, because the guard tests assert the partition is complete and non-overlapping. - The durations come from the `runs-on` public PR fleet. GitHub-hosted runners are faster in absolute terms, but the relative weights, which are all the planner uses, are the same. - The manifest will go stale again as suites grow. The guard test fails when coverage drops under 50%, and the matrix comment records how to refresh it. ## Model Used - Claude (Anthropic), model ID `claude-fable-5-1`, running as a Paperclip agent through the Claude local adapter with tool use (shell, file edits, GitHub CLI). The agent collected the CI data, built the manifest, ran the tests, and wrote this description. ## 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) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>canary/v2026.1010.0-canary.1 |
||
|
|
40701adecf |
fix(release): preserve pinned master identity for canary publishing (#15770)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - A master push publishes a canary from its exact source commit. > - The publisher now checks out that commit by SHA. Git leaves HEAD detached. > - The release script requires the local branch name to be master. > - This pull request verifies the trusted push and source before attaching local master at the same commit. > - The canary can pass the existing branch guard without following a newer master tip. ## Linked Issues or Issue Description Related: #15712 pinned the publisher checkout and bound the smoke lockfile to its source. I searched open PRs and issues for canary, detached HEAD, and checkout fixes. No overlapping fix was found. #15768 addresses a later tarball visibility error and does not change this branch guard. **What happened?** The canary publisher checks out the exact push SHA. The checkout is detached. `release.sh canary --skip-verify` then fails because the local branch is not master. Publication does not start. The [failed master run](https://github.com/paperclipai/paperclip/actions/runs/38008956836) shows this failure. **Expected behavior** The trusted master publisher must keep the exact verified push commit and pass the existing local master guard. It must not follow a newer branch tip. **Steps to reproduce** 1. Check out a master push commit by its full SHA. 2. Confirm that HEAD is detached. 3. Run the real `require_on_master_branch` helper from `scripts/release-lib.sh`. 4. Observe the detached-HEAD rejection. The tests reproduce this without calling a publisher. **Paperclip version or commit** `baa94bbea58919bcc6cf247a708f04e6e1002679`. **Deployment mode** The GitHub Actions master canary publishing lane. ## What Changed - Add one step immediately after the pinned publisher checkout. - Require the canonical repository, a push event, and the master ref before changing any Git ref. - Validate the full source SHA and require the checked-out HEAD to match it. - Attach local master to that exact SHA and recheck HEAD. Do not fetch or select a floating branch. - Preserve release scripts, local branch guards, package authentication, other publishing lanes, and source-named lockfile artifacts. - Add disposable real-Git tests for a pinned source behind local and remote master, rejected trust and SHA inputs, unchanged refs on rejection, and the original branch guard. Document the branch handoff. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/cloud-source-verification.test.mjs scripts/standard-image-contract.test.mjs scripts/release-lib.test.mjs` passed all 82 tests on Node 25.6.1. Twelve new cases include eleven real-Git fixtures and one workflow invariant check. The tests run the actual workflow shell and the unchanged release guard. - `actionlint -shellcheck= .github/workflows/release.yml` passed. ShellCheck passed for the new shell. Full local actionlint reports four pre-existing advisories in other steps; their text matches the base exactly. This change adds no advisory. - Workspace `pnpm -r typecheck` and `pnpm build` passed on Node 25.6.1. The local tests cover the changed release flow; the full application test suite runs in hosted CI. - [Hosted full CI](https://github.com/paperclipai/paperclip/actions/runs/38011530698) passed all 47 jobs at commit `ffff774a2629663fa71e2fad5143da0696afc5e6`. This includes policy, typecheck, release registry, build, runner tests, application tests, browser tests, and the canary dry run. Hosted policy ran all 12 new guard tests and passed all 67 source-policy tests. - Greptile scored the same commit 5/5 with no actionable issues. There are zero review threads. Separate source review approved all three changed files and 32 dependencies. It passed 82 tests and caught four broken variants. - The supply chain scanner returned neutral with zero annotations. It cannot verify this inline workflow change and reports limited coverage for existing action references. Manual review confirmed that all action references and pins are unchanged. The security, Socket, and Snyk checks passed. - No live canary install, registry publication, Docker image operation, workflow rerun, or deployment was performed. Tests use disposable Git repositories and local fixtures. ## Risks Low risk. The new step changes only local Git state in the trusted canary publisher. A wrong event or source fails before ref changes. The original release and authentication guards remain in place. The exact checkout and artifact source stay unchanged. Revert the new step to restore the previous behavior. No runtime or database change is required. ## Model Used OpenAI GPT-6 through Codex. Used repository inspection, code execution, Git and Bash fixtures, and independent agent review. The runtime does not expose a more specific model snapshot or context-window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.1010.0-canary.0 |
||
|
|
b1ebe3de3c |
perf(chat): wake action queues from commits and deadlines (#15808)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Chat keeps durable rows for provider actions and setup messages. > - Five action queues still scan the database every second when empty. > - Empty scans add idle database traffic and prevent cost savings from sleep. > - This pull request wakes these queues when their writes commit or their next deadline arrives. > - Existing rows retain retry and restart recovery. Empty queues stop scanning. ## Linked Issues or Issue Description Refs #15802, #15625, #15750, #15757. Related allocation work: #15153. **What existing behavior does this improve?** Idle chat reconciliation for Slack Board messages, Slack slash-command task starts, Slack setup verification messages, receipt reactions, and Slack session stops. **Current behavior** The app runs these five queue scans through chat maintenance every second, including when no work exists. **Proposed behavior** Each queue has an independent worker on the existing scheduler. Producers and foreground claim/retry/settlement writes announce work inside their database transaction. The worker wakes after the outer transaction settles. Startup restores durable work. Shared dispatch and deadline predicates select real retries and abandoned claims. Empty queues disarm. **Subsystem affected** Server chat services. No schema or migration changes. ## What Changed - Register five action workers alongside the three delivery workers from #15802. Remove their scans from periodic app maintenance. - Share action eligibility between dispatch and deadline selection. Park paused Board messages and task starts until endpoint changes. Preserve uncertain-send quarantine. - Wake setup verification after account, welcome, registration, or authenticated callback changes. Exclude prerequisites that need another event. - Persist a retry time for failed provider-confirmed task admission. Its own commit notification cannot cause an immediate retry loop. - Reuse the existing transaction signals and scheduler registration code. Provider calls remain outside database transactions. - Update the instance-sleep inventory and add scheduler and PostgreSQL regression coverage. ## Verification - Passed: 37 scheduler, coordinator, and app-wiring tests, including an idle hour with no further scans or timers. - Passed: seven focused PostgreSQL chat cases. These cover deadline eligibility, startup recovery, outer-commit wakes, actual producer signals, and signed-callback verification without maintenance polling. - Passed: `pnpm typecheck`. - Passed: full chat integration suite and related publication/coordinator tests, **1,278 tests** across six files, including **1,228 chat integration cases**. - Passed: `pnpm build`. - After the review fix, seven focused PostgreSQL integration cases and the server typecheck passed again. Deadline and dispatch queries now exclude completed action history. - Greptile: **5/5** on `35a979fce6bb9ab910fab3373ec8e537fc2d01a9`, with the prior finding resolved and no new findings. - Fixed a CI timing failure in the GitHub mention integration test: asynchronous admission now has an explicit ten-second assertion deadline instead of the default one second. The failure reproduced locally; all five mention variants and all 398 cases in the matching CI shard pass after the fix. - Hosted CI passed on `35a979fce6bb9ab910fab3373ec8e537fc2d01a9`: **54 successful checks**, two intentionally skipped Storybook checks, no failures or pending checks. Provider responses are simulated in the integration suite. PostgreSQL, transactions, service dispatch, and scheduling are real. No live Slack workspace was used. ## Risks - Every producer that changes runnable state must emit a transaction signal. This change covers the five queues and their foreground dispatch/retry paths. Direct SQL and independent DB owners still need explicit integration or startup recovery. - Missing retry or claim deadlines can strand work. Tests compare the dispatch and deadline behavior, including paused and uncertain states. - Other provider maintenance, sockets, and scheduled jobs remain. This change does not establish full instance sleep. - No new tables, migrations, or provider credentials are required. ## Model Used OpenAI Codex (GPT-6), with repository inspection, code execution, and automated tests. ## 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> |
||
|
|
fed251867b |
chore(lockfile): refresh pnpm-lock.yaml (#15820)
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> |
||
|
|
a7dd5284b5 |
feat: add company fast-response acknowledgements (#15748)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Human messages start agent work through task, chat, and external-channel intake. > - Agent startup can delay the first visible response. > - A small direct model call can acknowledge the request while normal work starts. > - This response must remain separate from evidence that the agent answered or completed work. > - This pull request adds optional company-wide fast responses with durable receipts, access checks, and cost accounting. > - Users receive prompt acknowledgement without changing the agent execution path. ## Linked Issues or Issue Description **Subsystem affected** Cross-cutting: database, shared contracts, server orchestration, connections, and UI. **Problem or motivation** Users can wait for an agent to start before they receive a contextual response. Generic progress messages do not confirm what the user asked. An acknowledgement must not falsely complete work or satisfy an unanswered turn. **Proposed solution** Add a disabled-by-default experimental fast-response model using an existing shared API connection. Generate one short acknowledgement for each accepted human turn. Use the existing agent identity and external publication outboxes. Retain platform provenance and account for the inference independently. **Alternatives considered** Running the acknowledgement through the agent runtime adds startup latency. Restricting implementation to OpenRouter leaves other existing API connections unsupported. This change supports all existing API connections and uses OpenRouter for live verification. **Roadmap alignment** This extends existing agent communication and connection settings. ROADMAP.md and open pull requests were checked. No duplicate fast-response implementation was found. The maintainer supplied the feature plan directly. ## What Changed - Add Experimental fast responses to instance settings. Keep the feature off by default. Enforce the flag at intake, dispatch, and publication. - Move Decision model and Fast response setup to company Settings → Connections when the experiment is enabled. Place Connections below Environments. Separate the model sections with clear headings and a divider. Keep Decision model in General when the experiment is off. Route Costs setup links to the available settings page. - Make the acknowledgement prompt a multiline template string. Ask for a brief, positive response in the user’s language. - Add settings, connection/model selection, sponsorship, fixed-sample testing, and Costs history. - Add a Vercel AI SDK text service for existing native, routed, Bedrock, and local API connections. - Add durable per-turn requests, a bounded worker, a three-second admission deadline, and one inference attempt. - Integrate task creation, task and agent chat, steering, queued follow-ups, experimental board chat, shared chat intake, and email. - Preserve receipt provenance and exclude receipts from completion, recovery, interaction resolution, and agent wakeups. - Recheck authorization, source validity, real replies, budgets, and destination binding before publication. Preserve accounting for suppressed or uncertain outcomes. - Add provider contracts, database race tests, channel outbox tests, UI tests, Stories, and documentation. Keep decision-model execution unchanged. ## Verification - Local `pnpm -r typecheck`, `pnpm build`, and UI token gates pass after rebase. The UI typecheck and build also pass after the final navigation fixes. All 37 focused navigation tests pass. The first full local `pnpm test:run` invocation reported seven chat failures. All seven passed in isolated reruns after fixture updates and host cleanup. This invocation was stopped after the full final-head CI suite passed. - Initial local database tests hit macOS shared-memory exhaustion. A diagnostic confirmed `shmget: No space left on device` with the system limit of 32 IDs. Three abandoned, unattached PostgreSQL IPC headers were reclaimed. The isolated rerun passed all 31 fast-response and channel tests. The two additional Slack regression cases also passed in a separate rerun. No active database was stopped. - UI token gates pass. Provider contract tests cover all supported API connection types. Fast-response tests cover uniqueness, authorization, budgets, expiry, cancellation, restart, real-reply races, and the experimental flag. - The test drive verified that disabling the experiment hides Connections and redirects its direct URL. Enabling it restores the saved OpenRouter setup. After restart on the final commit, the OpenRouter settings sample returned “Sure, I’ll take care of fixing the border around the settings panel.” in 428 ms. It used 260 input and 31 output tokens and recorded $0.0000576 in reported cost. - Earlier live OpenRouter verification produced a receipt in 1.013 seconds for a new task. The real agent then supplied its substantive answer. A separate settings test took 1.34 seconds, used 246 input and 23 output tokens, and recorded $0.0000361. - Live Slack verification on final commit `24016fa525961ebc7a4acffdc5019ce123970549` passed for a fresh initial task and a follow-up in a disposable bot DM. The initial acknowledgement appeared 2.405 seconds after the Slack message and 1.413 seconds after durable acceptance; the follow-up appeared in 2.322 seconds and 1.160 seconds respectively. The recorded generation/settlement durations were 898 ms and 697 ms. The initial call used 291 input / 39 output tokens and cost $0.00006705; the follow-up used 281 / 47 and cost $0.00007035. - The Slack acknowledgements retained the assigned agent identity and `origin: fast_response`, source-turn references, and no fabricated run ID. A status snapshot after the initial receipt showed the task still `in_progress` with its real execution run. The agent then read the CSV fixture and correctly reported two ready items, two blockers, and their owners. Both replies stayed in the originating DM, and no duplicate generic working message followed the delivered contextual acknowledgements. The `new` command started a fresh conversation session without generating a fast response. - An earlier eligible Slack turn generated a response but suppressed publication. Its reported cost was retained, generic progress remained, and the real agent completed the requested result. This is recorded separately from the two delivered acknowledgements; the history did not expose a precise suppression reason. - Slack verification used real signed provider events, the existing intake/publication paths, and a user-approved temporary webhook-only HTTPS tunnel. Subscriptions were limited to direct-message events. The test bot was paused and the tunnel stopped afterward. Live channel/group-thread and GitHub journeys remain unverified; their mocked tests cover intake, destination binding, publication, and continued underlying work. - Greptile reviewed final commit `24016fa525961ebc7a4acffdc5019ce123970549` at 5/5. Both new review findings are fixed and all threads are resolved. [Final-head CI run](https://github.com/paperclipai/paperclip/actions/runs/38060015730) passed. This includes grouped server/chat/workspace tests, serialized suites, runner checks, browser journeys, typecheck, build, release registry, policy, and the canary dry run. - Manual check: enable Experimental fast responses. Open company Settings → Connections. Select a shared API connection and model. Save and use Test response. Submit a task message and confirm that its receipt does not complete the task. ## Risks - The migration adds receipt and configuration tables plus accounting references. It uses idempotent statements and follows the current migration sequence. - A slow provider, authorization change, or real-agent reply can suppress an acknowledgement. Existing progress feedback remains available. - Unknown provider billing retains a reservation until reconciliation. External deliveries with uncertain outcomes must not be blindly repeated. - Live Slack initial-task and follow-up DM journeys pass. Live Slack channel/group-thread and GitHub journeys remain unverified. The PR remains a draft and records these gaps. Final-head repository CI and automated review pass. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, repository tools, code execution, and browser interaction. The runtime does not expose an exact model snapshot ID or context-window size; these are not asserted. ## 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> |
||
|
|
1100682261 |
ci: move the Grok public-install verification off Canary Dry Run (#15213)
Move the 'Verify built-in Grok from a clean public npm install' step from the Canary Dry Run lane to the end of the Build lane in pr-trusted.yml. The verifier only needs pnpm build output, which Build already produces. Expected: Canary Dry Run drops from ~484-572s to ~275-350s, and the run's critical path moves to the server (2/12) shard. |
||
|
|
0e37a385e6 |
fix(pi-local): avoid embedding model catalogue in errors (#13628)
<!-- Write all pull request text in Simplified Technical English (ASD-STE100): short sentences, one instruction per sentence, simple approved vocabulary, and the active voice. --> ## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The pi-local adapter discovers and validates models before it starts a local Pi process > - An unavailable-model error included model IDs from the discovered catalogue > - Repeating those IDs made persisted and rendered failures noisy and exposed substitute choices > - This pull request keeps the requested model, reports the available count, and points to the existing lookup command > - The benefit is a concise error without changing model discovery or matching ## Linked Issues or Issue Description Fixes #13612 ## What Changed - Replace model catalogue interpolation in unavailable-model errors with the requested model, normalized model count, and `pi --list-models`. - Add a regression test with 13 discovered models and exact error-message matching. ## Verification - `pnpm exec vitest run packages/adapters/pi-local/src/server/models.test.ts` - `pnpm exec vitest run packages/adapters/pi-local/src/server/*.test.ts` - `pnpm --filter @paperclipai/adapter-pi-local typecheck` - `git diff --check` All listed checks pass locally. The test suite uses a temporary Pi executable and verifies that model IDs are not appended to the error. ## Risks Low risk. Only unavailable-model error wording changes. Model discovery, matching, valid model execution, and failure handling remain unchanged. Full repository CI was not run locally because the host uses Node 22.22.1 and the repository declares Node >=24.11.0. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI GPT-5.6 Luna (`gpt-5.6-luna`); tool-assisted code execution. The context window size is not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [ ] 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 #13612) - [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 - [ ] 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 |
||
|
|
28e134873e |
fix(opencode-local): run in the realized workspace (#11438)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip adapters start each agent in its selected workspace > - Paperclip can realize a different workspace path for local and remote runs > - The OpenCode CLI prefers its inherited `PWD` when no `--dir` option is present > - The process `cwd` option does not update the inherited `PWD` value > - This pull request passes the realized workspace to OpenCode with `--dir` > - The benefit is that OpenCode sessions and tools use the workspace that Paperclip selected ## Linked Issues or Issue Description No matching issue exists. Refs #8287. That earlier pull request describes the realized remote workspace path. It does not make the OpenCode CLI use that path. I searched open and closed issues and pull requests for `opencode --dir`, `opencode cwd PWD`, and `opencode workspace directory`. I found no duplicate. **What happened?** Paperclip gives the OpenCode process the correct operating system `cwd`. However, the adapter does not pass OpenCode's `--dir` option. OpenCode uses `process.env.PWD` before `process.cwd()` when `--dir` is absent. A server `PWD` that differs from the realized workspace can therefore place the OpenCode session and its tools in the wrong directory. **Expected behavior** OpenCode must use the workspace that Paperclip realized for the run. An explicit `--dir` in `extraArgs` must remain valid and must not be duplicated. **Steps to reproduce** 1. Start the Paperclip server from directory A. 2. Configure an OpenCode agent with directory B, or realize directory B on a remote execution target. 3. Start a run without a manual `--dir` value in `extraArgs`. 4. Inspect the OpenCode session directory or run a directory-sensitive tool. 5. Before this change, OpenCode can use directory A from the inherited `PWD`. 6. After this change, OpenCode receives `--dir B`. **Paperclip version or commit** `b38d6ddb811b3ff3145ff5df60174eb9e7313fe6` **Deployment mode** Self-hosted server. The same adapter path is used in local development and remote execution. **Installation method** Built from source. **Agent adapter(s) involved** OpenCode. **Database mode** Not database-related. **Additional context** OpenCode v1.17.13 defines `--dir` and uses the inherited `PWD` as its fallback root. See the [OpenCode run command source](https://github.com/anomalyco/opencode/blob/10c894bdeef3618f5666fb506ef7f9491bb964d8/packages/opencode/src/cli/cmd/run.ts#L333-L339). ## What Changed - Add the realized execution workspace as `--dir` for OpenCode runs. - Preserve an explicit `--dir` or `--dir=...` value from `extraArgs`. - Stop option detection at the first `--` terminator. - Extend the remote execution tests for realized, explicit, and post-terminator directory arguments. ## Verification - `pnpm exec vitest run packages/adapters/opencode-local/src` passed: 7 files and 40 tests. - `pnpm --filter @paperclipai/adapter-opencode-local typecheck` passed. - `pnpm --filter @paperclipai/adapter-opencode-local build` passed. - `pnpm -r typecheck` passed for all 31 selected workspace projects. - `pnpm build` passed for all selected workspace projects. - `git diff --check` passed. I also ran `pnpm test:run`. It completed with 334 test files passing and 2 test files failing. It reported 3,790 passing tests and 4 skipped tests. The two failures are in `issue-monitor-scheduler.test.ts` and `workspace-runtime.test.ts`. Each failure reproduces on the unchanged base commit after this pull request is removed. Neither test imports or covers the OpenCode adapter. ## Risks - The behavior change is limited to OpenCode run arguments. - A custom old OpenCode binary that does not support `--dir` will reject the option. The current official OpenCode v1.17.13 CLI supports it. - An explicit operator `--dir` remains authoritative. The adapter does not add a duplicate option because OpenCode's parser converts repeated string options to an array. - This change does not modify schemas, migrations, APIs, telemetry, or user data. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used OpenAI Codex based on GPT-5. The runtime did not expose a more specific model ID or context-window size. The agent used high-depth reasoning, repository access, shell execution, and GitHub tools. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: commitperclip-bot <305974387+commitperclip-bot@users.noreply.github.com> |
||
|
|
40bb466d78 |
fix(ui): align chat connection and recovery cards (#15771)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task pages show external chat connections and recovery notices.
> - These cards use different widths, colors, and spacing.
> - The difference makes related task information harder to scan.
> - This pull request gives these cards one shared surface.
> - The benefit is a consistent task page for chat and email users.
## Linked Issues or Issue Description
**What happened?**
The external chat banner and recovery notice have different backgrounds,
padding, and widths. The first banner needs more space above it.
**Expected behavior**
Connection, recovery, workspace repair, and task email cards use the
same surface. The chat cards have the same width.
**Steps to reproduce**
Open a task with an external Slack conversation and a recovery notice.
Compare the two cards. Open the Tasks / Context notices story to compare
the updated cards with an AgentMail email card.
## What Changed
- Add a shared token-based surface for task context cards.
- Put chat recovery notices in the same width container as the
connection banner.
- Add space above the connection banner.
- Apply the surface to task email cards and workspace export repair.
- Add a Storybook view with per-card width, color, padding, and corner
checks.
- Give the workspace recovery card its own React key to prevent
duplicate connection banners.
## Verification
- Passed `pnpm check:token-gates`.
- Passed 57 tests for ExecutionBlockerNotice, WorkspaceExportRecovery,
and the external chat banner.
- Passed UI typecheck and UI production build.
- Captured desktop and mobile browser screenshots from the real
components with fixture data. The three cards have equal widths,
backgrounds, padding, and corners.
- Full local typecheck needs Cargo, which is absent in the task
environment. Full tests and build could not complete within the
environment memory limit. Remote typecheck, build, all test shards, and
security checks pass on commit
|
||
|
|
07fee85eaf |
refactor(heartbeat): extract workspace preparation (#15807)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The heartbeat service prepares the workspace and dispatches each agent run. > - After the runtime extraction, `heartbeat.ts` still had 6,417 lines. > - Workspace setup occupied one contiguous 857-line block inside `executeRun`. > - This pull request moves that block into one workspace preparation module. > - The executor keeps dispatch gates and terminal cleanup. Reviewers can inspect workspace setup as one phase. ## Linked Issues or Issue Description Refs #15803 and #15578. This continues the heartbeat refactor series. The search found no open duplicate workspace preparation extraction. **What existing behavior does this improve?** It makes heartbeat workspace preparation easier to maintain. It does not change the workspace policy or execution behavior. **Current behavior** `executeRun` contains workspace resolution, freshness decisions, provisioning, persistence, issue binding, environment acquisition, and realization inline. **Proposed behavior** `prepareHeartbeatWorkspace` owns that sequence in `server/src/services/heartbeat/workspace-preparation.ts`. `heartbeat.ts` calls it at the same point and uses its returned workspace, lease, target, and metadata. **Reason and benefit** The main file falls from 6,417 to 5,597 lines. The workspace phase has a typed boundary and direct regression tests. **Breaking changes** None. There are no schema, API, feature-flag, or execution-policy changes. ## What Changed - Extract the 857-line workspace preparation block without changing its operations or their order. - Preserve native recovery bindings, workspace persistence failure cleanup, issue rebinding after realization, and the cloned restore lease. - Keep environment selection, dispatch admission, terminalization, and final lease release in `heartbeat.ts`. - Add 12 boundary tests with disposable PostgreSQL, real Git repositories, and real local environment leases. - Make the existing Stop and plan-only recovery tests await executor completion instead of short polling deadlines. Assert exactly one continuation for the specific plan-only source run. - Keep server-only Node preload hooks out of the deterministic process adapter used by Stop browser acceptance. - Refresh workspace recovery browser acceptance for the current task composer, and give its disposable test-drive an explicit 10-second snapshot deadline. Production snapshot settings stay unchanged. - Document the workspace preparation boundary in `doc/DEVELOPING.md`. ## Verification - AST comparison: all 857 moved lines match the original block. The remaining module body differs only at the extraction call. - `pnpm build`: passed. - `pnpm -r typecheck`: passed. - Focused regression coverage: 651 distinct cases across eight suites passed across targeted runs, including all 12 new boundary tests. The complete 400-test recovery suite passed together on the final commit. - Workspace bootstrap browser acceptance: both journeys passed (4.2 minutes), including preserved source edits, ignored-file exclusion, bounded retries, and persistence across reload. - Stop/queue browser acceptance: both process and native runner journeys passed (2.2 minutes), covering queueing, Stop, subtree pause/cancel, resume, and unrelated-task isolation. - [Full repository CI](https://github.com/paperclipai/paperclip/actions/runs/38062408589): all 47 jobs passed, including the general and serialized test suites, eight browser shards, build, typecheck, native runner checks, and canary dry run. - The local `pnpm test:run` was interrupted to prioritize the recovery regression; the complete repository suite was verified in CI. - Greptile: 5/5 on `c28e698b885cf5fd12f36f7b4052e7a2e6f879d7`, with no open review threads. ## Risks - This code writes durable workspace bindings and acquires environment leases. A changed operation order could break recovery or cleanup after partial setup. The extraction preserves the original statements and exception boundaries. - The new tests cover creation, reuse, immutable recovery bindings, persistence failure, acquisition and realization failure, controller ownership loss, isolation, execution policy, and lease snapshot independence. - Browser acceptance uses real application services with deterministic local workers and a fake Codex protocol provider. It does not qualify live cloud providers. ## Model Used OpenAI GPT-6 through Codex, with code editing, shell execution, and test tools. The exact serving model identifier and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
19e9facc5b |
perf(chat): wake delivery queues from commits and deadlines (#15802)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Chat connectors store incoming messages and outgoing publications in durable queues. > - The app checks these queues every second, even when they are empty. > - Empty scans keep the database active and hinder instance sleep. > - This pull request wakes three queue workers after transactions settle and at known retry or recovery deadlines. > - Empty queues stop scheduling checks. Existing rows retain their ordering, retry, and recovery rules. ## Linked Issues or Issue Description **What existing behavior does this improve?** Idle database activity from incoming chat deliveries, outgoing publications, and Slack upload receipt recovery. **Subsystem affected** `server/` — chat delivery and background work scheduling. **Current behavior** The app's one-second chat timer scans the three queues together with provider and action maintenance. Empty queues continue to query PostgreSQL. **Proposed behavior** Register three independent workers with the existing delivery coordinator. Producers announce work inside their database transactions. Commit wakes the corresponding worker. Startup restores outstanding work; persisted retries and stale claims supply the next deadline. An empty queue has no recurring scan. **Reason and benefit** Remove avoidable queue reads without requiring a new table, an external scheduler, or a persistent PostgreSQL listener. **Breaking changes** No schema or public API change. Work notifications are scoped to the app's shared database owner. Direct SQL and independent database roots do not send these notifications; startup still scans durable work. **Additional context** Refs #15625, #15750, and #15757 for the preceding sleep work. Related: #15153 reduces chat query allocation while retaining polling. This PR changes when the three queue workers run; it does not add query caching. ## What Changed - Register independent incoming delivery, publication, and Slack receipt workers on the shared scheduler. - Add transaction work signals at queue writes, endpoint state changes, and action transitions that unblock publications. Keep provider I/O outside the added transactions. - Restore deadlines from durable retry times, abandoned claims, and publication lease expiry. Share publication and receipt eligibility rules between dispatch and deadline queries. Respect incoming conversation order and lifecycle dependencies. - Exclude publications blocked by unresolved Slack tool sends. Wake them when the tool receipt changes. - Wake publication dispatch when an endpoint send finishes so free slots refill. Preserve per-endpoint concurrency, conversation order, and conservative handling of uncertain sends. - Wake receipt recovery when a stale publication becomes `delivery_unknown`, and wake queues when a provider connection recovers. - Commit interaction publications with their callback tokens so dispatch cannot see an incomplete card. - Keep provider runtimes, other action outboxes, milestone and wake-notice projection, Teams protocol maintenance, GitHub recovery, and Slack session synchronization on their existing maintenance cadence. This PR does not make the whole chat subsystem idle. - Update the instance sleep inventory with this partial migration and its remaining work. ## Verification - All 1,225 PostgreSQL chat integration cases passed across the three hosted chat shards. These cover retry and lease deadlines, blocked followers, unresolved Slack sends, provider recovery, commit visibility, and endpoint slot refill. - 32 local app-wiring, queue-worker, and delivery-coordinator tests passed after updating the wiring assertion for event-driven dispatch. Fake timers cover an hour of idle time without queue scans. - Related publication, interaction, receipt, and wake-notice tests passed locally. The 13 interaction integration cases include atomic rollback when callback-token storage fails. - Local `pnpm typecheck`, `pnpm build`, and final server typecheck passed. All hosted checks passed on the final commit, including build, typecheck, test shards, release registry checks, and the canary dry run (54 successful checks; two Storybook checks skipped for this backend change). - The last local PostgreSQL rerun was skipped because the embedded database startup probe failed after five attempts. The hosted PostgreSQL cases ran successfully; their skips only partition cases across shards. - `git diff --check` passed. Greptile is 5/5 on the final commit with no unresolved findings. ## Risks - Every producer that makes queued work eligible must send a transaction work signal. The tests exercise commit visibility, concurrent wakes, worker failures, and restart recovery. Future direct SQL writers must participate in this contract. - The existing database work-signal layer reconciles uncertain transaction outcomes. This PR adds no work-signal table or schema migration. - Provider and action maintenance still polls. Further changes are required before an idle chat-enabled instance can sleep. - Tests use real PostgreSQL with simulated provider responses; they do not send messages through live provider accounts. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, tool use, and code execution. The exact serving model ID and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [ ] 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> |
||
|
|
1fb3f9746e |
refactor(heartbeat): extract prepared runtime execution (#15803)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Heartbeat prepares, dispatches, and completes each agent run. > - After the runtime-selection extraction, the main service still had 7,295 lines. > - Provider dispatch and workspace finalization formed one large block with shared cleanup rules. > - This pull request moves that block into a typed runtime-execution module. > - The service now has 6,417 lines. Readers can follow admission and outer cleanup without reading the provider execution details. ## Linked Issues or Issue Description Follow-up to #15746. I searched open heartbeat PRs and issues. I found no competing runtime-execution extraction. **What existing behavior does this improve?** The organization and test coverage of native and legacy heartbeat execution. **Current behavior** The heartbeat service contains a 912-line block for provider dispatch, usage capture, workspace finalization, and instruction cleanup. **Proposed behavior** Move that block to `server/src/services/heartbeat/runtime-execution.ts`. Keep the atomic dispatch gate, admission, terminal run status, and outer lease cleanup in the service. Preserve run behavior. **Reason and benefit** This gives runtime execution a named boundary and direct tests. It removes 878 lines from the main service in one bounded change. **Breaking changes** None intended. There are no schema, API, or policy changes. ## What Changed - Add `executeHeartbeatRuntime` for prepared native and legacy execution, usage capture, workspace finalization, and gateway/instruction cleanup. - Return an explicit dispatch result. Update outer ownership state through immediate callbacks, including before exceptions. Read instruction state through live getters. - Move the two internal recovery error classes with their existing behavior. The caller imports the same classes for `instanceof` checks. - Add 15 database-backed execution tests. Keep the existing heartbeat regression suites. - Repair the native Stop acceptance fixture: installed Codex now takes precedence over `PATH`. A test-only loader pins the fake provider. An isolated home and dummy key keep readiness offline. Add four loader tests. - Document the module boundary and fixture setup. ## Verification - Passed: eight focused heartbeat suites (483 distinct tests, including 15 new execution tests). The boundary suite passed again after adding the failed-restore retention case from review. - Passed: `node --test tests/e2e/fixtures/composer-stop-codex-loader.test.mjs` (four tests). - Passed: `pnpm -r typecheck` and `pnpm build`. - Passed: AST comparison of all 912 moved lines after the explicit boundary substitutions. SQL template text, recovery class bodies, public exports, and the rest of the executor match the baseline. - Passed: browser Stop journeys for legacy process and native Paperclip Runner (two tests). The native fixture log proves provider `turn/start` before Stop and `turn/interrupt` after Stop. - Passed: all three ACP continuation browser journeys (same-session queued input, no replay of an interrupted write, and a new direction after composer Stop). Five relevant browser journeys passed in total. - Passed: the full CI test groups, including all server, chat, workspace, serialized-server, runner, and browser shards. - Local full-suite limitation: `pnpm test:run` first hit the macOS shared-memory segment limit while starting embedded PostgreSQL. After releasing only this task’s unused acceptance-server segments, the retry progressed without reported failures. I stopped that duplicate run after the full CI test groups passed. - Passed: all 56 PR checks/statuses on `8694c116e8d43ed8ac11bc4c58623ea3af34a675`. Greptile is 5/5 with no unresolved review threads. ## Risks - Cleanup depends on state written before an error. The module reports dispatch, retention, and recovery ownership immediately. Tests cover early returns and exceptional cleanup. - Instruction callbacks can replace saved metadata during execution. Live getters preserve those changes. - Native acceptance uses a real server, database, browser, and Rust runner with a deterministic provider. It does not verify a live provider service. ## Model Used OpenAI Codex, GPT-6 family, with reasoning and repository/tool access. The exact serving model ID and context-window limit were not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
2a2071340d |
refactor(server): extract heartbeat runtime selection (#15746)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Heartbeat execution prepares a runtime, dispatches work, and records the result. > - Earlier refactors separated workspace services, scheduling, and completion. > - The executor still builds native inputs and records runtime selection inline. > - This preparation must preserve admitted inputs and serialize with Stop. > - This pull request moves that phase into a typed runtime-selection module. > - Reviewers can inspect runtime preparation separately from dispatch and cleanup. ## Linked Issues or Issue Description Refs: #15732. **What existing behavior does this improve?** Maintainability of heartbeat runtime preparation and selection. **Subsystem affected** server/ — orchestration services. **Current behavior** The main heartbeat service has 8,128 lines. `executeRun` builds or restores native inputs, selects sessions and sandbox lifecycle, and records native or legacy selection inline. **Proposed behavior** Move this phase into `server/src/services/heartbeat/runtime-selection.ts`. The executor calls `selectHeartbeatRuntime` at the existing boundary and receives an explicit selection result. The main file becomes 7,275 lines, a reduction of 853 lines. **Reason and benefit** This gives runtime selection its own typed boundary and direct tests. It preserves existing decisions, database transactions, and cleanup ordering. **Breaking changes** None intended. All public heartbeat exports remain available. ## What Changed - Move native input assembly, completion contract selection, checkpoint lookup, runtime persistence, and native workspace-sync preparation into `selectHeartbeatRuntime`. - Preserve the row lock and controller lease check that serialize native selection with cancellation. - Report lifecycle and ownership changes to the executor immediately, including when a later preparation step throws. - Move sandbox lifecycle and model fallback helpers with compatible public re-exports. - Add 12 database-backed boundary tests. Update the existing session-recovery source test and developer guide. ## Verification - Structural AST comparison against current `master` confirms the 784-line selection block, moved helpers, and remaining service bodies are unchanged after normalizing boundary callbacks. All 140 public exports are preserved. - On final head `2eddaa485f`, all 12 new database-backed tests and 83 existing lifecycle, selection, fallback-warning, and session regression tests pass (95 total). - Five executor integration cases passed before the rebase. Their final-head rerun could not start because the local checkout was removed during verification; no assertions ran in that last attempt. - `pnpm -r typecheck` and `pnpm build` both pass on final head. - Local verification limitations: the full `pnpm test:run` was attempted, then stopped after database/process startup timeouts in concurrent local runs. Two unchanged optional real-runner session cases timed out on the initial run and one isolated retry; they were excluded from the 95-test focused run. CI also skips those two binary-dependent cases. - All CI gates pass on final head `2eddaa485f`: typecheck, build, general and serialized tests, runner checks, E2E, and canary dry run. - Greptile reviewed final head at 5/5 with no actionable findings. ## Risks This boundary controls native admission and cleanup ownership. Losing an update after a later exception could change resource cleanup. Immediate callbacks preserve those updates. Tests cover Stop races, lost controller leases, immutable admitted inputs, competing runtime selection, and workspace-sync failures. The change adds no schema or API behavior. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, code editing, and command execution. The session does not expose the exact model variant 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 (95 focused tests on final head; broader local limitations documented above) - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
d6e6d1c78a |
Stream OpenCode immediately, scope reasoning to turns, and deduplicate instructions (#15708)
## Thinking Path
> - Paperclip helps people manage AI agents and observe their work.
> - The native runner carries provider output into the task transcript.
> - OpenCode sends incremental text in `message.part.delta` events.
> - The driver ignored those events and waited for a full part snapshot.
Accepted chats also waited after lifecycle verification was complete.
> - This pull request forwards each valid chunk as it arrives and
removes unnecessary isolated startup work.
> - Valid chunks reach Paperclip sooner without changing completion or
permission rules. The matched browser experiment below does not
establish a reliable end-to-end latency improvement.
## Linked Issues or Issue Description
**What happened?**
The native OpenCode driver withheld text until OpenCode sent a full
snapshot. A local delayed-provider probe with the pinned OpenCode
1.18.34 runtime showed a 1,496 ms gap between the first native text
delta and the first Paperclip text delta (1,510 ms from provider text).
**Expected behavior**
Forward valid assistant text and reasoning deltas immediately. Preserve
repeated identical tokens, message roles, turn ownership, and final
response selection.
**Steps to reproduce**
Send an empty text part, then text deltas, and withhold the final full
snapshot. The new fixture requires the consumer to acknowledge its first
text delta before releasing the snapshot. The previous driver cannot
pass this handshake.
**Paperclip version or commit**
Baseline: `011e5669bad61c435a4745fb10812bef70376841`. The patch is
rebased onto current master.
**Deployment mode**
Local native OpenCode 1.18.34 on macOS arm64. Live diagnostics use
`openrouter/deepseek/deepseek-v4-flash-0731`. These are narrow
diagnostics, not full Product E2E qualification.
## What Changed
- Keep the macOS verified OpenCode launch pathname until child exit,
with guarded reuse and cleanup on failed launches. This fixes a
reproduced asynchronous executable-lifetime failure.
- Dispatch accepted queued chats immediately after lifecycle readiness
commits, through normal scheduler admission. Preserve ready state if
dispatch fails.
- Validate native OpenCode model access with the real hello probe
without a redundant catalog scan. Keep legacy adapter discovery
unchanged and isolate unspecified native probe directories.
- Map incremental text and reasoning to the existing canonical event
path, using observed part and message identities.
- Keep additive chunks without IDs distinct. Preserve ID-based event
deduplication.
- Clear current streaming part metadata when a new turn starts. Reject
mismatched session/message identities and unknown parts or fields.
- Disable automatic updates, remote model refreshes, and default plugins
in each isolated OpenCode process. Keep assigned MCP tools and default
model reasoning intact.
- Retain the latest cumulative text/reasoning part while its message
role is unknown, including completion metadata after more than 100
chunks.
- Expose `startTurn({ message, reasoningMode: "disabled" })` for one
OpenCode/OpenRouter turn. Carry the selection in the durable command
through Rust and the proxy. An omitted/default option restores provider
defaults on the next turn, including warm and recovered sessions. There
is no environment-level setting or automatic selection policy.
- Group optional Rust turn inputs in `CodexTurnOptions` and dispatch
through `start_turn_with_options`; retain `start_turn` for defaults.
Future turn settings can be added without another feature-specific
method.
- Expose a native-session capability for per-turn reasoning and reject
explicit unsupported selections before dispatch, including direct ACPX
and Codex backends. Runnerd checks the durable selected model as well as
the provider.
- Remove duplicate agent instructions from the shared OpenCode proxy
task envelope for all users. Send one system copy on every turn,
including prepared and resumed turns, because OpenCode reads the latest
user message’s system field. Preserve task constraints and completion
contracts.
- Document startup and streaming behavior. Add regression coverage for
role ordering, repeated chunks, final snapshot deduplication, and stale
turns.
## Verification
### Lower-load browser retry — 2026-10-10
**All 8/8 trials succeeded. In this batch, median Send → first visible
reply fell from 30.586 s to 12.476 s (59.2% lower).** Four fresh-agent
trials per variant, phase order before/after/after/before with two
trials per phase. Every adjacent-phase pair favored the candidate,
although one difference was only 0.301 s. This is evidence for the
readiness/probe changes on this host, not a production percentile or a
guarantee across providers.
| Phase/trial | Variant | Send → reply (s) | Observed ready → run (s) |
Session open → turn start (s) | Model requests |
|---|---|---:|---:|---:|---:|
| 0/0 | before | 45.042 | 25.337 | 3.629 | 2 |
| 0/1 | before | 13.689 | 0.000 | 2.443 | 2 |
| 1/0 | after | 14.696 | 0.000 | 2.526 | 1 |
| 1/1 | after | 13.389 | 0.000 | 2.470 | 2 |
| 2/0 | after | 10.871 | 0.000 | 2.706 | 2 |
| 2/1 | after | 11.564 | 0.004 | 2.443 | 2 |
| 3/0 | before | 41.582 | 21.518 | 2.376 | 2 |
| 3/1 | before | 19.589 | 9.753 | 2.707 | 1 |
Observed ready-to-run median: **15.636 s → 0 s**; zero means execution
began by the first ready observation, not literally zero latency.
Polling interval is nominally 250 ms plus HTTP time.
Session-open-to-turn-start includes controller handling, not just child
startup. All eight ran within the existing startup timeouts; no timeout
or reasoning policy was changed. Host load at fixture creation stayed
**5.47–8.73 on 18 CPUs**, versus 68.9–100.8 in the prior campaign. No
builds/tests ran concurrently with measurement.
Same merged source **b0a0158729a7913882a0e756fe7e27228d72bf53**, release
runner, rebuilt static UI, OpenCode **1.18.34**, model
**openrouter/deepseek/deepseek-v4-flash-0731**, provider-default
reasoning, and empty isolated workspaces in both variants. Only the
readiness worker and explicit-model verification source were toggled;
the launch-lifetime fix and all proxy streaming changes were held
constant. Thus this does not separately measure the original streaming
changes. One browser per phase, two fresh companies/agents/chats per
phase. Measurement begins at capture-phase Send click and ends on
visible Hi text plus two animation frames. Status/thinking is excluded;
emoji can arrive just after the first text. Successful screenshots
inspected. Each variant had three two-request turns using
`paperclip_finish` and one one-request turn; no status lookup was
observed. Reported usage includes settlement after the first visible
reply.
Runner SHA-256
`57f658c220eecd2370ffd3333cd7e5d06d16bb2798af0cf43c84e01c8207c1c3`;
proxy
`bcc02fda2bf35b38a116cd880841aa6c534f6e0b497a96d97369a1e06dcc72ac`;
rebuilt UI tree
`eee238f2eda628c4e8c3660707986da4f8dd9100c814e26938fce3756df2eae4`
(sorted relative path, NUL, binary per-file SHA-256). Worker/probe
variant source hashes are unchanged from the preserved comparison below.
Measured turn cost **$0.00612574**, plus verification probes not
included in that figure. All eight attempts retained; all source/proxy
files restored and test supervisors exited.
Current commit validation: **53 successful CI checks, 4 skipped, zero
failing; Greptile 5/5 on
|
||
|
|
35511366dc |
perf(server): schedule browser cleanup only while sessions exist (#15757)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Hosted instances must become quiet when they have no work. > - Browser Use queried its session table every three seconds, even when empty. > - Existing session rows already store the next poll time and cleanup lease. > - This pull request uses commit signals and those saved deadlines to schedule cleanup. > - Empty instances stop browser database scans. Live sessions keep their safety checks. ## Linked Issues or Issue Description **What existing behavior does this improve?** Browser Use background cleanup and recovery. This follows #15625 and #15750. **Subsystem affected** server/ — REST API and orchestration services. **Current behavior** The app scans for due sessions every three seconds, including instances that have never used Browser Use. **Proposed behavior** Scan once at startup. Wake after session creation, provider-create settlement, stop requests, or credential-removal cleanup. Schedule the next check from `nextPollAt` and `leaseUntil`. Stop scheduling when all sessions are terminal. **Reason and benefit** Remove empty database traffic so idle stacks and their database connections can become quiet. **Breaking changes** No API or schema change. Running and idle sessions retain provider polling, cost accounting, access checks, expiry checks, and cleanup retries. ## What Changed - Register browser cleanup with the existing work coordinator. Remove the app's three-second interval. - Signal existing session transactions before writes. No new tables or provider infrastructure. - Restore deadlines from live sessions and their leases. Wake after a credential-removal sweep releases its lease. - Wait for concurrent cleanup instead of returning while it still runs. Drain and standby preserve deferred work. - Add scheduler tests and database-backed commit and restart coverage. Update the connector guide and sleep inventory. ## Verification - Passed: focused browser worker and shared coordinator tests, 17 tests. - Passed: browser lifecycle, route-scope, viewport, and transport tests, 50 tests. The lifecycle suite uses real local Postgres and a simulated provider. - Passed: `pnpm -r typecheck` and `pnpm build`. - Passed: all hosted test groups for this commit. Started full local `pnpm test:run`, then stopped its duplicate serial run after the complete hosted sharded suite passed; no full local-suite pass is claimed. - Passed: direct server TypeScript check. Greptile reviewed `99c3217a2dea505be94081e729941e542e6fbc03` at 5/5 with no findings. All 54 applicable hosted checks passed; the two Storybook checks were skipped because this PR has no UI changes. ## Risks - Process-local signals cover services that share the instrumented database owner. Independent processes and direct SQL writes require startup recovery; this does not add cross-process notification. - Live sessions still poll. This removes empty scans; it does not make a running hosted browser sleep. - Cleanup uses the existing provider protocol and lease fences. Tests simulate the provider; no paid live browser was created for this scheduling change. ## Model Used OpenAI Codex, GPT-6, with reasoning, tool use, and code execution. The exact deployment model ID and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
eedf25655b |
test(adapter-utils): publish bridge queue fixtures atomically (#15792)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Remote agents send API requests through a callback bridge queue. > - Queue readers reserve memory from each published file's measured size. > - Several tests wrote directly into visible queue files while the reader was active. > - A reader could measure an empty file and then reject its completed contents with HTTP 503. > - This pull request makes those fixtures use the existing atomic publisher and proves the race without timing guesses. ## Linked Issues or Issue Description **What happened?** The public readiness run [38035333062](https://github.com/paperclipai/paperclip/actions/runs/38035333062) failed the schema-discovery bridge test. It expected HTTP 200 but received 503. The same test logged `Bridge envelope exceeded the configured size limit.` The fixture wrote requests directly to visible `.json` files. If a writer completed between the reader's size measurement and bounded read, the reader correctly rejected the changed file. The production gateway and filesystem queue client already publish complete files by renaming a temporary file. **Expected behavior** Queue fixtures must publish requests with the same atomic contract as the production writer. Schema assertions must observe completed responses. The runtime must still reject a request that grows beyond the size reserved for its read. **Steps to reproduce** Create an empty visible request file. Have the worker measure its size. Complete the write before the bounded read. The new deterministic regression produces the exact error and HTTP 503, with no handler dispatch. A separate publication test polls during an incomplete write and verifies that the real atomic writer keeps it invisible. **Paperclip version or commit** The failing run used `de042e79efbb7bb88e9716835407882e3ebab188`. The same fixture and reader are present in the base of this PR, `7e10dbe652ef0104f0a688a196fe8ea47b6f4b8e`. **Deployment mode** Local filesystem fixtures in the adapter-utils readiness tests. No external provider is required. Related PRs #15003 and #15696 address shutdown listing and idle polling. This is a separate fixture-publication race. This PR does not adopt or change their runtime work. ## What Changed - Use the existing filesystem queue client's atomic publisher at seven live-worker publication sites in five tests. - Wait for all seven schema responses within the existing single five-second bound, then assert the GET response and all six denials. Worker shutdown remains cleanup for that test. - Add a deterministic incomplete-write publication regression and a real worker regression for the bounded reader's existing HTTP 503 recovery. - Keep intentional malformed fixtures, dedicated drain assertions, runtime limits and runtime source unchanged. Test comments explain the publication contract; no product documentation changes are needed. ## Verification - Full bridge file: 68/68 tests passed on Node 25.6.1. - Seven focused publication, schema, authorization, drain and recovery cases passed. - Negative control: replacing the fixture helper with a direct write makes the publication test fail in milliseconds with the exact bounded-reader error. Restoring atomic publication passes. - Broader adapter-utils run: 1,690 passed, 12 skipped, one unchanged GitHub-launcher identity test exceeded its existing five-second limit. That exact case passed unchanged in isolation. This is not claimed as a full aggregate pass; no timeout or launcher source was changed. - Full workspace `pnpm -r typecheck` and `pnpm build` passed. - Independent review passed all 68 bridge tests and adapter-utils typecheck, plus three negative controls: both forms of direct publication fail, and removing the bounded read fails the expected-503 regression. The original source was restored and targeted positives passed again. - Hosted [CI 38038772400](https://github.com/paperclipai/paperclip/actions/runs/38038772400) passed at `aa4bcd8c1729e8ce098f2eb0143502ab34237d01`, including the full workspaces-b suite that originally failed. The PR has 53 successful checks and two expected Storybook skips. - Greptile scored that same commit 5/5; independent source review is approved, no review threads remain open, and GitHub reports no merge conflicts. ## Risks This change only affects tests. The new filesystem spy is limited to its own temporary directory and is restored in `finally`. A producer regression must still fail the publication test. The schema test retains all authorization checks and a single five-second response bound. The bridge's size limits, failure recovery, request handling and shutdown policy are unchanged. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools and independent agent review. The exact service model identifier and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
7e10dbe652 |
fix(server): retain stopped ephemeral workspaces after failed copy-back (#15790)
## Thinking Path
> - Paperclip manages work performed by agents.
> - A remote adapter must copy workspace changes back after execution.
> - Cancellation can stop and release an ephemeral sandbox before
copy-back fails.
> - The recovery recorder previously considered only active or already
held leases.
> - This change carries the original host lease into the recorder and
checks both stop receipts.
> - The exact stopped source receives a board repair obligation without
replaying work.
## Linked Issues or Issue Description
**What happened?**
A legacy remote run can report `workspaceRestoreFailure` after its
dedicated stop has released the source lease. The recorder misses that
source and does not create its file-repair action. Related prior work:
#15637 adds bounded transfer diagnostics; #15718 protects native
accepted finalization. This change addresses the separate legacy
recording order.
**Expected behavior**
Preserve the exact eligible source and record the existing board repair
obligation. Preserve cancellation, later task progress, and newer
execution ownership.
**Steps to reproduce**
1. Acquire an ephemeral remote lease for a legacy run.
2. Complete the dedicated stop-and-retain lifecycle and persist both
stop receipts.
3. Report a workspace copy-back failure from the original adapter
invocation.
4. Observe that the old recorder omits the released source. The
PostgreSQL regression reproduces this order.
**Paperclip version or commit**
|
||
|
|
caa7895f9a |
fix(opencode): report timeouts without claiming deadline expiry (#15789)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The OpenCode adapter reports the outcome of a local or remote execution. > - A provider can report a timeout before the configured execution deadline. > - The adapter treated every timeout as proof that the configured deadline expired. > - This pull request uses a generic timeout message and retains the resolved policy. > - Operators can compare the run duration with its actual configured limit without a false cause claim. ## Linked Issues or Issue Description **What happened?** A remote execution can return `timedOut: true` after a short interval while the sandbox policy is four hours. OpenCode reported `Timed out after 14400s`. It also dropped the resolved policy on that result. Run finalization then used the raw `timeoutSec: 0` configuration, so diagnostics incorrectly reported an unlimited timeout. **Expected behavior** Keep the timeout outcome. Report the resolved policy separately from the failure message. Do not infer which timer fired from the provider's boolean or stderr. **Steps to reproduce** Call the OpenCode adapter with a sandbox execution target and `timeoutSec: 0`. Return a timed-out process result before four hours. Inspect the message and the policy that finalization sends to the run-failure collector. The new tests reproduce this with local fixtures and an in-memory Sentry transport. **Paperclip version or commit** Reproduced on `de042e79efbb7bb88e9716835407882e3ebab188`. **Deployment mode** Legacy OpenCode execution on a local instance or remote sandbox. Refs #14832 for related timeout result preservation; this PR does not change session state. Related PRs #14964, #15659 and #15715 cover silent-run limits, gateway requests and OpenCode v2 support. They do not fix this policy/message path. ## What Changed - Retain the complete existing timeout resolution on both OpenCode result branches. - Report `OpenCode execution timed out` without copying provider output into exception text. - Document that configured policy and the existing `timeoutFired` outcome field do not prove timer origin. - Test policy overrides, sandbox defaults, opt-out, ordinary exits, real local timer expiry, cleanup and real Sentry SDK delivery. ## Verification - 142 focused adapter, stop-metadata and diagnostic tests passed on Node 25.6.1. - The real Sentry SDK contract suite passed 11/11 with the audited optional peer 10.71.0 and an in-memory transport. The new test runs the actual adapter, finalization policy merge and collector. It verifies that raw HTML and credential canaries stay out of the event and unrelated captures stay isolated. - Full workspace `pnpm -r typecheck` and `pnpm build` passed. All hosted CI checks passed on `f4df5cba1d2223d444559de960bbf88dfa985bbf` (54 passed, 2 expected skips). - The local aggregate is not a pass: 15 existing PostgreSQL fixture cases initially failed because this fresh macOS install lacked bundled ICU symlinks. The dependency's existing hydration script repaired the isolated install; all 15 affected cases then passed with real PostgreSQL. No test or production source was changed for that setup issue. The aggregate was stopped after hosted test coverage passed; it is incomplete, not a local full-suite pass. All owned test processes exited. - Greptile scored this exact head 5/5 with no review threads. Independent review found no issues. It ran 58 positive cases and adapter typechecking. Three negative controls failed as expected when it restored the old producer, removed timeout policy, or copied raw stderr into the message. ## Risks The timeout message changes for local and remote OpenCode runs. The resolved policy is additive result data. The numeric timeout, grace period, process result, retry rules, session handling, cleanup and recovery behavior are unchanged. This fixes reporting and does not identify or fix an upstream provider timeout. No schema change or migration is required. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools and independent agent review. The exact service model identifier and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
30c8aa1cc1 |
fix(ui): remove workspace from task and inbox filters (#15788)
updated 14 checked lines erclip is the open source app people use to manage AI agents for work > - The board shows tasks in a list and in the inbox > - Each of those screens has a filter menu > - The filter menu includes a Workspace section > - The list already shows the workspace name, and the user can group by workspace > - This pull request removes Workspace from those filter menus > - The benefit is a shorter filter menu. The workspace label and the group option stay ## Linked Issues or Issue Description No public GitHub issue exists for this change. This description follows the enhancement template. Related pull request: Refs #15403. That pull request also edits the task list. It does not remove the Workspace filter. **What existing behavior does this improve?** The filter menu on the task list and the inbox. **Subsystem affected** ui/ — React + Vite board UI **Current behavior** The filter menu shows a Workspace section when isolated workspaces are on. The user can select one or more workspaces there. The task list also shows the workspace name as a label. The user can group the list by workspace. A workspace value in the page address also limits the list. **Proposed behavior** The filter menu does not show Workspace. The workspace name stays in the list. Group by workspace stays. A workspace value in the page address still limits the task list. A click on a workspace name in the list still limits the list to that workspace. **Reason and benefit** The filter menu repeats a choice that the list and the group control already give. Removal of that section makes the filter menu shorter. Saved links that include a workspace value still open the same limited list. **Breaking changes** The filter menu no longer lets the user pick a workspace. A saved workspace query still works. Decision filters are not part of this change. ## What Changed - Remove the Workspace section from the task list filter menu - Remove the Workspace section from the inbox filter menu - Keep workspace labels, group by workspace, and workspace query scope - Update the filter menu test so it checks that Workspace is absent - Drop a saved workspace selection when preferences load, and keep the other saved filters ## Verification - Run `corepack pnpm exec vitest run --config vitest.config.ts src/components/IssueFiltersPopover.test.tsx src/components/IssuesList.test.tsx src/pages/Inbox.test.tsx src/lib/issue-filters.test.ts src/components/IssueColumns.test.tsx` from `ui/` - Result: 5 files passed, 111 tests passed - Open the task list filter menu. Confirm that Workspace is not a section - Open the inbox filter menu. Confirm that Workspace is not a section - Open a task list with a workspace query. Confirm that the list shows only tasks for that workspace - Group the task list by workspace. Confirm that the groups still appear - A browser check of the live screens was not run in this workspace ## Risks - Low risk. The change removes a menu section. It does not change filter matching - A user who used the menu to pick a workspace must use the workspace label or the page address - Pull request #15403 also edits the task list. Merge order can cause a small conflict in `ui/src/components/IssuesList.tsx` ROADMAP.md does not plan this filter removal. This change does not add a core feature. ## Model Used - Provider: xAI - Model: Grok 4.7 - Capabilities: tool use, code edits, and test execution ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
de042e79ef |
fix(ui): keep code-block pastes in the nested editor (#15773)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - People write a routine description in a rich markdown editor > - That editor contains a nested code block for literal text > - A paste that starts with a markdown mark, such as a dash, goes to the outer editor > - The text does not appear in the code block > - This pull request sends that paste to the nested editor as literal text > - This pull request also adds a copy control next to the Overview heading > - The benefit is that a person can keep a routine description in a code block and copy it to another Paperclip instance ## Linked Issues or Issue Description **What happened?** A paste into a code block in a routine description does not appear when the pasted text starts with a markdown mark, such as a dash. A plain single line still appears. **Expected behavior** The nested code editor receives the paste as literal text. The text stays in the code block. **Steps to reproduce** 1. Open a routine and edit the description. 2. Add a text code block. 3. Click inside that code block. 4. Paste a line that starts with a dash. 5. The line does not appear in the code block. **Paperclip version or commit** `master` at `3389bea`. **Deployment mode** Local dev (pnpm dev) ## What Changed - The markdown editor does not take a paste that starts inside a nested code block. - The same editor is used for descriptions in the routine page and in the rest of the app. - The Overview heading has a copy button. - The button copies the draft description while you edit. - The button copies the saved description when you do not edit. - Unit tests cover the paste path and the copy button. - Screenshots show the heading while you view a description and while you edit it. ## Screenshots The copy icon sits next to the Overview title. The heading component is the production component. The page frame around it is a preview.     ## Verification - Run `corepack pnpm exec vitest run --config ui/vitest.config.ts ui/src/components/MarkdownEditor.test.tsx ui/src/components/RoutineSectionHeading.test.tsx ui/src/lib/routine-description-copy.test.ts` from the repository root. 57 tests passed on the code commit. - Open a routine description. Paste a line that starts with a dash into a text code block. Confirm that the line stays in the code block. - Click the copy button next to Overview. Paste the result into a new routine. Confirm that the description matches the draft while you edit, and the saved description when you do not edit. - Open the screenshots above. Confirm the copy icon is next to Overview in the view state and in the edit state, in light theme and in dark theme. - This workspace did not open a signed-in routine page. The screenshots render the production heading with the app color tokens. ## Risks Low risk. A paste inside a code block now stays in that block. A paste in the rest of the editor still follows the previous markdown path. The copy button only reads the description text. ## Model Used xAI Grok 4.7 with tool use. The model wrote this change in a Paperclip agent run. Context window is large. The model used tools to edit code, run tests, and capture screenshots. ## 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) - [ ] 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 user docs describe this paste path) - [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: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
32745f4e84 |
feat(issues): keep follow-up parents and show the creation source (#15762)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agents delegate work by creating follow-up tasks through the issue API, the CLI, and the chat `create_task` tool > - An agent can omit `parentId` when it creates a follow-up from an ordinary execution task. The API accepts the task as a top-level task. The task hierarchy does not show where the task came from, even though the run provenance is recorded > - The operator must read run history to learn why the task exists. This is slow and it hides delegated work from the parent task > - This pull request keeps the parent link for delegated follow-ups by default, keeps intentional standalone tasks possible, and shows an access-checked "Created from <task> by <agent>" note on the task page from the recorded run provenance > - The benefit is that each agent-created task shows its source without log inspection, while structural parentage, provenance, and blockers stay separate concepts ## Linked Issues or Issue Description Refs #13241 (shows tasks created from a task on the source task page; this PR shows the reverse direction on the created task) Refs #9727 (open proposal for creation provenance tracking) **What existing behavior does this improve?** Issue creation by agent runs, and the task detail page. **Subsystem affected** Server (`POST /api/companies/:companyId/issues`, `GET /api/issues/:id`), shared types, UI task detail page, CLI `issue create`, Paperclip skill docs. **Current behavior** When an agent run bound to an execution task creates a task and omits `parentId`, the task is created with no parent. The task page shows no source. The operator must inspect the run log to find the task that the agent was working on. The source run and the privacy parent are recorded, but the UI does not use them. **Proposed behavior** - When an agent run bound to an ordinary execution task omits `parentId`, the server sets `parentId` to that task. The `issue.created` activity records `parentDefaultedFromRunIssue: true`. - An explicit `parentId: null` keeps the task standalone. Conversation runs (chat handoffs), board or user creates, watchdog follow-ups, a run task the agent may not mutate, a default parent that would cause a delegation cycle, and a default parent the agent may not create a child under (for example a protected assignment policy without a grant) also stay standalone. The server runs the same `tasks:assign` decision with the defaulted parent in scope before it accepts the default. No request that succeeded before now fails. An explicit `parentId` is still checked as before. - `GET /api/issues/:id` returns `createdFrom` with the source task, the run, and the agent. The server resolves it from `origin_run_id`, or from the recorded creation activity for historical rows. It returns `null` when the viewer may not read the source task or the run, when the run is from another company, or when provenance is missing. - The task page shows "Created from <task> by <agent>" in the classic breadcrumb area and in the streamlined Tasks tab. The note is not a blocker and it is shown with or without a parent. - The CLI `issue create` command gets `--standalone`, which sends `parentId: null`. **Reason and benefit** Operators see why a task exists on the task itself. Delegated follow-ups stay inside the parent task tree, so parent completion and child wake-ups keep working. Private and cross-company sources stay hidden. **Breaking changes** None for the API schema. Agents that create tasks from a run and relied on the omitted `parentId` to mean "top-level" must now send `parentId: null` (CLI: `--standalone`). The skill and the spec document this. ## What Changed - `server/src/services/issue-creation-source.ts` (new): resolves a task's creation source from the origin run or the creation activity, scoped to the company, and loads the run-bound task by UUID or identifier. - `server/src/routes/issues.ts`: `POST /companies/:companyId/issues` defaults `parentId` to the run's task when the body omits it (with the exclusions above) and records the default in the activity log. `GET /issues/:id` adds the access-checked `createdFrom` field. - `packages/shared/src/types/issue.ts` and index exports: new `IssueCreationSource` type and the optional `createdFrom` field on `Issue`. - `ui/src/components/task-detail/IssueCreatedFromNote.tsx` (new), `TaskDetailTasksPanel.tsx`, and `IssueDetail.tsx`: show the creation source in both task page layouts and count it in the Tasks tab badge. - `cli/src/commands/client/issue.ts`: `issue create --standalone`. - Docs: `doc/SPEC-implementation.md`, `doc/CLI.md`, `skills/paperclip/SKILL.md`. - Tests: `server/src/__tests__/issue-creation-source-routes.test.ts` (new), `TaskDetailTasksPanel.test.tsx`, `IssueDetail.test.tsx`. ## Verification Run the new server route test (embedded Postgres): ```sh cd server && pnpm exec vitest run src/__tests__/issue-creation-source-routes.test.ts ``` It covers: ordinary delegation gets the parent and `createdFrom`; explicit `parentId: null` stays standalone but still shows the source; conversation handoff and board create stay standalone; a would-be delegation cycle falls back to standalone; a protected source task without a grant falls back to standalone while an explicit parent still returns 403; an explicit cycle still returns 409; historical provenance from the creation activity; missing provenance, a private source for an outsider, and a cross-company run all return `null`. Related existing suites that passed locally (11 files, 313 tests): `issue-created-from-routes`, `issue-create-deduplication-routes`, `issue-agent-mutation-ownership-routes`, `chat-project-tools`, `issue-assignee-invokability-routes`, `issue-watchdogs-routes`, `issue-dependency-wakeups-routes`, `public-mcp`, `native-runtime/task-creation-backlog`, `issue-access-grants-routes`, `issue-list-assignee-filter-routes`. UI: ```sh cd ui && pnpm exec vitest run src/components/task-detail/TaskDetailTasksPanel.test.tsx src/pages/IssueDetail.test.tsx pnpm check:token-gates ``` Manual check: as an agent run bound to a task, `POST /api/companies/:companyId/issues` with only a title. The response has `parentId` set to the run's task. Open the new task; the page shows "Created from <task> by <agent>". The related server suites pass locally (`issue-created-from`, `issue-create-deduplication`, `issue-agent-mutation-ownership`, `chat-project-tools`, `issue-watchdogs`, `public-mcp`, `task-creation-backlog`, `issue-access-grants`, `permissions-upgrade-boundary`). The full `pnpm -r typecheck`, `pnpm test:run`, and `pnpm build` were not run locally because the sandbox has a 4 GB memory limit and the TypeScript compiler is killed on the server project; the CI gates on this PR cover them. ## Risks - Behavior shift for agent clients: a run-created task without `parentId` now becomes a child of the run's task. Clients that want a top-level task must send `parentId: null`. The watchdog, conversation, and board paths are excluded, and the default never adds a blocker. - The default parent inherits the parent's execution workspace, which run-created tasks already inherited from the run's task. - `createdFrom` adds one run lookup, one issue lookup, one access decision, and one agent lookup to the task detail request. It is skipped when the task has no origin run and no creation activity with a run. - Privacy: the field returns `null` unless the viewer can read the source task and the run, so a private source is indistinguishable from missing provenance. ## Model Used Claude Fable 5.1 (`claude-fable-5-1`), Anthropic, run through Claude Code in a Paperclip-managed execution workspace with tool use, shell execution, and a local embedded Postgres for tests. ## 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 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
3ec7309d91 |
feat(voice): add experimental Speko task connection runtime (#15727)
First PR: runtime. UI: #15728. Qualification: #15729.
## Thinking Path
> - Paperclip manages agent work through tasks and governed connections.
> - Chat connections already bind external conversations to those tasks.
> - Speko handles voice and telephony, while the selected Paperclip
agent does the work.
> - A call needs durable session authority, ordered follow-ups, and safe
result delivery.
> - This PR adds an explicit voice transport to the existing connection
runtime.
> - The UI and qualification suites follow in linked PRs. Speko stays
experimental.
## Linked Issues or Issue Description
**Problem or motivation**
Phone and browser voice conversations cannot use the chat connection
task lifecycle. A separate voice runtime is needed to preserve task
authority, retries, and reply history.
**Proposed solution**
Add company-scoped voice sessions, signed callbacks, durable replies,
inbound intake, and an agent-facing outbound-call tool. Reuse existing
tasks, queues, secrets, and publications.
**Roadmap alignment**
This extends the experimental chat connector entry points under Agent
Chat and Connected Apps. The project owner requested this feature.
Refs #11418 for the original provider catalog proposal. This
implementation uses the newer chat connection infrastructure rather than
an MCP catalog-only integration. Refs #15721 for remote OpenCode
startup.
## What Changed
- Add additive voice schema, shared contracts, session APIs, and
provider callbacks.
- Bind browser, inbound, and outbound sessions to an endpoint, task, and
selected agent.
- Add low-trust guest intake in an explicitly selected sandbox and keep
ordinary approval rules.
- Submit task work through session-scoped tools and push approved
replies through Speko POST /v1/calls/{id}/messages.
- Distinguish provider acceptance from confirmed spoken playback.
Reconcile reports without downloading recordings.
- Add protocol, migration, persistence, provider, and
delivery-diagnostic tests.
## Verification
- Master
|
||
|
|
3389bea708 |
fix(recovery): surface exhausted review-path repair (#15764)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - An issue in review needs a saved path to its next action. > - A consumed review path starts one automatic repair run. > - The repair run can finish with only a promise to check later. > - The old code skips another wake but records no recovery action. > - This change records a board decision when that repair also leaves no saved path. > - The issue lock protects a new monitor, a changed owner, or newer work from stale finalization. ## Linked Issues or Issue Description **What happened?** An agent waiting for an external build said it would check again soon. Its one-shot monitor had already fired. The automatic review-path repair also finished without saving another monitor. The task stayed in review with no future wake or recovery card. **Expected behavior** The repair must save a monitor or another review path. If it cannot do so, Paperclip must show an explicit recovery action and stop automatic retries. **Steps to reproduce** 1. Leave an agent-owned issue in review after consuming its last monitor or interaction. 2. Let the source run finish without saving another review path. 3. Let the single automatic repair run also finish without saving a path. 4. Before this change, the task stays in review without a scheduled follow-up. After this change, it is blocked with a board-owned recovery action and an inline notice that links the repair run. Related work: Refs #14757 (preserve active review during stale recovery), Refs #11925 (review-path liveness). This PR handles exhausted repair wakes; it does not change path aging. ## What Changed - Return an explicit exhausted result after the single review-path repair attempt. - Record the recovery action, blocked state, notice, and activity in one transaction. Preserve the original assignee. Keep implicit service reads on the transaction connection. - Recheck the company, owner, saved review paths, and latest issue run before escalation. Publish activity after commit. - Tell the repair agent to save a one-shot monitor and report its check time when an external check remains pending. - Retry missed escalation from the saved terminal repair run during the stranded-issue sweep. Cover restart recovery and rollback with a one-connection pool. - Preserve valid due and claimed monitors for dispatch while the owner permits on-demand wakes. Surface overdue monitors after those wakes are disabled. Keep the future-only liveness classifier unchanged. - Cover monitor repair, stale finalization, company boundaries, duplicate finalization, and failed repair. Document the behavior. ## Verification - `pnpm exec vitest run server/src/services/recovery/review-path-recovery.test.ts server/src/__tests__/heartbeat-issue-liveness-escalation.test.ts server/src/__tests__/issue-liveness.test.ts` — 62 tests passed, including PostgreSQL integration tests. - `pnpm --filter @paperclipai/server exec tsc --noEmit` — passed. - `pnpm -r typecheck` and `pnpm build` — passed. - `pnpm test:run` — 18,144 passed, with three unrelated local fixture failures. Two Git fixtures pass when run with their expected initial branch (`master`); this machine defaults to `main`. The native same-task replacement fixture also fails on an unchanged checkout of master. No unrelated production behavior was changed to accommodate those fixtures. - Apex review — 5/5 on commit `3aca7059848`, with no unresolved review comments. - Latest-head CI — all required checks passed, including test shards, typecheck, build, browser checks, and canary dry run. No merge conflicts. - Repeat the steps above. Confirm that the issue has one recovery notice, one board-owned action, and no second automatic repair wake. Save a monitor during repair and confirm that the issue stays in review. ## Risks - A review repair that exhausts its one attempt now moves the task to blocked and asks the board to act. This is an intentional behavior change. - The check uses the current review-path classifier. A path that the classifier treats as healthy still suppresses escalation. - No schema, API, or UI contract changes are required. Existing recovery controls render the action and notice. ## Model Used OpenAI GPT-6 through Codex, with tool use and code execution. The runtime does not expose a more specific model ID or context window. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (62 tests for this change; full-suite fixture limitations are listed above) - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
8f13ec4d51 |
fix(slack): link created tasks in default reply guidance (#15579)
## Thinking Path > - Paperclip helps people manage AI agents and their tasks. > - Slack agents use shared guidance to write their replies. > - A reply can show a task ID without a link. > - The person must then search for the task. > - This change tells the agent to link each task it creates. > - People can open the task directly from the reply. ## Linked Issues or Issue Description **What existing behavior does this improve?** Default communication guidance for Slack agents. **Current behavior** The guidance does not require a link when an agent creates a task. **Proposed behavior** Require a clickable link to each created task. Use its identifier or title as the link text. Use a public URL supplied by Paperclip. Report when no public URL is available. **Reason and benefit** People can open the task without a separate search. Related work: https://github.com/paperclipai/paperclip/pull/13760 introduced the guidance. https://github.com/paperclipai/paperclip/pull/15576 adds account connection instructions and does not cover task links. ## What Changed - Add task link instructions to the shared Slack communication guidance. - Document the default and the existing conversation snapshot behavior. - Add regression coverage for the guidance in channels and DMs. ## Verification - Passed: `pnpm exec vitest run server/src/services/chat-communication-guidance.test.ts` (10 tests). - Passed: `git diff --check`. - Local full typecheck and build could not finish: the container killed compiler processes (exit 137; cgroup reports OOM kills). The full test run was stopped after this resource limit. CI results are pending. - Added checks for task links, public URL sources, and missing URLs in Slack channels and DMs. ## Risks - Low risk. This changes prompt text only. - Existing conversations keep their original guidance snapshot. New conversations receive the new default after deployment. - This is agent guidance. It does not force a link into provider output. ## Model Used OpenAI Codex, GPT-6. The runtime did not expose an exact model revision or context window size. Used reasoning, code inspection, file editing, and command 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 - [ ] 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 |
||
|
|
43212cb2b7 |
fix(slack): require result and review updates in conversation prompts (#15611)
## Thinking Path > - Paperclip helps people manage AI agents and their work. > - People can ask an agent to do work from a Slack thread. > - The agent must return results and review requests to that conversation. > - The current prompts explain reply format but do not require these updates. > - This change adds one set of instructions to initial prompts and later turns. > - Users can see the result and the action needed for review in Slack. ## Linked Issues or Issue Description **What happened?** An agent can save results or a plan in Paperclip without telling the user in Slack that the result is ready or that review is required. **Expected behavior** The agent reports results in the originating conversation. If review is needed, it saves the required interaction and tells the user what to review and how to act. **Steps to reproduce** Start work in a Slack thread. Have the agent prepare a plan that needs approval or produce a deliverable. The prompt does not explicitly require a result or review update in that thread. Related: #15579 adds task links to Slack replies. This change covers results and review requests, including later turns. ## What Changed - Add shared instructions for result and review updates. - Include the instructions in initial Slack guidance and per-turn guidance. - Keep the normal approval gates, delivery checks, and duplicate-message rules. - Add tests for channel and direct conversations, and for fresh and resumed native and CLI turns. - Update the Slack skill documentation. ## Verification - Passed: guidance and heartbeat context tests (65 tests in two files). - Passed: `git diff --check`. - Workspace typecheck and build could not complete because this sandbox has no `cargo` binary. - The full local test run was stopped due to the sandbox memory limit. GitHub CI runs the full checks. - GitHub CI and automated review are pending. ## Risks - Low risk. This change updates prompt text and tests. It does not change transport or permissions. - Prompt instructions guide agent behavior. They do not guarantee that Slack delivery succeeds. ## Model Used - OpenAI GPT-6 (Codex). Used reasoning, code editing, and command tools. The runtime does not expose a more specific model ID or context window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] 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 |
||
|
|
baa94bbea5 |
Fix idle sleep checks for finished login and wake history (#15761)
## Thinking Path
> - Paperclip manages AI agent work and keeps a durable record of each
run.
> - Automatic idle sleep must wait for accepted work and provider
cleanup.
> - The current sleep check treats every saved login session as active
work.
> - It also treats every coalesced wake request as pending work.
> - These records can remain after their work and cleanup finish.
> - This pull request checks the cleanup and linked-run evidence before
it treats these records as history.
> - The change lets otherwise idle instances sleep and keeps uncertain
work awake.
## Linked Issues or Issue Description
**What happened?**
A finished login session blocks idle sleep after its provider resource
has been removed. A consumed coalesced wake also blocks sleep after its
linked run finishes.
**Expected behavior**
Finished history should permit sleep when cleanup or run completion is
confirmed. Active work, missing evidence, retry debt, and pending
accounting must still block sleep.
**Steps to reproduce**
1. Create a finished login session with a retained provider reference.
2. Record a successful release for the same resource, company, and
environment.
3. Check idle sleep safety under an owned, quiet admission hold.
4. The current check reports background work. The new check treats the
session as history.
5. Repeat with a finished coalesced wake linked to a finished run in the
same company and agent.
**Paperclip version or commit**
Reproduced on master at
|
||
|
|
e9dae72c0c |
ci: use a Docker Hub mirror for image builds (#15756)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Image workflows build the exact source selected for a release. > - BuildKit fetches the Dockerfile frontend and base images from Docker Hub. > - Docker Hub token failures can stop these builds before application code runs. > - BuildKit supports a public image cache with canonical Docker Hub fallback. > - This pull request configures that cache in the two affected image builders. > - The build inputs and publication gates stay the same. ## Linked Issues or Issue Description **What happened?** [Docker run 37995539183](https://github.com/paperclipai/paperclip/actions/runs/37995539183) failed before application builds started. The AMD64 job received HTTP 504 from the Docker Hub token endpoint while it fetched `docker/dockerfile:1.20`. The ARM64 job fetched the frontend, then received the same error while it resolved `node:24-trixie-slim`. [Release preview run 37992058052](https://github.com/paperclipai/paperclip/actions/runs/37992058052) also failed while it fetched the frontend. **Expected behavior** Use the supported public cache when it has the requested Docker Hub image. Retain canonical Docker Hub fallback when the cache has no usable copy. Preserve build and publish failures. **Steps to reproduce** Run either affected image builder during a Docker Hub token failure. The unconfigured BuildKit container contacts Docker Hub for the frontend and base image. It cannot use a host Docker daemon mirror for those build requests. **Paperclip version or commit** The observed Docker run used `00d944f96c8c4aba8332ce224df2be73a601228a`. The preview used `b6b3cb3761dabd1bd668054e7a99a245d53707c4`. **Deployment mode** GitHub Actions image builds. No application runtime change. The public PR and issue search found no matching open registry-mirror change. #15743 addresses a separate npm canary dependency publication failure. ## What Changed - Add the official `docker.io` to `mirror.gcr.io` BuildKit configuration to the public Docker build matrix and the release preview image builder. - Keep all existing action references, image sources, targets, build arguments, platforms, credentials, cache settings, outputs, permissions, triggers, and publication gates. - Extend the existing dependency-free workflow tests to check mirror placement, verified HTTPS, both native platforms, preview isolation, and publication access. - Document cache eviction, tag freshness, canonical fallback, and builder bootstrap limits. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/cloud-source-verification.test.mjs scripts/standard-image-contract.test.mjs`: 43 passed on the final source. No dependency install required. - Six offline controls removed each builder's mirror, changed the registry or cache host, enabled insecure transport, or added preview registry login. Each control failed the new check as expected. - `actionlint -shellcheck='' .github/workflows/docker.yml .github/workflows/release.yml`: workflow validation passed. With optional ShellCheck enabled, the ten diagnostics match the unchanged base exactly. This PR changes no shell scripts. - A real TOML parser accepted the inline configuration. Removing the new block from each workflow produced byte-identical base files. - Read-only registry metadata checks confirmed matching raw bytes and SHA256 values for the current Node24 index and both native manifests. The Dockerfile frontend index and both native manifests also match Docker Hub and Google. No image config blobs or layers were fetched. - Full application tests, typecheck, and build were not repeated locally because application source is unchanged. [Hosted CI](https://github.com/paperclipai/paperclip/actions/runs/37998739440) passed the full required checks on `25fd57f`, including all test shards, build, typecheck, policy, E2E, and canary dry run. - The supply-chain advisory returned neutral because it cannot verify these infrastructure edits. It reported zero annotations. Independent review confirmed all action references, Dockerfiles, package files, and lockfiles are unchanged. The other 53 checks passed; two Storybook checks skipped as expected. - Independent review approved all four changed files and the workflow graph. Greptile scored the same source 5/5 with no unresolved comments. - No Docker build, workflow rerun, image publish, or deployment was started for verification. A normal image workflow after merge must prove full image acquisition. ## Risks Google is a cache, not an outage guarantee. It can evict images. Mutable tags can lag upstream changes or deletions. Matching manifests now does not prove future tag freshness or blob availability. A cache miss can still fail when Docker Hub is unavailable. The initial `moby/buildkit:buildx-stable-1` bootstrap uses the host Docker daemon before this configuration takes effect and remains dependent on Docker Hub. The registry mirror applies to image pull and resolution only. GHCR publication and cache writes keep their existing routes. See [Docker's supported configuration](https://docs.docker.com/build/ci/github-actions/configure-builder/#registry-mirror) and [Google's cache limits](https://docs.cloud.google.com/artifact-registry/docs/pull-cached-dockerhub-images). ## Model Used OpenAI GPT-6 through Codex, with reasoning and code execution tools. The exact service variant and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
935fb63ed5 |
fix(release): retry incomplete canary dependency publications (#15743)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Release checks must test the exact package that a new user installs. > - The canary onboarding smoke uses a fresh npm dependency graph. > - An upstream package can reference a dependency before that version is available. > - The smoke then exits before Paperclip onboarding starts. > - This pull request retries only that npm acquisition failure within the existing startup limit. > - Onboarding still runs once, and all other errors remain visible. ## Linked Issues or Issue Description **What happened?** [Release run 37986221440](https://github.com/paperclipai/paperclip/actions/runs/37986221440) published `2026.1009.0-canary.13`, then failed the onboarding smoke. The retained server log contains npm `ETARGET` for `@aws-sdk/credential-provider-env@^3.972.73`. The upstream parent package was published before this dependency. The missing version became available during the smoke startup. Paperclip onboarding never ran. **Expected behavior** Retry a short dependency publication window before onboarding starts. Stop on a permanent install failure. Never repeat onboarding to hide a startup failure. **Steps to reproduce** 1. Start the exact-version canary smoke with an empty npm cache. 2. Make the first npm install return `ETARGET` because a dependency version is not available. 3. Make the next install succeed after registry metadata changes. 4. Confirm that onboarding starts once. Repeat with permanent `ETARGET` and an unrelated failure; onboarding must not start. **Paperclip version or commit** The observed release source was `cb291bf1298ab484a2792c05eb977f3440f1f351`. **Deployment mode** Linux release CI. The change affects the canary smoke harness. Related: #15712 fixes a separate lockfile mismatch in the smoke's repository dependency install. This change covers the fresh published-package npm install. ## What Changed - Separate npm package acquisition from the onboarding command. - Retry only the final npm `ETARGET` error, up to three attempts with online metadata and clean temporary prefixes. - Share a two-minute acquisition budget across attempts and backoff. Keep the existing five-minute Playwright startup limit. - Run the installed exact-version CLI once. Preserve authentication, network, lifecycle, and onboarding failures. - Stop owned process groups on cancellation and remove owned install prefixes. Keep server logs and instance data for diagnostics. - Keep dependency-free helper subprocess tests in the required policy lane. Run real Playwright lifecycle tests in the required release-registry lane after its dependencies are installed. - Document the bounded behavior in the release runbook. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs`: 24 passed in a clean source snapshot with no `node_modules`. These cover transient and permanent missing versions, other npm errors, nested error codes, onboarding failure, deadline expiry, and cancellation. - `pnpm test:release-registry`: 153 passed, including real Playwright teardown with a descendant that ignores SIGTERM and startup-timeout cleanup of a detached npm installer. - `pnpm -r typecheck`: passed. - `pnpm build`: passed. - `pnpm test:run`: deliberately stopped after complete hosted CI passed; this is not a local full-suite pass. The run's 15 warm-runtime real-DB cases failed before assertions because the local macOS PostgreSQL package lacked library symlinks after installation with `--ignore-scripts`. After running the package's local hydration step, all 15 affected cases passed in a targeted rerun. The remaining aggregate was stopped with exact owned-process cleanup. - [Hosted CI](https://github.com/paperclipai/paperclip/actions/runs/37994486323) is complete and green at `1c80e6f`: all tests, build, typecheck, policy, release registry, E2E, and canary dry run passed. Greptile scored the same head 5/5 with no unresolved comments. - Independent review covered all seven changed files and the exact policy and release-registry commands. It also used real npm 11.9 against a loopback registry: a required version was absent, then became available. The retry refreshed metadata and started the installed exact-version CLI once. The one-attempt negative control failed. - The new subprocess tests use local npm and CLI fixtures. They do not contact a registry or start a real Paperclip instance. - The patch preserves the exact-version clean-install check. It adds no dependency pins, credentials, or workflow reruns. ## Risks The install phase now has a two-minute budget inside the existing five-minute startup limit. An unusually slow valid install can still fail the smoke. Permanent missing versions remain failures after the bounded retry. The lifecycle tests cover the Linux release runner behavior; Playwright does not support graceful SIGTERM on Windows. No application, database, or deployment behavior changes. ## Model Used OpenAI GPT-6 through Codex, with reasoning and code execution tools. The exact service variant and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes: #` 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> |
||
|
|
23b9aaa8e6 |
fix(release): reuse publisher lockfile for canary smoke (#15712)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Every master push publishes an exact canary and tests its onboarding flow. > - The publisher resolves dependencies before building, while the smoke job checks out the committed lockfile again. > - Patch or manifest changes can land before the separate lockfile refresh, so the smoke fails before testing the published app. > - This pull request passes the publisher's resolved lockfile to the same-source smoke job. > - The smoke keeps frozen dependency validation and tests the exact published canary version. ## Linked Issues or Issue Description Refs #10393, #13689. Related work: #13690 documents lockfile drift; #12115 addresses refresh-PR check triggering. This change addresses the canary smoke handoff. #15678 only refreshed the opencode importer. #15164 incidentally corrected the earlier patch hash on master. **What happened?** Canary publication succeeded, but the fresh onboarding smoke install failed with `ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` on sources `0b80ea17ef` and `ab8dcab809`. The committed `acpx@0.13.1` hash no longer matched its patch. A later run on `6080daf262` failed with `ERR_PNPM_OUTDATED_LOCKFILE` after an `opencode-ai` manifest addition. The current master lockfile has since caught up; the workflow still permits this race on future changes. **Expected behavior** The exact published canary reaches the onboarding smoke with test dependencies resolved for its source. A mismatched or missing lockfile must fail validation. **Steps to reproduce** Check out either affected source and run `pnpm install --frozen-lockfile` with pnpm 9.15.4. The smoke fails before a browser starts, although the publisher already installed that source with a resolved lockfile. ## What Changed - Pin both canary publisher and onboarding smoke checkouts to the triggering SHA. - Save the publisher's resolved lockfile before restoring tracked files or rewriting release versions. - Restore that same-run, source-named artifact before the unchanged frozen smoke install. - Add offline real-pnpm regressions for patch-hash and manifest drift, plus wrong-source rejection and workflow binding checks. - Document artifact retention and job reruns. No manifest or committed lockfile changes. ## Verification - Focused release workflow, exact-source verification and image-contract tests: 45 passed. - Negative control: both new real-pnpm fixture cases fail against the original workflow with their respective original lockfile errors; both pass with the handoff. - `pnpm install --frozen-lockfile` passed on the current source. - `pnpm -r typecheck` and `pnpm build` passed after reclaiming disposable build-cache space. - The browser onboarding smoke passed against exact published `2026.1009.0-canary.7`: 1 test passed using a fresh temporary instance. - Full local `pnpm test:run` was attempted twice. The first hit disk exhaustion; the second reported one chat integration failure and then a Vitest worker `ENOTCONN` crash before completing. This is not a full-suite pass. The named chat case passed in isolation without changes. All full sharded PR CI checks passed on the final head. - Independent source review and a clean-checkout run also passed all 45 focused tests, with separate real-pnpm negative controls. - The supply-chain scan is neutral because managed intelligence could not scan the pinned official `download-artifact` action. It reported no defect; independent review inspected the action source, same-run scope and v4/v4 compatibility. - Reviewed the diff for secrets, personal data and generated artifacts; none found. ## Risks - The smoke now depends on a same-run GitHub artifact retained for 14 days. A missing artifact intentionally fails instead of resolving a different dependency set. - A publisher rerun replaces its source-named artifact; a smoke-only rerun reuses the retained artifact. - Frozen validation and the exact published version remain required. The source app and publication logic do not change. ## Model Used OpenAI GPT-6 through Codex, with tool execution and parallel independent review. The exact serving variant and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
ce024457f3 |
perf(server): wake email work from commits and deadlines (#15750)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Email connects agent tasks to durable incoming and outgoing messages. > - The email worker scans the database every second, even with no inboxes. > - These queries prevent idle database connections from closing. > - This pull request wakes email work from committed writes and known deadlines. > - Empty email installations stop polling. Existing delivery and catch-up guarantees remain. ## Linked Issues or Issue Description Refs #15625. Related standby work: #15314. **What existing behavior does this improve?** The AgentMail background worker and its database traffic when idle. **Current behavior** Every instance queries active email endpoints each second. Active inboxes also scan delivery queues each second even when no work is due. **Proposed behavior** Scan once at startup. Wake after endpoint and queue transactions settle. Restore the next retry or catch-up deadline from existing rows. An instance with no active inboxes has no recurring email queries or timer. **Reason and benefit** Thousands of empty instances should not keep their databases awake to discover that email is still unconfigured. ## What Changed - Use the shared transaction-aware coordinator for email work, including changes made by separate service objects on the same database owner. - Signal endpoint activation and control changes, incoming events, and outgoing sends inside their transactions. - Add an optional deadline to the coordinator. Email uses persisted retry times, mailbox catch-up times, and socket reconnect times. Only the first pending send in each conversation determines its send deadline. - Preserve startup recovery, lease fences, idempotency, standby suppression, idle drain, and shutdown. - Update the sleep inventory and add quiet-idle, commit, activation, retry, and lifecycle tests. ## Verification - Focused coordinator, email idle, and warm standby tests: 20 passed locally. - Database-backed email integration suite: 41 passed locally with real PostgreSQL and a simulated AgentMail provider. - After review, the updated delayed-reply regression passed separately: 1 selected test passed, 40 intentionally filtered out. It verifies no scans before the first reply deadline and delivery of both replies in order. - `pnpm -r typecheck` and `pnpm build` passed locally. - The local `pnpm test:run` was interrupted after its checkout was removed externally. Completed local checks above are preserved. The [final-commit hosted CI matrix](https://github.com/paperclipai/paperclip/actions/runs/37997072212) passed: 54 successful checks, 2 expected Storybook skips, no failures. It includes the full general and serialized test matrix, runner checks, browser tests, build, typecheck, and canary packaging. - Greptile: 5/5 on `ec98f3b86ee476d75e0edf3366b357377ea09d69`, with no actionable findings. ## Risks - New email producers must register work inside their write transaction. No new tables or migrations are required. - Signals are local to one database owner and its dedicated pools. Independent processes and direct SQL do not emit them. Startup recovers existing work; configured inboxes also retain their recovery deadline. - Active inboxes still catch up each minute. WebSocket mode still renews its lease every 20 seconds. This change does not provide external waking or make active sockets sleep. - Provider calls were simulated in tests. No live email was sent. ## Model Used OpenAI Codex, GPT-6, with reasoning, repository inspection, code execution, and test tools. The exact deployment model ID and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.1009.0-canary.17 nightly/v2026.1010.0-nightly.0 |
||
|
|
417db14e7d |
fix: show credential access errors in task chat (#15741)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Agents use AI connections to run tasks for a responsible user. > - A connection can deny access when its owner has not shared it with that user. > - The task conversation hides this cause behind a collapsed failure marker. > - People need to see which connection blocked the agent and how to fix it. > - This pull request shows an expanded access error in the task conversation. > - The error names the agent and connection, and links to the agent's AI settings. ## Linked Issues or Issue Description **What happened?** A task could fail because its responsible user could not use the agent's AI connection. The user saw a temporary error toast and a collapsed task failure. The task did not clearly explain the access problem. **Expected behavior** The task should show a visible error that names the agent, the connection, and the person who lacks access. For example: "Codie is configured to use Dotta's API Key, but you don't have access to that credential." It should offer a link to change the AI connection. **Steps to reproduce** 1. Configure an agent with a personal AI connection. 2. Start a task for a user who cannot use that connection. 3. Open the task after the run fails. 4. Check that the access error stays visible and links to AI settings. Refs #15714. That change classifies expected connection-sharing denials. This change makes the same failure clear in task chat. ## What Changed - Keep the connection display name in private error metadata when a sharing check denies access. - Store a private grant reference for the name visibility check. Use one rule for task summaries and full run responses. Show the name to the affected user and the connection sharing audience. Other task readers see a generic label. Strip grant IDs from public run responses. - Show an expanded error card for native and legacy task runs. Use "you" only when the viewer is the responsible user. - Link to AI settings and the failed run. Preserve names on resumed native runs. Hide the old error after a newer successful attempt. - Add full task-page Storybook examples, focused tests, and design guidance. ## Verification - Passed 249 focused tests for task chat, error text, private error metadata, and the real database run summary. These include resumed native runs and viewer access rules. - Passed all UI token gates on the rebased branch. - Checked the production task page in Storybook. Verified the viewer's error, another user's error, mobile layout, and a newer successful attempt. - Passed `pnpm -r typecheck` and `pnpm build` in a clean checkout with Node 24 and the pinned pnpm version. Passed the final server typecheck after the response filter changes. - Passed the real database route regression for the connection owner, affected user, and another task reader. Passed the registered secret redaction tests. - The local route checks needed `--testTimeout 60000` for cold imports. A broader local route run hit cold-import timeouts and an old fixture assertion that is now fixed. The duplicate local `pnpm test:run` aggregate was stopped to free resources. The full suite passed in CI with the normal timeouts. - Passed the full [final-commit CI workflow](https://github.com/paperclipai/paperclip/actions/runs/37996148342), including all server, UI, runner, browser, typecheck, build, and canary packaging gates. All 54 executed checks passed; two Storybook jobs were skipped. Greptile reviewed the final commit at 5/5 with no remaining findings, and every review thread is resolved. - Review the Storybook group `Task / Credential access` for the notice and full task-page examples. ## Risks - Only the allowed connection display name enters the compact run summary. Credential secrets, grant IDs, and arbitrary error details do not enter it. - Existing runs can lack the connection name. They show a clear fallback message. - The notice uses the existing task-run relevance rules. A newer attempt or a completed task hides the old failure. - No schema migration or API permission change is required. ## Model Used OpenAI GPT-6 through Codex, with tool execution and browser verification. The exact serving variant and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.1009.0-canary.16 |
||
|
|
26d71d8def |
Fix human author identity and viewer-relative alignment in task chat (#15494)
Preserve human author identity in task chat and align only the current viewer on the right. Show other humans and agents on the left with their own identity. Include mixed-author Storybook journeys and regression coverage. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
ed2c22ea8c |
feat(connections): simplify dedicated GitHub App setup (#15416)
## Thinking Path > - Paperclip manages agent work and the tools each agent can use. > - GitHub bots need their own App identity and restricted repository access. > - Manual App configuration and repeated setup gates make that connection hard to finish. > - GitHub can create an App from a manifest, but people must approve creation and repository access. > - Each Paperclip stack should own configuration, credentials, signature verification, and task admission. > - This change uses Cloud as an encrypted callback and event gateway, then completes setup in the stack. > - GitHub review bots have their own experimental setting. Chat connector opt-in does not control them. ## Linked Issues or Issue Description **What existing behavior does this improve?** Dedicated GitHub App setup, bot settings, and task-scoped GitHub replies. **Current behavior** Users must configure an App, copy credentials, repeat repository selection, and complete manual verification gates. Review settings are hard to scan. Mentions in descriptions can be missed, and automatic completion text can produce an extra GitHub comment. **Proposed behavior** Choose an agent and connect GitHub under a personal account or organization. GitHub asks for creation and installation consent. Paperclip resumes the same draft, stores secrets locally, imports access, verifies delivery, and opens Settings. Each accepted request has one editable App-owned comment for progress and results. Review assessments produce deterministic checks for the reviewed commit. **Breaking changes** GitHub bots require their own default-off experimental opt-in. The setup-method and delegated-agent screens are removed. Per-person automatic-run flags remain readable but are replaced by author filters. Existing connections, direct webhooks, saved restrictions, and manual existing-App recovery remain supported. Companion gateway: https://github.com/paperclipai/paperclip-cloud/pull/688 (merged). The roadmap and related PRs were checked; no duplicate dedicated-App wizard was found. ## What Changed - Add an independent **GitHub review bots** setting across the catalog, routes, identity admission, and task controls. Existing bots continue running when the UI setting is off. - Replace setup with Choose agent and Connect GitHub. Support personal and organization owners, inline low-trust conversion, saved drafts, known organization suggestions, automatic completion, and same-App recovery. - Keep manifests, OAuth PKCE, credential exchange, vault storage, installation verification, and original webhook-signature validation in the stack. Use the Cloud sealed gateway for public callbacks and outbound local delivery. - Add resumable owner metadata in migration 0323. Retry a failed registration renewal through the same durable replacement rather than creating another App route. - Support authorized mentions in issue and PR bodies, comments, inline comments, and review summaries. Preserve attachments, edited-source identity, duplicate protection, and lifecycle invalidation. Filter requests explicitly addressed to another connected bot. - Give agents task-scoped review, comment, and update tools. Update one working comment through progress and final output. Close coalesced requests and recover delayed acknowledgements, including deleted earlier working comments. Preserve automatic replies for legacy connections without saved review configuration. Preserve partial publication evidence and quarantine uncertain automatic fallbacks without blocking Board messages or questions. - Reorganize Settings and Access with rich slash-skill instructions, numeric passing scores, clear automation controls, formal-review tooltips, member and contributor sections, and verified App branding links. Preserve invalid score drafts and automation choices across tabs. - Paginate repositories in 20-row batches with search and a true connection-wide toggle. Batch verification at GitHub's 500-ID token limit. Keep saved repository overrides while hiding their editor. - Give each review a detail URL that remains usable beyond the newest 100 records. Synchronize the manager OpenAPI contracts and add recovery, authorization, UI, and browser regressions. - Reconcile the current master branch and retain its agent avatar, feature catalog, and extracted heartbeat preparation code. Preserve a saved test-drive port and recover from an occupied high port. ## Verification - Focused UI, independent experimental-setting, and CLI tests: 199 passed. - `pnpm -r typecheck`, `pnpm build`, and `pnpm check:token-gates` passed. The broad local Vitest attempt was interrupted after resource timeouts and stale expectations; the affected regressions passed focused reruns. The latest-head full CI matrix passed, including all browser shards, server/chat suites, builds, typechecking, canary packaging, and Docker context integrity. A Docker Hub 429 required a CI retry; it passed without changing the code. - Final review repairs: 127 attachment/event tests and server typecheck passed. All 13 final integration regressions passed under the normal CI timeout, covering legacy reply compatibility, deleted coalesced comments, inline-only review completion, progress edits, and native final recovery. Restart-safe description/review attachments passed the attachment suite. - Final regressions: four reply/lifecycle tests, both native GitHub wait tests, 171 feature-gate/reply-contract tests, the routed review preview, and five scheduler/reply regressions passed. The final fixture repair also passed all six setup-continuation cases and all three complete chat-test shards in CI, covering terminal receipts and retries under the normal CI timeout. One loaded-host receipt run exceeded its local timeout; the exact case passed in an isolated rerun and the complete CI shard. - GitHub integration tests cover personal and organization setup, retry recovery, edited mentions, attachment provenance, coalesced requests, delayed acknowledgements, partial review writes, old review URLs, and company boundaries. - Browser qualification: both GitHub journeys, all five provider setup/management journeys, and the GitHub uncertain-send recovery journey passed. GitHub setup, reconnect, and task replies run with chat disabled; chat enabled alone cannot expose GitHub bots. The disposable qualification database was removed after testing. - Earlier live qualification verified App-owned issue replies, native slash-skill invocation, progress comment edits, and a 5/5 PR review with a passing current-head check in the dedicated permissions-smoke repository. These live checks did not use personal credentials as bot execution authority. ## Risks - Deploy the merged Cloud gateway protocol before the stack update. Each callback and encrypted event must retain the original instance and tenant binding. - Migration 0323 uses idempotent column additions for test installations that already applied the earlier draft migration number. - A verified connection does not prove runtime isolation or a completed review. Runtime checks remain separate. - Required merge checks must be configured in GitHub. A passing numeric score does not formally approve a PR; approval and request-changes tools remain opt-in. - Existing-App credentials cannot silently renew an uncertain manifest exchange. Recovery preserves the existing App, draft, connection, and agent. - Repository changes save immediately. Global toggles affect all currently available repositories, including unloaded rows, without granting new installation access. - A failed or uncertain tool write suppresses automatic fallback text; the governed outbox retains its evidence. Deleted or replaced response comments are not recreated through a personal credential fallback. - GitHub logo upload remains an optional human action in GitHub App settings. Runtime provisioning, delegated setup, screenshot publication, and production push delivery remain deferred. ## Model Used OpenAI Codex, based on GPT-6, with tool use and code execution. The 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 references) - [x] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (focused suites; complete test matrix is checked in CI) - [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> |
||
|
|
00d944f96c |
fix(chat-channels): resume follow-ups after Slack Stop (#15737)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Chat channels let verified users stop an agent and send another message from Slack. > - Native execution needs the stopping user's identity to recognize a deliberate Stop. > - Slack omitted that identity, so a stopped run could create a recovery hold. > - A pending AI login request for another user could then block the new message. > - This pull request records the verified stop actor and scopes AI login waits to the current user. > - Users can start a fresh turn after a verified Stop while access and approval gates remain in force. ## Linked Issues or Issue Description **What happened?** A user stops a native run from its bound Slack thread. Slack confirms the Stop. The user sends a follow-up and receives a queued acknowledgement, but execution does not start. The run can acquire a recovery hold. A pending AI login request addressed to another user then blocks explicit continuation. **Expected behavior** An acknowledged operator Stop ends the current response. A new authorized user message starts through normal admission after the previous execution has stopped. An AI login request for another user stays pending but does not gate this user's turn. Tool access, approvals, unknown identities, and unconfirmed cleanup still block execution. **Steps to reproduce** 1. Start a native agent run in a Slack thread with a pending AI login request addressed to a different user. 2. Stop the run with the signed Slack Stop action. 3. Send a new message from a verified linked user. 4. Observe the recovery hold and the pending-decision message on the saved follow-up. Refs: #15421 for the related verified linked-user authority path. That change separates guest and trusted tasks; this change handles cancellation and login wait scope. ## What Changed - Pass the verified Slack user's identity to canonical run cancellation. - Scope AI login waits by the current run's responsible user, with a company-scoped lookup. - Use the same wait predicate for explicit continuation, native execution, and recovery decisions. - Admit already-saved native follow-ups posted after Stop through the existing continuation checks. Keep pre-stop and delivered messages held. - Keep pending cards and their authorization state intact. - Add regression tests for signed Slack Stop, fresh-turn admission, and same-user, unknown-user, tool-access, and company-boundary gates. - Give the two affected database setup hooks the standard 90-second budget. - Document Slack Stop and user-scoped AI login waits. ## Verification - Red: signed Slack Stop omitted the cancelling user; direct continuation and already-saved post-Stop continuation both returned `null`. - Green: 57 continuation/audience checks passed, including legacy operator Stops, pre-stop input, delivered input, same-user login, unknown identity, company boundaries, cleanup, ownership, pauses, and approvals. - The combined signed Slack Stop and original gate check passed: 39 tests. - Existing native question/completion suite: 33 tests passed. - `pnpm -r typecheck` passed. - `pnpm build` passed. - Rebased regression check: 18 tests passed on current master. The reviewed database-support setup change passed all 7 audience checks. - Full latest-head CI passed, including all server, chat, package, serialized-server, Runner, browser, build, and canary gates. - The duplicate local `pnpm test:run` was stopped after the full CI matrix passed. It was slow on the contended host; no failure had been reported. The focused reproduction command is: ```sh pnpm exec vitest run server/src/services/issue-question-context.test.ts server/src/services/explicit-native-continuation.test.ts server/src/__tests__/chat-channels.integration.test.ts --fsModuleCache --testTimeout 60000 -t 'AI connection wait audience|scopes connection waits|resumes an already-saved follow-up|durably retries a signed Slack session stop' ``` - Manual evidence: inspected the bound thread's cancelled run, queued messages, recovery hold, and login card. The staging deployment has not been changed. ## Risks - AI login wait behavior changes only when both the addressee and current responsible user are known and differ. Missing identity retains the gate. - Starting a new turn does not grant access or answer the old card. Credential selection still uses the new run's authority. - Process, remote cleanup, recovery, task ownership, pause, budget, and approval checks remain in place. - No schema migration or public API change. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository inspection, browser inspection, and code execution. The exact runtime model ID and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
5cf90417d6 |
fix(ui): confirm cancellation from monitor cards (#15735)
## Thinking Path > - Paperclip helps people manage AI agents and their tasks. > - A task monitor schedules a later agent check. > - The monitor card shows when that check will run. > - The card has no direct control to cancel the monitor. > - This change adds an X button and a confirmation dialog. > - The operator can stop the scheduled check from the card. ## Linked Issues or Issue Description **What existing behavior does this improve?** The monitor card on the task page. **Current behavior** The operator must open task properties to clear a monitor. **Proposed behavior** Select the X in the top right of the card. Select Keep monitor to leave the schedule in place. Select Cancel monitor to remove the scheduled check. **Reason and benefit** The operator can cancel the monitor where its schedule is shown. Confirmation helps prevent an accidental cancellation. **Breaking changes** None. The change uses the existing task update API. ## What Changed - Add an accessible X button at the top right of the monitor card. - Confirm cancellation before the task update. - Keep the dialog open with an error if the update fails. - Preserve the other execution policy settings and refresh the task after success. - Reject stale policy writes under the task row lock with an optional expectedExecutionPolicy snapshot. - Document the snapshot field and add a database test for stale cancellation. - Restrict snapshot requests to policy-only edits before execution-control actions. - Add seven route tests for rejected mixed requests and absent policy updates. - Keep automatic retry waits separate from monitor cancellation. - Add component and task page tests. ## Verification - `pnpm check:token-gates` passed. - Monitor banner and task page tests passed: 199 tests. A targeted database test and seven route tests also passed. - UI typecheck and production build passed. - Open a task with a scheduled monitor. Select X, then Keep monitor. The schedule must remain. - Select X, then Cancel monitor. The card must disappear after the update. - Local full build reached the Rust runner build but could not complete because Cargo is absent. CI must verify the full build. - Full repository typecheck, build, test suites, and E2E checks passed in CI for the final commit. Local full checks were limited by missing Cargo and workspace memory. ## Risks - Low risk. Cancellation uses the existing company access checks and activity log. - A cancelled monitor no longer wakes the agent. The dialog explains this effect. ## Model Used OpenAI Codex, GPT-6. The runtime does not expose a more specific model ID or context window size. Used code editing, shell commands, and tests. ## 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> |
||
|
|
c27ee928b0 |
refactor(server): extract heartbeat run completion (#15732)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Heartbeat execution connects provider runs to task state, accounting, and recovery. > - Earlier refactors moved scheduling and lifecycle services into the heartbeat folder. > - The remaining executor still contains result persistence and two large failure handlers. > - These handlers must preserve the outcome chosen by Stop or native recovery. > - This pull request moves them into a typed run-completion module at the same call and catch boundaries. > - Reviewers can now inspect completion separately from provider dispatch and resource cleanup. ## Linked Issues or Issue Description Refs: #15717. Related behavior work: #13857 (agent status convergence). **What existing behavior does this improve?** Maintainability of heartbeat execution and terminal result handling. **Subsystem affected** server/ — orchestration services. **Current behavior** The main heartbeat service has 9,335 lines. Result persistence, accounting, presentation, session updates, and execution/setup failure handling are embedded in `executeRun`. **Proposed behavior** Move those steps into `server/src/services/heartbeat/run-completion.ts`. Keep the existing decisions and ordering. The main service becomes 8,125 lines, a reduction of 1,210 lines. **Reason and benefit** This creates a substantial boundary for the next execution refactor. It also gives terminal handling direct tests without starting a provider. **Breaking changes** None intended. Public heartbeat exports and method signatures remain compatible. ## What Changed - Add `createHeartbeatRunCompletion` with `completeRun`, `failRun`, and `failRunSetup` handlers. - Move terminal-result persistence, accounting, response presentation, retry decisions, and session updates with their failure helpers. - Keep Stop barriers and native ownership/recovery exceptions in the executor. Keep the outer cleanup in its original location. - Pass live output getters and an immediate trace-finalization callback so cleanup sees state even if a later completion step throws. - Add 19 boundary tests, update the existing publication-order source guard to read the extracted module, and document the module in the developer guide. ## Verification - Passed `pnpm -r typecheck` and `pnpm build`. - Structural AST comparison confirms all 74 top-level statements in the three extracted blocks, the moved helper bodies, and all remaining service statements are unchanged after normalizing the explicit boundary parameters. All 140 public exports are preserved. - Passed 304 existing tests across seven adjacent lifecycle, accounting, session, Stop, and presentation suites. After rebase, all 19 new boundary tests and all 12 publication tests pass together. Total focused coverage: 335 passing tests. - Full local `pnpm test:run` was stopped after more than 28 minutes without completing. Additional route-suite diagnosis hit local database startup timeouts. The complete CI run passed on the final head, including all test shards, build, typecheck, browser tests, and canary install checks. - Rebased onto the workspace-repair fix in #15726. Preserve its `defaultBranch` metadata in the moved helper and add a regression test. All 31 completion and publication tests and the server typecheck pass on the rebased head. - Greptile reviewed current head `65e3f8d8ac165dfec4508c467b1b2af8f2510f1a`: 5/5 with no actionable findings. - Final-head [CI run](https://github.com/paperclipai/paperclip/actions/runs/37991844034) passed. All 53 completed check runs succeeded; two optional Storybook checks were skipped. The legacy security status also passed. No unresolved review comments or merge conflicts remain. ## Risks Terminal handling is sensitive to Stop races, late native results, and failures during persistence. The tests exercise these paths with real database status writes, accounting, and task sessions. Native recovery exceptions and resource release stay at their existing boundaries. There are no schema or API changes. ## Model Used OpenAI Codex, based on GPT-6, with reasoning, code editing, and command execution. The session does not expose the exact model variant 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> |
||
|
|
9befc66a44 |
Retain bounded Daytona acquisition failure observations (#15736)
## Thinking Path > - Paperclip manages AI-agent work and reports failed runs. > - Some runs acquire a Daytona sandbox before model execution. > - Acquisition has one budget for creation, setup, and inline cleanup. > - A timeout currently carries cleanup ownership but loses the step that failed. > - This pull request carries a bounded observation through the existing error envelope. > - Operators can identify the first failed step without exposing provider responses or changing recovery. ## Linked Issues or Issue Description **What happened?** An acquisition timeout reports pending allocation cleanup without the first failed step. The provider already knows its current step, but that evidence is discarded at the worker boundary. A setup failure followed by slow cleanup is also indistinguishable from slow creation. **Expected behavior** The immediate setup-failure report should contain a fixed phase and bounded elapsed/budget values. Cleanup ownership, original messages, deadlines, retry policy, and task behavior should remain unchanged. **Steps to reproduce** Use the provider regression fixtures to stall creation, workspace setup, shell detection, expiry configuration, or sentinel upload. Also fail setup early and let cleanup consume the remaining budget. The previous source emits no phase diagnostic. **Paperclip version or commit** Base commit: `98e3cec78e8461774022a5ba0a777b09d4d16b96`. **Deployment mode** Hosted and self-hosted installations that use the Daytona sandbox provider and enable Sentry. Related public changes: #13979 established failed-allocation cleanup ownership; #14097 preserves the provider acquisition budget; #15637 carries bounded workspace-transfer evidence. Duplicate searches found no existing acquisition-phase diagnostic patch. ## What Changed - Capture the first acquisition failure before inline cleanup. Keep the observation if cleanup later reaches the deadline. - Add an optional, validated observation to the existing creation-cleanup envelope for acquire calls. Old ownership envelopes remain valid. Malformed observations do not alter cleanup. - Bind immediate reporting to an actual RPC error with matching company, environment, and run ownership. Project only three bounded fields from private host evidence. - Add provider, SDK, actual worker/client, PostgreSQL cleanup, collector, and real-Sentry regressions. Document the evidence limits. ## Verification - Passed 404 focused tests across the SDK cleanup envelope, complete Daytona provider suite, diagnostic collector, actual built worker/client subprocess, and mandatory real-Sentry SDK suite. - Passed 10 focused PostgreSQL cleanup-boundary cases. The filter excluded 152 unrelated cases. - Passed `pnpm -r typecheck` and `pnpm build` on the committed source. - Full `pnpm test:run` is running. Final outcomes will be recorded before merge. - Independent source review passed. Replacing the provider with the original source fails all 8 new phase/timing assertions. Replacing the host boundary with the original source fails all 3 owned diagnostic cases while 7 negative cases remain clean. - CI passed: 54 successful checks and 2 expected Storybook skips. This includes all server, workspace, serialized-server, Runner, browser, build, canary, and real-Sentry SDK lanes. - Greptile scored the committed source 5/5 with no review threads. - No live provider operation, task replay, runtime configuration change, or deployment was performed. ## Risks Low risk: this only adds optional diagnostic evidence. The first observed failing phase does not prove an upstream cause. Elapsed time ends at that observation, not at completion of later cleanup. Evidence is process-local and accompanies immediate failure reporting; post-restart reports cannot reconstruct it. No historical run or lease is backfilled. The wire schema remains v1 and cleanup ownership parsing is unchanged. ## Model Used OpenAI Codex, GPT-6, with repository inspection, code editing, local execution, and independent agent review. The exact model snapshot and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip <noreply@paperclip.ing>canary/v2026.1009.0-canary.15 |
||
|
|
c5f7713dd4 |
fix: clarify native tool use for external agents (#15734)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - External agents keep their own tools and app connections. > - The Paperclip assignment catalog controls the Paperclip bridge. > - Dot treated a qualification test restriction as a rule for later work. > - Existing prompts did not clearly separate these two tool sources. > - This pull request tells agents to use their own capabilities and return results to Paperclip. > - The benefit is that a missing Paperclip app does not block an available native capability. ## Linked Issues or Issue Description Related work: #15722 and #15691. I searched open PRs for Dot tool guidance and found no duplicate. **What happened?** After a qualification test, Dot refused a Slack request because the test Paperclip agent had no assigned Slack app. Dot already had a working Slack connection in ChatGPT. It carried the test's plugin restriction into a later task message. **Expected behavior** An external agent uses its own available tools, apps, plugins, skills, and capabilities to complete the current request. It then returns the result through Paperclip's task reporting and completion tools. The assignment catalog limits Paperclip calls. It does not disable the agent's native tools. **Steps to reproduce** 1. Connect a Dot that has a native Slack connection. 2. Complete a Paperclip qualification task with a restriction scoped to that test. 3. Send a later task message that requires Slack. 4. Observe that Dot can mistake the Paperclip catalog for its full tool inventory. **Deployment mode** Observed on Cloud staging with the Dot Runner. ## What Changed - Add shared tool-use guidance for external-agent onboarding and Dot setup. - Include it in the server onboarding document, pairing response, event instructions, and capability response. - Clarify the tool descriptions on both Dot bridge paths. - Include the same guidance in each Dot Runner assignment without adding a shared-package dependency to the standalone Runner. - Document native tool use and the scope of test restrictions. ## Verification - The 49 relevant onboarding, Dot invitation, and Runner context tests passed. The final UI run passed 29 tests. The updated plain-text renderer run passed all 4 tests. - Full workspace typecheck, full workspace build, and design token gates passed. All current-head CI gates passed, including full tests, Runner verification, and browser E2E. Greptile is 5/5 on the exact final commit, and the one review finding is resolved. - The real Dot received the standing correction and confirmed that it will use its relevant tools and connections, return results through Paperclip, and stop carrying the test restriction forward. - Extended the existing plain-text renderer test to check native Slack access, qualification-test scope, and the Paperclip denial boundary. This covers agents that receive only the onboarding.txt URL. - The full Vitest suite passed in CI. The earlier local Cloud qualification run encountered failures in unchanged suites; this follow-up uses focused local tests for the instruction changes. ## Risks This changes instructions, not access checks. Native tools retain their own permissions and approval requirements. Paperclip operations remain scoped to the authorized company, agent, and task. Agents must not use another connection or identity to bypass a denial. There is no database migration or new permission grant. ## Model Used OpenAI GPT-6 through Codex. Used reasoning, repository tools, and browser control. The runtime does not expose a more specific model ID or context window size. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
b6b3cb3761 |
Fix unavailable workspace branches with an inline repair and retry (#15726)
## Thinking Path > - Paperclip manages AI agents and their work. > - Isolated workspaces must resolve a starting Git ref before an agent starts. > - A task can explicitly select a branch that the repository does not have. > - The current recovery notice calls this a missing secret and offers no branch repair. > - This pull request explains the branch failure and adds a task-scoped repair action. > - Operators can correct the branch and request a guarded retry from the task thread. ## Linked Issues or Issue Description Related: Refs #11892 added unresolved-ref recovery. Refs #15719 added bounded failure diagnostics. This change uses that recovery path and adds its operator repair UI. **What happened?** A task that selects `main` in a repository with only `master` stops before the adapter starts. The task shows a missing-secret message and a generic retry. Repeating the run cannot fix the stored branch setting. **Expected behavior** Explain that the starting ref could not be resolved. Offer a verified repository default, or let the operator enter a branch. Save only the task's starting branch and retry its recorded owner through the existing admission gates. **Steps to reproduce** 1. Create an isolated-workspace task in a repository with `master` and no `main`. 2. Set the task's base ref to `main` and assign an agent. 3. Wait for the configuration failure. 4. Use the inline branch repair and confirm the agent completes in a worktree based on `master`. ## What Changed - Replace the missing-secret diagnosis for unresolved workspace refs. Keep uncertain fetch/access failures described as uncertain. - Read the remote's advertised default branch with the existing Git credentials and a bounded timeout. Do not guess or silently change the branch. - Add an atomic branch repair to the existing recovery resolution endpoint. Check company access, board runtime permission, incident identity, current owner, task/project state, dependencies, interactions, approvals, budget, and active execution before requesting a retry. - Preserve the effective inherited workspace setup when saving the task branch override, and attach one repair notice per failed run even when the incident is reused. - Bind the shared repair card to the exact recovery notice and failed run in both task-thread renderers. Validate branch syntax and prevent duplicate submissions. - Add Storybook examples, regression tests, and a documented local acceptance fixture with a real Git repository and process adapter. ## Verification - Red/green regressions cover the repair endpoint and preservation of inherited agent setup. The regression failed before each fix and passed afterward. - Focused integration suite: 162 tests passed; task-thread/card suite: 230 passed. After review refinements, all 13 repair-route tests, 10 card tests, 77 recovery-action tests, and the repeated-failure heartbeat regression passed locally. - Real browser acceptance passed for suggested-branch and custom-entry repairs. Invalid syntax left the task blocked. Both valid repairs ran the authenticated worker in a real isolated worktree and reached Done; reload preserved the result. - Repeated failures reused the recovery incident and retained an actionable notice on the latest run. The inherited-setup journey verified the provisioned file, agent branch template, worktree parent directory, and actual Git commit before completing. [Before/after screenshots](https://github.com/paperclipai/paperclip/pull/15726#issuecomment-6088734666). - Full local typecheck and build passed; server typecheck passed again after review fixes. Token gates passed. - The monolithic local Vitest run was stopped after resource-contention timeouts and stale assertions. Targeted regressions were rerun; the full CI matrix passed on final revision `26c543ff490bec29ddc77a49ee532c7f84fb96dc`. One signoff E2E worker-cancellation failure passed on a rerun without code changes. The two opt-in Storybook workflow jobs were skipped; the Storybook journey was checked manually. - Repeat the live journey with `tests/e2e/workspace-base-ref/README.md`. Storybook examples use simulated callbacks and are not the live acceptance proof. ## Risks - Default-branch discovery can add up to 10 seconds to an unresolved-ref failure. Lookup failure leaves manual entry available. - A valid branch name can still be absent or inaccessible. The retried workspace preparation remains authoritative and can block again with new evidence. - Retry remains subject to normal admission gates. The repair changes only the task override; it does not alter project or agent defaults. - No database migration or new dependency. ## Model Used OpenAI GPT-6 through Codex, with tool execution, repository analysis, and browser testing. The exact serving variant and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
98e3cec78e |
feat(costs): report monthly subscriptions beside API spend (#15634)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Its Costs page reports API charges and subscription token usage. > - Subscription runs do not show the recurring fee paid for the account. > - Several agents can share one paid seat, so a fee per agent would overstate cost. > - This pull request identifies connected subscription accounts and reports each monthly fee once. > - Users can compare API spend and subscription costs, see uncertainty, and enter their actual price. ## Linked Issues or Issue Description Refs #498 and #3406 for related subscription reporting needs. This change does not add subscription budget enforcement or automatic optimization. Related prior approaches: #10544 and #11104 proposed API-equivalent token costs for subscription work. This PR reports recurring account fees separately from usage charges and budgets. A search found no open PR for monthly account fee reporting. **Subsystem affected** Costs, managed AI connections, shared contracts, database schema, and board UI. **Problem or motivation** An organization can pay for subscriptions even when included runs record no additional dollar charge. The Costs page cannot show that monthly commitment or distinguish a shared paid seat from several separate seats. **Proposed solution** Discover account identity from the managed connection selected for a run. Use exact known plans for labeled monthly list-price estimates. Keep ambiguous plans and unconfirmed identities unpriced until the user supplies a price. Sum current monthly fees separately from date-filtered API charges and token usage. **Alternatives considered** A fee per agent double-counts shared accounts. Token-based API price estimates do not measure the recurring subscription fee. Provider invoices would be more exact but are not available through these account credentials. **Roadmap alignment** Extends the shipped Better Budgeting and Personal & Shared AI Accounts capabilities. The feature and UI were reviewed with the maintainer before this PR. ## What Changed - Add company-scoped subscription accounts, connection bindings, and immutable price revisions in replay-safe migration 0322. - Identify OpenAI workspace/seat and Claude organization/account pairs only after provider authentication. Keep provisional records grant-scoped; unchecked ID-token claims cannot combine accounts or grant billing editors. Keep credentials and raw provider identities out of reports. - Attach the selected subscription to new run receipts. Resolve duplicate aliases without rewriting old monetary receipts. - Add cached background discovery with four provider checks and twenty discovery requests at a time. Accepted requests wait for capacity; excess requests receive HTTP 429 and a UI retry action. Preserve saved prices and observations when a provider check fails. Dashboard polls load current prices only; audit revisions stay in the database. - Support owner-controlled monthly or annual prices, fractional-cent precision, separate currency totals, tracking status, and duplicate linking. Preserve both personal owners and shared-account managers when discovery finds the same paid seat. - Show API spend beside monthly subscription commitment, with separate token totals and clear estimate labels. Account details and fee totals follow billing-owner/shared-audience visibility; company-wide token totals remain available to cost readers. - Use consistent amount and estimate badge formatting for agent, user, project, and model rows. - Add real PostgreSQL tests, route authorization tests, UI tests, interactive Storybook fixtures, and operator documentation. ## Verification - Current head `d7b5c78dadf5033a3c447d83434676ac94687e77` passed all 53 checks, with two checks skipped. This includes the full test matrix, browser tests, build, typecheck, migration policy, canary packaging, and security checks. - Greptile Apex reviewed that exact head at 5/5 with no unresolved findings. - Local `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, migration safety checks, and `git diff --check` passed. - All 238 focused tests passed across accounting, subscription persistence, authorization, UI, migration replay, and snapshot drift. - The expanded local chat suite passed 1,149 tests. Two cases failed because this workspace found an unrelated ancestor skill directory; both passed unchanged in an isolated checkout. The full local Vitest command was not repeated after the rebase because of this environment issue. CI covered the complete test matrix on the final head. - Migration `0322_reflective_kree.sql` follows master's `0321_acoustic_human_fly.sql`. Its snapshot and journal were regenerated. Master's migration and snapshot are unchanged. The subscription SQL retains its original content and hash. - Disposable PostgreSQL upgrade fixtures applied master's added lifecycle and Slack migrations without changing saved subscription prices or cost receipts. The renamed subscription migration was recognized by hash, retained one history row, and a second migration run was a no-op. - Regression tests cover provider capacity, fractional-cent edits, billing visibility after grant revocation, and fixed-price/credit/unknown usage. The new UI billing-label tests fail against the old wording and pass with the fix. - Browser checks passed for desktop and mobile layouts, shared-account totals, annual price edits, unknown prices, and stale provider data. - A live OpenAI account probe returned HTTP 200 and a verified Pro account identity. The generic Pro plan correctly remains unpriced. - Live Claude discovery identified Max 20x and a $200/month estimate. Two real Claude agent runs were attributed to that same account, with two usage receipts, two agents, one monthly fee, and zero additional usage charges. Two OpenAI connections also deduplicated to one account. - Live Codex execution is not verified: both Paperclip's managed hello test and a direct host `codex exec` fail with a workspace-routing authentication error. The current credential passes the usage API probe. This is separate from the successful account-discovery check. - A local performance fixture with 50,000 usage events and 5,001 saved price revisions produced a 1,589-byte report in 11.5 ms median / 12.2 ms maximum over ten warmed runs. PostgreSQL used the subscription/revision index to read one current price row. These are local measurements, not a production latency guarantee. - [Desktop, account details, and mobile screenshots](https://pages.paperclip.ing/pr-15634-subscription-costs-d5d285e2/) show the production Costs page with synthetic Storybook fixtures. - To inspect the UI, run `pnpm storybook` and open **Costs / Subscriptions**. Edits there change fixture data only. ## Risks - Provider plan identifiers can change. Unknown plans remain unpriced. Automatic prices are estimates before tax; discounts and negotiated prices require a user-supplied amount. - Subscription fees describe the current monthly commitment. They do not follow the selected usage date range and do not consume agent budgets or create finance events. - Monthly fees cover only accounts visible to the viewer; company-wide token totals retain their existing scope. - Legacy or unmanaged usage can remain unattributed. Unconfirmed identities require manual prices and may need explicit duplicate linking after credential changes. - Disconnecting a connection does not prove provider billing stopped. Users must end or exclude tracking explicitly. - Migration 0322 adds tables, a nullable cost-event column, and an index. It is replay-safe, but normal migration locks still apply. ## Model Used OpenAI Codex, based on GPT-6. This session did not expose a more specific backend model ID or context-window size. Capabilities used: code editing, shell execution, database tests, and browser verification. ## 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.1009.0-canary.14 |