Commit Graph
330 Commits
Author SHA1 Message Date
DottaandPaperclip 0bb36b2c6b perf(skills): store repository packages outside Postgres
Convert legacy packages automatically, restore exact commits on cache misses, and expire unused recoverable packages while keeping warm turn checks metadata-only.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-28 17:15:19 -05:00
DottaandPaperclip f8484a9f8d fix(native): deliver selected skills to remote Codex homes (#18080)
## Thinking Path

> - Paperclip coordinates company agents and preserves their assigned
instructions and approval rules.
> - Native runs pin an immutable skill inventory for each execution.
> - Built-in remote Codex launches prepare that inventory on the
controller, but transfer only authentication, configuration, and the
separate context assets.
> - Codex needs the selected skills under its isolated home. An explicit
skill path does not load a skill outside its registered discovery roots.
> - This pull request transfers the sealed selected inventory to the
path already used by explicit skill inputs.
> - Each launch replaces stale assignments inside the authorized
workspace while preserving provider history.

## Linked Issues or Issue Description

Refs #18025. The corrected first-task instructions exist in the selected
bundle, but remote Codex must receive those bytes before it can follow
them. The legacy skill resolver work in #16646 and #9323 uses different
paths and does not repair native remote launch staging.

**What happened?**

A fresh remote native Codex run could not read its assigned first-task
skill. It produced an approval question instead of the required
confirmation. The Product E2E journey correctly rejected that question
before child creation.

**Expected behavior**

Codex receives the selected immutable skill at the same provider-local
discovery path used by explicit skill input. Removed or unassigned
skills do not remain available after a new launch.

**Steps to reproduce**

1. Prepare an isolated Codex home with one assigned skill.
2. Run the built-in remote launch staging path against a fresh remote
filesystem.
3. Resolve an explicit invocation of that skill. Before the repair, its
provider-local file is missing.

## What Changed

- Transfer only the prepared selected skill inventory into the isolated
remote Codex home before other launch writes.
- Reject writable files, symlinks, missing entries, and extra unassigned
packages in the controller projection.
- Validate each provider-home path component below the authorized
workspace. Reject redirected retained paths before deleting stale
skills.
- Create the private discovery root before native sandbox transfers,
which omit the source-root metadata and can ignore the requested
directory mode.
- Replace stale or empty inventories without changing provider
conversation history, preconfigured homes, other providers, or
plugin-provided launch preparation.
- Exercise the real home materializer and turn resolver through the
existing test-only Runner surface. Document the remote discovery
contract.
- Synchronize an existing Telegram attachment-failure test with the
durable provider-effect commit, preserving its required final states.
This CI repair is a separate test-only commit.

## Verification

- The new production-staging regression failed before the repair because
the resolved skill file was absent.
- All 23 focused staging checks pass. They cover delivery, file modes,
empty/revoked inventories, history retention, extra packages, writable
files, source symlinks, target symlinks, redirected ancestors on
sandbox/SSH, and an authorized workspace alias. The filesystem fixture
packs and extracts actual tar bytes without applying the requested root
mode; it preserves exact projected-file digests and executable bits.
- The unchanged materializer and prepared-launch contracts passed 26
tests. Eight selected native caller checks passed; other cases in that
filtered run were not selected.
- Independent probes used official Codex 0.160.0, the real materializer,
production staging, the real resolver, and a local model endpoint. The
original staging supplied no skill message. The final staging supplied
the complete selected skill body with its exact SHA-256. A final probe
also ran production Daytona `performSyncIn`, backing only its SDK
exec/upload/chmod edge with the local filesystem under umask `022`: the
pre-review source reproduced root `0755`, and the final source retained
root `0700`, package `0555`, file `0444`, and the exact selected digest.
All model requests returned local 403; there were no upstream requests
or credentials.
- Full local `pnpm -r typecheck` and `pnpm build` passed on verification
commit `e7d4e7a9`, based on `60b8089a`. The full local `pnpm test:run`
on that frozen tree was not completed: later embedded PostgreSQL startup
failed because the host could not allocate semaphore sets (`semget`,
SEMMNI/SEMMNS), and the owned attempt was stopped with its log
preserved. Its earlier four caller-fixture failures and one
workspace-conflict failure are recorded separately below; the later
resource error is not an explanation for them. Delivery commit
`567d838d` replayed the initial six-file patch onto `ee67d2ec`;
production was last changed in `23456f51`, followed by test-only commits
`002fa4a7` and `6e8fa595`. All 24 staging checks, all 26
materializer/prepared-launch checks, and the complete native executor
file (968 tests, zero skipped) pass locally. Server typecheck also
passed after these test edits. The complete CI matrix passed on
`002fa4a7`; current-head CI is tracked separately.
- Initial-head CI exposed four caller fixtures that manually wrote
auth/config without preparing the skills inventory. The same four
failures reproduced locally. Those fixtures now use the real home
preparer for their existing empty inventory and assert its transfer; all
34 retained/replacement scenarios and the complete 966-test caller file
pass. A sandboxed full-file attempt could not bind local PostgreSQL
(`EPERM`); it was stopped with its log preserved, then the identical
command passed with local fixture access. Initial-head CI also recorded
timeouts in workspace recovery, approval-queue backoff, and heartbeat
attribution. Their three complete files pass unchanged locally (102
tests); the next CI head also passed those cases. The original slowdown
remains unexplained. The consequent approval cleanup foreign-key failure
is a timeout teardown race already recorded in the owning worker
documentation.
- The frozen full local run also observed an existing workspace-conflict
test fail. The test and owning workspace code are unchanged between the
verification and delivery trees, and the isolated delivery case passes.
The original failure remains unresolved: stopping the later
resource-blocked run prevented the final assertion detail from being
emitted. That isolated pass does not replace the earlier result.
- CI on `23456f51` caught a Telegram test reading
`provider_effect=processing` after observing the provider mock call.
Production commits `processed` later, so the test now waits for the
unchanged complete durable-state assertion. All 18 selected Telegram
attachment/media cases pass (the other 1,670 cases were not selected).
The same CI attempt also recorded an E2E runner shutdown followed by
cancellation, without a failed Playwright assertion; the necessary new
test-only head reruns the matrix. Earlier failures remain preserved and
are not reported as passes.
- Review requested an executor-level preconfigured-home negative test.
Retained and replacement workspace cases now drive the actual launcher,
assert successful context staging, and exclude the isolated home's
skills/auth/config transfers. A counterfactual that removes only the
executor exclusion makes both tests fail; the exact production bytes
were restored before the complete 968-test pass. Flat and nested
selected package delivery is also covered. Optional arbitrary
remote-stderr expansion is deferred; the repair keeps the existing
closed error code and report surface.
- Final head `6e8fa595` passes the complete CI matrix, including
typecheck, build, Runner, browser, and aggregate gates. Two
first-attempt jobs were interrupted by runner shutdown/lost
communication; one unchanged-head rerun of those jobs and their
aggregates passed. The underlying host interruption cause remains
unknown. Both current-head automated reviews are 5/5 with the
implemented finding resolved.
- The original checked-in lockfile fails a fresh frozen install on the
baseline. The repository's maintained resolution-then-frozen sequence
passes. No lockfile change is included.
- Independent source review found and then verified the
retained-ancestor guard. This PR does not claim that the full live Cloud
onboarding campaign has passed. It changes no journey assertion or
approval gate.

## Risks

Launch preparation adds an asynchronous inventory walk, one bounded
remote cleanup command, and one transfer of the selected skill tree.
Those costs grow with selected files and bytes and occur only at
provider launch. A failed validation, cleanup, or transfer prevents
launch. Remote Node is already required by the shared SSH/sandbox
launcher. The selected packages remain read-only; the private discovery
root retains Codex's normal writable mode. No database, API,
credential-routing, or deployment change is included.

## Model Used

OpenAI Codex based on GPT-6, with reasoning, source inspection, tool
use, and code execution. The host does not expose the exact serving
model ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 16:37:13 -05:00
DottaandPaperclip c74171d620 fix(recovery): retire superseded native workspace retries (#18077)
## Thinking Path

> - Paperclip coordinates agents while retaining their work and
execution authority.
> - A failed native run can schedule an exact-session retry and retain a
sandbox.
> - An explicit task Retry can already have completed successfully on a
successor.
> - Recovery correctly refuses the old run after its task execution lock
changes.
> - It nevertheless leaves that old retry scheduled and its workspace
without a preservation owner.
> - This change retires that proven superseded retry and registers
exact-source preservation together.
> - Existing stop receipts and saved-file verification still control
workspace switching.

## Linked Issues or Issue Description

**What happened?**

A native sandbox run failed before starting a provider turn. An explicit
Retry completed on a linked successor. The original coordinator remained
in `retryable_failure` with an active sandbox lease. Restart recovery
returned `issue_execution_lock_changed`, while the ordinary sweep kept
delaying it. A pending workspace selection then made every new task run
fail during setup.

**Expected behavior**

Stop replaying a failed retry after its linked explicit successor has
completed. Preserve the original files through the existing system
worker. Keep the current task, ownership, pending choice, and unresolved
action outcomes intact.

**Steps to reproduce**

1. Persist a failed, unowned native run with a prepared remote workspace
and `retryable_failure` coordinator.
2. Complete a same-company/task/agent explicit Retry linked to that run.
3. Release the task's old execution lock and schedule a workspace
selection.
4. Run startup or ordinary retry recovery. Observe the old retry remain
scheduled and the selection fail with an unfinished-recovery conflict.

**Paperclip version or commit**

Regression reproduced against `644937c931`. The current repair is based
on refreshed master `60b8089a44`.

**Deployment mode**

Native Runner with remote sandbox workspaces. The reported runtime used
ACPX Claude with per-turn lifecycle. The original provider
session-resume rejection is not independently reproduced or claimed
fixed here; this PR addresses the subsequent stranded recovery.

Related: #17839 records preservation when restart classification becomes
terminal. This change handles the earlier lock-mismatch return and
ordinary retry admission after a completed explicit successor. It uses
the same preservation service and does not require that PR.

## What Changed

- Share a narrow superseded-retry settlement between startup recovery
and the ordinary retry sweep.
- Require a failed source with no coordinator owner or process, its
exact prepared source lease, and a completed linked successor under the
same company, task and agent.
- Atomically retire replay and register preservation. Do not alter task
state or create another provider run.
- Add PostgreSQL lifecycle/safety regressions, a real-file preservation
and workspace-selection regression, and execution/map documentation.

## Verification

- Red: both startup and ordinary admission regressions left the old
coordinator in `retryable_failure` with no preservation obligation.
- Green: the same two cases retire the retry and retain the exact lease
without another run or task mutation.
- The assembled PostgreSQL/filesystem regression passes: workspace
selection remains blocked before preservation, the existing service
saves `saved.txt` and preserves newer local work, then the normal
selection guard applies the pending shared workspace.
- All 90 native retention/resumption cases pass. Three neighboring
startup-recovery cases pass, including the blocked-owner inventory. Full
recursive typecheck and full build pass at runtime head `23ddb213b4`;
final `19d7738ae3` only moves the function comment into execution
documentation. Map, module-boundary and diff checks pass. The duplicate
full local Vitest run was stopped after 20 minutes in its first long
general shard once the complete current-head hosted test gates passed;
no complete local-suite pass is claimed.
- Current-head CI has 53 passing checks and two intended Storybook
skips, including full typecheck, all test shards, build, Runner
verification, browser shards and both aggregate gates. The separate
`commitperclip PR Review` job is still queued on `ubuntu-latest` with no
assigned runner; its outcome remains pending. Greptile reviewed exact
head `19d7738ae3` at 5/5, with zero unresolved threads.
- Live acceptance passes on exact final source `19d7738ae3`: a
disposable Daytona Linux sandbox, the current immutable staging fleet
snapshot, SDK 0.203.0, a Darwin arm64 source host and Node 26.4.0. The
real native workspace preparation/export and provider stop/start paths
preserve an unpredictable report and newer host files. The ordinary
workspace-selection guard stays blocked until preservation commits, then
applies the pending shared workspace.
- The old workload's start count and side-effect marker each remain one.
Recovery creates no new run or native result. The sandbox finishes
stopped and is then deleted by the probe; a final provider read confirms
it is absent.
- A second live acceptance also passes on the original runtime's older
immutable snapshot with the source explicitly archived before recovery.
It verifies cold source reopening, the same report/newer-file checks,
one workload start and side effect, pending workspace application, and
confirmed deletion. Its initial probe attempt used immediate
archive/deletion reads and failed during asynchronous cleanup
observation; bounded provider-state polling fixed the probe without a
product change. The abandoned probe allocation is independently
confirmed absent.
- Scope: database fixtures represent the already-failed run and
completed explicit successor. The old workload is a persistent shell
process with observable file/side-effect markers, not a paid Claude
turn. This qualifies the repaired recovery handoff and real provider
preservation; it does not reproduce the initial ACPX session-resume
rejection.
- The original hosted task has only been inspected read-only. No rollout
or original-task recovery is claimed.

## Risks

- Incorrect successor classification could retire legitimate work.
Matching requires the server-persisted explicit Retry link, same
company/task/agent, later successful committed execution, no current
source execution lock, no recorded process, no coordinator owner, and no
workspace finalization owner.
- Retirement is not a stop receipt. The exact source remains retained,
unknown effects remain unknown, and workspace switching still waits for
the existing worker's stop and file-persistence proof.
- A failed preservation transaction rolls back retirement. No new scan,
retry budget, schema or public API is introduced.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use and code execution.
The host does not expose a more specific model ID or the context-window
size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — focused suites and live
acceptance; full-suite status 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 — separate template-review job
still queued as noted above
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
exact head `19d7738ae3`
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 15:15:19 -05:00
DottaandPaperclip c4b6168e08 fix(server): disclose assigned tool search page bounds (#18056)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/187/changes/paperclip/187
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the control plane for AI agents at work.
> - Native agents find connected app tools through the assigned-tool
search tool.
> - Large catalogs require small pages and an offset for the next page.
> - The input schema enforces a maximum of 20 results, but its
descriptions omit that number.
> - Providers can render the integer field as a plain number and hide
its numeric bounds.
> - This pull request puts the existing range and default in both
descriptions.
> - Agents can choose a valid page size before they make a search call.

## Linked Issues or Issue Description

**What happened?**

An agent can request `limit: 50` for `paperclip_search_assigned_tools`.
The tool rejects the call with `invalid_tool_call` at
`/properties/limit/maximum`. Its model-visible description does not
state the accepted range.

**Expected behavior**

The tool description and the `limit` description must state the range of
1 to 20 and the default of 5. Agents can use `nextOffset` to read more
results.

**Steps to reproduce**

1. Inspect the assigned-tool search description in a provider tool list.
2. Render the integer schema as a TypeScript number field.
3. Request `limit: 50` without a visible page-size bound.
4. Observe the validation error. Retry with a valid size and offset.

### Hypothesis and thesis for a fix

The numeric schema is correct, but the descriptions omit the page limit.
Put the existing range and default in text that all providers can see.
Keep the strict validation in the assigned-tool discovery owner. This
should reduce avoidable retries. It does not guarantee that every model
call will be valid.

## What Changed

- State the accepted range and default in the search description and the
`limit` property. Add the existing default as schema metadata.
- Test the tool listing and calls through the real HTTP MCP bridge for
both compact delivery paths.
- Document the page size and offset procedure in the Runner README and
verification maps.

## Verification

- Red: the two new bridge tests fail against the unchanged
implementation because the listing omits the numeric guidance.
- Green: all 37 tests in
`server/src/services/native-runtime/assigned-mcp-tools.test.ts` pass
after the change. The tests cover default pages, a 20-result page,
offset continuation without duplicates, and rejection of 21 and 50.
Existing tests cover grants, revocation, modes, approvals, aliases, and
schema chunks.
- Current head `7d658d0c4e4d9db3feb53a5c508214440ff058c4`: 37/37 focused
tests pass locally. Greptile is 5/5 with no unresolved threads.
Current-head CI is green, including typecheck, build, unit tests, Runner
checks, and all browser shards ([CI run, attempt
2](https://github.com/paperclipai/paperclip/actions/runs/40733284523/attempts/2)).
Browser shard 7 initially failed in a newly merged agent YAML editor
test when its clipboard read included the whole page. The single retry
passed without a code change; the exact cause is unconfirmed. The
original failure remains in [the CI
log](https://github.com/paperclipai/paperclip/actions/runs/40733284523/job/122975224906).
- Run the focused suite from `server/`: `pnpm exec vitest run
src/services/native-runtime/assigned-mcp-tools.test.ts`.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- The bridge uses real local HTTP. The app gateway uses synthetic
descriptors. No deployed build or live model improvement is claimed.
- Full local verification is incomplete. Recursive typecheck and server
typecheck require `cargo`, which this workspace lacks. A direct server
TypeScript check was killed by the workspace. The full test suite had no
final verdict before the resource stop. CI must supply the remaining
verification.

## Risks

Low risk. This change describes existing limits and adds default
metadata. It does not change search execution, page caps, gateway
access, revocation, approvals, or audit. Models can still send invalid
calls. This change has not measured their future retry rate.

## Model Used

OpenAI Codex, GPT-6 family, with tool use and code execution. The exact
provider model ID and context window are not exposed to 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, its capabilities, and unavailable
model metadata
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs
- [x] I have described the issue in-PR following the bug report fields
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] The public branch name describes the change and has no internal
task ID
- [x] I have run the focused tests locally and they pass
- [x] I have added tests for the reported failure
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open recommendations or follow-ups
- [x] I will address reviewer comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 13:55:48 -05:00
Nicky LeachandPaperclip a2fbce9305 Fix plugin session and directory reuse on follow-up turns (#18045)
## Thinking Path

> - Paperclip preserves task state when agents receive follow-up work.
> - Plugin computers keep their process state outside the controller.
> - A local receipt proves that a previous plugin run suspended.
> - A cold resume left that receipt in place after the session became
live.
> - The next warm follow-up rejected the stale receipt as an identity
mismatch.
> - A separate follow-up path also treated a fresh task directory as a
Git worktree.
> - This PR consumes the obsolete receipt after admission and preserves
the bound directory on follow-up.

## Linked Issues or Issue Description

Related: #17820. This change retains the controller restoration added by
#18018.

**What happened?**

A plugin session resumed from a suspended checkpoint and completed a
turn. Its next warm follow-up failed with
`runner_state_identity_mismatch:
prior_owner_terminal_state_indeterminate`. The journal had the completed
run's identity. The local suspension receipt still had the preceding
run's identity. Two separate task histories showed this sequence.

After a fresh retry completed in a repository-free plugin directory, an
ordinary follow-up could instead fail with `The selected plugin
environment does not support Core Git worktree preparation.` The saved
task settings contained only `mode: isolated_workspace`, which
introduced the default Git strategy on the next admission.

**Expected behavior**

Keep the same admitted provider session during warm follow-ups. Reuse
the saved plugin task directory without Core Git preparation. Retain
ownership checks and explicit strategy settings.

**Steps to reproduce**

1. Complete a warm plugin task and let its session suspend.
2. Resume the checkpoint and complete another turn.
3. Send a follow-up while that session remains warm.
4. Separately, complete a fresh retry in a repository-free plugin
directory and send an ordinary follow-up.

**Paperclip version or commit**

Both regressions reproduce against base `820c45846` with the added
tests.

**Deployment mode**

Hosted plugin execution. Local reproduction uses the real filesystem and
a disposable PostgreSQL 18 database, with synthetic provider execution.

## What Changed

- Remove the local plugin suspension receipt after provider recovery and
durable run admission publish a live session. Admission still checks the
receipt first. Normal suspension writes a new receipt.
- Recognize a saved fresh plugin directory through its company, task,
workspace, owner, attempt and path. Use the existing directory-selection
path. Explicit strategy settings still apply.
- Add cold-to-warm, database-backed workspace-selection and ownership
regressions. Update execution semantics and session verification
recipes.

## Verification

- Red: the cold-to-warm regression failed on unchanged executor code
with `prior_owner_terminal_state_indeterminate` on the follow-up.
- Red: the PostgreSQL regression selected a Git strategy on unchanged
environment-selection code. The explicit-strategy denial case already
passed.
- Green: all 95 tests in `workspace-preparation.test.ts` and
`provider-fresh-workspace.test.ts` pass against a disposable local
PostgreSQL 18 database, selected with the existing
`PAPERCLIP_WORKSPACE_PREPARATION_TEST_DATABASE_URL` test seam.
- Green: 92 focused executor cases pass, including plugin checkpoint
recovery, warm rotation and denial cases. The full
`plugin-runner-task.test.ts` suite also passed (38 tests).
- Green: direct server check, `node node_modules/typescript/bin/tsc -p
server/tsconfig.json --noEmit`.
- Green: `node scripts/check-maps.mjs`, `git diff --check`, and a local
diff scan for secrets, personal data and live identifiers.
- Full local native suites: 988 of 1,004 cases passed. Sixteen
integration cases could not start their bundled PostgreSQL cluster. The
failure persisted outside the sandbox. These cases are not claimed as
passing. An earlier sandboxed attempt also denied process and loopback
operations; those denials disappeared when run outside the sandbox.
- The first broad local commands could not locate Cargo on `PATH`. Rust
is installed under `~/.rustup`; its Cargo executable was verified. Per
the requested scope, subsequent local verification stays targeted to
changed TypeScript paths; no Rust source changed. CI Typecheck + Release
Registry and Rust verification passed on the initial commit. The
complete repository test suite was not run locally.
- Review regression: an explicit agent-level Git strategy reproduced the
incorrect directory fallback before correction. After including the raw
agent strategy in the existing check, all three targeted cases
(implicit, task-level explicit, agent-level explicit) pass. The server
TypeScript check passes after this correction.
- CI on `a81668c4b`: the first workspace-a 2/2 attempt failed in
unchanged UI `AgentActionButtons.test.tsx` (`calls clearError and
refreshes agent-related queries`, zero mock calls). [Original failed
job](https://github.com/paperclipai/paperclip/actions/runs/40717870938/job/122921463517).
That shard passed on `294c5dfc3`. The failure is retained here. The UI
shard passed on final commit `687000287`; no unrelated UI edits or local
UI suite runs were added.
- CI also exposed three existing local-directory recovery failures on
`a81668c4b`: the review correction applied the raw agent strategy guard
to local directories. [Original failed server
job](https://github.com/paperclipai/paperclip/actions/runs/40717870938/job/122921463229).
Narrowed that guard to adapter-managed directories, preserving local
recovery behavior. All 20 targeted cases (three plugin selection cases
and 17 local recovery scenarios) pass afterward, and server TypeScript
verification passes.
- Final commit `687000287d3339b7e15e35d95515b3c75c273d7a`: [hosted CI is
green](https://github.com/paperclipai/paperclip/actions/runs/40720169342),
including the corrected server shard, all other server/workspace shards,
Runner checks, typechecking and build. All 55 non-skipped PR checks
pass. Greptile scores this exact commit 5/5, with no unresolved review
threads. GitHub reports no merge conflicts.
- Pre-merge hosted acceptance was requested. The maintained deployment
CLI stopped during artifact discovery: no published private Cloud
composition exists for `687000287`. The current private build requires
canonical Core master readiness and standard-image provenance. The
Core-only branch preview omits the private computer plugin needed for
the journey. No campaign or tenant update was started; private-preview
deployment support is a separate prerequisite. No live deployment or
provider acceptance run is claimed.

## Risks

The receipt is removed only after the existing runtime publishes an
admitted session. Earlier admission failures keep their proof. A later
normal suspension creates a new receipt. The change preserves existing
identity, lifecycle and controller checks.

Directory selection remains limited to the exact bound, active,
repository-free plugin recovery directory. Foreign owners, changed
paths, wrong attempts and explicit Git strategies do not gain this
fallback. No schema, API, credential, permission or fleet-default change
is required.

Existing failed runs and recovery holds remain history. This PR does not
edit quarantined state or replay an interrupted task. Rollback restores
the previous code and can reintroduce the two admission failures.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use and code execution.
A more specific model ID and context-window size are not exposed in this
session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 10:26:12 -07:00
DottaandPaperclip 567c043b17 feat(server): expose bounded hot-upgrade readiness (#18037)
## Thinking Path

> - Paperclip coordinates agent work and keeps its authority in the
server.
> - Remote native runners can preserve execution through a server
replacement.
> - Deployment operators need evidence that current runs support that
recovery.
> - Process-local drain counters do not establish this fact.
> - This PR adds an optional, operator-only readiness observation from
existing records.
> - A deployment consumer can use that report while the existing runtime
retains recovery authority.

## Linked Issues or Issue Description

Refs #17439.

**What happened?**

A deployment cannot distinguish recoverable remote native executions
from runs that require a task drain. The existing status endpoint
reports only process-local counts.

**Expected behavior**

An instance operator can request a bounded readiness report without
stopping admission or exposing checkpoint material. Missing ownership or
persistence evidence must prevent readiness. Ordinary status reads must
keep their current cost.

**Steps to reproduce**

Run a remote native task. Read the task-drain status. It reports active
work but supplies no recovery eligibility. Deployment code therefore has
no affirmative signal to select an active-run handover.

## What Changed

- Add `GET /api/instance/task-drain?upgradeReadiness=1` for instance
administrators and existing Cloud control callers.
- Return aggregate eligibility from current run identities, controller
leases and bound opaque checkpoint headers. Unknown work, pending
admission and incomplete reads prevent a positive report.
- Bound the explicit read to 1,001 rows, encrypted headers of at most
256 KiB each and 8 MiB total, and a two-second SQL statement timeout in
a read-only transaction. Keep ordinary status reads in memory.
- Add PostgreSQL, count-transition and route authorization tests. Update
the API contract, operator docs and access maps.

## Verification

- All seven readiness cases pass against an isolated PostgreSQL 18
fixture. They cover missing checkpoints, legacy adapters, missing
process/session identities, foreign owners, expired leases, missing
lease tokens, failure state and in-flight work. The positive SQL fixture
uses the real Runner checkpoint writer and encryption. Regular sandbox
workspace identity and plugin environment-lease identity are tested with
independent IDs. Stopped/released/undispatched plugin tasks and every
mismatched identity field are rejected. Local/legacy/malformed/oversized
or mismatched headers are rejected. A held PostgreSQL table lock proves
the two-second cancellation budget, rollback/connection release and
unrelated query responsiveness.
- All 123 focused readiness, instance-settings and Cloud control
assertion tests pass, including operator-only access and no readiness
read on ordinary status requests. Runner’s 168 checkpoint tests pass.
Runner and server typechecks pass after review fixes.
- Workspace typecheck, full build, module-boundary and map checks passed
locally before the master rebase. Current-head GitHub CI is now green,
including typecheck, build, all grouped/serialized server and Runner
tests, browser shards, policy and review-dispatch checks. Greptile
completed cleanly at 5/5 for `f15fb0c7e9dfb975090cd5d791a1c8e6701275f8`;
all actionable threads are resolved.
- The broad local test run was stopped after the macOS embedded
PostgreSQL fixture failed to bootstrap. The SQL test was then run on the
isolated PostgreSQL fixture. No assertion or timeout was weakened. One
unrelated existing route test exceeded its 15-second limit under
concurrent local builds; it passed on one isolated retry and the
subsequent whole route suite passed.
- Hosted active-run upgrade acceptance has not run. This PR supplies an
observation; it does not change rollout policy or establish live
continuity by itself.

## Risks

This is an instance-wide observation, so company members and agent keys
must not receive it. A readiness snapshot can age as work changes;
shutdown and startup retain their existing execution authority and
fencing. The report does not validate a replacement artifact or
authorize a schema migration. It decrypts only bounded headers through
the checkpoint owner and delegates format/identity inspection to Runner;
full journal restoration and physical sandbox authentication remain with
recovery. No migration, recurring query, new checkpoint write or wire
protocol change is included. The additive Runner header inspection
contract reuses its existing parser.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, source inspection, tool
use and code execution. The host does not expose the exact serving model
ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass for the affected contracts;
the broad-run limitation is 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>
2026-10-28 11:28:15 -05:00
DottaandPaperclip 1ed0af4186 fix(server): wake native chat progress from committed changes (#17639)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat users receive coarse progress updates while native runs
execute.
> - A recurring chat pass scans saved run events even when no progress
changes.
> - This traffic prevents an idle database from staying idle.
> - Events, lineage changes, and publication state already identify when
projection can change.
> - This PR gives native progress its own commit-driven worker and
schedules only unfinished work.
> - Idle progress stops scanning while restart and recovery preserve
delivery.

## Linked Issues or Issue Description

Refs #17606. This is slice 29 of the recurring-server-work stack, based
on `codex/sleep-28-chat-run-milestones`. It owns native chat progress
only. Related historical optimization: #16845. The parent and this PR
must land in stack order.

**What happened?**

Native chat progress is still called by the one-second chat
reconciliation loop. It repeatedly selects run events with no new work.
Its cursor also truncates PostgreSQL timestamp precision, which can
repeat a rejected full page forever.

**Expected behavior**

Committed events and eligibility changes should wake the projection
owner. Existing rows should reconstruct work after restart. A settled
worker should have no recurring database activity. Full batches, lock
contention, and errors must retain recovery.

**Steps to reproduce**

Start an otherwise idle instance with chat history. Observe the native
progress lane in the recurring chat coordinator. For the cursor defect,
create a full page of suppressed candidates sharing a microsecond
timestamp and one eligible later candidate. The old cursor fails to
advance.

## What Changed

- Extract native progress from lifecycle milestones into its owning
service. Keep the public combined API and budget compatible.
- Register a scoped worker with the existing delivery coordinator and
scheduler. Remove native progress from the recurring chat coordinator.
- Notify before allowlisted event writes in both persistence owners.
Preserve outer commit, rollback, duplicate detection, and the ordinary
non-progress log fast path.
- Extend the existing lineage/authority notification boundary once.
Failed-publication replay and operator retry carry their issue scope.
First working publications signal progress so commit ordering cannot
strand an already-inspected event.
- Limit notification payloads to company/task IDs so wider caller inputs
never serialize database handles or private fields. Load task-binding
fields only for progress event kinds; other native/recovery events
retain their narrow lock query.
- Preserve current safe phrases, cadence, phase deduplication, provider
policy, authorization, and final-output precedence.
- Retry concrete issue/run lock contention. Disarm deleted or terminal
candidates. Preserve scoped dirty work across batches, failures, drain
and shutdown.
- Preserve PostgreSQL timestamp precision in pagination. Add a bounded
regression for the former infinite rejected-page scan.
- Document the producer audit, lifecycle contract, failures, and
remaining limits in
`doc/plans/2026-10-25-native-chat-progress-sleep-audit.md`.

## Verification

Published head: `b7ee820e49fd06c780b36b79d9b1c0883557fb73`, targeting
master after #17606 merged at
`5f0da562dbfdf3229f3cd4bb3dc742ab541986b4`. A normal ancestry merge
preserves the complete 18-path native-progress patch byte-for-byte
relative to its verified parent, with all six unrelated current master
paths intact. No new production change was introduced during final
reconciliation.

- **163 distinct selected cases pass on the verified unchanged patch:**
137 across eight complete suites (native progress, atomic event append,
all five milestone worker suites, and app admission wiring), plus 26
real chat integration cases selected by `native progress`. The other
1,595 chat integration cases were skipped, not passed.
- The full worker suites cover restart, committed events, trace
reprojection, duplicate/no-progress events, first-working publication
ordering, concrete lock contention, issue scope, backlog, drain/resume,
failures and shutdown. Settled history leaves no recurring SQL. The real
chat cases verify operator retry and replay, microsecond pagination,
authority, cadence, phase deduplication, final/question precedence and
redaction.
- The sole earlier parent conflict preserves both this slice's
issue-scoped retry wake and the exact voice conversation scope. The
current parent's milestone producers, onboarding completion guard,
identity query/read-scope coverage, migration 0397 and voice
cleanup/retention repairs remain present.
- Server production typechecking, build and module-boundary checks pass.
The selected server tests live under the excluded `src/__tests__` path
and were executed separately. Each database owner uses a new isolated
app-migrated PostgreSQL fixture.
- [Current-parent acceptance and failure
ledger](https://github.com/paperclipai/paperclip/blob/b7ee820e49fd06c780b36b79d9b1c0883557fb73/doc/plans/2026-10-25-native-chat-progress-sleep-audit.md#current-milestone-parent-acceptance-october-28)
records current counts and scope. Older combined checks and failures
retain their original revision scope and are not added to 163. No new
table, dependency, workflow, migration, or scheduler contract is
introduced.
- **Exact-head Greptile is 5/5 and all 55 current checks are clean.** No
Ponytail review is present, which is an explicitly authorized
nonblocker; no failing verdict is waived. Older head/parent reviews are
not current passes. Actual failing Ponytail findings must be fixed.
Missing/stopped/paused turns without a verdict are authorized
nonblockers; active unfinished reviews retain the original per-head
timer with a 25-minute monitor cutoff respecting the 30-minute maximum.
- No complete local repository matrix, live provider tenant, external
wake, physical host/database suspension or savings claim is made.
Following stack duties remain separate.

## Risks

- Signals are process-local under the existing single active writer
contract. Independent SQL writers or another active process need an
explicit wake integration.
- Allowlisted direct log writes now use a transaction. Native bound runs
register transaction intent; unrelated direct event types retain their
atomic-statement path.
- The shared eligibility boundary wakes both lifecycle and native
projection. It does not decide provider policy or copy event payloads.
- The existing 24-hour selection window, event-time cadence and
authority checks remain. A suppressed event is not retried just because
wall-clock time passes.
- This establishes worker quiet, not whole-instance suspension. Cloud
alarm coverage and conservative sleep gates do not change. Other chat
maintenance remains on its existing cadence.
- This actual-master reconciliation still requires fresh exact-head
review and CI before protected merge. Subsequent slices retain their own
gates.

## Model Used

OpenAI Codex, GPT-6 family, with repository inspection, code execution
and browser-test tools. The exact serving variant and context-window
size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:22:29 -05:00
DottaandPaperclip 0791da0cc5 fix(server): synchronize routine history during native status commit (#18033)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/173/changes/paperclip/173
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages work assigned to AI agents.
> - A routine stores each invocation and its execution task.
> - Native completion commits task status without using the public issue
route.
> - That route synchronizes routine history, but the native status
transaction did not.
> - A successful task could remain listed as an unfinished routine
invocation on a local instance.
> - This pull request uses the existing database projection in the
native status transaction.
> - Task status and routine history now commit or roll back together.

## Linked Issues or Issue Description

**What happened?**

A real routine execution completed successfully. Its task had status
`done` and retained its routine origin and invocation identity. Public
routine history still returned `issue_created`, with `completedAt: null`
and a linked task whose status was `done`. The existing five-minute
reconciliation runs only on cloud-managed instances. It does not close
this path for a local instance.

**Expected behavior**

An authoritative native task status change must update the matching
routine invocation through the existing routine status rules. It must
not update another task, routine or company.

**Steps to reproduce**

1. Create a routine on a local instance and run it through the public
routine API.
2. Let its native execution finish and commit the task as done.
3. Read the routine run history. Before this change, the invocation can
remain `issue_created` while its linked task is done.

**Paperclip version or commit**

The retained failure used merged production `39e811c9c5`. The missing
hook is also present on this branch's base, `8049fbf51d`.

Related: #16633 contains the existing cloud-only reconciliation. A
bounded search found no duplicate native synchronization fix.

## What Changed

- Synchronize routine history inside the native status transaction after
the task status projection.
- Require matching company, invocation and linked task before
synchronization. Preserve supported custom display origins.
- Add database-backed tests for terminal and active states, replay,
invalid custody, rollback and a real plugin-managed routine dispatch
with a custom origin.
- Keep the routine status projection in a database-only helper. Both the
routine service and native status committer use it without loading
heartbeat execution from the committer.

## Verification

- Own-source server TypeScript check passed after the helper extraction.
It includes the new test source and production dependencies. Local
package exports point at another checkout, so the check used explicit
paths to this checkout's source and disabled declaration emit.
- Existing pure `status-arbiter.test.ts`: 20 tests passed. `git diff
--check` passed.
- Initial required CI run 40711603938 built and typechecked
successfully. It executed all ten new database tests: nine passed; the
public-dispatch fixture failed because it assumed status version zero.
The fixture now reads the saved version and decision binding.
- That CI run also exposed a heartbeat mock dependency cycle. The
database-only helper removes the
committer-to-routine-service-to-heartbeat import. Required CI on the new
head must confirm both repairs.
- Initial browser shard 3/8 failed during cleanup: legacy run
cancellation waited for a heartbeat row lock. Its cause is under
investigation; the failure remains recorded.
- A local runtime-execution check failed during module import from stale
package exports, before any tests or database setup ran. It is not
passing evidence. No local database, provider or live eval was run.
- Latest-head required CI run 40717315212 executed all ten new database
tests successfully in server shard 5/12 (2,163 passed; three unrelated
skips). The heartbeat runtime suite executed 23 tests successfully in
server shard 9/12 (1,704 passed).
- Latest-head browser shard 3/8 passed all 33 tests. This does not
establish the cause of the preserved earlier cleanup lock timeout.
- Required CI run 40717315212 completed successfully on head
`2d77f4302b36303741abad07266bbe9e376ba6a5`. All 48 workflow jobs are
green after one failed-jobs-only infrastructure retry. The first attempt
had seven explicit runner shutdowns and three lost-runner communication
failures. The exact chat shard host was independently confirmed as an
AWS Spot termination. Original logs and annotations remain retained.
- Greptile completed at 5/5 on this exact head, with no outstanding
findings. All review threads are resolved. The independent follow-up
review found no issues.
- No live qualification or corrected eval pass is claimed. The PR
remains open and unmerged, with auto-merge off.

## Risks

- Matching routine executions perform the existing bounded status
synchronization queries inside the status transaction. A database
failure rolls back both projections.
- Inconsistent invocation or linked-task metadata now prevents
synchronization. No unrelated invocation is inferred or repaired.
- The existing scheduled repair remains unchanged. This PR does not
change accounting, provider behavior or eval budgets.

## Model Used

- OpenAI `gpt-6.1-sol`, with reasoning and tool-assisted source
inspection and coding. The session did not supply a 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 references)
- [x] My branch name describes the change and contains no internal
ticket id or instance-derived details
- [x] I have run relevant credential-free tests locally and they pass;
database coverage is pending CI
- [x] I have added or updated tests where applicable
- [x] I have checked documentation; the existing routine status contract
is unchanged
- [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 Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:09:49 -05:00
DottaandPaperclip 5f0da562db fix(server): wake chat lifecycle milestones from committed changes (#17606)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connected chats show safe notices when a run starts, waits,
finishes, or fails.
> - A recurring scan projected these notices even when no eligible work
existed.
> - Eligibility depends on committed run state, conversation lineage,
and current authority.
> - Existing database rows can reconstruct that work after restart.
> - This PR wakes a scoped worker from those writes and removes
lifecycle polling.
> - Native progress events keep their separate existing owner until the
next migration.

## Linked Issues or Issue Description

**What happened?**

The chat maintenance timer repeatedly scanned run lifecycle state. Empty
and settled instances still queried the database. A run-status event
alone cannot replace the scan: prompt receipts, continuation receipts,
identity changes, and restored authority can make a run eligible later.

**What did you expect?**

Committed changes wake projection. Startup reconstructs eligible work. A
completed pass stops until another relevant change arrives. Failed work
retains recovery without scanning settled history forever.

**Steps to reproduce**

Configure an automatic chat endpoint. Finish its work, or leave it
unused. Observe recurring lifecycle projection queries from the chat
maintenance callback.

Stacked on #17592. Related foundation: #15625. This PR owns lifecycle
milestones only.

## What Changed

- Preserve upstream coalesced Cloud membership writes together with
locked membership restoration and its committed chat notification.

- Signal milestone eligibility from the real Slack account-link
transaction.

- Register the lifecycle worker with the existing delivery coordinator.
Remove lifecycle projection from the periodic chat callback. Keep native
progress in a separately named lane and preserve the explicit combined
API.
- Reconstruct company/issue scopes from the existing selector. Drain
bounded batches with company fairness. Retry failures, retain writes
through drain/resume, and disarm settled work.
- Signal from supported run, presentation, interaction, receipt,
lineage, conversation, recovery, and authority writers. Preserve their
transaction ownership, including nested savepoints and uncertain
settlement. No new table is added.
- Preserve provider authorization, authored-final suppression,
responsible-user continuity, deduplication, the 24-hour selection
window, and raw-output restrictions. Keep provider interpretation in its
owner.
- Preserve PostgreSQL timestamp precision in lifecycle pagination.
Rejected submillisecond candidates must not repeat the same page and
starve later notices.
- Document producer coverage and alternate-writer dispositions in
`doc/plans/2026-10-25-chat-run-milestone-sleep-audit.md`.

## Verification

Published head: `1d056f68c5b1005933b9e12de8745bf1c4cbeeca`, targeting
master after #17592 merged at
`7d75ae0569e41786640cf09647ae8849411d2f22`. A normal merge integrates
the actual landed parent. The entire 77-path milestone patch is
binary-identical to the locally verified preparation across that
ancestry reconciliation; both unrelated master paths are preserved. The
four earlier producer/test integration conflicts retain scoped milestone
and voice notices, current onboarding completion admission, and expanded
identity query/read-scope coverage.

- **330 distinct selected cases pass on the verified unchanged patch:**
305 across 14 complete suites (all five milestone worker suites, run
identity, board claim, Cloud provisioning, auth session routes, Cloud
actor authentication, stale-lock recovery, GitHub credentials, project
Git authorization, and app admission wiring), plus 25 selected real chat
producer cases. The remaining 1,590 chat integration cases were skipped,
not passed.
- The real producer cases cover saved milestone discovery, GitHub and
Slack identity changes, account-link rollback/reconfirmation, ordinary
ingress reactivation, post-close action/delivery receipt settlement, all
ten authority-restoration paths including Cloud synchronization, and
changed native review metadata.
- Worker coverage verifies outer commit, rollback, uncertain-write
recovery, restart, bounded batching/fairness, timestamp precision,
retries, drain/resume, and settled SQL quiet. Authorization and existing
publication deduplication remain with their owning services.
- Server production typechecking, build, and module-boundary checks
pass. The tests above were executed separately. Production typechecking
excludes `src/__tests__` and does not replace those runs. Each database
owner uses its own newly created and app-migrated PostgreSQL fixture.
- [Current-parent acceptance and preserved failure
ledger](https://github.com/paperclipai/paperclip/blob/1d056f68c5b1005933b9e12de8745bf1c4cbeeca/doc/plans/2026-10-25-chat-run-milestone-sleep-audit.md#current-parent-integration-and-acceptance-october-28)
records commands, counts, producer scope, conflict dispositions, and
limits. Earlier combined-stack counts and failures keep their original
revision scope; local acceptance does not erase old CI failures.
- No new migration, queue table, dependency, workflow, or shared
scheduler contract is introduced. Parent migration 0397, bounded consent
recovery, voice cleanup/retention repairs, and runner checkpoint
restoration remain present.
- **Exact-head Greptile is 5/5 and all 55 current checks are clean.** No
Ponytail review is present, which is an explicitly authorized
nonblocker; no failing review is waived. Older reviews and parent checks
are not current passes. Actual failing Ponytail findings must be fixed;
an absent/stopped/paused turn without a verdict is an authorized
nonblocker. Active unfinished Ponytail uses its original request/start
timer, with a 25-minute monitor cutoff respecting the user's 30-minute
maximum.
- No complete local repository matrix, live provider tenant, external
alarm, physical host/database suspension, or fleet savings claim is
made. Native progress remains a separate following slice.

## Risks

- A future eligibility writer must notify the existing projection
boundary. Independent SQL writers or another active server process are
outside this process-local signal contract.
- Authority and lineage remain sensitive. The worker uses the existing
selectors and publication policy; it does not grant execution or
disclosure authority.
- Native progress and other publication maintenance still have recurring
work. This PR removes one reason, not the entire chat maintenance timer.
- Worker quiet does not prove database suspension, host sleep, or
external alarm coverage. Cloud sleep blockers remain unchanged.
- Merge eligibility requires passing current-head CI and Greptile 5/5
after this actual-master reconciliation. Subsequent stack slices retain
their own gates.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model ID and
context-window size are not exposed. Used repository inspection,
reasoning, shell execution, PostgreSQL tests, browser E2Es 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 available in this session)
- [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 documented focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:07:54 -05:00
DottaandPaperclip 820c458465 fix(runner): restore per-turn controller checkpoints before resume (#18018)
## Thinking Path

> - Paperclip coordinates agents and preserves their work between turns.
> - Remote native sessions save controller checkpoints in the database.
> - External persistence leaves a small identity marker on local disk.
> - A later `per_turn` continuation must restore that checkpoint before
it reads the controller identity.
> - The restore path handled warm sessions only, so valid per-turn
continuations failed before provider execution.
> - This PR restores the referenced checkpoint and retains the existing
ownership and lifecycle checks.

## Linked Issues or Issue Description

Related: #17439 added external controller persistence and the warm
restore path. #18011 repairs warm preparation and fresh bootstrap
checks; it does not cover ordinary per-turn continuation.

**What happened?**

A remote OpenCode run completed with `per_turn` lifecycle and saved its
controller checkpoint in the database. Its next turn reused the
normalized session. Admission read the remaining external-persistence
marker as a full controller file and failed with
`runner_state_identity_mismatch: durable_identity_unreadable`. The prior
run's complete checkpoint and harness backup still existed. The failure
occurred before provider work started.

**Expected behavior**

Restore the exact prior controller checkpoint before identity
inspection. Then apply the existing company, task, session, prior-owner
and suspended-state checks before a provider can start.

**Steps to reproduce**

1. Complete a remote native OpenCode task with `per_turn` lifecycle and
external controller persistence.
2. Send a follow-up that resumes the same saved session without a
session reset.
3. Observe admission reject the valid external controller marker before
provider execution.

**Paperclip version or commit**

Observed at `40c1ab36cdac70c85dc8fe5e912431834fdb691b`. The same
warm-only restore remains on current master.

**Deployment mode**

Hosted Linux with Daytona and native OpenCode. The original model was
`openrouter/deepseek/deepseek-v4.1-flash-1017`.

## What Changed

- Restore external controller state for ordinary remote per-turn
continuations through the existing checkpoint loader.
- Bind that read to the current company and task, the marker's run, and
the expected normalized session.
- Keep local, warm and restart-recovery paths, prior-owner checks and
harness backup checks intact.
- Refresh a prior-run projection from the latest checkpoint after a
rejected active-owner attempt. Keep current-run full state and the
existing legacy file-backed fallback intact.
- Add restoration and denial regressions, execution documentation and
session verification recipes.

## Verification

- Red: the real controller generated an external marker; a valid
per-turn OpenCode continuation failed with the exact
`durable_identity_unreadable` error before tool-authority construction.
The repair passed the same case and its ownership guards.
- Review regression red/green: a real controller advanced its checkpoint
after an active-owner rejection. Before the follow-up fix, a later valid
continuation retained a null attach seed. After the fix, it restored the
newer attach template and prepare command. Legacy full-file roots with
no database checkpoint retain their existing behavior.
- At current head `1f6589233e6121d082a0c0c4444ea895b6e8cd7c`, 86 focused
executor cases and all 14 execution-driver cases pass. Coverage includes
checkpoint restoration, direct/backup suspension, Codex, legacy files,
warm admission and canonical bootstrap, missing or malformed evidence,
wrong bindings, active/foreign owners and unsuspended runners. Tests
stop before provider launch.
- The real PostgreSQL encrypted-checkpoint integration passes, including
normalized-session refusal before write and stale-writer fencing.
Independent source review found no actionable safety defect.
- `node scripts/check-maps.mjs`, `git diff --check`, full `pnpm -r
typecheck` and `pnpm build` pass on current head.
- The local full suite did not complete: native PostgreSQL startup
failed under the host sandbox, an initial Docker rerun lacked
migrations, and the migrated retry crossed the review-fix revision
change. Logs are retained; that mixed-revision run was stopped and its
owned database removed. Full test evidence comes from current-head CI.
- Current-head CI passes: 53 successful checks, two intended Storybook
skips, none pending or failing. Greptile is 5/5 on that exact head with
no open review threads. The only manual merge conflict with #18011 was
in the verification recipes; both recipes and the unchanged per-turn
restore helper are preserved.

**Live continuation acceptance remains unverified, so this PR stays
draft.** Two disposable OpenCode/Daytona attempts never reached turns
two and three:

- At `72b49208b1`, the first turn executed tools and produced the exact
33-byte workspace note, but exceeded its four-minute settlement
deadline. The first completion lacked a registered attachment; the
second decorated a typed attachment reference with filename/size/hash
text. The strict UUID parser rejected that reference before checking a
valid criterion reference. The scoped attachment, asset and publication
receipt exist. Replaying the actual guard rejects the original input
before a database lookup; correcting only that reference passes against
the recovered row and receipt. This did not show a
publication-persistence or controller defect. The task remained
unsettled.
- At `1f6589233e`, a separately approved replacement used a temporary
prompt-only fixture change requiring exact `deliverable:<attachmentId>`
references, with metadata in `verification.detail`. Production code,
grading and deadlines were unchanged; the fixture patch was removed
afterward. This attempt had no recorded provider authentication,
harness-ready, model, tool or result event. Ingress acquisition took
84.072 seconds; transport connection took 205.835 seconds within the
239.832-second failed native execution. A local settlement GET also
timed out after 30 seconds. The underlying startup stall is unresolved;
these observations do not establish a remote provider outage. Final
recovery was blocked with `ambiguous_remote_recovery_evidence`; no
successful settlement or continuation is claimed.

Both attempts used a Darwin arm64 source host with Node 26.4.0, isolated
PostgreSQL 18, a Linux x64 runner and OpenCode 1.18.34. The
representative qualified model was
`openrouter/deepseek/deepseek-v4-flash-0731`; the original incident used
`openrouter/deepseek/deepseek-v4.1-flash-1017`. The controller defect
occurs before provider work. Runtime artifacts came from immutable build
`e7ea2e2961`, whose Runner package source is identical to the candidate.
The current-source manifest, artifact, distribution, asset and all 110
archive-hash checks passed. Each attempt had $10 company/agent model
budgets and zero automatic workflow/task retries. Accounting was
incomplete; zero recorded spend is not proof of zero cost.

Earlier setup failures are also retained: host PostgreSQL bootstrap
denial, cached-pack compatibility admission before provider work, and an
[official artifact
build](https://github.com/paperclipai/paperclip/actions/runs/40696838122)
that stopped during an unrelated Pi npm install at its 300-second bound.
No manifest or integrity guard was weakened. Owned local processes and
databases are stopped, and the temporary fixture patch is removed.
Standard fixture cleanup had left one replacement sandbox started; it
was stopped and deleted through the SDK. Every owned sandbox was then
verified absent with a final 404 readback. Resource cleanup does not
establish successful task finalization.

An earlier head retained one [voice-recovery timing
failure](https://github.com/paperclipai/paperclip/actions/runs/40695892339/job/122843005098):
a deadline test observed two failed-provider inspections instead of one.
A single isolated shard rerun passed all 1,579 tests without a source
change. Its timing explanation remains an inference. The current
reconciled head passed without a retry.

## Risks

Restoration writes a local projection before the existing admission
checks. The encrypted checkpoint loader validates company/task/run and
normalized session before writing. A later ordinary continuation
refreshes a prior-run projection so rejected admission cannot freeze an
active owner's older checkpoint. Active, foreign or unsuspended prior
owners still cannot start a successor. Missing or malformed evidence
remains blocked. The change adds no retry, credential, provider binary
or lifecycle-policy change; it preserves the existing legacy fallback.

This PR does not deploy the repair or recover the original hosted tasks.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use, code execution and
collaborating agents. The session exposes GPT-6 as its model version; a
more specific model ID and context-window size are unavailable.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 09:49:32 -05:00
DottaandPaperclip 25f1070fbd fix(runner): preserve checkpoint proof across warm preparation (#18011)
## Thinking Path

> - Paperclip coordinates agent work and preserves its execution state.
> - Native Runner checkpoints preserve authority across controller
changes.
> - Warm sessions also need checkpoint writes while their successor
prepares.
> - External persistence replaces the local state file with a marker.
> - Two existing checks treated those valid states as lost ownership or
prior activity.
> - This PR uses the existing preparation lease and canonical controller
state to keep those checks accurate.
> - The result is safe warm-session retirement and fresh-session startup
on reused sandboxes.

## Linked Issues or Issue Description

Related: #17439 and #17320. The open #17401 changes the recovery welcome
window and does not cover these paths.

**What happened?**

A configuration change could fail before the next provider turn with
`runner did not durably suspend before checkpoint`. The task already
pointed to its preparing successor, but that successor did not yet have
a native coordinator. The old completed runner's maintenance checkpoint
was rejected.

A separate fresh session on a reused sandbox could fail with
`resumed_unavailable`. Checkpoint registration had replaced the full
local state file with an external-persistence marker. The bootstrap
check still required the old full-file format. Process supervision then
reported unconfirmed termination before launch.

**Expected behavior**

Retire the completed warm runner under the same process's live
preparation lease. Admit a fresh remote session only when the registered
controller proves exact identity, no prior activity and pending
bootstrap commands, and the remote session directory can be claimed
atomically.

**Steps to reproduce**

1. Complete a native warm turn with external checkpoint persistence.
2. Change configuration so instruction preparation must retire that
session, then submit a follow-up.
3. Separately, admit a fresh native session on a reused sandbox lease
after external checkpoint registration.

**Paperclip version or commit**

Reproduced in the checkpoint implementation introduced by #17439. Fixed
against current master.

**Deployment mode**

Source checkout tests and a hosted Docker/Daytona incident. No
deployment or original-task retry is part of this PR.

## What Changed

- Accept completed-run maintenance under the exact successor's live,
same-process preparation lease only before a native coordinator exists.
- Preserve original controller generation, accepted-result, no-new-work,
company and task checks.
- Pass the registered controller through the existing connection
callback and read its current canonical state for untouched-session
proof.
- Keep marker-only, identity, activity, backup and atomic
remote-directory guards.
- Add regressions and update execution semantics and session
verification recipes.

## Verification

- Warm retirement red: the real Postgres writer rejected the preparing
successor's `runner.suspend` checkpoint with
`native_runner_checkpoint_owner_lost`.
- Warm retirement green: 14 Postgres ownership cases pass, including
stale/foreign/expired owners, conflicting native authority and new
provider work.
- Bootstrap red: real controller registration and external persistence
caused the resumed and replacement positives to fail. Six external
negative cases passed.
- Bootstrap green: all 34 bootstrap cases, the bootstrap-state predicate
and 13 connection-driver cases pass (48 total).
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Full `pnpm -r typecheck` and `pnpm build` pass.
- Full local `pnpm test:run` remains partial/interrupted. The default
attempt could not initialize embedded Postgres on this Mac. A dedicated
Postgres 18 attempt ran for 17 minutes without a completed file result
before interruption; the generic helper separately confirmed unsupported
embedded Postgres (`initdb` failed after five attempts) and ignores the
external database URL. The generic probe skipped one test. Setup and
interrupted-run logs are retained; neither is claimed as a behavioral
red or a full local pass.
- Real source-hosted Codex/Daytona acceptance was attempted at
`6ce7fcacc4` with `gpt-6.1-sol`, `xhigh`. The actual task stopped before
provider work at `runner_ingress_auth_failed`, with zero authenticated
connections and zero source events. A separate environment-qualification
handshake reached challenge/response; that does not prove task
authentication. The three-turn warm reuse, configuration retirement,
useful output and reload workflow remains unverified, so this PR stays
draft.
- The live attempt used the cached Linux amd64 Runner binary
`7437a4e32a099180889be534fcfb2a086046514490c1448aba46c55848983ed8` from
the immutable Daytona image. The current staging binary could not be
copied because SSH timed out, and the configured current EXE image
returned registry 403. No compatible current local or CI-downloadable
artifact was available. Earlier setup failures and cleanup receipts are
retained; no provider success is claimed. Disposable test resources were
cleaned up.
- Exact-head Greptile completed at 5/5 with no open feedback:
https://github.com/paperclipai/paperclip/pull/18011#issuecomment-6469515952.
All current-head CI checks pass: 53 successful checks and two intended
Storybook skips.

## Risks

The preparation fallback affects maintenance checkpoints only after an
accepted result. An existing native coordinator prevents that fallback.
Stale controller generations, expired or foreign preparation leases,
wrong tasks and new provider work remain denied.

The bootstrap check retains the live controller object and reads current
state each time. It does not trust a marker or restore local state
beneath a live controller. Pending turns, prior events/connections,
backups and existing remote directories retain recovery gates. No
schema, provider binary, credential, permission or lifecycle-policy
change is required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use, code execution and
collaborating agents. This session does not expose a more specific model
ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 09:09:09 -05:00
DottaandPaperclip 356c7de9b7 fix(runner): bind Grok packs to current admission source (#17972)
## Thinking Path

> - Paperclip manages agents and their work.
> - Native agents use verified Runner and provider-pack artifacts.
> - A protected installed pack can be reused when its selected provider
profile matches.
> - Grok kept profile 1 when its sidecar gained effort, search, and
startup diagnostics.
> - An older Grok sidecar can therefore pass compatibility and reject
the new session fields before provider startup.
> - This PR binds the current Grok profile to its admission source so a
fresh run selects the current verified pack.

## Linked Issues or Issue Description

Refs: #17922, #17942, #17962. Related installation contract: #14024. No
duplicate repair was found.

**What happened?**

The selected Grok profile digest stayed unchanged across native session
contract changes. The installed-pack verifier correctly compared that
digest, but the unchanged value let a pre-effort sidecar satisfy a
current controller. That old parser rejects `grokEffort` and
`grokDisableWebSearch` before the new startup diagnostics run.

**Expected behavior**

A fresh Grok run must use a pack that supports its current session
contract. Source-only app changes must still permit warm reuse when the
selected Grok profile matches. Reattachment must keep its exact admitted
artifact authority.

**Steps to reproduce**

1. Retain a protected pack with published Grok profile 1 and ACPX
interface 1.
2. Upgrade the controller to the native effort and search contract.
3. Start Grok 4.7 with High effort and disabled web search.
4. The old profile passes installed-pack compatibility, but its sidecar
rejects the new fields.

**Paperclip version or commit**

Reproduced from master at `09ad9adce2cf4742944353a3707a2f908e9bb35e`.

## What Changed

- Advance Grok to profile 7. Keep historical versions 1–6 decodable and
keep the Grok 1.0.13 runtime pin.
- Stamp the Grok admission source identity into a generated launcher
comment. Keep the existing physical command-byte digest check unchanged.
Bind effort/search/credential handling, sidecar admission, and Rust
backend/session/diagnostic source.
- Check the source attestation in the existing TypeScript/Rust profile
build gate. Keep its required fixture in the Docker context. Refuse to
overwrite a versioned identity after source changes.
- Add regression coverage for rejecting the old pack, current-profile
warm reuse, exact historical recovery authority, and actual sidecar
dispatch of Grok 4.7 High with both search policies.
- Re-attest Copilot as profile 71 because its bound shared recovery
decoder now retains Grok 6. Preserve Copilot 70 and all earlier
identities. Keep the compatibility algorithm, other provider identities,
dependencies, lockfile, and workflows unchanged.

## Verification

- The production installed-pack regression failed before the profile
update: the old Grok pack was accepted. It now passes.
- 105 server manifest, artifact, archive, and authority tests passed.
- 246 Runner profile, physical launcher integrity, Grok
effort/search/credential, and actual sidecar process tests passed; six
existing platform cases were skipped.
- 31 Node packaging and identity tests passed, including an actual
generator CLI regression that preserves all authority files when a
versioned identity would change.
- 55 Rust ACPX unit tests and 17 real sidecar pipe tests passed. After
the final profile declaration, all 55 unit checks passed again.
- Final `pnpm -r typecheck` and `pnpm build` passed at the final source.
- CI on the preceding head caught Copilot’s stale attestation for the
shared recovery decoder. The same current-source test failed locally,
then passed after profile 71 was generated with version 70 retained. All
106 affected Copilot/profile checks pass. Final head
`78e6d76fc52f492371e15574482b3641735a6d89` passed the full CI workflow;
the failed prior job log is retained.
- Review follow-up: mutating the Rust backend’s actual Grok descriptor
field left the prior identity unchanged. This regression failed before
binding `acpx_provider_backend.rs` and passes afterward. Profile 7
retains the prior versioned fixture and recovery decoder. All 179
affected Runner checks and 75 focused server pack/manifest checks passed
after this change.
- `pnpm test:run` hit the recorded embedded PostgreSQL bootstrap failure
after five attempts. The full run also exposed a current-release fixture
with the historical Grok digest; it now reads the current profile. Its
11 focused manifest tests now pass. The failed local run log is
retained; final exact-head CI passed.
- The same filtered-context Docker build that failed CI now passes
locally after adding its required source fixture.
- A separate probe used the built sidecar in a private HOME with no
credentials. It admitted the current profile and the new Grok fields,
then returned the closed working-directory rejection before provider
launch or inference.
- A historical parser probe reproduced the pre-effort sidecar rejection.
These probes establish the contract boundary; they do not establish
native subscription task acceptance.
- Initial restricted local ownership tests failed because loopback
listeners were denied. The same tests passed with loopback access. One
new dispatcher fixture first lacked required instructions; the completed
request passed. These setup failures are retained in local evidence.
- Live native task acceptance remains pending deployment. Earlier
deployed attempts failed before tool output. No successful native shell
proof is claimed.

- Final exact-head merge gate: all 62 contexts are clean (57 success,
four intentional skips, one informational neutral formal review).
Greptile and Paperclip reviews are both 5/5, with no unresolved
actionable threads. The formal review uses the existing report-only
neutral policy.

## Risks

- The first fresh Grok run after upgrade may need to stage the current
provider pack. Matching current profiles keep their existing reuse path.
- Fresh admission rejects older Grok profile identities. Historical
decoding and exact reattachment authority remain separate; this change
does not reinterpret an old identity or replace an active session's
pack.
- Future changes to bound source require a new Grok profile attestation.
The build gate fails if the checked-in identity is stale.
- Model, effort, search, credential, approval, and retry policy are
unchanged.

## Model Used

- OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact deployment model ID and context-window size are not
exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused checks; full-suite
database failure is retained above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 07:15:13 -05:00
DottaandPaperclip 6cc765bd81 feat(live): deliver recoverable transcripts to interested views (#17456)
## Thinking Path

> - Paperclip should show live agent output without repeating
presentation work for every view.
> - Execution, acknowledgements and durable checkpoints must remain
independent of browser interest.
> - The server already owns authorization and redaction at delivery.
> - A shared browser connection can declare which visible runs need full
transcripts.
> - Catch-up must handle subscription races, disconnects, terminal
output and slow consumers.
> - This PR delivers the backend and UI contract together without a
database migration.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Visible transcript consumers receive recoverable output through one
shared browser connection.

**Current behavior**

Independent views can create duplicate connections, presentation work
and recurring history reads. A subscription race or filtered native
history can lose the saved tail.

**Proposed behavior**

Negotiate run interests, subscribe before catch-up and retain
independent canonical recovery cursors. Keep lightweight lifecycle and
attention events available without full transcript delivery.

PR 4 of #17097 → #17439 → #17455 → #17456. The runtime feature is
independent of hot-upgrade recovery; the stack order is for review
convenience.

## What Changed

- Add additive WebSocket capability negotiation, replacement interests,
revision acknowledgement and resynchronization notices.
- Reference-count visible consumer interests on one company-scoped
browser connection. Preserve older-client/server behavior.
- Reuse canonical structural/current-user/registered-secret redaction
for plugin run notifications through the same bounded delivery queue.
Keep producer and uninterested streams free of recipient lookups.
- Refresh application queries after the matching recovery
acknowledgement, including one follow-up after an older in-flight read.
Ordinary interest acknowledgements add no refresh.
- Keep authorization and redaction at delivery. Browser interest cannot
change harness execution, PRP ACKs, checkpoints, accounting or canonical
logs.
- Deduplicate by sequence and log identity. Catch up terminal output and
saved tails without recurring reads during healthy negotiated streaming.
- Bound delivery to 1,000 items and 1 MiB. Overflow requires
resynchronization; persistent congestion closes the connection.
- Preserve compact-history expansion from current master across
paginated catch-up. Snapshot the original read window before React can
defer its update.

## Verification

On current source `f6710f0b3c`, Linux [job
122604880503](https://github.com/paperclipai/paperclip/actions/runs/40624101891/job/122604880503)
executes all five run-read permission cases successfully (2.574
seconds), including grant and revocation on the same connection. Its
shard passes all 2,430 cases.

Current [server-shard job
122604880416](https://github.com/paperclipai/paperclip/actions/runs/40624101891/job/122604880416)
has 1,513 passes, one failure and three skips: an unchanged nested-clone
expiration/restore test exceeds its 15-second deadline. The preceding
`5efc6c48bf` source has identical non-document bytes; [its corresponding
job
122601359272](https://github.com/paperclipai/paperclip/actions/runs/40623017917/job/122601359272)
passes all 21 nested-clone cases, including that case in 9.505 seconds.
The exact timing cause is unproven. The single diagnostic [retry job
122609332597](https://github.com/paperclipai/paperclip/actions/runs/40624101891/job/122609332597)
passes all 21 nested-clone cases (61.316 seconds), including the
formerly timed-out case in 7.003 seconds, and all 1,514 shard cases
(three skips). The failure remains recorded; no timeout or assertion was
changed.

After the server squash merge and qualification retarget, all 50 focused
server cases and all 91 focused UI cases pass again, with both
typechecks and token gates. Runner vendor preparation rebuilds current
master inputs before those tests. This source needs fresh CI and
reviews; prior CI and browser receipts do not qualify it by inference.

Current candidate `f6710f0b3c` now targets master `6987c2f20b`, after
merged #17097, #17439 and #17455. Its diff contains only transcript
delivery and its documentation. It adds no database migration.
Retargeting changes only the evidence document; all production and test
code is byte-identical to `5efc6c48bf`.

On the eighth integration, all 50 focused server delivery cases and all
91 focused UI cases pass, with both typechecks and token gates. The
following 35-case receipt belongs to the earlier delivery correction.
Four low-queue authorization/decoration stall variants and the
late-rejection case fail before correction. They now verify the
five-second read deadline, old and negotiated clients, revisions that
cannot reset the deadline, unaffected sibling connections, rejected late
results, and timer cleanup. The first combined toast run has four
loopback EPERM failures and 31 passes; its permitted repeat passes all
35. Earlier 28-case evidence excluded the toast file.

The permission correction requires the current HTTP company-scope
transcript permission, plus task access, for both native events and
legacy logs. Prior Linux source `49a8783e9b`, job 122549913643, executes
all five run-read cases, including grant/revocation on the same
connection, successfully. That source placed this file in server shard
11; later shard assignments can differ and must be checked against their
actual inventories. The older `405bedd189` receipt retains a separate
scheduled-retry teardown race and inherited fixture collision; neither
is waived. The new head must pass again in Linux CI.

The seven extracted stream-recovery tests preserve their assertions. All
39 related legacy/native cases, UI typecheck and token gates pass after
restoring the initially missed fixture helper. Earlier full workspace
build/typecheck and Chrome journeys at `445a76563c` cover two views,
company switches, reconnect, terminal catch-up, reload and zero
recurring healthy transcript reads. Those browser receipts are
historical source evidence and do not qualify this new head by
inference. The [qualification
record](https://github.com/paperclipai/paperclip/blob/f6710f0b3c84c6fdb2021df67206261b446dfc97/doc/plans/2026-10-22-hot-upgrade-qualification.md)
retains exact earlier UI/history, source-boundary and cleanup failures
with their fixes and limits.

The workload-cost test preserves bounds and authorization callback
counts for zero interests, one viewer, multiple browsers and a slow
viewer. Its socket congestion is simulated. It measures neither SQL nor
network costs. Current permission checks and the final hosted
active-agent/viewer matrix remain unmeasured; no production savings are
claimed.

Fresh exact-head CI, legacy status, completed Greptile 5/5, resolved
feedback and ordinary merge eligibility remain required.

The earlier recipient corrections pass all 47
registry/plugin/delivery/WebSocket/toast cases and all 174 UI
provider/recovery/interest cases, both typechecks and token gates on
source `b202e59a25`. A real bus/host-service test registers a synthetic
run secret through the production registry and reproduces its raw
notification before the fix; native/legacy/final notifications now
redact it, disposal prevents late worker notification. A later P1 review
reproduces lost final notifications on settings-read and
secret-resolution failure. Both cases fail before correction. Any
delivery failure or subscription timeout now sends one content-free
stream error and removes the plugin subscription. It never changes the
agent execution or run status. Later events start no new redaction
reads. The final integrated six-file server lane passes all 50 cases,
with server typecheck and token gates. Existing browser delivery
behavior is unchanged. Storage and secret-provider seams are scripted.
Two real React Query/provider regressions first miss a run during
resync; both now refresh after the valid replacement ACK, including
pending-read and stale-scope cases. The prerequisite qualification batch
passes all 118 cases and E2E typecheck after master integration. Fresh
CI, security scan and reviews remain pending on this head.

The contribution-rule review correction removes 104 explanatory comments
introduced by this slice and keeps the ordering, deadline and
plugin-delivery explanations in the delivery document. Existing comments
and functional test/lint directives remain. All edited source files have
identical parsed non-comment tokens before and after the change. All 50
server delivery cases and all 91 cases in six affected UI suites pass,
along with token gates. The new head requires fresh CI, security and
review.

## Risks

A slow or disconnected viewer must resynchronize from authorized
canonical history. It may see a display gap until catch-up completes.
Company changes and revoked access must remove delivery interests. This
slice adds no database migration and cannot change execution or recovery
authority. Full transcript delivery evaluates current company-scope
permission per delivery. Active plugin recipients also perform canonical
redaction reads; viewer-load database costs on this final source remain
unmeasured.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools and code
execution. The runtime does not expose a more specific model ID or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 22:23:30 -05:00
DottaandPaperclip 09ad9adce2 feat(server): adopt running remote agents through durable controller checkpoints (#17439)
## Thinking Path

> - Paperclip must keep admitted remote work alive while its main server
is replaced.
> - Runner owns recovery mechanics and exposes opaque checkpoints
through #17097.
> - The server owns company scope, encryption, Stop, tool authority and
execution ownership.
> - A successor must prove current ownership before it adopts the
original execution.
> - Checkpoint bursts must also leave capacity for normal requests and
lease renewal.
> - This PR persists and adopts that authority through the existing
runtime boundaries.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Remote agents retain the original execution during a bounded main-server
outage.

**Current behavior**

A server restart can lose the controller's local state and connection.
An unsafe replacement could repeat a turn or an uncertain mutation.
Checkpoint writes in the request pool can also delay ordinary requests
during an aligned burst.

**Proposed behavior**

Restore encrypted control records from Postgres and adopt the original
runner under a fenced lease. Recover known tool receipts through current
tool authority. Give control checkpoints a shared pool capped at two
connections per database owner.

Depends on #17097. Successors are #17455 and #17456. Qualification and
presentation remain separate review slices.

## What Changed

- Add company/run-bound encrypted checkpoint records and migration 0394.
Keep the SQL idempotent after renumbering against current master.
- Recover startup and expired ownership through native runtime and
heartbeat. Preserve the sandbox lease, admitted runner artifact, harness
configuration, native session and active turn.
- Keep Stop, finalization, preparation ownership and stale-writer
fencing transactional. Preserve graceful detach and natural crash
takeover.
- Recover committed tool receipts through the existing authority.
Reauthorize reads and hold uncertain mutations.
- Bound startup retention with the existing coordinator and preserve
zero idle scans.
- Share at most two checkpoint connections per database client. Keep
application and liveness capacity separate. Close the checkpoint pool
during shutdown; late writes cannot reopen it.
- Count SQL across both application and checkpoint clients. Prove
request/liveness progress, command recovery and failure after pool
shutdown with real Postgres.

## Verification

Project creation recovery now uses the existing project activity receipt
owner. It retains authenticated input normalization, fingerprint checks
and current run authority after the receipt lock. An absent receipt
returns no result before mutation. The new lost-HTTP-response and
no-effect regression uses real API routes and Postgres. The seven
transport cases pass locally. This Mac skips all 20 database cases. On
current source `5de803c2cd`, Linux [job
122593415890](https://github.com/paperclipai/paperclip/actions/runs/40620576702/job/122593415890)
executes all 20 project-tool cases successfully (9.480 seconds),
including the committed-project lost-response regression. Its shard
passes 1,627 cases with three unrelated skips. Server typecheck passes.
The transport regression initially has two failures; a subsequent
incorrect expectation about schema defaults was corrected before the
final pass. Ordinary execution adds no checkpoint writes or recurring
work.

Current candidate `5de803c2cd` includes the project-creation receipt
recovery fix and master `2cd747d1b6`. Migration 0394 retains the prior
idempotent checkpoint DDL. Every master SQL file and journal entry is
preserved. Snapshots 0390–0394, migration checks and server typecheck
pass.

The ordinary warm-turn regression fails on its second turn before
`a219ab51ad`. After correction, three completed warm turns select the
correct prior checkpoint and preserve the original session. All 288
provider-wiring cases pass. The control plane, external persistence
callback, identity rotation and filesystem are real; the backend and
database-load seam are scripted. The 13 warm admission/configuration
variants also pass after final master integration. This does not qualify
an underlying harness.

At current source `5de803c2cd`, Linux [job
122593415907](https://github.com/paperclipai/paperclip/actions/runs/40620576702/job/122593415907)
passes all 940 native-session-executor cases (61.431 seconds), including
the warm external-checkpoint behavior; the shard passes 2,358 cases with
one skip. Current [Runner job
122593415475](https://github.com/paperclipai/paperclip/actions/runs/40620576702/job/122593415475)
passes the native recovery lane: 115 passes and five container-only
skips, including the encrypted restore guard, fresh preparation (63.189
seconds), blocked claim lock (1.226 seconds) and recovery beyond 101
blocked owners (3.897 seconds). The first lane passes 2,215 cases with
one skip. The SQL cost test reports zero idle and streaming SQL for both
output volumes; this is component evidence, not a production capacity
claim. At prior candidate `1ff7bb44f4`, Linux job 122549307215 passes
all 938 native-executor cases, including the three-turn
external-checkpoint regression. Job 122549306469 passes the native
recovery lane with 115 passes and five container-only skips, including
the encrypted-restore session guard, fresh preparation (63.664 seconds),
claim-lock contention (3.961 seconds), and 101-owner recovery (3.824
seconds). This Mac skips the real-Postgres suite. The earlier full local
executor attempt has 921 passes and 16 failures during embedded-Postgres
initialization before assertions. The original fixture collisions and
their corrections remain recorded.

At earlier candidate `8fbe62b41d`, server shard job 122535673841 has
3,876 passes, one failure and one skip in an unchanged expiry-worker
retry/drain timing test. The same server/database tree on qualification
source `b64cac6951` passes all 20 expiry cases and all 3,877 shard
cases. The single diagnostic retry, job 122541891915, passes all 20
expiry cases and all 3,877 shard cases (one skip). No assertion was
weakened. The original failure remains recorded and its exact timing
race is not proven. All Actions checks and legacy status passed on
`8fbe62b41d`, with completed Greptile 5/5 and no open feedback. The next
candidate `1ff7bb44f4` also passed all Actions checks and Greptile 5/5.
Its Paperclip Review remained queued before the new master conflict
required integration. The new candidate needs fresh exact-head CI and
reviews; old checks do not qualify it. Migration generation is
checkpoint-only, all master SQL and journal entries remain unchanged,
and migration checks, server typecheck and all 13 warm-owner variants
pass after integration. The first migration check was blocked by TSX
sandbox IPC; its permitted repeat passes. The first warm-test command
used an incorrect path and ran no tests; the corrected command supplies
the 13-case receipt.

All 16 database pool-lifetime/options/teardown cases pass after granting
loopback permission; the first batch had two EPERM failures and 14
passes. Earlier semantic-tool/HTTP recovery, adoption, encryption-batch,
zero-streaming-write and idle-SQL receipts remain source-attributed in
the [qualification
record](https://github.com/paperclipai/paperclip/blob/2ff66f57da0da35bac1c19a2366ea4b84d87a986/doc/plans/2026-10-22-hot-upgrade-qualification.md).
That record retains earlier assertion, setup and cleanup failures and
their corrections. No failed gate is waived.

The historical 300-session component campaign passes four after phases:
steady read p99 is 107–108 ms at 500 reads/s and 100 writes/s;
aligned-burst read p99 is 103–105 ms after the bounded pool, versus
584–689 ms before. This comparison isolates the persistence corrections.
It does not measure the final stack's hosted active-agent capacity. The
hosted zero-agent API pair leaves SQL and CPU essentially unchanged, but
both arms fail absolute latency gates and candidate peak cgroup memory
fails its gate. The active-agent/viewer matrix, different-artifact
upgrade and rollback remain open.

Run `PAPERCLIP_TEST_DATABASE_URL=<owned-disposable-postgres> pnpm
--filter @paperclipai/server exec vitest run
src/services/native-runtime/native-runner-restart-recovery.integration.test.ts`.

Previous head `f2db8a6568` had one failed workspace setup gate: [job
122555672441](https://github.com/paperclipai/paperclip/actions/runs/40608984238/job/122555672441)
passes all 4,169 UI tests and 285 CLI cases (one skip), but the company
import/export suite reaches its 30-second health deadline during doctor
startup. Its output does not reach the server-start step. The CLI,
server, database, shared, adapter and plugin trees are identical on
qualification source `a866619d7b`, whose [job
122555886663](https://github.com/paperclipai/paperclip/actions/runs/40609057937/job/122555886663)
passes that fixture and all 286 CLI cases. The one diagnostic retry,
[job
122561057225](https://github.com/paperclipai/paperclip/actions/runs/40608984238/job/122561057225),
passes the formerly failing fixture and all 286 CLI cases. All Actions
checks and legacy status on `f2db8a6568` pass. Its exact-head Greptile
completed at 5/5 with no open feedback. The current integrated head
requires fresh checks and a completed Paperclip Review before merge. The
original failure remains recorded; its exact timing cause is unproven. A
repeated failure requires investigation and repair rather than another
retry.

All current-head CI, legacy status, exact-head completed Greptile 5/5,
resolved feedback and ordinary GitHub merge eligibility remain required
before merge.

The latest integration preserves master’s published Copilot v70 profiles
and every published migration. Checkpoint migration
`0394_conscious_whizzer.sql` was generated with `pnpm db:generate` and
retains the prior idempotent DDL. The Runner vendor rebuild and replay
parity checks pass. Server typecheck and all 13 warm-owner variants pass
after that rebuild. The imported report-lock patch is byte-identical to
master; its intentional patch-context whitespace is retained, and the
feature delta passes whitespace checks. No hosted experiment was run.

## Risks

The pool adds up to two active connections per instance, shared across
agents. Checkpoint delivery can wait behind that bound; it still
requires its commit. Steady component-test Postgres CPU rises by about
1.7 percentage points of a two-CPU allocation. These corrections do not
remove the stack's control and renewal writes. The migration and key
must survive replacement. Fresh-database tests and local load do not
establish different-artifact hosted upgrade or rollback continuity.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools and code
execution. The runtime does not expose a more specific model ID or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 21:39:23 -05:00
DottaandPaperclip 39e811c9c5 fix(runner): prepare diagnostic proxy and reduce bundled skill queries (#17941)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native turns reconcile company skills and select verified remote
runtime packs.
> - Catalog imports repeat folder transactions for skills in the same
bundled category.
> - Diagnostic requests can also reuse an older image proxy that lacks
the phase collector.
> - This pull request reuses categories within one import and selects
the current proxy for fresh diagnostics.
> - Each import has its own category map, and recovery keeps its
admitted runtime identity.
> - The result is less preparation work and a runtime that can provide
the requested measurements.

## Linked Issues or Issue Description

Refs #17918.

**What happened?**

A hosted run retained `PAPERCLIP_OPENCODE_PERFORMANCE_DIAGNOSTICS=1` but
emitted no provider phase batch. Its saved pack authority selected an
older image proxy. The deployed server proxy contained the collector.
The image proxy did not. Bundled inventory reconciliation also repeats
folder transactions for skills in the same category. The paired local
benchmark exposes that preparation cost.

**Expected behavior**

A fresh diagnostic request must use a verified proxy that supports the
current collector. Bundled skill reconciliation should resolve each
category once per import.

**Steps to reproduce**

1. Use a protected image pack with the same OpenCode interface revision
and an older proxy hash.
2. Enable `PAPERCLIP_OPENCODE_PERFORMANCE_DIAGNOSTICS=1` for a fresh
remote run.
3. Observe that the current backend accepts the older proxy and cannot
emit the requested phase batch.

## What Changed

- Reuse each bundled category during one import. Every skill still runs
its existing validation, access lookup, value comparison, and write
path.
- Compare the installed proxy hash with the current build when a fresh
run requests diagnostics.
- Keep compatible-pack reuse for ordinary runs and exact admitted
identity for recovery.
- Cover selection through the real backend, including recovery after
diagnostics are enabled.
- Document runtime preparation costs and admission limits for diagnostic
requests.

The skill importer owns category reuse. The provider verifier owns the
artifact comparison. The native backend passes the resolved diagnostic
requirement at the existing admission seam. The changes stay in those
existing owners and share one latency investigation and rollout.

## Verification

- Before the fix, the new verifier and backend cases failed because both
accepted a stale proxy.
- After the fix, 63 focused cases passed in 8.10 seconds. They cover
normal reuse, current diagnostic proxy selection, stale proxy rejection,
selected ACPX profiles, and admitted recovery identity.
- 110 skill and folder service cases passed against isolated real
PostgreSQL databases. Only cluster bootstrap used the existing local
PostgreSQL service. Queries, migrations, authorization, file handling,
and transactions ran on their real paths.
- A paired benchmark used the same immutable skill snapshot,
authenticated actor, 170-skill inventory, and 3.5 ms delay in each
network direction. It checked every delivered file and executable bit.
Warm median fell from 3.319 s to 2.482 s (25.2%). SQL calls fell by 81
in each matched sample, from 241–243 to 160–162. The bundled phase
median fell from 2.596 s to 1.721 s. The final measurement uses commit
`37eac8d8de`; only the skill importer differs from baseline
`7951455073`. These local results are not hosted acceptance.
- `pnpm -r --workspace-concurrency=1 typecheck` passed with the pinned
pnpm 9.15.4 and a 6 GiB Node heap. Earlier attempts exposed a subprocess
toolchain mismatch, a local IPC restriction, and a fixture type error.
Each was corrected before the passing run.
- Module boundary and whitespace checks passed.
- `pnpm build` passed for all workspaces.
- `pnpm test:run` did not complete. Embedded PostgreSQL initialization
failed after repeated startup attempts. The owned test subtree was
stopped after preserving the failure log. This is not a full local test
pass. On final commit `37eac8d8de`, all 53 successful check contexts
passed; two optional Storybook checks were skipped. Greptile is 5/5 with
no unresolved findings. The draft awaits merge approval.
- The catalog change has a measured local gain. The proxy change fixes
missing phase capture. Real hosted response latency remains above the
target and needs a new matched measurement after delivery.

## Risks

The category map belongs to one import and one company. The importer
still resolves current skill data on every invocation.

Fresh diagnostic runs can prepare a current verified pack, which can add
startup time. Admission can fail when matching runtime assets are
unavailable. Ordinary runs keep the existing fast compatibility path.
Recovery keeps the already admitted identity, even if diagnostics are
enabled later. The operator endpoint gate, collector limits, and closed
span fields are unchanged.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, shell execution,
browser tools, and Honeycomb queries. The session does not expose a
verifiable backend deployment ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 21:00:05 -05:00
DottaandPaperclip d40f9ac377 fix: enforce first-task completion decisions and retain E2E evidence (#17940)
## Thinking Path

> - Paperclip lets people delegate work to agents and approve proposed
work.
> - The onboarding first task asks for scope, proposes a task, and waits
for a human decision.
> - An answer to its opening question supplies scope. It does not
approve a proposal.
> - Task creation already checks the saved proposal decision.
> - Native completion used the general completion policy and could mark
the onboarding parent Done without that decision.
> - This PR checks the trusted decision before completion feedback and
again when the native status is committed.
> - The first task stays in review until a saved human decision permits
closure. Ordinary completion and acknowledged refusal keep their current
behavior.
> - The Product E2E guard also retains closed scalar evidence so future
failures show which boundary condition was observed.

## Linked Issues or Issue Description

Refs: #17914. Profile compatibility follow-up to #17922.

**What happened?**

A native onboarding run can submit a valid low-risk Done result after
only the opening answer. The native finalizer then marks the first task
Done even though no human has accepted or rejected a proposal.

**Expected behavior**

The opening answer must not permit completion. A trusted saved proposal
decision must permit it. A saved rejection permits acknowledgment and
closure, but does not authorize new work. A later pending proposal must
keep the task in review.

**Steps to reproduce**

Create a server-owned onboarding first task with an answered opening
question, no proposal decision, and a valid low-risk completion
contract. Pass a Done result through native completion feedback, the
control-plane port, and the finalizer. Before this fix, the persisted
status is Done. The regression expects In review. Ordinary completion
and acknowledged rejection pass as controls.

## What Changed

- Share the trusted latest-proposal and human-response checks with
completion admission. Keep task creation acceptance-only.
- Refuse premature native completion feedback. Keep an already saved
premature result in review during finalization.
- Check the decision again under the existing task and run locks before
committing Done.
- Cover accepted decisions, saved refusals, forged context, pending or
changed proposals, and a real database race.
- Retain a closed scalar receipt when the existing E2E pre-acceptance
guard fails. Validate and display it without task content, IDs,
filenames, or raw rows. Preserve the original failure, blocked
dependents, and historical reports.
- Include the evidence module in the journey definition hash. Bind the
receipt to its exact failure code and check its closed keys against the
full type.
- Repair base-branch profile drift found by the full harness check:
include the active Copilot v66 fixture in image hashing and update stale
Pi version/hash expectations from #17922. Keep all older image inputs
and strict hash checks.
- Update the onboarding feature and agent access maps and E2E evidence
documentation.

## Verification

- Semantic regression before implementation: one failure and two passing
controls on PostgreSQL 18. The failed assertion observed Done instead of
In review.
- The local database uses an owned disposable container with an
immutable image digest. Actual migrations, feedback, control-plane port,
finalizer, and status commit run against PostgreSQL. A temporary test
adapter replaces only the embedded database transport because this host
has exhausted its PostgreSQL semaphores.
- Native control-plane suite: 55 tests passed, including 17 new
controls. Existing task-creation admission: 25 passed. Existing
completion feedback: 19 passed.
- Credential-free E2E support: 206 Vitest suites passed, 4,407 tests
passed, and two skipped. All 137 Node support checks passed. Harness
typecheck passed.
- The failure-receipt regression had 11 failed assertions before capture
was implemented. Two failure-code binding assertions fail without their
gate. Eight placement/binding cases first validate the receipt-free
control, then reject the misplaced receipt.
- The untouched base reproduced the three profile compatibility
failures. The narrow repair passed all 83 affected tests before the full
harness run.
- Private workflow preparation and credential-free onboarding preview:
nine compatibility checks passed. Ownership, recovery, evidence,
shared-contract and workflow compatibility: 77 passed. The actual
provider preview also confirms immediate success deletion, earlier
declared failure eligibility, limits, and zero retries without
credential access. Map checks and git diff checks passed.
- Required repository typecheck passed for the product fix. The combined
branch build passed. The local full repository suite was stopped after
repeated PostgreSQL startup failures; a separate initdb probe confirmed
host SysV semaphore exhaustion. No shared IPC resources were changed.
[Hosted
CI](https://github.com/paperclipai/paperclip/actions/runs/40591020873)
passed the full database suites, typecheck, build, runner checks,
serialized suites, and browser shards on final head
`1ac4c23605a03bfd1f1f8a017b14ce29fda85f6b` (55 success, two expected
skips, one advisory neutral).
- Independent source review approved the product guard, atomic race
regression, evidence contract, and maps with no actionable findings.
Both automated reviews are 5/5 on final head
`1ac4c23605a03bfd1f1f8a017b14ce29fda85f6b`; prior findings are fixed and
resolved. Final CI is green and the PR is conflict-free.
- No Cloud workspace, provider call, release publication, or deployment
is part of this verification. These tests do not identify a historical
Cloud failure or qualify live onboarding.
- Local dependency installation uses the existing CI-generated lockfile
from #17811. No lockfile change is included.

## Risks

- Existing onboarding runs without a trusted saved proposal decision
remain in review even when the agent reports success. This is the
intended approval boundary.
- Decision changes can race completion. The status commit checks the
decision under its existing locks and uses the existing status-race
recovery path.
- A saved refusal permits closure only. Creation admission still rejects
it.
- Evidence readers reject malformed receipts and unrelated failure
codes. The version-1 key registry is checked against every receipt field
at compile time. Existing attempts do not gain evidence after the fact.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`), ultra reasoning, through Codex. Used
repository inspection, code execution, and collaborating coding agents.
The runtime did not report a 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 references)
- [x] My branch name describes the change and contains no internal
ticket or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 17:07:50 -05:00
DottaandPaperclip dc8cbdb819 perf(server): narrow native session resume database reads (#17934)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/94/changes/paperclip/94
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and their work.
> - Native agents resume prior provider sessions from saved run
checkpoints.
> - Resume selection must respect every newer progress barrier.
> - The prior query returned large context and profile JSON for up to 32
candidates.
> - Most candidates need only process, status, binding, and
checkpoint-presence checks.
> - This PR selects the same source in one SQL snapshot and returns only
its required payloads.
> - This reduces database response bytes while preserving session
authority and saved task context.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Native task/session resume selection in `findNativeSessionResumeRun`.

**Current behavior**

At baseline `bf3ef12f3a78d0b15a32ad57f7e16520fbf6cd5e`, a resume lookup
reads complete context and profile JSON for up to 32 runs, then reads
provider-event evidence. A synthetic 15-run history returns about 4.44
MB even though one checkpoint is selected.

**Proposed behavior**

A bounded CTE finds the first checkpoint or progress barrier. The same
SQL statement returns the selected source's native input, checkpoint,
tool fingerprint, wake envelope, canonical task brief, and process
identity. All fallback barriers and the 32-run limit stay in place.

**Reason and benefit**

Rejected candidates no longer transfer saved prompts and execution
inputs to Node. A single snapshot also prevents a gap between candidate
selection and payload hydration.

**Breaking changes**

None to public APIs or stored history. This private service returns the
fields consumed by runtime selection and checkpoint rebinding. It keeps
complete required nested values and distinguishes missing brief fields
from explicit JSON nulls.

**Additional context**

Checked `ROADMAP.md`. This is a targeted improvement to existing resume
behavior. Public searches for native session resume projections found no
duplicate. Related work includes #6573 (durable agent sessions) and
#17011 (managed Claude resume opt-in); neither changes this database
read. Provider-refusal recovery in #17676 is a separate concern and is
unchanged.

## What Changed

- Select the newest progress barrier within the existing exact
company/agent/task/session and 32-run window in one SQL snapshot.
- Return three required profile fields, the full wake envelope, and the
saved task's ID, title, and description only for the selected source.
- Preserve invalid non-null checkpoint barriers, provider evidence,
process authority, terminal-status rules, timestamp precision, and exact
string binding checks.
- Add real PostgreSQL regression coverage and a reproducible
baseline/treatment benchmark. Document the read and benchmark command.

## Verification

- `pnpm -r typecheck` passed. `pnpm build` passed. The final server `tsc
--noEmit` also passed. The later benchmark-only relocation passed `pnpm
check:module-boundaries` and the real PostgreSQL proof; runtime and
regression-test source are unchanged.
- Related suites: `native-session-resume-projection.test.ts`,
`native-session-resume.test.ts`, `heartbeat/retries.test.ts`, and
`heartbeat-retry-scheduling.test.ts`: 78 passed and 54 skipped across 3
passed files and 1 skipped file. Embedded PostgreSQL/platform gates
caused the skips. Resume orchestration and the 10 new SQL tests ran
against isolated PostgreSQL 17.11. The final 10-test projection rerun
passed.
- New SQL cases cover all seven provider evidence kinds, each process
authority field, all terminal statuses, wrong bindings and runtime,
invalid checkpoints, null/scalar/array/object JSON, missing versus null
brief fields, the 32-row bound, ordering ties, future barriers,
submillisecond timestamps, and a change committed before the one
selection statement.
- `pnpm test:run` was attempted. The host's embedded PostgreSQL startup
failed after five attempts. The broad run recorded failures/skips in
embedded-database suites and was stopped after that concrete host
limitation (exit 143). It is not a local full-suite pass. The full
final-head CI matrix passes on
`dcde4e3dac2173321d7be2406e7775af8411826a`: 55 successful checks, one
neutral check, and two optional Storybook skips. Greptile completed at
5/5 on that exact head, with zero unresolved findings. The initial
benchmark-location policy failure was fixed before this final run.
- Reproduce the benchmark with `pnpm --filter @paperclipai/server exec
tsx ../scripts/benchmark-native-session-resume-reads.ts
--baseline-ref=bf3ef12f3a78d0b15a32ad57f7e16520fbf6cd5e`. The optional
`PAPERCLIP_SESSION_RESUME_BENCHMARK_DATABASE_URL` must name an isolated
database ending in `_test`.
- The harness imports the pinned baseline module, invokes both actual
services, captures complete generated SQL and parameters, compares every
retained consumer field, and captures `EXPLAIN (ANALYZE, BUFFERS, FORMAT
JSON)`. Its incompressible wide fixture keeps a complete 96 KiB native
input in the selected result. Raw PostgreSQL text DataRow frames are
measured exactly; RowDescription, protocol command metadata, TLS, and
TCP are excluded.

| Synthetic local case | Baseline DataRow bytes | Treatment DataRow
bytes | Reduction |
| --- | ---: | ---: | ---: |
| 15 runs, one selected checkpoint | 4,441,143 | 104,599 | 97.64% |
| 15 unused bootstraps | 4,435,590 | 0 | 100% |
| One small selected source | 6,395 | 6,319 | 1.19% |

The committed-head benchmark uses two warmups and seven alternating
samples per variant. Local round-trip medians and ranges were:

| Synthetic local case | Baseline median (range), ms | Treatment median
(range), ms |
| --- | ---: | ---: |
| Wide history | 20.32 (18.63–24.37) | 1.63 (1.40–2.21) |
| Unused history | 18.52 (17.63–20.35) | 1.20 (1.13–1.56) |
| Small selected source | 1.05 (0.95–1.70) | 0.78 (0.73–1.30) |

The small case has overlapping ranges and a 1.19% byte change, so it is
neutral. `EXPLAIN` server execution time was higher for the treatment
(wide: 0.402 ms versus 0.028 ms across the two baseline statements).
`EXPLAIN` does not serialize result rows; the new JSON presence checks
do extra server work while avoiding large result transfer. These are
local synthetic round-trip measurements, not production latency claims.
The final proof ran on `dcde4e3dac2173321d7be2406e7775af8411826a` with
no runtime source diff.

## Risks

- Selection policy now has a SQL form. Regression tests preserve the
pure selector's barrier semantics, including invalid non-null
checkpoints and JavaScript Date precision.
- Checkpoint-presence checks can still detoast candidate profiles inside
PostgreSQL. The change reduces returned bytes; it does not eliminate all
database JSON work.
- The selected checkpoint, native input, and wake envelope can still be
large because consumers require them in full. No new payload cap is
introduced.
- There is no migration, cache, background polling, ownership lock
change, deployment, or merge in this PR.

## Model Used

OpenAI GPT-6 through Codex. The host did not expose an exact runtime
model ID or context-window size. The agent used reasoning, code
execution, real PostgreSQL, 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
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 16:31:55 -05:00
DottaandPaperclip c3a9a8e92a perf(server): scope run identity reads to operation needs (#17931)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tool and connection operations capture the current accepted
requester.
> - Capture locks the task and run, then reconciles pending steering.
> - Most callers use identity or task fields from the returned run.
> - The default query also transfers saved prompts, runner
configuration, results, and logs.
> - This pull request gives each production caller an explicit read
scope.
> - Narrow scopes keep their authority checks and return only selected
columns.
> - The Muse project path still reads its complete saved execution
input.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Operation-time run identity capture for native tools, gateway sessions,
project and workspace access, Slack, voice, connection management, and
connection token admission.

**Current behavior**

These callers use the default full run read. Large saved execution
documents cross the database connection even when the caller only needs
the current accepted requester or task binding.

**Proposed behavior**

Use typed identity, task, broker, and project-execution scopes. Keep
task-before-run locks, company and agent predicates, active status
validation, and pending-steering reconciliation. Return the complete
saved native input only where project admission uses it.

**Reason and benefit**

A synthetic PostgreSQL 17.11 fixture matches a wide run with a 142 KB
context and a 77 KB runner profile. Its locked run DataRow falls from
225,101 bytes to 190–605 bytes for authority reads. The project scope
returns 66,004 bytes because it must retain a complete 64 KB execution
input. These are local DataRow measurements, not a forecast of
production billing or latency.

**Breaking changes**

None to public APIs, saved data, or authority policy. Internal narrow
return types omit columns that were not selected. The default full
compatibility read and the existing GitHub-credential and authentication
scopes keep their current contracts.

**Additional context**

The public issue and PR duplicate searches found no matching open
change. This is one independent query optimization. It does not require
other performance PRs.

## What Changed

- Add typed scopes for accepted identity metadata, task authorization,
token attribution, and saved project execution input.
- Assign explicit scopes at all production `captureRunIdentity` call
sites.
- Keep the full native execution input for Muse project admission while
omitting unrelated profile, context, result, and log data.
- Narrow the broker's initial read and the existing Slack and
connection-management historical reads to the same required fields.
- Extend steering and acknowledgement regressions to all new scopes. Add
real PostgreSQL projection, malformed JSON, tenant and agent,
session-generation, and saved-input coverage.
- Add a service-generated SQL benchmark with exact raw DataRow
accounting, retained-field equality, plans, and alternating transaction
timings.
- Document the scope contracts and reproducible benchmark.

## Verification

- Baseline: `623f1dc289a14a699ebbe3f09b94179d38fc2ae2`.
- `vitest run server/src/__tests__/run-identity-projections.test.ts
server/src/__tests__/run-identity.test.ts`: 54 tests passed on an owned
disposable PostgreSQL 17.11 database.
- The tests retain task-before-run and audit foreign-key lock behavior.
Every scope rejects uncertain steering, accepts its durable
acknowledgement, and preserves requester replay ordering.
- A full-row mutation makes the narrow identity regression fail. The
restored treatment passes.
- `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-run-identity-projections.ts
--baseline-ref=623f1dc289a14a699ebbe3f09b94179d38fc2ae2` captures the
real locked SQL for both versions.
- Every retained column and selected JSON field matches the baseline.
Identity contexts match. The complete stored run remains unchanged.
Capture keeps the same five queries.

| Scope | Before DataRow bytes | After DataRow bytes | Reduction |
| --- | ---: | ---: | ---: |
| Identity | 225,101 | 190 | 99.92% |
| Task authorization | 225,101 | 410 | 99.82% |
| Token broker | 225,101 | 605 | 99.73% |
| Project execution input | 225,101 | 66,004 | 70.68% |

- DataRow bytes include row framing and raw text-format column values.
They exclude response metadata, TLS, and TCP.
- Two warmups and seven alternating samples measure the complete capture
transaction. Several timing ranges overlap. The primary claim is byte
reduction; production latency is not verified.
- Initial fixture runs exposed an empty external schema and an
incomplete synthetic conversation binding. The test setup now applies
migrations and supplies the required user/state fields. The final 54
tests passed.
- `pnpm -r typecheck` and `pnpm build` passed locally.
- Four existing skill-setup tests passed. Four assembled
connection-management/native-tool consumer cases passed with real
JWT/API-key authentication. These include per-request identity freshness
and task-scoped activity authority.
- A CI-only stale mock assertion expected two capture arguments; it now
verifies the explicit identity scope. A repository-wide capture mock
audit found no other stale argument assertions.
- Review follow-up: the projection suite uses the existing
embedded-support guard while always enabling an explicitly supplied
external database. The audit-lock regression merges URL query parameters
and retains existing PostgreSQL options.
- `vitest run server/src/__tests__/run-identity-projections.test.ts
server/src/__tests__/run-identity.test.ts
server/src/__tests__/company-skills-routes.test.ts
server/src/__tests__/project-skill-setup-identity.test.ts`: 123 tests
passed. The external PostgreSQL URL included both `application_name` and
`options`; lock tests verified `lock_timeout=1s` and retained
`statement_timeout=5s`.
- Full local tests are not run because the host's embedded PostgreSQL
setup is unavailable. Greptile reviewed
`06e1dd53a3fb24df74d5fbfb2ad397f291f1e30f` at 5/5 with zero unresolved
threads. The full final-head CI matrix passes. All 58 checks are
terminal: 55 success, one neutral, and two optional Storybook skips.
- No migration, lockfile, workflow, new polling, or cache change.

## Risks

A narrow read must retain each caller's actual fields. The caller audit
includes Slack's wake-request fallback, conversation generation, legacy
broker attribution, and the Muse parser's complete native input. JSON
selection retains value types, including malformed legacy values. The
saved-input scope preserves missing-key behavior. The default full read
still returns the complete stored row for compatibility. Locks and live
authority checks are unchanged.

## Model Used

OpenAI GPT-6, accessed through Codex. The exact runtime model ID and
context-window size were not exposed in this session. Used repository
inspection, code execution, and PostgreSQL validation.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 16:31:21 -05:00
DottaandPaperclip f60ac29cf1 fix(runner): migrate Grok Build with native reasoning effort (#17922)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Harness selection maps supported agents to Paperclip Runner.
> - The native Runner already supports Grok Build, but its migration
mapping excludes Grok.
> - Grok agents also have a thinking-effort setting that the native
execution contract does not carry.
> - This pull request adds the migration path and preserves explicit
Grok effort through startup and resume.
> - Operators can upgrade an existing Grok agent without silently losing
its model, account, or effort.

## Linked Issues or Issue Description

**What happened?**

Existing Grok Build agents have no Runner selector or upgrade action.
Adding only the mapping would route conversion through the Codex
fallback and lose Grok execution semantics. Native execution also
ignores the legacy reasoning-effort field.

**Expected behavior**

A qualified Grok agent can explicitly upgrade. The saved model, account,
instructions, history, and supported effort remain intact. Unsupported
legacy settings fail before saving. The provider must acknowledge the
selected effort before inference.

**Steps to reproduce**

1. Open the runtime page of an existing Grok Build agent on a qualified
Linux x64 or macOS ARM64 computer.
2. Observe that the Runner selector and upgrade action are absent.
3. Compare the native execution input with the saved legacy
reasoning-effort setting.

Related work: #13882 introduced native Grok Build. #15422 covers the
earlier default-runner work. This change extends the current shared
selection contract.

## What Changed

- Add the Grok harness mapping, qualified platform limits, upgrade
action, and company-scoped computer qualification.
- Translate Grok settings to ACPX without changing the selected account
or explicit model. Resolve the legacy default model to the native
default. Preserve the effective legacy search policy. Reject
incompatible command, argument, permission, and turn-limit settings.
- Add native execution input v10 for explicit Grok effort and search
policy. Preserve historical schemas. Enforce disabled search through
Grok requirements and bind it across startup and recovery.
- Apply and verify ACP `reasoning_effort` before prompting. Bind the
value to provider descriptors, checkpoints, runtime identity, and resume
checks.
- Use the Grok catalog and effort choices in the task composer. Apply
task model and effort overrides while retaining the agent account and
search policy. Update runtime controls, portability/default handling,
documentation, and capability maps.
- Advance Pi and Copilot source attestations for changed shared
transport and recovery code. Keep historical identities intact and
update all Rust integration fixtures.

## Verification

- Migration and review regressions were reproduced before the fixes.
Coverage includes the Grok mapping, default model, explicit effort,
implicit search policy, task overrides, and incompatible legacy
settings. The broad migration, route, immutable-input, and composer
check passed 478 tests. The final catalog and task-input check passed
135 tests.
- Runner startup, recovery, search policy, and profile checks passed 361
tests, with one platform skip. The final source-identity,
search-admission, and transport event-pump check passed 89 tests.
- All 757 Rust workspace tests passed for the broad implementation.
After the final source attestation update, all 55 ACPX profile/session
tests passed.
- `pnpm -r typecheck` and `pnpm build` passed for the implementation.
Server and Runner typecheck passed after the final production change.
Server `tsc --noEmit` passed after the final test-fixture change. Docker
context integrity, token gates, maps, generated protocol data, and
replay goldens passed.
- The v10 startup fixture initially used an ambient local Grok login and
failed on CI. An explicitly empty credential home reproduced all four
failures. The fixture now supplies a synthetic key and a private empty
home. A separate case checks that missing credentials fail closed. All
seven selected Grok v10 and Claude v9 startup cases pass without host
credentials.
- The full local suite could not complete because embedded PostgreSQL
failed before database-backed fixture setup. The broad executor-suite
attempt hit the same limit and was stopped. Neither attempt is counted
as passing. Current-head CI must verify those paths before merge.
- Earlier CI found missing Rust input fields, stale source attestations
and exact fixture pins, a missing Docker context entry, and an outdated
import expectation. Those failures were fixed and checked locally. The
CI logs retain the original failures.
- Different earlier CI runs also failed unchanged cleanup pagination,
device-login timeout, and chat lost-response recovery cases. Later
attempts passed the cleanup and login cases without changes to those
implementations. Their causes remain unproven. The original evidence
remains in [the first
run](https://github.com/paperclipai/paperclip/actions/runs/40563402840),
[the login
run](https://github.com/paperclipai/paperclip/actions/runs/40571128328),
and [the chat
run](https://github.com/paperclipai/paperclip/actions/runs/40573072163).
A passing retry does not establish a root-cause fix.
- Both reviews rate current head
`16fba9b4cdf12bc7945e6628912e79da42959f35` 5/5. All current-head CI
gates pass in [run
40576580699](https://github.com/paperclipai/paperclip/actions/runs/40576580699).
All 60 check runs completed cleanly, including the four intentional
skips and the neutral 5/5 Paperclip review. The legacy security status
is successful. No review threads remain unresolved.
- Staging migration and a real shell task are pending deployment. This
PR does not claim full Grok provider qualification. Reviewers can verify
the operator path by upgrading a qualified Grok agent, checking its
saved model and effort, and running a shell task through native
execution.

## Risks

- Explicit effort and search policy require the matching Runner and
sidecar build. Older immutable execution inputs keep their existing
schemas.
- Providers that omit or reject the selected effort fail before a
prompt. Unsupported effort does not fall back silently.
- Existing agents retain their saved runner until an explicit change.
New Grok agents use native execution only on qualified platforms.
- Grok token and cost reporting remain unverified, as before.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model ID and
context-window capacity are not exposed in this session. Used reasoning,
source editing, shell execution, and browser inspection.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and the focused suites pass; the full
local suite has the environment limitation 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>
2026-10-27 15:28:42 -05:00
3cd3af5d75 Trace native preparation and OpenCode execution phases (#17918)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each native run prepares its workspace and skills, then starts its
provider.
> - A long preparation span does not show whether inventory refresh, a
cache lock, repository reads, or file checks caused the delay.
> - One hosted run spent 81 seconds in this phase. The same deployed
service and pinned files took 2.55 seconds in a separate diagnostic
process.
> - Another hosted turn spent 69 seconds before its first output. A
matched public-workspace local model replay took 7.64 seconds.
> - We need skill preparation and provider-internal measurements before
choosing another fix.
> - This pull request adds skill spans, a real-service benchmark, and
opt-in filtered provider timing.
> - The benefit is a faster and more precise diagnosis loop.

## Linked Issues or Issue Description

Refs #17620. That PR owns the batched read optimization. This PR adds
diagnostics and does not change its read policy.
Refs #17907. That PR protects long cache lock transactions from the
database idle timeout.

**What happened?**

Native skill configuration can take much longer than matched standalone
resolution. Provider execution also has long gaps with no internal
timings. Existing spans cannot separate inventory refresh, cache
acquisition, repository reads, context loading, Git snapshots, or model
streaming.

**Expected behavior**

An operator-configured trace shows these phases under the existing run
context. Without an OTLP endpoint, the new spans stay off. A local
benchmark can reproduce the service path with real PostgreSQL, files, an
agent actor, and a responsible user.

**Steps to reproduce**

1. Run `pnpm --filter @paperclipai/server exec tsx
scripts/benchmark-native-skill-preparation.ts --actor=agent
--staging-shape=true`.
2. Inspect cold and warm phase timings, SQL counts, and file
verification results.
3. Set the existing operator OTLP configuration and add
`--export-otlp=true` to inspect the same hierarchy in the collector.

## What Changed

- Add bounded skill inventory, refresh wait, cache acquisition, row,
version, repository, file check, and consumer spans.
- Keep the existing endpoint gate, attribute allowlist, cache locks,
authorization, file validation, and durable pin boundary.
- Add a standalone benchmark with a full repository fixture, immutable
snapshot input, calibrated local transport delay, and optional OTLP
export.
- Verify every delivered file and executable bit outside the timed
section. Create its fixture agent through the lifecycle API.
- Add an opt-in authenticated loopback sink for OpenCode. Discard raw
attributes, logs and content. Retain only closed phase names and
timestamps.
- Carry one bounded diagnostic batch through the real proxy, Rust
normalization, durable journal and server trace projection. Group
provider phases under their execution parent.
- Freeze the Date clock in an existing delegated Slack rate-limit test.
This fixes a CI failure when consecutive requests cross a rate-window
boundary. It does not change rate-limit behavior.
- Document phase boundaries and the difference between SDK startup and
confirmed ingestion.

## Verification

- Skill service, runtime selection, concurrency, cache and timing
suites: 122 tests passed with real PostgreSQL and migrations.
Enabled-span integration tests also passed. They verify parent
relationships and a real advisory-lock timeout.
- A captured 208-file repository produced 209 verified runtime files.
The benchmark uses real agent and responsible-user authorization. The
lifecycle fixture correction passed with the staging-shaped inventory.
- Affected OpenCode driver, collector and transport tests: 72 passed.
The tests cover authentication, content removal, size/count bounds,
disabled behavior and the rebuilt native Runner boundary. One Rust
projection test and 18 server trace tests also passed. A held run-log
sink proves that a full 128-span diagnostic batch adds no duplicate
database writes before terminal consumption.
- The two CI-failing delegated Slack rate-limit cases passed against
real PostgreSQL with only the Date clock frozen.
- Runner TypeScript and server TypeScript checks passed. Rust formatting
and module-boundary checks passed.
- Real Honeycomb readback confirmed the 14-span skill waterfall and a
40-span provider waterfall. Provider phases have the correct execution
parent. The provider export uses synthetic model replies and is
instrumentation proof only.
- Earlier full local checks failed on missing package-local executables,
then on the default Node heap and a missing generated service worker.
The dependency links were repaired. The server check passed with a
larger heap. The full local test attempt could not start embedded
PostgreSQL on this host and was stopped after retaining its failures;
real database coverage uses an isolated database on an existing local
server. These attempts do not count as a full local pass.
- CI on the prior revision passed typecheck, build, Runner and all E2E
shards. It failed the benchmark lifecycle boundary and one existing
rate-window test. Those fixes passed CI. A later Runner assertion
exposed the Copilot source identity pin on the shared transport file.
The diagnostic flag now uses the existing configured-environment
projection, preserving that file byte-for-byte. All 66 selected
installation and native transport tests passed. New-head CI and review
remain required.
- The under-15-second hosted response target remains unmet. This PR adds
diagnostics and does not claim a hosted latency fix.

## Risks

- Skill spans and Honeycomb export retain the operator endpoint gate.
OpenCode phase collection requires a separate explicit diagnostic flag.
Without an endpoint, its closed measurements stay in the instance run
log.
- Raw OpenCode OTLP can contain prompts and authorization attributes.
The new sink rejects unauthenticated requests and discards all
attributes before any measurement reaches PRP or the operator collector.
Request, event and per-phase limits bound memory and journal growth.
- Collection does not wait for a provider flush. Late or oversized
exports can be absent; these measurements are not a complete profiling
guarantee.
- The benchmark's inventory contents and transport delay are explicit
fixtures. They do not reproduce server contention or prove hosted
response time.
- The one durable diagnostic batch remains the local evidence. Its child
span export does not add per-phase run-log rows.
- No database migration, authorization policy, model selection or
inference transport changes. The Rust Runner and OpenCode proxy must be
shipped together for the new opt-in diagnostic.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, shell execution,
browser tools, and Honeycomb queries. The session does not expose a
verifiable backend deployment ID or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Paperclip <paperclip@paperclip.ing>
2026-10-27 14:53:32 -05:00
DottaandPaperclip f6ba9afab0 perf(server): narrow explicit continuation run reads (#17896)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Recovery must prove that old execution stopped before it admits new
user input.
> - Explicit continuation reads the source run before and after it takes
the run lock.
> - Both reads transfer the saved prompt and the full Runner profile.
> - The preflight needs only identity, comment, adapter, and workspace
receipt fields.
> - This pull request narrows those reads and keeps the complete locked
profile for session proofs.
> - The benefit is less database transfer with the same admission and
recovery rules.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Explicit native continuation admission after a failed or stopped run.

**Current behavior**

The preflight and locked reread select complete heartbeat run rows.
Large saved contexts and execution profiles cross the database
connection twice.

**Proposed behavior**

Read only required scalar fields and typed context keys. Read only
historical adapter identity and workspace sync receipts before the lock.
Keep the complete Runner profile in the locked reread. Keep lock order,
company scope, text lookup of historical run IDs, stop proofs, queued
input, and replay rules.

**Reason and benefit**

A synthetic PostgreSQL 17 fixture removes 74.9% of the two queries'
DataRow bytes. This result is local query evidence. It is not a claim
about deployed latency or monthly transfer.

**Breaking changes**

None intended. No schema, API, migration, workflow, or dispatch contract
changes.

**Additional context**

Related: #17491 narrows the separate execution blocker read path. This
PR covers explicit continuation admission. The PR has no dependency on
the other byte reduction PRs.

## What Changed

- Select required continuation fields and typed context keys instead of
complete run rows.
- Read a small historical adapter/workspace profile during preflight.
Preserve the full locked profile for exact suspended-session and
quarantined-cleanup proofs.
- Narrow four helper input types to their actual field requirements.
Their runtime behavior is unchanged.
- Add real PostgreSQL admission comparison coverage and a reproducible
baseline/treatment benchmark.
- Document the query boundary and benchmark command.

## Verification

- Baseline: `663fe667d66d3863d0919a8724f1d99500feef0b`.
- Disposable PostgreSQL 17.11. One source run has a 192 KiB
incompressible context and two 96 KiB profile payloads.
- Command: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-continuation-run-reads.ts
--baseline-ref=663fe667d66d3863d0919a8724f1d99500feef0b`. Set
`PAPERCLIP_CONTINUATION_BENCHMARK_DATABASE_URL` to a disposable database
ending in `_test` to use an external server.
- The harness captures SQL generated by both real service versions.
Baseline imports use current helpers; only their TypeScript input types
changed in this PR. Their runtime behavior stays fixed.
- Preflight DataRow bytes: 394,067 to 466 (99.88% less). Locked reread:
394,067 to 197,168 (49.97% less). Combined: 788,134 to 197,634 (74.92%
less).
- Byte counts cover exact PostgreSQL text-format DataRow frames. They
exclude RowDescription, command metadata, TLS, TCP, and other queries in
the service.
- Seven measured samples per query follow two warmups. The order
alternates. Final-head median preflight time: 6.53 to 2.28 ms (ranges
5.34–7.41 and 1.84–4.46 ms). Median locked read: 8.06 to 5.26 ms (ranges
5.94–13.84 and 4.61–6.81 ms). These are warm local SQL measurements
under shared machine load. The deterministic byte counts are the
acceptance criterion; these noisy timings do not establish a deployed
latency gain.
- The harness compares the admitted continuation, blocked reasons, every
retained scalar column, kept JSON, and the full locked profile. It fails
unless the fixture removes more than half of the two reads' DataRow
bytes. It records SQL, parameters, revision identity, samples, and
EXPLAIN plans.
- All 291 continuation tests pass together on the final head with no
skips in a clean isolated PostgreSQL 17 database. This includes all
seven new projection comparisons and six malformed/missing JSON cases.
- Edited server TypeScript check passes: `node
node_modules/typescript/bin/tsc --noEmit -p server/tsconfig.json`.
- `pnpm -r typecheck` and `pnpm build` pass on the final head. The
normal server build verifies the complete pinned Copilot closure. Local
full `pnpm test:run` is not claimed: host embedded PostgreSQL startup
limits prevent that gate. The isolated PostgreSQL regressions pass; the
full exact-head test matrix runs in CI. The targeted exact-head test
retry passes all 4,086 tests in 98 files. All CI verification checks and
the dependent aggregate are complete and successful on head
`47c1b5f7d17a58310f7a3ebd494fdcaa814777c2`. Greptile completed cleanly
on head `47c1b5f7d17a58310f7a3ebd494fdcaa814777c2`: 5/5, no findings,
and no unresolved review threads.
- Local setup evidence: embedded initdb could not load its ICU data
library. Tests therefore use a dedicated PostgreSQL 17 container. A run
against reused test fixtures produced stale sweep failures; a new clean
database passed all 285 cases. The first comparison mock replaced an
unrelated aliased query; it was narrowed to the two admission reads
before the clean pass.

- The first [server test shard
6/12](https://github.com/paperclipai/paperclip/actions/runs/40529210562/job/122277218565)
failed one existing workspace-recovery case: a third export stayed
`scheduled` at its 20-second poll deadline; 4,085 other tests passed.
The exact case passes on the pinned baseline and final head with the
same PostgreSQL 17 fixture. Temporary spies recorded zero calls to both
changed admission functions in either replay. Other touched helpers have
type-only changes. This supports one timing-flake retry; the exact
scheduler delay remains unproven. The single [targeted shard
retry](https://github.com/paperclipai/paperclip/actions/runs/40529210562/job/122285744135)
passes all 4,086 tests in 98 files. The exact case completes in 17.25
seconds. The dependent aggregate is complete and successful. No timeout
or unrelated runtime code was changed.

- The separate Paperclip Review check ended `NEUTRAL` without a final
report. The completed source review is the exact-head Greptile 5/5
result above.

## Risks

- A future admission check may need an additional saved context key.
Keep the projection and helper contracts in sync with that consumer.
- Exact suspended-session and quarantined-cleanup proofs still require
the complete Runner profile. This PR retains it under the lock rather
than weakening those checks.
- JSON values retain their types and missing keys stay absent.
Malformed-context comparisons preserve the existing controller hold.
- These measurements use synthetic local data. Deployed transfer savings
require a fresh capture after rollout. Nothing was deployed.

## Model Used

OpenAI GPT-6 through Codex. The exact runtime model ID and context
window are not exposed by this session. The work used repository tools,
code execution, and real PostgreSQL validation.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 12:05:51 -05:00
DottaandPaperclip 663fe667d6 fix(recovery): reconstruct missing native workspace obligations (#17877)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A failed native run can still own prepared files in a remote
sandbox.
> - Cleanup must preserve those files before another executor can start.
> - Older failure producers can omit the preservation record.
> - A saved message then waits for cleanup without a recovery owner.
> - This change reconstructs that record during user continuation and
orphan cleanup.
> - The existing worker saves the files, verifies stop, and returns
input to normal admission.

## Linked Issues or Issue Description

**What happened?**

A failed native run retained a prepared workspace and an active sandbox
lease. It had no file-preservation obligation. Cleanup protected the
files. The next user message waited for a stop receipt that no worker
owned.

**Expected behavior**

A new message registers the missing maintenance work at once. Existing
orphan cleanup recovers historical saved input. Ordinary Retry remains
available. Saved input can start once, after verified preservation and
containment.

**Steps to reproduce**

1. Persist a failed native run with an exact prepared remote workspace
and its active lease.
2. Leave its finalizer terminal and unowned. Omit the workspace recovery
record.
3. Send a user comment or run orphan cleanup.
4. Observe that no preservation worker starts and the comment remains
deferred.

**Paperclip version or commit**

Reproduced on `bd382eee536f4ada680072b1cc19100163c3d04a`.

**Deployment mode**

Native Runner with a remote sandbox. Local verification uses disposable
PostgreSQL 18 and real temporary workspace files.

Refs #17788 and #17800. Those fixes preserve future deadline failures
and register historical preservation on Retry. This change adds
automatic recovery for new and saved messages. Refs #17839 for the
separate restart-failure producer repair.

## What Changed

- Register missing preservation before an authenticated continuation
waits for remote cleanup.
- Reconstruct the same exact-source obligation during the existing
orphan lease sweep.
- Notify the existing preservation worker in the registration
transaction. Do not add a timer or history scan.
- Test ephemeral and reusable sources, live owners, active executors,
mismatched sources, rollback, lock contention, Retry and saved-input
delivery.
- Document the recovery contract and feature-map behavior.

## Verification

- Red: both new orphan-recovery cases fail on unchanged production code.
Four ownership and source negative controls pass.
- Red: a new comment starts no preservation work without the admission
repair.
- All 461 test cases across five affected suites pass across the local
runs. One existing 30-second timing case timed out under concurrent
verification; its isolated rerun passed with the same deadline and
assertions.
- The three final-head entry journeys pass again: HTTP Retry, HTTP
comment creation, and historical saved-input recovery.
- `pnpm -r typecheck` and `pnpm build` pass on final head
`8fab8b2ba9049f640fd884094a2007a69465e6da`. The affected server
typecheck and build also pass.
- The integration journey holds the provider stop reply, checks that no
successor starts, preserves real files and newer host edits, and checks
one saved-input successor.
- Module-boundary checks, map checks and `git diff --check` pass.
- Native macOS PostgreSQL cannot start because host semaphore capacity
is exhausted. Database verification uses separate disposable PostgreSQL
databases for each suite. An earlier shared-database attempt caused
fixture interference and is not counted as a pass.
- Greptile gives 5/5 with no findings or unresolved threads on
`8fab8b2ba9049f640fd884094a2007a69465e6da`. All final-head GitHub checks
are settled: 55 passed, two Storybook checks skipped, and one neutral
Paperclip review. Full CI test, build, typecheck, Runner and browser
lanes pass. No full local `pnpm test:run` pass is claimed. The fix is
not deployed. This PR makes no claim of a live hosted model turn or
recovery of the original incident.

## Risks

- Registration grants maintenance authority only. Existing coordinator,
descriptor, allocation, stop, file-receipt and execution gates remain
effective.
- A locked source remains held. Its one-second lock timeout does not
prevent an unrelated source from registering recovery.
- New preservation writes wake existing work. Settled sources produce no
new recurring work. Historical discovery uses the existing orphan
cleanup lifecycle and its backoff.
- Provider lifecycle is simulated in local integration. PostgreSQL, HTTP
routing, file export/merge, the worker and queue admission are real.
- No schema, credential, model, trust, retry-budget or assignment
change.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository inspection, tool
use and code execution. The runtime does not expose the exact model ID
or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 09:50:50 -05:00
DottaandPaperclip db70c5acd9 fix(runner): retain startup Stop and exhaust reconnect recovery (#17812)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators must be able to stop a remote runner while it starts.
> - Remote artifact staging can finish after the transport's bounded
cleanup wait.
> - The launcher discarded an early Stop request and could dispatch
after staging.
> - A separate path missed the runner's plain-text reconnect expiry
receipt.
> - This change retains startup cancellation and ends an exhausted
reconnect incident.
> - Public package imports and a source-bound profile keep the
regressions buildable and admission checks intact.

## Linked Issues or Issue Description

Related work: Refs #16835, Refs #16843, Refs #16855.

**What happened?**

The HTTP Stop route returned 200 and recorded a cancelled run. After
bounded bootstrap cleanup, releasing artifact staging still dispatched
one launch RPC. A separate reconnect test accepted a replacement after
the runner reported that its grace period had expired.

The first PR head also failed CI. The HTTP regression imported Runner
source across the server TypeScript boundary. Its event receipt mock
read a field that is not present on both event forms. The changed
transport also invalidated the pinned Copilot source identity.

**Expected behavior**

A cancelled launch must remain cancelled after staging. An exhausted
reconnect receipt must end that incident. Regression tests must use
public package contracts. The source identity must cover the changed
transport without replacing historical profile bytes.

**Steps to reproduce**

1. Hold the remote launcher's artifact staging promise.
2. Call the board Stop route and let bootstrap cleanup reach its
preparation deadline.
3. Release staging and count launch RPCs.
4. For reconnect expiry, end an owned runner with its coded or
plain-text expiry message.
5. Run the server typecheck and the Copilot profile identity check.

## What Changed

- Retain cancellation through staging, trace publication and an
in-flight launch RPC.
- Apply a deferred signal through the existing identity checks when the
launch identity arrives.
- Preserve an earlier KILL request when a later TERM request arrives.
- Recognize both coded and plain-text reconnect expiry receipts.
- Test the real board Stop route and heartbeat cancellation with
PostgreSQL. Use public Runner exports and handle both event receipt
forms.
- Generate source-bound Copilot profile v65 after integrating current
master. Preserve exact published v62, v63 and v64 fixtures, retain the
earlier v63 reconnect candidate as historical evidence, and reject
historical profiles for a current launch.
- Document process evidence, retained uncertainty and the limits of
cleanup and continuation evidence.

## Verification

- At current integration head
`2b96ee3adcb3be642c538436113e1159d92f843d`, launcher and HTTP Stop
regressions: 21 passed. This includes the existing process-generation
and exact-exit safety cases on the integrated base. The HTTP case
includes bootstrap expiry; it is not isolated Stop-only settlement
proof.
- At current integration head, reconnect expiry regressions: 2 passed,
for coded and plain-text receipts.
- At current integration head
`2b96ee3adcb3be642c538436113e1159d92f843d`, the Copilot installation and
identity suite passed all 63 tests and the canonical generator check
passed. Before regeneration, the merged-tree admission test failed with
a transport source hash mismatch and the generator reported a stale
identity. Published v62, v63 and v64 bytes remain unchanged; the prior
reconnect candidate is preserved separately. The v62 fixture SHA-256
remains
`faa4d1b35267b54e134a8e0c84586fe1196d8fad5525cb53aa195aae53ca6e83`.
- Current integration head passed all 86 focused tests, the full
recursive repository typecheck and the root repository build. The normal
server typecheck also passed, including its full Runner release rebuild.
- Historical full recursive repository typecheck and the root repository
build passed at `187bb85b4fa1fbd2ffaec992650a1c8557df9ebe`. Server
typecheck also passed through the normal package script and a direct
full server TypeScript check. The prerequisite full Runner release build
passed.
- The historical HTTP baseline returned 200 and dispatched one late
launch RPC. The repair returned 200 and dispatched zero in the bounded
fixture.
- Earlier failures remain part of the evidence: the first head failed
TypeScript package boundaries and source identity. One local HTTP run
failed before migrations; it passed after the disposable test database
received normal migrations. Earlier sandbox-wide checks ran out of
memory or lacked Cargo. Those runs did not pass.
- Historical head `187bb85b4fa1fbd2ffaec992650a1c8557df9ebe` received
Greptile 5/5 with no actionable findings and all hosted gates passed in
run `40412261957`: 53 successful check runs, four expected skips and a
successful legacy Snyk status. Those results predate the master
integration and do not establish current-head readiness.
- Current integration head `2b96ee3adcb3be642c538436113e1159d92f843d`
includes master `bd382eee536f4ada680072b1cc19100163c3d04a`. All
current-head hosted gates passed in run `40512885858`: 53 successful
check runs, four expected skips and a successful legacy Snyk status,
with zero pending or failed checks. Build passed at 13:42:36 UTC and the
final `ci / verify` aggregate (job `122224566238`) passed at 13:43:00
UTC on 2026-10-27. Greptile reviewed exact head
`2b96ee3adcb3be642c538436113e1159d92f843d` at 5/5 (updated 2026-10-27
13:36:41 UTC), with no actionable findings and no open inline threads.
The hosted partitions passed full-suite verification, including browser
and release gates. The wider qualification limits below remain in force.
- Local setup on current master initially failed frozen install with
`ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` because `patchedDependencies`
differs from the lockfile. Pinned pnpm 9.15.4 hydrated dependencies with
`--no-frozen-lockfile --ignore-scripts`; its generated lockfile change
was restored. This PR changes no lockfile or workflow.
- Reproduce the Stop tests from `server`: `pnpm exec vitest run
src/services/native-runtime/native-session-executor.test.ts -t 'remote
runner process supervision|HTTP Stop during remote runner staging'`. The
test accepts a guarded disposable `_test` database through
`PAPERCLIP_TEST_DATABASE_URL`, or starts its normal embedded database.
- Reproduce reconnect tests from `packages/paperclip-runner`: `pnpm exec
vitest run src/live/runnerd-codex-transport.test.ts -t 'does not restart
an exhausted reconnect'`. Build the normal test runner first.
- Reproduce profile checks from `packages/paperclip-runner`: `node
scripts/copilot-profile-identity.mjs --check` and `pnpm exec vitest run
src/drivers/acpx/copilot-installation.test.ts`.

## Risks

- The wider qualification is incomplete. Verified-stopped replacement
and concurrent recovery plus Stop each entered two physical provider
processes. Both fail the original requirement of at most one physical
provider entry. Passing fixture assertions do not make all incident
scenarios accepted.
- HTTP concurrent recovery, shared provider-attempt accounting,
server-admitted restored continuation, live-provider behavior and
product cleanup settlement remain unrun or unproved.
- Accepting a deferred signal is not proof that a dispatched process
stopped. The existing monitor remains authoritative.
- The HTTP test uses the real route, heartbeat cancellation and
PostgreSQL state. Execution lease and event ports, plus the launch RPC,
are controlled fixtures. Bootstrap expiry participates in this case.
- The local incident matrix uses an installed runner binary and a
scripted provider. It does not qualify a live provider. Local fixture
teardown does not certify product cleanup settlement.
- This change does not authorize historical turn replay. It does not
change ownership, pause, approval or provider-attempt gates.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose the exact
serving model ID or context-window size. The agent used reasoning,
repository inspection, shell execution and connected 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
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 08:45:00 -05:00
DottaandPaperclip 13709b4c7a feat(connections): let agents configure connections within delegated authority (#17737)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections provide governed tools, chat channels, model accounts,
and gateways.
> - Several management routes require a human board actor even when an
agent has the required grant.
> - Default agents must configure these resources within the responsible
user's authority.
> - This pull request adds a shared authorization path to the existing
REST and native API surface.
> - Human authentication, execution approvals, and local host boundaries
remain enforced.
> - The benefit is that a standard agent can complete authorized setup
with a bounded human handoff.

## Linked Issues or Issue Description

**Subsystem affected**

Server authorization, connection services, shared contracts, native API
discovery, database schema.

**Problem or motivation**

Connection administration is available in the web app but often
unavailable to agents. Agent grants, responsible-user authority,
credential ownership, and actor attribution need separate checks.
Opening gateway-token creation also requires preserving the issuing
agent's delegated authority during token use.

**Proposed solution**

Use the existing authorization evaluator for every connection family.
Enforce current responsible-user authority, effective trust, grant
scope, resource visibility, and target-agent access. Keep existing agent
grants unchanged. Expose authorized configuration through default
`search_api` and `call_api`. Save human authentication steps and let
agents continue after completion.

**Roadmap alignment**

This change completes the API access path for the existing Connected
Apps, Personal & Shared AI Accounts, and governed MCP Gateway
capabilities in `ROADMAP.md`. It follows the maintainer's requested
design. Related work: #11899 enforces connection execution access and
creator/manager rules; this PR extends agent management across
connection families. It does not replace that execution-policy work.

## What Changed

- Add shared connection management context and mandatory
responsible-user, trust, scope, and target checks.
- Allow authorized agents to configure tool, chat/email, GitHub/Slack,
AI, profile, and gateway resources through existing routes.
- Preserve human credential ownership and record the actual agent,
responsible user, and run or key in audit data.
- Preserve saved browser authentication handoffs and callback session
checks.
- Bind agent-issued durable gateway tokens to their responsible user and
recheck delegated authority at use.
- Add explicit REST transport and management capability metadata,
built-in guidance, and sensitive-response handling.
- Intersect caller and endpoint-agent Slack test/invitation policies,
including independent and shared rates. Require the addressed human’s
current endpoint identity link before completing identity handoffs.
- Add production-authenticated integration scenarios. Companion #17739
contains the saved setup UI (including the required human
import/rotation step), product and permission documentation,
catalog/Vercel credential and callback ownership, and operation maps to
keep each review below 100 files. Both PRs must ship together; merge
this implementation first, then its companion.

## Verification

- Current implementation head:
`2ecd6451d0d0c8d82121a4e3fa4ce94c5befbbd6`, including master
`ea727dc3c2`, 99 files. The latest follow-up fixes the two valid
findings from the preceding f9 review. Exact-head Greptile has completed
at5/5 with no findings and Superagent passed. Full exact-head Linux CI
workflow40446606056 completed SUCCESS; only the queued external
Paperclip Review remains pending; earlier Linux passes do not qualify
this successor.
- Latest preserved-stack verification passed **2,165 tests** in fresh
PostgreSQL: **70 actual-auth scenarios**, 27 OpenAPI contracts, 2,022
native API tests and 46 saved GitHub wizard cases. **141 existing
gateway/policy acceptance tests** also passed. Workspace
typecheck/build, maps and token gates passed. The first workspace
typecheck was blocked by sandbox tsx IPC permissions; its authorized
rerun passed. This is focused local evidence; the full Linux CI matrix
is still required.
- Issuer/target gateway policy regressions were red before the fix. Both
decisions now intersect, including Block/Ask first/rates, same
credential identity and current token/user/agent authority after
approval. Invocations retain their token and actual requesting agent;
deleted tokens fail closed. Thirteen actual-auth cases cover revocation,
narrowed scope, approvals, shared rates and board compatibility.
Intermediate missing-token attribution, review-context and
implicit-session actor failures remain in the qualification record; all
final cases pass.
- Activity pagination now retains a bounded cursor across private-only
windows. The actual-JWT regression reaches three older readable events
after 27 private ones without exposing private details. A native
device-login regression was red for plaintext receipts; local check and
test-call results now use existing protected-response handling. The
passing actual-auth case proves encrypted persistence, exact replay,
redacted history and no response asset.

- Previous-head `5b55195593` Linux CI initially failed e2e shard 4/8 in
the existing connection-intent continuation test: periodic recovery
queued a repair at 01:21:47, the scripted journey completed the task at
01:21:48, and the extra queued run was cancelled at 01:21:49 because the
task was terminal. The assertion selected that latest cancelled run.
GitHub refused the first attempt while the workflow was nonterminal.
After completion, the single evidence-supported failed-job rerun was
accepted as **attempt 2** on the same head (workflow 40431202466). The
failed shard and final E2E aggregate passed on attempt 2, and the
complete Linux workflow for that head is successful. The original
failure remains part of qualification. No additional unchanged-code
rerun will be used for this failure.

- Companion CI also has an unchanged login-cleanup idleness timeout,
retained in its qualification record. That same 16-case suite passed in
this parent Linux run and a fresh local database. Both preceding
workflows passed after their single failed-job reruns as attempt 2; the
original failures remain recorded. No additional unchanged-code rerun
was used.

- Migration `0380_broken_aqueduct.sql` was regenerated through the
repository workflow after master took 0379 for project Git
authorization. It adds the responsible-user column with `IF NOT EXISTS`,
preserves upstream migrations, and satisfies snapshot retention and
migration safety checks.
- Upstream published Copilot v62 and v63 identities remain byte-for-byte
unchanged. The combined guidance is now v64, digest
`sha256:22e31f95ef972bcead98a4a707c9f33433558fd111e390e027a2bbb4346e112a`.
The normal shared TypeScript/Rust identity check and **61 Copilot
installation tests passed**. The old source-identity assertion first
failed against unchanged published v63; regenerating a new v64 preserves
the published release.
- Workspace `pnpm -r typecheck` and `pnpm build`, map validation, and UI
token gates passed on the final combined stack after the upstream merge.
Node 24.22.1 / pnpm 9.15.4 were used.
- **Earlier 82 API/OpenAPI tests passed** in fresh PostgreSQL 18: 55
assembled-server scenarios and 27 contracts. They use real persistent
agent keys, run JWTs, human sessions, production defaults, and
deterministic provider fixtures. No actor injection establishes access.
- The new email regression was red before per-account scope filtering.
The Arcade regression was red before human ownership and inventory-key
fixes; it also verifies actual-agent audit identity and a human-session
inventory read. The activity regression measured **200 authorization
checks before the fix and one afterward** for the same one-item page.
- **82 GitHub UI tests passed**, including all three new
failed-replacement regressions that were red before their fix. The UI
preserves an earlier copy only after confirming its committed
generation. Changed or unreadable results block copying and reconnecting
until reconciled. Human-only secret responses now include their
nonsecret committed generation.
- Private test status now rechecks the originating principal and linked
task, including mandatory agent/responsible-user privacy. Cross-agent
tests require the full caller tool access decision and the same
credential identity, regardless of auth label; caller and target
policies/approvals and rate limits apply before execution and after
human approval. A profile-only precondition was found to reject valid
allow-policy and scoped-grant access and has been removed. Both
permitted-access cases and a no-auth-label identity regression were red
before the correction; caller-specific Block still prevents provider
execution. The private-status regression was also red before its fix.
- The tool-activity regression measured 100 capability decisions and 102
run captures on a 100-event page before the fix. It now uses two task
decisions and at most two captures while retaining the same 50 visible
events, private-event filtering, and 403 after audit-grant revocation.
The regression was red before request-context reuse and task-decision
sharing; final server typecheck/build also pass.
- Generic chat configure/reconnect now hands agent-supplied verification
credentials to the addressed human before provider work or vault
changes. Actual key/JWT regressions were red for Slack signing-key
replacement and generic channel secret-reference rebinding. They now
prove unchanged refs and vaulted signing value, human setup, permitted
agent bot-token repair, and governed test messages. All 82 API/OpenAPI
cases pass in fresh PostgreSQL. Eight native receipt protections and
final server typecheck/build also pass.
- The preceding review found that old healthy state could retire a
credential-entry card before a human changed anything. The actual-JWT
regression was red. Saved field generations now change only with
protected values and commit with refs plus a verification fence; retries
retain the baseline. Old health, bot-token repair and unchanged entry
stay pending. New signing verification and current authority permit
continuation. A separate red race proved that user revocation during
provider authentication could return 403 after refs changed; authority
is now checked before persistence and inside the credential transaction.
The final 82 API/OpenAPI cases, four neighboring real-database
Slack/GitHub lifecycle cases, and final server typecheck/build pass.
- A preceding full run crossed a rate-window boundary. Database rows
prove one consumed slot at 23:35 and another at 23:36 for the same
policy/bucket. Only Date is frozen in the rate test cases; transport and
asynchronous timers remain real. Production rate behavior is unchanged,
and the final full run passes. An intermediate fixture failure that
overwrote hidden generation metadata with an API projection is retained
in the qualification record.
- Linux CI on an earlier head found two rate-admission assertions that
omitted the newly persisted bucket key. The failures were reproduced
locally; both assertions now verify the exact actor/tool bucket and all
49 policy-service tests pass. The companion qualification record retains
the initial and intermediate failures. Catalog creator attribution is
preserved in the companion to keep this implementation review at 99
files.
- The latest review reproduced three regressions before repair: complete
human replacements failed on unavailable old signing secrets, fresh
GitHub links incorrectly selected reconnect, and different
credential-entry requests shared an idempotency key. Each old protected
ref now has a narrow known-unavailable fallback; unexpected resolver
failures and company/scope violations still abort. Fresh imports keep
their credential form, configured endpoints keep reconnect, and
canonical field sets/completion modes distinguish handoffs while
matching retries retain their baseline. All 55 actual-auth scenarios and
27 separately run OpenAPI contracts pass, as do server typecheck/build.
Companion #17739 also passes all 41 wizard tests including actual
fresh-form submission, UI typecheck, maps and token gates. Earlier red
results and a mistyped OpenAPI filename are retained in qualification.
- The configured GitHub handoff regression was red in the
browser-component tests and actual-auth link/persistence tests. Saved
links now name requested fields and all/any completion mode; the
companion form submits those supplied fields through reconnect and
retains other saved credentials. Webhook/client-secret reconnect remains
human-only; first-setup secret restrictions remain. All 46 wizard tests
pass, including combined modes and legacy links. A duplicate review
referenced the older companion bf760912; the current form is already
fixed, linked in the reply, and its thread is resolved.
- Linux CI on bf760912 failed automatic Slack provisioning because vault
persistence cleared an already verified manifest-update challenge. The
same regression was reproduced locally. The provider-owned helper now
preserves proof only for the current signing fingerprint and callback
URL. Eight existing compatibility cases pass, including this case and
initial GitHub secret rejection. The first uncommitted GitHub-field
variant also failed that initial boundary and was narrowed to reconnect;
both failures remain in qualification.
- The upstream merge conflicted only in generated migration metadata.
Upstream 0379 is preserved, normal generation/pruning produced 0380, and
two repeated applications of the idempotent additive SQL passed. The
final combined stack passed **128 tests** (55 actual-auth, 27 OpenAPI
and 46 wizard cases) in fresh PostgreSQL. Eight Google UI cases also
pass; the two protocol cases could not initialize embedded PostgreSQL in
this fresh local attempt. Their earlier passing evidence remains
historical; fresh Linux CI must execute them. Vercel personal credential
attribution is preserved in companion #17739 with its other
ownership/consent follow-ups, keeping this PR at 99 files.
- The suite covers fresh defaults, restricted users/agents, scopes,
personal isolation, token revocation, human handoffs, callback replay,
execution approvals, authorized self-targeted policy changes,
self-approval denial, and current authority before commit. Reproduce API
checks with `pnpm exec vitest run
server/src/__tests__/connection-management.integration.test.ts
server/src/__tests__/openapi-routes.test.ts`, using a fresh database
through `PAPERCLIP_CONNECTION_MANAGEMENT_TEST_DATABASE_URL` or the
default embedded test database.
- Companion #17739 also records consent separately from token refresh so
saved Google choices survive refresh. Its eight service-picker and two
local-HTTP OAuth tests pass; both new UI cases were red before the fix.
Normal migration generation confirms no SQL change is needed for the
additive JSON metadata.
- The integration module shares one assembled server, authentication
factory, and provider lifecycle to preserve the
HTTP-to-vault-to-task-continuation proof. A reused external database
caused a Slack fixture identity conflict; the fresh final run passed.
Earlier fixture/transport and contract-update failures remain in the
companion qualification record.
- The broad local `pnpm test:run` attempt remains blocked by macOS
embedded PostgreSQL's host semaphore limit. It is not a clean pass. The
fresh Linux CI matrix must complete. Provider fixtures do not prove live
setup or an empirical LLM success rate.
- A current-head completed Paperclip assessment is not yet recorded. Its
earlier external recovery boundary has not been bypassed, and no
incomplete assessment is reported as passing. The user authorized both
merges when checks pass; merge this implementation first, then replay,
retarget, and requalify companion #17739 against the squash-merged
master.

- After the master refresh, local workspace typecheck/build, **97
actual-auth/OpenAPI cases** and **141 gateway/policy cases** pass. The
original fixed database port was occupied; Docker assigned a free
localhost port. The first neighbor setup command could not resolve root
`tsx`, leaving its schema uninitialized; the built database package
migrated the separate fixture and all unchanged cases passed. Both setup
failures are retained in qualification. Fresh Linux CI remains required;
no full local test-sweep pass is claimed.

- The f9 Greptile review scored **2/5** for two reproduced findings:
Slack test sends skipped the caller’s tool policy, and healthy App
credentials completed an unconfirmed identity handoff. Both are fixed in
this head and have resolved evidence threads
([Slack](https://github.com/paperclipai/paperclip/pull/17737#discussion_r4384927765),
[identity](https://github.com/paperclipai/paperclip/pull/17737#discussion_r4384927895)).
Actual key/JWT cases cover twelve Slack caller/target/recipient
combinations; the human-session GitHub OAuth callback alone remains
pending until explicit confirmation. All **99 API/OpenAPI tests** (72
actual-auth + 27 contracts), workspace typecheck and build pass. On the
combined companion, all four focused cases (including the twelve Slack
combinations), typecheck/build and maps also pass. The continuation
suite’s 50 embedded-PG cases were skipped because its database could not
start locally; fresh Linux CI must run them. Initial fixture
credential-collision and audit-projection assertion failures are
retained with the red reproductions in the companion qualification
record. No full local sweep or live consent is claimed.

## Risks

- The maintainer explicitly confirmed authorized policy administration,
including self-targeted changes that loosen controls. These writes
require management grants and the responsible user’s current authority.
Agents cannot approve their own governed action requests or edit their
own principal permission grants. The actual-auth regression exercises
both permitted administration and those denials.
- This is a broad authorization change. Incorrect scope or owner
resolution could deny permitted setup or expose another user's
resources. Integration cases cover both permitted and denied requests
with actual authentication.
- The additive nullable gateway-token column does not infer identities
for legacy clients or backfill agent grants. Legacy agent tokens without
a responsible user fail closed.
- Provider fixtures test supported setup and callback contracts. They do
not prove live provider availability.

## Model Used

- OpenAI Codex, GPT-6 family, with reasoning, repository tools, and code
execution. The runtime does not expose a more specific deployment ID or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — focused suites above;
full local sweep remains blocked as documented
- [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 — exact `2ecd6451d0` Linux CI
completed SUCCESS; external Paperclip Review is still queued
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
exact `2ecd6451d0` review completed; both f9 findings have resolved
evidence replies
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 08:20:24 -05:00
Devin FoleyandPaperclip 94819b6ded fix(recovery): preserve live heartbeat preparation ownership (#17838)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Heartbeat prepares each run before it starts the native provider.
> - Startup recovery can run while that preparation is still active.
> - The native input and coordinator exist before workspace
synchronization saves its descriptor.
> - Recovery checked the later native executor registry but missed the
earlier heartbeat execution registry.
> - It could claim the live run and dispatch a second executor against
incomplete workspace state.
> - This change gives the recovery claim the existing live heartbeat
registry and checks it before changing ownership.

## Linked Issues or Issue Description

**What happened?**

Startup recovery can claim a native run that the same server is still
preparing. The second execution reads the admitted native input before
workspace synchronization has saved its descriptor. It fails with
`native_workspace_sync_descriptor_binding_missing`. The original
preparation then finds a failed run and cannot start the provider.

**Expected behavior**

Leave live preparation with its current executor. Do not change its
native coordinator or dispatch another executor. An inactive run must
still pass the existing recovery checks.

**Steps to reproduce**

1. Start heartbeat runtime selection for a remote sandbox.
2. Hold workspace synchronization after native input and coordinator
persistence.
3. Run native startup recovery with the heartbeat execution still
active.
4. Observe an unintended `bootstrap_incomplete` claim and a second
execution.

Refs #17439 for broader remote controller recovery. This change repairs
the current heartbeat startup race. It does not add checkpoint storage
or remote adoption. A separate diagnostics correction is in #17837.

## What Changed

- Pass the existing heartbeat live execution registry to native recovery
claims.
- Check the current registry after locking the run and before any
takeover or coordinator change.
- Return the existing waiting disposition for live preparation. Keep
workspace descriptor validation unchanged.
- Add a PostgreSQL regression at the real runtime-selection boundary and
an assembled heartbeat recovery regression with the real claim service.
- Document the preparation interval and its recovery behavior.

## Verification

- Red: the new runtime-selection test observed an unintended bootstrap
claim on the original code. The heartbeat regression also failed because
recovery dispatched the live run.
- Green on current head `88bec51f10d61eb851eec849e82a80bb198555c7`: all
144 runtime-selection, heartbeat recovery, workspace-preparation and
restart-policy tests pass.
- These cases check an unchanged coordinator, no duplicate recovery
dispatch, a running source run, and normal recovery after the execution
leaves the registry.
- The full native restart integration file passes all 22 available
cases. Nine real-runner process cases are skipped because local Runner
test binaries were removed to recover disk space. The passing cases
include remote startup, old preparation fencing, ownership conflicts,
Stop, and concurrent recovery.
- Direct full server TypeScript check passes: `pnpm exec tsc --noEmit -p
server/tsconfig.json`. Hosted CI passes on this head, including full
test partitions, typecheck, build, native Runner checks, serialized
suites, browser shards, canary and both aggregates. Apex is 5/5 with no
actionable findings. The current head has 54 successful checks, two
expected skips and successful Snyk status.
- `git diff --check`, module boundary checks, and map checks pass.
- A wider local safety run stopped with PostgreSQL error 53100 and
ENOSPC after 64 tests passed. Recursive typecheck also stopped with
ENOSPC. These attempts did not pass. Generated files in this worktree
were removed to free space. The full local test suite and build have not
been run for this change; hosted CI must supply those results.
- Live evidence: a production startup recovery claimed a new run during
outward workspace staging. The second preparation failed before provider
startup. Its exact sandbox was later destroyed with successful cleanup.
The patch is not deployed. A later audited retry on the existing
deployment completed successfully and saved the requested answer once.
An audited operator repair through the normal issue service completed
the final user assignment in Review after the agent API handoff failed.
This acceptance verifies recovered work, not deployment of the new
guard.

## Risks

- A live heartbeat remains responsible for its own completion and
cleanup. Recovery must not compete with it. The registry is
process-local; existing durable ownership checks still govern other
controllers.
- An executor that is still active remains protected until its cleanup
removes its registry entry. This adds no timer, polling loop, schema or
credential change.
- Missing or corrupt workspace descriptors still fail closed. This
change does not authorize replay of unknown provider actions.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, source inspection, tool use
and code execution. The runtime does not expose the exact serving model
ID or context window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 21:34:15 -07:00
4da876ab0b fix(native): always advertise run-scoped readers to provider threads (#16995)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs use a Paperclip tool authority to declare tools to the
provider thread. Codex runs through runnerd.
> - An external-chat wake with a truncated comment batch requires the
agent to call `read_current_wake_comments`. A terminal fence fails the
run if the agent did not read every bound comment.
> - Codex `thread/resume` has no `dynamicTools` parameter. A resumed
thread keeps the tool catalog from its first `thread/start`.
> - The tool authority declared `read_current_wake_comments` and
`read_chat_attachment` only when the current run had a binding. The
tool-contract fingerprint already said that both tools are "always
advertised", so the code and the contract did not agree.
> - When a truncated chat wake resumed a thread that started on an
ordinary turn, the agent could not see the reader. The agent blocked,
and the fence failed the run with `native_current_wake_comments_unread`.
The task then stayed blocked for the board.
> - This pull request declares both readers on every turn and rotates
threads that started with the old catalog.
> - The benefit: truncated GitHub, Slack, and other chat wakes can read
their full comment batch on resumed threads. They no longer fail at the
fence.

## Linked Issues or Issue Description

No public issue exists. This is the bug description, in the fields of
`bug_report.yml`.

**What happened?**

A native Codex run got a GitHub chat wake with a truncated comment
batch. The prompt told the agent to call `read_current_wake_comments`.
The agent searched for the tool and did not find it. It reported a block
(`required_wake_reader_unavailable`). The server sent the reader in the
run's authorized tool list, but the provider thread had resumed. The
fence then failed the run with `native_current_wake_comments_unread`,
and the task became blocked. This happened 6 times on staging for the
same task.

**Expected behavior**

A resumed thread can call `read_current_wake_comments` and
`read_chat_attachment` on any turn that has a binding. The run then
completes normally.

**Steps to reproduce**

1. Start a native Codex session on a task with an ordinary wake. Do not
use a truncated chat wake.
2. Send an external-chat message that makes the wake comment batch
truncated (`fallbackFetchNeeded: true`).
3. The run resumes the same Codex thread. The model cannot see
`read_current_wake_comments`. The run fails with
`native_current_wake_comments_unread`.

**Paperclip version or commit**

Hosted staging release `fc0d390d`. The code is the same on `master` at
`3bbc210`.

**Deployment mode**

Hosted (staging). The native runner uses the `codex_app_server` backend
through runnerd in an external sandbox.

**Agent adapter(s) involved**

Codex (native `paperclip_runner`).

Related history: the existing retained-fingerprint table already lists a
"conditional current-wake reader" rotation. This change fixes a
regression of that contract. I searched open and closed PRs for
`current_wake_comments` and "wake comments" and found no duplicate fix.

## What Changed

- `PaperclipRunnerToolAuthority.definitions()` now always declares
`read_current_wake_comments` and `read_chat_attachment`. Execution stays
fail-closed: without the server-verified binding or scope, a call still
fails with `paperclip_runner_tool_not_advertised` or
`paperclip_runner_chat_attachment_read_scope_unavailable`.
- The native tool-contract fingerprint goes from v17 to v18, with the
two policy values set to `.v2`. Checkpoints from deployed v17 threads,
which may lack the readers, start a fresh provider thread one time with
full task context.
- New regression test: the catalog for an ordinary turn is equal to the
catalog for a truncated chat turn, and it contains both readers.
- New resume tests: the deployed v17 local and remote fingerprints do
not rebind. The existing test that asserted conditional advertisement
now asserts the stable catalog and the fail-closed execution.

## Verification

- Red before the fix: `npx vitest run
src/services/native-runtime/paperclip-runner-tool-authority.test.ts -t
"advertises only real bindings|keeps run-scoped reader declarations
stable"` had 2 failures. The unbound catalog had 48 tools and did not
include either reader.
- Green after the fix: `paperclip-runner-tool-authority.test.ts`,
`native-session-resume.test.ts`, `current-wake-comments.test.ts`,
`chat-attachment-read.test.ts`, `native-execution-input.test.ts`, and
`file-delivery-bridges.test.ts` all pass.
- `native-session-executor.test.ts`: 764 pass and 1 fails. The failure
(`compares export process compatibility … (changed: false)`,
`db.transaction is not a function`) also happens on unchanged `main`, so
this change did not cause it.
- Consequential assumption: Codex does not refresh dynamic tools on
resume. Evidence: `codex app-server generate-json-schema` for codex-cli
0.160.0 shows `ThreadStartParams.dynamicTools`, but `ThreadResumeParams`
has no `dynamicTools` field. The failed staging run also showed it: the
server listed `read_current_wake_comments` as authorized, but the
model's tool search returned no match after `thread/resume`.
- Not run locally: the server `tsc --noEmit` step (the sandbox has a 4
GB memory limit and the process was killed) and `dot-runner.test.ts`
(`cargo` is not installed). CI runs both.
- Not run: a live end-to-end chat wake against a real Codex provider.
That needs a staging deployment.

## Risks

- The fingerprint bump makes every native session that resumes from a
v17 checkpoint start a fresh provider thread one time. Paperclip
rebuilds the full task context, but the provider-side conversation
history is not carried over. This is the same tradeoff as earlier
fingerprint bumps.
- Two more tool declarations use a small part of the Codex dynamic-tool
budget. The assigned-MCP fit check already includes these definitions.
- Follow-up, not in this PR: the native Codex driver reports
`toolRefreshOnResume: true`, and the runnerd fake app server accepts
`dynamicTools` on `thread/resume`. Real codex-cli 0.160.0 has no such
field. Connection-tool continuations that depend on resume refresh need
a separate check.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) from Anthropic, running as a
Paperclip agent with tool use (shell, file edit, and test execution).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

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

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 21:08:00 -07:00
Nicky Leach ea727dc3c2 Preserve plugin session continuity through warm execution and checkpoint recovery (#17820) 2026-10-26 20:25:10 -07:00
DottaandPaperclip 208a093d19 fix(chat): preserve resumed review waits and retry newer saved input (#17725)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/36/changes/paperclip/36
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review agents publish findings and wait for an authorized
reply or head change.
> - Review tools could retain the requester after resume while
completion lost that same wait proof.
> - A yielded report could then queue its own continuation or repeat a
missing-wait error.
> - Ordinary Retry could also select an older failed turn while a newer
saved request had no admission.
> - This change shares the existing authority proofs and canonical
admission owners.
> - Current access, publication, execution and budget gates remain
required.

## Linked Issues or Issue Description

Refs #17318. Builds on the canonical saved-input retry owner in #17733.
Related #16550 covers deferred legacy comments after ownership waits.
The separate recovery repair in #17724 owns the cleanup-to-saved-input
handoff; this PR does not add a second admission owner.

A resumed review could publish an assessment, then turn its
`response_wake` into an immediate `issue_status_changed` wake. A
provider that omitted its continuation could instead repeat a completion
error. A newer linked-human message saved during a budget hold could
also remain unstarted because Retry selected the older failed source.

## What Changed

- Resolve passive review waits through the accepted requester ledger
used by GitHub tools. Require the latest reviewed head, exact company,
task, agent, repository and processed publication under current access.
- Fill omitted/null yielded continuation from that server proof. Permit
an inherited normal tree resume only through its accepted parent
identity. Permit an ordinary follow-up only after this run has a
processed useful reply linked to its exact inbound message. Reject
acknowledgements, partial assessments, pending or uncertain writes as
that reply proof.
- Recheck the same run/review/head/source proof during feedback,
finalization and final status commit. Preserve explicit malformed-input
rejection and Done policy. Add no monitor permission or publication
grant.
- Keep heartbeat and publication projections narrow. Preserve both
published Copilot v62 identities and generate source-bound v63 from the
pinned merged base. No v63 live qualification is claimed.
- Certify the structured isolated-directory binding failure only at its
pre-allocation boundary and only through canonical task Retry. Other
workspace validation reasons and unknown effects remain denied.
- Route Retry to eligible newer saved input through the existing
canonical owner. Preserve the old result and skipped receipt. Require
current principal, source, App, runtime fence, budget, native ownership
and exact cleanup proof.
- Recover absent historical App metadata only through an earlier trusted
processed response receipt and an immutable non-null endpoint claim.
Explicit malformed or conflicting metadata stays denied.
- Revalidate execution through the exact claimed wake, coalesced task
Retry and resolved user-continuation receipt after admission. A second
normal Retry can recover the exact never-started authorization failure
with unchanged saved input. Require empty execution evidence, exact
diagnostics and no allocated or active executor.
- Explain when a recorded result prevents exact replay. Ordinary board
Retry directs a new task message to continue from saved work. Inherited
requester identity alone never grants replay.
- Keep accepted board-message preparation failures with the canonical
task Retry owner. Certify the exact unchanged comment, original user
wake, accepted same-user identity and absence of provider execution. Pin
that source, recheck it at admission, and bind identity initialization
to the coalesced intent and exact claimed successor receipt.
Uncertifiable sources retain an actionable fresh-message refusal.
- Return safe named authority categories for board Retry refusals.
Update execution documentation and capability maps. Add no schema or
polling loop.

## Verification

- A fresh external review request exposed a separate isolated-directory
preparation failure before allocation. Its first normal Retry saved an
intent but admitted no successor. This follow-up certifies only that
exact structured preparation boundary through the existing canonical
Retry owner, with trusted failed settlement and no executor, lease,
result or output. A real HTTP/queue regression reproduces the missing
successor before the repair. Twenty-three current-source safety cases
and the final 98-case Retry/HTTP group pass, including a fresh click
after a denied intent, source revocation, accepted results and the older
direct API remaining denied. The warning case uses actual configuration
preparation and production event append; unknown warning shape or
provider provenance stays denied. Full workspace typecheck, build, maps
and diff checks pass. Renewed hosted normal Retry now succeeds on the
final combined source: it preserves the exact saved request and linked
requester, starts one native successor in a fresh attempt workspace,
publishes the current-head 2/5 assessment and commits In review with
passive response wake.

- A later hosted normal Retry published a low-score assessment but lost
its accepted source identity because the previous attempt failed before
identity initialization. It repeated continuation errors, then submitted
Done. This is failed acceptance, not a successful qualification. The
initializer now retains the exact source only after execution-time
failed-chat Retry authorization; generic Retry and Done policy are
unchanged. A real queue/initializer regression fails with a null source
on the previous code and passes with the newer saved source. Two real
database completion cases verify that source yields the authoritative
wait and commits In review. Renewed hosted normal Retry now retains the
accepted source and exposes the authoritative current-review wait. It
completed after two semantic feedback corrections (wrong contract
revision, then wrong criterion IDs); the correct contract was present in
emitted input. The third finish was accepted and committed In review,
with no missing-wait loop or Done escalation.
- Repeated board-message preparation failures now walk their canonical
intent, failed dispatch and accepted parent identity, rechecking each
contained predecessor. A production queue regression fails the second
ordinary HTTP Retry before the repair and passes afterward. Changed
source, contradictory execution evidence and cyclic receipts remain
denied; traversal stops after twenty links.

- New inherited omission cases failed before the repair. The final full
PostgreSQL 18 wait/status suite passes **252 tests** under Node 24.22.
It covers omitted/null input, malformed-first recovery, same-head
resume, exact-source replies, changed heads, revoked access,
pending/uncertain/mixed publications, final commit revalidation, no
duplicate review and no self-wake.
- **15 existing publication tests passed before the pinned merge** on a
separate fresh database. They retain default partial-delivery and
failure-fallback behavior. Context reads remain below the unchanged 16
KiB heartbeat and publication response limits with large saved output
present.
- Saved-input tests cover a real signed PR webhook, production
accounting-budget refusal, normal policy recovery and canonical Retry.
Historical producer-shaped tests prove the missing-App case red, then
check trusted prior receipts and malformed, late, revoked or mismatched
proof. A broader order-coupled test was reproduced on the prior source;
its global fault injector now targets its own authorization query. The
43-case sequence passes without changing production behavior or its
safety assertions.
- New signed-ingress and real heartbeat execution tests reproduced the
admitted-successor failure, then the next normal Retry failure. The
final pinned merged source passes 249 full GitHub review/publication and
Retry cases on a fresh database, including all 49 saved-input cases. A
separate 74-case Retry/HTTP run also passes. Exact dispatch negatives
cover source, company, agent, task, successor, receipt, pause,
assignment, accepted success, controller and cleanup proof. Bootstrap
contradictions remain denied. The canonical Retry suite passes 16 cases
through its supported external PostgreSQL test connection.
- The normal board HTTP route reproduced the unusable inherited-result
refusal. It now returns actionable guidance without starting a
successor. The actual UI Retry hook and banner tests pass 12 cases.
- A production-shaped accepted board comment followed by a pre-provider
qualification failure reproduced HTTP 409 before the repair. The final
real HTTP/queue test certifies one canonical successor and preserves the
accepted identity. It rejects changed source, actor, task, agent,
result, controller, process, profile, allocation and receipt evidence. A
post-acceptance source change keeps the same intent pending. Execution
revalidation rejects removed or mismatched proof. The probe stops
deliberately after production identity initialization; it does not claim
provider execution. The final source passes the 75-case Retry group, the
focused two-case board/inherited-policy group and 19 canonical Retry
cases. Full workspace typecheck, build and map checks pass.
- Full workspace `pnpm -r typecheck` and `pnpm build` pass. Map,
module-boundary and diff checks pass. Full local `pnpm test:run` remains
unverified. The 256-case explicit-native suite cannot initialize its
packaged PostgreSQL because libzstd is absent; an existing
command-scoped fallback did not resolve it. Current-head remote
full-suite checks are required. Merged-source full GitHub+Retry (249),
separate Retry/HTTP (74), full wait/status (252), profile/history and
completion (75), and visible Retry hook/banner (12) checks pass. The
fresh owned PostgreSQL 18 databases applied all 377 migrations.
- Actual Rust Runner, OpenCode 1.18.34 and exact DeepSeek used unchanged
production-generated synthetic contexts. Resume finished with an
explicit server wait. The author-reply trial omitted continuation twice:
its first report failed the existing empty-criteria check; the corrected
second report still omitted continuation and received the exact server
wait. It completed once with no missing-wait loop or Done escalation.
Controller acknowledgments were synthetic; these probes do not establish
hosted publication or board state.
- Hosted combined testing proved automatic admission of the exact saved
author reply, a useful GitHub answer and committed passive wait. It
required two malformed-continuation rejections before a nullish fallback
succeeded. A later normal Pause/Resume completed in one finish with
explicit response_wake and no new review/comment. The admitted normal
Retry then exposed the execution guard gap repaired here. Those remain
checkpoint results. On the final combined source, renewed normal Retry
completed actual native provider work and GitHub publication, committed
the passive wait, released ownership and cleaned up its environment. A
subsequent ordinary unmentioned author reply woke once, made no GitHub
tool calls or new assessment, and completed its first finish with an
explicit response wake. Both exact leases expired with successful
cleanup and the queue was empty. However, final destination inspection
found a separate automatic fallback overwrote the existing summary with
a generic no-final-response message. External summary preservation
therefore remains failed acceptance; the separate publication repair in
#17726 owns that producer. Full combined publication preservation has
not passed. These hosted runs include the pinned-base native additions;
they do not qualify Copilot v63.
- Current-head automated review is 5/5 with zero unresolved threads. All
current-head CI gates passed (54 successful checks/contexts, four
skipped, none pending). The earlier login-cleanup idle-work assertion
also reproduced locally while its controlled baseline passed; its cause
remains unknown, but the exact assertion passed in the fresh
current-head CI shard. No timeout, assertion or production workaround
was added. This PR is ready for review within its source, authority,
native finalization, state, wake and cleanup scope. The independent
automatic fallback publication regression is tracked by #17726; no
complete combined workflow pass is claimed.

## Risks

- The latest saved review defines the durable head boundary. Ingress
must record a new head before admission. A reply receipt proves delivery
only for its exact saved source; a shared GitHub comment ID alone cannot
authorize this wait.
- Historical App recovery cannot infer identity without direct proof or
an earlier valid server response receipt. It never replays that
response.
- This does not infer review-score policy from instructions or override
Done. No deployment, merge or repair of historical tasks is claimed by
the PR.

## Model Used

OpenAI `gpt-6.1-sol`, with reasoning, repository inspection, code
editing and test execution. The context-window size is not exposed in
this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [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 database and
native suites; full local suite limitation 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 (verified on immutable latest
head)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(verified on the latest head)
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 22:22:47 -05:00
DottaandPaperclip f0877a9c7c fix: recover native work and requalify saved computers (#17724)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/32/changes/paperclip/32
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and preserves their work after an
interruption.
> - Native Stop must confirm termination and save the workspace.
> - Task and run views must show the current recovery receipt.
> - A new external reply can arrive while that cleanup is pending.
> - The reply must return to its original chat owner after cleanup.
> - A successful fresh retry also becomes the task’s bound workspace for
its next ordinary turn.
> - Managed computer updates can invalidate a saved snapshot
qualification.
> - This pull request fixes those instructions, acknowledgements,
handoffs and the existing native-agent Test path.
> - The operator can continue with new input while the stopped turn
remains preserved.

## Linked Issues or Issue Description

**What happened?**

Stopped native runs could keep the initial workspace-repair instruction
after files were recovered. Native Stop could also leave the shared
cancellation state at requested after remote termination was confirmed.
A new GitHub reply saved during cleanup could then remain queued because
cleanup did not ask its original inbound owner to reconsider the
receipt. After a managed snapshot update, an existing native agent could
also need qualification while the generic environment Test required
instance-admin access.

**Expected behavior**

Show the current saved-work state. Acknowledge Stop only after exact
termination proof. Let an authorized operator use the existing
saved-agent Run test to qualify its current computer. After cleanup,
recheck the saved reply's current authority and admit it once as new
input. Preserve the stopped run and uncertain external effects.

**Steps to reproduce**

1. Stop an active native turn before it returns a semantic result.
2. Send a new authorized external reply while cleanup is pending.
3. Let workspace recovery and provider cleanup finish. Inspect the run
instruction, Stop acknowledgement and queued reply.

Related work: #17594 preserves native processes through controller
outages. #17401 addresses a separate bootstrap failure. This pull
request does not replace those fixes.

## What Changed

- Use the exact run's workspace recovery receipt for task and run
guidance, including the Activity ledger.
- Retire an obsolete exact-session notice through the existing bounded
reconciler. Preserve the separate no-replay hold.
- Write the shared native Stop acknowledgement only after the audited
Stop intent and every exact remote lease receipt match.
- Delegate saved external input to the live inbound owner. Recheck its
source, actor, endpoint, principal and conversation generation. Promote
the same receipt in the transaction that creates its new run.
- Use that owner from the cleanup callback and existing stranded-queue
catch-up after a lost callback or restart. A denied source cannot abort
other items.
- Reuse the current private task directory after a successful fresh
retry. Re-read the company/task/workspace binding and validate the
canonical stable or attempt namespace without recreating missing files;
keep a later fresh retry separate.
- Extend the existing agent-scoped qualification owner to native agents.
The clean saved-agent Test qualifies its exact computer before runtime
testing. Reuse a current proof; require a real probe and verified
cleanup for a stale proof. Preserve draft tests and metadata-only
external/pool previews.
- Update execution semantics, capability maps and the recovery
verification recipe. Add a production-page Storybook interaction for the
normal native Test.

## Verification

- **Red:** persisted recovery states returned stale instructions; an
exact terminated native lease left shared Stop requested; the real
GitHub subscribed-message fixture left zero successors after cleanup.
The controlled baseline restored the previous production source,
reproduced the failure, then restored the fixed bytes with matching
SHA-256 hashes.
- **Green:** 382 durable-chat, native-continuation, Stop and recovery
tests pass. The real GitHub/PostgreSQL handoff matrix passes 12/12. It
covers callback, application restart, callback/sweep race, valid input
behind a deleted source, and denial for unknown stop, wrong allocation,
paused endpoint, revoked principal, deleted or changed source, changed
conversation generation and foreign scope. Repeated callbacks preserve
one receipt, its actor, one successor and the unchanged stopped
predecessor.
- **Workspace continuation red/green:** the real PostgreSQL preparation
flow created a fresh attempt and saved a marker, then rejected the next
ordinary turn with the same binding mismatch observed in deployed use.
The repaired preparation and filesystem suites pass 86/86: stable and
attempt-root reuse, saved-marker preservation, a later clean sibling,
changed current bindings, foreign company/task, closed workspace,
traversal, missing path and symlink refusal. No task row reset or
old-turn replay is used.
- **Qualification red/green:** a native saved-agent qualification
returned 422, and its normal Test skipped qualification. The repaired
path passes 224 qualification/immutable-snapshot/environment tests and
176 UI/upgrade tests. It covers revoked authority, foreign or changed
computer, current-proof reuse, failed/missing proof, draft settings,
settings changed during the probe, and external/pool previews. On exact
current source, the real local Harness / Runtime UI also qualified a
newly saved disposable Computer with missing proof through actual
Daytona, then completed the actual OpenCode/OpenRouter hello probe using
`openrouter/deepseek/deepseek-v4.1-flash-1017`. Supported availability
changed from Legacy-only to Paperclip Runner after proof persistence.
Qualification and runtime leases both completed normal release/cleanup.
The five prior task run IDs were unchanged; no task wake was created.
This is macOS source-server/UI with real Linux Daytona and provider
services, not a hosted UI claim. Test probes are archived by the
existing inspection contract; release does not claim physical deletion.
- Full workspace `pnpm -r typecheck`, `pnpm build`, token, map and diff
checks pass at `f6450f4739fc8141815b8b7c35fde22a655c5f90`. The broad
local `pnpm test:run` passed 24,899 tests and reported one existing
nested-clone test timeout at 15 seconds. The complete failing file then
passed 21/21 with the normal timeout; the exact case also passed on the
pinned earlier baseline. The broad runner stopped before its later
groups. No timeout or production workaround was added. Prior head
`f6450f4` has 53 successful checks, two conditional Storybook skips and
Greptile 5/5 with no inline threads. New workspace-reuse head
`fcb13399ec70f92f71bd8250081251dca3f48962` passes workspace typecheck,
full build, 86 scoped tests, maps and diff checks; Current-head CI has
53 successful checks and two conditional Storybook skips; Greptile is
5/5 with no inline findings. Deployed ordinary-turn reuse acceptance
passed as described below.

- **Hosted Stop proof:** the real GitHub issue-mention path used native
OpenCode, `openrouter/deepseek/deepseek-v4.1-flash-1017`, Daytona and an
exact low-trust task boundary. Normal UI Stop interrupted an active Bash
call. Native and shared acknowledgements matched the exact lease.
Automatic recovery saved exactly `STARTED\n` (8 bytes), with no finish
marker. Reload showed Stopped and saved work recovered. Only the
original cancelled run remained. Normal five-minute cleanup completed
its exact provider-destruction transition.
- **Limits:** the provider buffered command output, so the marker was
read after recovery. The approved local provider credential could not
inspect the hosted sandbox; its 404 is not deletion proof. Cleanup
success comes from the exact lease's platform destruction transition. An
earlier hosted stale instruction disappeared after rollout with
unchanged raw run/action data; that historical cause remains
unexplained. Original incident holds and publication receipts were
untouched.
- **Hosted handoff proof:** after QA deployed the combined candidate
containing `46b2e99`, startup admitted the previously saved GitHub
author reply without another comment, Retry or manual action. The new
native run used the exact original wake receipt and saved comment. It
completed once, committed an external-response wait, preserved the
stopped predecessor, emptied the queue and left the task In review. The
answer appeared in the original GitHub conversation. Workspace
finalization and the exact lease's normal destruction transition
succeeded.
- **Hosted workspace proof:** on the combined candidate containing
`fcb13399`, normal Retry preserved the original authenticated GitHub
request and completed a fresh native attempt. One later ordinary
same-head author reply then completed in the exact same workspace ID and
attempt directory, with no Retry/fresh directive. Its input tree digest
matched the Retry's finalized digest; final copyback preserved that
digest. The persisted assessment row and all five prior run records were
unchanged, exactly one new reply run completed, and the task returned to
In review with an empty queue and no live run. Both exact leases
completed normal verified destruction. This used real native OpenCode,
the exact DeepSeek/OpenRouter model and Daytona, without workspace-row
repair or a new remote marker.
- **Publication limit:** the workspace audit compares the persisted
assessment and run history. The ordinary reply exposed a separate
destination-summary fallback that changed the visible GitHub summary
despite the preserved assessment row. The publication track is repairing
that behavior; this proof does not claim the visible summary was
preserved.
- **Deployment boundary:** current-head CI/review and hosted same-source
Retry/ordinary-workspace reuse acceptance passed. The separate
visible-summary publication failure remains owned by the publication
track. Combined hosted UI confirmation of the native-agent Test path is
coordinated separately. Actual missing-proof UI/provider qualification
has passed in the isolated local instance above; prior hosted Stop and
same-input handoff proof remains separate. No merge or deployment is
performed by this pull request.

## Risks

Recovery state and termination receipts must match the exact source run
and allocation. Missing or foreign proof keeps the hold. The chat owner
must retain the original receipt and actor and recheck current
authority. Cleanup cannot grant authority or replay the stopped turn.
Existing native ownership, Stop, budget, permission and uncertain-effect
guards remain in place.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) through Codex, with reasoning,
repository tools, source editing and test execution. The context-window
size is not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [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 (affected suites and
isolated failing file pass; broad timeout retained 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 (current fcb has 53 successful
checks/two conditional Storybook skips)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 22:21:58 -05:00
6874fed05c feat(adapters): refresh model catalogs and sandbox CLI pins (Oct 23 audit) (#17809)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/26/changes/paperclip/26
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents run on coding harnesses. Each adapter has a model catalog,
and sandboxes contain pinned CLIs.
> - Upstream providers released new CLI versions and new models. OpenAI
retired some Codex models for ChatGPT sign-in.
> - A stale catalog hides valid models. A misleading error makes
operators upgrade a CLI that is already current.
> - This pull request adds verified OpenCode model IDs, names Codex
ChatGPT retirements in the environment Test, and refreshes the sandbox
CLI pins.
> - The benefit is that operators can select current models and get the
correct reason when a retired model fails.

## Linked Issues or Issue Description

Refs #16708 (adds Claude Haiku 5.5 to `claude_local`; this PR does not
duplicate it).
Refs #17245 (moves the Codex runtime to 0.163.0; this PR does not change
Codex pins).

**What happened?**

OpenAI retired `gpt-5.5` (October 14, 2026) and `gpt-5.4` /
`gpt-5.4-mini` (August 31, 2026) from Codex with ChatGPT sign-in. A
saved agent with one of these models and ChatGPT sign-in now fails. The
legacy environment Test says that the plan, the rollout, or an old CLI
can be the cause. The Paperclip Runner Test gives generic account and
runtime advice. The real cause is the retirement.

**Expected behavior**

Both Tests give the retirement date and the documented replacement.
API-key users keep the models.

**Proposed change**

Record the verified retirements. Add the new verified OpenCode IDs.
Refresh the sandbox CLI pins with verified digests. Record the audit.

## What Changed

- Codex: add a table of models retired from Codex with ChatGPT sign-in
(`gpt-5.5` → `gpt-6.1-sol`, or `gpt-6-luna` on Free and Go; `gpt-5.4` →
`gpt-6-sol`; `gpt-5.4-mini` → `gpt-6-luna`). The shared
`codexChatGptRetirementHint` builds the hint. The legacy CLI Test
(`codexHelloProbeModelRejectionCheck`) and the Paperclip Runner Test
(`testNativeRunnerAuthentication`) both use it when the backend rejects
one of these models. For other failures, the Paperclip Runner Test hint
stays the same. The picker keeps the models for API-key users.
- OpenCode: add `anthropic/claude-haiku-5-5` and `google/gemini-4-argon`
to the remote fallback catalog. The Paperclip Runner OpenCode picker
also uses this catalog.
- Evaluation image sandbox layer (`docker/daytona-runner`):

  | CLI | Before | After |
  | --- | --- | --- |
  | Grok CLI | 1.0.46 | 1.0.70 |
  | Gemini CLI | 0.62.0 | 0.65.0 |
  | Kimi Code | 2.1.1 | 2.3.3 |
  | Cursor CLI | 2026.10.01-e373342 | 2026.10.22-27dcf5f |
  | GitHub CLI | 2.102.0 | 2.103.3 |

- Add `doc/adapter-model-audit-2026-10-23.md` with sources,
compatibility findings, and deferred items.

No model in this PR needs a newer Codex, Claude, or OpenCode runtime
than the current pins. Claude Haiku 5.5 needs Claude Code 2.1.293 or
later; #16708 records that floor, and this PR does not add it.

## Verification

- `vitest run src/index.test.ts src/server/test.remote.test.ts
src/server/acp.cli-version.test.ts` in `packages/adapters/codex-local`:
41 passed.
- `vitest run src/services/native-runtime/setup-readiness.test.ts` in
`server`: 98 passed. These include the two new Paperclip Runner Test
cases: a retired model shows the retirement hint, and a model that is
not retired keeps the generic hint. The retirement case fails on the
earlier code. Run with the host's empty `ANTHROPIC_BASE_URL` unset; see
the baseline note in the audit doc.
- `vitest run` in `packages/adapters/opencode-local`: 87 passed.
- `vitest run src/__tests__/adapter-models.test.ts` in `server`: 27
passed.
- `tsc --noEmit` in `packages/adapters/codex-local` and
`packages/adapters/opencode-local`: passed.
- Cursor archive SHA-256
`85296944e4600a83c4b764f578d1502bf9c416db200d33a593e8f3ecabfdc294` is
computed from the versioned Linux x64 tarball. The extracted binary
reports `2026.10.22-27dcf5f`. On October 26, 2026,
`https://cursor.com/install` still resolves this version.
- GitHub CLI SHA-256
`4c806978ffce1cec70853302a56d70ac6da4f19bae7adca4e1a8ab00633dd91d`
matches `gh_2.103.3_checksums.txt`.
- Grok CLI 1.0.70 and Kimi Code 2.3.3 installed from npm report those
versions. The flags that Paperclip uses (`-m`, `--effort`, `grok
models`; `-m`, `-p`, `--output-format`, `acp`) are present in `--help`.
- `git merge-tree` with #16708 (head `3a06740e9`) and #17245 (head
`41f9c611f`): this PR shares no files with either PR. The two PRs can
merge in any order.
- Not run in the authoring environment: the full `pnpm -r typecheck` and
`pnpm build` (no Rust toolchain), the full server `tsc` (memory limit),
and the image build. CI runs these.

## Risks

- Low risk for catalogs: the IDs are additive suggestions. No saved
selection, default, or spending setting changes.
- The Paperclip Runner Test changes only the hint text, and only for a
ChatGPT rejection of a retired model. Check codes and pass/fail results
do not change.
- Sandbox CLI pins:
- Kimi Code 2.2.0 and 2.3.0 remove the `kaos` MCP executor and require
qualified plugin skill names. Paperclip uses neither. Kimi Code 2.3.2
stops automatic swarms in `kimi -p` and ACP sessions.
- Gemini CLI 0.65.0 makes workspace settings read-only in untrusted
folders. Paperclip writes home settings and sets
`GEMINI_CLI_TRUST_WORKSPACE` for remote runs.
- xAI publishes no Grok CLI changelog. Grok 1.0.70 behavior changes are
verified only against the CLI reference and `--help`.
- The pins apply only after a new image is built and promoted. The fleet
sandbox image definition must get the same pins.
- Rollback: revert this PR.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, with tool use (shell,
web research, repository search).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 16:32:13 -07:00
DottaandPaperclip 32ec84db2e fix(native): restore plugin checkpoints for same-run retries (#17814)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Native sessions retain provider state across execution attempts.
> - A same-run retry can receive a replacement plugin task lease.
> - The executor loaded the old task checkpoint only for crash recovery.
> - An ordinary retry could fail its local authority check before
reading that checkpoint.
> - This change restores the checkpoint through the existing authorized
lease transfer.

## Linked Issues or Issue Description

**What happened?**

A native provider turn ended without its completion result. Paperclip
scheduled an exact-checkpoint retry on the same heartbeat run. The retry
acquired a new plugin task lease, then failed with
`runner_state_identity_mismatch: authority_indeterminate`.

The checkpoint restore branch required a `resume_dead_runner` restart
claim. Ordinary same-run retries have no such claim. A controlled
fixture with a retained remote checkpoint and no local lifecycle receipt
reproduces the error. The original controller file contents were
unavailable, so that part of the incident mechanism remains inferred.

**Expected behavior**

Load the retained plugin checkpoint after the existing policy proves the
lease transfer is safe. Keep the original run, session, and saved
control journal. Reject an unverified predecessor or a changed
checkpoint identity.

**Steps to reproduce**

1. Start a native session through a plugin task environment.
2. End its provider turn without a completion result and retain its
checkpoint.
3. Retry the same run on a replacement task lease without a restart
claim.
4. With no local lifecycle receipt, observe the authority error before
the checkpoint read.

**Paperclip version or commit**

Reproduced against source `507dc70be26c191e372f09e58dc0965e73bf8f57`.

**Deployment mode**

Native Runner with a plugin task environment. The observed provider used
ACPX Claude. The controlled executor fixture uses the shared native
boundary.

Related work: #17439 concerns recovery after controller replacement.
This fix uses the existing checkpoint contract and does not depend on
that PR.

## What Changed

- Restore prior plugin state for an ordinary same-run attempt when its
lease changes.
- Keep the existing company, agent, workspace, retained-state, and
termination checks.
- Extend executor regressions for ordinary retries, mismatched
checkpoints, and missing stop proof.
- Exercise the same-run checkpoint read through the database-backed task
API.
- Document the recovery rule and verification recipes.

## Verification

- Failing before: the ordinary retry reproduces
`authority_indeterminate`. Both new denial cases also fail because the
old branch never reaches the transfer policy.
- Passing after: all six focused checkpoint cases pass. The saved
control journal stays byte-for-byte unchanged. Rejected cases do not
construct a provider backend.
- `pnpm -r typecheck` passes.
- Map and module-boundary checks pass.
- All 858 executor, database lease-authority, plugin task, and ownership
tests pass. `pnpm build` passes.
- The broad local `pnpm test:run` attempt did not complete. It hit a
20-second timeout in the existing historical workspace-recovery HTTP
Retry case. That exact case then passed in isolation on the unchanged
head. The broad local attempt was stopped after the full CI matrix
passed; it is not counted as a local pass.
- Greptile reviewed current head
`5bc11fa978ab87d3d9c5d575fa9666185aaafc2c` at 5/5 with no actionable
findings. The full current-head CI matrix passed on attempt 2: 55 checks
passed, no pending or failed checks, and two expected Storybook jobs
skipped.
- The first broader local attempt could not bind embedded PostgreSQL
inside the sandbox (`EPERM`). It was stopped and restarted with loopback
access. This was a setup failure, separate from the observed red
regression.
- The first CI attempt failed two existing checks: the process-adapter
signoff happy path exhausted its run wait budget, and the workspace
export scheduler did not reach `complete` within 20 seconds. Both tests
pass in isolated local runs on the unchanged head. Both failed shards
passed on their single rerun without code changes. The initial failures
remain recorded. Their timing cause is not proven by the later passes.
- Live acceptance at the fixed revision has not run. The hosted
workspace still serves the earlier release. No deployment or retry of
the original task is claimed.

## Risks

The new checkpoint read runs only for same-run plugin recovery with a
replacement lease. Missing termination proof, changed scope, or a
changed Runner identity still stops execution. The lease resolver owns
these checks. The fix does not replay tools or change retry budgets. A
turn that omitted its completion result still needs the existing bounded
continuation to finish useful work.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, and code
execution. The runtime does not expose a more specific backend model ID
or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 18:01:55 -05:00
DottaandPaperclip 718c73dafe fix(native): require verified remote process exit receipts (#17799)
Require fresh ESRCH or an exact matching zombie generation before treating a remote Runner as stopped. Preserve uncertain ownership through adoption and transport close, retire local controller resources after failed close, and check Node before remote launch.

Bind the shared transport change in Copilot profile 62 while retaining historical profile decoding. Add red-green process, permission, launch, adoption and cleanup regressions.

Thanks to @hsm-lv for the original investigation in #17073.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 21:39:04 +00:00
DottaandPaperclip 9ae4c25e7e perf(runner): reuse compatible protected provider packs (#17749)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner starts provider runtimes in remote execution
environments.
> - Sandbox images already contain qualified provider packs.
> - Startup required the image pack to match the entire current app
release manifest.
> - An unrelated app commit could therefore cause pack verification,
transfer, and installation again.
> - This pull request selects protected packs by their provider
interface and platform.
> - The benefit is no extra pack probe, directory scan, version command,
link, or upload on the compatible image path.

## Linked Issues or Issue Description

**What happened?**

Starting a remote task can reject a compatible image pack because its
source revision or unrelated provider differs from the controller. Pack
replacement added about 16 seconds in the investigated startup. Startup
also repeated full content checks.

**Expected behavior**

Use an already qualified, protected pack when its selected provider
interface and target platform are compatible. Keep the selected artifact
identity for process launch and recovery.

**Steps to reproduce**

1. Install a qualified provider pack in a sandbox image.
2. Start a controller built from another app commit.
3. Start a remote OpenCode task. The old complete-manifest comparison
rejects the image pack even when the provider interface still works.

Related repairs: #16493 reduced transfer cost. #17512 retained exact
artifact authority during reattachment. This change preserves that
recovery rule and changes fresh-launch pack selection.

## What Changed

- Add explicit OpenCode and ACPX interface revisions to produced pack
manifests. App Git SHAs and dependency pins remain provenance.
- Read bounded protected-installation metadata in the existing final
runner metadata query. Accept only root-owned paths that the execution
user cannot write, including ancestors and manifest. Reject writable
aliases.
- Select and prepare the pack in server-owned environment setup before
constructing the existing transport. Bind provider launch paths and
digests from the selected installation. Save that identity for exact
reattachment.
- Keep full content verification for uploads, writable installations,
and legacy packs. Reuse successful verification within one startup. Keep
older attached runners compatible with the optional metadata request.
- Seal image packs and document the one-time image refresh that enables
reuse across later compatible releases. Keep selected ACPX agent
qualification checks.

## Verification

- Red/green regression: the old code rejects a protected pack from
another app revision with `manifest mismatch`; the fixed path selects it
without executing verification commands.
- Native startup regression: select the installed pack's own Node digest
with one existing runner metadata request and no pack verification or
version commands.
- Targeted pack, artifact, recovery, execution-driver, and Rust metadata
tests pass. Incompatible interfaces/platforms, malformed identities,
writable roots, path aliases, and exact reattachment are covered.
- Final revision `91dc1676ff67bdbe5866c8586daac10240530cca`: workspace
typecheck and build pass. All 53 current-head checks are successful,
with no pending or failed checks. Greptile is 5/5 with no open findings.
- The broad local `pnpm test:run` attempt reported a workspace-runtime
conflict test failure; its isolated rerun passed. The broad run was
stopped after that failure. Full CI now passes, including the server
test shards. This is not a claim that the full local run passed.
- Linux filesystem evidence: the production metadata functions read a
real root-owned preinstalled pack as a non-root user in 16 microseconds
median and 20 microseconds p95 across 100 warm reads. This measures
metadata admission, not model or hosted response latency.
- All 910 affected server tests and 57 Copilot attestation tests pass
locally on the final implementation. Full CI covers the unchanged Runner
transport. No provider qualification hash was refreshed.
- Built the actual Linux daemon at
`416e7ec7425d0d3565b4a5e1808002d650a60414` and ran its metadata command
as UID 65534. The protected installation returned its real manifest with
`immutable: true`; writable alias and missing-pack cases returned
`immutable: false`. This is metadata/permission evidence, not provider
execution.
- Hosted rollout and a hosted end-to-end latency measurement have not
run.

## Risks

- Existing images need one rebuild to publish the compatibility
declaration. Packs without it keep the legacy content-verification path.
- Fast admission relies on image publication producing a qualified
protected tree. Root execution and task-writable installations retain
full verification.
- Bump an interface revision when required runner/pack behavior changes
incompatibly. Deploy a new image to roll out compatible runtime fixes or
upgrades.
- This removes provider-pack preparation delay. Other runner startup,
context, model, and finalization costs remain separate.

## Model Used

OpenAI Codex, configured model `gpt-6.1-sol`, reasoning effort `xhigh`,
with tool use and code execution. The context-window size is not exposed
in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:43:12 -05:00
DottaandPaperclip 063a498b54 Bound native OpenCode assigned-tool catalog projection (#17740)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents use assigned connection tools through a governed
gateway.
> - OpenCode received the gateway catalog directly, outside the bounded
server tool projection.
> - A large catalog can exceed a provider grammar compiler's capacity
even when it fits the transport limits.
> - Synthetic requests reproduced the Fireworks grammar timeout on the
configured DeepSeek model.
> - This pull request gives OpenCode two assigned-tool discovery and
call schemas through the existing server relay.
> - The gateway keeps the same grants, validation, approvals,
revocation, and audit rules.

## Linked Issues or Issue Description

**What happened?**

A native OpenCode run could fail during provider grammar compilation
before its first assigned-tool call. OpenCode advertised the full
assigned gateway catalog. A synthetic catalog of 741 tool schemas
reproduced `Grammar processing took too much time` on Fireworks through
OpenRouter with `deepseek/deepseek-v4.1-flash-1017`. The same model and
backend accepted a compact two-tool discovery/call catalog. This
reproduces the mechanism; it does not replay a historical private
request.

**Expected behavior**

Assigned-tool discovery must keep provider grammar size bounded. Every
call must retain the run's original gateway binding and permissions.

**Steps to reproduce**

1. Give a native OpenCode run a large assigned connection catalog.
2. Use a provider that compiles tool schemas into a constrained output
grammar.
3. Observe the full catalog in the provider tool surface before this
change.
4. After this change, observe only `paperclip_search_assigned_tools` and
`paperclip_call_assigned_tool` for assigned tools. Discover and call a
permitted tool through its pinned alias.

**Paperclip version or commit**

Source checkout based on current `master`.

**Deployment mode**

Native local or sandbox execution with OpenCode 1.18.34.

Related work: Refs #14258 (discovery paging), #16678 (local adapter MCP
launch), and #17688 (gateway capability advertisement). This change
covers native OpenCode catalog projection.

## What Changed

- Route native OpenCode assigned tools through the existing server-owned
authenticated relay.
- Use bounded discovery/call schemas for OpenCode, including small
catalogs. Preserve transport capacity checks.
- Keep assigned gateway credentials on the controller. Ignore gateway
and credential values in tool arguments.
- Preserve exact declared MCP operation names through admission and
driver dispatch. Resolve transport prefixes only against the closed
catalog. Reject unknown or shortened names.
- Refresh former OpenCode direct-catalog and shortened-name checkpoints.
Keep the existing fingerprints for other providers.
- Add local and remote wiring, catalog capacity, alias, scope,
work-mode, approval, and revocation tests.
- Allow the native test files to use a validated dedicated external test
database when embedded PostgreSQL is unavailable.
- Document the assigned-tool execution contract.

- Bound OpenCode discovery pages to 32 KiB and large-schema chunks to
16K characters. Keep other harness budgets unchanged.
- Test medium pages and escaped large schemas through the actual HTTP
MCP bridge on the explicit Runner testing surface.

## Verification

- Red before the catalog fix: OpenCode did not create the server relay,
and forced compact delivery advertised 1 or 741 direct schemas.
- Red before the alias repair: HTTP MCP changed declared operation
names, and the driver sent `search_assigned_tools` instead of the
authorized `paperclip_search_assigned_tools`.
- Current repair tests: 112 OpenCode/proxy tests pass, plus one actual
Rust/proxy/HTTP MCP regression. Two checkpoint regressions fail with the
former scoped revision and pass with the new revision. Other providers
keep their prior fingerprints.
- The combined QA candidate with this exact PR head passes all 916
native tests and all 113 transport tests on supported Node 24.22. An
earlier Node 26.4/macOS run passed the 113 assertions but had an
uncaught networking error. That non-clean run remains recorded; its
stack matches [the upstream Undici
defect](https://github.com/nodejs/undici/issues/5544). No production
workaround or error suppression was added.
- `pnpm -r typecheck`, `pnpm build`, and `git diff --check` pass on
`bc41ba72be2195eabeb0d7727227ee0cd02e8532`. The maps structural check
passes.
- The local `pnpm test:run` attempt stopped after host embedded
PostgreSQL initialization failures. The relevant database suites pass
with isolated PostgreSQL 18. All repository CI gates, including
aggregate `ci / verify`, pass on the current head.
- Synthetic live provider comparison: 741 invented schemas produced the
exact Fireworks grammar timeout in 20.9 seconds. Two compact invented
schemas produced a discovery call in 585 ms on the same model and
backend.
- The first hosted QA attempt exposed the alias failure described above.
On the patched source, a real local Rust runner → proxy → OpenCode
1.18.34 → exact DeepSeek smoke completed discovery, one synthetic
gateway read, and `paperclip_finish`, then emitted `turn/completed`. It
used the production compact projection and unchanged Rust allowlist.
- Two earlier local smoke attempts exposed missing terminal authority
and completion-contract fields in the smoke harness. Those failures
remain recorded. The corrected ordinary bindings produced the clean
result.
- Fresh Greptile: 5/5 on `bc41ba72be2195eabeb0d7727227ee0cd02e8532`,
with no new actionable findings or unresolved threads.
- Hosted QA publication and lifecycle acceptance remain pending. The
separate deployed-agent `Paperclip Review` check is also pending; it
follows a task that failed on the earlier deployed runtime.

- Local OpenCode/OpenRouter acceptance at `bc41ba72`: 530 synthetic
tools were authorized and installed. A simple model-ID reply completed
in 17.3 seconds with no app calls. A discovery task completed in 37.6
seconds, used the search/call relay, made one upstream call, and
returned the exact synthetic value. This is local source acceptance, not
a staging sandbox timing comparison.
- The large-result review finding has a failing-before/passing-after
HTTP MCP regression. Five medium schemas now page without invalid JSON.
A large schema with escaped text reconstructs exactly through bounded
chunks. All 35 assigned-tool tests and the server typecheck pass after
this follow-up.
- Final head `d84ce4856a6e65a35ad5fb8b561492598b525f4e`: all CI gates
pass. Greptile and Paperclip Review both rate the change 5/5. No review
threads remain open. The final full build, server typecheck, and 35
assigned-tool tests pass locally.

## Risks

- OpenCode uses discovery before it calls an assigned tool, including
for small catalogs. This can add a model turn.
- An existing OpenCode provider checkpoint rotates once because it
retains the former tool declarations. Paperclip task history remains
available.
- The historical filtered catalog was not captured. The synthetic
comparison proves the failure mechanism, not the exact cardinality of an
earlier private request.
- No model, provider route, permission, or automatic retry policy
changes.

## Model Used

The bounded-result follow-up also used OpenAI Codex (GPT-6 family). The
exact backend model ID and context-window size were not exposed for that
session. It used reasoning, code execution, and tool use.

OpenAI `gpt-6.1-sol` in Codex, with reasoning, tool use, code execution,
and source inspection. The runtime does not expose the context-window
size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 10:49:23 -05:00
DottaandPaperclip 5823e9a664 fix(runner): preserve disabled Codex web search (#17744)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Codex agents use the saved agent settings to prepare each
provider launch.
> - Onboarding saves web search as off, but native configuration
conversion removes that setting.
> - Codex 0.160.0 includes a hosted web-search tool by default, even in
an authentication probe that asks it not to use tools.
> - A gateway that permits only priced function tools can reject that
request before budget admission.
> - This change preserves the explicit restriction through native
execution and disables web search for authentication probes.

## Linked Issues or Issue Description

**What happened?**

A native Codex authentication probe can include hosted web search.
Normal task execution also loses a saved `search: false` setting. A
restricted Responses gateway can reject these requests before it makes a
model call. Related repairs: Refs #17445, Refs #17529. The roadmap and
related PRs were checked; no duplicate repair was found.

**Expected behavior**

Authentication probes check the selected account and model without
hosted web search. A saved search-off setting remains effective in
native task launches, prepared launches, and session recovery. Existing
behavior for an absent setting remains unchanged.

**Steps to reproduce**

1. Create a Codex agent with search off and choose Paperclip Runner.
2. Use a Responses gateway that rejects hosted tools.
3. Inspect the request from the native authentication probe or task
launch. Before this fix, the pinned Codex SDK includes `web_search`
despite the saved setting.

## What Changed

- Preserve an explicit search-off setting when native agent
configuration is built and converted.
- Carry the restriction in the durable native input and provider launch
requirements.
- Apply the restriction to authentication probes and normal launch
paths, including custom arguments and recovery.
- Reject prepared launches that discard the required restriction. Keep
gateway billing rules unchanged.
- Admit only the restrictive literal value in the strict plugin task
API. Exercise the real plugin setup path.
- Add regression coverage and document the policy.
- Add the immutable Copilot v60 source identity required by the changed
shared files. Preserve v59 and all original live evidence. Copilot
authentication probes keep their prior launch requirements.

## Verification

- Regression cases were run against the unfixed source and failed at the
configuration and launch boundaries.
- An isolated capture using the real Codex 0.160.0 app-server reproduced
hosted-tool rejection. Disabling web search reached a mocked budget
reservation. The helper and child processes permitted only loopback
network access and used synthetic credentials. It made zero upstream
calls.
- Focused checks passed: 284 server cases, 61 native form cases, 198
backend/security/launch/parser cases, and 36 authentication/launch
cases. A separate complete transport/launch/parser run passed 393 cases.
These groups overlap.
- Head `617b98f` passed workspace typecheck/build and 28/28 plugin
contract and actual Runner probe tests with no skips. Final rebased head
`20ff0c1` passed all current-head CI checks, including full isolated
test lanes, and fresh Greptile and Paperclip reviews at 5/5.
- The additive Copilot identity update passed 134
compatibility/policy/protocol checks and nine authentication probe
checks. The real pinned Codex SDK capture was repeated after the final
policy change: all five cases passed with zero upstream calls.
- Two local full-suite attempts stopped after native PostgreSQL loader
failures. Seven local dependency aliases were restored, and an isolated
cluster initialized successfully. A third run later encountered host
PostgreSQL semaphore exhaustion and was interrupted before
source-profile regeneration. Its zero exit code after SIGINT is
explicitly not a full-suite pass. Final full-suite verification runs in
isolated CI; the local attempts remain recorded.
- The first CI run exposed a missing strict plugin API field. Its five
failures were reproduced locally, then passed after repair. The next run
passed every underlying job except the source-identity guard. That guard
now binds an additive identity with v59 retained. Final-head CI and both
fresh reviews passed; addressed review threads are resolved.
- The offline capture runs on Darwin ARM64. It does not prove the
contents of a prior unretained Linux request or complete Cloud
onboarding acceptance.

## Risks

- The restriction must survive prepared launches and resumed sessions.
Regression tests cover those boundaries.
- Existing absent settings retain their prior behavior. This change does
not add native search-on support or loosen gateway admission.
- Older durable inputs without the optional restriction must remain
valid.
- Copilot now uses profile v60 for exact launch admission. Historical
v59 inputs remain readable. The new declaration adds no live Copilot
qualification and does not change its executable or admission flags.
- A deployed Cloud acceptance run is still required after this source
repair.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code execution, and
delegated review. The exact backend model identifier and context-window
size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 10:29:51 -05:00
Devin FoleyandPaperclip 6336c34041 perf(chat): narrow bound-conversation authorization reads (#17684)
Read current identity, policy, and setup credentials without transferring unused chat content. Preserve company predicates and all three lock modes.

Verified workspace and server typechecks, the server build, 246 selected tests, all CI checks, and Apex 5/5. The setup cases use fixed ordered receipt and processing timestamps.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 20:04:45 -07:00
Devin FoleyandPaperclip 5a28f7acf8 fix(server): include restored monitor proof in assessment identity (#17665)
Include validated preserved monitor proof in the immutable assessment input so restored receipts or completion times can produce a new status decision at the same deadline. Preserve accepted results, earlier decisions, provider attempts, monitor deadlines, and idempotent replay.

Validate two baseline regressions, 201 targeted tests on current master, workspace typecheck, server build, full CI, and Apex 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 16:06:36 -07:00
Devin FoleyandPaperclip 332e4c5df9 fix(native): settle completed results that retain a valid monitor (#17641)
Preserve a valid saved monitor after its successful source releases execution and checkout. Recheck accepted result identity, receipts, ownership and governance under the task lock. Notify the existing scheduler once and preserve accepted live and recovered replies.

Apex 5/5 after fixing its reply-presentation finding. All CI checks, 191 focused tests, 293 broader native tests, workspace typecheck and server build pass. Hosted effects require staging verification.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 10:47:02 -07:00
Devin FoleyandPaperclip b792165ba4 Expire native runner continuity archives and quarantine (#17616)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native runner sessions keep durable state under
`<instance>/runtime/paperclip-runner/durable-sessions/`
> - When a session starts a fresh provider session, the retired state is
moved into `<session>/continuity-breaks/<epoch>-<uuid>/`; when state
loses authority, it is moved into
`quarantine/<session>.<reason>.<epoch>.<pid>.<uuid>/`
> - Nothing ever removes either, and each can hold a full Codex home of
several gigabytes
> - A sleep-aware sweep already expires failover backup copies in the
same tree
> - This pull request extends that sweep to remove both kinds of
evidence after a retention window, while keeping anything recovery may
still read
> - The benefit is that native runner disk use stops growing without
bound

## Linked Issues or Issue Description

Bug report described in-PR (bug report template).

**What happened?**
On one instance, one day of native runs produced 20 continuity-break
archives totaling 4.8 GB, one session alone holding 4 GB. The quarantine
folder held 12 entries totaling 2.1 GB, the oldest a month old. Neither
is read again by normal operation (continuity-break archives are written
by `archiveContinuityState` and never read), and nothing deletes them.
They were removed by hand to free space and will regrow.

**Expected behavior**
Evidence older than a bounded window is removed automatically, as
failover backup copies already are, without removing anything a live
session or recovery path still needs.

**Steps to reproduce**
1. Run a native Codex session that hits a continuity break (fresh
provider session), or whose state is quarantined (for example
`identity_indeterminate`).
2. Inspect `durable-sessions/<session>/continuity-breaks/` and
`durable-sessions/quarantine/`.
3. Wait any length of time: the entries stay forever.

**Paperclip version or commit:** `master` at e335265568.
**Deployment mode:** any with native runner sessions.
**Agent adapter(s) involved:** native runner (Codex, and any provider
whose state lands in these folders).

## What Changed

-
`server/src/services/native-runtime/native-harness-backup-expiration.ts`:
the existing tick also retires evidence.
- **Continuity-break archives** (`<epoch ms>-<uuid>` under each
session): removed when older than the window. Age is the epoch in the
name, or the folder mtime when that epoch is in the future.
`archiveContinuityState` refuses to archive state with warm-transition
evidence, and no code path reads `continuity-breaks`.
- **Quarantine entries**
(`<session>.<identity_indeterminate|identity_mismatch>.<epoch
ms>.<pid>.<uuid>`): removed by the same age rule. Native cleanup source
archives (`<session>.identity_indeterminate.cleanup.<uuid>`) are
referenced from recovery history, have no epoch, and keep their original
inode's mtime, so they are always kept.
- Every entry is skipped while its session is executing, initializing,
warm, or closing in this process; this is checked again just before
removal. Symlinked entries and symlinked
`continuity-breaks`/`quarantine` folders are reported as `unsafe_path`
and never followed.
- Removal renames to `.expired-<uuid>` in the same folder and then
deletes; later sweeps finish interrupted deletions. An empty
`continuity-breaks` folder is removed.
- Archives, quarantine entries, and leftover deletions count toward
`maxEntries` and `maxRemovals`, and stop on `shouldContinue`. Paging
resumes inside a session's archives and then in quarantine, so a bounded
or dry-run batch always makes progress and never recounts a session's
backup.
- New result fields: `evidenceCandidates`, `evidenceCandidateBytes`,
`evidenceRemoved`, `evidenceReclaimedBytes`, and skip reasons
`recent_evidence` and `cleanup_archive`. The service also exposes
`noteEvidence(writtenAt)`.
- `server/src/services/native-runtime/native-runner-evidence-signal.ts`
(new): a process-local signal. `native-session-executor.ts` raises it
with the entry's epoch right after `archiveContinuityState` creates an
archive and after `quarantineRunnerdStateRoot` moves state into
quarantine; `server/src/index.ts` subscribes the sweep and unsubscribes
on shutdown.
- `server/src/config.ts`:
`PAPERCLIP_NATIVE_RUNNER_EVIDENCE_RETENTION_DAYS` (default `7`, minimum
`1`).
- `server/src/index.ts`: passes the window and logs a batch when it
found evidence candidates.
- `doc/recoverable-disk-cleanup.md`, `doc/DEVELOPING.md`: document the
variable and behavior.

**Sleep-aware background work**
(`rules/sleep-aware-background-work.mdc`):
- *Trigger:* each entry's own expiry deadline (its epoch plus the
window), plus a direct call from the executor when it writes new
evidence. No timer, interval, or polling loop is added; the pass runs
inside the existing sweep's tick and keeps its drain, warm-standby, and
shutdown handling.
- *Source of truth:* the filesystem entries themselves. After a restart
the first sweep reconstructs the next deadline from them.
- *Pending-work predicate / next deadline:* after a full pass the sweep
keeps the earliest due time of the entries it retained; ticks before
that time skip the evidence pass entirely (no readdir, no SQL). A busy
session, a failed removal, or a full batch makes it due on the next
sweep while that obligation remains.
- *Quiet condition:* no evidence, or only evidence not yet due. The pass
never queries the database, so retained evidence never causes recurring
SQL. Dry run reports each candidate once rather than every hour.

No code comments were added.

## Verification

- `pnpm exec vitest run src/__tests__/native-harness-backup-expiration`
(in `server/`, embedded Postgres): 52 passed. New cases:
- old archives and quarantine entries are removed, recent ones kept; the
empty `continuity-breaks` folder is removed;
- age comes from the name, with mtime used for a future epoch;
non-archive folders are ignored;
- a busy session keeps its evidence, including when it becomes busy
after the first check, and it is retried on the next tick;
- dry run reports candidates and bytes, changes nothing (including
leftovers), and reports each candidate once until new evidence comes
due;
- symlinked entries and symlinked evidence folders are skipped without
touching the target;
- an old quarantine entry is removed even when its session's issue is
still open; cleanup source archives are kept;
- the pass stays quiet until retained evidence is due, and a
`noteEvidence` signal schedules newly written evidence;
- inspected archives and leftovers count against `maxEntries`, and
leftover removal stops on `shouldContinue` and resumes next tick;
- a due pass stopped by drain before any session stays pending;
one-entry batches finish without recounting a resumed session;
- interrupted `.expired-*` deletions are finished; paging across ticks
with `maxRemovals`, in normal and dry run, with no recount of the backup
when resuming.
- `native-session-executor.test.ts`: quarantining a legacy root raises
the evidence signal with the epoch in the entry name.
- `native-harness-backup-expiration-config`: default, explicit, minimum,
and fallback parsing.
- **Mutation checks**, each failing at least one test: removing the age
check, the future-epoch fallback, either busy check, the busy retry
deadline, the recent-entry deadline, the due gate, the `noteEvidence`
update, merging the pass deadline, the entry and both folder symlink
checks, the dry-run return, the dry-run leftover guard, leftover
removal, the leftover budget check and its retry deadline, counting
archives against `maxEntries`, the cleanup-archive skip, the
empty-folder removal, the resume cursor, the per-archive budget check,
the resume skip of the backup pass, not charging a resumed session,
keeping the pass active across drain, and the executor's quarantine
signal.
- `pnpm exec vitest run config native-harness
native-workspace-sync-retention native-session-executor server-startup`
(in `server/`): 1272 passed on the previous commit; `config
native-harness native-workspace-sync-retention server-startup`: 450
passed on the head commit.
- `pnpm run typecheck` (in `server/`): pass.
- Not run: server build and boot smoke. The continuity-archive signal
call is exercised only by a runner integration test that needs the
runnerd binary.

## Risks

- **Quarantine as a fail-closed fence:** recovery
(`recoverQuiescentRunnerdState`) and failed-run retry
(`nativeFailedRunRetryStateIsSafe`) treat a quarantined entry for a
session as a reason not to bootstrap fresh. Once such an entry ages out,
a later run of that session can start a fresh provider session instead
of failing with `quarantine_owner_unverified`. This applies only after
the window, matching what backup expiry already accepts for closed work.
- **Signal coverage:** the signal is process-local. Evidence written by
another process sharing the same state directory is picked up when the
next retained deadline is due or after a restart, not immediately.
- **Legacy-path quarantine:** entries quarantined from legacy roots
carry a legacy digest, so the in-process busy check cannot match them;
they are removed by age only.
- **Remote sandboxes:** archives moved aside on a remote runner
(`<root>.continuity-break-<token>`) are outside this sweep.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), 1M context, through Claude Code
with tool use (shell, file edits, tests).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-25 09:20:30 -07:00
Devin FoleyandPaperclip 34409a92c4 fix(native-runtime): stop failover backups from carrying throwaway provider state (#17618)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native runner sessions on managed sandboxes keep a failover backup
of provider state, so a replacement sandbox can resume the session
> - Each backup copies the provider's runtime directory, with a
per-directory sha256 manifest, minus `excludeEntries`
> - Codex already excludes credentials and re-downloadable plugin
caches; OpenCode excluded nothing, and ACPX excluded only per-agent
credentials
> - OpenCode also leaked a temporary HOME on every launch, because
removing it failed on the read-only skill snapshot inside and the error
was swallowed
> - So every backup carried every earlier launch's HOME (with its npm
cache) plus re-installable plugin `node_modules`
> - This pull request removes those homes correctly, sweeps homes left
by earlier versions, and excludes the throwaway entries from OpenCode
and ACPX backups
> - The benefit is much smaller backups and live session directories,
while session history is still backed up and restored

## Linked Issues or Issue Description

Bug report described in-PR (bug report template).

**What happened?**
On one instance, current native failover backups totalled 24 GB across
about 300 sessions. For OpenCode sessions:
- `opencode/<session>/home-XXXXXX/`: 170 per-launch HOME directories
across 67 sessions, 9.3 GB. Each held `.npm` (about 111 MB of npm
cache), `.claude` (the skill snapshot) and `.local`.
- `opencode/<session>/config/opencode/node_modules`: 68 sessions, 4.3 GB
of OpenCode plugin installs.

One ACPX session also carried `acpx/<session>/data/pnpm/store` (229 MB
in the current backup, several GB in older copies).

Cause of the leaked homes: `startRuntime` in the OpenCode driver creates
a fresh `mkdtemp` HOME for each launch and seals the assigned skills
inside it (directories `0555`, files `0444`). `close()` and the
startup-failure paths removed it with `rm(..., { recursive: true, force:
true }).catch(() => undefined)`. That fails with `EACCES` on the sealed
directories, and the failure was ignored, so each launch left its HOME
behind.

**Expected behavior**
Per-launch homes are removed when the runtime closes, and backups hold
only state needed to resume a session. Caches that the provider
re-creates are left out.

**Steps to reproduce**
1. Run an OpenCode native session with at least one assigned skill on a
managed sandbox, over several turns or runs.
2. Inspect `<session>/` in the OpenCode runtime directory: one
`home-XXXXXX` per launch remains.
3. Inspect `failover-backups/current/opencode/<session>/`: the same
homes and `config/opencode/node_modules` are in the backup.

**Paperclip version or commit:** `master` at e335265568.
**Deployment mode:** any with native OpenCode/ACPX sessions on managed
sandboxes.
**Agent adapter(s) involved:** OpenCode (native), ACPX.

## What Changed

- OpenCode driver
(`packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts`):
- `removeIsolatedHome` unseals the skill snapshot with the existing
`releaseMaterializedNativeRuntimeSkills`, then removes the HOME. Close
and every startup-failure path use it. It only unseals when `.claude` is
a real directory, not a symlink.
- Per-launch homes are now created under `<session>/homes/home-XXXXXX`,
so one exact path can be excluded.
- When a session opens, `home-*` directories left at the session root by
earlier versions are removed. History is not in them: OpenCode keeps it
in `XDG_DATA_HOME` (`<session>/data/opencode/opencode.db`), and HOME
only holds caches, state locks and the skill copy.
- Exports `opencodeRuntimeSessionDirectoryName` (the existing
session-directory naming) and `OPENCODE_ISOLATED_HOMES_DIRECTORY` for
the server.
- `resolveNativeHarnessPersistenceProfile`
(`server/src/services/native-runtime/native-session-executor.ts`):
- OpenCode excludes `<session>/homes` and
`<session>/config/opencode/node_modules`.
- ACPX (every agent) excludes `acpx/<session>/home/.npm` and
`acpx/<session>/data/pnpm/store`, in addition to the existing per-agent
entries.
- `excludeEntries` are matched as exact relative paths (wildcards are
rejected), so the session directory is computed in the same way as the
existing ACPX entries.
- Exposes the two new exports through the server's runner vendor shim.

No code comments were added.

## Verification

- `pnpm exec vitest run src/drivers/opencode
src/drivers/runtime-context-materializer` (in
`packages/paperclip-runner/`): 108 passed. The 1 failure, `uses provider
structure rather than prose length to select a post-tool answer`, also
fails on unmodified `master`.
- The existing skill-tree test, with and without a startup retry, now
asserts that homes are created under `homes/` and that `homes/` is empty
after close.
- New test: a sealed legacy `home-*` at the session root is removed when
the session reopens, and `data/opencode/opencode.db` is kept.
- `pnpm exec vitest run src/services/native-runtime/
src/__tests__/native-harness-backup-expiration.test.ts` (in `server/`):
5080 passed. `plugin-runner-probe` could not run locally because of a
cargo manifest-path problem in this environment; it is unrelated to this
change.
- Profile tests cover the new OpenCode and ACPX exclusions, including a
session id that needs sanitizing.
- New checkpoint/restore round-trip tests for OpenCode and ACPX. They
use `syncRemoteRunnerDirectoryOut` for the backup and
`stageRemoteRunnerDirectory` for the replacement. Excluded caches are
absent from both the backup and the replacement, while history, config
and workspace files are restored and the live directory is unchanged.
- **Mutation checks**, each failing its test:
- removing the skill unsealing (homes leak again; 3 runner tests fail);
  - removing the legacy sweep (1 test fails);
  - emptying the OpenCode/ACPX exclusion lists (4 server tests fail).
- Checked by hand against the bundled OpenCode 1.18.34 binary, with the
driver's environment:
- launching with a fresh HOME and no `config/opencode/node_modules`
still lists earlier sessions;
  - OpenCode reinstalls the plugin dependencies on launch.
- `pnpm run typecheck` in `server/` and `packages/paperclip-runner/`:
pass.
- Not run: server build and boot smoke.

## Risks

- **Rollout:** existing backups still contain legacy `home-*`
directories. After a restore, the sweep removes them when the session
opens, and the next backup no longer carries them.
- **First launch after restore:** OpenCode reinstalls its plugin
dependencies and npm repopulates its cache. This needs network access to
the npm registry, the same as a brand-new session.
- **Crash leftovers:** a HOME left behind by a hard crash (the runner
killed before `close()`) stays under `homes/` until the session
directory is removed. It is still excluded from backups. Homes under
`homes/` are not swept on open, to avoid touching a HOME that a
concurrently running runtime might still use.
- **pnpm store:** dropping the pnpm store from ACPX backups means the
next `pnpm install` in a replacement sandbox downloads packages again.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), 1M context, through Claude Code
with tool use (shell, file edits, tests, and running the real OpenCode
binary to check what state it reads on resume).

## 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>
2026-10-25 08:51:39 -07:00
Devin FoleyandPaperclip 7ebf98eafd fix(recovery): avoid duplicate terminal run status notifications (#17614)
Retain pending status deliveries when Native or legacy terminal recovery projects the same state. Preserve completion time on unchanged Native terminal status. Real state, metadata, error, explicit patch, and retained-file changes still notify. The publisher acknowledgement, accepted results, retry deadlines, recovery holds, ownership checks, and workspace cleanup remain intact.

Correct the queued Retry browser fixture race by releasing its old-process guard at the exact Retry request, requiring a successful response, and retaining fixture cleanup after failure.

Validated by 159 focused tests, 653 wider Native recovery tests, six real Chromium/PostgreSQL browser cases, five queued Retry repeats, build/typecheck, exact-head Apex 5/5, and green required CI. The original detached-button CI timeout is documented in the PR. The additional full local repository Vitest command is still running and is not claimed complete.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 08:22:53 -07:00
DottaandPaperclip aec86c794b fix(runner): preserve native work through controller outages (#17594)
Keep remote native work under its authenticated connection lease through controller outages. Hold durable ACPX tools through reconnection, align the native Claude HTTP MCP client budget, and wait for the recovered handler before dispatch. Preserve Stop, cancellation, exact identity and artifact checks.

Verified with real-process regressions and a real Claude Opus 5.5 Daytona workflow: 125 seconds offline during useful work, original process and lease retained, no failed native tool calls, queued follow-up completed, independently verified ZIP and committed workspace receipts. All current-head CI gates pass and Greptile is 5/5 with all findings resolved.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 09:01:24 -05:00
Devin FoleyandPaperclip 8c6bd5a83b perf(runner): skip wake payloads in ordinary authority reads (#17600)
Omit saved wake payloads from ordinary unlocked Native authority reads. Load the current full wake for mail restrictions. Preserve stored rows, locked mutation reads, and current authorization predicates.

Verified with full build and typecheck, 2,360 affected tests, real PostgreSQL byte and response checks, counterfactual performance and mail authorization failures, complete exact-head CI, and Greptile 5/5 Medium with no unresolved comments.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 05:36:43 -07:00
Devin FoleyandPaperclip 2e47c42fad perf(runner): omit unused launch context from tool authority reads (#17591)
Omit nine unused named launch values from the unlocked Native authority query. Preserve complete wake payloads, other context, result receipts, stored input, and locked execution and mutation readers.

Verified with full build and typecheck, 2,359 affected tests across 20 suites, real PostgreSQL byte/retention/cancellation checks, a counterfactual, complete exact-head CI, and Greptile 5/5 Medium with no unresolved comments. An existing cleanup scheduling test passed on CI retry after its suite passed locally with both base and branch source.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 04:21:50 -07:00
Devin FoleyandPaperclip 35d5b0686a perf(runner): narrow current tool authority reads (#17587)
Select the current run fields used by Native tool authority without transferring unused saved profiles or output. Preserve full context, receipts, authorization predicates, and locked mutation reads.

Verified with full build and typecheck, 2,358 affected tests across 20 suites, a counterfactual real PostgreSQL byte regression, complete exact-head CI, and Greptile 5/5 Medium with no unresolved comments.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 03:45:25 -07:00
Devin FoleyandPaperclip bf142db65a perf(server): narrow external review wait context reads (#17562)
Project current chat authorization fields for external review-wait discovery instead of saved execution input. Preserve typed source bindings, nested question receipts, candidate eligibility, live revocation checks, and stored context.

Validation: 181 native chat integration tests, full build and typecheck, exact-head Greptile 5/5 (medium), full green CI, and no unresolved review threads. The full-context counterfactual fails both direct-chat size regressions.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 00:02:32 -07:00
DottaandPaperclip 2a9d527c68 fix: preserve native startup during controller restart (#17511)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The native runtime keeps a durable runner alive across controller
restarts.
> - A restart can begin while a provider session is still opening.
> - The old controller fenced read-only run admission before it could
publish that prepared session.
> - Admission failure then closed the runner that shutdown needed to
detach.
> - This pull request lets only the existing startup finish admission
within the bounded shutdown wait.
> - The controller detaches that exact session before it can submit a
turn. New work and state changes stay fenced.

## Linked Issues or Issue Description

**What happened?**

A controller restart during native provider startup could close the
prepared runner with `native control-plane run admission failed`.
Recovery then found no running process and placed the task in a
reconciliation hold. The same admission path follows both fresh startup
and replacement after a failed provider resume.

**Expected behavior**

Shutdown must detach the existing prepared session so the next
controller can recover it through the normal identity checks. Shutdown
must not admit a new executor, submit a turn, or override an explicit
Stop.

**Steps to reproduce**

1. Delay a native backend while it opens its provider session.
2. Request controller restart detachment for that run.
3. Let backend startup finish before the 30-second deadline.
4. Observe that read-only admission fails and shutdown reports the run
as inactive instead of detached.

**Additional context**

Related work: #17073 handles remote process-monitor classification;
#17459 handles macOS process fingerprints; #17097 covers broader hot
upgrade recovery. This change fixes the startup admission fence. It does
not relax process identity or provider launch-profile checks.

## What Changed

- Separate the read-only admission guard from the guard on control-plane
state changes.
- Let shutdown await only the startup already registered for the run.
Close its admission window when the wait ends.
- Reject a new execution after its run is fenced for shutdown.
- Detach the prepared session and exit before runtime-question
attachment or provider turn submission.
- If Stop is pending before or after publication, retain its exact
cancellation acknowledgment and cleanup owner across authority reads and
runtime-question attachment.
- Share one 30-second admission/Stop-settlement deadline across the
restart sweep. Report an unsettled run as pending while healthy runs
continue hot-restart adoption.
- Cover the real runtime and admission path, deadline expiry, new-start
rejection, persisted binding checks, and write fences.
- Document the bounded startup handoff in the restart ownership
contract.

## Verification

- Red: the new actual-runtime/admission regression failed on the
previous code. Shutdown reported the run as inactive and did not detach
it.
- Red: review regressions reproduced detach before a post-publication
Stop acknowledgment and an actual hot-restart preparation error when
startup Stop cleanup timed out.
- Green on `e10d0cb238`: 18 startup/restart tests passed, including Stop
during authority reads and runtime-question attachment, the real
recovery preparation and shutdown coordinator with a stalled Stop plus
healthy peer, and the shared sweep deadline. The earlier 36-case
Stop/restart selection also passed before this follow-up.
- Both complete changed test files previously passed on head
`8e9c2610fe`: 857 tests. They used real PostgreSQL 18 with a fresh
database per fixture. An earlier local harness attempt reused one
database and hit duplicate fixture keys; that harness was corrected
before this complete pass.
- Real PostgreSQL: 7 admission and revocation tests passed. These cover
wrong runner identity, persisted binding mismatch, checkpoint/result
rejection, and in-flight write revocation. The local test harness used a
fresh Docker PostgreSQL 18 instance because macOS embedded Postgres
exhausted the host semaphore limit. Only database provisioning was
replaced; assertions and production port code were unchanged.
- Transport safety acceptance: the current source transport controlled a
real Linux ARM runner and a deterministic Codex test provider in a
disposable Debian container. After startup, detach and generic cleanup
preserved the process. A new controller authenticated the same PID and
provider session. The provider log had exactly one session start and no
turn start. Duplicate launch was forbidden, the retained workspace was
unchanged, and no stop or suspend command was issued.
- The Linux acceptance check tests the shared native transport safety
contract. It is not a live Claude response, a hosted Daytona run, or
recovery of the original task. Those remain unverified. No original
task, sandbox, credentials, or permissions were changed.
- `pnpm -r typecheck` and `pnpm build` passed before the review
follow-up. Server typecheck passed on current head `e10d0cb238`;
current-head CI also passed the full typecheck and build gates.
- The full local `pnpm test:run` command was attempted, then stopped
after repeated embedded PostgreSQL bootstrap setup failures. That broad
local run is incomplete. The current-head four-file Docker PostgreSQL
run passed 879 tests, with one existing warm-copy `claim-uncertain` case
timing out and recovery failing to import because the temporary
provisioning mock omitted a support export. The harness is corrected and
affected cases are being rechecked. The timeout is unexplained; it is
not being labeled an infrastructure failure. No assertions are skipped
by the database provisioning replacement.
- All 55 clean-host CI checks passed on current head `e10d0cb238` (2
conditional skips), including all general test shards and native runner
verification. Greptile reviewed that exact head at 5/5 with no findings.
The previous Paperclip review findings are addressed in [the review
response](https://github.com/paperclipai/paperclip/pull/17511#issuecomment-6391520242);
its new advisory review remains queued.

## Risks

- Admission must stay read-only. All writes retain the original
synchronous controller fence, and both admission checks still validate
the exact persisted binding.
- Startup that exceeds the 30-second shutdown wait still fails closed.
It cannot claim a successful detach or start a turn.
- No schema migration or provider configuration change is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution, and test execution. The exact runtime model ID and context
window are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-24 21:05:45 -07:00
Devin FoleyandPaperclip ef0a8db502 perf(native): narrow reconciliation candidate payloads (#17531)
Select the complete workspace-sync record and native status wake identifier for reconciliation candidates. Preserve candidate policy, JSON types, full later evidence, and stored data. The committed replay regression includes the real reconciliation scan. Full build, typecheck, 114 focused tests, complete CI, and exact-head Greptile5/5 pass.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-24 19:01:23 -07:00
Devin FoleyandPaperclip 64a8b927c1 fix(native): narrow committed finalization and cleanup reads (#17525)
Select fresh metadata for committed finalization and cleanup. Preserve full saved evidence for new finalization, cancelled workspace retention, and legacy Stop. PostgreSQL byte-budget and unchanged-row regressions pass, full CI is green, and Greptile scored the exact head 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-24 17:48:47 -07:00
DottaandPaperclip 5c3dce09b5 fix(runner): preserve verified remote artifacts across controller releases (#17512)
## Thinking Path

> - Paperclip manages AI agents and owns their task authority.
> - Remote native agents can keep working while their controller
restarts.
> - The controller must authenticate the same runner and verify its
provider files before recovery.
> - The current path compares a retained provider pack with the new
controller release. A release change can reject intact files.
> - The new controller binary digest can also reject the original daemon
during PRP authentication.
> - This PR records the admitted release authority in private controller
state and uses it for exact process reattachment.

## Linked Issues or Issue Description

**What happened?**

A remote Claude session started and used tools. After controller
shutdown, recovery failed with
`runner_remote_provider_artifact_incompatible`. The transport combined
stderr into stdout, so the error omitted the verifier reason. The
historical rejected manifest is unavailable. This PR reproduces
controller release drift as a cause; it does not claim that the
historical mismatch is proven. Reaching pack verification implies the
earlier exact-process/controller-identity checks passed. That supports a
preserved-state recovery path but is not a direct inspection of the
deployed volume.

**Expected behavior**

A compatible, unchanged remote runner can reattach after a controller
release changes. Full package hashes, exact process scope, protocol
capabilities, and authenticated runner identity must still pass. Fresh
launches use the current release.

**Steps to reproduce**

1. Verify and admit a remote native session with release A.
2. Preserve its runner process and replace the controller with release
B.
3. Reattach the original process. The old path compares its pack with B
and fails at `manifest mismatch`.
4. With this fix, the controller reads its saved A authority and
verifies all A hashes. Changed files still fail.

**Paperclip version or commit**

Reproduced from master `470cb34c0e42cb9d0b232d0bcf5d45cc7b0a81ca`;
rebased onto `a3675ddcdf`.

**Deployment mode**

Native remote runner on a Daytona-backed Paperclip Computer. Local
acceptance uses isolated Linux containers and actual packaged artifacts.

Related work: #17361 and #17448 handle runner upgrade and qualification
permissions. #17097 and #17439 add durable controller checkpoints and
server adoption. That stack can skip remote artifact preparation with a
saved checkpoint. This PR fixes the current file-backed path and retains
full provider-pack verification; it has no checkpoint schema or
empty-disk controller recovery.

## What Changed

- Save the complete verified pack manifest and authenticated runner
version/digest after successful session admission.
- Bind the receipt to company, agent, workspace, session, runner,
environment lease, remote directory, and provider descriptor. Keep it
outside guest backup directories.
- Reuse the saved authority for exact reattachment. Keep current release
selection for fresh launches and explicit session replacement.
- Fail closed for mismatched or corrupt receipts. Historical sessions
without a receipt retain the current release integrity gate.
- Report bounded, redacted verifier output from both transport streams.
Warn on receipt write failure while returning the already admitted
session to its owner.
- Add scope, persistence, replacement, storage failure, and backend
wiring regressions. Update recovery documentation and the feature map.

## Verification

- Test-first red: the original selection chose release B instead of A
after controller recreation. The new receipt regression passes. A
separate red test showed the missing stdout diagnostic; it passes after
the diagnostic fix.
- Authority and diagnostic suites: 49 tests pass. Backend pack, process
adoption, and harness persistence selection: 47 tests pass.
- Actual Linux provider image: complete A manifest/artifact verification
passed; controller source-revision drift failed on the old path; saved A
authority passed; a modified ACPX sidecar failed its SHA-256 check.
- Actual native Linux runner: authenticated a session, detached the
controller, changed the controller manifest and binary, then
authenticated the original PID and provider session with saved
authority. There were zero duplicate spawns, zero new provider turns, no
stop/suspend, and the workspace file remained. This probe used the real
runner with a deterministic Codex fixture; it is separate from the real
ACPX package integrity proof.
- Full workspace typecheck and build passed. The full native executor
suite first hit host PostgreSQL semaphore exhaustion. The complete
changed files then passed 864/864 tests with separate real PostgreSQL
databases in a disposable Linux container. The temporary local fixture
changed only database provisioning and used normal repository
migrations. Current-head CI also passed the full required test, Runner,
browser, typecheck, and build lanes.
- `node scripts/check-maps.mjs` and `git diff --check` passed. These
structural checks do not prove live recovery.
- Current head `48fca2ae33d99f7f6d2fe12f431cf76d25185c70`: 55 successful
checks, two conditional skips, no pending or failed checks; fresh
Greptile 5/5 with zero findings and zero unresolved review threads.
Commitperclip quality review passed.
- No original task was retried or changed. Existing Daytona access could
not resolve the original sandbox or its image; a fresh staging Claude
recovery is not claimed.

## Risks

This prevents recurrence for sessions admitted with the new receipt. It
does not retroactively recover the historical failed run. Saved
authority exists only after this change has admitted a session. It
cannot repair an ambiguous historical launch or restore a receipt on an
empty replacement controller. A stale protocol or modified pack remains
a hard failure. Receipt write errors warn without losing the live
session handle, but later recovery still needs matching authority. The
broader checkpoint stack changes the same server preparation and
runner-artifact option and will require a deliberate integration.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, and code
execution. The runtime does not expose a more specific model ID or
context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-24 16:44:50 -07:00