mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-06 10:48:12 +02:00
92d4868e79b0451aeb0746681a7d93d1cc199dda
100
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
92d4868e79 |
fix(server): isolate run errors and redact runtime capability headers (#13826)
## Thinking Path
> - Paperclip manages AI agents and their work.
> - Operators use Sentry to investigate failed runs and server errors.
> - Run reports attach a task ID, run ID, error code, and adapter
fingerprint.
> - The server skips Sentry's OpenTelemetry setup to preserve its
separate tracing and privacy settings.
> - Without an async context manager, a scope mutation can attach old
run data to later errors.
> - The HTTP logger also retains a runtime credential capability header.
> - This change isolates run metadata and redacts that header so
diagnostics identify failures without leaking credentials.
## Linked Issues or Issue Description
Refs #13446 and #13719.
**What happened?**
After a terminal run failure, an unrelated server exception can inherit
that run's tags, context, and fingerprint. Sentry then groups a database
error with an earlier adapter failure. The real SDK reproduces this with
the application's `skipOpenTelemetrySetup: true` setting. HTTP request
logs also retain the `x-paperclip-github-capability` header, which must
be treated as a credential.
**Expected behavior**
Run metadata belongs to the terminal run event. Later exceptions must
not inherit it. Every genuine error must still be captured. Runtime
capability headers must be redacted on success and failure logs.
**Steps to reproduce**
1. Initialize the optional Sentry SDK with the application's options and
an in-memory transport.
2. Capture a terminal run failure.
3. Capture an unrelated exception.
4. Inspect the second event. Before this fix, it contains the first
run's identity and fingerprint.
5. Send a request with a fixture runtime GitHub capability header.
Before this fix, HTTP logs retain the fixture value.
## What Changed
- Pass tags, context, and fingerprint directly to `captureException`
instead of mutating the ambient scope.
- Preserve the existing run fields, grouping keys, ordinary exception
capture, and privacy settings.
- Test two run identities interleaved with unrelated exceptions against
the real optional SDK.
- Update the capture contract tests and document event-local run
metadata.
- Redact the runtime GitHub capability header through the existing HTTP
logger policy. Test successful, denied, and failed requests.
- Add a dedicated GitHub-hosted CI check that installs the exact
optional SDK version declared in `server/package.json`. It fails if the
real-SDK regression would be skipped. The SDK stays outside the
workspace and production dependency graph.
## Verification
- The real-SDK regression failed before the fix because the unrelated
event contained `contexts.run_failure`.
- Five focused suites passed: 123 tests, including all optional SDK
tests. Suites: `run-failure-sentry-real-sdk.test.ts`,
`run-failure-sentry.test.ts`, `sentry.test.ts`,
`run-failure-report.test.ts`, and `http-log-redaction.test.ts`. A custom
in-memory transport prevented outbound Sentry delivery.
- All three new header-redaction cases failed before the policy fix and
passed afterward.
- The dedicated CI command passed locally with
`PAPERCLIP_REQUIRE_SENTRY_TEST_SDK=1` and the audited SDK available
through `NODE_PATH`.
- Server TypeScript check passed with a scratch configuration that
resolves this checkout's workspace packages. The existing dependency
links point to another checkout.
- `node scripts/check-module-boundaries.mjs` and `git diff --check`
passed.
- Gitleaks and a separate private-data scan passed before push.
- Full local workspace typecheck, test, and build were not run. The
machine has less than 2 GiB free and those commands include Rust builds.
Full PR CI must pass before merge.
- The dedicated real-SDK GitHub check passed with 1 test executed and no
skips: https://github.com/paperclipai/paperclip/actions/runs/35774449002
- Greptile reviewed
|
||
|
|
5f1100e3b3 |
refactor(server): remove retired operator UI snippet injection (#13789)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators can extend its interface through trusted plugin UI contributions. > - The server also accepts executable HTML through two legacy environment settings. > - This older path bypasses the plugin installation and lifecycle model. > - This pull request removes snippet injection from static and development pages. > - Operators must migrate existing integrations before upgrading. ## Linked Issues or Issue Description **What existing behavior does this improve?** Retire the operator HTML injection path from the server. Related public changes: #13168, #13245 and #13496 introduced the legacy settings; #13646 supplies the generic plugin host contract. **Current behavior** Managed instances append operator-supplied HTML or a decoded script body to every page. The same integration can use supported trusted plugin UI slots. **Proposed behavior** Ignore both retired settings. Serve normal branded static and development HTML, and keep plugin contributions unchanged. **Breaking changes** Installations that rely on `PAPERCLIP_CLOUD_UI_SNIPPET` or `PAPERCLIP_CLOUD_UI_SNIPPET_B64` must migrate before upgrading. The maintainer-owned staging and production deployments have completed the migration prerequisite. Other operators must migrate their integrations before adopting this change. ## What Changed - Remove the snippet injector and its static/dev rendering integration. - Remove injector-specific tests and retain a regression that old settings no longer change served HTML. - Replace setup instructions with a retirement and plugin-migration note. ## Verification - Rebased onto current master; `pnpm exec vitest run server/src/__tests__/static-index-html.test.ts server/src/__tests__/vite-html-renderer.test.ts`: 5 tests passed. - With repository-pinned Rust/Cargo installed, full `pnpm -r typecheck` and `pnpm build` pass after rebase. - Previous full local `pnpm test:run` encountered unrelated macOS runtime-cache rename `EACCES` errors and a missing AgentMail skill path; a focused reproduction confirmed 5 failures / 95 passes. That is not a passing full-suite result. The unchanged focused suites, build and typecheck were repeated after rebase; the full local suite was not repeated. All 54 refreshed GitHub checks/contexts passed on `bd62bff63f9d7980bfd10e54cb0102693d27ecfb`; fresh Greptile is 5/5 with no unresolved threads. - No UI component styling, database or API contract changed. - Maintainer approved the remaining rollout and cleanup. Staging snippet retirement and sleep/wake verification are complete. Production migration and removal of the legacy settings are complete for serving tenant instances. Remaining old warm inventory is excluded from new signups until configuration reconciliation completes. The maintainer authorized upgrading the remaining old deployments and clearing their pins. ## Risks - Removing the settings disables integrations that still depend on them; operators outside the completed maintainer rollout must migrate before upgrading. This is an intentional behavior change, documented at the existing setup-doc path. - Keep a previous image and its configuration for rollback. Existing browser tabs need a refresh to unload already-injected code. - Plugin UI remains trusted same-origin code. This does not add a security sandbox or change ordinary branding. ## Model Used - OpenAI GPT-6 (Codex; exact deployment variant and context-window size are not exposed in this session). Reasoning, repository inspection, local code 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 - [x] I have run tests locally and they pass (focused rendering tests; unrelated local full-suite failures are disclosed 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 refreshed checks pass on `bd62bff63f9d7980bfd10e54cb0102693d27ecfb` - [x] Fresh Greptile is 5/5 on the current head, with no unresolved findings - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
110d176fc9 |
fix: preserve chat message bindings in review recovery (#13818)
## Thinking Path > - Paperclip manages AI agents and their work. > - External chat messages can start work on tasks that remain in review. > - Paperclip queues one recovery run when a task loses its review path. > - That recovery keeps the chat source but loses the admitted message IDs. > - The authorization check then rejects the recovery before execution starts. > - This change retains the message IDs so the existing check can verify current access. ## Linked Issues or Issue Description Refs #13809. **What happened?** A successful external-chat run can leave an active task in review without a maintained review path. Its automatic recovery then fails with `reviewed_chat_execution_binding_not_authorized`. The recovery context retains `chat:slack` but drops `wakeCommentIds`. **Expected behavior** An eligible recovery should retain its admitted message references and pass a new authorization check. Missing or revoked access must still prevent execution. **Steps to reproduce** 1. Finish a chat run whose task remains in review with no maintained review path. 2. Build the bounded review recovery from that run's context. 3. Dispatch the recovery through the reviewed-chat authorization check. The new regression tests fail before this patch. Related PR #13809 handles answered conversations that become idle. This patch handles recovery when the conversation remains active. ## What Changed - Retain the admitted message batch for external-chat review recovery. Derive the current comment reference from that batch. - Share the existing supported-provider selector between recovery and run-bound chat authorization. AgentMail remains on its separate email inbox path. - Keep the existing authorization check. Do not copy prior checkout, authorization, session, or prompt state. - Test Slack and Discord recovery, missing batches, revoked access, and changed task or company bindings. - Document the recovery authorization contract. ## Verification - The new tests reproduced the missing-message failure before the fix. - Six focused suites passed: 257 tests covering review recovery, reviewed-chat authorization, issue liveness, Slack lifecycle, comment-wake batching, and external-chat waits. PostgreSQL integration tests ran against a temporary local PostgreSQL database. - Focused test files: `review-path-recovery.test.ts`, `heartbeat-reviewed-chat-binding.integration.test.ts`, `heartbeat-issue-liveness-escalation.test.ts`, `slack-conversation-lifecycle.test.ts`, `heartbeat-comment-wake-batching.test.ts`, and `external-chat-wait.integration.test.ts`. - Server TypeScript check passed with scratch configuration that resolves this checkout's workspace packages. Existing dependency links point to another checkout; the default check reports stale shared-type errors. - `node scripts/check-module-boundaries.mjs` and `git diff --check` passed. - `git diff | gitleaks stdin --redact --no-banner` passed. The diff was also checked for private identifiers and user data. - [Full PR CI](https://github.com/paperclipai/paperclip/actions/runs/35760757895) passed on the latest commit, including build, workspace typecheck, general and serialized tests, Rust checks, and all eight browser shards. The unchanged local-service readiness test and agent-chat page-load assertion passed when their failed shards were retried. The local-service suite also passed locally (6 tests). The first, superseded run lost a chat runner; its stuck browser job was cancelled to unblock the current run. - Full local workspace typecheck, tests, and build were not run. The machine has about 2 GiB free, and those commands include Rust builds. The full PR CI checks passed before merge. ## Risks Small context-construction change. Dispatch still checks current execution ownership and access for every admitted message. The recovery remains bounded to one attempt per consumed path. No schema changes. Existing failed runs are not retried by this patch. ## Model Used OpenAI GPT-6 (Codex), with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
83abfa46f6 |
feat(ui): enable Grok in Cloud agent setup (#13791)
## Thinking Path > - Paperclip manages AI agents and their execution settings. > - The new-agent flow selects an adapter before configuring credentials and a model. > - Cloud uses one adapter policy for the picker and direct setup links. > - That policy excludes Grok despite its existing adapter and xAI connection support. > - This change adds Grok to the Cloud policy. > - Cloud users can configure Grok with the existing subscription or API-key flow. ## Linked Issues or Issue Description **What existing behavior does this improve?** Agent creation on Cloud. **Current behavior** The Cloud picker offers Claude, Codex, and OpenCode. Direct Grok setup links also fail the shared adapter check. **Proposed behavior** Offer Grok alongside the existing choices. Use the existing xAI connection and managed sandbox setup. **Reason and benefit** Users can select an already-supported adapter through the Cloud creation flow. **Breaking changes** None. Loaded and enabled checks still apply. Other excluded adapters remain excluded. ## What Changed - Add `grok_local` to the shared Cloud creation policy. - Display four adapter choices in a 2×2 grid on desktop and mobile, and reuse the theme-aware provider mark on the connection step so Grok is visible in dark mode. - Verify picker navigation and both Grok authentication methods through sandbox setup, model testing, and agent creation. - Verify that probe and hire payloads carry the xAI connection binding without the entered API key. - Update the agent configuration specification. ## Verification - `cd ui && pnpm exec vitest run src/components/NewAgentDialog.test.tsx src/pages/NewAgent.test.tsx src/components/new-agent/AgentProviderConnection.test.tsx` — 69 tests passed. - Chromium checks against the production components and built stylesheet — four cards occupy two rows and two columns at 1280px and 390px; the connection step loads and displays the white Grok logo in dark mode and the black logo in light mode. - `pnpm --filter @paperclipai/ui typecheck` — passed. - `pnpm --filter @paperclipai/ui build` — passed. - `pnpm check:token-gates` — passed. - `git diff origin/master...HEAD | gitleaks stdin --redact --no-banner` — no leaks found; manual diff review found no private identifiers or user data. - `pnpm -r typecheck` and `pnpm build` — blocked at the existing runner package because `cargo` is not installed locally. - `pnpm test:run` — started locally, then stopped after the equivalent CI suites passed. - Initial [PR CI](https://github.com/paperclipai/paperclip/actions/runs/35681351752) passed, including full typecheck/build, general and serialized tests, Rust checks, and all eight browser-test shards. One unchanged Cursor test timed out on the first attempt; its five-test file passed locally and the failed CI shard passed on retry. - The [latest CI run](https://github.com/paperclipai/paperclip/actions/runs/35683642812) passed build, typecheck, all general and serialized tests, Rust checks, and all eight browser-test shards. One unchanged local-service-supervisor test failed its HTTP readiness check on the first attempt; its six-test file passed locally, and the failed server shard passed on retry. - Live xAI login and model execution were not run; the setup tests mock provider calls. ## Risks Small UI policy change. The existing Grok adapter, authentication, and secret storage paths remain in use. No schema or control-plane change is required. Cloud must deploy a tenant-app release containing this change. Revert the policy entry to hide Grok from new-agent setup again. ## Model Used - OpenAI GPT-6 (Codex), with repository inspection, code editing, and shell-based 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> |
||
|
|
e3d8fb0876 |
feat: attest standard production images at full source commits (#13797)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators deploy its standard production container on several CPU architectures. > - Downstream image builders need to identify the exact source of their base image. > - A short commit tag does not provide signed source evidence. > - This pull request adds a full commit tag and signed image digest for canonical master pushes. > - Consumers can verify the source and compose from the immutable digest. ## Linked Issues or Issue Description **What existing behavior does this improve?** Publication of the standard multi-platform production image. **Current behavior** The Docker workflow publishes short commit tags and channel tags. It does not provide a signed standard-image contract tied to the complete master commit. **Proposed behavior** Canonical master pushes also publish `sha-<full-commit>` and attest the exact index digest after platform validation and an immutable-image orphan-reaping check. The signer certificate binds the source repository, commit, workflow and ref. Existing tags and the separate cloud producer remain available. **Reason and benefit** Downstream builders can prove the source of a standard base without adding their dependencies or repository details to the public workflow. No matching open issue or duplicate PR was found. ## What Changed - Add the canonical full-SHA tag without changing existing tag mappings. - Validate amd64 and arm64 descriptors and hash the exact registry response bytes and require its digest header to match. - Verify the immutable image and sign it with GitHub artifact attestations. - Run the contract tests in trusted PR verification and document the consumer contract. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/cloud-source-verification.test.mjs scripts/standard-image-contract.test.mjs`: 37 passed. - A read-only check against an existing published index returned its exact expected digest. - `actionlint -shellcheck='' .github/workflows/docker.yml .github/workflows/pr-trusted.yml`: passed. Normal ShellCheck reports only existing `ls` and word-splitting warnings. - `pnpm build`: passed locally with Cargo available. - `pnpm -r typecheck`: passed locally. - Full local Vitest was attempted: 8,260 passed, 14 failed, with 34 failing suites. The failures were missing embedded-PostgreSQL library aliases in this fresh install and existing macOS runtime-skill-cache rename errors. Native aliases are now restored. Rerunning the 33 affected database suites produced 577 passes and two unrelated AgentMail skill-root lookup failures (32 suites passed). The four directly failing database tests also pass independently. This is not a claim that the full local suite passed. - All final-head CI checks pass. One unrelated routine-route mock assertion passed on the single-shard retry; its 15 tests also pass locally. Greptile is 5/5 on this exact head, with no unresolved threads. - Actual signing requires a canonical master push. This draft PR does not publish trusted provenance. ## Risks The new attestation step requires OIDC and attestation write permissions in the merge job. Signing failure leaves the image available but without the new admission proof. Consumers must fail closed when proof is missing. Existing release tags, the legacy producer, and image retention remain unchanged. No database or application behavior changes. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository inspection, shell execution and test tools. The session does not expose a more specific 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> |
||
|
|
8326e33ada |
Fix oversized sandbox process launch payloads (#13793)
## Thinking Path > - Paperclip manages agent work and preserves context across retries. > - Sandbox ACP runs encode their command and environment into one launch value. > - A long continuation can make that encoded value exceed Linux's exec limit. > - The launch shell then exits before the agent can initialize. > - This PR transfers large command envelopes through a private temporary file. > - The agent receives the complete environment and can start normally. ## Linked Issues or Issue Description Refs #13777. **Bug description** Sandbox tasks with long retry context fail during ACP initialization with exit 127. The streamed bridge also drops the shell error that explains the failure. **Steps to reproduce** Launch the streamed sandbox process bridge on Linux with one valid 110,000-byte environment value. Its base64 command envelope exceeds the limit on one exec argument or environment string. Daytona reports `argument list too long: env`, then exit 127. **Expected behavior** The command envelope must not make a valid child environment too large to launch. A shell startup failure must retain its diagnostic in the run log. ## What Changed - Keep envelopes up to 64 KiB on the existing launch path. Upload larger envelopes in bounded chunks inside a mode-0700 session directory. Set the final payload file to mode 0600. - Read the file without following symlinks and delete it before spawning the child. Remove incomplete uploads on failure. Both streamed and polled bridges use the same envelope. - Preserve stderr when the launch shell fails before the wrapper emits a terminal event. Emit a fixed terminal error and shutdown acknowledgement if a payload cannot be read or parsed, without exposing its contents. - Cover large environments, file permissions, payload deletion, interrupted uploads, missing or malformed payloads, and startup diagnostics. Document the transfer and cleanup behavior. ## Verification - Both large-envelope regressions fail before the fix and pass after it. - Targeted bridge, ACP engine, real-spawn, and stdin-race checks pass: 370 tests. - `pnpm --filter @paperclipai/adapter-utils typecheck` passes. - A gated live Daytona probe on the current sandbox image reproduced exit 127 with the old bridge. The fixed bridge launched the same command successfully. A second probe completed real Claude ACP initialization with a 110,000-byte context value. It did not run an agent task. All temporary sandboxes were deleted. - `pnpm -r typecheck` and `pnpm build` reach the unchanged Rust runner step and stop because this machine has no `cargo` executable. - Full CI passes on `ea816cf58d`: [run 35683853754](https://github.com/paperclipai/paperclip/actions/runs/35683853754). All 53 checks pass; two optional checks are skipped. The local full-suite run was stopped after equivalent CI suites passed; it has no final local result. - Greptile is 5/5 on `ea816cf58d`, with no unresolved review threads. The branch is mergeable. ## Risks Large envelopes require extra upload calls during startup. The temporary data stays inside the private session directory and is removed before child startup or during failure cleanup. Individual child environment values still obey the operating system's native limits. No migration or configuration change is required. ## Model Used OpenAI GPT-6 (Codex), with reasoning, repository tools, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (targeted checks; full-workspace limits described 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> |
||
|
|
c496acb570 |
Return client errors for known OAuth reconnect states (#13794)
Map missing OAuth refresh credentials and terminal reauthorization to HTTP 422. Preserve reconnect instructions and reporting of unexpected provider failures. All 363 focused tests and server typecheck pass. Required CI and review checks passed; Greptile 5/5 with no unresolved comments. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
1f3ff75d33 |
Recognize confirmed container loss when resuming Daytona leases
Daytona can retain a sandbox API record after its container disappears. Confirm the exact missing-container response with a bounded fresh read, then let the host apply its existing replacement and backup policy. Preserve unknown failures, recoverable errors, and identity mismatches. Verified 251 provider tests, 93 host lifecycle tests, plugin typecheck and build. Added 15 regressions. Read-only inspection confirmed the provider response and an existing verified backup without changing live state. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
a7d3b17a97 |
Explain disabled Slack MCP app access during discovery
Recognize Slack's exact disabled-app response and return actionable setup instructions from catalog and health routes. Bound response parsing and keep unknown upstream errors reportable without exposing provider settings links. Verified 361 focused tests, server typecheck, and authenticated discovery. The three route regressions fail before this change and pass afterward. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3c2bc4f546 |
ci: halve the isolated native Runner check by seeding it from the public master build cache (#13736)
## What Recurring CI health check (PAP-31): on the most recent fully-green PR run (`cb703ac`, run [35519542997](https://github.com/paperclipai/paperclip/actions/runs/35519542997)), the slowest check was **Compile isolated native Runner** at **452s** — ahead of the largest test shards (379s). Every run recompiled the full Rust dependency tree from zero, even though `docker.yml` already refreshes a **public** `mode=max` BuildKit cache (`ghcr.io/paperclipai/paperclip:buildcache-{amd64,arm64}`) on every master push, containing exactly these layers. This PR seeds **only the baseline build** with that registry cache, via anonymous pull. **Measured on this PR's own CI (which exercises the seeded path): the check completed in 123s, down from 452s — a 73% reduction, ~5.5 minutes saved per run.** ## Thinking Path Cost breakdown of the 452s from the job log: `cargo chef cook` dependency compile 214.7s, local cache export 43.1s, runner-core build 37.0s, metadata proof layer 36.8s, `cargo install cargo-chef` 36.4s, rebuild-verification build ~65s, setup/teardown ~20s. The dependency compile and toolchain layers are identical to what the production `docker.yml` build already caches publicly on every master push, so recompiling them here bought no signal — the check's real assertions live in the *verification* build, not the baseline. A first attempt used `actions/cache` plus a master `push` trigger, but the CI bot's GitHub App lacks `workflows` permission; the registry-cache approach is strictly better anyway (shared across PRs immediately, no 10GB Actions-cache quota pressure, no workflow change). ## What Changed - `scripts/check-docker-runner-cache.sh`: the baseline build now adds `--cache-from type=registry,ref=ghcr.io/paperclipai/paperclip:buildcache-{amd64|arm64}` (selected by host arch). `RUNNER_CHECK_SEED_CACHE` overrides the ref, or set it empty to force the old cold path. The script header documents the anonymous external read. - `.github/workflows/docker-runner-check.yml` (comment-only): the stale "no external cache" note now describes the anonymous GHCR seed and the verification build's local-cache-only isolation. This was pushed in a follow-up commit with workflow-edit permissions; the original CI-bot token could not touch workflow files. No Dockerfile stages or verification assertions changed. ## Verification - This PR's own `Compile isolated native Runner` check runs the seeded path (the script is in the workflow's trigger paths): **passed in 123s** vs the 452s baseline. - The rebuild-verification semantics are untouched: it still runs on a **fresh builder** importing **only the local cache exported by this run's baseline**, so it proves exactly what it proved before — that the runner image rebuilds reproducibly from this run's own exported layers. - Verified `ghcr.io/paperclipai/paperclip:buildcache-amd64` is anonymously readable (unauthenticated manifest pull succeeds), so the check gains no credential or secret dependency. ## Risks - **Stale or missing seed cache:** if the GHCR ref is unreachable, private, or garbage-collected, BuildKit logs a warning and falls back to the pre-PR cold compile — the check gets slower, never wrong. `RUNNER_CHECK_SEED_CACHE=""` restores the cold path explicitly. - **Cache trust:** the seed only accelerates the *baseline* build; the verification build still runs on a fresh builder against only this run's locally exported cache, so a stale or poisoned registry cache cannot make verification pass spuriously. The ref lives under `ghcr.io/paperclipai/*`, written only by repo CI on master pushes. ## Model Used Claude Fable 5 (`claude-fable-5`) via Paperclip agent **Bender (Fable)**, issue PAP-31. --------- Co-authored-by: Bender (Fable) <bender-fable@paperclip.local> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ded156a904 |
Keep interaction continuations scoped to the target task
Separate an interaction's producer from explicit resume history. Do not import another task's comments or results. Filter newly captured foreign origins and recover older inherited origins only when the saved producer context and comment row prove their source. Keep missing context and company boundaries fail-closed. Verified 46 continuation tests, 201 related recovery tests, and server typecheck. Added 20 database regressions for provenance and scope guards. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3c70b3d008 |
docs(release): curate stable notes for the 2026.921.0-beta.1 promotion (#13785)
## Thinking Path > - The stable promotion reads `releases/beta/v<beta-version>.md` from `master` and publishes it as the GitHub Release body. > - Beta `2026.921.0-beta.1` (source `8f8a0ab7`, 77 commits since v2026.916.0) just published and starts its 3-day soak, headed for a stable around 2026-09-24. > - This PR rewrites the auto-generated draft into release voice during the soak, per the release checklist. ## Linked Issues or Issue Description Notes for the stable to be promoted from [`2026.921.0-beta.1`](https://github.com/paperclipai/paperclip/releases) — planned as `v2026.924.0`. **If the promotion date slips past 2026-09-24, bump the title and Released date before dispatching stable.** ## What Changed - Rewrote `releases/beta/v2026.921.0-beta.1.md` from the 77-entry scaffold into the standard release-notes structure: overview, Breaking Changes (legacy Composio broker retirement [#13758](https://github.com/paperclipai/paperclip/pull/13758); full-auto execution defaults [#13686](https://github.com/paperclipai/paperclip/pull/13686)/[#13693](https://github.com/paperclipai/paperclip/pull/13693)), Highlights, grouped Fixes, Improvements, and an Upgrade Guide (migrations `0280`–`0283`, `enableMcpAggregators` flag). - Folded out release-infra noise: CI-only PRs, test-only PRs, release-notes bookkeeping commits, and the hide/restore Google-connector pair ([#13551](https://github.com/paperclipai/paperclip/pull/13551)/[#13552](https://github.com/paperclipai/paperclip/pull/13552), net zero). - Noted that the composer fix ([#13562](https://github.com/paperclipai/paperclip/pull/13562)) already shipped early as stable 2026.916.1. ## Verification - Docs-only; every PR number cited was cross-checked against `git log dffc2b3ca..8f8a0ab7e`. - Migration range `0280`–`0283` verified against `packages/db/src/migrations` diff and attributed per commit. ## Risks None — documentation only. Content can be edited freely during the soak; the stable preflight only requires the file to exist on `master`. ## Model Used Anthropic Claude Fable 5 (`claude-fable-5`) via Claude Code, with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [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 (docs-only; no tests apply) - [x] I have added or updated tests where applicable (none apply) - [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 (pending on this fresh PR) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending) - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
cf2742ac48 |
docs(release): canonicalize v2026.916.1 release notes (#13774)
## Thinking Path > - Stable `2026.916.1` just published from beta `2026.921.0-beta.0`; its curated notes live at `releases/beta/v2026.921.0-beta.0.md` on `master`. > - The release workflow's `canonicalize_stable_notes` job pushed this branch, which `git mv`s them to the canonical stable path. > - Merging restores the canonical `releases/` layout, matching every prior stable. ## Linked Issues or Issue Description Follow-up to the [v2026.916.1](https://github.com/paperclipai/paperclip/releases/tag/v2026.916.1) stable release; notes were curated in [#13766](https://github.com/paperclipai/paperclip/pull/13766). ## What Changed - `git mv releases/beta/v2026.921.0-beta.0.md releases/v2026.916.1.md` (workflow-generated, content unchanged). ## Verification - Rename only; the GitHub Release body was already published from this content. ## Risks None — documentation layout only. ## Model Used Anthropic Claude Fable 5 (`claude-fable-5`) via Claude Code, with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [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 (rename-only; no tests apply) - [x] I have added or updated tests where applicable (none apply) - [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 (pending on this fresh PR) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending) - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
878734a061 |
fix(tools): treat OAuth sign-in challenges as client errors (#13786)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Connected apps can require OAuth sign-in before they list their tools. > - Remote discovery recognizes this condition as `oauth_challenge`. > - Discovery and catalog refresh currently return it as HTTP 502. > - The server error handler reports that response as a crash. > - This pull request returns HTTP 422 for the explicit sign-in challenge. > - The operator keeps the sign-in instructions, while unexpected upstream failures remain reportable. ## Linked Issues or Issue Description **What happened?** Connecting a remote MCP app that answers with a recognized OAuth challenge returns HTTP 502. Reading an empty catalog or explicitly refreshing it does the same. The server error handler then sends the expected sign-in condition to error monitoring. **Expected behavior** A known sign-in requirement returns HTTP 422 with the existing `oauth_challenge` code, message, and setup/reconnect links. An unexplained upstream HTTP 400 or an unavailable upstream service still returns 502 and reaches error monitoring. **Steps to reproduce** 1. Configure a remote MCP app that returns HTTP 401 with a Bearer challenge. 2. Connect the app, read its empty catalog, or request a catalog refresh. 3. Observe HTTP 502 and a server error report before this change. **Paperclip version or commit** Reproduced on `6de50ba594b15efaa3eae6ed869cd39b3a436456`. **Deployment mode** Server with remote MCP connections. The regression coverage uses local PostgreSQL and mocked upstream HTTP responses. Related: #9750 addresses MCP initialization and session recovery. It does not change the classification of this recognized sign-in condition. Targeted searches found no duplicate classification PR. ## What Changed - Return 422 for `oauth_challenge` from discovery and from catalog health-error normalization. - Preserve the existing structured error and remediation links. - Test automatic empty-catalog reads and explicit refreshes. Verify that OAuth challenges produce no Sentry capture and that upstream 400/503 failures still do. - Update the direct-connect and blocked-redirect expectations and document the monitoring behavior. ## Verification - Before the fix, three sign-in route regressions fail with 502 instead of 422; all four upstream-error controls pass. - After the fix, all 339 tool-access and error-handler tests pass, including authorization and redirect protections. - These suites ran against disposable Homebrew PostgreSQL 16.14 through the existing test-constructor seam. The temporary setup and config remain outside the repository. CI uses the ordinary embedded PostgreSQL setup. - Direct server `tsc --noEmit` passes. - Full build and recursive typecheck were attempted; the Runner Rust step cannot run because `cargo` is absent on this machine. - Full `pnpm test:run`: 8,211 passed, 14 failed, 4,759 skipped. The 36 failed files match the existing embedded PostgreSQL startup/cleanup and macOS runtime-cache `EACCES` limitations. The changed database-backed service suite passed separately with local PostgreSQL. - Greptile: 5/5 with no unresolved comments. Seven CI workers received a simultaneous shutdown signal; the failed jobs are being retried through the normal workflow. Other completed checks passed. ## Risks Low risk. Clients now receive 422 instead of 502 for the explicit `oauth_challenge` condition. The code, message, and remediation links remain available. No permissions, credential handling, OAuth discovery rules, retry policy, or schema change. Other upstream failures retain their existing behavior. ## Model Used OpenAI GPT-6 via Codex, with reasoning, repository inspection, code editing, and test execution. The session does not expose an exact 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 (339 service and error-handler tests; full workspace limitations are 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 - [ ] 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> |
||
|
|
6de50ba594 |
fix(sentry): carry the deployment environment to the browser (#13784)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators can enable Sentry for the server and the signed-in browser. > - The server SDK reads `SENTRY_ENVIRONMENT` from the process environment. > - The browser receives its DSN through the session response, but receives no environment. > - A browser in staging therefore reports errors under the SDK's production default. > - This pull request passes the configured environment through the existing session and monitoring gate. > - Browser errors then identify the deployment environment while preserving the existing privacy settings. ## Linked Issues or Issue Description **What happened?** With `SENTRY_ENVIRONMENT=staging`, browser exceptions are tagged `production`. This can send errors to the wrong environment's alerts and makes deployment follow-up unreliable. **Expected behavior** The browser uses the server's configured Sentry environment. A reused image works in either staging or production. A signed-out browser still sends no events. **Steps to reproduce** 1. Configure a frontend Sentry DSN and `SENTRY_ENVIRONMENT=staging`. 2. Sign in and capture a browser exception. 3. Inspect the event environment. Before this change, it is `production`. **Paperclip version or commit** Reproduced on `a3749aac4680a901fa0fe1cc898907887abc9908` with the real browser SDK and a local test transport. **Deployment mode** Authenticated server and browser with optional Sentry monitoring enabled. No duplicate environment-attribution issue or pull request was found in the targeted GitHub search. ## What Changed - Add `sentryEnvironment` to the authenticated session response and shared schema. The optional field supports a newer browser reading an older server response. - Pass the environment to the browser SDK. An environment change restarts the client through its existing serialized lifecycle. - Cover environment attribution with a real SDK event, session authorization, unchanged-session refetches, environment changes, and legacy responses. - Document configuration and compatibility. Keep the loaded bundle's release identity and existing privacy filters. ## Verification - The regression test emits `production` for a requested staging environment before the fix. - Focused route, schema, browser lifecycle and real-SDK tests: 69 pass. - UI and shared-package typechecks, direct server `tsc --noEmit`, and token gates pass. - Full `pnpm build` and `pnpm -r typecheck` were attempted. Both stop at the Runner Rust step because `cargo` is absent on this machine. - Complete UI suite: 6,540 tests pass in 626 files. - Full `pnpm test:run`: 8,210 passed, 14 failed, 4,753 skipped; 36 files fail due to embedded PostgreSQL startup/cleanup and macOS runtime-cache `EACCES`. These match the existing local baseline; none touch the changed behavior. - Greptile: 5/5, no unresolved review threads. Linux CI has passed Build, Typecheck + Release Registry, and the completed test jobs so far. Remaining jobs are running or queued: the AWS runner provisioner is retrying EC2 CreateFleet `InternalError` responses. Full results will be recorded before merge. ## Risks Low risk. This adds one optional session field and changes Sentry attribution only. No migration or new monitoring opt-in is introduced. Missing settings keep the browser SDK default. Agent and unauthenticated requests still receive 401 without monitoring settings. Existing loaded browser bundles keep their old behavior until refreshed. ## Model Used OpenAI GPT-6 via Codex, with reasoning, repository inspection, code editing, and test execution. The session does not expose an exact 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 - [ ] I have run tests locally and they pass (focused and full UI suites pass; full-root environment failures 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 - [ ] 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> |
||
|
|
c221589b69 |
fix: close sandbox process proxies after remote exit (#13777)
## Thinking Path > - Paperclip manages AI agents and their tasks. > - Sandbox agents use a local proxy to exchange ACP messages with a remote process. > - ACP keeps the proxy input stream open while it waits for a reply. > - The proxy received a remote exit but kept that input stream open. > - This left the proxy alive and could block later task retries. > - This pull request closes the input handle after a terminal remote event and lets final output drain. ## Linked Issues or Issue Description **What happened?** A sandbox process could exit while its local proxy stayed alive. During startup, this could appear as a handshake timeout. A later task retry could then stop because the previous process was still alive. **Expected behavior** The proxy should exit with the remote process status, even when ACP has not closed its input stream. Final output and diagnostics should arrive before the proxy closes. **Steps to reproduce** 1. Start a sandbox process-session bridge with a child that writes output and exits. 2. Start the generated local proxy and keep its input stream open, as ACP does during startup. 3. Observe that the proxy stays alive after the remote process exits. **Paperclip version or commit** Reproduced on master at `846336e5a0`. Related: #13272 covers legacy sandbox startup recovery. #13765 covers the task retry UI. This change fixes the proxy process lifecycle. ## What Changed - Close the proxy input handle on remote exit or error, and preserve the exit status. - Stop forwarding input after the terminal event. - Wait for process close in the test helper so output is fully drained. - Test successful exit, failed exit, and spawn failure with input held open in both output modes. Check complete delivery of 208 KiB of final output. ## Verification - Before the fix, all four remote-exit regression cases timed out. - After the fix, all six terminal-event cases pass. - Targeted runtime suite: 362 tests pass across the sandbox bridge, stdin queue races, real ACP spawn, and ACP engine suites. - `pnpm --filter @paperclipai/adapter-utils typecheck` passes. - Full workspace tests hit local platform failures: embedded PostgreSQL fails during initialization, and runtime skill-cache tests fail with `EACCES` while renaming read-only directories on macOS. The affected server code is unchanged in this PR. Those suites pass in CI. - `pnpm -r typecheck` and `pnpm build` stop at the existing Rust runner step because this machine has no `cargo` executable. The CI typecheck and build gates pass. - [CI run 35658635907](https://github.com/paperclipai/paperclip/actions/runs/35658635907) passes all required gates. The first browser shard run passed all 12 tests but hit a GitHub 403 during report upload; the rerun passed, including upload. - Greptile scored commit `9c3c89148e` 5/5 with no review threads. The branch is mergeable. ## Risks The proxy now closes its input immediately after a terminal remote event. Tests cover final output delivery and preserve nonzero exit codes. Existing orphan processes still require cleanup or a server restart. Live sandbox startup needs validation after deployment; this change addresses the confirmed proxy hang and does not establish why an earlier remote process stopped. ## Model Used OpenAI GPT-6 (Codex), with reasoning, repository tools, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (targeted checks; full-workspace limits described above) - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (existing behavior restored; no documentation change needed) - [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> |
||
|
|
a3749aac46 |
fix(deps): share Lezer node properties across editor languages
fix(deps): share Lezer node properties across editor languages The installed graph gave syntax highlighters @lezer/common 1.5.1 and language parsers 1.5.2. Their independent NodeProp counters collided, so highlighting ordinary code read unrelated metadata as tags and crashed with tags-is-not-iterable. Override @lezer/common to one compatible version in both manifests. Extend the installed-graph check and exercise Python, JavaScript, HTML and SQL highlighting through the editor dependencies. All four examples failed before the override and pass with it. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
8f8a0ab7ef |
docs(release): curate stable notes for v2026.916.1 (#13766)
## Thinking Path > - Paperclip publishes stable releases from curated notes: the stable promotion reads `releases/beta/v<beta-version>.md` from `master` and publishes it as the GitHub Release body. > - Beta `2026.921.0-beta.0` was just published from a candidate branch carrying the 2026.916.0 source plus the cherry-picked composer fix #13562, headed for patch stable `2026.916.1`. > - Its `draft_stable_notes` job pushed the auto-generated scaffold; this PR rewrites it into release-notes voice so the stable promotion's preflight finds curated notes. ## Linked Issues or Issue Description Notes for the upcoming `2026.916.1` patch stable. The fix being shipped is [#13562](https://github.com/paperclipai/paperclip/pull/13562) (fixes #13561, the desktop chat composer send button starting out disabled). ## What Changed - Rewrote `releases/beta/v2026.921.0-beta.0.md` from the auto-generated commit list into the patch-release format used by `releases/v2026.831.1.md`: what the patch is, the user-facing composer fix, the rode-along document-conflict classification repair, and an upgrade guide (no migrations, no configuration changes). ## Verification - Docs-only change; no code paths affected. - Format matches the prior patch release notes (`releases/v2026.831.1.md`). - The stable promotion will resolve this file from `master` for beta `2026.921.0-beta.0` and canonicalize it to `releases/v2026.916.1.md` after publishing. ## Risks None — documentation only. If the wording needs adjusting during review, the stable dispatch simply waits until this is merged. ## Model Used Anthropic Claude Fable 5 (`claude-fable-5`) via Claude Code, with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (docs-only; no tests apply) - [x] I have added or updated tests where applicable (none apply) - [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 (pending on this fresh PR) - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups (pending) - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
df66219780 |
fix(ui): retry the latest failed task attempt (#13765)
## Thinking Path > - Paperclip manages work done by AI agents. > - The task thread lets an operator retry a failed run. > - Legacy runs with transcript output did not get a failure marker. > - The thread could therefore offer Try again for an older failure. > - The server correctly reused that failure's existing retry, even when it had already failed. > - This change keeps the latest failure actionable and reports stopped retry responses to the operator. ## Linked Issues or Issue Description **What happened?** Try again could return success without starting work. An initial setup failure had an empty transcript. Its later retry produced output and failed. Only the initial failure had a retry marker, so the button kept requesting the initial failure's already-failed successor. **Expected behavior** Try again targets the latest failed attempt. An already-stopped retry response shows an error and refreshes the task's run state. **Steps to reproduce** 1. Start a legacy adapter task that fails before producing transcript output. 2. Retry it. Let this attempt produce output and a final failure comment before it fails. 3. Click Try again in the task thread. 4. Before this fix, the click targets the original failure and replays the stopped successor. **Paperclip version or commit** Reproduced against `1483bb8bcf`; the regression is also present on the branch base `8813a50105`. **Deployment mode** Authenticated server with a legacy adapter. The bug is in the shared task UI and retry API client. Related: #11650 adds a different recovery-notice action. This change fixes failed-run markers and retry response handling. Searches found no duplicate of this failure case. ## What Changed - Render legacy failure markers even when the run has a transcript or final comment. - Keep later cancelled automatic retries from replacing the failed run's retry action. - Reject already-stopped retry responses in the API client so existing error feedback appears. - Refresh task run queries after both successful and failed retry requests. - Add regression coverage for failed and timed-out attempts, execution gates with output, and retry response states. ## Verification - Before the fix, the new regression tests failed: two selected the original failure, and four accepted a stopped successor as success. - Targeted task-thread, retry API, marker, and issue-page tests: 279 passed. - `pnpm --filter @paperclipai/ui typecheck`: passed. - `pnpm --filter @paperclipai/ui build`: passed. - `pnpm check:token-gates`: passed. - Full UI suite: 6,529 tests passed across 626 files. - [CI run 35650385023](https://github.com/paperclipai/paperclip/actions/runs/35650385023): all 53 checks passed, including full workspace build, typecheck, unit/integration suites, and browser tests. The redundant local full-workspace test run was stopped after CI passed; it is not counted as a completed local pass. - Greptile: 5/5 on `608ee58c99`, with no review threads or unresolved comments. The branch is mergeable. - `pnpm -r typecheck` and `pnpm build` were attempted. Both stop at the Runner's Rust checks because this host has no `cargo`. The full workspace checks passed in CI. ## Risks Low risk. This changes UI presentation and response handling only. The server's exact-retry idempotency, authorization, execution ownership, and recovery gates remain in place. No schema changes or live task mutations. Existing documentation describes this retry action; the fix restores that behavior. ## Model Used OpenAI GPT-6 (Codex), with reasoning, repository tools, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (targeted checks; full-workspace limits described above) - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (existing behavior restored; no documentation change needed) - [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> |
||
|
|
1483bb8bcf |
fix: pass plugin workers to issue tree resume (#13757)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Issue tree controls can resume tasks and wake their assigned agents. > - A sandbox-backed run needs the shared plugin worker manager to acquire its lease. > - The issue tree route constructed a heartbeat service without that manager. > - A ready sandbox provider therefore appeared offline and the resumed run failed setup. > - This pull request passes the existing manager to the route and distinguishes missing wiring from a stopped worker. ## Linked Issues or Issue Description Related implementation: #10262 identified this wiring defect in several dispatch paths. This PR applies the issue-tree resume fix to current master and adds coverage in the current route and runtime suites. The other dispatch paths remain in the scope of that earlier PR. **What happened?** Resuming a paused issue subtree can fail to acquire a sandbox lease even while its provider plugin is ready and its worker is running. The error says the worker is not running because this route's heartbeat service never received the process's worker manager. **Expected behavior** Resumed work uses the same worker manager as normal issue dispatch. Missing wiring and an actually stopped worker produce distinct diagnostic errors. **Steps to reproduce** 1. Configure an agent with a plugin-backed sandbox environment and start the provider worker. 2. Pause a subtree assigned to that agent. 3. Release the hold with `metadata.wakeAgents: true`. 4. The old route constructs an unwired heartbeat service and the resumed run fails during setup. **Paperclip version or commit** Reproduced by source inspection and regression coverage against `9d19f98b50`. **Deployment mode** Server with a plugin-backed sandbox environment. ## What Changed - Pass the process's plugin worker manager from `createApp` through issue tree controls to heartbeat dispatch. - Check for a missing manager before reporting the sandbox worker as stopped. - Exercise the resume request with a shared manager and cover both runtime failure cases. Model a stopped worker explicitly in the existing infrastructure-retry fixture. Existing board and company access checks remain covered. ## Verification - Targeted Vitest route/runtime/recovery suites: 17 passed; 384 native database tests skipped because embedded Postgres cannot start on this host. - Direct server `tsc --noEmit` passed. - `pnpm -r typecheck`, server typecheck wrapper, and `pnpm build` were attempted. Their runner dependency requires `cargo`, which is absent on this host. CI must pass these checks before merge. - Full `pnpm test:run` was attempted. The general server stage reported 8,146 passed, 4,747 skipped, and 14 failed tests across 35 failed suites. Failures were embedded Postgres startup errors (with related teardown errors) and 10 cache-directory rename failures on this macOS host. The local run stopped there; Linux CI must pass the complete suite before merge. - All CI gates are green, including the native database recovery suite, workspace typecheck/build, runner checks, and browser tests. Greptile reviewed the current commit at 5/5 with no unresolved threads. - No live provider operations were performed by these tests. ## Risks Low risk: dependency forwarding and error classification only. The route retains board authorization, company boundaries, hold semantics, and existing cancellation/replay guards. The change does not replace a sandbox or discard a retained lease. No schema or API shape changes. ## Model Used OpenAI GPT-6 (Codex), with reasoning, repository tooling, and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] This fixes existing behavior and does not add planned core features - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have described the issue in-PR following the bug issue template - [x] I have not referenced internal/instance-local Paperclip issues or links - [x] My branch name describes the change and contains no private ticket or instance data - [x] Targeted local tests pass; full-suite and toolchain limits are recorded above - [x] I have added or updated tests where applicable - [x] No documentation changes are needed for dependency forwarding - [x] I have considered and documented 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 reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
c65fc9e3c8 |
fix: recover authentication and browser connection failures (#13724)
fix: recover authentication and browser connection failures Include connect timeouts in the bounded retry policy for idempotent actor synchronization. Handle WebSocket constructor failures through existing reconnect paths and preserve HTTP polling while realtime is unavailable. Refresh visible company queries until the socket recovers and clear all fallback timers on hiding or unmount. Verify 172 focused tests, server/UI typechecks, UI build, and design token gates. Full workspace build/typecheck require the unavailable Rust toolchain; the full test run is tracked separately. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
600e552d7b |
fix: attribute Sentry errors to the loaded source release (#13719)
Attribute optional server and browser Sentry events to their source build. Use validated build commits for Docker and source/npm artifacts, preserve explicit server release overrides, and keep cached browser bundles tied to the commit they loaded. Verify 127 focused tests, server/UI typechecks, Docker and source build stamps, all 53 CI checks, and Greptile 5/5 with no unresolved comments. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
b70641f23f |
feat(plugins): support image catalogs and persistent application overlays (#13646)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Plugins extend the application without adding each integration to
Core.
> - A downstream image needs a way to supply prebuilt plugins.
> - Some plugin UI must stay mounted as users move between pages.
> - This change adds an image catalog and a persistent application slot.
> - Operators can upgrade or remove these plugins through their image
and configuration.
## Linked Issues or Issue Description
**Subsystem affected**
Plugin packaging, activation and application UI.
**Problem or motivation**
The built-in plugin catalog is fixed in Core source. Downstream images
cannot add entries through an explicit catalog. Existing page slots also
cannot preserve a small application overlay across route changes.
**Proposed solution**
Read a bounded catalog of prebuilt plugins from the image. Verify its
files before importing manifests. Use the existing managed selection and
plugin lifecycle. Add an `appShellOverlay` slot with account and company
cleanup.
**Alternatives considered**
A downstream fork adds merge work. Script injection provides no plugin
lifecycle. A separate runtime download system adds a second distribution
channel.
**Roadmap alignment**
This extends the existing plugin system. Related PR #9006 covers runtime
install replication; this change covers immutable image contents. PR
#12555 covers CLI scaffolding. Neither provides this catalog or
application slot. The maintainer requested this work directly.
## What Changed
- Validate catalog identities, confined paths, package versions and
bundle hashes before importing code.
- Apply image selection to persisted plugin installs, including removal
and rollback. Adopt the verified image path from existing npm/local
installs and bind runtime worker/UI entrypoints to verified package
declarations.
- Mount application overlays in both UI shells. Preserve route state and
clear it on account, company and onboarding changes.
- Restrict service-worker offline storage/fallback to hashed public
assets in a separate cache namespace; exclude application HTML and
extension/API data, including after worker restart.
- Document the packaging contract, trust model and rollback
requirements.
## Verification
- Passed `pnpm -r typecheck`, `pnpm build`, and `pnpm
check:token-gates`. Affected server/UI typechecks and builds, plus token
gates, passed again after rebasing onto current master; the 124 focused
tests also passed after rebase.
- Latest focused verification: 124 tests in nine files passed for
catalog/reconciliation/loader, overlay lifecycle, Layout and
service-worker policy. The broader UI/shared/SDK run passed 7,204 tests
in 690 files with canonical `TMPDIR`.
- Real disposable Core/PostgreSQL: catalog install, selection removal,
0.1.0→0.1.1→0.1.0, same-version npm/legacy-path adoption, and
preservation of disabled status passed. Added permissions entered
`upgrade_pending`, withheld UI across restart, and activated only after
explicit operator enable.
- Real Chromium: desktop/mobile layout, route draft retention and
Escape/focus passed with mocked extension responses. A persistent
browser restart retained public hashed-asset offline fallback while
refusing seeded legacy/current private entries and legacy HTML.
- Full `pnpm test:run`: 12,539 passed; 17 failed across six existing
files, stopping later phases. macOS read-only directory renames fail in
runtime-skill-cache and company-skills-service; email tests require an
absent local AgentMail fixture. Native runner/comment-redaction passed
in isolation after temporary Rust setup; agent-conversations also passed
in isolation. No unrelated source was changed to hide failures.
- After rebase, two unchanged chat timing tests failed in CI and passed
locally in isolation. Their CI shard passed on its single retry. All
other current-head CI jobs passed on the initial run; review is 5/5 with
no unresolved threads.
- No live deployment or external plugin service was used.
## Risks
- Plugins are trusted code. The catalog detects packaging errors; it
does not authenticate an untrusted image builder.
- Invalid catalogs fail startup. Images must contain the catalog and
bundles together, with stable directories.
- A host older than this contract lacks the activation guard. Disable
added plugins and remove their configuration keys before reverting to
it.
- Offline navigation now returns 503 instead of replaying cached
application HTML. Only public build assets have offline fallback.
- Rolling back an unapproved permission change retains the approval
gate; review the current manifest and explicitly enable it. A reduced
permission set cannot establish prior approval or prior enabled status.
- Plugin data migrations need their own rollback policy. This change
retains installed records and does not reverse migrations.
## Model Used
- OpenAI GPT-6 (Codex), model ID `gpt-6`, with repository inspection,
code execution and browser verification. The runtime does not expose an
exact 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 (relevant suites; broad
macOS server-run exceptions are 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 (fresh run on 488b3754ae; chat
shard passed its single retry)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(fresh review on
|
||
|
|
3ff3b34e15 |
Return safe client errors for malformed JSON requests (#13660)
Malformed JSON requests currently reach generic crash handling and return 500 before any route handler runs. Classify the specific Express parser error as a 400 with a constant response, preserving unrelated server error reporting. Carry forward the original three commits from #7410, preserve contributor credit, and add request privacy and negative regression checks. Document the API response. Fixes #7390. Validation: 80 focused tests, direct server typecheck, and complete Linux CI passed. Greptile 5/5. Full local typecheck/build require missing Rust tooling; local test environment failures are documented in the PR. Co-Authored-By: developers-universe-1 <madelynreyes2026@gmail.com> Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
e18ed02a56 |
Validate heartbeat run IDs before database lookups (#13657)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Operators inspect heartbeat runs, logs, and provider traces through the API. > - These routes use UUID database keys. > - A malformed path value such as `undefined` reaches the database and causes a server error. > - This pull request validates run IDs before those lookups. > - Valid requests keep the existing company and permission checks. ## Linked Issues or Issue Description Related: Refs #8135. That proposal guards actor run headers and activity writes; this fix covers heartbeat run path parameters. **What happened?** A request such as `GET /api/heartbeat-runs/undefined` passes a non-UUID value to a UUID lookup and returns a server error. Run logs and the other heartbeat run endpoints have the same unchecked path input. **Expected behavior** Reject malformed run IDs with HTTP 400 before any run lookup. Preserve valid run reads, company isolation, and the existing board and instance-admin checks. **Steps to reproduce** 1. Request a heartbeat run endpoint with `undefined`, `null`, another malformed ID, or a UUID with surrounding whitespace. 2. Observe the database UUID error. 3. Run the route regressions before and after this change. **Paperclip version or commit** Confirmed on master at `6d0342868`. **Deployment mode** The defect affects API deployments backed by PostgreSQL. Regression tests exercise the actual Express routes and authorization code with stubbed services. The historical request does not identify the originating client, so this change does not alter a guessed UI caller. ## What Changed - Share strict run-ID validation across the 12 heartbeat run endpoints in the agent router. - Keep existing board and instance-admin gates ahead of validation. Keep valid-run company and telemetry checks intact. - Reject surrounding whitespace, which the shared UUID helper accepts but PostgreSQL rejects. - Encode the UUID constraint and document the 400 response in OpenAPI. Test the generated parameter pattern on all 12 endpoints. - Cover malformed IDs on every affected endpoint, uppercase UUIDs, missing and cross-company runs, and permission precedence. Use UUID-shaped run fixtures in existing route tests. ## Verification - Before the fix: four malformed-ID regression cases fail; three access-control cases pass. - Focused agent route, permission, cross-company, and OpenAPI suites: 154 tests passed, including the final uppercase-UUID case. - Direct server typecheck passed: `pnpm --filter @paperclipai/server exec tsc --noEmit`. - The full local test attempt is still running; the complete Linux test suite passed in CI. Local results will be recorded when it finishes. - Complete Linux CI passed on the exact head: 53 checks passed, two non-applicable checks skipped. One untouched preview-service readiness test failed initially; its three targeted cases passed locally and the failed-jobs-only CI rerun passed. Greptile scored the final head 5/5 with no unresolved comments. - Full local `pnpm -r typecheck` and `pnpm build` reach the native runner step and stop because `cargo` is absent. The complete Linux CI checks passed. ## Risks Low risk: this changes malformed route inputs to HTTP 400. Valid UUID requests keep their existing lookup and authorization paths. There is no migration, dependency, provider operation, or configuration change. The separate activity router and actor run headers are outside this change. ## Model Used OpenAI GPT-6 through Codex, with code editing, shell execution, and test tools. The exact context window size was not exposed. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change and contains no internal Paperclip ticket id or instance-derived details - [x] I have run focused tests locally and they pass; full-check limits are recorded 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> |
||
|
|
6d03428682 |
Skip task-only connector reads for agent chat views (#13654)
Agent chat views reuse the task surface with synthetic chat-prefixed IDs. Skip their task-only email and external chat-binding queries, and reject invalid UUIDs after existing authentication checks on both read routes. Preserve normal task reads and company isolation. Verified failing regressions before the fix, all 6,377 UI tests, route and OpenAPI regressions, server/UI TypeScript checks, all Linux PR CI gates, and Greptile 5/5 with no unresolved comments. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
d54b750111 |
Preserve Claude ACP quota classification and reset time (#13651)
Typed Claude ACP quota failures lost their recovery classification and reset time when the runtime reduced provider metadata to a generic category error. Inspect terminal metadata in memory and retain only safe recovery labels and a parsed reset timestamp. Preserve the existing handling of other limits. Verified real child processes on both pinned ACPX runtimes, adapter and server recovery regressions, all PR CI gates, and Greptile 5/5. Also isolate a pre-existing chat regression from unrelated fixtures’ retry work. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
685d4faba3 |
Fix PostgreSQL recovery after a transaction connection closes (#13643)
Reject queued and late work from disconnected transaction and reservation scopes. Keep closed reservations out of the open pool, and clear old connection buffers and responses so new requests can reconnect safely. Twelve real-PostgreSQL regression cases cover crash prevention, recovery, and transaction isolation in both ESM and CommonJS. Database checks and all PR CI checks pass. Greptile: 5/5, no unresolved comments. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
4b8dc416da |
Fix default isolation for projects without workspace configuration (#13636)
Require a company-scoped configured workspace before applying the operator default for Git worktree isolation. Projects that only have a plain managed directory retain their existing behavior. Explicit isolation requests still require a valid checkout. Add policy and heartbeat integration regressions and document the default. The regression fails before the fix. An isolated checkout passes 541 relevant tests, and the server TypeScript check passes. Local repo-wide typecheck and build require the missing Rust toolchain; all CI lanes passed, and Greptile reviewed the refreshed head at 5/5 with no comments. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
352153b5ed |
fix: run the cargo-building native-runner CI suite in the Rust-cached vitest lane (#13586)
## Thinking Path Post-merge of #13557, the slowest check on the freshest fully-green PR run ([35246999382](https://github.com/paperclipai/paperclip/actions/runs/35246999382)) was `ci / General tests (server (1/12))` at **339s**. The cause is one suite: `server/src/services/native-runtime/native-codex-runner.integration.test.ts` runs 1 test in **277s of a 291s vitest step (95%)** because its `beforeAll` cargo-builds the Runner release binaries, and the general-server shards carry no Rust cache — every PR run cold-compiles the full third-party crate graph. The other 19 suites in that shard finish in under 70ms each. The obvious fix (a dedicated Rust-cached matrix lane) requires editing workflow files, which the available GitHub App credentials cannot push (`workflows` permission). But the `Verify Paperclip Runner` lanes **already restore the shared `release-runner-v1` Rust cache read-only**, and their commands are `pnpm --filter @paperclipai/paperclip-runner <package script>` — so the suite can move into a Rust-cached lane purely through script changes. ## What Changed - `scripts/run-vitest-stable.mjs`: new `general-server-native-runner` group carrying exactly that suite. Under the PR workflow (`GITHUB_WORKFLOW == "PR"`, inherited from `pr.yml` by the reusable `pr-trusted.yml`) the without-chat server shards exclude it and rebalance to ~211s of tests each. Every other caller — local runs, `release-verify.yml` under the Release / Cloud readiness workflows — keeps the suite in the shards, so a renamed or unknown workflow degrades to today's slower-but-covered behavior instead of dropping coverage. - `packages/paperclip-runner`: `test:typescript:vitest` now routes through `scripts/run-pr-vitest-lane.mjs` — the identical `ensure:eval-build-deps && build:rust && vitest run` chain (shard flags passed through), plus the native-runner group on the **final PR shard only** (`--shard=N/M` with `N == M`, i.e. today's `vitest 2/2`, the 122s lane). With the restored cache the suite's cargo build becomes an incremental rebuild. - `scripts/__tests__/run-vitest-stable-shard.test.mjs`: guards pin the whole contract — PR 12-shard coverage (shards + chat + native-runner = full server group exactly), Release/local 10-shard runs keep the suite, `pr.yml` is named `PR`, the vitest lanes partition with exactly one final shard, the package-script wiring, and the wrapper's shard/workflow gating via its `--dry-run` plan output. No workflow files change. `.github/workflows/*` are untouched. ## Verification - `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs scripts/__tests__/release-verify-workflow.test.mjs`: **36/36 pass** locally on this branch (includes the new coverage, wiring, and wrapper-gating guards). Both files run in CI's `Test general-server shard partition` / `Test release verify workflow wiring` steps. - Wrapper `--dry-run` plan matrix verified for all six shard/workflow combinations plus malformed-shard rejection (pinned as a guard test). - The executing proof is this PR's own CI: `ci / Verify Paperclip Runner (vitest 2/2)` must go green while running the native-runner suite (its log will show the `general-server-native-runner` group after the package vitest shard), and the 12 `ci / General tests (server (x/12))` shards must go green without it. ## Risks - The exclusion keys on `GITHUB_WORKFLOW == "PR"`. Failure mode of a rename is safe (suite falls back into the server shards, slower but covered) and the guard test on `pr.yml`'s name makes it loud. - `vitest 2/2` grows from ~122s to an expected ~210–260s — still well under the ~306s `vitest 1/2` and ~326s e2e shards, and inside the 20-minute lane timeout. If the cache misses (key drift), the lane pays a cold compile like the server shard does today; a miss is slow, never wrong. - Double-run/coverage-loss combinations are enumerated in the wrapper header and pinned by tests: each caller runs the suite exactly once. ## Model Used Claude (Bender agent, Paperclip) — Fable 5. --- Expected savings once merged: the 339s `server (1/12)` check drops to ~265s-equivalent shard levels (~211s of tests), the slowest `ci /` check becomes the ~326s e2e shard (~13–33s off PR wall time), and every PR run stops paying ~4.5 min of billed cold Rust compile. For the merger (squash): please keep the trailer below in the squash body to preserve authorship. `Co-Authored-By: Bender (Fable) <Paperclip-Paperclip@users.noreply.github.com>` ## Related PRs Searched the GitHub PR list for prior work on this surface — related groundwork, none duplicate this change: - #13457 — restored master's Rust dependency cache on the PR runner lane (the read-only cache this PR relies on) - #13500 — made that cache key image-toolchain-independent so GitHub-hosted PR runners actually hit it - #13521 — rebalanced PR shards and split the Verify Paperclip Runner lanes this PR extends - #13557 — previous health-check iteration (split the runnerd transport suite); this PR targets the next slowest check ## Checklist - [x] I have searched GitHub for duplicate or related PRs and linked them above Co-authored-by: Bender (Fable) <Paperclip-Paperclip@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
de9414dd8b |
fix: return empty read instead of past-EOF range when log reader is caught up (#13592)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The server streams agent run logs to the UI. It reads the log in
byte ranges from a local file, or from an S3 mirror after a pod restart.
> - The range math in `readS3Range()` clamps the range end up to the
range start. A fully caught-up reader then asks S3 for the range
`bytes=total-total`.
> - S3 rejects a range that starts at the end of the object. It returns
a 416 `InvalidRange` error. The API turns this into a 500 error, and the
log poller repeats it.
> - This pull request removes the clamp. A caught-up or past-EOF reader
now gets an empty read, and the server does not send an invalid range to
S3.
> - The benefit is that log polling after a pod restart does not cause
repeated 500 errors.
## Linked Issues or Issue Description
No public GitHub issue exists for this bug. The description follows the
bug report template.
**What happened?**
The run-log API returns a 500 error when a client polls a run log that
lives on the S3 mirror and the client is fully caught up (`offset ===
total`). The cause is in `server/src/services/run-log-store.ts`. The
function `readS3Range()` computes `end = Math.max(start, Math.min(start
+ limitBytes - 1, total - 1))`. When `offset === total`, the
`Math.max(start, …)` clamp forces `end` up to `start`. The `start > end`
empty-read guard does not operate, and the code sends `Range:
bytes=total-total` to S3. S3 rejects a range that starts at or past the
end of the object with a 416 `InvalidRange` error. The error monitor
records this error many times, only in the staging environment, because
only the S3 fallback path is sensitive to it. The local-file path has
the same math, but Node file streams accept past-EOF reads. The function
`readFileRange()` in
`server/src/services/workspace-operation-log-store.ts` has the same
latent math.
**Expected behavior**
A caught-up reader gets an empty read: `{ content: "", nextOffset:
undefined }`. The server does not send an invalid range request to S3.
The poller sees no contract change.
**Steps to reproduce**
1. Start a run and let it write a run log.
2. Let the log upload to the S3 mirror, and remove the local file (this
occurs when the pod restarts).
3. Poll the run-log read endpoint until the client offset is equal to
the log size.
4. Poll one more time. The server sends `bytes=total-total` to S3, S3
returns 416 `InvalidRange`, and the API returns a 500 error.
**Relevant logs or output**
```
InvalidRange: Invalid range
at readS3Range (server/src/services/run-log-store.ts)
```
## What Changed
- `server/src/services/run-log-store.ts` — remove the up-clamp in
`readLocalRange()` and `readS3Range()`. A caught-up or past-EOF reader
gets an empty read.
- `server/src/services/workspace-operation-log-store.ts` — apply the
same fix to the shared math in `readFileRange()`.
- `server/src/services/run-log-store.test.ts` — the in-memory S3 mock
now rejects past-EOF ranges with `InvalidRange`, the same as real S3.
Add two regression tests for caught-up readers on the S3 path and on the
local path.
## Verification
- Run `pnpm vitest run server/src/services/run-log-store.test.ts`. All
17 tests pass.
- Revert only the source fix, and the new regression test fails with the
exact caught-up scenario. This shows the test covers the bug.
- Run the suites that use the workspace operation log store
(`workspace-runtime-control-recovery`,
`workspace-operations-reconciliation`). All 15 tests pass.
- Run `tsc --noEmit` on the server package. It reports no errors.
## Risks
- Low risk. The change only affects the empty and caught-up boundary of
range reads. Normal in-range reads give byte-identical results.
- Behavior change: a read with `limitBytes <= 0` now returns an empty
chunk instead of one byte. No caller passes a non-positive limit (the
default is 256000).
- Caught-up local reads keep the `nextOffset: undefined` semantics, so
pollers see no contract change.
## Model Used
- Claude Fable 5 (Anthropic, model ID `claude-fable-5`), with extended
thinking and tool use, run through the Claude Agent SDK.
## 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
Co-authored-by: Bender (Fable) <noreply@paperclip.ing>
|
||
|
|
45586170e1 |
fix(ui): reveal task history while retries wait to start (#13597)
## Thinking Path > - Paperclip lets people manage AI agents and inspect their work. > - Task conversations combine comments with run transcripts. > - The first reveal waits for the relevant history to load. > - Scheduled retries have not started, so the log reader does not hydrate them. > - Waiting for those retries keeps the whole conversation hidden after its header loads. > - This change reveals available history while a retry waits to start. ## Linked Issues or Issue Description **What happened?** A task header loads, but the conversation stays behind the loading overlay while a linked run has `scheduled_retry` status. The readiness check expects that run in `hydratedRunIds`, although the log reader does not read its log. A retry delay can therefore become a task-loading delay. **Expected behavior** Show existing comments and transcripts once their data is ready. A retry that has not started must not block the conversation. **Steps to reproduce** 1. Open a task with existing comments and a linked run waiting in `scheduled_retry`. 2. Let the comments and other run transcripts finish loading. 3. Observe that the header loads but the conversation stays hidden until the retry changes status. **Paperclip version or commit** Reproduced on master at `3f1d897a7` with regression tests. **Deployment mode** Web UI, built from source. This is a client readiness bug. Searched public issues and PRs for scheduled retries, conversation loading, and history loading. No duplicate found. Related: #10255 changes the server response for active runs with no log; it does not address this scheduled-retry readiness gate. This focused bug fix does not add a roadmap feature. ## What Changed - Exclude `scheduled_retry` runs from the initial task-history readiness gate. - Extend transcript mocks to expose per-run hydration state. - Add six regression cases across legacy and native runs. Existing history loads during retry waits, while unhydrated running and completed runs still block the first reveal. - Document the exception in a code comment. No user command or configuration changes need documentation. ## Verification - All six new cases fail before the production fix. - `pnpm --filter @paperclipai/ui exec vitest run src/components/TaskChatThread.test.tsx src/components/transcript/useLiveRunTranscripts.test.tsx src/components/transcript/useNativeRunTranscripts.test.tsx`: 164 passed. - `pnpm --filter @paperclipai/ui typecheck`: passed. - `pnpm --filter @paperclipai/ui build`: passed. - `pnpm check:token-gates` and `git diff --check`: passed. - `pnpm -r typecheck` and `pnpm build`: attempted; both stop in the native runner package because the local machine has no Rust `cargo` executable. UI checks pass separately. - `pnpm test:run`: started locally, then stopped before completion after full CI passed on the same commit. The local full-suite result is incomplete. - CI on `46daa8b06`: all 53 checks passed; two optional Storybook jobs were skipped. This includes the full test matrix, build, typecheck, native runner checks, browser tests, and canary dry run. - Greptile: 5/5 on `46daa8b06`, with no review threads or actionable findings. The branch has no merge conflicts with master. ## Risks Low risk. The exception applies only to runs waiting in `scheduled_retry`. Running and completed runs retain their existing readiness checks. Retry scheduling, transcript fetching, and server behavior stay the same. No migration is needed. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository inspection, code execution, and test tools. The exact backend revision 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> |
||
|
|
5442f2d869 |
fix: repair managed Git launchers in sandbox projects (#13588)
## Thinking Path > - Paperclip runs agents in local and remote execution environments. > - Managed GitHub launchers select credentials for each Git operation. > - Remote launchers are written inside the project checkout as extensionless CommonJS scripts. > - An ES module project makes Node interpret those launchers as ESM, so they crash before credential resolution. > - When the launcher can start, empty identity variables also override valid repository and command-line Git configuration. > - This change gives the launchers their own CommonJS scope and clears empty identity overrides while preserving managed credential isolation. ## Linked Issues or Issue Description **What happened?** In a repository with `"type": "module"`, the managed `git` and `gh` launchers fail immediately with `ReferenceError: require is not defined in ES module scope`. The launchers use CommonJS but inherited the enclosing project's module type. Sandbox agents also report empty `GIT_AUTHOR_NAME` and `GIT_COMMITTER_NAME` variables and try to unset them for each command. With no managed identity available, the Git launcher recreated those empty values. `git commit` failed with `fatal: empty ident name`, even with explicit `user.name` and `user.email` configuration. **Expected behavior** Managed `git` and `gh` start in both ES module and CommonJS projects. Local commits with an explicitly configured identity work without manual environment cleanup. Managed credentials and captured identity continue to take precedence. Missing identity does not silently select the host user's details. **Steps to reproduce** 1. Create a sandbox project whose `package.json` contains `"type": "module"`. 2. Stage the managed GitHub launchers and run `git --version` or `gh --version`. Before this fix, the launcher fails at its first `require()`. 3. In a CommonJS project with no available managed identity, configure repository `user.name` and `user.email`, or supply them with `git -c`. 4. Run `git commit --allow-empty -m test`. Before this fix, both identity configuration forms fail with empty identity. **Paperclip version or commit** Reproduced from master commit `165b10bd9`. **Deployment mode** Sandbox execution. The shared launcher is also used for managed local and SSH execution. Related work: #13094 introduced the local-operation fallback; #13053 changes launcher discovery on Windows. Neither fixes empty identity overrides. Related identity work in #8945 and #8946 configures worktree authorship and does not remove these environment overrides. ## What Changed - Stage `package.json` with `"type": "commonjs"` in the launcher directory before the Node scripts. Keep the project's package configuration unchanged. - Leave inherited author and committer variables unset in the real Git process. When credentials are absent, require explicit Git identity configuration with `user.useConfigOnly`. - Clear empty identity merge overrides in staged shell profiles after environment merging. Preserve nonempty captured identity values. - Exercise real Git commits with repository and command-line identity, broker failures, and managed-user switching. Verify startup in ES module and CommonJS projects, shell cleanup, and captured identity preservation. - Document launcher module scope and local identity behavior in the execution GitHub identity contract. ## Verification - Confirmed both new local-commit regression cases fail before the fix with `fatal: empty ident name`. - Confirmed the new ES module project regression fails before the fix with `require is not defined in ES module scope`. - Focused launcher and shell tests: 28 passed. - `pnpm exec vitest run --project @paperclipai/adapter-utils --exclude '**/dist/**'`: 1,216 passed, 11 skipped across 58 files. - `pnpm --filter @paperclipai/adapter-utils typecheck` and `pnpm --filter @paperclipai/adapter-utils build`: passed. - `pnpm -r typecheck` and `pnpm build`: attempted; both stop in the unchanged native runner because Cargo is not installed on this machine. - Full `pnpm test:run`: started locally; stopped the duplicate run after the complete CI suite passed. No local full-suite success is claimed. - CI on `99ea8050e`: all 53 checks passed (2 skipped), including full tests, typecheck, build, native runner checks, and browser checks. - Greptile reviewed `99ea8050e`: 5/5 with no findings or unresolved comments. GitHub reports no merge conflicts with master. - No live sandbox or GitHub push probe performed. ## Risks - The new package scope is confined to the run-specific launcher directory. It does not change the project's module type, launcher names, or credential selection. - Without a managed identity, an explicitly configured repository author can now create local commits. GitHub access remains subject to the existing credential broker. Global/system Git configuration, ambient credentials, and SSH identity remain isolated. - Managed identity still wins over repository settings. Missing local identity still fails instead of guessing host details. - New or resumed executions must stage the updated launcher and shell profiles. Existing processes retain their prior files and environment until refreshed. No database migration or sandbox image rebuild is required. - Revert this change to restore the prior behavior. ## Model Used - OpenAI GPT-6 via Codex, with code inspection, implementation, and local test execution. The hosted model variant and context window were not exposed. ## 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 (the affected adapter-utils package) - [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> |
||
|
|
ec40bd8bf6 |
ci(runner): split retained-settlement suite out of runnerd-codex-transport.test.ts (#13557)
Moves the 19-case 'settles only retained control authority' family (~156s) plus its two private helpers from runnerd-codex-transport.test.ts (8,895 lines, 398s sequential) into a new runnerd-codex-transport-settlement.test.ts so vitest can schedule the two files onto separate workers. Pure code move, no test-logic changes; vitest collects the identical 182 test names. Measured on the PR's own CI run: 'ci / Verify Paperclip Runner (vitest 1/2)' dropped from 531s to 340s and the end-to-end PR workflow from ~545s to ~415s. Co-Authored-By: Bender (Fable) <Paperclip-Paperclip@users.noreply.github.com> |
||
|
|
165b10bd98 |
fix: enable GitHub Actions MCP toolset (#13553)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The GitHub connector lets agents use repository tools through MCP. > - GitHub excludes Actions from its default MCP toolsets. > - Approval of Actions permissions therefore does not make workflow tools appear in Paperclip. > - This pull request adds Actions to the requested toolsets for discovery and execution. > - Users can refresh existing connections and use workflow tools under the existing access rules. ## Linked Issues or Issue Description **What happened?** GitHub Actions tools remain absent after the GitHub App receives Actions read/write access and the user refreshes actions in Paperclip. Paperclip does not request the Actions MCP toolset. **Expected behavior** Authorized GitHub connections expose workflow tools, including `actions_run_trigger` with `method: "run_workflow"`, so agents can dispatch an existing release workflow. **Steps to reproduce** 1. Connect GitHub to Paperclip with access to a repository that has a dispatchable workflow. 2. Grant the GitHub App Actions read/write permission and approve the installation update. 3. Refresh the connection's actions in Paperclip. 4. Observe that the workflow tools are absent. **Paperclip version or commit** Base commit: `fae698031`. **Deployment mode** Hosted instance with a managed GitHub connection. The same missing header affects PAT connections. No matching public issue or pull request was found in the duplicate search. ## What Changed - Send `X-MCP-Toolsets: default,actions` through the shared GitHub MCP header helper. This covers discovery, refresh, and execution for existing and new managed or PAT connections, including legacy rows identified through `transportConfig`. - Test catalog refresh, tool risk classification, and workflow dispatch through a mock MCP server. - Document tool names, workflow arguments, required GitHub permissions, and the refresh step. ## Verification - Passed both affected test suites: `pnpm exec vitest run server/src/__tests__/tool-access-service.test.ts server/src/__tests__/tool-gateway.test.ts` (391 tests). - Passed `pnpm check:token-gates` and `git diff --check`. - Live provider check: the default catalog returned 45 tools. `default,actions` returned 49 tools, with no tools removed. The four added tools were `actions_get`, `actions_list`, `actions_run_trigger`, and `get_job_logs`. - Live `actions_get` / `get_workflow` call succeeded. No workflow was dispatched during live verification. - Passed `pnpm -r typecheck` and `pnpm build` with the existing Rust toolchain added to PATH. - Rechecked server typecheck and build after the legacy-connection fix; both passed. - The full local test run has reported three skills-cache failures in `company-skills-service.test.ts`. All three reproduce on the untouched base commit (`fae698031`) on this macOS host: runtime-cache directory renames fail with `EACCES`. The full run remains in progress. - Greptile: 5/5 on `7d391e3c7`, with no unresolved review threads. - After deployment, use **Refresh actions** on an existing GitHub connection and verify the workflow tools appear. ## Risks - Refreshed GitHub catalogs expose more tools. Existing access, approval, and quarantine rules still apply. `actions_run_trigger` keeps GitHub's destructive classification because it also supports cancellation and log deletion. - GitHub still enforces token and installation permissions. Dispatch requires Actions write permission and a workflow with `workflow_dispatch`. - No database migration or saved connection edit is required. ## Model Used OpenAI GPT-6 through Codex, with code execution and tool use. The exact serving model ID and context window are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] 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> |
||
|
|
fae6980310 |
revert(apps): restore Google connector visibility (#13552)
## Thinking Path > - Paperclip helps people manage AI agents for work. > - The Connectors catalog lists services that agents can use. > - PR #13551 temporarily hid Google connectors. > - We now want to restore their catalog visibility. > - This PR reverts that change and restores the previous catalog behavior. ## Linked Issues or Issue Description Refs: #13551 Revert the temporary removal of Google connectors from the UI. ## What Changed - Restore Gmail and eight Google Workspace entries to the catalog. - Restore the matching branding flags and original catalog and service tests. - Remove the temporary-hiding documentation note. This is an exact revert of commit `cf1e873ab24277d55ffd3ab06074f77014dc4015`. ## Verification - Passed: 507 catalog, UI, and connection service tests. - Passed: `pnpm check:token-gates` and `node scripts/check-app-brand-assets.mjs`. - Passed: `pnpm --filter @paperclipai/ui... build` and `pnpm --filter @paperclipai/ui... typecheck`. - Full local build and typecheck stop at the Rust runner because `cargo` is not installed. - Full local Vitest was not repeated because the unchanged base has confirmed macOS skill-cache permission failures. The full CI suites passed. - Passed: all GitHub CI gates; Greptile 5/5 on commit `4e3dddef0ebfef1f99001e7735822ed4cba852ab`, with no review threads. - Reviewer check: open Connectors and confirm that Gmail and Google Workspace entries appear again. ## Risks Low risk. This restores the previous catalog visibility and setup entry points. Connector implementations and saved connection data are retained. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The exact deployment 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> |
||
|
|
cf1e873ab2 |
fix(apps): temporarily hide Google connectors (#13551)
## Thinking Path > - Paperclip helps people manage AI agents for work. > - The Connectors catalog lists services that agents can use. > - We need to temporarily remove Google connectors from the UI. > - The catalog already separates visibility from retained definitions. > - This PR uses that setting so Google can return with a small change. ## Linked Issues or Issue Description **What existing behavior does this improve?** The Connectors catalog and its setup entry points. **Current behavior** The catalog shows Gmail and eight Google Workspace connectors. **Proposed behavior** Temporarily hide those nine entries. Keep their definitions and existing connections. **Reason and benefit** Make the temporary UI removal easy to reverse. **Breaking changes** Fresh catalog setup no longer offers Google. Saved connections keep the existing management and reconnect paths. ## What Changed - Add the nine Google connector slugs to the existing hidden list. - Match the branding manifest visibility flags. - Update existing catalog and service tests. Keep backend Google connection coverage and document how to restore visibility. ## Verification - Passed: 507 targeted tests covering catalog definitions, URL matching, setup routing, connector UI, branding, and the connection service. - Passed: `pnpm --filter @paperclipai/ui... build` and `pnpm --filter @paperclipai/ui... typecheck`. - Passed: `pnpm check:token-gates` and `node scripts/check-app-brand-assets.mjs`. - Full local build and typecheck stop at the Rust runner because `cargo` is not installed. - Stopped the full local Vitest run after skill-cache permission failures. Three failures in `company-skills-service.test.ts` also reproduce on the unchanged base branch. The final connector service suite passes all 319 tests. - Greptile: 5/5 on the current commit, with no open review threads. CI is retrying one unrelated preview-server readiness timeout. That test file passes all seven tests locally. - Reviewer check: open Connectors in a company with no Google connections. Gmail and Google Workspace entries should be absent. Existing saved connections remain manageable. ## Risks Low risk. This uses the existing catalog visibility mechanism. No connector implementation, credential, or database schema is removed. Restoring visibility requires updating both the hidden list and branding manifest. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The exact deployment 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 - [ ] 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> |
||
|
|
6fe8e30625 |
feat(apps): add Railway connection and governed deployment tools (#13415)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Apps gives agents governed access to external resources. > - Operators need to inspect Railway services, read logs, deploy code, and run container commands. > - Railway offers hosted MCP with OAuth, but broad remote actions hide their internal operations. > - This PR adds a branded connection and fixed direct operations through the existing gateway. > - Separate SSH keys enable container commands under the same grants and policies. > - Operators can require approval for an action and inspect the resulting audit record. ## Linked Issues or Issue Description **Subsystem affected** Apps catalog, connection setup, gateway execution, and connection documentation. **Problem or motivation** Agents need Railway access through Paperclip. Operators need to grant and revoke that access, inspect available actions, and govern deployment and container operations without giving agents provider credentials. **Proposed solution** Reuse hosted MCP OAuth, vault storage, catalog discovery, grants, and the gateway. Probe the actual credential before enabling fixed GraphQL operations. Use a dedicated grant-owned SSH key for bounded container commands. **Alternatives considered** A catalog entry alone cannot execute the missing operations. The hosted general agent has opaque internal effects. An unrestricted CLI runtime can bypass action policy and inherit ambient credentials. **Roadmap alignment** This extends the existing MCP Tool Gateway & Apps path and the Connected Apps direction in ROADMAP.md. It does not add a plugin or parallel connection service. Related PRs #311, #939, and #7861 concern hosting Paperclip on Railway. They do not add this outbound Apps connection. The separate shared agent-picker fix is #13414 and is not included here. ## What Changed - Add the generated Railway catalog entry, official marks, provenance, and OAuth setup guidance. - Add fixed service/deployment status, bounded logs, and redeploy/restart/rollback tools. Block source deployment until the provider can atomically bind the approved repository and commit. - Verify API access with an explicit workspace before exposing direct tools. - Add grant-owned SSH key setup and a bounded runner with host verification, target checks, isolated state, and cleanup. - Block the opaque hosted railway-agent and accept-deploy actions. Preserve normal Allowed defaults and Ask-first policies for other actions. - Quarantine new or changed Railway schemas after initial discovery, including reconnect. - Add provider, lifecycle, gateway, SSH, UI, and browser fixtures. Document setup, limitations, and the release checklist. ## Verification - Security follow-up: removed the unsafe source-deployment mutation. Direct calls and old active catalog entries are denied before any upstream request, including normalized aliases. Refresh marks retired entries disabled. All 386 focused Railway, catalog and gateway tests passed, and server TypeScript checking passed. Full [GitHub CI](https://github.com/paperclipai/paperclip/actions/runs/35139421144) passed on |
||
|
|
dcb04a8062 |
fix(claude-local): read a macOS isolated login from its suffixed Keychain item (#13519)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Connecting a Claude subscription during onboarding uses an isolated
login: the wizard points `claude` at a per-connection
`CLAUDE_CONFIG_DIR` and then verifies the credential before saving the
connection
> - The verifier reads `.credentials.json` from that directory — but on
macOS, Claude Code does not write a credentials file at all: it stores
the OAuth credential for a custom config dir in a per-directory Keychain
item named `Claude Code-credentials-<first 8 hex chars of sha256(dir)>`
> - So on macOS the connect step can never verify a successful sign-in,
and onboarding dead-ends at "Could not verify the local subscription"
(Linux works because the CLI falls back to writing the file there, which
is why the Docker-based smokes pass)
> - This pull request teaches the credential readers to consult the
login home's own suffixed Keychain item when the file is missing
> - The benefit is that macOS self-hosted users can connect a Claude
subscription during onboarding, while the standing isolation invariant —
an isolated login must never fall through to the machine-level operator
login — is preserved, because only the per-directory suffixed item is
ever read
## Linked Issues or Issue Description
No existing issue. Description follows the bug-report template:
**What happened?**
On macOS, connecting a Claude subscription during onboarding (or from
Connections) always fails with "Could not verify the local subscription.
Run the sign-in command shown for this connection, finish signing in,
then try Connect again" — even after `claude auth login` completes
successfully in the isolated `CLAUDE_CONFIG_DIR`.
**Expected behavior**
After finishing the browser sign-in for the printed command, clicking
Connect verifies the subscription and saves the connection.
**Steps to reproduce**
1. On macOS, run onboarding on a fresh instance and reach "Connect a
model" → Claude → Subscription.
2. Run the printed `export CLAUDE_CONFIG_DIR=… && claude auth login`
command in a terminal on the same machine and complete the browser
sign-in.
3. Return and click Connect. Verification fails every time. Inspecting
the isolated directory shows `.claude.json` with a fully populated
`oauthAccount` but no `.credentials.json`; `security
find-generic-password -s "Claude Code-credentials-<suffix>"` shows the
credential landed in the Keychain, where the verifier never looks.
**Paperclip version or commit**
Reproduced on `2026.915.0-canary.11` (`dffc2b3ca`) with Claude Code
2.1.231.
**Deployment mode**
Self-hosted, authenticated instance on macOS.
**Installation method**
`npx paperclipai onboard` (also affects any macOS install; Linux is
unaffected).
## What Changed
- `packages/adapters/claude-local/src/server/quota.ts`:
- New exported helper `readIsolatedClaudeKeychainToken(loginHome)` —
computes the suffixed service name (`Claude Code-credentials-` + first 8
hex chars of `sha256(loginHome)`) and reads only that item via
`/usr/bin/security`; returns null off macOS
- `readClaudeToken` with a custom `CLAUDE_CONFIG_DIR` now consults that
directory's suffixed item after the file reads miss (previously it
refused the Keychain entirely for custom homes). The unsuffixed operator
item is still gated behind the explicit `allowKeychain` opt-in with no
custom home, unchanged
- `server/src/services/local-ai-credentials.ts`: for anthropic isolated
logins, fall back to the suffixed Keychain item after the hardened
credentials-file reads miss. The file path is untouched and still
preferred; the hardened file reader (`readLocalAiCredentialFile` with
its uid/mode/symlink checks) is not bypassed
- Tests: adapter keychain suite extended (suffixed lookup for custom
homes, no unsuffixed fallback when the suffixed item is absent,
off-macOS null); server verifier suite extended (keychain fallback when
the file is missing, file preferred over keychain, absent-login failure
still never touches the ambient reader)
Security note: the suffix binds each Keychain item to exactly one auth
home, so reading it can only surface the login performed inside that
home. The account-isolation invariant the old code enforced by refusing
the Keychain outright ("never substitute the server operator's login for
a user's isolated login") is preserved — the unsuffixed item is never
consulted for an isolated login, and a new test pins that.
The suffix derivation was confirmed against a live login on macOS: a
real `claude auth login` into an isolated home left no credentials file,
wrote the full `oauthAccount` to `.claude.json`, and created a Keychain
item whose suffix equals the first 8 sha256 hex chars of the exact
`CLAUDE_CONFIG_DIR` string; reading it back with the same `security`
invocation returned the live token, which the new code path then
verifies via the existing quota probe.
## Verification
- `pnpm exec vitest run src/server/quota-keychain.test.ts`
(claude-local): 10 tests pass; full claude-local suite: 287 passed, 1
skipped
- `pnpm exec vitest run src/__tests__/local-ai-credentials.test.ts`
(server): 11 tests pass
- Reverting only the verifier change makes the two new server tests fail
— the suite reproduces the live bug
- End-to-end on macOS: a dev server built from this branch, fresh data
dir, full onboarding walk with a real `claude auth login` into the
printed isolated dir — the connect step verifies and saves the
connection
## Risks
- Low. The change is additive and fail-closed: when the suffixed item is
absent (Linux, older Claude Code versions, no login performed), behavior
is byte-identical to today — the file reads run first and the failure
message is unchanged
- The `security` call runs with the existing 10s timeout and swallowed
errors, matching the established unsuffixed-item code path
- No migrations, no API surface changes
## Model Used
Claude Fable 5 (`claude-fable-5`), extended thinking with tool use
(Claude Code).
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [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
|
||
|
|
d08abcba15 |
ci: cut PR wall clock from ~16 to ~6 minutes (#13521)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every pull request runs the Trusted PR CI workflow before merge > - The test suites roughly tripled in six weeks, and shard balance did not keep up, so PR runs crept from ~4 to ~17 minutes > - Slow CI delays every merge and every contributor > - This pull request rebalances the shards from fresh measurements, splits the largest test files, reuses the Rust build cache in three more jobs, and takes the policy job off the critical path > - The benefit is a PR wall clock near 6 minutes with the same coverage ## Linked Issues or Issue Description **What existing behavior does this improve?** PR CI wall clock. A typical green run took 16-17 minutes. Two months ago it took about 4 minutes. **Subsystem affected** The Trusted PR CI workflow (`.github/workflows/pr-trusted.yml`), the shard-duration manifests, the vitest shard runner scripts, the `paperclip-runner` package scripts, and the dry-run branch of `release.sh`. **Current behavior** The shard-duration manifests were stale. The general-server manifest had durations for ~400 of 649 suites. The e2e manifest was missing 14 of 29 specs. Stale median weights made shard steps range 417s-806s (server) and 277s-745s (e2e). Three jobs each paid a ~3m40s cold cargo release build. Every test lane waited ~60s for the policy job before it could start. **Proposed behavior** All lanes finish in a narrow ~200-290s band. The manifests carry fresh measured durations for every suite. The three largest test files are split so no single file caps a shard. The Rust cache restore runs in every job that builds the Runner binary. Test lanes start as soon as the gate resolves. **Reason and benefit** Merges stop waiting on CI. The projected wall clock is ~6 minutes for the same test coverage. ## What Changed - Rebuild `scripts/general-server-shard-durations.json` (646 suites) and `scripts/e2e-shard-durations.json` (all specs) from per-suite completion timestamps in runs 35036001734 and 35024948947. - Move the PR server lane to the release-verify shape: `general-server-without-chat` across twelve duration-balanced shards, plus the chat integration suite split by collected test location across three dedicated lanes. - Split `tests/e2e/chat-adapters-ui.spec.ts` into `-providers` and `-messaging` specs, and `tests/e2e/agent-chat.spec.ts` into `-sessions` and `-projects` specs. Each pair shares fixtures through a `.shared.ts` module. Playwright collects the same test sets (39 and 20 tests). - Raise e2e shards to eight and serialized shards to nine. - Run the runner package's `check:all` as four matrix lanes: `check:static`, `check:runner`, and two native vitest `--shard` halves. The union is exactly `check:all`. - Add the read-only Rust cache restore (toolchain pin, `save-if: false`) to the Canary Dry Run, Build, and Typecheck jobs. - Make release.sh preview publish payloads concurrently in batches of eight during `--dry-run`. The real publish path stays strictly serial. - Drop the policy-job lockfile artifact chain. Each lane installs with `--frozen-lockfile` and falls back to an inline `--resolution-only` regeneration. The policy job stays a required check through the `verify` and `e2e` aggregates. - Update the shard-count mirrors and workflow assertions in the partition and gate tests. ## Verification - `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs scripts/__tests__/e2e-shard.test.mjs` — 30 pass. - `node --test '.github/scripts/tests/'*.test.mjs` — 410 pass. - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/cloud-source-verification.test.mjs scripts/__tests__/release-dry-run-notes.test.mjs` — 42 pass. - `playwright test --list` collects 39 tests across the chat-adapters split and 20 across the agent-chat split, equal to the original files. - A local vitest collection of the chat suite partitions 995 tests into 498/497 line shards. - Projected shard weights: server 230s x12, chat ~143s x3, e2e 207-242s x8, serialized ~216s x9. ## Risks - The split spec files reorder tests relative to the original files. Every describe seeds its own company, so the specs stay independent; a hidden cross-describe dependency would surface as a deterministic failure in one shard. - The inline lockfile fallback changes install behavior for manifest-changing and stacked PRs. The policy job still validates resolution as a required check. - `release.sh` changes are confined to the `--dry-run` preview branch. The publish loop is untouched. `bash -n` passes and the release dry-run tests pass. - One PR now schedules ~44 fleet runners. If the RunsOn fleet caps concurrency, queueing may absorb part of the gain; watch the first runs. ## Model Used - Claude Fable 5 (`claude-fable-5`, Anthropic), extended thinking, with tool use (shell, file edits) in Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [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 |
||
|
|
c49336acdf |
docs(release): canonicalize v2026.916.0 release notes (#13548)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Stable v2026.916.0 shipped today; its release notes were maintained during the beta window at `releases/beta/v2026.916.0-beta.0.md` > - The release workflow's canonicalize step renames the file to its canonical stable path once the promotion completes, pushing the rename to a branch for a human-opened pull request (bot-opened PRs trigger no CI) > - This pull request is that rename: `releases/beta/v2026.916.0-beta.0.md` → `releases/v2026.916.0.md` > - The benefit is that the published GitHub Release body and the in-repo notes file agree on the canonical path ## Linked Issues or Issue Description Routine post-release canonicalization for the `v2026.916.0` stable, generated by the release workflow's `canonicalize_stable_notes` job (run 35126040769). Content is byte-identical to the notes published on the GitHub Release. **What happened?** Stable promotion completed; the notes file needs its canonical name. **Expected behavior** `releases/v2026.916.0.md` exists on master matching the published release body. **Steps to reproduce** n/a — mechanical rename. ## What Changed - Rename `releases/beta/v2026.916.0-beta.0.md` to `releases/v2026.916.0.md` (no content change) ## Verification - Diff is a pure rename; content matches the published GitHub Release body for v2026.916.0 ## Risks - None — docs-only rename. ## Model Used None for the change itself (generated by the release workflow); PR opened via Claude Fable 5 (`claude-fable-5`, Claude Code). ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
5b6e54fba8 |
fix(cli): accept prompt defaults in onboarding wizard validators (#13520)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The CLI onboarding wizard's custom-setup path collects server,
database, storage, and secrets configuration through `@clack/prompts`
text prompts, most of which show a sensible default
> - `@clack/prompts` runs each prompt's `validate` callback on the raw
typed value, and only substitutes `defaultValue` after validation passes
— so pressing Enter to accept a shown default hands the validator an
empty string
> - Eleven of the wizard's validators reject the empty string, which
makes their own displayed defaults unacceptable: accepting "Embedded
PostgreSQL port: 54329" fails with "Port must be an integer between 1
and 65535", "Backup directory" fails with "Backup directory is
required", and so on through every prompt in the custom path
> - This pull request makes each affected validator accept empty input
when a default exists, while keeping all real validation for typed input
> - The benefit is that the custom-setup wizard is walkable by pressing
Enter through the defaults, as the UI clearly intends
## Linked Issues or Issue Description
No existing issue. Description follows the bug-report template:
**What happened?**
In `paperclipai onboard` custom setup, pressing Enter to accept a
prompt's displayed default fails validation on eleven prompts. Confirmed
live on the "Embedded PostgreSQL port" prompt (default 54329 → "Port
must be an integer between 1 and 65535") and the "Backup directory"
prompt (populated default path → "Backup directory is required"). The
only way through is to retype every default by hand.
**Expected behavior**
Pressing Enter accepts the displayed default, as in every standard
`@clack/prompts` flow.
**Steps to reproduce**
1. `npx paperclipai onboard` → choose Custom setup.
2. At "Embedded PostgreSQL port", press Enter to accept the shown
default.
3. Validation rejects it. Same for the backup directory, backup
interval/retention, server port, bind host, storage directory, S3
bucket/region, and secrets key-file prompts.
**Paperclip version or commit**
Reproduced on `2026.915.0-canary.11`; the same validators exist in the
latest stable (`v2026.831.1`) — long-standing, not a recent regression.
**Deployment mode**
Any (the bug is in the CLI wizard).
**Installation method**
`npx paperclipai onboard`.
## What Changed
- Audited all 15 `validate:` callbacks across
`cli/src/prompts/{database,server,storage,llm,secrets}.ts`. Eleven
rejected the empty string while displaying a default; two were already
fine (hostname CSV prompts, where empty parses to `[]`); one is an
intentionally required password with no default (left alone); one
(PostgreSQL connection string) and one (public base URL) are
conditionally required — empty now passes only when a saved default
exists, so fresh setups still enforce the field
- Fix pattern: allow empty/undefined input at the top of each affected
validator; every check for non-empty typed input is unchanged. One
deliberate exception: the bind-host validator validates `(val ||
defaultHost)` so accepting the default still runs the loopback safety
check rather than bypassing it
- New `cli/src/__tests__/prompt-default-accept.test.ts` (repo-convention
vitest + clack mock reproducing real submit semantics — validate raw
`""`, then substitute the default): drives the four prompt modules
end-to-end and unit-exercises each captured validator (empty accepted,
garbage still rejected, required-when-fresh still rejected)
## Verification
- `pnpm exec vitest run src/__tests__/prompt-default-accept.test.ts` in
`cli/`: 13/13 pass; with the prompt fixes stashed: 12/13 fail — the
suite reproduces the bug
- Full cli suite: 483 passed; 15 failures are pre-existing/environmental
on the clean tree too (macOS `/var` realpath mismatch in
`worktree.test.ts`, one parallel-run flake that passes in isolation)
- `pnpm run typecheck` in `cli/`: zero errors in `cli/src` (the 228
pre-existing errors in `../server/src` from missing prebuilt workspace
dist are identical with and without the change)
## Risks
- Low. Typed input validates exactly as before; whitespace-only input is
still rejected (clack substitutes the default only for truly-empty
input). The two conditionally-required prompts still hard-require a
value on fresh setups
- No migrations, no API surface changes; CLI-only
## Model Used
Claude Fable 5 (`claude-fable-5`), extended thinking with tool use
(Claude Code); implementation drafted by a subagent on the same model
and reviewed before commit.
## 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
|
||
|
|
de9ac61fb5 |
docs(release): curate stable notes for v2026.916.0 (#13522)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release system publishes canary, nightly, beta, and stable channels; a stable promotion publishes its release notes as the GitHub Release body > - At beta publish time the workflow auto-drafts a raw commit-log skeleton on this branch (`releases/beta/v2026.916.0-beta.0.md`) for humans to edit > - The skeleton is a 1,800-line commit dump; stable `v2026.916.0` cannot ship user-facing notes in that form > - This pull request replaces the skeleton with the curated changelog for the `v2026.916.0` promotion: overview, breaking changes, highlights, fixes, upgrade guide, and contributor credits for the 483-commit range since `v2026.831.1` > - The benefit is that the stable promotion reads finished, accurate notes from master and publishes them as the release body ## Linked Issues or Issue Description Refs #13403, #13247, #13248, #13268, #13256, #13038, #13299 — the headline features this changelog describes. The notes-drafting flow itself (skeleton branch at beta publish, stable promotion reading the file from master, post-ship canonicalization) is the standing release process; this PR is the curation step it expects. ## What Changed - Replaced the auto-drafted skeleton in `releases/beta/v2026.916.0-beta.0.md` with the curated release notes for stable `v2026.916.0` (promoted from beta `2026.916.0-beta.0`, source `dffc2b3ca`) - Also removes the orphaned `releases/beta/v2026.915.0-beta.0.md`: that beta's promotion was abandoned before publishing, and this changelog supersedes it - Sections: overview, Breaking Changes (5), Highlights (Connections train leads), Improvements, Fixes, Upgrade Guide (migrations `0231`–`0279`, new env vars, removed API surface), Contributors ## Verification - Every PR link and claim was checked against the actual commit range `dbf052577..667c79ded` (the same range the skeleton header names) - Migration list enumerated from `git log --diff-filter=A` over that range; only `0231` and `0236` discard data, called out as such - New environment variables verified in code (`server/src/config.ts`): announcement flags (default on), split Sentry DSNs with legacy fallback, token-broker allowed hosts, cwd `.env` opt-out - Contributor list built from commit authors plus co-author trailers; core maintainers excluded per release-notes convention - Docs-only change: no code paths, no tests to add ## Risks - Low risk: documentation only. The stable promotion reads this file from master at dispatch time; if wording needs a follow-up after merge, the promotion pins the master revision it resolved, so edits must land before the stable dispatch - The file is renamed to `releases/v2026.916.0.md` by the post-ship canonicalization step, as with previous promotions ## Model Used Claude Fable 5 (`claude-fable-5`), extended thinking with tool use (Claude Code). The commit-range analysis and draft were produced by a subagent on the same model and human-review-style checked against the range before commit. ## 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
a8d32e5e61 |
feat(sandbox-providers): add CreateOS sandbox provider (#13434)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Agent work runs in sandboxes that provider plugins supply > - Operators can choose a provider to run agent work > - CreateOS adds another provider with workspace-preserving pause and resume > - This pull request adds a CreateOS provider plugin > - The benefit is that operators can preserve a workspace between runs without keeping its compute active ## Linked Issues or Issue Description Refs #13203 and the earlier closed #13096. This continues the CreateOS contribution from @bhautikchudasama and @ashwaq06. The branch preserves the original implementation commit. Thank you to both contributors. When squash-merging, preserve the original author's credit in the squash commit body: ```text Co-Authored-By: bhautikchudasama <BhautikChudasama@users.noreply.github.com> ``` The original fork rejects maintainer pushes. This branch includes the merge-conflict resolution and review fixes. The request is described below using `adapter_request.yml`. **Agent or provider** CreateOS sandbox API (https://api.sb.createos.sh). **Why this adapter is useful** CreateOS can pause a sandbox and resume it by ID. The workspace survives the pause. This adds a reusable-lease option to the existing sandbox provider system. **How the agent is invoked** Build and install the local plugin as described in its README. Open Instance Settings, then Environments. Select the `createos` driver. Supply an API key and shape. The driver then supplies sandbox leases for agent runs. **Are you willing to implement it?** Yes. This pull request is the implementation. ## What Changed - Adds the `createos` sandbox provider under `packages/plugins/sandbox-providers/createos`. - Calls the CreateOS HTTP API directly. The package adds no vendor SDK. - Implements the environment lifecycle hooks, incremental process output, and binary workspace sync. - Registers the optional bundled provider and its trusted host credential fallback. The fallback is limited to the official API origin; custom endpoints require an explicit key. - Lists the package in the release manifest with `publishFromCi: false` until its first npm publish is bootstrapped. - Waits through delayed pause/resume state updates without duplicate action requests. - Cancels queued API requests promptly while preserving request spacing. - Uses direct CLI invocation in the setup guide so paths and IDs are passed without an extra shell expansion. - Includes current master and retains its existing Git-subfolder containment fix. ## Demo Fresh setup and a run against a CreateOS sandbox. https://github.com/user-attachments/assets/e71b9e06-c006-4fb9-b847-52dfd68f6110 https://github.com/user-attachments/assets/43b5ac75-66bd-4f76-8563-67e4c7759084 ## Verification All 25 jobs in [CI run 34884260542](https://github.com/paperclipai/paperclip/actions/runs/34884260542) passed at commit `f8d0997677024b784fdadf9d44a84c01cb4e813c`, including typecheck, build, native runner verification, server and workspace tests, browser tests, and the canary release dry run. Greptile reviewed the same commit at 5/5 with no unresolved review threads. GitHub reports no merge conflicts. The remaining merge gate is code-owner approval for the new `package.json`, as required by `.github/CODEOWNERS` and the `master` ruleset. Reviewers have been requested automatically. Local checks passed: - Provider: `pnpm typecheck`, `pnpm test` (52 passed, one live smoke skipped), and `pnpm build`. - Host: focused credential and bundled-plugin tests (17 passed), plus CLI invocation safety (39 passed). - Release: package manifest check and release policy tests (18 passed). The full local `pnpm test:run` attempt caught the README command issue; its focused rerun now passes. The full local run stopped after its general-server group: 7,804 tests passed, with unrelated embedded PostgreSQL startup failures and 10 failures in unchanged runtime-skill-cache tests (`EACCES` on directory rename on macOS). It did not reach the later test groups. Local `pnpm -r typecheck` and `pnpm build` reach the runner package and stop because this machine has no Rust/Cargo installation. The corresponding CI checks passed on provisioned runners, as linked above. The live CreateOS smoke requires explicit provider credentials and was not run during this review. It is available with `CREATEOS_LIVE_TEST=1 pnpm test` in the provider directory. The author supplied the demo links above. ## Risks The provider is opt-in and is not installed by default. It is available through a local-path install or explicit image inclusion. npm publication remains disabled until a maintainer bootstraps the package and enables publishing. Sandbox creation has no idempotency key. An ambiguous create response can leave a resource that requires provider-account inspection. Process tracking is in memory; durable lease recovery belongs to the host. The provider does not advertise guaranteed expiry, interactive login, snapshots, duplex channels, or ingress. Live native-runner qualification remains outside this PR's tested claims. ## Model Used Original provider implementation: human-authored by @bhautikchudasama, as reported in #13203. The original description reports Claude Opus 5 assistance. Review and follow-up fixes: OpenAI GPT-6 via Codex, with code review, editing, and tool execution. The precise runtime model 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 (focused checks; full-suite environment limits 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: bhautikchudasama <bhautikrchudasama@gmail.com> Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
bfb4ceabbb |
perf(release): wait for npm registry visibility of all packages concurrently (#13495)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release system publishes ~33 public npm packages per release across the canary, nightly, beta, and stable channels > - `scripts/release.sh` publishes them strictly sequentially: publish one package, poll npm until that version is registry-visible, then start the next > - npm accepts a publish in seconds, but registry packument propagation can lag minutes per package (the CI budget was raised to 30 minutes per package after two aborted releases), so the total publish time is the sum of every package's lag — about two hours on a bad npm day, paid by every channel run including every canary on every master push > - This pull request keeps the publishes sequential but runs all the registry visibility polls concurrently once every publish is accepted > - The benefit is that the wall-clock cost of npm propagation drops from the sum of all packages' lag to the single slowest package's lag, with every existing safety property preserved ## Linked Issues or Issue Description No existing issue. Description follows the enhancement template: **What existing behavior does this improve?** The npm publish step of `scripts/release.sh` (Step 5), used by every release channel. **Subsystem affected** Release tooling (`scripts/release.sh`, `scripts/release-lib.sh`). **Current behavior** Packages publish one at a time, and after each publish the script polls npm until that package's version is visible in the registry packument before publishing the next. With per-package propagation lag of minutes (observed up to ~15 minutes; per-package CI budget is 30 minutes), the full 33-package set takes up to ~2 hours of mostly idle waiting. **Proposed behavior** Phase 1 publishes every package sequentially exactly as today (a rejected publish still aborts the batch immediately with exact attribution). Phase 2 then polls registry visibility for all packages concurrently. Each package keeps its own `NPM_PUBLISH_VERIFY_ATTEMPTS` × `NPM_PUBLISH_VERIFY_DELAY_SECONDS` budget, and any version that never becomes visible still hard-fails the release, now naming every straggler. **Reason and benefit** Total publish wait becomes the slowest single package's lag instead of the sum of all lags — typically minutes instead of hours. This shortens every canary, nightly, beta, and stable run and reduces exposure to job timeouts during npm slowdowns. **Breaking changes** None. Dry-run output is byte-identical in structure, dist-tags are still applied at publish time (`--tag`), the Sigstore TLOG duplicate-recovery path is untouched, and the later dist-tag integrity check (`wait_for_release_registry_state`) is unchanged. ## What Changed - `scripts/release-lib.sh`: replaced `publish_package_to_npm_and_wait` with `wait_for_npm_package_versions`, which takes the package tuple list and polls every package's visibility in background subshells, each reusing the existing `wait_for_npm_package_version` poll (same per-package budget), then reports per-package success or fails naming all stragglers - `scripts/release.sh` Step 5: the publish loop calls `publish_package_to_npm` only (sequential, fail-fast on a rejected publish), followed by one call to `wait_for_npm_package_versions` for the whole set; Step 6's recap line updated to match - `scripts/release-lib.test.mjs`: the registry-visibility and workflow-budget tests now drive the new function (same assertions on `npm view` counts, virtual sleeps, and the fail-closed message, which now names the straggler); a new cross-visibility test proves concurrency — two fake packages that each become visible only after the other has been polled can only converge when polled in parallel, so the test fails if the waits ever serialize again Safety analysis for the ordering change: nothing in the publish loop resolves sibling packages from the registry. `prepare-bundled-package.mjs` bundles and patches from the local workspace tree, and the TLOG duplicate-recovery path only queries the package it just published. The only consumer of the "visible before next publish" invariant was the release script's own final verification, which still runs against the full set. ## Verification - `node --test scripts/release-lib.test.mjs` — 15 tests pass, including the new concurrency proof and the existing 15-minute-20-second budget tolerance test against the new function - `npm run test:release-registry` — full lane, 140 tests pass - `bash -n` on both scripts; `shellcheck` reports no findings beyond the three pre-existing ones on master (verified by comparing counts against `origin/master` copies) - A real-release exercise happens on the next master push: every canary run executes this exact path ## Risks - Low. The failure mode most worth watching is a release where some packages become visible and others never do: previously the run stopped at the first invisible package with later packages unpublished; now all packages are accepted before visibility is enforced, and the run fails naming every straggler. Recovery is identical in both worlds (the next attempt derives a new version number), and the accepted-but-lagging packages carry the correct dist-tag either way. - Publish jobs run the source commit's copy of `release.sh`, so this change takes effect for a given channel only once its source commit includes this merge — promoted nightlies/betas cut from older commits keep the old sequential behavior until their trains catch up. ## Model Used Claude Fable 5 (`claude-fable-5`), extended thinking with tool use (Claude Code). ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [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 |
||
|
|
544c3476a8 |
feat(server): wrap a bare Cloud UI snippet body in a <script> element (#13496)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - A Cloud-managed instance injects an operator-owned HTML snippet before `</body>` through `injectCloudUiSnippet`. > - The Cloud control plane delivers that snippet to each instance as an environment variable through a provider API. > - The provider edge firewall now base64-decodes the request payload and blocks any value whose decoded form contains a `<script` marker. > - A working snippet needs a script tag, so every delivery is now blocked and the operator cannot ship the snippet at all. > - This pull request treats a resolved value that does not start with `<` as a bare script body and wraps it in a `<script>` element at injection time. > - The benefit is that the operator can deliver a tag-free body that the firewall passes, and the instance restores the script element on the page. ## Linked Issues or Issue Description No public issue exists. The problem is described below. Related PRs (searched the PR list; none duplicate this change): - Refs #13168 — added `injectCloudUiSnippet`, the mechanism this extends. - Refs #13245 — added the base64 `_B64` path on the assumption that base64 clears provider WAFs. That assumption no longer holds; this PR is the successor. - Refs #13441 — the in-product feedback approach that the Cloud-owned snippet replaced (closed). **What happened?** `injectCloudUiSnippet` injects `PAPERCLIP_CLOUD_UI_SNIPPET` (or the base64 `_B64` form) verbatim before `</body>`. A working value must therefore contain a `<script>` tag. The Cloud control plane delivers this value as an environment variable through a provider API that sits behind an edge firewall. The firewall now base64-decodes the payload and rejects any value whose decoded form contains `<script`. The delivery request fails, so the snippet cannot reach the instance. **Expected behavior** The operator can deliver the snippet through the provider API, and the instance runs it. **Steps to reproduce** 1. Build a snippet that contains a `<script>` element. 2. Deliver it to a Cloud instance through the provider variable API, in plain or base64 form. 3. The firewall rejects the request. The instance never receives the snippet. ## What Changed - `injectCloudUiSnippet` now wraps a resolved value that does not start with `<` in a `<script>...</script>` element. A value that already looks like markup is injected byte-for-byte, so existing full-`<script>` snippets are unchanged. - Added two unit tests: one for the wrap path (plain and base64), one that confirms `$&`-style replacement tokens in the body survive the wrap. ## Verification - `pnpm exec vitest run src/__tests__/cloud-ui-snippet.test.ts` — 17 pass. - `pnpm exec vitest run src/__tests__/static-index-html.test.ts` — 2 pass. - Confirmed the changed file has no type errors. The full `pnpm run typecheck` needs the Rust runner toolchain (`cargo`), which is absent on this machine; CI runs it in full. - Verified out of band that a tag-free body clears the provider firewall and wraps into valid, executable standalone JavaScript with no premature `</script>` close. ## Risks Low risk. The change adds a branch that only affects values that do not start with `<` — previously injected as inert text, never as a running script. Values that start with `<` keep their exact bytes. The content is trusted operator HTML, consistent with the existing contract. Roll back by reverting this commit. ## Model Used Claude — `claude-fable-5` (Fable 5), extended thinking, with tool use and code execution in Claude Code. A human author reviewed and verified the change before submission. ## 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 - [ ] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing> |
||
|
|
081006bee4 |
docs(release): curate stable notes for v2026.915.0 (#13487)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release system publishes canary, nightly, beta, and stable channels; a stable promotion publishes its release notes as the GitHub Release body > - At beta publish time the workflow auto-drafts a raw commit-log skeleton on this branch (`releases/beta/v2026.915.0-beta.0.md`) for humans to edit > - The skeleton is a 1,800-line commit dump; stable `v2026.915.0` cannot ship user-facing notes in that form > - This pull request replaces the skeleton with the curated changelog for the `v2026.915.0` promotion: overview, breaking changes, highlights, fixes, upgrade guide, and contributor credits for the 483-commit range since `v2026.831.1` > - The benefit is that the stable promotion reads finished, accurate notes from master and publishes them as the release body ## Linked Issues or Issue Description Refs #13403, #13247, #13248, #13268, #13256, #13038, #13299 — the headline features this changelog describes. The notes-drafting flow itself (skeleton branch at beta publish, stable promotion reading the file from master, post-ship canonicalization) is the standing release process; this PR is the curation step it expects. ## What Changed - Replaced the auto-drafted skeleton in `releases/beta/v2026.915.0-beta.0.md` with the curated release notes for stable `v2026.915.0` (promoted from beta `2026.915.0-beta.0`, source `667c79ded`) - Sections: overview, Breaking Changes (5), Highlights (Connections train leads), Improvements, Fixes, Upgrade Guide (migrations `0231`–`0279`, new env vars, removed API surface), Contributors ## Verification - Every PR link and claim was checked against the actual commit range `dbf052577..667c79ded` (the same range the skeleton header names) - Migration list enumerated from `git log --diff-filter=A` over that range; only `0231` and `0236` discard data, called out as such - New environment variables verified in code (`server/src/config.ts`): announcement flags (default on), split Sentry DSNs with legacy fallback, token-broker allowed hosts, cwd `.env` opt-out - Contributor list built from commit authors plus co-author trailers; core maintainers excluded per release-notes convention - Docs-only change: no code paths, no tests to add ## Risks - Low risk: documentation only. The stable promotion reads this file from master at dispatch time; if wording needs a follow-up after merge, the promotion pins the master revision it resolved, so edits must land before the stable dispatch - The file is renamed to `releases/v2026.915.0.md` by the post-ship canonicalization step, as with previous promotions ## Model Used Claude Fable 5 (`claude-fable-5`), extended thinking with tool use (Claude Code). The commit-range analysis and draft were produced by a subagent on the same model and human-review-style checked against the range before commit. ## 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: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
4cc387f907 |
fix(ci): remove npm propagation from cloud readiness (#13456)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Cloud needs a verified image and matching database
migrator before it can deploy a merge.
> - New npm package versions can take minutes to become downloadable
after the package build finishes.
> - The direct producer now publishes signed archives and a complete
dependency lockfile for each master commit.
> - This pull request makes readiness verify those artifacts and removes
the duplicate automatic npm migrator run.
> - Deployment still requires all source checks, exact image identity,
migration compatibility, and pinned dependencies.
## Linked Issues or Issue Description
Refs: #13455, #13454, #13192
**What existing behavior does this improve?**
The time from a master merge to the `Cloud deployable v1` signal.
**Current behavior**
Readiness polls npm metadata for the new DB and shared versions. An
automatic dispatcher also starts a separate npm-only migrator workflow.
A measured source built its packages at 06:22:41 UTC on 2026-09-15, but
both npm archives were not downloadable until 06:31:56 UTC.
**Proposed behavior**
Wait for the successful exact-source direct producer, verify its signed
manifest and all pinned downloads, and publish readiness only after the
existing source and image jobs pass. Keep manual npm migrators and
branch previews available.
**Reason and benefit**
Remove new-version npm propagation from merge-to-deployable time. The
gain depends on whether image building or source verification finishes
later; it is not a fixed subtraction from every run.
## What Changed
- Require a successful producer from the canonical repository, exact
commit, master ref, expected workflow, and approved event.
- Verify the manifest's GitHub attestation with the hosted GitHub CLI.
Enforce the exact source SHA, master workflow identity, and hosted
runner.
- Download and validate both archives and the complete dependency
lockfile after publication succeeds. Reject invalid signatures,
inaccessible objects, corrupt bytes, and source mismatches.
- Remove automatic npm-only migrator dispatch. Retain manual release and
branch-preview publication.
- Document the cloud feature-switch prerequisite and coordinated
rollback.
## Verification
- `node --test .github/scripts/tests/*.test.mjs`: 405 pass.
- Focused readiness, routing, preview, and artifact tests: 249 pass.
- Workflow lint and `git diff --check`: pass.
- `pnpm test:release-registry`: 139 pass after installing this
worktree's dependencies.
- All latest-head GitHub CI checks passed. Greptile is 5/5 with no
unresolved comments.
- Application source is unchanged. Common-source local typecheck and
build passed. The full local application suite has the documented macOS
read-only-directory rename limitation from #13454 (13 failures in two
unchanged suites); Linux CI is the final application gate.
- Live readiness verification of master
|
||
|
|
da77a0c28c |
feat(ci): publish immutable cloud migrator artifacts (#13455)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Cloud deploys images and a matching database migrator.
> - New migrator versions must currently become available on npm before
cloud can use them.
> - npm can serve package metadata while the named archive still returns
404.
> - This pull request publishes immutable migrator archives and a
complete dependency lockfile through the existing artifact store.
> - Cloud can install these exact packages without waiting for their new
npm versions.
> - This producer change prepares a separate cloud consumer and
readiness cutover.
## Linked Issues or Issue Description
Refs: #13454
**What happened?**
A recent master run built both packages by 06:22:41 UTC on 2026-09-15.
Both archives became downloadable from npm at 06:31:56 UTC. Fresh
metadata requests did not remove the delay.
**What did you expect to happen?**
Cloud should be able to install the verified migrator as soon as its
package build and artifact upload finish.
**Steps to reproduce**
Compare package build completion, npm publication, version metadata
availability, and tarball download availability for a fresh full commit
SHA.
**Version**
Master commit `08adcc70d5ec45b7ced9619a3dc10c1d1bec397d`.
## What Changed
- Add a master-only workflow that builds the DB and shared archives
without publication credentials.
- Resolve the dependency lockfile from local archives, then pin those
archives to content-addressed URLs.
- Publish the complete bundle to a separate prefix in the existing
S3/CloudFront artifact store. Write the commit manifest last and verify
public downloads.
- Add a dedicated OIDC role policy. Only canonical master can assume it.
Writes require `If-None-Match: *`; the role cannot overwrite or delete
objects.
- Add source, integrity, lockfile, publication, and real npm install
tests. Document the format and staged rollout.
- Attest the validated manifest with GitHub/Sigstore before S3
publication. The signature binds every package and lockfile hash to the
exact master workflow and source commit.
## Verification
- `node --test scripts/cloud-migrator-artifacts.test.mjs`: 7 tests pass,
including real `npm ci` with an empty cache and no new-version metadata
lookup.
- `pnpm test:release-registry`: 136 tests pass.
- `actionlint .github/workflows/cloud-migrator-artifacts.yml` and `git
diff --check`: pass.
- Ran the workflow's filtered install and package build against the
exact master source. Built and validated the dependency lockfile from
those real archives.
- Latest-head application tests passed, including reruns of two failures
in unchanged application tests. The final CI aggregate passed. The
application source is unchanged. Common-source local typecheck and build
passed; the full local suite has the same documented macOS
read-only-directory rename limitation as #13454 (13 failures in two
unchanged suites).
- The dedicated role and additive bucket read permission are configured.
IAM simulation allows only conditional writes in the intended prefix;
overwrite without the condition, other prefixes, and deletion are
denied.
- Published the verified master
|
||
|
|
058c55bf8f |
fix(ci): overlap preview migrator publication waits (#13454)
## Thinking Path
> - Paperclip manages AI agents and their work.
> - Cloud deploys an application image with a migrator from the same
source commit.
> - The migrator consists of the DB package and its matching shared
package.
> - npm can accept a package several minutes before readers can see it.
> - The publisher waits for shared visibility before it submits the DB
package.
> - This change submits both validated packages before polling their
visibility.
> - Their availability delays can then overlap while the final gate
still requires both packages.
## Linked Issues or Issue Description
Related: #13334. No duplicate open migrator-publication fix was found.
**What happened?**
The cloud migrator publisher waits up to ten minutes for the shared
package before submitting the DB package. The two registry delays
therefore accumulate. A shared visibility timeout can prevent the DB
package from being submitted at all.
**Expected behavior**
Submit both valid packages, then wait for both to pass the existing
exact-source metadata checks. Report which package remains unavailable.
**Steps to reproduce**
Return 404 for shared metadata after npm accepts the shared archive.
Observe that the old publisher never submits the DB archive until shared
becomes visible. The new regression test requires both submissions
before the first visibility sleep.
**Paperclip version**
Base commit
|
||
|
|
08adcc70d5 |
fix(ci): retry transient GitHub reads while waiting for source verification (#13429)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - Every commit on master is published as an npm canary, and a canary
is the only thing a nightly, a beta and then a stable can be promoted
from
> - A canary only publishes after the release run confirms that Cloud
readiness passed for that exact commit, which it does by polling the
GitHub Actions API for up to 45 minutes
> - That poll used a read that threw on any non-OK response, so one
gateway error ended the wait immediately
> - The release run then failed and the commit published no canary,
although readiness itself had passed
> - A commit with no canary can never be promoted, so this silently
removes commits from the release path
> - This pull request retries the reads that mean "ask again" and leaves
every real failure fast
> - The benefit is that a transient API error costs a few seconds
instead of a release
## Linked Issues or Issue Description
No existing issue. The problem, in the bug report format:
**What happened**
The `Reuse exact-source verification` job failed 12 seconds into a
45-minute wait:
```
Waiting for Cloud source verified v1 for
|
||
|
|
667c79ded2 |
fix: prevent retry-exhaustion events from exhausting attention-feed memory (#13451)
## Thinking Path > - Paperclip manages AI agents and their work. > - Its attention feed shows failed runs whose retry budget is exhausted. > - Startup retention builds this feed before startup completes. > - The feed joins every exhaustion event to the full run context, then removes duplicate runs in JavaScript. > - Recovery can revisit an exhausted run and append the same event again. This multiplies the data loaded into memory. > - This pull request selects one small row per run in PostgreSQL and makes exhaustion writes idempotent. > - Existing duplicate events can stay in the database without multiplying run contexts in server memory. ## Linked Issues or Issue Description Refs #13367. This fixes the repeated-event allocation path in the retention feed. Other full-feed sources and sweep cadence remain separate concerns. **What happened?** The attention query loaded one full run context for every matching exhaustion event. Deduplication ran only after the driver had loaded those rows. A run with thousands of exhaustion events therefore produced thousands of context copies. The startup retention sweep can exhaust the server heap while reading this result. **Expected behavior** The query should return one row per exhausted run and only the context fields that the feed needs. Repeated checks of the same exhausted retry budget should reuse the original event. **Steps to reproduce** 1. Create a failed run with a 32 KB context and 2,500 matching exhaustion events. 2. Build the attention feed, including dismissed items, as startup retention does. 3. Inspect the database result before JavaScript feed processing. The old join returns 2,500 copies of the run context. 4. Call bounded retry scheduling repeatedly for a run at its retry limit. The old writer appends another exhaustion event on every call. **Paperclip version or commit** The attention query was introduced by #9380 and is present in stable `v2026.831.1`. The retention caller is also present in that stable release. The later recovery callback added by #13075 provides a repeated path into the exhausted-budget writer. This change is based on `c0fda8fac` after rebasing onto current master. Related PR: [#12162](https://github.com/paperclipai/paperclip/pull/12162) changes retention cadence and newer-run suppression queries. This change addresses the exhaustion-event join and duplicate event writes. ## What Changed - Select the newest company-scoped exhaustion event per run with a PostgreSQL `DISTINCT ON` subquery before joining run data. - Project only `issueId` and `taskId` from run context. Preserve JSON types, fallback behavior, run ordering, company filters, and run/agent status filters. - Reuse an exhaustion event for the same run, reason, attempt, and retry limit under the existing run-row lock. Recognize historical events without a migration. - Skip sequence allocation and live publication when a receipt already exists. - Document the run-log behavior and add PostgreSQL regression tests. ## Verification - Focused attention, retry-scheduling, and event-sequencing suites: 72 tests pass on the rebased head `39ce77158`. - The large-history fixture verifies two database result rows under 4 KB, newest-message selection, task-ID fallback, and company/status filtering. This assertion runs before feed deduplication. - Concurrent event tests verify one receipt across two database clients, reuse of historical receipts, distinct reason/attempt/budget keys, and stable event sequences. - Repeated scheduling through a new service instance produces no extra run-log or live events. - `pnpm --filter @paperclipai/server exec tsc --noEmit`: passes. - `pnpm -r typecheck` and `pnpm build`: pass on the rebased head, including native runner checks. - Greptile: 5/5 on `39ce77158`, with no review threads. - [GitHub CI](https://github.com/paperclipai/paperclip/actions/runs/34929002304): all 25 workflow jobs pass, including all server/workspace test shards, serialized server suites, browser tests, typecheck, build, native-runner verification, and the release dry run. Security checks also pass. The branch has no merge conflicts. - `pnpm test:run`: stopped with unrelated failures. Two chat integration cases passed when rerun separately (2 passed, 993 unselected). Three skill-cache cases failed on both this branch and the unmodified parent commit, with `EACCES` during directory rename. The full suite is not reported as green. ## Risks - No schema migration or data cleanup is required. The query still scans matching event history in PostgreSQL; its result size now scales with exhausted runs. - This does not bound every source in the attention feed or change retention scheduling. - An exhaustion receipt is emitted once per retry decision. Consumers that observed repeated copies will now receive one event. - Native source-event replay handling stays on its existing path. - A deployed application boot has not been verified. ## Model Used OpenAI GPT-6, used through Codex with reasoning, repository inspection, code editing, and test execution. 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 the focused tests locally and they pass (full-suite limitations are 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> |
||
|
|
c0fda8fac5 |
fix(apps): restore action test picker scrolling and agent eligibility (#13414)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Apps action tests let operators use an agent's permissions. > - The agent picker must scroll inside the test dialog. > - Its body portal sits outside the dialog's scroll boundary and blocks wheel input. > - Admin permission bypasses also skip agent lifecycle checks. > - This PR fixes scrolling and rejects agents that cannot receive assignments. ## Linked Issues or Issue Description **What happened?** The Act as picker does not scroll with the mouse wheel inside an action test dialog. Admins can also see terminated agents. **Expected behavior** The list scrolls normally. Terminated and pending-approval agents are absent. Direct requests cannot test an action as one of those agents. **Steps to reproduce** 1. Create enough agents to overflow the list. Terminate one agent. 2. Open a connected app's Permissions tab. Click Test on an action. 3. Open Act as and use the mouse wheel over the list. 4. Check whether the terminated agent appears as an admin. **Paperclip version or commit** Reproduced on master at |
||
|
|
52d120f68d |
fix(release): wait 30 minutes for npm to expose a published version (#13436)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every release publishes a batch of npm packages and then waits for each one to become visible before continuing > - npm accepts a publish immediately but exposes it later, so that wait exists to keep a release from continuing past a package nobody can install yet > - Today that wait was too short twice in a row, and each timeout aborted the release with the batch half-published > - Version numbers are derived from what is already on npm, so every retry moves to a new number and meets the same lag > - Two canary attempts burned two versions this way and shipped nothing > - This pull request raises the per-package budget from ten minutes to thirty > - The benefit is that ordinary registry lag costs waiting instead of a failed, half-published release ## Linked Issues or Issue Description No existing issue. The problem, in the bug report format: **What happened** `publish_canary` failed twice in a row with the batch half-published: ``` Warning: npm accepted @paperclipai/server@2026.914.0-canary.2, but the version did not become registry-visible. Error: stopping release: npm did not publish and expose @paperclipai/server@2026.914.0-canary.2 ``` The version was accepted at 17:49:09 and became visible at 18:04:29 — about five minutes after the poll gave up. `shared`, `db` and `adapter-utils` published at that version; `server`, `paperclip-runner` and the root package did not. **Expected behavior** Ordinary registry propagation delay costs the release some waiting, not a failure. A package that becomes visible after 15 minutes must not abort the batch because of the old 10-minute wait. Longer registry outages can still leave a partial batch. **Steps to reproduce** 1. Publish any channel while npm is propagating slowly. 2. A package takes longer than `NPM_PUBLISH_VERIFY_ATTEMPTS * NPM_PUBLISH_VERIFY_DELAY_SECONDS` to become visible. 3. The release aborts, that version is half-published, and the retry picks a new version number and meets the same lag. **Paperclip version or commit** Present on master. Observed on 2026-09-14 across canary runs in workflow run 34869494325. ## What Changed - Increase npm visibility checks from 60 to 180, retaining the 10-second delay: about 30 minutes per package. - Increase canary, nightly, beta, and stable publish job timeouts from 90 to 150 minutes. - Add offline regression tests using the workflow's actual settings. They cover the observed 15-minute 20-second delay, immediate visibility, exhausted retries, and job timeout sizing. - Load the access router in test setup so its cold transform does not consume the first permission test's 10-second timeout. The permission assertions are unchanged. ## Verification - `node --test scripts/release-lib.test.mjs`: 14 passed. - `pnpm run test:release-registry`: 129 passed. - `pnpm exec vitest run server/src/__tests__/access-routes-permissions-upgrade.test.ts`: 3 passed. - Regression proof in temporary fixtures: restoring 60 attempts fails the observed-delay test; restoring 90-minute jobs fails the timeout-budget test. - [CI run 34916632804](https://github.com/paperclipai/paperclip/actions/runs/34916632804): all jobs passed, including typecheck/release registry, build, all general and serialized server shards, browser tests, runner verification, and canary dry run. The PR has 31 successful checks and two expected Storybook skips at `a27f5e896`. - [Previously failing serialized shard](https://github.com/paperclipai/paperclip/actions/runs/34916632804/job/104215809616): all three access-route permission tests passed in CI after preloading the router. - Greptile's final review is 5/5 with no outstanding findings. Both review threads are resolved. - Local limits: `pnpm -r typecheck` and `pnpm build` stop at the runner package because this machine has no Rust `cargo` executable. The duplicate full local `pnpm test:run` was interrupted while the complete CI matrix ran. Targeted local results are listed above; full validation is from CI. The previous CI failures were unrelated to npm propagation: - [PR review](https://github.com/paperclipai/paperclip/actions/runs/34891770396) required a test file for this fix. - [Serialized server shard 3](https://github.com/paperclipai/paperclip/actions/runs/34891773736/job/104136392196) timed out in the first access-route permission test at 10 seconds. The other two tests in that file passed. - The canary dry run passed in that same CI run. ## Risks Low risk. Production behavior changes only in release waiting budgets. - Polling exits as soon as npm exposes the version, so healthy publishes do not wait longer. - An unavailable version now takes about 30 minutes to report. Polls remain bounded and still fail the release on exhaustion. - The 150-minute jobs leave roughly 30 minutes for setup/build plus four full polling windows. npm command runtime and later release steps also consume that budget; a broader outage can still interrupt a batch. - The permission-test change moves module loading into a bounded setup hook; it does not relax authorization assertions. - No schema changes or operational migrations. ## Model Used - Claude Fable 5 (`claude-fable-5`), 1M context, extended thinking, run through Claude Code with tool use and code execution. - OpenAI GPT-6 (Codex), with reasoning, tool use, and code execution, for the CI follow-up. Context-window size is not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass — targeted checks listed above; full validation passed in CI - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes — workflow comments and verification details - [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> |
||
|
|
5054c9ef9b |
fix(grok): stage the environment test from a host directory, and survive an absent workspace (#13416)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - An agent runs through an adapter. Before you use an environment, the
adapter's environment test probes it and reports structured checks
> - The grok adapter's environment test stages the managed account into
a remote environment first. It gave the runtime its resolved `cwd` as
the host workspace directory
> - For a remote target that `cwd` is a path inside the sandbox. It does
not exist on the host that runs the test
> - A new workspace ignore scan reads that host directory. The scan
failed on the missing directory, and the error escaped the environment
test
> - The user got a server error instead of a result with checks
> - This pull request stages from a host temporary directory, sends the
remote path separately, and reports a staging failure as a check
> - The benefit is that the grok environment test always answers with
checks, and a workspace directory that does not exist no longer stops a
runtime preparation
## Linked Issues or Issue Description
No existing issue. The problem, in the bug report format:
**What happened**
The grok environment test failed with `Error: Workspace ignore scan
failed: git-ignore-scan-failed`. The route returned a server error, so
the user saw no checks at all.
**Expected behavior**
The environment test always returns `{status, checks}`. Every other
problem it finds (an invalid working directory, a command it cannot
resolve, a probe that times out) becomes a check with a level. A
credential staging problem must do the same.
**Steps to reproduce**
1. Configure a grok agent with a managed AI connection.
2. Point the agent at a remote (sandbox) environment.
3. Run the environment test for that environment.
**Paperclip version or commit**
Present on master. Both halves landed on 2026-09-12: the call site in
#13247, and the scan that it trips in #13353.
## What Changed
- `packages/adapters/grok-local/src/server/test.ts` stages the managed
account through a fresh host temporary directory and passes the remote
path as `workspaceRemoteDir`. This is the split `codex-local` and
`opencode-local` already use.
- A failure while staging becomes a `grok_environment_unprepared` check
with level `error`, instead of an exception that escapes the function.
The probe does not run after it, because there is no prepared
environment to probe.
- The temporary directory is removed in the existing `finally` block.
- `packages/adapter-utils/src/sandbox-managed-runtime.ts` treats a
`workspaceLocalDir` that does not exist as "nothing to sync". A
directory that is not there has no files for ignore rules to govern,
nothing to stage, and nothing to restore.
- Tests: the grok environment test now covers the managed-connection
remote branch, which had no coverage. `sandbox-file-sync.test.ts` covers
a preparation whose workspace directory does not exist.
## Verification
```
npx vitest run packages/adapters/grok-local/src/server/test.test.ts # 9 passed
npx vitest run packages/adapter-utils/src/sandbox-file-sync.test.ts \
packages/adapter-utils/src/sandbox-managed-runtime.test.ts # 90 passed
cd packages/adapter-utils && npx tsc --noEmit # clean
cd packages/adapters/grok-local && npx tsc --noEmit # clean
```
The two new grok tests fail against the old call site: the first asserts
the runtime never receives the remote path as its host workspace
directory, and the second asserts a staging failure becomes a check
instead of an exception.
## Risks
Low risk, and limited to environment preparation.
- The adapter change only affects the managed-connection remote branch
of one adapter's environment test.
- The `adapter-utils` change makes a preparation that used to throw now
continue with no workspace sync. A real workspace is unaffected, because
the directory exists in that case and the scan runs exactly as before.
- No migration. No API change.
## Model Used
- Claude Fable 5 (`claude-fable-5`), 1M context, extended thinking, run
through Claude Code with tool use and code execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes — no
documented behavior changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green — pending first run
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
pending first review
- [x] I will address all Greptile and reviewer comments before
requesting merge
|
||
|
|
46bcc0863c |
test(runner): stop two CI-contention flakes that starve the canary lane (#13418)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Each master commit is published as an npm canary, and the nightly release gate installs the newest canary and runs the onboarding smoke against it > - A canary only publishes after the Cloud readiness workflow passes for that exact commit > - Cloud readiness fails often, and almost every failure stops that commit from ever becoming a canary > - The nightly gate then keeps testing an old canary, so a fix that landed after it cannot reach the gate, and the gate stays red for reasons no longer in the code > - Most of these failures are short timeouts that only expire because the runner is loaded > - This pull request gives two such timeouts the budget the surrounding tests already use > - The benefit is that more master commits publish a canary, so the nightly gate tests current code ## Linked Issues or Issue Description No existing issue. The problem, in the bug report format: **What happened** Cloud readiness failed on 25 of 85 runs over three days (29%). 24 of those failures stopped the commit from publishing a canary. Two timeout clusters account for 10 of the 25: - `packages/paperclip-runner/src/control-plane/durable-prp-control-plane.test.ts` — `Error: Test timed out in 5000ms.` in "promptly fails the real transport request and notification paths on authenticated bad semantic input". Seen in runs 34652752663, 34654215468, 34656885170, 34657111560, 34661910120. - `packages/paperclip-runner/src/live/live-session.test.ts` — `Turn settled before the intentional SIGKILL: Error: Capability Codex turn timed out after 2000ms`. Seen in runs 34632264036, 34658026290, 34658106386, 34727991195, 34760283177. **Expected behavior** A commit that is good publishes its canary. A test fails because the behavior is wrong, not because the runner was busy. **Steps to reproduce** 1. Run the Cloud readiness workflow on master repeatedly. 2. Watch the Runner protocol and chaos jobs. 3. The two tests above fail intermittently, and the commit then publishes no canary. **Paperclip version or commit** Present on master. Measured over runs from 2026-09-11 to 2026-09-14, which is the workflow's whole history. ## What Changed - `durable-prp-control-plane.test.ts`: the "promptly fails the real transport request..." `it.each` now takes the same 15s budget as the test directly above it. It ran on the 5s default, although it builds a real control plane over a socket. The neighbouring test already asks for 15s, so this reads as an omission. - `live-session.test.ts`: the real-runner SIGKILL test gives the turn a 60s timeout instead of 2s. The test kills the runner process and then asserts the turn was still running at that moment, so the timeout is only a backstop. At 2s a loaded machine settles the turn first and the assertion fails. Neither change weakens an assertion. No test in this PR asserts that a timeout happens, and the tests that do assert one (`turnTimeoutMs: 500` and `turnTimeoutMs: 20`) are untouched. ## Verification ``` cd packages/paperclip-runner npx vitest run src/control-plane/durable-prp-control-plane.test.ts # 87 passed npx vitest run src/control-plane/durable-prp-control-plane.test.ts \ -t "promptly fails the real transport" # 2 passed (both it.each cases) ``` The live-session change is verified by the readiness lane itself, because that suite needs a real runner and a provider. ## Risks Low risk, and limited to test budgets. - A genuine hang in either test now takes longer to report: 15s instead of 5s, and 60s instead of 2s. - A real regression still fails, because the assertions are unchanged. - Timeouts are not a complete fix for this lane. Port races (`EADDRINUSE`), lease races, and lost runner VMs cause about another 40% of its failures. A retry on the `verify` matrix would cover all of those classes, and none of them reproduce on a second attempt. That is a larger policy change, so it is not in this PR. ## Model Used - Claude Fable 5 (`claude-fable-5`), 1M context, extended thinking, run through Claude Code with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] I have updated relevant documentation to reflect my changes — no documented behavior changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green — pending first run - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups — pending first review - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
e1d2e279a3 |
fix(db): replay a query whose socket write failed on a recycled pooled connection (#13417)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - A hosted instance keeps its data in Postgres, and it reaches that
database through a connection pooler
> - A pooler recycles the server side of a connection that sat idle. The
client still holds the socket and believes it is open
> - The next query fails while the driver writes it to that dead socket,
with `write CONNECTION_CLOSED host:5432`
> - The request that happened to draw the recycled connection fails,
although nothing is wrong with the query or the database
> - Only one code path guards against this today, so the same error
keeps reaching users and error reporting from every other path
> - This pull request replays a query when the write itself failed,
because those bytes never reached the server
> - The benefit is that a recycled connection costs one retry instead of
one failed request
## Linked Issues or Issue Description
No existing issue. The problem, in the bug report format:
**What happened**
Requests fail with `write CONNECTION_CLOSED <host>:5432` (driver code
`CONNECTION_CLOSED`). It is most visible on the first queries after an
idle period, when the pool holds connections the pooler already
recycled.
**Expected behavior**
A connection that the pooler recycled while it was idle is not a
user-visible failure. The client notices the dead socket and uses a live
connection.
**Steps to reproduce**
1. Run the server against a pooled Postgres endpoint (for example a Neon
`-pooler` host).
2. Leave the instance idle until the pooler recycles the server side of
the pooled connections.
3. Issue any request that queries the database.
**Paperclip version or commit**
Present on master.
## What Changed
- `packages/db/src/transient-write-retry.ts` (new) wraps the root
`postgres.js` client. When a query fails while the driver writes it to
the socket, the wrapper runs it again on a fresh connection. Three
attempts, 50 ms then 100 ms backoff.
- `packages/db/src/client.ts` gives Drizzle the wrapped client. The
teardown registry keeps the real client, because shutdown must end the
actual pool.
- The wrapper is deliberately narrow:
- It matches only the write phase (`code === "CONNECTION_CLOSED"` and a
message that starts with `write CONNECTION_CLOSED`). The write failed,
so the server never saw the query, and a replay cannot run anything
twice. That makes it safe for reads and writes alike.
- An error after the write propagates untouched, because the server may
have acted on the query.
- `CONNECTION_ENDED` and `CONNECTION_DESTROYED` propagate untouched,
because they mean a deliberate shutdown.
- Queries inside `db.transaction()` run on the scoped client that
`sql.begin()` returns, which the wrapper does not touch. A transaction
that loses its connection must abort, not replay.
- A query runs once however many handlers attach to it, and it still
executes lazily, like `postgres.js` itself.
## Verification
```
npx vitest run packages/db/src/transient-write-retry.test.ts # 7 passed
npx vitest run packages/db/src/client-teardown-registry.test.ts \
packages/db/src/client-options.test.ts # existing db suites pass
npx vitest run server/src/__tests__/cloud-tenant-transient-db-retry.test.ts # 6 passed
cd packages/db && npx tsc --noEmit # clean
```
New tests cover the replay, the `.values()` form Drizzle uses, the
attempt budget, an error that must not replay, and one execution per
pending query. A Drizzle round trip runs through a fake wire-protocol
server, which shows the wrapper is transparent to ordinary queries.
## Risks
Low risk.
- The retry only fires for a failure during the socket write, where the
server never received the query. A replay therefore cannot duplicate an
effect.
- A permanently unreachable database costs two extra attempts and 150 ms
before the same error surfaces.
- Transactions keep exactly their current behavior.
- Existing `retryOnTransientDbConnectionError` in the auth middleware
stays. It wraps a broader set of codes for one path, and it is
unaffected.
- No migration. No configuration change. No API change.
## Model Used
- Claude Fable 5 (`claude-fable-5`), 1M context, extended thinking, run
through Claude Code with tool use and code execution.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes — no
documented behavior or configuration changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green — pending first run
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
pending first review
- [x] I will address all Greptile and reviewer comments before
requesting merge
|
||
|
|
13368c5183 |
fix: unblock clean-machine onboarding for api_key AI connections (nightly smoke) (#13372)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The release pipeline gates each nightly on a Docker onboarding smoke. The smoke proves a clean machine can finish onboarding and hire the first agent. > - #13247, #13248, #13344, and #13351 changed the Connect step. Connect now creates an AI connection that the server verifies live with the provider. > - The managed adoption check also demanded a CLI hello probe. A clean machine has no provider CLI and cannot complete a subscription login. Onboarding dead-ends and the nightly gate fails. > - This pull request lets a live-verified API key adopt on the engine's own verdict, and re-verifies the key with the provider at adoption time. > - It also drives the release smoke through the API-key path against a provider mock that lives inside the test harness. > - The benefit is a green, deterministic release gate with no paid credential in CI, and a working first run for API-key users on clean installs. ## Linked Issues or Issue Description No public issue exists. The failure surfaced in the nightly release gate. Related PRs (no duplicates found): #13247, #13248, #13344, #13351 (the Connect changes), and #12423, #12135, #12151 (earlier release-smoke updates). **What happened?** The nightly Release cut failed its gate: [run 34749840498](https://github.com/paperclipai/paperclip/actions/runs/34749840498), job `smoke_nightly / smoke`, on published canary `2026.913.0-canary.2`. The wizard never left the "Connect a model" step. The subscription path waits for a human to run `claude auth login` on the server. The API-key path saves and live-validates the key, but the environment test then fails with `Command not found in PATH: "claude"` and `ai_connection_validation_incomplete`, and the wizard blocks the hire. **Expected behavior** A clean machine with a provider-accepted API key completes onboarding and hires the lead agent. The release smoke passes without a real paid credential in CI. **Steps to reproduce** 1. Run `scripts/docker-onboard-smoke.sh` with `PAPERCLIPAI_VERSION=2026.913.0-canary.2`. 2. Sign in, complete onboarding to "Connect a model", select "Use API key instead", pick Claude, enter a valid API key, and press Connect. 3. The environment test fails on the missing `claude` CLI and blocks the hire. **Paperclip version or commit** `2026.913.0-canary.2` (nightly candidate `c9e3bb7ca`). ## What Changed - `server/src/routes/agents.ts`: `testManagedEnvironment` no longer forces the CLI-lane hello probe for a resolved `api_key` binding. It re-verifies the key against the provider's live endpoint instead (the same `validateAiApiKey` check the save performed, which needs no CLI). A key the provider rejects fails adoption with `ai_connection_api_key_rejected`. Subscription adoption keeps the strict hello-probe requirement. - `scripts/docker-onboard-smoke.sh`: the harness now serves `api.anthropic.com` itself. A sibling container (the already-built smoke image) runs a small HTTPS mock. The app container gets `--add-host` for that one hostname and trusts the mock's certificate through `NODE_EXTRA_CA_CERTS`. The private key stays mode 600 in the mock container; the app container mounts only the certificate. The mock serves only `GET /v1/models` and returns 404 for every other path. `SMOKE_PROVIDER_MOCK=false` disables it. - `tests/release-smoke/docker-auth-onboarding.spec.ts`: the spec drives the API-key path — switch the credential mode before the source tile (the link hides when the row collapses), enter the key, and Connect. Loopback targets use a placeholder key that the mock accepts. Any other target must set `PAPERCLIP_RELEASE_SMOKE_ANTHROPIC_API_KEY`, and the test fails on arrival without it. - `server/src/__tests__/agent-test-environment-routes.test.ts`: three new route tests cover accepted keys (no CLI probe consulted), provider-rejected keys, and subscriptions that cannot complete a hello probe. ## Verification - `npx vitest run src/__tests__/agent-test-environment-routes.test.ts` — 26/26 pass. - `npx vitest run src/__tests__/ai-connections.test.ts src/__tests__/ai-legacy-compatibility.test.ts` — 42/42 pass. - `tsc --noEmit` reports no errors in the touched files. - Full local harness + suite run against the exact failing canary: the app container reaches the mock (request visible in the mock log), the placeholder key validates, and the connection saves as the default. The flow then stops at the forced CLI hello probe — the exact server check this PR removes, still present in the published canary. The next canary that includes this fix is the end-to-end proof. - Hardening check: from inside the app container, the mock answers with status 200 and `key.pem` is not visible. ## Risks - Behavior shift: `api_key` adoption no longer requires a CLI hello probe. It re-verifies the key with the provider at adoption instead. Subscription adoption is unchanged. - The mock returns 404 for unexpected provider calls, so a future onboarding change that calls a new endpoint fails the smoke loudly instead of passing silently. - Release-smoke runs against non-loopback targets now require an explicit key and fail fast without one. - No database migration. No dependency change. No provider routing change. ## Model Used Claude Fable 5 (`claude-fable-5`) through the Claude Code CLI, with extended thinking and tool use (shell, file edits, Playwright runs, GitHub CLI). No other models were used. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
6b45db0c35 |
fix(deps): force one @codemirror/state resolution via pnpm overrides (#13324)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The web UI embeds CodeMirror editors, and CodeMirror validates
extensions with `instanceof`
> - Different CodeMirror packages pin different transitive minors of
`@codemirror/state` (6.7.1 / 6.7.2) and `@codemirror/view` (6.43.9 /
6.43.11), so the bundle ships two module instances
> - The second instance makes valid extensions fail the `instanceof`
check and crashes the editor
> - This pull request adds a shared caret override to `pnpm.overrides`,
the same mechanism the existing `react` and `rollup` overrides use, so
every consumer resolves one copy of each package
> - The lockfile is not edited by hand; the lockfile automation
regenerates it from the manifests
> - The benefit is that the editor stops crashing with "Unrecognized
extension value in extension set"
## Linked Issues or Issue Description
**What happened?**
The production UI throws `Error: Unrecognized extension value in
extension set ([object Object]). This sometimes happens because multiple
instances of @codemirror/state are loaded, breaking instanceof checks.`
Observed 43 times in one week.
**Expected behavior**
The editor loads its extension set without errors. One instance of
`@codemirror/state` and `@codemirror/view` serves every CodeMirror
package.
**Steps to reproduce**
1. Run `grep "'@codemirror/state@" pnpm-lock.yaml` on master: two
versions resolve (6.7.1 and 6.7.2).
2. Build `ui/` and search the output for `Unrecognized extension value`,
a string unique to `@codemirror/state`: two chunks each carry a full
copy, one with a 6.7.1-only code pattern and one without it.
3. Open a view that composes extensions from packages on different
copies: the extension set rejects the foreign-instance extension.
**Paperclip version or commit**
master (
|
||
|
|
44f6312cd8 |
fix(ci): reuse one available Cloud registry cache (#13334)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud needs a verified image for each merged source commit. > - Fresh builders restore compiled native dependencies from registry caches. > - The current workflow imports up to eleven historical cache manifests at once. > - Live builds missed native layers that a fresh builder reused from one manifest. > - This PR selects the nearest available cache and tests reuse across fresh builders. ## Linked Issues or Issue Description Refs #13329 and #13330. A search of open cache PRs found no duplicate of this change. **What existing behavior does this improve?** Remote Docker cache reuse on fresh Cloud image builders. **Current behavior** [Cloud run 34714483272](https://github.com/paperclipai/paperclip/actions/runs/34714483272/job/103609096836) imported the previous cache manifest successfully but rebuilt `cargo-chef` and Rust dependencies. The dependency compile took 3m43s. The preceding image build had already exported those layers. A controlled [fresh-builder diagnostic](https://github.com/paperclipai/paperclip/actions/runs/34715336530) used the same source and registry cache. The single-manifest job reused both layers immediately. The multiple-manifest job rebuilt them and failed the cache assertion. Both jobs used GitHub-hosted runners with read-only access. **Proposed behavior** Inspect cache manifests in first-parent order and import only the nearest available one. Keep full-SHA cache exports, the ten-commit search bound, and the legacy fallback. If caches cannot be read, permit a cold build. **Reason and benefit** Avoid the observed cache misses without changing image contents or builder sizes. Expected savings include about four minutes of native tool/dependency compilation when those inputs are unchanged. The final merge-to-deployable gain still needs a post-merge measurement. **Breaking changes** No image, artifact, deployment, or runner-routing contract changes. ## What Changed - Select one available ancestor cache after Docker login and Buildx setup. - Preserve separate writable cache tags for each full source SHA. - Test cache ordering, missing caches, registry errors, and workflow integration. - Add the selector tests to the existing release-registry suite. - Export a local test cache, remove the first builder, and verify a source rebuild on a fresh builder. - Document cache selection and the stronger Docker check. ## Verification - Passed 456 focused workflow, routing, readiness, preview-artifact, and cache-selector tests. - Passed shell syntax, ShellCheck for the changed probe, actionlint workflow validation, and `git diff --check`. actionlint's shell checks were disabled for the workflow validation because unchanged migration-label commands trigger existing SC2012 notes. - The fresh-builder registry diagnostic proves the single-cache behavior. The [permanent two-builder probe passed](https://github.com/paperclipai/paperclip/actions/runs/34715771048/job/103612624090), including a changed real binary and dependency-declaration invalidation. - Passed all 35 latest-head checks (green or intentionally skipped), including full typecheck, test, build, and browser suites in [PR CI run 34715771217](https://github.com/paperclipai/paperclip/actions/runs/34715771217). - The real selector CLI inspected registry metadata and chose the nearest available ancestor cache. - Fresh Greptile review is 5/5 with no open findings. The PR title was corrected to meet the source-change naming rule; the review check passed after that correction. - Local full-suite runs and Docker builds are unavailable because the local Docker daemon is unresponsive after disk exhaustion. CI provides the Linux verification. ## Risks - Missing or unreadable caches cause a slower cold build. The selector logs that condition and preserves image publication. - Inspecting several missing ancestors adds lookup time. Each lookup has a ten-second timeout and the search is bounded. - The Docker test now exports a local cache. It removes the first builder before starting the second to release disk space, then cleans up its builders and files. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
0ce7df2648 |
ci: keep Cloud readiness markers out of the builder queue (#13330)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud consumes versioned readiness markers for each merged source commit. > - Those markers can be published only after the required checks and artifacts pass. > - The marker jobs currently wait for the same AWS runner capacity as builds and tests. > - A busy builder pool can delay readiness after all required work has finished. > - This PR moves the small readiness jobs to GitHub-hosted runners while retaining every dependency gate. ## Linked Issues or Issue Description Refs #13326 and #13328. **What existing behavior does this improve?** Time from completed Cloud verification to a deployable marker, and AWS capacity occupied by artifact polling. **Current behavior** In [Cloud readiness run 34711557083](https://github.com/paperclipai/paperclip/actions/runs/34711557083), all builds and tests finished at 18:43:05 UTC. The source marker did not start until 18:44:21, and the deployable marker did not start until 18:44:37. Merge-to-deployable was 11m33s, although the prerequisite work finished in 9m44s. **Proposed behavior** Run the artifact wait and both versioned marker jobs on `ubuntu-latest`. Keep the compute jobs on the approved post-merge AWS fleet. **Reason and benefit** Avoid builder-pool queue delays after verification finishes. This also removes the long artifact-wait job from AWS capacity. Expected savings depend on queue depth: the observed run had over 90 seconds of avoidable marker waiting. The marker commands themselves take only seconds. **Breaking changes** Runner placement changes for three bookkeeping jobs. Marker names, exact-source artifact checks, required verification, and image verification stay the same. **Additional context** Searched the related runner and Cloud readiness work. This addresses queue time observed after the parallel verification change. ## What Changed - Place the artifact wait, source-verification marker, and deployable marker on GitHub-hosted runners. - Keep all existing job dependencies, source guards, permissions, and commands. - Extend routing regressions to enforce this placement and retain fail-closed readiness gates. - Document why readiness bookkeeping uses separate runner capacity. ## Verification - Passed 433 workflow, routing, source-verification, and Cloud readiness tests with `node --test .github/scripts/tests/*.test.mjs scripts/cloud-source-verification.test.mjs scripts/cloud-readiness.test.mjs scripts/__tests__/release-verify-workflow.test.mjs`. - Passed `actionlint` and `git diff --check`. - Passed all latest-head CI gates in [run 34712624340, attempt 2](https://github.com/paperclipai/paperclip/actions/runs/34712624340), including typecheck, build, browser, Runner, and all general/serialized tests. - Attempt 1 had one localhost readiness timeout in an unchanged test. A single targeted retry passed all 166 files (3,225 tests passed, one existing skip), including all seven tests in that file. No timeout, assertion, or application source was changed; the retry is documented in the PR comment. - Local full-suite verification is limited by local disk exhaustion; the focused checks above pass. - Fresh Greptile review is 5/5 with no unresolved findings. ## Risks - GitHub-hosted capacity can also queue, but these jobs no longer compete with AWS build/test demand. The change does not reserve instances or change box sizes. - Readiness must still fail if any prerequisite fails. The existing `needs` relationships and success-only execution are preserved and tested. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
7435b2ee9c |
ci: cache compiled Docker Rust dependencies separately from source (#13329)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud deploys images that contain the native Rust Runner. > - The image already builds that Runner before copying ordinary app source. > - A Rust source change still invalidates its entire compiled dependency layer. > - Compiled dependencies can survive source changes when their recipe is unchanged. > - This PR adds a separate locked dependency build before compiling the real workspace. ## Linked Issues or Issue Description Refs #13195. A search of related Docker and Cargo cache PRs found no duplicate dependency-recipe change. **What existing behavior does this improve?** Docker image build time after Rust source or embedded protocol changes. **Current behavior** The `runner-build` stage compiles dependencies and workspace code in one layer. In Cloud readiness run 34698143548, that stage took about 3m48s when its cache was unavailable. **Proposed behavior** Generate a recipe with pinned cargo-chef 0.1.73. Build locked release dependencies in `runner-deps`, then copy and compile real Rust source and embedded protocol inputs in `runner-build`. Source edits can reuse the dependency layer from the existing registry cache. **Reason and benefit** Reduce dependency recompilation during source changes and merge bursts. Expected savings are roughly 2–4 minutes when the old native layer would miss but dependency layers are available. Full cold builds also pay for the recipe tool installation. Ordinary app-only cache hits gain little from this change. **Breaking changes** None to the shipped application or image tags. The recipe tool and compiled dependencies remain in build stages. ## What Changed - Install a pinned recipe generator with its locked dependencies and the existing package-owned compiler. - Add recipe planning and compiled dependency stages. Use the same release profile, package, binary, and lockfile enforcement as the real native build. - Remove generated source stubs before copying actual source. Preserve protocol inputs, timestamp normalization, binary staging, and application checks. - Add Docker cache wiring regressions and update the Docker cache documentation. - Run a two-build probe in Docker Runner check. It requires dependency reuse, changed real binary metadata after a source edit, and a changed recipe after a dependency declaration edit. It uses a disposable tracked-source context and exports only small metadata files. ## Verification - Passed all five Docker build-stamp and dependency-cache tests with `pnpm exec vitest run server/src/__tests__/docker-build-stamp.test.ts`. - Passed the local ARM64 `docker buildx build --target runner-build --progress plain`. Local Docker then hit storage errors during a runtime probe; cache invalidation verification continues on GitHub-hosted Linux. - Passed `bash -n scripts/check-docker-runner-cache.sh`, `actionlint`, and `git diff --check`. - Passed a [Linux AMD64 cache probe](https://github.com/paperclipai/paperclip/actions/runs/34711042199) against the PR source: dependencies compiled in 3m49s for the baseline and were `CACHED` after a source edit; real source compilation took about 37 seconds. Binary metadata changed and dependency declaration changes altered the recipe. The permanent probe is also running in latest-head Docker Runner check. - Passed latest-head [Docker Runner check](https://github.com/paperclipai/paperclip/actions/runs/34711145160), including the permanent source/dependency invalidation probe. - Passed full [PR verification](https://github.com/paperclipai/paperclip/actions/runs/34711145352/attempts/2): typecheck, all grouped tests, native verification, build, release dry run, and browser checks. One unrelated signoff-policy browser test failed waiting for a heartbeat run on attempt 1; only that failed shard and dependent checks were retried, and passed. - Latest-head Greptile is 5/5 with no unresolved findings. Full local tests/build were limited by local disk exhaustion; Linux CI completed those checks. ## Risks - The two-build CI probe has a 20-minute job limit to cover the cold build and source rebuild. It adds no AWS routing. - A fully cold build must install cargo-chef and populate the dependency layer. Both become reusable registry layers; no Actions cache is added. - The recipe and final build must keep the same compiler, build profile, package, binary, and directory layout. A source-change rebuild probe checks real cache reuse and binary invalidation. - Dependency or compiler changes still require rebuilding dependencies. Existing image verification and full-SHA publication gates remain unchanged. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
8df3ee2cf5 |
ci: rebalance serialized tests with current suite durations (#13328)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Cloud deployments wait for verified source commits. > - Verification splits serialized server tests across independent runners. > - The shard duration estimates came from August and no longer match current tests. > - Stale estimates put much more work on one runner than the others. > - This PR refreshes the estimates from a complete successful run to balance the existing runners. ## Linked Issues or Issue Description **What existing behavior does this improve?** The time spent waiting for the slowest serialized server-test shard in PR and release verification. **Current behavior** In [Cloud readiness run 34705914878](https://github.com/paperclipai/paperclip/actions/runs/34705914878), the five serialized shards spent 479, 371, 322, 390, and 365 seconds running tests. The recovery suite had a 55-second estimate but now takes about 156 seconds including process overhead. **Proposed behavior** Use fresh per-suite measurements with the existing deterministic duration balancer. Applying the same measured costs to the new assignment gives 385, 385, 386, 385, and 385 seconds. This predicts about 93 seconds less waiting for the slowest shard, before runner/setup overhead. Live CI will confirm the result. **Reason and benefit** Use the existing runners more evenly. No extra runner, test parallelism, cache, timeout, or routing change is needed. **Breaking changes** Suite-to-shard assignments change. The full suite set, assertions, and per-suite process isolation stay the same. **Additional context** Searched related CI and shard PRs. This updates the existing duration manifest, without duplicating a pending sharding implementation. ## What Changed - Refresh all 145 serialized suite weights from the same successful release verification run. - Record source job IDs and the measurement method in the manifest. Durations include process startup, imports, collection, tests, and shutdown. ## Verification - Passed all 30 shard and release-workflow tests: `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs scripts/__tests__/release-verify-workflow.test.mjs`. - Confirmed every measured suite appears exactly once across all five source logs. - Compared old and new assignments using the same measured weights. The maximum fell from 478862ms to 385551ms. - In [PR CI run 34710696242](https://github.com/paperclipai/paperclip/actions/runs/34710696242), all five serialized jobs passed in 7m05s–7m27s including setup. The measured assignment is now balanced in a live run. - The same run passed full typecheck, all grouped tests, native verification, build, release dry run, and browser checks. Local full-suite verification on this base was limited by disk exhaustion; local typecheck and targeted shard tests passed. - Latest-head Greptile is 5/5 with no open findings. Every current-head CI check must be green or intentionally skipped before merge. ## Risks - Individual durations vary with load and future test changes. These estimates affect assignment only; missing or renamed suites receive the existing median weight. - Both PR and release verification read this manifest, so both receive the new assignments. Each suite still runs in its own serialized Vitest process. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
d2e940f4c1 |
ci: run release Runner protocol and Rust checks in parallel (#13326)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud deploys verified images from merged source commits. > - Cloud readiness waits for every release verification check. > - Runner verification currently runs long TypeScript tests before Rust checks. > - These checks can run on independent runners with their own build directories. > - This PR runs them in parallel while preserving all checks and the shared dependency cache. ## Linked Issues or Issue Description Refs #13194. Related prior work: #13142 and #13259. A search found no duplicate parallel release-check change. **What existing behavior does this improve?** Time from merge to Cloud source verification and deployment readiness. **Current behavior** Recent successful runs take roughly 13 minutes from merge to deployable. In run 34705914878, Runner verification took 11m23s. Protocol tests finished before Rust tests and API authority checks started. **Proposed behavior** Run protocol and Rust verification in two matrix jobs. Cloud readiness still requires both jobs to pass. **Reason and benefit** Remove the serial dependency between independent checks. Expected improvement is about 2–3 minutes on a typical cached run, until the image build or server tests become the longest job. This is an estimate; post-merge timing will confirm it. **Breaking changes** Individual release Runner job names gain a lane suffix. Cloud source and readiness marker names stay the same. PR runner routing is unchanged. ## What Changed - Split release Runner checks into protocol and Rust lanes. Keep every constituent of `check:all` exactly once. - Restore the existing Rust dependency cache in both lanes. Allow only the Rust lane to save it after warming both build profiles. - Add coverage and cache authorization regressions. Document the parallel verification and single cache writer. ## Verification - Passed 477 workflow and source-verification tests with `node --test .github/scripts/tests/*.test.mjs scripts/cloud-source-verification.test.mjs scripts/__tests__/release-verify-workflow.test.mjs`. - Passed `actionlint`, `git diff --check`, and the private AWS routing regression suite. - Passed local `pnpm -r typecheck` and the standalone `check:runner && check:api-authority` lane, including all 1,671 API tests before the protocol lane had built TypeScript output. - The broad local protocol run under Node 25 had four failures. The two affected files passed under CI's Node 24.19.0: 67 passed, 6 platform skips. - Local `pnpm test:run` aborted when disk space ran out; local `pnpm build` could not run afterward. These are local verification limits. [Linux CI run 34710421424](https://github.com/paperclipai/paperclip/actions/runs/34710421424) passed full typecheck, all grouped tests, native verification, build, release dry run, and browser checks. Native protocol CI passed 1,986 tests, plus 1,671 API tests and the Rust suites. - Latest-head Greptile is 5/5 with no open findings. All 33 current-head checks are successful or intentionally skipped. ## Risks - Uses one additional short-lived verification runner per release verification. The existing AWS exact-master restriction remains in place. - The Rust lane warms debug dependencies so its cache save also serves protocol tests. Both lanes always rebuild workspace code. - A workflow regression could omit a check. The new coverage test compares the matrix checks directly with `check:all`; Cloud readiness depends on the complete reusable workflow. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
a59f5a8adc |
fix(server): stop reporting expected managed-cloud transients to Sentry (#13323)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work
> - The server reports crashes to Sentry so operators can find real
faults
> - Three expected conditions report as crashes: a client that closes
the connection mid-request, one stale pooled database socket after a
pooled endpoint recycles, and the short boot window where a supervised
cloud stack runs a new app image before its migration runner has caught
up
> - These events arrive in the hundreds and bury real errors
> - This pull request classifies each condition as expected and stops
the Sentry capture for exactly that condition, with behavior unchanged
everywhere else
> - The benefit is a Sentry feed where each event is a real fault
## Linked Issues or Issue Description
**What happened?**
Three noise classes fill the backend Sentry project on managed cloud
fleets:
1. `Error: aborted` (ECONNRESET) reports as a 500 crash when a client
closes the tab or loses its network mid-request. Observed 18 times in
one week from routine client disconnects.
2. `Error: write CONNECTION_CLOSED ...` reports from many query paths
after a pooled Postgres endpoint suspends. The existing single retry in
cloud actor resolution still fails, because a suspended endpoint kills
every pooled socket at once and the one replay draws another dead
socket.
3. `Error: PostgreSQL has pending migrations (...). Refusing to start`
reports from every supervised stack during a fleet upgrade. The
supervisor delivers the new app image before it runs the migration
runner, so each stack crash-loops briefly by design. One fleet roll
produced 329 events (11 per container).
**Expected behavior**
A client disconnect ends the request quietly. A transient dead socket is
replayed until a live socket answers. A supervised mid-upgrade boot
refusal logs and exits nonzero without a Sentry capture, while the same
refusal on a self-hosted deployment keeps reporting.
**Steps to reproduce**
1. Abort an HTTP request mid-flight: the error handler reports a crash
to Sentry.
2. Suspend a pooled Postgres endpoint under an idle server, then issue
two quick requests: the first replay can draw a second dead socket and
surface `CONNECTION_CLOSED`.
3. On a deployment with `PAPERCLIP_CLOUD_API_ORIGIN` set, add a
migration file without running the migration runner and boot: the
refusal reports to Sentry.
**Paperclip version or commit**
master (
|
||
|
|
09e208c54f |
ci: activate shared PR dependency cache restores (#13302)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - PR checks share a repository cache budget with post-merge cloud verification. > - Per-PR dependency store copies consume about 700 MB each and displace useful build caches. > - The reviewed workflow now restores shared dependency caches without saving PR copies. > - The public entry point must pin an approved immutable workflow before it can use AWS runners. > - This PR activates the merged workflow after the runner group accepted its exact SHA. > - Native verification and the app build also run in parallel, as defined in the merged workflow. ## Linked Issues or Issue Description Refs #13300. Refs #13301. The cache definition is merged, and its exact SHA is authorized in the restricted runner group. This PR activates it. Its base also contains the two synthetic fixture fixes from #13301. No duplicate activation PR was found. ## What Changed - Advance the `pr-trusted.yml` pin from `03609aa6ecc9a047ed53d6b6469d8be554fbc46d` to merged commit `44dde2dec42a22746a2f36b595acacc9ccfa1df6`. - Update the adjacent pin comment to identify #13300 and the activated behavior. - Activate restore-only pnpm caching and removal of redundant Node setup steps from #13300. - Activate the already-merged separate native verification job, required by the aggregate `verify` check. The app build no longer waits for native verification inside the same job. - Activate the merged module-boundary and source-verification checks and explicit Runner Evalbook viewer build. ## Verification - Passed all 505 workflow, routing, cache, sharding, and source-verification tests. - Passed `actionlint` for both workflow files and `git diff --check`. - Passed the runner infrastructure's workflow routing regression tests. - Confirmed that the gate is unchanged between the old and new workflow definitions. The restricted runner group permits the exact merged SHA and retains its existing workflow pins. - Full workspace typecheck and build passed on the timeout-fix branch. Its 107 targeted runner tests and all Linux CI groups passed. The broad local Mac test command had 15 unrelated permission and missing-skill-path failures, documented in #13301; it stopped before later groups. - [Current-head CI run 34662664879](https://github.com/paperclipai/paperclip/actions/runs/34662664879) passed. All 33 checks are green or intentionally skipped at `ded4f1d093644b9279cdf56457f69a196fcf8cc2`. Greptile is 5/5, with no unresolved findings. - The live build restored the master pnpm cache, downloaded the resolved lockfile artifact, and completed a frozen install. It had no dependency-cache upload step. GitHub reports zero cache entries for this PR. Native verification and the app build started together and both passed. - [Post-merge cloud readiness for #13301](https://github.com/paperclipai/paperclip/actions/runs/34662389233) passed all 30 jobs in 12m42s from merge. Native verification restored the master Rust cache and passed the formerly failing fixtures. ## Risks A new PR-only dependency can require a download until a master cache contains it. The new pin also activates the merged workflow changes listed above, so the live PR must pass all checks. The repository storage cap is still 10 GB; this PR does not increase it. No allowlist or runner permission logic changes. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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> |
||
|
|
5cc7784986 |
test: remove cold executable reads from runner integrity deadlines (#13301)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Native runner protocol tests verify that invalid authenticated input fails closed. > - Cloud readiness requires those tests to pass before a source commit can deploy. > - Two test fixtures hash the host Node executable twice even though its process launcher is synthetic. > - Cold reads of a large Linux executable consume time unrelated to protocol failure handling. > - This PR gives both synthetic runner fixtures tiny real artifacts and keeps their existing deadlines. > - Real authentication, encrypted frames, and request and notification failures remain covered. ## Linked Issues or Issue Description **What happened?** Cloud readiness repeatedly failed in `DurablePrpControlPlane > promptly fails the real transport request and notification paths on authenticated bad semantic input (throwing observer: false)` with `Test timed out in 5000ms`. The image built, but the failed source check prevented deployment. See runs [34656885170](https://github.com/paperclipai/paperclip/actions/runs/34656885170) and [34657111560](https://github.com/paperclipai/paperclip/actions/runs/34657111560). The first case took 5.6–11.4 seconds; the following case took about 0.4 seconds. The original test reads and hashes `process.execPath` once itself and once through the real transport. The Node executable is 122,678,944 bytes in the local Linux Node 24 container, versus 68,672 bytes on the development Mac. Instrumented Mac runs pass; cold executable reads are a likely cause of the CI-only timeout. **Expected behavior** The deadline should measure real protocol rejection and consumer failure, without reading a large unrelated executable as test fixture data. **Steps to reproduce** 1. Run the named test with the real transport and synthetic process launcher. 2. For a deterministic probe, inject a six-second delay into the first `readFileSync(process.execPath)` call. 3. The original test exceeds its existing five-second deadline. Both cases pass after this change because neither reads the host executable. The probe is temporary instrumentation, not part of this commit. **Paperclip version or commit** f12b647ae; the same failure also occurred on |
||
|
|
44dde2dec4 |
ci: reuse dependency caches without per-PR uploads (#13300)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Cloud releases wait for source verification before deployment.
> - That verification reuses compiled Rust dependencies to finish
sooner.
> - PR jobs save large pnpm stores under separate merge refs and
different lockfile keys.
> - Those copies compete with master build caches for the repository's
10 GB cache limit.
> - This PR makes PR dependency caches restore-only and reuses
master-compatible keys.
> - A separate pin update will activate the reviewed workflow.
## Linked Issues or Issue Description
**What happened?**
PR merge refs accumulated roughly 700 MB copies of the same pnpm store.
Master Rust caches disappeared, and Cloud readiness run
[34656098157](https://github.com/paperclipai/paperclip/actions/runs/34656098157)
rebuilt dependencies after cache misses. The repository currently has a
10 GB limit. GitHub rejected a request for 50 GB; that setting needs
separate organization/billing access.
**Expected behavior**
PR jobs should reuse downloaded packages without evicting post-merge
compilation caches through duplicate uploads.
**Steps to reproduce**
1. Run several PRs while the checked-in lockfile needs policy
regeneration.
2. Compare the setup-node keys in PR jobs and master jobs.
3. List Actions caches by ref, key, and archive size. The PR keys repeat
across merge refs.
**Paperclip version or commit**
|
||
|
|
37d7dfb0e3 |
ci: allow dependency changes in cloud eval verification (#13286)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Cloud deployment requires source verification for the exact merged commit. > - Contributor PRs leave lockfile updates to a separate bot PR. > - Most release checks can refresh an outdated lockfile while installing dependencies. > - Two Runner checks still require a frozen lockfile and fail after dependency changes. > - This PR gives those checks the same install policy as the other release checks. > - A valid dependency change can become deployable without waiting for another merge. ## Linked Issues or Issue Description Refs #13257. The dependency change in #13256 exposed this gap. The separate lockfile update is #13279. Related #12115 addresses the bot PR check trigger; this PR fixes exact-source cloud verification itself. **What happened?** [Cloud readiness for |
||
|
|
1c4bcff2b1 |
fix(test): await issue lock before retry race assertions (#13273)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Retry decisions must respect changes to an issue owner. > - Database tests verify this with two concurrent transactions. > - The test started the competing operation before its fixture held the lock. > - That race can fail a correct source verification run and block deployment. > - This PR waits for lock acquisition before starting the competing operation. ## Linked Issues or Issue Description Refs #13257 for the deployment verification work that exposed this test race. No duplicate fix was found. **What happened?** [Cloud verification job 103424158921](https://github.com/paperclipai/paperclip/actions/runs/34648268409/job/103424158921) failed because the test did not observe a concurrent issue-row lock waiter. The fixture and retry operation both started without an ordering guarantee. **Expected behavior** The fixture must hold the issue lock before the competing retry operation starts. The test must still prove that the retry waits for the lock and observes the reassignment. **Steps to reproduce** 1. Add a temporary 50 ms delay before the fixture acquires the issue lock. 2. Run the promoteOrCancelDueRetry issue-lock test. 3. The original fixture fails with the same missing-waiter error as CI. 4. The synchronized fixture passes with that delay. The delay is not part of this PR. ## What Changed - Separate fixture readiness from its transaction completion promise. - Wait for readiness at both callers before starting the retry decision. - Propagate transaction failure during setup through Promise.race. ## Verification - The original fixture fails under the temporary delayed-lock probe. The fixed fixture passes the same probe. - All 31 tests in server/src/modules/run-dispatch/adapters/postgres.test.ts pass after removing the probe. - The real concurrent waiter, lock-order, and reassignment assertions remain intact. No timeout was increased. - Full local typecheck and build pass (221s and 50s). The full local test command stopped in its server phase after 10,610 passes, 65 skips, and 14 failures: 13 existing macOS skill-cache rename/permission failures and one unchanged Telegram test assertion. The Telegram test passes in a focused rerun. Later local phases did not run after that failure. Current-head Greptile is 5/5 with no findings. All 32 current-head checks pass, including full Linux typecheck, build, native verification, server suites, browser suites, and canary packaging. The unchanged GitHub browser mock assertion passed its single failed-shard retry. - git diff --check passes. ## Risks - Only test synchronization changes. Production database behavior is unchanged. - Awaiting the transaction itself during setup would deadlock the test. Returning the completion promise inside an object avoids that problem. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. The exact serving model ID and context window are not exposed by this environment. ## 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 — all 31 database adapter tests pass; full local verification limits are disclosed 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> |
||
|
|
19c76bfc3f |
fix(ci): avoid empty pnpm caches from lockfile refresh (#13267)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - CI installs dependencies before it verifies and builds cloud artifacts. > - Install jobs share a pnpm package-store cache with lockfile refresh. > - Lockfile refresh resolves versions without downloading packages. > - That job saved an empty cache before full install jobs could save theirs. > - This PR prevents lockfile refresh from publishing that empty entry. > - Full install jobs can then populate the cache and reuse dependencies. ## Linked Issues or Issue Description Refs #13259 for the related cloud verification cache work. No duplicate empty-cache fix was found. **What happened?** Refresh Lockfile run 34517514932 saved a 216-byte default-branch pnpm cache at 18:58:08 UTC on September 10. Full install jobs still restore that empty entry. The cache API reports 216 bytes for master and about 703 MB for populated entries with the same key and cache version in PR scopes. **Expected behavior** A job that installs dependencies should populate the shared package-store cache. **Steps to reproduce** 1. Run lockfile refresh with a new lockfile cache key. 2. Its resolution-only command leaves the package store empty. 3. The Node action saves the empty archive before a full install finishes. 4. Later jobs report a cache hit but download packages again. **Paperclip version or commit** Observed on master |
||
|
|
778ac33308 |
feat: accept a base64-encoded Cloud UI snippet (#13245)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Paperclip Cloud instances can inject a trusted operator HTML snippet before `</body>` in served UI pages (#13168) > - Operators deliver env vars to managed instances through hosting-provider APIs > - Web application firewalls in front of those APIs reject request bodies that contain raw `<script` markup > - The snippet value always contains a script tag, so the firewall blocks its delivery every time > - This pull request adds `PAPERCLIP_CLOUD_UI_SNIPPET_B64`, which carries the same snippet as standard base64 > - The benefit is that operators can ship the snippet through WAF-fronted delivery pipelines without firewall exceptions ## Linked Issues or Issue Description Refs #13168 (introduced the Cloud UI snippet). **Subsystem affected** Server UI shell serving: `server/src/cloud-ui-snippet.ts`, used by `static-index-html.ts` and `app.ts`. **Current behavior** `PAPERCLIP_CLOUD_UI_SNIPPET` is the only way to configure the Cloud UI snippet. The value is raw HTML. Delivery pipelines that write env vars through provider APIs can fail to deliver it: web application firewalls classify a request body that contains `<script` as an injection attempt and block it. Verified against Railway's GraphQL API, which sits behind Cloudflare: a variable value with a bare `<script></script>` returns HTTP 403 before authentication, and JSON unicode escapes (`<script`) do not bypass the block. The snippet is exactly the kind of value that always contains a script tag, so such pipelines cannot deliver it at all. **Proposed behavior** A new optional `PAPERCLIP_CLOUD_UI_SNIPPET_B64` carries the same snippet as standard base64 of the UTF-8 HTML. The server decodes it and injects the result through the existing path. The plain variable wins when both are set. Whitespace and line wrapping in the value are tolerated. A value that is not canonical base64, or that decodes to blank, is ignored instead of injected as garbage. **Reason and benefit** Operators can deliver the snippet through WAF-fronted APIs without requesting firewall exceptions. Base64 contains no markup, so the firewall has nothing to match. Existing deployments see no behavior change. **Breaking changes** None. The new variable is optional. The existing variable is unchanged and takes precedence. ## What Changed - `server/src/cloud-ui-snippet.ts`: resolve the snippet from `PAPERCLIP_CLOUD_UI_SNIPPET` first, then from base64-decoded `PAPERCLIP_CLOUD_UI_SNIPPET_B64`; ignore non-canonical or blank-decoding values. - `server/src/__tests__/cloud-ui-snippet.test.ts`: cover decode-and-inject, plain-wins precedence, whitespace tolerance, invalid/blank values, and the self-hosted no-op. - `doc/cloud-ui-snippet.md`: document the variant, how to produce the value, and the ignore rules. ## Verification - `pnpm vitest run server/src/__tests__/cloud-ui-snippet.test.ts server/src/__tests__/static-index-html.test.ts` — 13 tests pass. - `tsc --noEmit` in `server/` passes. - Manual check: on a Cloud-managed instance, set `PAPERCLIP_CLOUD_UI_SNIPPET_B64="$(base64 < snippet.html)"`, restart, open `/`, and confirm the decoded snippet appears before `</body>`. On a self-hosted instance, confirm no snippet is injected. ## Risks Low risk. The injection path and the Cloud-managed gate are unchanged. A malformed base64 value is ignored, so the failure mode is a missing widget, not corrupted HTML. The decoded value is trusted operator configuration, the same trust model as the plain variable. ## Model Used - Claude Fable 5 (Anthropic, `claude-fable-5`) via Claude Code CLI, agentic workflow with tool use (code edits, test runs, and live API verification of the WAF behavior). ## 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 |
||
|
|
bc68312327 |
ci: use reserved AWS capacity for post-merge cloud verification (#13257)
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - Cloud deployments consume a verified image and exact-source
migrator.
> - An image alone is not deployable until source checks and artifact
checks pass.
> - GitHub-hosted queues delayed those checks and the final readiness
signal.
> - This PR gives trusted master work a separate concurrency allowance
on existing AWS runners.
> - Community PRs and arbitrary source inputs keep the GitHub-hosted
fallback.
## Linked Issues or Issue Description
Refs #13243.
**What existing behavior does this improve?**
Time from a master merge to the Cloud deployable v1 signal.
**Current behavior**
For merge
|
||
|
|
a23ae894a5 |
ci: cache Rust dependencies used by post-merge typecheck (#13259)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Cloud images become deployable only after source verification passes. > - The typecheck job builds the native Runner binary through the server package. > - Fresh runners repeatedly compile Rust dependencies for that binary. > - This PR caches those dependencies for exact-source master verification. > - Workspace code and every typecheck still rebuild or run as before. ## Linked Issues or Issue Description Refs #13243 and #13257. **What existing behavior does this improve?** The typecheck portion of post-merge cloud source verification. **Current behavior** The typecheck job has no Rust dependency cache. An observed release build in this job took 4m 13s, including dependency compilation. **Proposed behavior** Restore dependency build outputs for canonical master pushes with the exact source SHA. Use a separate cache key from the Runner verification job, which builds other profiles. **Reason and benefit** A warm cache should remove roughly 2–3 minutes of dependency compilation from this job. Overall deployment gains depend on the remaining critical path. The first cache population still compiles from scratch. **Breaking changes** None. All checks remain enabled. Non-master callers compile without restoring or saving this cache. ## What Changed - Select the pinned Rust toolchain before the typecheck cache lookup. - Reuse the existing pinned Rust cache action with a typecheck-specific key. - Exclude workspace crates and installed cargo executables. - Test restore/save trust boundaries and document cache behavior. ## Verification - All workflow script tests pass locally, including nine new cache trust/contract cases. - actionlint passes for release-verify.yml. - Full local typecheck and build pass on the same source base (167s and 206s); `pnpm test:run` is still running and is recorded with #13257. This PR changes only the workflow, cache guard tests, and documentation. - All 32 current-head checks are successful or intentionally skipped, including the complete Linux test matrix, build, and Greptile 5/5 with no unresolved findings. Verify cache population and subsequent restore on actual master runs. ## Risks - The first run and any toolchain/dependency invalidation compile from scratch. - Cache restore/save overhead reduces the benefit for small dependency graphs. - Disable the cache step to roll back; the existing uncached build remains valid. ## Model Used OpenAI GPT-6 through Codex, with reasoning, repository tools, and code execution. Exact serving model ID and context window are not exposed by this environment. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass — focused change tests pass; full-suite local permission failures are disclosed 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> |
||
|
|
d0b7ba4194 |
ci: route approved master cloud builds to AWS (#13243)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Paperclip Cloud deploys images built from master commits. > - Cloud image builds share GitHub-hosted capacity with other workflows. > - The organization already operates AWS runners through RunsOn Fleet. > - This pull request allows approved master builds to use a dedicated cloud Fleet. > - The benefit is separate build capacity with a quick operator rollback. ## Linked Issues or Issue Description Refs #13189, #13192. **What existing behavior does this improve?** Placement of the Docker cloud build after a master merge. **Current behavior** Every Docker cloud build uses a GitHub-hosted runner. Busy periods delay the job. **Proposed behavior** An operator variable enables the approved cloud Fleet for canonical master pushes and manual master builds. Other events, refs, and repositories use GitHub-hosted runners. ## What Changed - Add a guarded AWS runner selector to the Docker cloud job. - Keep the existing image cache, verification, and publication steps. - Test the selector against master, branch, tag, PR, fork, and disabled contexts. - Document provisioning requirements, placement checks, and rollback. ## Verification - 29 focused Node tests pass for routing, readiness, and disk handling. - The full workflow-script Node suite passes. - `pnpm -r typecheck` passes locally. - The pinned PR routing regression suite passes. The first live PR run assigned 21 jobs to the approved AWS PR group. AWS then reclaimed 16 Spot instances. The failed run is being repeated on GitHub-hosted runners while the Fleet moves to On-Demand. - Actionlint passes with existing shellcheck findings excluded (SC2012, SC2016, SC2129). - `git diff --check` passes. - Greptile reports 5/5 on commit `764d505a41dd2023751c3f361906fa9ea35bf0c6`, with no review threads. - All 30 current-head CI checks pass, including typecheck, build, all server/workspace test shards, Runner verification, and browser tests. Two Storybook checks are intentionally skipped for this change. Run: https://github.com/paperclipai/paperclip/actions/runs/34630550799 - The broader local test/build sequence is still running. This Mac has reported failures in unchanged application suites; their complete Linux CI shards pass. Local targeted workflow tests and typecheck pass. - Both On-Demand Fleets are deployed and healthy. Live master cloud-build verification follows the merge. ## Risks - Missing Fleet capacity or runner-group authorization can leave an AWS job queued. Disable `AWS_CLOUD_BUILDS_ENABLED` and rerun the workflow to use GitHub-hosted capacity. - The runner group must restrict access to this repository and the master version of `docker-cloud.yml`. - Docker needs more disk space than the PR Fleet. Provision 120 GiB disks and retain the free-space check. - This changes image build placement only. Source verification and migrator publication remain separate prerequisites. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The exact serving model identifier and context-window size are not exposed by this environment. ## 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> |
||
|
|
4fde92107e |
fix(ci): reuse cloud source verification for npm canaries (#13233)
Reuse the exact master source-verification result before npm canary publication, removing a duplicate verification matrix while preserving fail-closed release checks. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
974949a39b |
ci: spread cloud server verification across ten runners (#13227)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Cloud waits for source verification before deploying a new image. > - The slowest server verification job spends about ten minutes running tests. > - Each job uses one test worker to preserve test isolation. > - This pull request distributes those suites across ten standard hosted runners. > - The benefit is a shorter verification path with the same test coverage. ## Linked Issues or Issue Description **Current behavior** In [readiness run 34572340764](https://github.com/paperclipai/paperclip/actions/runs/34572340764), the slowest server job ran for 638 seconds. Test execution used 594 seconds. This held readiness behind the image job. **Proposed behavior** Use ten general server jobs in the reusable release verification workflow. Keep the three chat jobs and every existing prerequisite. The complete partition test verifies that no server suite is omitted or duplicated. **Reason and benefit** Reduce merge-to-deployable time on the existing runner type. The next longest prerequisite was Runner verification at 526 seconds, so the initial expected total gain is about two minutes rather than a halving of readiness time. Measure actual queue and execution time before claiming a result. Related: #13198 introduced the separate chat lane. #12577 refreshes duration estimates; this change leaves that manifest alone. ## What Changed - Increase the general server matrix from five jobs to ten. - Verify the ten-way partition covers the complete server suite when combined with the chat lane. - Document runner demand and the unchanged local and PR grouping. ## Verification - `node --test scripts/__tests__/release-verify-workflow.test.mjs scripts/__tests__/run-vitest-stable-shard.test.mjs`: 29 passed. - `actionlint .github/workflows/release-verify.yml`: passed. - Full local `pnpm -r typecheck` and `pnpm build`: passed. - All latest-head GitHub CI checks passed, including the complete Linux test partition, build, typecheck, and browser gates. Greptile: 5/5 with zero open findings. - [Ten-shard timing probe](https://github.com/paperclipai/paperclip/actions/runs/34606772388): all 16 jobs passed; slowest server job 6m 23s versus 10m 38s in the earlier five-shard sample. This compares the server lane, not total readiness, and is not a controlled same-source A/B. - The full local `pnpm test:run` is also running. It has reproduced previously observed macOS-only failures in unchanged skill-cache and native-session suites; the corresponding Linux CI suites passed. Final local results will be attached separately. No affected-workflow test failed. ## Risks Five additional concurrent jobs per release verification run increase runner demand and repeated setup work. Queueing can offset the gain. Test workers, timeouts, permissions, and readiness requirements stay unchanged. Revert the matrix and its partition test to restore the previous split. ## Model Used OpenAI GPT-6 / Codex, with reasoning, tool use, and code execution. The exact serving model identifier and context-window size are not exposed by this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run the affected workflow tests locally and they pass; full-suite macOS limitations are disclosed 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> |
||
|
|
932c8bec56 |
fix(ci): bake the managed runtime identity into cloud images (#13210)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Managed deployments start from the image built by the Cloud workflow. > - The managed runtime requests user and group 1001. > - The image currently builds the node user as 1000. > - Startup must remap that user, which can walk a large mounted home directory. > - This pull request uses the existing Docker build arguments to bake user and group 1001 into Cloud images. > - Matching the runtime identity removes that startup work and helps avoid health-check retries. ## Linked Issues or Issue Description Refs #13208, #1923, and #7861. Searched open and closed PRs for the Cloud UID change. The older #7861 addresses build context and volume ownership repair. This change uses the existing identity arguments in the Cloud workflow and preserves ownership repair. **What happened?** A measured rollout had a container log `Updating node UID to 1001` after startup. The container stayed at this step for at least 2 minutes 55 seconds before rollback stopped it. The baked node identity was 1000, while the managed runtime requested 1001. A health check timed out and the target required a second deployment attempt. **Expected behavior** Cloud images should already have the managed runtime identity. A matching image should skip user and group remapping. Fresh or mismatched volumes must still receive ownership repair. **Steps to reproduce** 1. Build the current Cloud image with its default build arguments. 2. Start it with `USER_UID=1001`, `USER_GID=1001`, and a populated home volume. 3. Observe the startup user remap before the application starts. **Paperclip version or commit** `fc06f7f05f42c675be71ff0927b6334405d520ed` **Deployment mode** Docker on managed hosts. ## What Changed - Pass `USER_UID=1001` and `USER_GID=1001` to the Cloud image build. - Check the pushed digest's baked identity before the entrypoint can repair it. Then check the normal entrypoint's effective identity and writable home before publishing the verified full-SHA tag. - Add a workflow regression and two entrypoint cases for a matching Cloud identity, including a mismatched volume. - Document the runtime identity and the first-build cache cost. ## Verification - Focused workflow and artifact tests: 27 passed. - Entrypoint tests: 11 passed. Actionlint passed. Full local `pnpm -r typecheck` passed. Full local `pnpm build` passed. The manual [Cloud image build](https://github.com/paperclipai/paperclip/actions/runs/34575473213) passed on the exact PR head. It checked Sentry, baked and effective identity, writable home, orphan reaping, and full-SHA publication. The new identity check took one second. All 30 PR checks passed; the Storybook workflow was intentionally skipped. Greptile reviewed commit `114d408f637a0b53e2e2b1339c263779b1e4ae54` at 5/5 with no findings or open threads. - The full local suite for the same application source was already run in #13205. Its macOS general-server phase had 10,471 passes and 70 failures in seven unchanged files. Those failures included missing Runner fixtures, filesystem errors, timeouts, a port conflict, and a load-count mismatch. After configuring Cargo and rebuilding fixtures, 37 of 38 native tests passed; one unchanged native-resume assertion still failed. Linux PR CI passed. This change adds entrypoint tests and does not change application code. ## Risks - The first build must rebuild layers that depend on the base image identity. Later builds can reuse them. - A future managed runtime identity change must update these build arguments and checks together. - The Dockerfile's self-hosted defaults remain 1000. Runtime overrides and mounted-volume ownership repair remain supported. - The observed startup delay supports this change, but fleet timing also includes provider startup, image pull, canary order, and retries. No fixed end-to-end gain is claimed before a live rollout. ## Model Used OpenAI GPT-6 through Codex, with reasoning, code execution, and tool use. 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 (focused workflow tests; full-suite 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> |
||
|
|
fc06f7f05f |
fix(ci): isolate chaos verification by caller workflow (#13208)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Cloud deployments require verified artifacts for the merged source commit. > - Cloud readiness and the npm release independently run the same source checks. > - Their shared chaos workflow used only the source ref as its concurrency key. > - One caller could cancel the other caller's required job for the same commit. > - This pull request scopes that key to the caller workflow and source ref. > - Both callers can finish their checks without blocking deployment readiness. ## Linked Issues or Issue Description Refs #13192 and #13205. Searched for related open issues and PRs; no duplicate fix was found. **What happened?** The master push for `398d304e15739d1ee6105633bd8a0e42c929d33f` started Cloud readiness and Release together. GitHub cancelled the Cloud readiness chaos job before it acquired a runner. Its annotation reported a higher-priority waiting request for the same concurrency group. The required readiness gate cannot pass after that cancellation. **Expected behavior** Cloud readiness and Release must each finish source verification for the same SHA. Standalone chaos evals must also have a separate group. **Steps to reproduce** Merge a commit to master while the npm release queue is empty. Both callers reach the reusable chaos workflow with the same source SHA. See [the cancelled job](https://github.com/paperclipai/paperclip/actions/runs/34569569760/job/103168603926). **Paperclip version or commit** `398d304e15739d1ee6105633bd8a0e42c929d33f`. **Deployment mode** GitHub Actions on master. ## What Changed - Add the caller workflow name to the chaos workflow concurrency group. Retain source isolation and cancellation of duplicate calls within the same workflow. - Add a regression test that evaluates the group for Cloud readiness, Release, and standalone evals at the same source SHA. - Document the concurrency boundary in the readiness runbook. ## Verification - `node --test scripts/preview-artifacts.test.mjs scripts/__tests__/release-verify-workflow.test.mjs` passed: 26 tests. - The new regression test fails against the previous concurrency key and passes with this fix. - `actionlint -shellcheck= -pyflakes= .github/workflows/runner-chaos-evals.yml .github/workflows/release-verify.yml .github/workflows/cloud-readiness.yml` passed. - `git diff --check` passed. - The full local typecheck passed for the same application source in #13205. Its macOS general-server test phase had 10,471 passes and 70 failures in seven unchanged application test files: missing Cargo/Runner test binaries, filesystem permissions, timeouts, a port conflict, and a load-test count mismatch. Linux CI test checks passed. The full local build passed with Cargo on PATH. This PR changes workflow configuration, its test, and documentation only. - All CI checks pass on the final head, including typecheck, tests, browser suites, build, and canary dry run. Greptile is 5/5 with no open findings. After merge, verify both callers' chaos jobs complete for the same master SHA and record the resulting readiness time. ## Risks - Two callers may now run chaos tests at the same time. This uses two existing GitHub runners, which is the intended cost of independent verification. - Renaming a caller changes its concurrency group. The fixed prefix keeps this child group separate from caller-level concurrency groups. - The readiness gate continues to require every verification prerequisite. No gate is bypassed. ## Model Used - OpenAI GPT-6 / Codex, with reasoning, repository editing, and command/API tools. Exact serving model ID and context-window size are not exposed by this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (26 focused workflow/artifact tests) - [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> |
||
|
|
398d304e15 |
docs: measure cloud deployment through target health (#13205)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Hosted deployments need a verified image and migrator for the same source commit. > - The cloud readiness workflow certifies those inputs before a deployment consumer acts. > - Its completion time does not show when a tenant runs the new commit. > - This pull request documents each milestone from merge through target health and fleet completion. > - Operators can use the evidence to find the slow stage and measure a complete deployment. ## Linked Issues or Issue Description Refs #13192, #13188, and #13189. Searched related issues and PRs; no duplicate timing documentation change was found. **Issue type** Missing documentation. **Where is the issue?** `doc/cloud-build-readiness.md`, Timing and rollout. **What's wrong?** The timing instructions stop at the readiness job. That omits consumer queues, artifact resolution, and target deployment. An image can be ready while the tenant still runs an older commit. **Suggested fix** Record separate merge, image, readiness, canary health, and fleet completion timestamps for the same full source SHA. Keep preparation-only runs out of deployment results. ## What Changed - Define the evidence needed for each merge-to-deployment milestone. - Explain how consumer queues can hide upstream build gains. - Require target source identity as well as health, and report exclusions, retries, cache state, and queue conditions. ## Verification - `git diff --check` passed. - `node --test scripts/preview-artifacts.test.mjs scripts/__tests__/release-verify-workflow.test.mjs` passed: 25 tests. - Cross-checked the readiness identity and artifact prerequisites against the current workflows and consumer contract. - Full local `pnpm -r typecheck` passed using the session's installed Rust toolchain. The full local test suite and subsequent build are still running. - All CI checks pass and Greptile is 5/5 on the exact head, with no unresolved findings. This changes one documentation file and adds no runtime behavior. ## Risks - Low risk: documentation only. Timing must still use trusted run evidence and the actual target commit. A single measured run is not a latency guarantee. ## Model Used - OpenAI GPT-6 / Codex, with reasoning, repository editing, and command/API tools. Exact serving model ID and context-window size are not exposed by this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (25 focused workflow/artifact tests; full checks pending) - [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> |
||
|
|
d56be3f3fc |
fix(ci): verify deployable cloud artifacts independently (#13192)
Verify source, build the cloud image, and wait for exact-source migrator packages concurrently. Emit Cloud deployable v1 only when every prerequisite succeeds for the merged full SHA. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5cc51fad06 |
fix(release): publish exact-source cloud migrators on merge (#13188)
Publish exact-source shared and database migrator packages for each master merge through the existing trusted Release workflow, independently of the full release and image build. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
6a7025ebe3 |
ci: skip cloud runner cleanup when disk headroom is ample (#13191)
Skip cloud runner disk cleanup when both the Docker and workspace filesystems have at least 64 GiB free. Preserve the existing cleanup for low, unavailable, or invalid measurements and verify the actual shell behavior across eight scenarios. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
5c660a32f3 |
ci: build cloud images independently for each merge (#13189)
Build cloud images independently for each master commit through a reusable workflow. Preserve production release dependencies and image runtime checks, and write cloud registry caches per commit with bounded ancestor imports to prevent overlapping builds from replacing each other's cache. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
59d74b68b2 |
ci: cache the native Runner in a separate Docker stage (#13195)
Compile the native Runner from its complete Cargo and protocol inputs in a separate cached Docker stage. Preserve Cargo validation and generated-contract checks during the normal application build, normalize input timestamps across checkouts, and compile the isolated target in PR CI. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
42961b6ef1 |
fix(ci): split release chat verification into test shards (#13198)
Split release chat verification into three validated test-line shards and balance other server suites across five runners using the measured native Runner integration cost. Retire each chat case's fixtures after assertions, preserve complete test coverage, and exercise the real shard CLI in PR tests. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
9e970df4c5 |
ci: cache Rust dependencies in release Runner verification (#13194)
Cache external Rust dependencies in trusted master release verification after selecting the package-owned toolchain. Keep source compilation and all validation unconditional; restrict both restore and save to the matching master push. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
3fd556b8f6 |
ci: preserve weekly Docker tool cache across commits (#13190)
Keep stable Docker tool installation layers independent of application build version and commit metadata. Preserve the existing weekly tool refresh and runtime build stamp. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
399daa1f25 |
ci: publish verified full-SHA cloud image tags (#13187)
Publish the full-source-SHA cloud image tag only after the pushed digest passes runtime, revision, and platform checks. This makes verified images directly resolvable by Cloud. Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|
|
c5c80e1feb |
ci(release-verify): split server tests five ways like pr-trusted (#13185)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every master push publishes a canary through release.yml, gated by release-verify.yml — the fleet's staging deploys and the nightly/beta/stable chain all start from those canaries > - release-verify splits the server test suite across three shards with a 20-minute job cap, while pr-trusted splits the same suite across five > - The server suite grew on 2026-09-10 and the three shards moved to 17-19 minutes; that evening every push-triggered canary run was cancelled by the 20-minute cap mid-verify, and no canary published after 18:50 UTC > - This pull request mirrors pr-trusted's five-way server split in release-verify, putting shards back at the 10-15 minute range with real headroom > - The benefit is a canary lane that reports test verdicts instead of dying on an infrastructure cap ## Linked Issues or Issue Description **What happened?** Push-triggered Release runs stopped publishing canaries on 2026-09-10. Runs at 19:34, 22:30, and 22:37 UTC were all cancelled by "The job has exceeded the maximum execution time of 20m0s" on a `verify_canary / General tests (server (N/3))` shard. No canary published after 18:50 UTC, which also starves the staging fleet's continuous deploys. **Expected behavior** release-verify's server shards finish well inside the 20-minute cap and runs conclude with a test verdict, as pr-trusted's five-way split of the same suite does (10-15 minutes per shard). **Steps to reproduce** 1. Compare server shard durations in the `verify_canary` job across 2026-09-10: 11-14 minutes in the morning, 17-19 minutes from 15:06 UTC, over 20 minutes by evening. 2. Observe runs 34521169020, 34537798488, and 34538332689 cancelled at the cap. **Paperclip version or commit** `master` at `d1ba17eec` (current tip; its canary run was one of the cancelled ones). ## What Changed - `release-verify.yml`: the `general-server` matrix goes from three shards to five, byte-for-byte the shape `pr-trusted.yml` already runs, with a comment recording why. ## Verification - The identical five-way split runs green on every pr-trusted run (10-15 minutes per shard today, including on PRs merged this evening). - The suite's own growth (slower chat-connector tests) is being addressed separately; this PR only removes the artificial cliff. ## Risks - Low risk: two more runners per verify run; no test content changes. If shard durations regress further, the cap fires again — which is the correct signal once shards have honest headroom. ## Model Used - Claude (Anthropic), model ID `claude-fable-5` (Claude Fable 5), extended thinking, tool use via Claude Code CLI. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
2585ed0550 |
test(server): settle three contention flakes that killed canary verifies (#13186)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Every master push publishes a canary through release-verify; the staging fleet and the nightly/beta/stable chain start from those canaries > - The server suite grew substantially on 2026-09-10 and now runs under real contention in CI, where three tests assert timing properties that only hold on an idle machine > - Each of the three failed a release-verify canary run that day (runs 34497348802 and 34517515849), and together with the shard timeouts (#13185) they kept any canary from publishing after 18:50 UTC > - This pull request makes the three assertions contention-tolerant without weakening the invariants they prove > - The benefit is a canary lane whose verdicts reflect the code, not the load on the runner ## Linked Issues or Issue Description **What happened?** Three server tests failed release-verify canary runs on 2026-09-10 under CI load: 1. `chat-channels.integration.test.ts › returns a retryable webhook failure when the delivery insert fails before durable receipt` — the duplicate-redelivery request drew the retryable 503 instead of an immediate 200 (run 34517515849). 2. `chat-channels.integration.test.ts › returns ephemeral guidance for exact Slack controls in channels without creating tasks or actions` — a `provider_effect` row was read before its async settlement reached `processed` (run 34497348802). 3. `runner-connection-eval-fixtures.test.ts › resets paired attempts…` — the fixture's `TRUNCATE companies CASCADE` was chosen as a deadlock victim (40P01) against the helper app's own background sweeps (run 34497348802). **Expected behavior** Verify runs fail only for real regressions. A momentary-contention 503 on a duplicate redelivery, an in-flight settlement row, and a deadlock-victim reset are all recoverable states the code handles by design. **Steps to reproduce** Run the three tests under a loaded 3-shard release-verify split; the timing assertions flake. Under `pr-trusted`'s lighter shards they usually pass, which is why the PRs that introduced them were green. **Paperclip version or commit** `master` at `d1ba17eec`. ## What Changed - The duplicate-redelivery assertion retries on 503 the way Slack itself would (bounded, 250 ms apart), then asserts the 200 and the unchanged dedup invariants: duplicate count increments, still exactly one issue. - The channel-controls settlement read is wrapped in a bounded `vi.waitFor`, the same pattern the file's durable-receipt paths already use. - The runner eval fixture retries its TRUNCATE on Postgres error 40P01, bounded at five attempts, and rethrows anything else. ## Verification - All three run green locally: the two chat tests via `-t` filters, the eval fixtures file in full (6 tests). - Each change is assertion-shape only; no product code is touched. - Observation for a follow-up, not this PR: the chat integration file costs ~15 s transform + ~28 s import per vitest worker before any test executes — splitting it would give back real shard time. ## Risks - Low risk: the retries and waits are bounded, so a genuine regression (permanent 503, settlement that never lands, persistent deadlock) still fails within the same timeouts as before. ## Model Used - Claude (Anthropic), model ID `claude-fable-5` (Claude Fable 5), extended thinking, tool use via Claude Code CLI. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
4042eb1c48 |
test(release-smoke): follow the connect-step source question and the first-task chat (#13166)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The release pipeline promotes canary → nightly → beta → stable, and the nightly lane is gated by the Docker release smoke, a Playwright walk of first-run onboarding against the exact published artifact > - Onboarding changed twice since the smoke was last updated: the connect step now opens as a model-source question (#12796, #12801), and the seeded first task now opens as a chat with the lead that deliberately creates no run until the user answers (#13068) > - The smoke still waited for an immediate "Connect" button and then polled for an assignment-triggered heartbeat run, so it failed every scheduled nightly since 2026-09-03 and blocked all nightly and beta promotions > - This pull request updates the smoke to follow the current arc: pick the Claude source tile, press Connect, launch, then assert the seeded chat greeting, the opening question card, and the absence of heartbeat runs > - The benefit is a release pipeline that can promote current master again, with the smoke asserting the product's current contract instead of a removed one ## Linked Issues or Issue Description **What happened?** The scheduled nightly lane of `release.yml` has failed every night since 2026-09-03. The `smoke_nightly / smoke` job fails in `tests/release-smoke/docker-auth-onboarding.spec.ts` at `expect(connectButton).toBeVisible()`. No nightly has published since `2026.902.0-nightly.0`, so no beta can promote recent master. **Expected behavior** The release smoke follows the current onboarding arc and passes against a healthy published artifact. The nightly lane promotes the newest green canary each night. **Steps to reproduce** 1. Run `PAPERCLIPAI_VERSION=2026.910.0-canary.5 SMOKE_DETACH=true ./scripts/docker-onboard-smoke.sh`. 2. Run `pnpm run test:release-smoke` against the container with the previous spec. 3. The spec times out waiting for a "Connect" button. The step now shows a model-source tile row first, and after launch the seeded task is a chat with no heartbeat run. **Paperclip version or commit** Reproduced against published `paperclipai@2026.910.0-canary.5`; spec updated on current `master`. ## What Changed - The spec answers the connect step's model-source question: it asserts the "Connect a model" heading, picks the Claude tile from the "Model source" radiogroup, and only then waits for the "Connect" footer button (#12796, #12801 rebuilt the step around that question). - The spec replaces the assignment-run poll with the first-task chat contract from #13068: it asserts the deterministic greeting ("Welcome to Paperclip!"), the opening question card ("What would you like to do?"), and that the lead has zero heartbeat runs, because launch must not wake the assignee before the user answers. ## Verification - Launched the CI harness locally: `scripts/docker-onboard-smoke.sh` with `PAPERCLIPAI_VERSION=2026.910.0-canary.5` (the newest canary, the one the next nightly would promote). - `pnpm run test:release-smoke` against that container: 1 passed. - The previous spec against the same container reproduces the CI failure mode first (Connect-button wait), and after the connect-step fix, the run-poll failure — both match the nightly logs. ## Risks - Low risk: the change touches only the release smoke spec. If onboarding's copy for the greeting or the question card changes, the smoke fails loudly at that assertion, which is this suite's job. ## Model Used - Claude Fable 5 (`claude-fable-5`), via Claude Code CLI, extended thinking and tool use enabled. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
daea92b647 |
feat(server): accept a Cloud control assertion on the task-drain endpoint (#13125)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The server has a task-drain admission hold so operators can stop new agent work and wait for quiescence before maintenance > - Cloud deploys restart tenant containers, but the Cloud control plane has no sanctioned credential for the drain routes, so agent runs are killed mid-restart > - The only Cloud credential this server trusts is the runtime identity assertion, deliberately scoped to the one-time bootstrap health call > - This pull request adds a disjoint, action-bound Cloud control assertion accepted only on the task-drain endpoint > - The benefit is that Cloud can hold new work and drain a stack before it restarts the container, through the same authorization and audit paths a human operator uses ## Linked Issues or Issue Description Refs #12485 (the task-drain admission hold this makes reachable for the Cloud control plane). **Problem or motivation** Cloud deploys restart the container without stopping agent work first. The task-drain hold from #12485 exists for exactly this, but its routes require instance-admin board authority. The Cloud control plane holds no such credential: the runtime identity assertion is accepted only on `GET /api/health`, by design. So in-flight runs die at every deploy. **Proposed solution** A second, deliberately disjoint use of the same Cloud signing key (`PAPERCLIP_CLOUD_RUNTIME_IDENTITY_JWKS`): a control assertion with its own JWS type (`paperclip-cloud-control+jwt`), its own audience, an `action` claim, a request id, and a short maximum lifetime. A new middleware accepts the `x-paperclip-cloud-control` header only on `/api/instance/task-drain`, binds each method to one exact action (`task-drain:read` / `task-drain:start` / `task-drain:stop`), verifies the assertion against the configured JWKS and `PAPERCLIP_CLOUD_STACK_ID`, and installs a synthetic instance-admin board actor so the existing route authorization, validation, transactional audit, and activity publishing run unchanged (audit rows record actor id `paperclip-cloud`). The header is rejected with 400 anywhere else, so it can never become an ambient credential. The board mutation guard exempts the new `cloud_control` source exactly like the other non-browser lanes. **Alternatives considered** Widening the existing runtime identity middleware would conflate a one-time bootstrap claim with a repeatable management credential and weaken both. A per-stack minted instance-admin API key would work with no auth change but adds a long-lived privileged credential per tenant to store and rotate. The action-bound short-lived assertion keeps authorization per-call and stateless. **Additional context** Self-hosted instances have no `PAPERCLIP_CLOUD_STACK_ID` and reject every assertion — the feature is inert off Cloud. A runtime identity token cannot replay as a control token or vice versa (disjoint `typ` and `aud`, covered by tests). The Cloud-side caller (drain before deploy, bounded quiescence wait) lands separately in the Cloud control plane. ## What Changed - `server/src/services/cloud-runtime-identity.ts`: `verifyCloudControlAssertion` plus the control header/audience/type/action constants, reusing the existing JWKS resolution, JWS parsing, and lifetime discipline. - `server/src/middleware/cloud-control.ts` (new): accepts the header only on the task-drain endpoint, per-method action binding, installs the synthetic instance-admin actor on success, 401 on invalid assertions, 400 anywhere else. - `server/src/app.ts`: mounts the middleware directly after the actor middleware, so a valid assertion replaces whatever actor the request otherwise resolved to. - `server/src/middleware/board-mutation-guard.ts`: `cloud_control` joins the non-browser exemptions. - `server/src/types/express.d.ts`, `server/src/services/authorization.ts`: `"cloud_control"` added to the actor source unions. ## Verification - `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/cloud-control-task-drain.test.ts server/src/__tests__/instance-settings-routes.test.ts server/src/__tests__/heartbeat-task-drain.test.ts server/src/__tests__/heartbeat-scheduling-suppression.test.ts server/src/__tests__/cloud-runtime-identity.test.ts` — 87 tests, all passing. - `pnpm --filter @paperclipai/server exec tsc --noEmit` reports no new errors against the base commit's known pre-existing set. - The new suite covers: acceptance per method, cross-action rejection, unknown-action rejection, runtime-identity-token replay rejection, wrong-audience rejection, wrong-stack and self-hosted rejection, expiry and oversized-lifetime rejection, unknown-key rejection, request id validation, endpoint containment (400 elsewhere, 400 on unbound methods), pass-through without the header, and the mutation-guard exemption. ## Risks Low risk, additive. No behavior changes without the header; the header grants nothing outside the one endpoint; each assertion authorizes one action for at most five minutes; the existing route-level validation, queued transitions, and audit writes are unchanged. The browser-facing Cloud proxy strips Cloud headers, and possession of the shared tenant-session token cannot mint an assertion (signing key never leaves Cloud). ## Model Used Claude (Anthropic) — Fable 5 (`claude-fable-5`), extended thinking, agentic tool use via Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (module doc comments carry the contract) - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge |
||
|
|
bce976d60d |
feat: bind an agent to a Codex login whose account differs from the company default (#13067)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `codex_local` adapter signs agents in to OpenAI, and a company keeps one default Codex identity in its shared company home > - A login with a DIFFERENT account than the company default is deliberately kept out of the shared home — one agent's sign-in must not switch every unbound agent's credentials — but that left the cross-account login inert: nothing connected the agent the operator was configuring to the credential the login stored > - The stored credential and its company secret already exist; only the last mile — an agent actually using them — was missing > - This pull request reports a non-secret binding claim on the authenticated login and lets the agent page bind that one agent's `CODEX_HOME` to the account's secret, exactly and only when the identities differ > - The benefit is that multi-account Codex becomes one click on the agent that needs it, with company-wide identity untouched ## Linked Issues or Issue Description **What happened?** On an agent's detail page, "Sign in with Codex" using a different OpenAI account than the company default succeeds but changes nothing for that agent. The credential lands in the per-identity store and a company secret names it, but the agent keeps using the company default. The Test keeps reporting that authentication is needed, and no repeat login helps. **Expected behavior** When the operator deliberately signs an agent's page in with a different account, that agent starts using that account. Agents that were not part of the action keep the company default. A same-account login keeps working through the shared company home with no per-agent pinning. **Steps to reproduce** 1. Configure a company whose Codex home holds account A. 2. Open a `codex_local` agent's detail page with a sandbox environment and complete "Sign in with Codex" using account B. 3. Press Test. Before this change the agent still resolves account A and the authentication-needed check returns. ## What Changed - `packages/adapters/codex-local` — the prerequisite shield: `isCodexAuthCachePath` recognizes per-identity credential-store entries, and `seedManagedCodexHome` refuses to symlink, heal, or API-key-overwrite an entry's `auth.json`. The seeding pass runs before every probe and execute; without the shield, an agent bound to an entry would have its stored login silently swapped for the host credential. Static shared config files still copy in. Rotation already survives binding: the sandbox copy-back writes rotated credentials into the identity-keyed store slot. - `server` — the promotion records whether the company default home ended on a different account than the login (any read failure degrades to `false`, so the client can never be told to bind wrongly). After the terminal commit, the routes layer remembers a non-secret claim — the opaque account-home secret id plus that verdict — in a bounded in-memory map, and merges it into the owner read of an `authenticated` `codex_local` session. A restart drops the claim; the panel then shows plain success. - `packages/shared` — `CodexAccountBindingClaim` on the owner session response. It carries no account identifier and no credential byte. - `ui` — the login panel reports the claim upward once. The edit-mode form binds the agent's `CODEX_HOME` to the secret and saves in one step, only when `companyIdentityDiffers` is true. Same-account logins bind nothing on purpose: the company-home refresh already carried them, and an unbound agent keeps following the company default across rotations. Create mode is unchanged. ## Verification - Adapter suite: 381 passed, 1 skipped (includes the new store-entry shield tests and the path-predicate cases). - Server suites (8 files): 130 passed, 15 skipped — including two new route tests that drive a login to `authenticated` and assert the claim with both identity verdicts. - UI render suite: 85 passed — including a panel test that the claim is reported upward exactly once. - `tsc --noEmit` clean in `packages/shared`, the adapter package, and `ui`; `server` clean for the touched file. ## Risks - The bind changes one agent's configuration through the normal agent-update patch, initiated by the operator's own login on that agent's page. The failure direction of every fallback is "offer nothing": a missing claim, a restart, or an unreadable company home all degrade to no bind. - The seed shield narrows what the seeding pass may touch; homes outside the credential store behave exactly as before, covered by the existing seed tests. - Builds on the sign-in credential-resolution fix (#13064), now merged; this branch is rebased onto master and the diff contains only the binding feature. Supersedes #13066, which GitHub auto-closed when its stacked base branch was deleted on merge. ## Model Used Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended thinking, agentic tool use in Claude Code (terminal). **Related PRs (searched; no duplicates found):** #12740, #12082, and #9621 touch adjacent Codex credential sync paths; #8495 is the standing hardening effort for probe auth seeding. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (no standalone docs cover this flow; the behavioral contracts are documented in-line at each changed site) - [x] I have considered and documented any risks above |
||
|
|
01ad858492 |
ci: raise the multi-arch Docker publish timeout to 120 minutes (#13114)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The Docker workflow publishes the server images that all deployments pull, including the `sha-*` images that downstream consumers deploy > - The `build-and-push` job builds for linux/amd64 and QEMU-emulated linux/arm64, and that build now takes more than its 60 minute job timeout > - Every run dies at the timeout, and each doomed hour-long run holds the per-ref concurrency slot, so queued master pushes supersede each other and no image publishes at all > - This pull request raises the multi-arch job timeout to 120 minutes > - The benefit is that image publishing works again, with headroom for the build to grow ## Linked Issues or Issue Description Related: #12821 replaces the QEMU-emulated arm64 build with native runners — that is the durable fix for the build duration itself. This PR is the immediate unblock so images publish again while #12821 lands. No existing issue for the outage. Description follows the bug report template: **What happened?** The `docker.yml` `build-and-push` job hits its 60 minute `timeout-minutes` cap on every run. The last fully successful `docker.yml` run was September 2. Since then almost every run ends `cancelled`: the multi-arch build is killed at the timeout, and runs queued behind it are superseded by newer master pushes before they can start. The amd64-only `build-and-push-cloud` job often still succeeds inside those cancelled runs, which masked the breakage. **Expected behavior** Every master push and canary tag dispatch publishes its `sha-*` production and cloud images, and the `promote_canary_channel` job runs. **Steps to reproduce** Look at the runs of the Docker workflow on master: `gh run list --workflow docker.yml --branch master`. Nearly every run since September 5 ends `cancelled` or `failure`. Open a cancelled run: the `build-and-push` job runs for 61+ minutes and its "Build and push" step ends `cancelled` at the job timeout. The last runs that succeeded (September 2) took 39 to 54 minutes for the same job. ## What Changed - Raise `timeout-minutes` on the `build-and-push` job from 60 to 120, with a comment that explains why. The amd64-only `build-and-push-cloud` job keeps its 60 minute cap. ## Verification - `actionlint .github/workflows/docker.yml` reports no issues in this change (only pre-existing info-level shellcheck notes in untouched steps). - Compared job durations across the last successful runs (39-54 minutes) and the recent timeout kills (61+ minutes) to confirm the cap is the failure cause. - After merge, the next master push should produce a `docker.yml` run that completes with both build jobs green. ## Risks Low risk. The change only gives the existing build more time. A genuinely hung build now occupies a runner for up to 120 minutes instead of 60. The slow arm64 emulated build itself is worth a separate look (native arm runners or splitting the platforms), but that is a larger change than this outage fix. ## Model Used Claude (Anthropic) — Fable 5 (`claude-fable-5`), extended thinking, agentic tool use via Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (no code paths changed; workflow linted with actionlint) - [x] I have added or updated tests where applicable (not applicable for a CI timeout value) - [x] I have updated relevant documentation to reflect my changes (the workflow comment documents the rationale) - [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 |
||
|
|
fe5e68d7a5 |
fix: make Codex sign-in and the environment test agree on the credential a run uses (#13064)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The `codex_local` adapter signs agents in to OpenAI with a device-code login, and the agent page has a Test button that probes the sandbox with the credentials a real run would use > - The login stored its credential where the Test never looked: the company Codex home kept an old shape-valid credential, so the Test failed with "authentication needed" right after a successful sign-in > - The Test also staged a different Codex home than a real run resolves, so the Test and real runs could disagree in both directions > - This pull request makes the login, the seeding pass, and the Test probe agree on one credential resolution > - The benefit is that a sign-in from the agent page fixes the Test on the next click, and a green Test means the same thing a real run experiences ## Linked Issues or Issue Description **What happened?** Sign in with Codex works during onboarding but not on the agent detail page. The operator completes the device-code login. The panel reports success. The Test button still reports that authentication is needed. No number of repeat logins changes the result. Three defects combine to cause this: 1. The device-login promotion only wrote the company default Codex home when that home held no shape-valid credential. A stale credential (for example a symlink to an old host login) blocked the write forever, so the fresh login stayed invisible to the Test. 2. The seeding pass that runs before every probe and execute replaced a same-identity regular-file `auth.json` with a symlink to the host credential, with no freshness comparison. Even a freshly promoted credential was deleted on the next Test. 3. The sandbox hello probe always staged the company default home. An agent with a configured `CODEX_HOME` was tested against one credential and ran with another. **Expected behavior** A completed sign-in updates the credential the Test probes. The Test stages the same Codex home a real run resolves. A stale credential never outranks a strictly newer one from an interactive login. **Steps to reproduce** 1. Configure a company whose Codex home holds a shape-valid credential that no longer authenticates (for example an old host login symlink). 2. Open a `codex_local` agent's detail page with a sandbox environment and press Test. The result shows the authentication-needed check. 3. Complete the "Sign in with Codex" device-code flow from the panel. 4. Press Test again. Before this change the result still shows authentication needed. ## What Changed - `packages/adapters/codex-local/src/server/adapter-auth-promotion.ts`: the promotion writes the company default home unconditionally. The shared `last_refresh` merge predicate scopes the write. It seeds an absent or unusable slot, refreshes a same-identity slot only with a strictly newer credential, and keeps a slot a different account or an API-key file holds. The atomic rename replaces a symlinked `auth.json` at the link itself. It never writes through into the host home. - `packages/adapters/codex-local/src/server/codex-home.ts`: the same-identity heal in `seedManagedCodexHome` is freshness-aware. A regular-file credential is swapped for the shared symlink only when the shared source is strictly fresher by `last_refresh`. Ties and unparseable timestamps keep the file, which matches the predicate's fail-closed direction. A genuine stale copy still heals as soon as the host credential rotates past it. - `packages/adapters/codex-local/src/server/test.ts`: the sandbox hello probe prepares and stages the same home a real run resolves. The identity-anchored cache vend runs first. A configured managed `CODEX_HOME` is seeded in place and staged. A genuine external override is staged as-is and never seeded or mutated. - Tests: new pins for the strictly-newer company-home refresh, the different-account keep, the symlink-replaced-without-writing-its-target property, the freshness-aware heal (newer kept, older healed, ties kept), the configured-home staging, and the external-home no-mutation proof. The remote-probe suite now pins `CODEX_HOME`/`PAPERCLIP_HOME` to scratch directories so no test can touch a real `~/.codex`. ## Verification - `pnpm exec vitest run packages/adapters/codex-local/src --root packages/adapters/codex-local` — 378 passed, 1 skipped. - Server suites for device login, reconciliation, and the codex adapter (8 files) — 128 passed, 15 skipped. - `tsc --noEmit` clean in the adapter package. ## Risks - Behavioral shift is scoped by the shared merge predicate: only a strictly newer same-identity login can displace a company-home credential, so a second account still never takes over the company slot, and API-key files are never displaced. - The heal keeps ties and unparseable timestamps instead of swapping. A kept file self-corrects on a later seed once the source is provably fresher; deleting a promoted credential is irreversible, so the failure direction is chosen deliberately. - The probe change makes the Test exercise the credential a run uses. A Test that previously passed against the company home while the agent's configured home was broken now fails honestly. ## Model Used Claude (Anthropic) — Claude Fable 5 (`claude-fable-5`), extended thinking, agentic tool use in Claude Code (terminal). Diagnosis traced through the live promotion locks, the on-disk Codex homes, and the adapter's credential-resolution code paths. **Related PRs (searched; no duplicates found):** #12740, #12082, and #9621 touch adjacent Codex credential sync paths; #8495 is the standing hardening effort for probe auth seeding. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes (no standalone docs cover this flow; the behavioral contracts are documented in-line at each changed site) - [x] I have considered and documented any risks above |
||
|
|
8f099c3f83 |
ci: dispatch a Docker build for every canary tag (#12950)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Every master merge publishes an npm canary, and downstream managed deployments consume the matching `sha-<short>-cloud` Docker image. > - The canary image relies on the master-push `docker.yml` run, whose single pending concurrency slot is superseded by every newer push. > - On a busy day the image build never survives: five consecutive canaries shipped npm packages with no cloud image on 2026-09-06, and downstream deploys starved for ~18 hours while master kept moving. > - The nightly and beta lanes already solve exactly this by dispatching `docker.yml` at their tag ref after pushing it. > - This pull request wires the canary lane into the same mechanism, so every canary tag gets an image build no master push can supersede. > - The benefit is that a published canary always has its images, and downstream release resolution stops walking back to day-old builds during busy merge windows. ## Linked Issues or Issue Description Refs #12769 / #12855 (the earlier image-publishing incident in the same pipeline, different failure mode). **What happened?** `docker.yml` serialises per ref with one pending slot (`concurrency: docker-${{ github.ref }}`, `cancel-in-progress: false`). Master pushes arriving faster than the ~50-minute build supersede the pending build indefinitely. On 2026-09-06, canaries `2026.906.0-canary.1` through `.3` (and the commits between) published to npm with no `sha-<short>-cloud` image on GHCR — the Docker run list shows `cancelled, cancelled, cancelled` for their commits. Downstream managed rollouts correctly refused to deploy image-less canaries and pinned at `canary.0` for ~18 hours. **Expected behavior** Every published canary has its Docker images. A busy merge window must not be able to prevent image publication for tagged releases. **Steps to reproduce** 1. Merge to master more often than the Docker build takes to complete, for several hours. 2. Observe npm canaries advancing while every `Docker` run for their commits completes `cancelled`. 3. Observe `ghcr.io/paperclipai/paperclip:sha-<short>-cloud` returning 404 for each of those canaries. **Paperclip version or commit** Master at `83987210` (diagnosis time); the starved canaries were `2026.906.0-canary.1`–`.3`. **Deployment mode** GitHub Actions release + image pipeline; consumed by managed cloud deployments. ## What Changed - `.github/workflows/release.yml`, `publish_canary` job: - New step after "Push canary tag": dispatch `docker.yml` at `refs/tags/canary/v<version>` — identical to the nightly and beta lanes' existing step, including the step-summary note. The dispatched run keys its concurrency off the tag ref, so master pushes cannot supersede it, and `docker.yml`'s `type=sha` mapping publishes `sha-<short>` / `sha-<short>-cloud` for any ref. - The job gains `actions: write`, mirroring `publish_nightly`. - No `docker.yml` changes: it already accepts `workflow_dispatch` for exactly this pattern. - No dry-run guard needed: `publish_canary` runs only on `push` events, so the `dry_run` dispatch input cannot reach it. ## Verification - YAML lints clean; the step is a line-for-line mirror of the proven nightly-lane step (tag source swapped for the job's existing `canary_tag` output). - The concurrency claim is docker.yml's own documented behavior: groups are per-ref, and a tag ref is distinct from `refs/heads/master`. - Not run: a live canary publish — the next master merge after this lands exercises it end to end; the worst case (double build for a canary whose master-push run also survives) is benign, since both runs push identical content-addressed tags. ## Risks - Low. Roughly one additional Docker build per canary on busy days (on quiet days the master-push run and the dispatched run both execute — duplicate work, identical images, no conflict since the sha tags are content-equivalent for the same commit). - `actions: write` on `publish_canary` matches the grant `publish_nightly` already carries for the same purpose. > 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 Claude Fable 5 (Anthropic, model id `claude-fable-5`), extended thinking, agentic tool use in Claude Code: GHCR manifest probing, Actions run-list forensics, and workflow-lane comparison. ## 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 (workflow-only change; YAML linted; no test harness targets release.yml) - [x] I have added or updated tests where applicable (not applicable — CI wiring mirroring an existing proven lane) - [x] I have updated relevant documentation to reflect my changes (the step's inline comment documents the invariant) - [x] I have considered and documented the 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 |
||
|
|
4b0e324c63 |
ci: activate the Docker context integrity gate for PRs (#12860)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Pull request CI runs through `pr.yml`, which pins the reusable `pr-trusted.yml` workflow by commit SHA, so `pr-trusted.yml` changes take effect only when the pin moves. > - PRs #12855 and #12858 added the `docker_context_integrity` job and wired it into the `verify` aggregate, but the pin still points at a commit from before them. > - Until the pin moves, a pull request that strips a committed Docker build input still merges green and breaks every post-merge image build. > - This pull request bumps the pin to the #12858 merge commit, the standard second step of every `pr-trusted.yml` change. > - The benefit is that the Docker context integrity gate now blocks merges, which closes out the 2026-09-04 image-publishing incident end to end. ## Linked Issues or Issue Description Refs #12855 and #12858 (the gate this activates) and #12769 (the incident that motivated it). **What happened?** The `docker_context_integrity` job exists on master but does not run on pull requests, because `pr.yml` pins `pr-trusted.yml` at `a0a78ee6`, which predates it. **Expected behavior** Pull requests run the gate, and the `verify` required check fails when a change strips a committed Docker build input. **Steps to reproduce** 1. Open any pull request before this change: the ci run shows no "Docker context integrity" job. 2. After this change, the job runs on every full-CI pull request and `verify` requires its result. **Paperclip version or commit** Pin moves from `a0a78ee60946a5f79f85b2bd0584fc766fae43bb` to `03609aa6` (the #12858 merge commit). **Deployment mode** GitHub Actions pull request CI. ## What Changed - `.github/workflows/pr.yml`: the `pr-trusted.yml` pin moves to the #12858 merge commit. One line. ## Verification - The pinned commit is master's current tip and contains the job, the `verify` wiring, and both probe revisions; its own CI (on #12855 and #12858) is fully green. - This PR's ci run itself executes the newly pinned workflow, so the gate's first live run is visible on this very pull request. ## Risks - Low. Identical mechanism to every previous pin bump. If the new lane misbehaves on some runner, reverting this one line restores the previous pin. > 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 Claude Fable 5 (Anthropic, model id `claude-fable-5`), extended thinking, agentic tool use in Claude Code. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass (one-line pin bump; the pinned workflow's tests ran green on #12855/#12858) - [x] I have added or updated tests where applicable (covered by the pin tests updated in #12855) - [x] I have updated relevant documentation to reflect my changes (not applicable to a pin bump) - [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 |
||
|
|
03609aa6ec |
ci: keep traceability regression tests in the Docker build context (#12858)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - GitHub Actions builds the Docker images that ship Paperclip, and the image build re-runs the runner's committed-artifact checks. > - PR #12855 restored the capability-contract files that PR #12769's context slimming stripped, and image builds then progressed one step further in the chain. > - The next check, `check:runner-workflow-traceability`, access()es every regression test its spec names — `src/**/*.test.ts` files that the same slimming block also strips. > - Every image build since #12855 merged now fails there with ENOENT, so image publishing is still down. > - This pull request restores those files with one more narrow exception and teaches the context probe to derive the required paths from the spec itself. > - The benefit is that image publishing recovers, and the probe now covers this input class without a hand-maintained path list that could rot. ## Linked Issues or Issue Description Refs #12855 (first restoration from the same incident) and #12769 (the context-slimming change). **What happened?** After #12855 merged, every `Docker` workflow run on master still failed, now inside `check:runner-workflow-traceability`: `Error: ENOENT ... access '/app/packages/paperclip-runner/src/contracts/native-execution.test.ts'`. The check access()es all 29 regression tests named by `spec/evals/stress-workflow-traceability.json`; they are `src/**/*.test.ts` files, and the `packages/paperclip-runner/**/*.test.ts` ignore rule strips them from the build context. **Expected behavior** The Docker build context must contain every file the image build reads. The context-integrity probe must catch this class on the pull request, including inputs named dynamically by a spec. **Steps to reproduce** 1. Check out master after #12855. 2. Run `docker buildx build -f .github/docker-context-checks.Dockerfile .` with this PR's probe, or the real `Docker` workflow build. 3. Observe the ENOENT above; with this PR's `.dockerignore` exception, both pass. **Paperclip version or commit** `bb920fb8` (first post-#12855 failing image build) through master tip. **Deployment mode** GitHub Actions image builds (`docker.yml`), consumed by managed cloud deployments. ## What Changed - `.dockerignore`: re-include `packages/paperclip-runner/src/**/*.test.ts` and `.tsx` — the traceability spec references only files under `src`, so the remaining test exclusions stay. - `.github/docker-context-checks.Dockerfile`: new spec-driven existence walk that replicates the traceability check's own access() loop against the exact build context. The path list comes from the spec at probe time, so a future spec change is covered automatically; the check itself still runs only inside the real image build, where `dist/` exists. ## Verification - `docker buildx build -f .github/docker-context-checks.Dockerfile .` without the `.dockerignore` exception: fails with the exact production ENOENT (`src/contracts/native-execution.test.ts`). - Same command with the exception: passes end to end (all probe stages, including the drift checks from #12855). - Static re-sweep of the remaining image-build chain steps (`build:binary`, replay goldens, semantic-action catalog) against the ignore rules: their inputs are all in the context; cargo needs no `tests` directories (no crate declares an explicit `[[test]]` target). ## Risks - Low. The exception re-adds source test files to the build context only; image contents do not change (tests are neither compiled into the production output nor run in the image build — the check only requires that the referenced files exist). - The probe addition is one dependency-free Node one-liner. > 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 Claude Fable 5 (Anthropic, model id `claude-fable-5`), extended thinking, agentic tool use in Claude Code: GitHub Actions log forensics, spec-driven path inventory, and local docker buildx verification in both failing and fixed states. ## 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 (the probe in both failing-before and passing-after states) - [x] I have added or updated tests where applicable (the spec-driven probe walk is the regression test) - [x] I have updated relevant documentation to reflect my changes (inline comments explain the invariant) - [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 |
||
|
|
bb920fb859 |
ci: keep the Docker build context complete and guard it on every PR (#12855)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - GitHub Actions builds the Docker images that ship Paperclip, and downstream deployments consume the `-cloud` image variant on every master merge. > - PR #12769 slimmed the Docker build context with a broad `.dockerignore` block for `packages/paperclip-runner`, and the block also removed three files the image build itself reads. > - The image build re-runs the runner's generated-file drift checks, so it found no committed capability contract in the context and failed on every master commit after the merge. > - PR CI never runs those checks against the Docker context, so the pull request stayed green and the breakage only appeared post-merge, on every image build. > - This pull request restores the three files with narrow `.dockerignore` exceptions and adds a PR CI job that runs the drift checks against the exact Docker build context. > - The benefit is that image publishing works again now, and the next context-slimming regression fails the pull request instead of every post-merge image build. ## Linked Issues or Issue Description Refs #12769 (the context-slimming change that exposed this) and #12608 (which committed the generated contract outputs the image build checks). **What happened?** Every `Docker` workflow run on master failed from 2026-09-04 12:58Z onward, in both the `build-and-push` and `build-and-push-cloud` jobs. The failing step reported `Generated contract drift: generated/capability/capability-contract.md` from `check:capability-contract` inside `pnpm --filter @paperclipai/server build`. The committed contract file is current — regeneration on a full checkout is a no-op. The file was simply absent from the build context: the new `packages/paperclip-runner/**/*.md` ignore rule strips the committed drift-check outputs (`generated/capability/capability-contract.md`, `generated/capability/downstream-handoff.md`), and the `packages/paperclip-runner/docs` rule also strips `docs/capability-contract.md`, which `check:capability-inventory` reads next in the chain. No cloud image published for eight hours, which stalled every downstream deployment that consumes the canary images. **Expected behavior** The Docker build context must contain every file the image build reads, and a change that removes one must fail the pull request that introduces it, not every image build after the merge. **Steps to reproduce** 1. Check out master at any commit from `af3023f1` onward. 2. Run `docker buildx build -f .github/docker-context-checks.Dockerfile .` (the probe added by this PR), or start the real `Docker` workflow build. 3. Observe `Generated contract drift: generated/capability/capability-contract.md` — while `node packages/paperclip-runner/scripts/generate-capability-contract.mjs --check` passes on the same checkout outside Docker. **Paperclip version or commit** `d593463ab` (master tip at diagnosis time; first failing commit `af3023f1`). **Deployment mode** GitHub Actions image builds (`docker.yml`), consumed by managed cloud deployments. ## What Changed - `.dockerignore`: narrow exceptions (last match wins) re-include the committed drift-check outputs (`!packages/paperclip-runner/generated/**`) and the inventory check's documentation input (`!packages/paperclip-runner/docs/capability-contract.md`). Every other exclusion from #12769 stays: no crate declares an explicit `[[test]]` target, so cargo builds without the `tests` directories, and the image build chain never runs the excluded smoke scripts. - `.github/docker-context-checks.Dockerfile` (new): a small probe that COPYs the real build context — identical `.dockerignore` semantics — and runs the dependency-independent drift checks inside it (`generate-capability-contract.mjs --check`, `check-capability-inventory.mjs`). ajv installs in an isolated directory for schema validation only; codegen checks such as `generate-protocol-schema-module` stay out because their emitted bytes vary with the ajv release and would raise false drift alarms outside the locked dependency tree. - `.github/workflows/pr-trusted.yml`: new `docker_context_integrity` job builds the probe on every full-CI pull request, and the existing `verify` aggregate now requires its result, so the guard gates merges through the same required check as the other lanes. - Activation note: `pr.yml` pins `pr-trusted.yml` by commit SHA, so the new job starts gating pull requests after the usual follow-up `ci: activate ...` pin bump once this merges. The `.dockerignore` fix needs no activation — `docker.yml` reads it directly, so image builds recover on the first master commit after this merges. ## Verification - `docker buildx build -f .github/docker-context-checks.Dockerfile .` on master (before the `.dockerignore` fix): fails with the exact production error, `Generated contract drift: generated/capability/capability-contract.md`. - Same command with the `.dockerignore` exceptions applied: passes, which also proves BuildKit honors the `!` exceptions, including the file inside the excluded `docs` directory. - `node scripts/generate-capability-contract.mjs --check` on a full checkout: passes both before and after, which confirms the committed contract was never stale — only missing from the context. - Static sweep of every script in the image build chain (`build`, `build:typescript` and their `check:*` steps) against the ignore rules: the three restored files are the only build inputs the #12769 block strips. - YAML for `pr-trusted.yml` lints clean. ## Risks - Low. The `.dockerignore` exceptions only re-add three committed files to the build context; image contents do not change otherwise. - The probe job adds one context transfer and two Node scripts per full-CI pull request run (about one to two minutes, no dependency install beyond one isolated ajv package). - The `verify` aggregate now also requires the new job, mirroring the existing pattern for the other lanes; on non-full-CI runs the job skips and `verify` asserts the skip, unchanged from how the other lanes behave. - The new job only takes effect for pull requests after a follow-up pin bump in `pr.yml` (same two-step flow as every `pr-trusted.yml` change). > 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 Claude Fable 5 (Anthropic, model id `claude-fable-5`), extended thinking, agentic tool use in Claude Code: GitHub Actions log forensics to isolate the failing check, static analysis of the build-chain scripts against the ignore rules, and local docker buildx runs to reproduce the failure and verify the fix. ## 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 (the docker probe, both failing-before and passing-after; the drift checks themselves on a full checkout) - [x] I have added or updated tests where applicable (the probe IS the regression test for this class) - [x] I have updated relevant documentation to reflect my changes (inline comments in `.dockerignore` and the probe explain the invariant) - [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 |