Files
PaperClipAI/server
DottaandPaperclip 85dec04677 fix(native): validate active controller durability during eligibility (#20601)
## Thinking Path

> - Paperclip controls agents while their work runs outside the web
server.
> - A web replacement must retain each controller's durable recovery
state.
> - Modern controllers commit that state to the database before sending
work.
> - Their local controller file is only an external-persistence identity
marker.
> - Disk eligibility still required recovery metadata that can arrive
after a run finishes.
> - This pull request verifies the complete active database authority
instead.
> - It also bounds concurrent source reads so a large history does not
require serial network waits.

## Linked Issues or Issue Description

Refs: #20311, #20584, #20599.

**What happened?**

A live native run can have a complete database controller checkpoint and
no terminal session snapshot yet. The disk-preservation check treats its
local identity marker as a local-only obligation. The check also
resolves selected sources one at a time.

**Expected behavior**

Accept a complete, bound active recovery authority. Refuse missing,
partial, stale or foreign evidence. Keep all execution and enrollment
guards.

**Steps to reproduce**

Use the new active-controller regression. Start a real Runner controller
with the database checkpoint writer. Keep the business run active and
omit its terminal snapshot metadata. The previous check returns a local
obligation even after the full checkpoint commits.

## What Changed

- Require the exact external-persistence marker and a complete decoded
encrypted checkpoint for active runs. Match run, agent, task, session,
Runner and workspace identities. For warm reuse, also permit an older
marker only when its full older checkpoint matches that marker and its
exact earlier successful run has a committed accepted result in the same
company, agent, task, session, Runner and workspace. Keep the current
live writer mandatory. Read the marker again after validation.
- Accept that proof only with its fenced live writer and task binding,
or the existing exact saved recovery snapshot. The saved-snapshot path
still requires the full active journal.
- Keep newer remote workspace authority strict. A malformed reference
cannot fall back to an older prepared reference. Conflicting plugin task
authority remains blocked.
- Resolve selected sources at most eight at a time for read-only
eligibility. Join every started reader before reporting an error. Keep
source order, pagination, predicates and all write paths unchanged.
Offline migration and prestaging still resolve sources one at a time.
- Add real PostgreSQL regressions for active durability, partial and
foreign state, expired ownership, previous prepared-reference state,
post-result state and reader failure joining.

## Verification

- Canonical Node24 preflight passed in74.2s. It built the current Runner
inputs and published the cache. No shared Cargo target or hosted
database was used.
- Genuine active regression RED: the previous check returned true when
false was required. The real checkpoint writer had committed the
complete authority and replaced the local file with the Runner marker.
Treatment passed, including the refusal controls.
- Genuine source-reader RED: sixteen retained pointers used one reader
at a time. Treatment used at most eight and joined all eight when the
first reader failed. With a controlled20ms reader delay and real
PostgreSQL selection, the small fixture changed from497.5ms to85.3ms.
This is a bounded-concurrency proof, not a production speedup
measurement.
- All54 cases in the affected controller migration integration file
passed in76.07s, with no skips. These include existing
failed-controller, archived-controller, inline database and
previous-session preservation cases.
- Server TypeScript passed. The normal merge of current master kept both
changed files byte-for-byte identical to the54-case proof. Final
post-merge focused checks passed two of two in14.83s (52 other cases
intentionally unselected); server TypeScript and module boundaries
passed. Comment-only correction743 removed all new code comments
required by CONTRIBUTING. A later warm-reuse regression reproduced the
remaining false blocker through the real Runner rotateRunIdentity API.
The bounded treatment uses one exact older-run lookup and full
old/current checkpoint validation; it adds no Runner format, release or
lineage service. Final normal-merge head
`c62d6eb1755cf99b6def9563ba69854dba17de42` includes the new0459
baseline. All three focused PostgreSQL cases passed in21.37s (52
existing cases intentionally unselected); fresh server TypeScript and
module boundaries passed. The prior54-case regression evidence is
retained; no full matrix was repeated.
- `git diff --check` passed. Final-head CI passed:56 checks succeeded
and4 were skipped; the separate Paperclip Review advisory was still
queued. All required test, build, typecheck and ci/verify gates passed
on c62. [Final required
workflow](https://github.com/paperclipai/paperclip/actions/runs/42868279612).
Fresh [Greptile
review](https://github.com/paperclipai/paperclip/pull/20601#issuecomment-6774537057)
is5/5 on exact head `c62d6eb1755cf99b6def9563ba69854dba17de42`, with no
open review threads.

```sh
node scripts/agent-preflight.mjs --skip-rust-debug
node --import ./cli/node_modules/tsx/dist/loader.mjs packages/db/src/test-postgres-command.ts pnpm exec vitest run server/src/services/native-runtime/native-controller-migration.integration.test.ts --disableConsoleIntercept
pnpm --filter @paperclipai/server exec tsc --noEmit
```

## Risks

- This reports preservation evidence. It does not grant attachment,
execution, replacement or enrollment authority. The normal live-owner
and admission gates still apply.
- A partial old or current checkpoint, stale local controller state,
identity mismatch or uncertain owner stays blocked. Warm-marker proof
also rejects a foreign agent, newer source, later completion, rejected
result, per-turn scope or expired current writer. No source, checkpoint,
session, lease, archive or provider state is changed by the check.
- The eight readers add bounded database concurrency during an explicit
eligibility request. There is no new background scan, cache, row filter
or timeout change. Live enumeration time still needs deployed
measurement.
- The plugin task-lease branch uses the producer's environment lease row
ID, as native-session-executor and existing diskless adoption coverage
require. A direct active-eligibility positive for that plugin branch is
a coverage limit; existing mismatch/conflicting-authority checks remain.
The advisory found no must-fix defect, and this does not change the
current tested revision.
- Saved formats and terminal migration behavior remain unchanged. Older
prepared workspace references remain supported. A fully saved result can
still pass before the run-status update, but its entire active
checkpoint must decode.
- The observed staging run finished naturally and became valid on the
existing terminal path during investigation. That observation is not
deployed verification of the new active path.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, tool use and code execution. This
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-11-10 12:02:22 -06:00
..