Commit Graph
381 Commits
Author SHA1 Message Date
DottaandPaperclip 0e15c92073 feat(skills): make managed content independent of web-server disk (#18334)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use installed skills and exact version pins during execution.
> - Managed skills still depended on mutable directories on the web
server.
> - A replacement server could lose acknowledged edits or remove an
unassigned skill whose directory was absent.
> - This pull request makes immutable versions the authority for managed
content and installed repository reads.
> - The server can rebuild delivery files from durable content after
replacement.
> - This establishes skills readiness for ephemeral web servers. General
server draining and workspace recovery remain separate work.

## Linked Issues or Issue Description

**Subsystem affected**

Skills services, shared contracts, database receipts, Skill Studio, and
runtime delivery.

**Problem or motivation**

A fresh web server must discover, read, edit, and deliver protected
installed skills using the same database, object storage, secrets, and
supported application artifacts. It must not need its predecessor's
files or process memory.

**Proposed solution**

Use `managed` ownership with a null source locator. Read installed
content by immutable version. Prepare packages before a short
publication transaction. Persist execution selections before
materialization. Recover exact pinned runtime assets and reject deletion
while active or recovering pins exist.

**Alternatives considered**

Reconstructing a mutable installed directory preserves the old
source-of-truth ambiguity. Permanent dual writes create two competing
authorities. This change uses one managed model after a bounded legacy
conversion.

**Roadmap alignment**

This improves the existing Skills Manager, Studio, version history, and
Cloud execution capabilities. The maintainer supplied the implementation
contract. This does not add a separate skills product or deploy fleet
changes.

Related work: #18082 supplies immutable package storage. #17273
addresses edits outside the API for linked local skills; this PR keeps
that source category separate. #2648 is a closed earlier
ephemeral-filesystem proposal.

## What Changed

- Add managed ownership and focused content publication and execution
materialization modules. Keep the archive format and package storage
tables.
- Publish managed create, save, delete, fork, rename, restore, and
catalog content with version checks. Add durable create receipts.
Preserve file-save receipt responses.
- Return file version identities. Keep Studio drafts after a conflict
and provide an explicit reload action. A delayed reload cannot overwrite
newer typing or navigation.
- Persist exact runtime selections, including empty selections. Rebuild
pinned assets and verify their admitted digests on a replacement server.
- Preserve source access on forks and disconnected copies. Keep the
existing workspace policy category for managed skills.
- Add bounded conversion, eligibility, and independent verification
phases. Load persisted Cloud configuration in the standalone CLI without
seeding or changing it. Reject partial current versions against
installed inventories; recover only complete saved content or the exact
source. Document storage migration blockers and the compatible rollback
floor.
- Add separate-process PostgreSQL/S3 qualification and update domain,
retention, policy, and UI regressions.
- Pass the plugin worker manager into Studio execution, admit restricted
`skill_test` mode through native Runner contracts, and preserve admitted
scope across native and REST tools. Native tests cannot create ordinary
tasks, browse company data, or use external tools.
- Select the exact durable Studio revision even when unassigned or Beta
skills is off. Persist Studio output and audit atomically with native
task completion, preserving the result on replay.

## Verification

- Final revision `13e8af480b88ba6fea5737bac4bd81104d604792` passed full
CI: all 49 workflow jobs completed successfully ([run
41127396098](https://github.com/paperclipai/paperclip/actions/runs/41127396098)).
This includes typecheck, test suites, Runner checks, browser checks and
build. Greptile review 15 is 5/5 on that same revision, with zero
unresolved threads. The PR is ready for review.
- Local workspace typecheck and build passed after integrating master.
Focused checks passed: 33 execution/completion cases, 52 Runner HTTP
cases, 16 managed-content cases, 17 Studio cases, the new real-process
CLI regression, map checks and UI token gates. The CLI regression proves
inspection does not seed missing Cloud configuration. Server typecheck
passed after that fix.
- The independent-process PostgreSQL/S3 matrix passed through normal
HTTP skill routes. It covers A → B → C replacement, lost commit
responses, upload crashes, concurrent saves, binary contents and
executable delivery. Metadata listing and warm selected delivery retain
zero object downloads. Local timing measurements are recorded; they do
not establish hosted latency.
- Hosted A → B → C passed on the owned disposable test tenant with
external Postgres, S3 and a real remote Paperclip Computer. Predecessor
temporary homes were absent. C read and executed B's acknowledged
managed save. New runs used repository v1 while v2 was installed. Hashes
matched an independently checked exact upstream commit.
- Compatible image rollback to `6518b323` passed. Studio retained the
unassigned fork's C save. A fresh remote run executed the newer managed
content and historical repository pin. The actual shell event confirmed
expected hashes, stdout, exit 0 and mode 0555.
- Runtime candidate `9200e3fcb4` deployed successfully ([Cloud run
41124147876](https://github.com/paperclipai/paperclip-cloud/actions/runs/41124147876)).
The final Studio test delivered only the unassigned fork's exact v3,
executed its script and persisted a successful output snapshot.
Independent command-event inspection confirmed all three hashes, stdout,
exit 0 and mode 0555. All 14 installations were version-backed.
Independent verification checked all 25 versions: 23 remote objects, two
bundled database snapshots, zero blockers.
- The deployed image is `9200e3fcb4`. Later master integration, the
client-only delayed-reload draft guard and the CLI bootstrap have
separate automated proof. The CLI bootstrap was also exercised against
the tenant's stored configuration and storage through the same read-only
services. This PR does not claim that the deployed image is the final PR
revision.
- Live Studio checks exposed worker wiring, admission, access scope,
exact selection and completion-publication gaps. They are fixed. Failed
attempts remain in the evidence. The full local suite exceeded 80
minutes under host contention and was stopped. Later combined/isolated
local attempts also timed out; they are not counted as passes. Full CI
covers the integrated suites. Earlier CI found an obsolete restart-scope
fixture, which was corrected and passed all 52 HTTP cases.
- Reproduction and migration:
[`doc/skill-ephemeral-web-servers.md`](doc/skill-ephemeral-web-servers.md).
Source revisions, deployments, versions, run IDs, hashes and failure
history:
[`doc/plans/2026-10-30-ephemeral-web-skills.md`](doc/plans/2026-10-30-ephemeral-web-skills.md).

## Risks

- Legacy conversion requires stopped admission and retired
filesystem-authoritative writers. Pre-conversion binaries are not
supported rollback targets afterward.
- Cloud readiness requires remote object storage. Local provider
receipts and provider mismatches remain blockers until objects are
copied and verified.
- Linked local sources retain filesystem semantics and are outside the
cloud guarantee.
- Cold reads still fetch the existing archive format. Warm runtime
preparation retains the verified-cache path.
- Bundled reconciliation preserves an installed head. Existing release
snapshots remain selectable. An older server must not replace a newer
head with its shipped files.
- No production volumes, fleet defaults, or general deployment
coordination change in this PR.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser use. The exact backend model ID and
context-window size are not exposed in this session. No subagents were
used.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 16:18:27 -05:00
Nicky LeachandPaperclip 6174b4d7c8 fix(runner): allow session reset after confirmed task retirement (#18373)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Native warm sessions retain a Runner owner between turns.
> - Closing that owner must stop execution and preserve valid recovery
state.
> - A failed suspension can leave a rejected close promise after the
task has stopped.
> - A session reset then retries that same promise and blocks every
fresh session.
> - This PR separates task retirement proof from checkpoint reuse for a
new session.
> - A reset can proceed after exact stop proof, completed handoff, and
file collection.

## Linked Issues or Issue Description

Refs #18011. That change preserves checkpoint authority during warm
preparation. This change handles a stopped owner whose checkpoint cannot
be reused. Related: #14695 covers managed files retained with warm
processes. A search found no duplicate stopped-owner reset fix.

**What happened?**

A warm Runner can stop and complete its task handoff while close reports
`runner did not durably suspend before checkpoint`. The transport caches
that rejected close promise. Core retains the warm owner. Each session
reset retries the same promise before it can launch a provider. A
controller restart clears the in-memory owner and permits recovery.

**Expected behavior**

A reset to a new normalized session should release the old owner when
its exact task has proved that execution stopped and its handoff
completed. Core must collect stopped instruction files before it admits
the new session. An unconfirmed owner must continue to block
replacement.

**Steps to reproduce**

1. Complete a warm native run through a plugin task provider.
2. Change configuration so Core retires the warm owner.
3. Let the task stop and complete, but fail durable suspension proof.
Close keeps its rejected promise.
4. Reset the session and start another run on the same task environment.
5. Observe the old close error before any new provider work starts.

## What Changed

- Keep a lease-bound retirement receipt in the plugin task owner. It
requires `executionStopped: true` and successful task completion after
credential handoff.
- Accept an unrecoverable suspension error only during retirement for a
different normalized session, with that exact owner's receipt and
settled Core tool results.
- Collect stopped instruction files before releasing the warm owner.
Preserve old checkpoint evidence.
- Keep same-session, active-owner, incomplete-handoff, unrelated-owner,
unresolved Core tool results, and other close-error fences.
- Report Core tool settlement on the close error after ingress
retirement and drain. Default missing proof to false. Expose the error
through the server's Runner shim. Add regression tests and document the
recovery boundary.

## Verification

- The reset regression fails with the new handling disabled and passes
with it enabled.
- Both affected suites passed: 1,032 tests. The final 15 focused
owner/reset cases pass after adding the tool-settlement guard.
- The assembled regression uses the real task-owner and backend binding.
Its controlled task provider proves stop and completion. Close returns
the same rejected promise on every call.
- Negative cases cover incomplete handoff, other close errors,
same-session continuation, provider change with the same session ID,
unrelated receipts, unresolved Core tool results, and failed file
collection. Collection can later succeed without replaying stop or
reading the old checkpoint.
- Five real-process transport cases pass. They cover an insufficient
suspension deadline, the cached rejected promise, late tool completion
within and beyond the deadline, interruption, and result-persistence
failure. Unsettled callbacks produce `semanticToolsSettled: false`.
- `pnpm -r typecheck` passed with the repository's pinned Rust toolchain
on PATH. After the final contract change, Runner TypeScript build and
server `tsc --noEmit` passed.
- The local full-suite run was stopped at the requester's direction.
Full regression and build coverage are delegated to GitHub CI.
- Full GitHub CI passed on `ef0040d80af679ce6d4a130468e15f75678c1f4c`.
Standard Greptile reviewed the same commit: 5/5, zero comments. Apex
then reviewed that same commit: 5/5, zero comments. Final checks confirm
no unresolved review threads and no merge conflicts.
- Initial full CI on `00c002fd5a` failed one scheduled-retry route test
at 18/20 cancellations. Controlled cancellation latency reproduced the
short poll-budget failure. Before the next cycle, master advanced with
#18322, which coordinates that test at the first completed batch. The
separate local timeout commit was dropped during rebase. The upstream
test passes locally. The rebased run passed 46 targeted owner/reset and
scheduled-retry route cases. This PR has no scheduled-retry source or
test diff.
- No deployed provider run or tenant rollout is claimed by these source
tests.

## Risks

The exception applies only to a new normalized session and an exact
completed plugin task. The old checkpoint remains evidence and cannot
authorize reuse through this path. The original suspension failure can
remain visible on its run. This fix prevents repeated startup failures
after a reset; it does not hide unconfirmed cleanup or make every
suspension succeed. Missing task receipts and failed file collection
continue to block replacement. No schema migration, plugin protocol
change, Rust Runner binary change, or new polling is required. Tests use
a controlled task boundary; they do not certify every external provider
implementation.

## Model Used

OpenAI Codex, GPT-6 family, with tool use and local code execution. The
exact runtime 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 references)
- [x] My branch name describes the change and contains no internal issue
or instance 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] Greptile Apex is 5/5 with no unresolved findings
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 13:57:12 -07:00
DottaandPaperclip 9f524ec1a7 fix: persist native Runner usage before transport acknowledgement (#18354)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent execution must preserve usage so Paperclip can price work and
enforce budgets.
> - Remote Runner execution can outlive its web receiver.
> - The receiver previously acknowledged Runner events before its later
usage recorder saved the accounting receipt.
> - This pull request saves required native usage receipts before that
transport acknowledgement.
> - A replacement receiver can accept the same retained report and
create one ledger charge.

## Linked Issues or Issue Description

**What happened?**

Native remote Runner usage could leave its durable outbox before the web
receiver saved its accounting receipt. The later recorder required a
local receipt directory. A replacement web receiver could lose the only
remaining report when the database write failed.

**Expected behavior**

The Runner retains unaccepted structured usage. Postgres owns accepted
receipts. Repeated delivery preserves one receipt for each source report
and one charge for the run. Missing usage keeps accounting pending.

**Steps to reproduce**

1. Start a supported built-in native remote Runner.
2. Make the receipt database insert fail after the provider reports
usage.
3. Replace the web receiver and its local directory.
4. Reconnect the same Runner and inspect the saved receipt and ledger.

**Paperclip version or commit**

The initial investigation used
`ebd05e9f4c88c66af7473db86bbaacfd1544aa0a`.

**Deployment mode**

A web server with a remote native Runner and shared Postgres.

Related work: #18327 owns output logs and provider traces. This change
has no dependency on its S3 export path. #18031 covers interrupted Codex
receipt recovery. #18005 covers legacy spool reads. #17516 covers Codex
stop-boundary retention.

## What Changed

- Add native producer receipt delivery through the existing Runner
callback before transport acknowledgement.
- Reuse `run_usage_receipts`, stable source sequences, and deterministic
report identities. Reject conflicting replay and retry a lost commit
response with the same receipt.
- Restore per-turn usage from structured receipt facts. Preserve
provider turns that share one PRP envelope turn.
- Bind retained warm transport callbacks to the current run authority
epoch, allowing old attachment control acknowledgements while preserving
accounting ownership.
- Persist Codex session baselines and cumulative totals in the existing
provider checkpoint. Mark qualified whole-run deltas, preserve them
across resume/restart/attachment, and leave old unmarked reports
incomplete and unpriced.
- Normalize the bounded final usage tail before the terminal event.
Retain later increases for explicit reconciliation, block further
attachment, and fail an affected successor without changing its
baseline.
- Complete runs from the accepted immutable receipt and its exact saved
rate-card amount; preserve existing live-budget enforcement.
- Skip the local receipt recorder for supported built-in native remote
Runner execution. Keep local, legacy, and external Dot/Muse behavior
unchanged.
- Keep pricing, reservations, ledger settlement, source fencing, and
budget holds with their existing owners.
- Put the actual Runner integration test in the existing Rust-cached
native test lane. Build before opening Postgres and give cold
compilation its own bounded budget.

## Verification

- Fresh Greptile review is 5/5 on
`e7376a50c8162770da1d581ecf25c8cffac64520`, with no unresolved findings.
Parent and independent peer review approved the final changes.
- Real PostgreSQL 18.6 and a real Rust Runner exercise failed receipt
insertion, receiver-directory loss, replay from the same producer, and
exactly one 25-cent ledger charge. The actual accounting spool path
stays absent. Optional logs/traces are disabled. The provider is
controlled; no paid request is made and the fixture never pre-saves the
expected receipt.
- Producer checks passed 32 usage/provider tests,37 terminal controls,
corrected completion, all 3 previously failing exit cases, and both full
transport goal-continuation cases. Rejected active-goal completion
retains its 120-token tail before failure. Baseline 100→successor150→33
duplicate old snapshots→old120 retains explicit incomplete
reconciliation evidence and positive budget exposure.
- Heartbeat executor checks passed 982/982. PostgreSQL tests preserve
exact 1.002 USD pricing, the 100.2-cent ledger amount, budget holds,
source takeover, partial/final receipts, cost-only corrections, equal
rate-card replay, and stale-completion interleaving. Newer incomplete
usage remains pending rather than settling an older snapshot.
- Runtime replay and strict usage-schema checks passed 2/2; generated
contracts and Rust formatting pass. Test-partition contracts passed
32/32.
- [Final combined-head
evidence](https://github.com/paperclipai/paperclip/pull/18354#issuecomment-6531526158)
records full workspace typecheck/build and 41/41 accounting tests
against all five cloud PR heads, including this final accounting commit.
It includes commands and evidence limits.
- Exact-head CI is green: 53successful checks, 6intentional skips, and
the legacy Snyk status passed. Typecheck, build, Runner, server,
browser, and aggregate gates pass. Runner Vitest1/2 initially failed an
unchanged mocked Antigravity login fixture; its focused case passed
locally, then one unchanged job retry passed 131 files/1995 tests,
including all 11 Antigravity tests. The initial failed attempt remains
recorded in CI.

Initial local attempts exposed the host SysV semaphore limit and
corrected harness path, IPC readiness, and queue-counter defects. A
temporary test loader selected an existing POSIX-semaphore PostgreSQL
18.6 build without changing repository dependencies. An optional
expanded debug provider run was interrupted at its unrelated 8192-turn
rollover stress case; no full-file local pass is claimed. Required
failure cases were run directly, and the full Runner CI remains
required.

## Risks

- The guarantee covers built-in native remote Runner execution. Local
native execution, legacy adapters, external Dot/Muse execution, and
server-originated model calls retain their existing contracts.
- This does not provide traffic switching or general web-server
failover. The existing controller identity, checkpoint, and generation
gates still apply.
- The receipt JSON gains optional structured producer facts. No schema
migration or accounting S3 spool is added. Text output and raw trace
payloads are excluded.
- Codex accounting authority requires a Runner artifact built from this
provider baseline implementation and qualified by digest. Update
receivers and strict usage-schema readers before releasing that Runner;
PRP does not negotiate this payload field. Existing unmarked Codex
reports remain pending/unpriced. No deployed Runner artifact is claimed
fixed.
- Usage arriving beyond the bounded terminal tail may require manual
reconciliation or a fresh session. Its evidence remains in the existing
producer checkpoint/outbox; no adjustment ledger or recurring scan is
added.

## Model Used

OpenAI `gpt-6.1-sol` assisted with the implementation, tests, and
documentation through code execution and repository tools. The context
window size is 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-30 15:20:42 -05:00
DottaandPaperclip 36f4422389 build(runner): reduce development debug information (#18307)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents and contributors compile the Rust runner inside workspaces
with limited storage.
> - Default development builds include full debug information in many
test executables.
> - A controlled Linux build used 11.54 GiB with those defaults.
> - This pull request uses line-only debug information for the
development profile and its test profile.
> - The measured build used 4.35 GiB and retained source-line
information for backtraces.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The storage used by Rust development builds and default-profile test
builds in `packages/paperclip-runner`.

**Current behavior**

The workspace uses Cargo's full development debug information. A clean
Linux ARM64 comparison on source
`d2280108f56872a6052a5011649a73cef9aac206`, Rust 1.97.1, and four build
jobs used 11.54 GiB for the test build output. This can exceed a small
sandbox's entire disk allocation.

**Proposed behavior**

Set `[profile.dev] debug = "line-tables-only"` in the Rust workspace
manifest. The default test profile inherits it. The same comparison used
4.35 GiB, a 62.3% reduction. Incremental compilation stays enabled.
Release settings stay as they are.

**Reason and benefit**

Reduce build storage while preserving file names and line numbers in
backtraces. This avoids removing all debug information or changing which
tests compile.

**Breaking changes**

Default development builds omit type and local-variable debugger
information. Contributors can restore it with
`CARGO_PROFILE_DEV_DEBUG=2` and `CARGO_PROFILE_TEST_DEBUG=2`. There are
no product API changes.

Related: #18172 handles workspace export after disk exhaustion. #16500
proposes separate CI-only debug settings and test scheduling changes.
This PR sets the workspace default and remains compatible with explicit
environment overrides. Searches found no existing PR for
`line-tables-only`.

## What Changed

- Set the runner workspace development debug level to
`line-tables-only`.
- Document test-profile inheritance and the full-debug environment
overrides.

## Verification

- Prior controlled comparison: fresh target directory per setting,
shared dependency downloads outside timing, identical source and
lockfile, Rust/Cargo 1.97.1, Linux ARM64, four build jobs, and a six-GiB
memory limit. First compile library tests, then all test targets with
`cargo test --locked --offline -p paperclip-runner-core --no-run
durable::`. Both configurations compiled all 32 test executables.
Measure the target directory with `du -sk`, counting hard links once.
Full debug: 11.54 GiB. Line-only debug: 4.35 GiB. These numbers exclude
source, registry, image, and Node dependencies. The initial benchmark
setup omitted an external fixture; that run was discarded after adding
the fixture from the same source revision.
- Current manifest verification passed on Linux ARM64 / Rust 1.97.1 with
profile environment overrides unset: all 32 test executables compile,
all 98 durable unit tests pass, and development binaries build. Verbose
compiler commands show `-C debuginfo=line-tables-only` and an
incremental directory for both the library and its test harness. This
verifies test-profile inheritance from the manifest. The fresh target
directory is 4.36 GiB on the updated source. No new test asserts the
manifest text; validation uses the actual compiler and existing tests.
- `cargo metadata --manifest-path
packages/paperclip-runner/runner/Cargo.toml --locked --offline --no-deps
--format-version 1` and `git diff --check` pass.
- [CI passed on commit
`14d798139f5ff04414c6acbe15cec04e9b680a00`](https://github.com/paperclipai/paperclip/actions/runs/41059532543),
including the `ci / verify` aggregate. The separate native Docker Runner
check also passed. The final check inventory has 55 successful checks,
four expected skips, and the neutral review described below; the legacy
security status passed. Two first-attempt worker interruptions required
one targeted retry each: Runner Vitest 2/2 received a shutdown signal
during native integration verification, and chat 1/3 lost communication
with GitHub. The exact interruption causes remain unknown. The Runner
retry passed 132 files / 2,321 tests (two existing skips), then four
native integration files / 127 tests (five existing skips). The chat
retry and final aggregate passed. The successful retries establish
recovery on this commit; they do not establish the cause of either
original interruption.
- Greptile reviewed the current commit at 5/5 with no findings. The
separate Paperclip review execution did not complete and returned a
neutral check without an assessment. This is not counted as a completed
review.

## Risks

- Native debugger inspection of types and local variables needs a
full-debug override. Source-line backtraces remain available.
- Changing debug settings rebuilds affected artifacts. Existing
full-debug outputs may remain until the contributor cleans their target
directory.
- The measured savings are from Linux ARM64 and the cited source
revision. Other platforms and workloads can differ. This is a
build-profile change, not a sandbox capacity increase.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, shell
execution, and Linux build measurements. The session does not expose a
more specific 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-30 14:21:01 -05:00
Nicky LeachandClaude Opus 5.5 8362dbff4d feat(runner): make every ACPX provider declare its release attestation (#18342)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native ACPX runs admit a provider only when its saved profile
version and `commandDigest` match the current profile exactly.
> - #18325 made every provider digest attest its upstream release, and
bound the shared ACPX layer and Runner source through the pack
`contractDigest`.
> - The model is documented, but it lived in prose. A new provider, such
as one in an open PR, could still choose another digest model without
any check or guidance.
> - This pull request makes the model the default path: each provider
declares its attestation in one registry, and the generator, a test and
a scoped rule explain the pattern where contributors meet it.
> - The benefit is that new providers and upstream bumps follow one
model, without a growing list of blocked legacy patterns.

## Linked Issues or Issue Description

Refs #18325, #18237.

**What happened?**

After #18325, only Copilot, Grok and Pi went through
`acpx-release-attestations.mjs`. Cursor and Antigravity had separate
inline checks in the generator, and Claude and Codex had none. A new
provider could add a profile with any digest. Nothing told the author
how to compute it, and nothing pinned the profile versions that now
change only for deliberate resets.

**Expected behavior**

Every ACPX provider declares how its `commandDigest` attests the
upstream release. Tools and review guidance describe the pattern when a
contributor adds a provider, bumps an upstream release or changes a
version.

**Steps to reproduce**

1. Add a new provider profile to
`packages/paperclip-runner/acpx-profiles.json` with an arbitrary
`commandDigest`.
2. Run `node
packages/paperclip-runner/scripts/generate-acpx-profiles.mjs --check`.
3. Before this change, the check passes.

## What Changed

- Add `ACPX_RELEASE_ATTESTATIONS` to
`scripts/acpx-release-attestations.mjs`. Every profile declares one
kind:
- `installed-command` (Claude, Codex): installation hashes the upstream
launch command.
  - `launcher` (Grok): the SHA-256 of the launcher shipped verbatim.
- `closure` (Copilot, Pi): upstream versions and complete platform
closure pins.
- `declaration` (Cursor, Antigravity): a checked-in release declaration,
as canonical JSON.
- `generate-acpx-profiles.mjs` checks every profile through the
registry. The separate Cursor and Antigravity digest checks are now part
of the same path. No digest changes.
- A profile without a declared attestation fails generation. The message
says to declare one and points to the rule.
- A stale digest message now says that a digest changes only with its
upstream release, and that an upstream change keeps the profile version.
- Add a test that pins the profile versions. It explains that a bump
resets every saved session for that provider, and that a new provider
starts at 1.
- Add `rules/acpx-profile-identity.mdc`. It describes the identity
model, how to add a provider, when to bump a version, and review
criteria. `AGENTS.md` and `.greptile/files.json` route the profile,
attestation, contract-registry, ACPX driver and provider paths to it.
- Update the profile identity section in
`packages/paperclip-runner/docs/durable-recovery.md` with the
attestation kinds and the version policy.

## Verification

- In `packages/paperclip-runner`:
- `node scripts/generate-acpx-profiles.mjs --check` passes. Running it
without `--check` changes no digest.
- `node --test scripts/acpx-release-attestations.test.mjs
scripts/contracts/contract-fingerprints.test.mjs`: 22 tests pass. New
cases: every profile declares an attestation, a new provider without one
fails with guidance, and Cursor and Antigravity declaration changes
affect only their own digests.
- `vitest run src/drivers/acpx/profile-compatibility.test.ts`: 15 tests
pass, including the version table.
  - `tsc -p tsconfig.json --noEmit` passes.

## Risks

- Low risk. No digest, version or runtime admission behavior changes.
- A new provider PR must add one registry entry. The generator error
states what to add.
- The version table needs an edit for each deliberate reset. Upstream
bumps do not touch it.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use
(shell, file edits, local test runs).

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:25:06 -07:00
Nicky LeachandClaude Opus 5.5 abc270ee4c fix(runner): attest upstream releases and bind ACPX uniformly for every harness (#18325)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native ACPX runs admit a provider only when its saved profile and
`commandDigest` match the current profile exactly.
> - For Copilot, Grok and Pi, `commandDigest` hashed dozens of Paperclip
source files. Claude, Codex, Cursor and Antigravity hash only their
upstream release.
> - Any change to a bound source therefore advanced these profiles.
#18212 alone moved Copilot from v88 to v91 and Grok from v15 to v19.
Each bump reset in-flight sessions and added immutable identity fixtures
(about 160 on master).
> - #18237 added the provider pack `contractDigest`, which now guards
Runner source compatibility at the pack boundary.
> - This pull request changes the Copilot, Grok and Pi digests to
upstream release attestations, as the other providers already use.
> - It also binds the shared ACPX layer the same way for every ACPX
harness: the profile's `acpxVersion` and the pack `contractDigest`,
which now covers the Runner's ACPX patch.
> - The benefit is that Runner source changes no longer reset these
sessions or need new profile versions and fixtures.

## Linked Issues or Issue Description

Refs #18237, #18212, #17972.

**What happened?**

A Runner change that touched a bound source file changed the Copilot,
Grok or Pi `commandDigest`. The author had to advance the profile
version, regenerate an identity fixture and keep every old fixture. On
deploy, saved sessions for that provider failed the exact admission
check and started fresh.

**Expected behavior**

A provider's `commandDigest` changes only when its upstream release
changes: an upstream version, a platform closure, the ACPX patch or the
Grok launcher. Runner source compatibility is the job of the pack
`contractDigest`.

**Steps to reproduce**

1. On master, change a comment in `src/drivers/acpx/runtime-host.ts`.
2. Run `node packages/paperclip-runner/scripts/grok-profile-identity.mjs
--check`.
3. The check fails. The Grok profile must advance, and the next deploy
resets Grok sessions.

## What Changed

- Add `packages/paperclip-runner/scripts/acpx-release-attestations.mjs`.
It computes the release attestation for each provider:
- Copilot and Pi: a canonical-JSON hash of the profile version, upstream
package versions and the platform closure pins (Pi also binds its Node
version).
- Grok: the SHA-256 of `launcher.cjs`. Admission already hashes these
bytes.
- The attestation binds no Paperclip source, shared ACPX layer, absolute
path, pack manifest digest or install layout.
- Bind the shared ACPX layer once for every ACPX harness (Claude, Codex,
Copilot, Cursor, Grok, Pi, Antigravity):
- Add the Runner's ACPX patch (`patches/acpx@<runner acpx
version>.patch`) to the pack `contractDigest`. A patch change now
retires older image packs for every harness. Other packages' ACPX
patches are not read. A build context without the Runner's patch fails.
- Remove the ACPX patch hash from Cursor's release declaration
(`cursor-contract.json`) and advance Cursor once to profile 17. Copilot,
Pi and Cursor no longer bind ACPX in their own digests, like Claude,
Codex, Grok and Antigravity.
- Saved inputs for every harness already must match the current
`acpxVersion`.
  - Claude and Codex digests do not change.
- `generate-acpx-profiles.mjs` writes these digests to
`acpx-profiles.json`. `check:acpx-profiles` refuses a stale digest.
- Move the Copilot closure pins to `copilot-closure-pins.ts`, so that
the generator can import them. `copilot-installation.ts` re-exports
them.
- Advance each profile once and then freeze it: Copilot 92, Grok 20, Pi
37. A version change at the switch keeps the rollout on the same path as
every earlier profile bump.
- Replace the historical version lists in `profile-compatibility.ts`
with a range. Every revision from 1 through the current one decodes.
Claude and Codex still decode revisions 1 through 5. Launch and recovery
admission still require the exact current profile and digest.
- Delete:
- `scripts/copilot-profile-identity.mjs`,
`scripts/grok-profile-identity.mjs` and its test
  - the Grok launcher source stamp
- 159 Copilot, Grok and Pi identity fixtures, including three
unreferenced `copilot-mainline-v*` fixtures. The Cursor fixtures stay.
- Rewrite the affected tests as behaviour checks:
- Each provider admits only the exact current profile. Every earlier
version decodes and is refused at admission.
- The last source-bound digests, and a changed digest at the current
version, are refused by recovery and by the backend factory.
- The Rust Pi descriptor test uses the generated profile instead of
fixtures.
- New `acpx-release-attestations.test.mjs`: a relocated copy of the
inputs gives the same digests, each upstream input changes only its own
providers, and the generator refreshes and checks the manifest.
- Remove the fixture exceptions from `.dockerignore`. Add the
attestation script and the generator to the Daytona image content
inputs.
- Update the Pi install probe and the Rust integration constant for the
new Pi digest.
- Update the docs to describe the current attestation model:
`doc/grok-native-runner.md`, `doc/RUNNER-INTEGRATION-PLAYBOOK.md`,
`doc/observability.md`,
`packages/paperclip-runner/docs/durable-recovery.md`, and the Copilot,
Pi and rich ACP architecture reports. Each report now opens with the
current profile identity; earlier source-bound profiles remain as dated
chronology. No doc references a deleted file.

## Verification

- In `packages/paperclip-runner`:
- `node --test scripts/acpx-release-attestations.test.mjs
scripts/contracts/contract-fingerprints.test.mjs`: 19 tests pass,
including a Runner ACPX patch edit that changes the contract digest,
other patch edits (including `acpx@0.12.0` for `adapter-utils`) that do
not, and a build context without the patch that fails.
  - `node scripts/generate-acpx-profiles.mjs --check` passes.
- `vitest run src/drivers/acpx src/backends src/contracts`: 1647 tests
pass, 9 skipped.
  - `tsc -p tsconfig.json --noEmit` passes.
- From the repository root, `vitest run --config
tests/runner-e2e/vitest.config.ts
tests/runner-e2e/daytona-image.test.ts`: 11 tests pass.
- In `server`, the 8 test files that use ACPX profiles, pack digests or
`contractDigest`: 1617 tests pass.
- Not run locally: the Rust tests and `cargo fmt`, because this machine
has no Rust toolchain. CI runs them.
- Before this change, a synthetic upgrade check built two Runner
revisions that differ only in shared source. A Claude checkpoint saved
under the first revision rebinds under the second, and a changed Claude
`commandDigest` starts fresh. This confirms that the provider JSON has
no other build-dependent field.

## Risks

- **One reset at rollout.** The Copilot, Grok, Pi and Cursor digests and
versions change once. Saved sessions for these providers start fresh on
their next run, as after any earlier profile bump. After this change,
Runner source changes no longer cause this reset.
- **Lost "source changed, so requalify" signal.** The old digest forced
a new profile version when bound source changed. Nothing enforced
requalification: Copilot was last qualified at v47. Pack-boundary
contract changes are now caught by the pack `contractDigest`.
- **Image packs are retired once for every provider.** Adding the ACPX
patch changes the pack `contractDigest`, so the controller uploads its
bundled pack (about 16 s per remote start) until images are refreshed.
Claude and Codex sessions are not reset: their digests and versions do
not change.
- **Grok launcher and closure pins.** The Grok digest covers only the
launcher bytes. Grok's runtime version is still checked separately at
admission, as before.
- **Grok digest equals early Grok profiles.** The launcher bytes have
not changed since profile 1, so the new Grok digest equals the published
profile 1 digest. The profile version still separates them: launch,
recovery and the backend factory require profile 20. An image pack from
that period has no `contractDigest`, so the pack gate refuses it.
`remote-provider-pack-verification.test.ts` now covers this case.
- **Docker context checks** run `generate-acpx-profiles.mjs --check`,
which now imports `.ts` pin files through Node type stripping.
`materialize-pi-distribution.mjs` already relies on this on Node 24.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool use
(shell, file edits, local test runs).

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:10:50 -07:00
Nicky Leach fba0ab8162 fix(runner): preserve GitHub helpers and Codex probe policy (#18212) 2026-10-30 07:42:10 -07:00
e345b9217d fix(runner): paginate native task searches without hidden truncation (#18282)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents search tasks to find work that already exists.
> - The search schema permits 200 results, but the server returns at
most 100.
> - The response does not tell the agent that more results exist.
> - This pull request adds pages and reports the page size and
continuation cursor.
> - Agents can read the full accessible inventory before they decide
that a task does not exist.

## Linked Issues or Issue Description

**What happened?**

A native `search_tasks` request with `limit: 200` returns only 100
tasks. Historical scans recovered 167 and 173 tasks with status
partitions. This proves missing inventory and extra work. It does not
prove duplicate task creation.

**Expected behavior**

Honor the declared limit. Report more results and give the caller a
continuation cursor.

**Steps to reproduce**

Create 205 matching tasks in a test company. Call `search_tasks` with
`limit: 200`. The baseline returns 100. The fixed path returns 200, then
five when the caller uses `nextCursor`.

**Paperclip version or commit**

Baseline: `81ebe479e8db8a3d59c86cdfb894bd917734492f`.

Related changes: #16979 changes UI status filters before pagination.
#13699 adds public task URLs. Neither repairs this native limit. An
exact `search_tasks` plus pagination PR search returned no result.

Pattern: [Task searches omit cases beyond the first
hundred](https://www.braintrust.dev/app/Paperclip/p/Paperclip%20Staging/patterns/c20462d6-05fd-4862-bfbd-7bec1f2bc159).

### Hypothesis and thesis for a fix

The native authority uses `boundedLimit` with its default maximum of
100. The tool schema permits 200. The response contains only `tasks`.
The raw request and result counts agree with this cause.

Fix the native authority and its canonical tool contract. Keep the
existing `tasks` field. Add `limit`, `returnedCount`, `hasMore` and
`nextCursor`. Use ascending task IDs so task activity does not move
results between pages. Apply current company, privacy and Muse read
checks before each page. A cursor grants no access. Callers must keep
the same filters and read every page. Concurrent task changes require a
fresh scan.

## What Changed

- Honor the native search limit of 1 to 200, with a default of 50.
- Add ID cursor pagination and page metadata.
- Describe complete inventory reads in the tool contract and access map.
- Refresh the generated semantic contracts and seeded catalog identity.
- Add regression coverage for complete inventories and access-filtered
pages.

## Verification

- Red: the database integration test requested 200 of 205 persisted
tasks. Baseline returned 100.
- Green: the same regression returns pages of 200 and five without
duplicate IDs.
- The native authority and Muse suites cover company exclusion, status
filters, empty pages, invalid cursors and readable-only metadata.
- Command: `pnpm --filter @paperclipai/server exec vitest run
src/services/native-runtime/paperclip-runner-tool-authority.test.ts
src/services/native-runtime/muse-native-visibility.test.ts`.
- The test uses the real run-bound native authority and disposable
PostgreSQL. It does not use an external model or change a deployed
scanner.
- Both native authority and Muse suites pass: 71 tests. Server direct
`tsc --noEmit`, Runner `typecheck:typescript`, `node
scripts/check-maps.mjs` and generated semantic contract checks pass.
- Full typecheck and build cannot finish here because `cargo` is absent.
The full local test command was stopped after about five minutes when
the complete CI matrix was running. It has no complete verdict.
Current-head CI passed, including typecheck, build, all
general/serialized/Runner test suites and E2E. Greptile is 5/5 with no
actionable findings at `392cb7424a1fa0ec73401d5e8a10a22b504fde32`.
Optional Storybook and manual Docker workflows were skipped and are not
executed coverage. The success-example correction also passed all 82
contract tests locally.

## Risks

Task order changes to ascending ID. Pagination is not a snapshot. New or
changed tasks can require a fresh scan. Each page retains the existing
full company-list read and Muse authorization cost. This change adds no
database query loop or new background work. Existing callers can still
read `tasks`, but must follow `nextCursor` for a complete inventory. No
scanner implementation was supplied. No migration or deployment is
included.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
provider deployment ID and context limit 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)
- [ ] 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

The task requires the supplied branch to stay unchanged. All applicable
CI and review checks pass at the current head. Unmerged and not
deployed.

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 09:23:10 -05:00
Nicky LeachandClaude Opus 5.5 fa760dbce4 fix(runner): reuse image packs only with matching contract digest (#18237)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote native runs use a provider pack. The controller reuses a
protected pack from the sandbox image when the pack is compatible.
> - #17749 gates this reuse on a hand-maintained interface revision in
`provider-pack-contract.json`.
> - Later changes altered the runner/pack boundary (#17922, #18188), but
nobody bumped the revision. A stale Claude or Codex image pack can still
be reused across a sidecar contract change. This is the failure class of
#17972.
> - A manual revision has a "forgot to bump" failure mode. Source-byte
hashes change on every refactor, so they are too brittle.
> - This pull request declares the sidecar `session.open` contract in
its JSON schema and computes a contract digest from the JSON contracts
and Rust shapes.
> - Image-pack reuse now requires an equal digest.
> - The benefit is that an incidental change keeps image packs reusable,
and a real contract change retires them automatically.

## Linked Issues or Issue Description

Refs #17749, #17972, #17922, #18188.

**What happened?**

The controller reused an image provider pack when `compatibility.acpx`
and the selected agent's profile digest matched. For Claude and Codex,
that profile digest binds only the upstream executable. The ACPX
interface revision stayed at 1 after later sidecar contract changes. A
pack built before those changes passed the reuse check.

**Expected behavior**

The controller reuses an image pack only when the pack uses the same
runner/pack contracts as the controller's bundled pack. Comments,
formatting and refactors do not change that result.

**Steps to reproduce**

1. Build an image pack from a commit before a sidecar input change, such
as a new `session.open` field.
2. Run a controller from a later commit that sends the new field, with
the same interface revision and Claude version.
3. Before this fix, `verifyRemoteProviderPack` accepts the old image
pack.

## What Changed

- Declare the sidecar `session.open` parameter set as a closed
`sessionOpenParams` definition in `acpx-sidecar.schema.json`.
- `generate-acpx-sidecar-contract.mjs` now generates
`GENERATED_ACPX_SIDECAR_OPEN_PARAMS` from it.
- `parseOpenParams` uses the generated list instead of an inline `Set`.
The accepted set is unchanged.
- This is the surface of #17972. The schema is now its source of truth.
- Declare the nested `session.open` contracts that the sidecar parses
strictly:
- `protocol/provider-schemas/runtime-context.schema.json` closes every
runtime context object. `parseNativeRuntimeContext` uses the field lists
that `scripts/generate-runtime-context-contract.mjs` generates from it.
- The sidecar schema declares the closed `providerPolicy` object, and
`parseProviderPolicy` uses its generated field list.
  - The accepted fields do not change.
- Add
`packages/paperclip-runner/scripts/contracts/contract-fingerprints.mjs`.
It fingerprints these contracts:
  - the PRP and sidecar JSON schemas, with annotation text removed
  - the generated catalogs in `generated/`
- the Rust serde shapes, `json!` payload keys, match literals and env
keys in `runner-core/src`, without test-only modules
  - the reserved env key lists in `configured_environment.rs`
- Read only the trees that every pack build context contains. Fail when
a registered source is missing, so two build contexts cannot silently
produce different digests.
- Use only Node built-ins. The registry adds no dependency.
- Write `contractDigest` as a top-level payload field in
`build-provider-pack.mjs`. The manifest digest algorithm and the
existing field layout do not change.
- Require an equal `contractDigest` for image-pack reuse in
`remote-provider-pack-verification.ts`. A pack without a digest is not
reused. The controller uploads its bundled pack, as it does today for
any incompatible pack.
- Re-attest the source-hashed profiles, because this PR changes their
bound sidecar sources:
- Grok becomes profile 15 and now also binds the generated allowlist, so
a Grok field change in the schema still invalidates the Grok identity.
- Copilot becomes profile 88, and also binds the generated runtime
context fields.
  - Earlier profiles stay decodable.
- Add the registry script and `generated/` to the Daytona image content
inputs.
- Document the digest and the schema-first rule in
`docker/daytona-runner/README.md` and `doc/DEVELOPING.md`.

## Verification

- `node --test scripts/contracts/contract-fingerprints.test.mjs` (in
`packages/paperclip-runner`): 4 tests pass.
  - These changes keep the digest:
    - schema description text
    - schema reformatting
    - renaming `parseOpenParams`
    - Rust comments, `#[serde(skip)]` fields and `#[cfg(test)]` modules
- edits to the `#[path]` test module `tests/provider_api_validation.rs`
  - These changes alter the digest:
    - a new `session.open` schema field
    - a changed constraint on the `remainingWork[].description` property
    - a new reserved env key
    - a new sidecar env key
    - a new checkpoint field
  - A build context without a registered source fails.
- `node --test test/acpx-sidecar-contract.test.mjs`: 13 tests pass. A
new case rejects an unknown `session.open` parameter and accepts each
declared parameter.
- `node --test scripts/grok-profile-identity.test.mjs`: 4 tests pass. A
change to the Grok field in the generated allowlist invalidates the Grok
identity.
- `generate-acpx-profiles.mjs --check`,
`generate-acpx-sidecar-contract.mjs --check` and
`generate-protocol-manifest.mjs --check` pass.
- Runner vitest suites pass: 470 passed, 1 skipped. They cover the
sidecar, sidecar input and protocol, Copilot and Pi installation,
profile compatibility, native execution, recovery identity, the backend
factory and the environment.
- Server tests: pack verification, executor and artifact preparation
pass (1,004 tests).
- `tsc --noEmit` passes for `packages/paperclip-runner` and `server`.
- `tests/runner-e2e/daytona-image.test.ts`: 10 of 11 tests pass. The
failing test also fails on `master`. It expects a literal
`profile-v19-identity.json` line in `.dockerignore`, which uses a
`profile-v*` glob.
- Not run locally:
- A complete `build-provider-pack.mjs` run. The builder rejects the
local Homebrew Node because it is not portable after relocation.
- Rust tests and `acpx-controller-recovery.test.ts`, because `cargo` is
not installed.
  - The full `pnpm -r typecheck`, `pnpm test:run` and `pnpm build`.

## Risks

- Only JSON contracts and Rust shapes are part of the digest. The
remaining TypeScript-only definitions are the `paperclip_finish` and
`paperclip_block` tool schemas in `completion-result.ts` and the
TypeScript env key lists. They are not covered until they move into a
schema. The nested `expectedIdentity` and `tools` values ignore unknown
fields, so a change there cannot cause a startup rejection.
- A change there can let a stale image pack be reused. The sidecar then
rejects the input with its strict parser error.
  - Today, Claude and Codex image packs have no contract check at all.
- The digest covers all registered contracts for the whole pack. A
contract change for one provider kind also retires image packs for the
other. Each replacement costs about 16 s per remote start until the
image is refreshed.
- Existing image packs have no digest. After deploy, the controller
uploads its bundled pack until the image is rebuilt.
- The Grok and Copilot re-attestations start fresh sessions for those
agents once after deploy, as each profile bump does today.
- The Daytona image content ID formula changes, so the next image build
does not reuse a cached image.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

Anthropic Claude Opus 5.5 (`claude-opus-5-5`) through Claude Code in the
desktop app, with repository tools, shell execution and research
subagents. The session 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
- [ ] 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>
2026-10-29 22:55:11 -07:00
Nicky Leach a8e07500db fix(runner): preserve runtime activity through the native bridge (#18239) 2026-10-29 18:36:04 -07:00
DottaandPaperclip ebed7f5237 test(evals): protect Antigravity setup and two-turn delivery (#18190)
## Thinking Path

> - Paperclip manages agents and their work.
> - A provider integration must work through ordinary agent setup and
task controls.
> - The recorded Antigravity walkthrough exposed setup, delivery, and
continuation failures.
> - A repeatable check must verify real work and retain failed attempts.
> - This pull request converts all 47 recorded steps into one fixed
Product E2E journey.
> - Maintainers can rerun the case and inspect independent delivery,
cleanup, and accounting evidence.

## Linked Issues or Issue Description

Builds on merged #18187, #18188, and #18189, and consumes the shared
repairs from merged #18230 and the equivalent manual-policy declaration
from #18222. Refs #18214 for the CI task wrapper. Refs #12503 and #14938
for related legacy adapter work.

**Agent or provider**

Google Antigravity native Runner with a saved managed Google
subscription and the exact Low model.

**Why this adapter is useful**

A user must be able to add an agent, connect its account, and receive
real task results across a follow-up. Picker visibility alone is
insufficient.

**How the agent is invoked**

A fixed Playwright driver uses ordinary product controls. The agent runs
through native ACP. Independent checks use public APIs, actual
downloads, owned process observations, and native lifetime fences.

## What Changed

- Register one explicit-only case:
`antigravity-agent-journey.runner-antigravity.local.saved-subscription-two-turn`.
- Map all 47 source steps and declare saved-account prerequisites,
finite limits, and same-host macOS ARM64 scope.
- Create an agent through the ordinary picker, connect the saved
account, select Low, run Test, and wait for readiness. Save an
instruction marker, deliver a file, and update it through an ordinary
follow-up.
- Require each run's visible completed file activity, exact downloaded
bytes, committed Done result, same tagged conversation, distinct
physical owner birth, released lease, and free native fences. Verify
reload persistence.
- Stop failed native runs that still own a retry. Replay an existing
Stop with its durable request identity and wait for the matching audited
acknowledgement. A terminal reservation without a native intent remains
unconfirmed.
- Keep private evidence in the existing result, report, dashboard, and
accounting pipeline. Retain the paused QA agent and financial history
while preserving the shared account and budget policies.
- Journal only the ordinary wizard's future ID, target, name, intended
harness and expected creator before forwarding its POST unchanged. Bind
the response and interrupted recovery to exact identity reads; a pending
404 stays unconfirmed.
- Serialize private resource snapshots through temporary-file fsync,
atomic rename and directory fsync. Abort forwarding on storage failure
and preserve legacy receipts. If later journal or diagnostic writes
fail, retain the primary error, always close the browser, and attempt
the ordinary failed report.
- Add production-component browser controls and harden task-menu
readiness, alias selection, scroll restoration, failure packaging, and
one hermetic auth-test budget.
- Wait for the existing GitHub recovery fixture to register its next
deadline before asserting the original range; preserve its
nested-transaction and zero-request checks. In the decision-expiry
fixture, verify the exact saved expiry separately from the earlier
global wake of another queue.

## Verification

- Fresh registered acceptance passed on eval source
`9060f3cd01b7c3445ecdf703d72e9cf30fe42b59` and merged serving product
`61bd4ac6919c2309f766a25e62273b074cee3261`. It completed ordinary setup
and two turns with native `.5` and `gemini-3.8-flash-low`. All 16
matchers, 14 checkpoints, and cleanup passed in **165,613 ms**. Actual
downloads were **61 bytes** and **119 bytes**. Both turns passed their
own run-bound browser activity checks and reload persistence.
- Independent read-back confirms Done, a paused retained agent, the same
connected saved default account, and no active owned run. Both accepted
results have the same full tagged conversation and distinct primary
process births. All 21 observed processes retired; both leases released
and all three native fences were free after each turn. The selected `.5`
checkpoints also showed equal agent/backend session IDs; this is an
observed case requirement, not a generic ACP invariant.
- Receipts report 339,273 input tokens, 7,224 output tokens, and 202,846
cached input tokens. Subscription prices are unavailable. Billing
coverage remains incomplete, not free.
- The normal report CLI passed. All 310 files from nine original
attempts and two separate recoveries retained their hashes. The twelve
current screenshots are byte-identical, and 194 local report links are
contained and valid. The eight earlier reports were copied without
regeneration.
- Delivery source `1bf4fb04df04710b82844b3c9355767f46b5f68f` branches
from `d3f2a60e795fc60d64c8b19d1eed4d48657d5492` and merges cleanly with
current master `1d571de5f9f886d66e520800baec8fc2f67d0948`. All 41 prior
`c8b332` authored file blobs remain identical; the 42nd path is the
decision-expiry fixture contract correction. Creation ownership, the
strict durable writer, and the ordinary successful workflow remain
unchanged. Of 43 measured file blobs, 30 remain identical. The
Antigravity oracle, artifact, billing and report gates and its
suite-specific validation block remain unchanged. The actual retained
agent matches its original creator; its original request `setupId` was
not captured and is not reconstructed.
- Later master changes include model-visible workspace guidance and
rejected-terminal-report handling. Their bounded source assessment is
separate: the first actual finish failed, then a same-turn replacement
was accepted and committed. Later read-only results match both original
native-result hashes, and the complete event catalogs have no
`session.failed` event. Master #18228 also expands detection of explicit
JSON file requests. The measured create/update-and-attach `.txt` task
already required publication under both parsers; the publication
validation gate itself is unchanged. Master #18240 changes remote
workspace cache staging and adds an OpenCode index refresh. The selected
local lane returns before those paths. Master #18213 adds optional
numeric turn timing and trace boundaries. Its selected Antigravity
model, text, IDs, result and retirement semantics remain unchanged in
the bounded source review. Local diagnostic rows and awaits can change
event ordinals and latency; the oracle checks relative semantic order.
Collector coverage and latency improvement remain outside this proof.
This does not claim that the whole current runtime is byte-identical to
serving `61bd`, or relabel the measured result as a new run.
- The adopted upstream cache controls passed 3/3 with pinned real Turbo.
Forced work disables local and remote reads and writes; ordinary work
reuses local results. The original genuine-pnpm/Turbo controls remain
historical to `9060`'s earlier write-only policy. The duplicate cache
patch is superseded by #18230. Its qualification-only pnpm addition is
removed because the adopted upstream controls do not require it.
- The E2E typecheck, map checks and 277-control replay are carried from
the unchanged eval source paths. That replay passed, including the 183
Antigravity controls, catalog/connection checks and the separate
product-journey validator. The carried creation controls include 91
config/recovery cases. The final launcher suite passed 19/19, including
five real campaign finalization fault cases; the report suite passed
7/7. These final checks did not rerun the earlier 277-control group. The
canonical production-component browser spec passed in 27.4 s under its
unchanged 60 s limit before the replay. Four paused-composer cases and
the product base's build/typecheck plus 376 focused regressions were
verified earlier.
- The shipped wizard and actual API client cover persistence before
forwarding, lost response JSON, foreign/malformed requests, wrong
response identity/creator and cleanup-error preservation. Real
filesystem controls failed 5/5 before the writer repair and passed 5/5
afterward, preserving the old journal on partial-write, temporary-file
sync and rename faults. Three persistent-sync campaign controls failed
before the finalization repair and passed afterward. All five final
campaign fault cases preserve the primary failure, cleanup failure,
usage and failed report while attempting browser closure. The strict
journal still blocks the next mutation. These are provider-free
ownership controls; the Google task proof remains the original `9060` →
`61bd` acceptance.
- The decision restart check passed in the local 20-case fixture run. A
current-source real-PostgreSQL rollback control reproduced the exact
90,000 ms earlier global wake: the old equality rejected it, while the
exact durable expiry and new future-wake bound passed. The original 60 s
open-state, exact-timestamp, continuation and quiet checks remain. The
broader local run was **FAILED: 19 passed / 1 failed**, with a 15 s
timeout and a 30 s cleanup timeout in an unchanged timestamp-pagination
case. That case passed in canonical `c8b332` CI; the local timeout cause
remains inconclusive. An extra local server typecheck failed against
stale cached Runner declarations; it did not check this excluded test
file. Both limits remain recorded for fresh canonical CI.
- A broader local GitHub recovery group passed 21/22. Its unchanged
pagination case observed an unexpected config request; the log does not
establish the cause. That result remains retained, and fresh
current-head CI is the final broader gate.

- Exact delivery-head CI completed with 55 successes, two skips, and one
optional neutral review. Required `ci / verify` and `ci / e2e`, build,
typecheck, and Runner checks passed. Fresh Greptile is 5/5 with zero
unresolved threads. Optional Paperclip is neutral 4/5; its carried
recommendations are dispositioned against the public Stop contract and
selected live identity evidence.

Seven earlier converted attempts retain their failed grades and partial
evidence. Historical Paid8 and its later read-only per-run UI
observation remain separate from the fresh acceptance above. Unknown
prices and the older partial startup accounting remain explicit. Full
lineage and raw evidence remain private in the normal report bundle.

## Risks

- This case requires an authorized saved personal default Google
subscription and finite operator candidate admission. It does not test
fresh OAuth or establish global qualification.
- The physical observer supports a same-host loopback macOS ARM64
target. Cloud, Linux, and other models remain outside this case.
- A known-cost stop cannot cap missing prices or in-flight subscription
charges. Existing operator policies remain unchanged.
- Raw account/native identities stay private. Missing retirement proof
keeps resources retained. The selected cleanup mode does not test agent
purge.

## Model Used

OpenAI Codex (GPT-6). The host did not expose the exact model revision
or context limit. The model used tools for code edits, tests, browser
automation, and review.

## 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-29 19:51:32 -05:00
Nicky LeachandPaperclip 1d571de5f9 Add shared native turn attribution boundaries (#18213)
## Thinking Path

> - Paperclip manages work performed by AI agents.
> - Native execution crosses the plugin worker, Runner, sidecar, and
durable event boundaries.
> - Existing outer spans leave repeated preparation and admission work
unattributed.
> - Optimizations need a common baseline with accurate ownership and
event meanings.
> - This change extends the existing opt-in tracing contract with
bounded timing receipts.
> - It preserves execution policy and keeps provider internals opaque
where the API provides no timing proof.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Attribution of native task preparation, retained/cold Runner handoff,
and completion-to-text work.

**Current behavior**
Worker spans use a flat provider contract. Workspace calls lack a
consistent dispatch envelope. Submitted-to-started timing is named as a
provider queue even though it includes other work. The transport does
not expose a shared breakdown of its waits.

**Proposed improvement**
Add invocation-scoped nesting, bounded numeric remote receipts,
current-run transport timing, durable receipt intervals, and distinct
completion/text milestones. Reuse the existing exporter. No latency
optimization is included.

Related public work: #17842 consolidates existing startup tracing tests;
it does not add this runtime coverage.

## What Changed

- Extend the optional SDK tracer with nested async scopes and completed
timing receipts. Keep the host responsible for parent identity,
capability checks, attributes, clocks, depth, and count limits.
- Add dispatch and bounded host-read timings for environment and
workspace providers.
- Resolve transport parents on each call so retained sessions do not
retain an earlier run's trace.
- Split cold/resume/attach/prepare/registration/command/started-event
waits. Add opt-in numeric ACPX Runner/sidecar status and prompt-start
receipts.
- Distinguish first completion request, validated tool receipt, final
result commit, first nonempty text, and event persistence. Rename the
submitted-to-started interval to match its meaning.
- Link completed earlier remote lifecycles to their host-owned observer
rather than placing them under a later polling request. Preserve
sampling, timestamp limits and budgets.
- Document the versioned coverage map, causal clock limits, and baseline
acceptance requirements.

## Verification

- Current head: GitHub CI is fully green. Standard Greptile and Apex are
both 5/5, with no unresolved review threads. Full-suite validation was
performed in CI; follow-up local validation was limited to affected
packages and tests.

- Review follow-up: early rejection, missing provider capability and
startup-parent regressions were reproduced and fixed. The affected
worker/SDK/timing set passes 128 tests; 28 timing/context tests, SDK
typecheck and direct server TypeScript checking pass. The server
typecheck wrapper reached an unrelated Runner rebuild and stopped
because Cargo was absent from PATH; full Runner/image validation remains
in CI.

- CI failure accounting: the earlier Turbo cache/force conflict and
Linux OpenCode shell assertion were reproduced and diagnosed. A direct
proc probe ruled out permissions; a portable shell comparison identified
Bash skipping BASH_ENV with stripped SHLVL and socket stdin. Upstream
#18230 now supplies the CI and ignored-stdin fixture fixes; this PR
adopts them without duplicate CI changes. The strict Linux OOM assertion
passed before this source-equivalent merge.
- Retry follow-up: the three insertion/replay/failure timing cases and
server typecheck pass. The existing database regression now asserts a
single marker across identical result replay; the current-head CI
integration gate passes.
- Upstream CI alignment: all three real-Turbo 2.11.10 integration cases
pass. The repository policy gate rejected committing a generated
lockfile; the final PR contains no lockfile edit and uses the maintained
inline stale-lockfile recovery.
- Linked-lifecycle follow-up: 44 focused host/export tests pass (three
optional SDK-dependent cases skip); SDK and server typechecks pass. The
API contract test verifies an explicit root context, host-owned observer
link and unsampled suppression.
- SDK typecheck and focused worker/invocation tests: 30 passed,
including clock changes, bounded legacy IPC, and manual-span
creation-scope parentage.
- Focused reviewed host/native/transaction-boundary checks: 44 passed.
The 86-test worker-manager suite passes after updating its exact
assertions for the host-owned timing budget found by CI. Earlier
preparation/first-text checks also passed.
- Affected server and Runner TypeScript checks pass after building local
workspace declarations.
- Merge follow-up: the profile/candidate startup subset passes 94 tests,
the four Grok source-identity checks pass, and Runner TypeScript
checking passes. A subsequent execution-factory merge passes 21 focused
timing/trace tests and server TypeScript checking.
- Pinned Rust build and the ACPX Rust subset pass. The hostile receipt
projection test passes. Source profile compatibility checks: 127 passed,
one existing skip. Grok identity checks: four passed.
- Broad transport/ACPX suite: 410 passed after building all fake
provider binaries. Earlier attempts failed on missing
Runner/fake-provider outputs; building the required fixtures resolved
those failures.
- The first CI run correctly rejected stale source attestations. After
integrating current master, Grok advances 13→14 and Copilot 84→85;
master’s historical fixtures and Pi 35 stay byte-identical. Provider
dependencies, models and permission defaults are unchanged. Identity
generation/checks now pass.
- The added real-Postgres result lock regression could not initialize
its local embedded cluster. The insertion/replay/failure unit
regressions pass. The current-head CI integration gate passes.
- Comprehensive repository checks and image builds are delegated to CI,
as requested for this instrumentation pass. No deployment, model run,
collector-ingestion proof, or latency improvement is claimed.

## Risks

The new SDK methods are optional. Legacy span calls and endpoint-off
behavior remain supported. The host accepts only closed timing names and
bounded attributes. Remote durations are anchored at local receipt;
transport/scheduling uncertainty remains explicit. Trace trees have
count/depth limits. The first rollout must inspect actual collector
exports before treating the baseline as accepted. Fresh live
qualification for the new source identities remains a rollout
requirement. Revert these commits to remove the new measurements; no
schema migration is required.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and local code/tool
execution. The exact runtime 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 described the issue in-PR following the enhancement
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal issue
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] Standard Greptile and Apex are both 5/5, with no unresolved
findings
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 17:45:56 -07:00
DottaandPaperclip fe3e0f2d5f Preserve rejected native completion reports as failures (#18227)
Keep rejected declared completion reports on the existing permanent native failure path. Preserve rejection across restoration and order permanent failure ahead of terminal goal facts, goal results, and continuation while retaining the original provider terminal.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-29 18:49:01 -05:00
Devin FoleyandClaude Opus 5.5 16816d45e6 fix(runner): keep OpenCode thread/read within runnerd's frame limit (#18218)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Runner runs OpenCode agents through runnerd and the
OpenCode app-server proxy
(`packages/paperclip-runner/src/cli/opencode-app-server-proxy.ts`).
> - When runnerd restores an OpenCode session, it sends `thread/resume`
and then `thread/read`. It uses `thread/read` only to find an active
provider turn.
> - The proxy answered `thread/read` with the full retained OpenCode
message history (`GET /session/{id}/message`) in one JSON-RPC line.
> - runnerd rejects a provider stdout line that is larger than 4 MiB
(`CODEX_APP_SERVER_MAX_FRAME_BYTES`). A long OpenCode session therefore
can never resume. Each restore fails with `harness stdout frame exceeded
4194304 bytes`, and the run stops with `provider_frame_too_large`.
> - This pull request makes the proxy return turn metadata only, the
same as the Codex metadata-only read.
> - The benefit is that long OpenCode sessions resume again, and resume
no longer reads the full message history.

## Linked Issues or Issue Description

**What happened?**

A Paperclip Runner OpenCode task on staging tried to resume its session
in a new sandbox. The restored OpenCode state was approximately 41.5 MB.
The `run.attach` command failed with `failed to resume OpenCode
provider: failed to start opencode provider: harness stdout frame
exceeded 4194304 bytes`. The server recorded
`native_session_recovery_failed` with error code
`provider_frame_too_large`, and it stopped automatic replay. Each new
attempt has the same failure, because the message history only grows.

**Steps to reproduce**

1. Run an OpenCode task until its session holds more than 4 MiB of
message parts.
2. Let the run continue in a new runner process, so that runnerd must
send `thread/resume` and then `thread/read`.
3. The proxy writes the full message history in the `thread/read`
response. runnerd rejects the frame and the resume fails.

**Expected behavior**

The resume succeeds. The size of the session history does not change the
size of the `thread/read` response.

**Root cause**

`thread/read` in the OpenCode proxy added `transcript: await
session.read?.()`. No consumer reads this field. The Rust provider reads
only `thread.turns` (`latest_active_turn_id`). The Codex path already
avoids message hydration for the same check ("Never hydrate message
contents just to decide whether this thread has an active turn").

## What Changed

- `opencode-app-server-proxy.ts`: `thread/read` now returns `thread.id`,
`thread.cwd` and `thread.turns` only. It does not call `session.read()`.
- `test/fixtures/fake-opencode-server.mjs`: the fake OpenCode server can
now return a large retained message history. The test enables this with
a `fake-message-history-bytes` file in `XDG_DATA_HOME`. This follows the
existing file-switch pattern of the fixture. Without the file, the
response is `[]`, as before.
- `src/cli/opencode-proxy-thread-read.test.ts`: a new regression test.
It builds the real bundled proxy entrypoint, starts a session, stops the
proxy, gives the persisted session a 5 MiB history, then starts a new
proxy and sends `thread/resume` and `thread/read` (the runnerd restore
sequence). It asserts that all stdout frames stay below 4 MiB and that
`thread/read` still reports the thread id and turns.

## Verification

- Red before the fix: `npx vitest run
src/cli/opencode-proxy-thread-read.test.ts` failed with `expected
5243183 to be less than 4194304`. The 5,243,183-byte frame was the
`thread/read` response.
- Green after the fix: the same command passes.
- `npx vitest run src/cli/opencode-app-server-proxy.test.ts
src/cli/opencode-proxy-thread-read.test.ts`: 6 passed.
- `npx vitest run src/cli/opencode-proxy
src/backends/native-instruction-measurement.test.ts
src/drivers/opencode`: 158 passed, 1 failed. The failure
(`opencode-server-driver.test.ts` > "uses provider structure rather than
prose length to select a post-tool answer") also fails on the unchanged
base commit in this environment. This change does not touch that path.
- `tsc -p tsconfig.json --noEmit` for `packages/paperclip-runner`:
passed.
- Safety checks:
- Consumers: only the runnerd Rust provider (`read_thread`) calls
`thread/read` on this proxy. It reads `thread.turns`. No TypeScript or
Rust code reads `transcript`.
- Active-turn detection does not change. The `turns` logic is the same
code.
- Resume now does less work: one `GET /session/{id}/message` request
less.
- Not run locally: the Rust tests and a full runnerd plus real OpenCode
resume. This environment has no Rust toolchain. The Rust code does not
change. CI runs the Rust suites.

## Risks

- Low risk. The change removes one unused response field.
- If an external tool read `transcript` from the proxy's `thread/read`,
it does not get it now. I found no such consumer in this repository.
- Tasks that already failed with `provider_frame_too_large` continue
only after this proxy reaches the runner provider pack and the task runs
again.

## Model Used

- Provider: Anthropic. Model: Claude Opus 5.5 (`claude-opus-5-5`). Used
through Claude Code with tool use (shell, file edit, GitHub connector)
and standard reasoning.

## 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 (related: #16401 kept OpenCode turns alive through oversized
SSE events. It does not change `thread/read`.)
- [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 (none
required: no documented contract includes `transcript`)
- [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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 15:13:29 -07:00
DottaandPaperclip 54cc522e86 feat(runner): add gated native Antigravity ACP execution (#18188)
## Thinking Path

> - Paperclip manages agents and their work.
> - Native Runner must bind each provider turn to the selected task,
account, model, and instructions.
> - Antigravity needs native ACP admission and physical process
ownership across continuation.
> - A saved conversation must not reuse an old process owner or silently
switch its effective model.
> - This pull request adds the native candidate behind exact operator
admission.
> - The default release gate remains closed while qualification is
pending.

## Linked Issues or Issue Description

Builds on merged #18187. Product account setup and the candidate
producer are in dependent #18189. The repeatable browser journey is in
#18190. Refs: #12503, #14938; those proposals use legacy CLI adapters.

**Agent or provider**

Google Antigravity ACP 1.4.3.

**Why this adapter is useful**

Users need to set up an Antigravity agent and run real work through
their managed Google subscription.

**How the agent is invoked**

Native Paperclip Runner uses the pinned Antigravity ACP runtime. Exact
operator admission is required while qualification remains pending.

## What Changed

- Add native Antigravity ACP model and instruction admission,
selected-account homes, and fenced refresh ownership.
- Carry exact candidate authority from the control plane through Runner,
Rust, the sidecar, and each current run. Clamp daemon lifetime to the
absolute permission expiry, including replacement owners.
- Preserve a rotated OAuth refresh token before later identity
verification can fail, including failed or cancelled startup admission.
Make private lease-close retries safe.
- Bound native probe retirement and retry the exact original owner; do
not delete credential homes before physical proof.
- Preserve Gemini API-key recovery when shared Google subscription
capability is added.
- Resume the same tagged native conversation with fresh per-turn process
ownership and physical native retirement.
- Include native manifests in isolated Rust image stages, release cache
keys, and dev rebuild detection. The workflow changes only extend
existing cache input lists.
- Keep current master provider behavior and append Grok 13, Pi 35, and
Copilot 84 input identities. Preserve prior identities, including saved
Copilot 82 and 83 runs.

## Verification

- Runner TypeScript main checks, profile generators, Rust formatting,
and offline workspace checks pass. The native backend integration target
passes 28 tests.
- The complete transport and cleanup group passes 387 tests without
unhandled rejections. These checks use local scripted children and
actual process and port ownership.
- Saved-profile decoding, native-execution parsing, installation, and
selected-credential controls pass 208 focused tests. All 109
pre-existing profile identity files remain byte-for-byte unchanged.
Copilot, Grok, and shared TypeScript/Rust generation checks pass.
- The final recovery fixture passes all seven cases. After the master
rebase, the combined recovery and owned-Node-runtime group passes all 10
cases. Each expiry case sets one 45-second absolute grant before
startup. It includes the deliberate six-second cold delay, four existing
eight-second command budgets, and active-turn headroom. The test proves
an active turn before expiry and then checks the daemon, owned process
group, child processes, and all three native port fences. The 60-second
test deadline does not renew provider authority.
- The consolidated model-discovery and pending-release group passes 22
tests. Google credential compatibility and auth recovery pass 25 tests,
including existing Gemini API-key recovery. The full product settings
test group remains intact in #18189.
- Earlier failures remain in their original CI runs and local records.
They exposed the Copilot 82 decoder gap, an expired five-second fixture
bootstrap ticket, and a fixture grant consumed before activation on
loaded CI. Each repair has a separate result. Production ticket limits
and admission behavior are unchanged by the final test commits.
- An unrelated decision-expiry check failed in [the earlier CI
run](https://github.com/paperclipai/paperclip/actions/runs/40941986698/job/123688668997).
Its owning code is unchanged from the base. The unchanged suite passes
20 tests on isolated PostgreSQL. A controlled database rollback
reproduces the earlier wake: clean startup schedules the 120-second
decision expiry, while rollback reconciliation leaves a 30-second
continuation-coalescing wake. The decision stays open, with no wake
delivery or error. The fresh final-head server shard passes; the failed
result is preserved.
- Final native commit `ec6bc7e4d77f5ae0cc4946dbba6c662e95a87f5b` passed
`ci / verify` and `ci / e2e`. Fresh Greptile and Paperclip reviews both
score 5/5, with no open findings. Antigravity retains the recorded
native `.5` closure and exact low-model profile. This PR does not claim
global or cross-platform qualification.

## Risks

- The new transport carries private managed credentials. Exact
ownership, account generation, model, instructions, and native
retirement are fail-closed.
- Only local macOS ARM64 has a verified complete Antigravity runtime.
Default Antigravity task execution remains disabled without current
trusted operator admission. The Google server sign-in lane and
production candidate producer ship in #18189; this native slice does not
expose the subscription catalog choice.
- Shared launch inputs change provider identities. New identities are
append-only; existing recorded identities remain available.

## Model Used

OpenAI Codex (GPT-6). The host did not expose the exact model revision
or context limit. The model used tools for code edits, tests, and
review.

## 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-29 16:36:12 -05:00
DottaandPaperclip 9e09d8f51f fix(runner): clarify native approval argument recovery (#18205)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - First-task onboarding requires a saved human proposal decision
before child work can start.
> - Native proposal tools reject interaction metadata placed outside
their advertised schema.
> - The existing rejection text focuses on question forms and does not
explain the misplaced approval metadata.
> - This pull request explains the field placement and keeps approval
recovery in its original confirmation or checkbox kind.
> - It also retains safe schema guidance in the run log so operators can
identify the rejected field.

## Linked Issues or Issue Description

Refs: #18025 for native first-task proposal recipes and #16889 for safe
native schema guidance. Related open PR #18105 changes separate server
API-client guidance.

**What happened?**

A native first-task confirmation copied `version` and
`supersedeOnUserComment` to the tool root. Both belong inside `payload`.
The runner correctly rejected the call before execution, but its
feedback described question forms. Later calls kept the misplaced field
and changed the approval into a question. No proposal card was created.
The run log retained only a generic schema error.

**Expected behavior**

Keep strict validation. Explain the nested field locations. Keep a
confirmation or checkbox approval in that kind while correcting its
arguments. Save the normal pending card and wait for an actual human
decision. Retain bounded schema guidance without storing rejected input.

**Steps to reproduce**

1. Send an otherwise valid native confirmation with root-level `version:
1` and `supersedeOnUserComment: false`.
2. Observe the pre-dispatch `invalid_tool_call` rejection.
3. Move both fields into `payload` and keep `interactionKind:
"confirmation"`.
4. Verify that the corrected call creates one pending confirmation,
exact replay creates no duplicate, and child creation still needs saved
human acceptance.

**Paperclip version or commit**

The observed argument shape and initial regressions came from public
source base `c32e1ba6`. The repair is based on maintained master
`4a6f6a65`. Public tests use synthetic prompts and identifiers.

## What Changed

- Give rejected confirmations and checkboxes approval-specific guidance.
It names `payload.version` and `payload.supersedeOnUserComment` without
suggesting a question-form recipe. Other human-input errors retain
complete question-form guidance and stable question/option ID
instructions.
- State the allowed native root fields in the first-task skill and put
the metadata inside both executable proposal recipes.
- Retain the existing safe guidance in `semantic_tool_denied`
diagnostics. Keep the original rejection identity and
`paperclipExecuted: false`.
- Preserve only the exact bounded scalar diagnostic payload after
verified event admission. The rest of the envelope and all API
request/result bodies keep their existing redaction.
- Add a real native Codex transport regression and strengthen
advertised-schema, card replay, human-admission, persistence, and
privacy controls. Update the execution contract and onboarding maps.

## Verification

- Red: the native transport reproduced the malformed confirmation and
showed that the old hint omitted the metadata correction. A second red
confirmed that approval guidance still included the question-form
recipe. The corrected transport case now rejects before execution,
retains a safe hint, and dispatches one corrected confirmation that
returns a pending card.
- Red: both shipped recipe checks lacked explicit nested metadata. All
49 first-task admission tests now pass, including advertised-schema
validation, idempotent card replay, actual human acceptance, agent-only
rejection, and question-answer controls.
- Updated native checks pass on the current repair: 95 native Codex
transport tests with 2 existing ignored cases, all 32 provider-bridge
tests, and the schema-feedback unit control.
- API/case persistence regressions were red before the event-boundary
correction. All 71 affected port/redaction tests pass in a clean run at
frozen head `3be3a70f`, including the corrected envelope privacy
regression. The focused 16-test persistence/privacy group and server
typecheck also passed earlier.
- Full local `pnpm build` and `pnpm -r typecheck` pass at exact head
`3be3a70f` in a clean detached checkout with Node 24.22.0 and pnpm
9.15.4. Exact-head CI passes: [full PR
CI](https://github.com/paperclipai/paperclip/actions/runs/40950360142)
and [isolated native Runner
readiness](https://github.com/paperclipai/paperclip/actions/runs/40950359835).
- The full local unit attempt recorded a 15-second timeout in the
unrelated Microsoft Teams 100,000-character existing-comment publication
case. That failure remains recorded. The exact isolated rerun passed (1
test; 1,814 unselected). The aggregate timeout cause is unproven. That
long local run straddled subsequent source edits and also observed the
two port regressions during their red phase; it was stopped and is not
final-head evidence. The clean affected-suite run above and current-head
CI provide the final verification. No timeout or assertion was weakened.
- Release-registry CI initially rejected the native test's compile-time
schema include outside the release crate's hashed input closure. The
guard was reproduced locally. The test now reads the current canonical
schema at execution. All 10 crate-cache controls and the real native
approval regression pass afterward; the cache guard and workflow keys
remain unchanged.
- Current-head Greptile review is 5/5 with no unresolved review threads.
All required checks pass (56 success, 4 skipped). The advisory Paperclip
Review remains neutral/incomplete after one normal re-review request; no
completed assessment or score is claimed.
- `cargo fmt --check`, map structural checks, and `git diff --check`
pass.
- Source and scripted-provider checks do not prove that a model will
follow the guidance. The original live onboarding attempt remains
failed; acceptance at a deployed revision is separate work.

## Risks

- This changes repair guidance and shipped instructions. It does not
make malformed arguments valid or supply a human decision.
- Diagnostic retention adds no rejected arguments, values, or unknown
input keys. The API receipt allowlist is unchanged. The validated-event
exception restores only the safe scalar payload; optional debug and
other envelope metadata still pass through redaction.
- The existing 512-byte guidance bound, strict tool schema, company/run
binding, idempotency checks, and proposal admission remain effective.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) through Codex, with tool use and code
execution. The context-window size is 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 (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-29 15:48:37 -05:00
DottaandPaperclip d2c7edda16 test(runner): own Node executable in ACPX recovery fixtures (#18196)
## Thinking Path

> - Paperclip manages AI agents and controls their work.
> - The runner recovery tests check durable ACPX session ownership.
> - The runner must reject a qualified executable that other users can
write.
> - The recovery fixture passes the shared host Node executable to that
guard.
> - A hosted CI job rejected the fixture before it opened a session.
> - This pull request gives the fixture its own Node copy with safe
permissions.
> - The recovery tests can then check recovery without changing the
production guard.

## Linked Issues or Issue Description

Refs: #18185, #14529.

**What happened?**

The Runner vitest 2/2 job in [run
40928584358](https://github.com/paperclipai/paperclip/actions/runs/40928584358/job/123645695206)
failed five ACPX controller recovery tests. Each test failed at
`session.open` with `qualified ACPX must not be group- or
world-writable`. The assertion did not retain the failing artifact path
or mode. The fixture passes `process.execPath` as its command and digest
source.

**Expected behavior**

A test must supply an owned executable with the permissions that the
production guard requires. It must not change the shared host executable
or weaken the guard.

**Steps to reproduce**

Run `acpx-controller-recovery.test.ts` on a host where the shared Node
executable permits group writes. The remote job above retains the actual
failure. Local validation in this PR does not execute the controller or
compile Rust.

## What Changed

- Extract the existing Node and Homebrew `libnode` copy logic into a
test-support helper.
- Use that helper in the existing native distribution fixture.
- Use an owned Node copy for the recovery descriptor, qualified command
and command digest.
- Add filesystem checks for copied bytes, permissions, library selection
and unchanged source files.
- Ignore only a missing adjacent library directory. Report other read
errors with the directory and original cause.

## Verification

- Three filesystem-only Vitest tests passed. They use synthetic writable
artifacts and copy the actual host Node bytes without executing them.
- TypeScript no-emit passed for the new helper and its pure test.
- The new real-filesystem `ENOTDIR` control fails against the first PR
head and passes after the review fix. The parent returned an incomplete
closure; the successor rejects it during preparation.
- `git diff --check` passed.
- The first-head Build job failed in the public npm consumer check with
`ETARGET` for `@aws-sdk/credential-provider-web-identity@^3.972.85`. A
later single exact-version official registry metadata request returned
HTTP 200 for `3.972.85`. This preserves the original failure and does
not establish its cause. No dependency version or check was changed. The
source review fix will receive normal fresh-head CI.
- The first local test configuration had an import error. The first
typecheck invocations had configuration and type-path errors. Corrected
invocations passed; those setup failures are retained in the source
receipt.
- On the reviewed successor, remote Build passed and all five ACPX
controller recovery tests passed. The other runner shard failed because
the new real-Node Buffer deep-equality assertion exhausted its worker
heap. The one-line follow-up uses native Buffer byte equality and keeps
the same invariant. Its three filesystem controls and scoped typecheck
pass; latest-head normal CI remains required.
- Final head `1939f41a7e9cb4031acdf8e99df431b81f28ba03`: both required
checks (`ci / verify`, `ci / e2e`) pass. Remote tests confirm 5 recovery
tests, 33 native distribution tests and all 3 owned-Node tests pass.
Greptile is 5/5 with no open review threads.
- A server queue test timed out at 15 seconds on this head. Its actual
CI checkout has identical server and dependency sources to the prior
passing checkout. One authorized failed-only replay passed at the same
checkout: all 105 files and 2,270 tests passed. The specific test took
5.23 seconds. Passing Build and runner jobs were carried forward. The
original timeout remains retained; this does not establish its cause.
- The actual recovery and native distribution tests, full typecheck,
build and full suite were not run locally. Those tests can compile or
execute native runtime code. Normal PR CI must verify them before
delivery.

## Risks

- Moving the existing fixture copy logic could affect platform-specific
Node library loading. The helper retains the existing Homebrew library
rule and permission modes. Remote CI remains required.
- This change does not prove which artifact mode caused the retained CI
failure. It removes the fixture's dependence on shared host executable
permissions.
- Production code, dependency versions, timeouts, retries, workflows and
writable-artifact guards are unchanged.

## Model Used

OpenAI GPT-6 through Codex, with source inspection and code tools. The
exact serving model identifier 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-29 14:57:08 -05:00
DottaandPaperclip 09c05c5505 feat(runner): provision pinned Google Antigravity native runtime (#18187)
## Thinking Path

> - Paperclip manages agents and their work.
> - Native Runner providers need verified executables before they can
run.
> - Google Antigravity ships a native ACP server and a helper
executable.
> - An archive hash alone does not verify the installed runtime or its
child process cleanup.
> - This pull request adds a pinned installer and a small, verified
compatibility patch.
> - Later pull requests add Runner execution, account setup, and the
recorded user journey eval.

## Linked Issues or Issue Description

Refs: #12503, #14938. Those pull requests use the legacy CLI adapter.
This stack adds native Runner ACP support.

**Agent or provider**

Google Antigravity ACP 1.4.3.

**Why this adapter is useful**

Users need a reproducible runtime before they can select Antigravity for
a Paperclip agent.

**How the agent is invoked**

The installer prepares the native ACP server and helper. This pull
request does not enable task execution. Default execution remains closed
pending qualification.

## What Changed

- Pin the complete macOS ARM64 runtime closure. Keep other platforms as
inventory only.
- Verify archive entries, installed bytes, ownership, and cache layout.
- Patch exact upstream code anchors for model admission, instruction
loading, native process ownership, and per-call file tool completion.
- Package a self-contained installer and expose `paperclipai runtime
setup antigravity`.
- Record candidate limitations and historical acceptance evidence.

## Verification

- Runtime provisioning, packaging, metadata, and patch support tests: 62
passed. The separate exact pinned native patch run passed all 5 tests
with no skips and no Google authentication.
- CLI runtime setup tests: 5 passed.
- Map contract check passed. Staged diff whitespace check passed.
- The first test command ran before dependency installation and failed
on missing esbuild. The same command passed after installation.
- Current master has a stale lockfile. Dependencies were resolved
locally with scripts disabled. The generated lockfile is excluded from
this pull request.

- Final head: required `ci / verify` and `ci / e2e` passed, and Greptile
is 5/5 with both review threads resolved. The optional external
Paperclip Review remains queued. Two original timing failures are
retained; one failed-job rerun passed without source or deadline
changes.

## Risks

- The patch depends on exact upstream native code. A new upstream
release must get a new verified closure.
- Only macOS ARM64 has a complete verified runtime. Installation does
not qualify authentication, task execution, or other platforms.
- The installer downloads official Google assets when the verified cache
is absent.

## Model Used

OpenAI Codex (GPT-6). The host did not expose the exact model revision
or context limit. The model used tools for code edits, test execution,
and review.

## 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-29 13:25:54 -05:00
DottaandPaperclip 6f278dd6d7 fix(runtime): settle recovery lease and connection lifecycles (#18167)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - A remote runner can survive a controller restart.
> - Recovery renews its execution lease during slow preparation.
> - The native executor then shares that renewal timer.
> - Preparation kept its reference until all finalization finished. A
tick after lease release treated completion as ownership loss and
detached the retained runner.
> - A Linux continuity test also found that buffered wire events could
arrive before their connection was registered. Cleanup then kept a
completed promise under an undefined key and never finished.
> - This pull request transfers renewal ownership after execution
acquires its reference. It also registers each connection before wire
callbacks can run.
> - Recovered turns can complete, retain the warm runner, and settle
connection cleanup.

## Linked Issues or Issue Description

**What happened?**

A recovered remote run could complete, release its coordinator lease,
then detach during instruction collection. The next turn could find the
old runner still using the ingress port. Recovery then stopped because
it could not prove process ownership.

**Expected behavior**

Preparation keeps the lease alive until execution owns renewal.
Execution stops renewal before releasing the lease. Actual ownership
loss still detaches the runner. Buffered wire callbacks must use the
registered connection, and cleanup must finish.

**Steps to reproduce**

1. Recover an in-flight remote runner after a controller restart.
2. Let the recovered turn complete.
3. Hold instruction collection open through the next lease renewal tick.
4. Send a follow-up that needs the retained runner.

Related: #17439 introduced remote controller recovery. #18011 preserves
checkpoint authority through warm preparation. This change fixes the
lifetime of preparation's renewal reference.

## What Changed

- Pass an internal lease-acquired callback from recovery through
heartbeat dispatch.
- Release preparation's renewal reference after the executor registers
its own. Keep final cleanup for exits before dispatch.
- Add a PostgreSQL regression for completion while finalization is still
pending. Cover callback forwarding, acquire-before-release ordering, and
failure before dispatch.
- Register the authority connection before subscribing to wire events.
Handle an immediate close before accepting buffered data.
- Add regressions for a message or close delivered during subscription.
- Extend Linux continuity coverage with preparation renewal and delayed
instruction collection after recovery.
- Update the continuity guide and session verification recipes.

## Verification

- The new recovery regression failed before the fix because renewal
detached the runner after lease release. The 76 recovery, renewal, and
dispatch tests then passed. The final ordering and early-exit checks
passed again after replacing fixed sleeps with controlled interval
ticks.
- Both buffered-wire regressions failed before the connection fix. All
170 control-plane tests passed afterward. Existing tests cover stale
authority, ownership loss, pending operations, and closed ingress.
- Linux ARM64 acceptance passed at
`a7daefacceb8bd994d0b79d284cdf54f3e3829d1`, with Node 24.19.0,
PostgreSQL, the real Rust runner, TLS ingress, and a deterministic Codex
protocol fixture. The test interrupted the first turn, recovered it,
held finalization open for a renewal interval, and completed two
follow-ups. It retained one provider process, three turns in one
history, and the same runner identity. Final suspension and connection
cleanup completed. The ordinary warm-reuse case also passed three turns
with one provider process.
- Earlier Linux attempts completed the turns but hung during cleanup. A
debugger found a fulfilled promise keyed by an undefined connection. The
regression reproduces that defect. One later setup attempt timed out
while staging an unstripped 373 MB debug binary. The passing run used
the same binary with debug symbols removed.
- Reproduce Linux acceptance with the `same-server` case in
`doc/testing-native-remote-continuity.md`.
- `pnpm -r typecheck`, `pnpm build`, map validation, and `git diff
--check` passed at the final revision. The full local `pnpm test:run`
command was attempted, but the serial run had not finished after 13
minutes. It was stopped after the equivalent CI lanes passed. It is not
counted as a full local pass.
- Greptile and the Paperclip review both scored the final revision 5/5
with no findings. All Runner verification lanes passed. The first CI
attempt hit timing failures in voice recovery, agent YAML configuration,
and the task-title outage browser test. The full YAML and voice-recovery
files passed locally (88 and 19 tests). These paths were unchanged and
passed on the prior revision. All three passed on the single retry.
Final current-head status: 55 successful checks, one neutral check, and
two skipped Storybook checks. No pending or failed checks remain.
- Live Daytona/model acceptance and recovery of the hosted task remain
unverified. This PR does not deploy the change.

## Risks

- Releasing preparation before execution starts renewal could leave a
gap in authority. The callback runs after the executor registers its
reference.
- Preparation errors must not leak renewal. The recovery promise retains
idempotent final cleanup.
- Wire callbacks can run during subscription. Message and close
regressions check that registration is complete before either callback
runs.
- No schema, API, model, permission, lease duration, or retry policy
changes.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and browser diagnostics. The exact serving model identifier
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-29 11:18:53 -05:00
DottaandPaperclip c32e1ba6da fix(onboarding): keep approved child task handoffs runnable (#18160)
## Thinking Path

> - Paperclip manages work through tasks, agent runs, dependencies, and
human decisions.
> - The first-task workflow asks for approval before it creates an
execution task.
> - File-producing work must run on a child task before onboarding can
finish.
> - A child blocked by its onboarding source cannot start while the
source waits for that child.
> - This change rejects that dependency during task creation and later
edits, and gives the agent a correction.
> - The shipped recipe shows the dependency direction and requires the
actual approved inputs in the child instructions.

## Linked Issues or Issue Description

**What happened?**

After human approval, an onboarding run could create a child with the
onboarding source in `blockedByTaskIds`. Creation saved a blocked child
with no wake. The parent could then wait for that child. A handoff could
also refer to input from the parent conversation without including the
input in the child description.

**Expected behavior**

The approved child can execute before its waiting parent. Invalid
first-task dependency input fails before task creation and leaves the
same command key available for a corrected call. The child instructions
include the required approved input and constraints.

**Steps to reproduce**

1. Accept a proposal on a server-created first task.
2. Call native `create_task` with `status: "todo"` and the onboarding
source in `blockedByTaskIds`.
3. Observe a blocked child with no scheduled wake. Block the parent on
that child to expose the stalled handoff.

**Paperclip version or commit**

The regression reproduces on `f8484a9f8d1f68e9534fee4f29e00e716dc680f4`.
The repair is based on current master.

**Deployment mode**

Core native and REST task creation. The same server boundary serves
self-hosted and hosted instances.

Related: #18080 fixed remote delivery of the selected first-task skill.
This change handles the later child handoff boundary.

## What Changed

- Reject a task blocked by its authenticated first-task source during
creation and later dependency edits. Later agent edits also check the
locked target's server-owned onboarding parent, protecting a child
running under its own execution. Compare UUID identity in PostgreSQL so
alternate supported UUID spellings cannot bypass the check. The error
explains the correction.
- Add a native child/dependency recipe with self-contained approved
input guidance. Clarify the general `create_task` input descriptions and
update their generated contracts.
- Cover native and REST rejection, corrected retry, preserved valid
dependencies and replay, and an executable recipe with exact input bytes
read from the child's own context. Thread the authenticated run through
native dependency edits. Keep blocker corrections independent of a new
proposal decision.
- Update execution semantics and the existing onboarding map entries.

## Verification

- Red on `f8484a9f`: the new native regression received a created
blocked child instead of the expected rejection.
- Review regressions were red on the original PR head: uppercase,
unhyphenated and braced source UUIDs created blocked children; a later
child PATCH returned 200 and saved the reversed blocker.
- Review follow-up reproduced both native and REST child-own-run
bypasses on `75fa75a6`: the native dependency call applied the reverse
edge; the child's own PATCH returned 200. The regression uses the actual
authenticated child execution and an already checked-out task.
- All 95 tests across first-task admission, assets, and the full native
tool-authority suite pass. The shipped recipe is validated against the
native schemas and exercised through real task/dependency services with
disposable PostgreSQL. Rejected PATCH tests preserve existing
authorization and attempt-audit behavior and require no requested
task-field, relation or wake change. Compatibility controls retain
ordinary manual parent blockers, explicit board edits, other blockers
and empty-list corrections.
- Runner TypeScript build, generated contracts, capability inventory,
protocol manifest, and map checks passed.
- Server typecheck and all 95 focused tests pass with the child-run
follow-up. All latest checks pass on `f24509ae`: 55 successful checks,
one neutral review check, four skipped checks, and a successful legacy
security status. Both automated reviews are 5/5 on this exact commit.
- Prior-head CI failures are preserved: the Runner close fixture had
unconfirmed provider drain while suspension succeeded; its exact
fake-provider subprocess row passed locally with unchanged sources. The
browser outage test lost its title textarea before any outage write. A
bounded local control with a fully loaded composer passed every original
outage assertion. The prior failure is an editor-readiness race; its
exact asynchronous ordering remains unproved. No UI, browser-test, or
timeout change is included. Neither failure is counted as a pass or
silently discarded.
- The first `f24509ae` CI attempt had two interrupted jobs: Typecheck
and General server 9/12. Their logs record runner shutdown signals. The
server job also records lost runner communication. The same-head
failed-job rerun passed both jobs and the required aggregate. It reused
the other successful results. No source, test, or timeout change was
made for the rerun. The failed attempt remains preserved. Full
repository checks pass in CI; the local full repository typecheck, test,
and build commands were not repeated.
- No external model or provider calls are used by these checks.
Real-provider acceptance at this revision remains separate.

## Risks

- The new rejection uses the authenticated run and the server-owned
onboarding origin. Ordinary tasks, other blockers, empty-list
corrections, and already committed creation replay retain their existing
behavior. Blocker edits do not reapply the creation approval gate.
- Nonempty blocker edits perform two indexed identity reads; the task
lookup covers at most the run source and locked structural parent. Other
patches and empty-list corrections add no source lookup. The update
guard adds no parent row lock behind a child. Existing REST
authorization checkout and attempt auditing remain in place before the
domain mutation guard.
- The explicit input recipe guides the model. Schema and persistence
tests do not prove that a future model follows every instruction.
- The tool guidance changes the generated semantic catalog identity. The
maintained generated files are synchronized in this change.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with `ultra` reasoning effort,
repository tools, code generation, and test execution. The context
window is not exposed by the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used and stated the available runtime
detail
- [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 described the issue in-PR following the bug issue template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
ticket ID
- [x] I have run 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 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-29 10:57:31 -05:00
DottaandPaperclip 76a796e964 test(runner): cover ACPX execution across controller replacement (#18161)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner keeps provider execution separate from the main
server.
> - A server replacement must reconnect to the original execution.
> - ACPX recovery also needs the original provider session to remain
alive.
> - We need to distinguish a controller outage from a provider crash or
an explicit close.
> - This pull request adds five process-level regression tests for those
boundaries.
> - The tests prevent duplicate launches and preserve the scope of the
evidence.

## Linked Issues or Issue Description

Refs #17097, #17439 and #17455. These changes add coverage for the
existing recovery contract. They do not add another recovery
implementation.

**What existing behavior does this improve?**

Native ACPX execution across authenticated PRP controller replacement.

**Current behavior**

Runner has recovery coverage, but this ACPX sequence needed a focused
test: lose the controller, restore its checkpoint, adopt the same
process, and close the old controller. A provider that has already
closed can return `ACPX request snapshot requires the surviving
provider`. That message alone does not identify why it closed.

**Proposed behavior**

Run five credential-free regressions with the production Rust Runner and
a scripted ACPX peer. Preserve active work and offline completion. Check
native transport adoption and old-controller cleanup. Keep
provider-crash and explicit-close controls separate from controller
recovery.

**Reason and benefit**

Catch a future change that kills or replaces a live execution during
controller replacement. Keep a matching error control from being
mistaken for proof of a hosted root cause.

## What Changed

- Add five process-level ACPX controller recovery tests.
- Restore controller state from an external checkpoint after deleting
local controller storage.
- Check that native transport adoption does not launch a replacement
Runner.
- Build the debug Runner before the tests. Pass only the test bootstrap
credential to its process.
- Verify scripted-peer shutdown through its lifetime sockets instead of
signaling a saved provider PID.
- Document the command, dependencies, optional prebuilt binary/profile
overrides and verification limits in the Runner README.
- Give the setup hook 30 seconds of margin above the bounded Cargo
build.

## Verification

- Focused test: `pnpm --filter @paperclipai/paperclip-runner exec vitest
run src/control-plane/acpx-controller-recovery.test.ts --maxWorkers=1` —
5 passed.
- Adjacent regression selection: `src/control-plane/`,
`src/live/runnerd-controller-outage.test.ts`, and
`src/live/acpx-request-recovery.test.ts` — 5 files and 195 tests passed.
- Protocol manifest and package ownership checks passed. The standalone
forbidden-import checker reports existing imports in unchanged files;
this PR changes none of those files or the checker.
- `pnpm -r typecheck` and `pnpm build` passed. The full `pnpm test:run`
attempt is retained. Its first database cases failed because the local
macOS PostgreSQL package lacked required dylib aliases. Direct native
probes identified the missing libraries. Local dependency aliases
restored initialization, and one unchanged failing warm-session database
case then passed. The original full-suite attempt was stopped after that
diagnosis. Its failures remain retained; full-suite completion is not
claimed.
- Current-head CI repair: browser shard 5 failed after the task reload
because the result was still behind the conversation loading veil. The
saved snapshots show this state. The UI has a 15-second history reveal
limit, but the result assertion had a 5-second wait. The test now
returns to the task tab and waits for its existing history-content
readiness before it checks the result. `PAPERCLIP_E2E_PORT=38741 pnpm
exec playwright test --config tests/e2e/playwright.config.ts
tests/e2e/connection-reviews.spec.ts --grep 'connection review:
(approve|decline|always|failure),'` passed all four journeys in 2.9
minutes against a fresh local server and database. Master independently
received the same readiness fix in #17923. This branch merged that exact
base version, so the browser file is not part of the final PR diff. The
five ACPX tests passed again after that merge. No production UI code
changed in this PR. The original failed CI report is retained.
- Retained CI failure: the first Linux run rejected the scripted peer's
automatically assigned ports because they can be below the protocol
minimum of 49152. The fixture now binds explicit random ports in the
permitted range, with bounded collision retries. No production
validation was relaxed. The fixed peer also passed a network-isolated
Linux arm64 container check; that check used the actual generated peer
and verified permitted ports and clean EOF shutdown.
- Review follow-up: both native-transport reads require the original
active turn ID with status `inProgress`. Adoption always runs for a
selected prebuilt binary. The crash control accepts only explicit
provider-loss diagnostics, not any snapshot-error wrapper. Focused tests
cover these changes.
- Final review follow-up: the setup hook has a 150-second limit around
the 120-second Cargo build. The README documents both optional
overrides. All five focused tests passed in default mode (17.72 seconds)
and with the prebuilt binary plus profile overrides (10.90 seconds). The
fixture version is explicitly passed through `--runner-version`; it is
not a check against Cargo package metadata. The crash control verifies
the original PID receipt and released lifetime fence ports before it
accepts only known provider-loss diagnostics.
- CI completed successfully for
`d31647fb95f38b7d9d56bc8c13a9a8c0b391d247`, including all eight browser
shards. Final head `949a70596f07042cf7b39a5a3ccb9a9445b6e855` also
passed [all CI
gates](https://github.com/paperclipai/paperclip/actions/runs/40904592159),
including all eight browser shards, and received fresh 5/5 Greptile and
Paperclip reviews. All six review threads are resolved.
- Separate manual provider evidence used real Claude Opus 5.5, ACPX
0.13.1, Claude ACP 0.73.0 and Claude SDK 0.3.286 on macOS arm64. Source
`929e840595c8933ca485ac7a2e99413e1e11ca64` survived 10-second and
300-second controller outages. Original source
`4f8104dec6a0bb37009080daa8984a80f58b7a04` survived a 10-second outage.
The five-minute case retained the original processes and session, made
useful progress, reattached at 303.793 seconds from disconnect, and
completed once. These runs preceded this branch rebase and do not
qualify every change in the rebased server.
- Retained manual failures: the first historical attempt failed
installation admission because scratch dependency symlinks escaped their
root. Correcting that setup allowed the next attempt to start. The
five-minute harness initially checked the final message before
asynchronous projection finished. Saved final-item and terminal events
passed an independent evidence check. The original failed result remains
retained.

## Risks

- This PR adds tests and documentation only. It changes no production
protocol, recovery logic, database schema or browser behavior.
- The automated tests use a scripted ACPX peer. They do not establish
real Claude, PostgreSQL, Daytona or Cloud rollout acceptance.
- The tests require Cargo and a POSIX host. Their waits are bounded.
They stop only their own Runner and scripted peer.
- The earlier hosted provider loss remains unexplained. The separate
real-provider experiments did not reproduce it.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The host does not expose a more specific serving model ID or
context-window size. Anthropic Claude Opus 5.5 (`claude-opus-5-5`)
performed the separate synthetic verification workloads.

## 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-29 10:56:24 -05:00
Nicky LeachandPaperclip 27be859044 Record runtime activity under Runner authority (#18050)
## Thinking Path

> - Paperclip manages agents and tasks.
> - Runner owns each authenticated run and its provider process.
> - Runtime clients need to report successful activity in that run.
> - A retained process can outlive a run, so an operation needs current
authority.
> - This PR captures that authority before the operation and records
activity afterward.
> - Core can consume the event through the existing run stream.

## Linked Issues or Issue Description

Builds on merged #18129 and targets master. The dependent consumer is
#18131.
Test stability fixes were separated into merged #18128. Earlier
combined-head
verification remains in [the
archive](https://github.com/paperclipai/paperclip/pull/18050#issuecomment-6489369676).

**Subsystem affected**

Runner activity recording and provider command environments.

**Problem or motivation**

A retained provider process can complete an operation after its original
run ends.
Runtime clients need a host-attributed event and a helper that works
inside the
provider sandbox.

**Proposed solution**

Capture opaque Runner context before use. Publish a structured
notification after
success. Runner checks current authority and records
`runtime.activity.recorded`.

## What Changed

- Add `notification-context` and `record-activity CONTEXT NAMESPACE
ACTIVITY_KEY`.
Rotate context on warm attachment and process recovery. Accept no caller
run ID.
- Use one private named pipe. Reuse Runner's bounded JSON-line reader.
Serialize
concurrent publishers with a read-only lock. A blocking reader queues at
most
  128 records; the existing control loop handles at most 16 per pass.
- Grant Codex access to the exact helper, descriptor, lock and pipe.
Preserve
other filesystem and network limits. Preserve host discovery values
through
provider launch boundaries and reject configured-environment overrides.
- Update source identities to Pi 34, Copilot 81 and Grok 12. Keep
historical
  identity fixtures and recovery behavior.

## Verification

- Targeted release notification and sandbox-policy tests: seven passed.
They cover
run rotation, recovery, Unicode limits, concurrent writers, malformed
and partial
  records, bounded queues, failed persistence and fixed-path cleanup.
- Real CLI integration and pinned Codex 0.160.0 sandbox checks: passed.
The sandbox check uses no model, credential or network call. It verifies
activity
recording while unrelated state reads and parent-directory writes remain
denied.
- ACPX profile generator check, formatting and diff checks: passed.
- Rebased onto master `31b927e30` at head `64d0248a8`. Master used the
same profile versions, so the resolution preserves its Pi 33, Copilot 79
and Grok 11 fixtures byte-for-byte and creates new identities. All
identity checks pass. Five targeted provider/environment/recovery files
pass 168 tests with one existing skip; the Rust Pi admission regression
passes. The notification module and Codex sandbox implementation are
byte-identical to the tested pipe head `671373fe0`.
- Removed the mailbox traversal reported by security review. Its
regression replaces
the pipe path with a 100-level tree and an unreadable leaf. Shutdown
preserves the
leaf, performs no traversal and completes promptly, including with a
partial record.
- An initial targeted test failed because its run-rotation fixture
updated config
without updating durable state. The corrected fixture passes. Runner
also rejects
  inconsistent run bindings.
- Previous head `26abbf62b` passed Runner, build and browser CI. Server
shard 11/12
failed in unchanged `attention-service.test.ts`: cleanup/test timeouts
were followed
by a duplicate `ATQ` fixture key. The final head needs fresh CI and
review.
- CI on `64d0248a8` completed with 52 successful checks and four
intentional skips. Runner Vitest shard 1/2 failed when retained-state
copies encountered the live FIFO; the aggregate also failed. Standard
review scored 4/5 and found relative pipe paths plus late context
publication. Follow-up `5c3f14d32` places IPC in a private canonical
temporary directory and publishes context before welcome commands. Its
relative-state CLI test, two authenticated reconnect cases, seven
notification/policy cases and real Codex sandbox pass. One affected
retained-settlement case passes with the matching release binary; the
other 18 cases remain for CI. The sandbox denies sibling-directory and
lock writes. All build, test and security checks pass on `5c3f14d32`;
standard review is 5/5 with no unresolved threads. The requested Apex
review is 5/5 on this exact head, with no findings or unresolved
threads.
- Earlier broad test results in the archive apply to their recorded
source revisions.
Per the requested workflow, final local checks stay targeted; GitHub CI
supplies
  broad coverage.

- After Apex completed, master advanced again and conflicted on Copilot
identity. Head `e94a9359d` is rebased on master `8ac5a128e`; it
preserves the published Copilot 80 fixture and uses Copilot 81. The
notification module, Codex sandbox and durable control-loop code are
byte-identical to Apex-reviewed `5c3f14d32`. All 131 targeted
installation/compatibility/recovery cases and identity generator checks
pass. All 55 checks pass with four intentional skips on the rebased
head. Standard review is 5/5 with no unresolved threads. Apex is 5/5 on
`e94a9359d`, with zero findings and no unresolved threads. GitHub
confirms this head is conflict-free and ready for review.

## Risks

Activity remains an optional hint and grants no access. A successful
helper exit
means publication to the pipe; Runner persists accepted events through
its existing
durable outbox. Full queues, unavailable helpers or failed writes can
drop a hint
without failing the operation. Context reads are local and do not wait
for the
control loop. Publishers have a 500 ms lock deadline and a 2 KiB record
limit.
IPC lives outside durable state. Idle transport blocks; cleanup removes
its fixed files and empty private directory. The host must provide
`/usr/bin/mkfifo`. Rebuild matching Runner/provider artifacts for the
updated source
identities. No dependency, migration, live provider call or deployment
is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools and code
execution.
The exact serving snapshot is not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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-29 07:40:50 -07:00
DottaandPaperclip b81b870732 Add QA smoke journeys and OpenCode run traces (#18098)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Product E2E journeys verify saved application behavior across
deployments.
> - Task creation and questions need reusable smoke selections and exact
run attribution.
> - Operators also need to inspect the OpenCode execution behind a
measured question.
> - Company observability does not currently support native OpenCode.
> - This change adds the journeys and a bounded projection of normalized
OpenCode run events.
> - The projection follows the configured capture policy and retains the
current run identity across warm reuse.

## Linked Issues or Issue Description

Related foundation: #17262. Related alternative: #17989 exports metadata
from OpenCode's native OTLP stream. This change uses normalized run
events to support the existing content switches and per-run linkage. It
does not forward the native stream. The two PRs overlap in launch
registration and must be reconciled before both land.

**What existing behavior does this improve?**

Reusable Product E2E smoke selections and company observability for
native OpenCode.

**Current behavior**

The journey catalog lacks reusable task creation and attached-agent
question checks. Native OpenCode is marked unsupported for company
observability, so a successful destination connection test does not
prove that agent traces will appear.

**Proposed behavior**

Add explicit task-create and ask-question selections. Verify saved state
and exact company, issue, agent, model, environment and successful run
attribution. Export normalized OpenCode turns, tools and usage to the
configured OTLP destination. Honor each capture switch and redact known
secrets.

**Reason and benefit**

CI can run a small measured smoke selection, retain its screenshots and
checks, and link results to traces belonging to the same run.

**Breaking changes**

Existing selectors remain unchanged. OpenCode export is opt-in through
existing company settings. Legacy OpenCode stays unsupported.

## What Changed

- Add reusable task creation and question journeys, configured-agent
capability, owned-fixture checkpoints and strict evidence validation.
- Add an OpenCode-owned projection of normalized run events. No provider
SDK or raw payload schema enters heartbeat coordination.
- Extend the private launch union and reserved environment allowlist for
native OpenCode. With export disabled, no receiver request runs.
- Keep destination headers in the parent wrapper and out of the actual
provider child environment and configuration.
- Bound each turn to 64 tool and 64 usage entries, 8 KiB per text field
and a 1 MiB request. Use a three-second request deadline, four
concurrent exports, and no retries or idle worker.
- Pass the rotated runner authority to each proxy turn. A retained
process no longer attributes later turns to its original launch run.
- Update settings copy, observability documentation and capability maps.

## Verification

- `pnpm -r typecheck` and `pnpm build` passed after the implementation
changes.
- Adapter launch/redaction: 9 tests passed. Projection and actual proxy:
12 tests passed before the review fix; the expanded projection suite
passed all 12 cases after the fix. The proxy test exercises two runs in
one process against a real local HTTP receiver and a fake provider.
- Full OpenCode driver/projection suite: 72 passed, one existing
response_wake test timed out at five seconds. A focused check then
passed both existing omitted-continuation cases and the new trace export
case. The timeout cause remains unconfirmed.
- Runner package TypeScript and Rust `cargo check` passed. Map and UI
token checks passed.
- Prior journey validation: 273 tests across 12 files and the journey
TypeScript check passed.
- Broad local `pnpm test:run` encountered native-runtime integration
failures with repeated embedded PostgreSQL initialization failures and
was stopped. All 16 failing cases passed in an isolated run outside the
filesystem sandbox (961 unrelated cases unselected). The broad local run
is not a clean acceptance result. A later focused database-backed
chat/heartbeat run passed all six selected observability cases,
including native OpenCode launch and successful allocation (1,809
unrelated cases were unselected).
- All CI gates passed for `21085f880d8babc9efeb22d0623db99613d33093`,
including packaged-runner, clean-install, browser and build checks:
https://github.com/paperclipai/paperclip/actions/runs/40884658995 .
Greptile reviewed the same commit at 5/5 with no unresolved findings.
- Verified OTLP JSON acceptance and indexing with an explicitly
synthetic transport marker. No live OpenCode model trace or deployed
smoke acceptance is claimed yet.

## Risks

Export is best effort. Abrupt termination, recovered in-flight turns
without a new submitted event, limits or receiver failure can lose
traces. Export failure does not change task success. The projection
represents observed normalized events, not raw native model spans or
hidden reasoning. Known-secret redaction is not an OS isolation
boundary. UI changes can break journey locators. Deployment adapters
retain credential, ownership and cleanup responsibility. Both the
controller and native runner bundle must be updated before live
qualification.

## Model Used

OpenAI Codex, GPT-6, with reasoning, code execution and browser tools.
The exact serving model ID and context size 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 (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (targeted suites; broad
local limitation documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 08:57:12 -05:00
4c56702e06 fix(server): schedule retained native-session cleanup (#17717)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs can retain a local session after an interrupted durable
suspend.
> - The orphan reaper repeatedly scans completed history for that
cleanup duty.
> - Idle scans keep the database active. Removing them requires complete
wake and ownership paths.
> - This pull request moves retained-session cleanup to committed
signals, local release events and saved deadlines.
> - Existing physical proof checks still decide whether cleanup is safe.
The shared scheduler does not grant execution authority.
> - The benefit is quiet retained history with recoverable cleanup and
owned shutdown.

## Linked Issues or Issue Description

Refs #17709 and #18135. This is slice 51 of the existing
recurring-server sleep stack. Both referenced dependencies have merged.
The target is `master`.

**What happened?**

The periodic orphan pass scans retained native sessions even after their
cleanup is complete or no automatic action is safe. Some eligible
sessions also depend on a local session, environment lease or original
maintenance callback releasing ownership. An earlier decision
notification can be consumed before the run's later terminal projection
commits.

**Expected behavior**

Reconstruct existing work at startup. Wake from committed writes and
actual owner release. Register the saved claim expiry or a probe for a
specific live process. Stop recurring discovery when no obligation
remains. Preserve original callback ownership and all existing cleanup
proof checks.

**Steps to reproduce**

1. Retain completed native runs with a durable-suspend close failure.
2. Let the periodic orphan pass run with no new work.
3. Observe repeated cleanup discovery. Separately, delay terminal
projection after its decision notification is consumed and observe the
missing cleanup wake.

**Paperclip version or commit**

Parent #17709 at reviewed head
`3b75f4bc1da1370304f069fc287af3d693575716`, landed as
`df6156c2e37f542a69f393dde31e357b82b7cac1`. Current integrated master:
`31b927e3013a8a4b3266854b740cf40a24753788`.

## What Changed

- Move scoped, paged discovery to the retained cleanup owner. Preserve
explicit manual recovery.
- Register the duty with the shared scheduler and remove it from the
periodic orphan pass. Keep concrete lease expiry and live-process probe
obligations.
- Use typed outcomes for settled/refused work and process, session,
environment, maintenance or lease waits. Keep physical proof and
quarantine decisions in the executor.
- Wake from committed finalization and terminal projection writes,
durable process/lease release, and local session or callback settlement.
Routine company-only finalization hints leave dormant cleanup quiet.
- Join duplicate cleanup and serialize inspections on one database lane.
Keep original Runner callbacks owned until settlement and shutdown.
- Preserve all master profile fixtures and the branch's historical
identities. Save the colliding sleep profile 79 separately. Generate
combined Copilot profile 80 from its source and retain master's other
provider profiles.
- Add the owner audit and regression coverage. No new table, migration
or independent maintenance timer is added.

## Verification

- Server acceptance: **2,342 distinct passing cases in 18 complete
files**. The 14-file unaffected group contributes 1,532 passes. Full
startup contributes 76, process recovery 410, environment service 51,
and external-chat response 273. The 29-case cleanup worker suite and
977-case executor suite run in full. No case in these files is skipped.
- Controlled scope regression: removing only the ordinary finalization
issue/run guard wakes dormant retained cleanup; the same assertion
passes after restoring it. A real local owner release still resumes the
durable candidate.
- Preserve the first broad failure: 1,607 passed and one startup
shutdown case failed because the coordinator mock lacked `stop()`. Add
only that mock method. All 76 unchanged startup cases then pass. Do not
treat the first broad command as green.
- Dedicated PostgreSQL 17 databases use the existing migration 413
schema. Embedded-only fixtures use the existing recovery helper with
fresh per-call databases. All temporary imports are restored byte-exact.
No assertion or timeout is relaxed.
- Current-master integration preserves both complete source histories.
The server, UI and database trees are identical to the server-tested
source. All master historical profile fixtures remain byte-exact. The
prepared sleep profile 79 remains independently inspectable.
- Current runtime validation at
`d08f764e3efe75e96929173afe7ee8739121ad9f` passes all 12 commands (22
installed ACPX/Grok contract cases and 26 native-provider Rust cases):
`pnpm install --frozen-lockfile --ignore-scripts`; Copilot/Grok identity
and generated profile checks; Runner and server typechecking; server
build; Copilot/Pi installation, profile compatibility and transport
settlement files (130 passed; one opt-in closed Pi snapshot case skipped
because its distribution root is not configured); installed ACPX
model/reconnect package contract and Grok identity tests; Rust
native-provider backend tests; module boundaries and migration order.
- Earlier 94-case installation/settlement acceptance applies to the
prepared profile 79 source. It is retained as history and does not
substitute for the current profile 80 validation above.
- Failure history and duty-specific evidence remain in
`doc/plans/2026-10-26-retained-native-session-cleanup-sleep-audit.md`.
Exact-current-head acceptance: all 60 checks are clean, including
protected CI and security; Greptile gives 5/5 for
`281d579de0d08e907194b8b790a0597b07d16b7b` with no actionable findings.
No Ponytail review is present under the authorized missing-review
policy.
- These checks do not claim a full local repository suite, live Copilot
or Daytona qualification, deployed host/database suspension, or measured
cost savings.

## Risks

- Missing a supported producer could strand cleanup. Tests exercise real
finalizer, heartbeat, environment and process writers. Process-local
signals cover in-process writers; no multi-replica or external SQL
notification transport is added.
- A timeout can leave an original callback active. Cleanup and shutdown
must keep waiting for it. The existing global maintenance drain is
conservative across roots.
- A retained live process still has a scoped 30-second absence probe. A
saved lease keeps its actual deadline. Operational errors retain retry
work. Immutable proof refusals and operator-required histories do not
gain automatic retry authority.
- Cleanup keeps all existing artifact, identity, claim, no-launch and
quarantine checks. Terminal status alone does not authorize physical
cleanup.
- This PR does not expand Cloud alarm coverage or relax host sleep
eligibility. It proves worker behavior, not deployed app/database
suspension.
- The Copilot source identity has changed; these checks do not claim new
live provider qualification.
- The parent has merged. This PR is merged only after its current-head
protected CI and review gates pass under the existing campaign
authorization.

## Model Used

OpenAI Codex, GPT-6 family, with code execution and repository 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>
Co-authored-by: Codex <noreply@openai.com>
2026-10-29 04:24:57 -05:00
Nicky LeachandPaperclip aa75ec9d56 Replay Claude native options on ACP reconnect (#18135)
## Thinking Path

> - Paperclip manages agents and their task execution.
> - Runner uses ACPX to connect to Claude sessions.
> - Claude receives native options when ACPX creates a session.
> - ACPX omits those options when it loads or resumes the same session.
> - A reconnect can lose allowed tools, instructions, and settings
sources.
> - This pull request replays the existing options through the existing
Claude metadata contract.
> - Resumed tasks keep the configuration admitted for their session.

## Linked Issues or Issue Description

**What happened?**
A Claude task can complete its first turn and then fail on a warm
follow-up. The provider refuses an internal completion tool because
`session/load` omits the `allowedTools` options sent with `session/new`.
The same omission exists on `session/resume`.

**Expected behavior**
Creation, load, and resume must supply the same caller-selected native
session options. The existing policy for native user settings must stay
unchanged.

**Steps to reproduce**
Create a persistent Claude ACP session with an explicit allowed-tool
list and appended instructions. Complete a turn, close its connection,
and reconnect to the saved session. Inspect the ACP request. Before this
change, the reconnect has no `_meta` field.

**Paperclip version or commit**
Reproduced on Runner source `e8b78cce5bb557b086bee9ca930eeaab1d09b244`.
The offline protocol regression also fails on the current base
`80a2b9284bf189e93ca4313085814548f48b8dc8`.

Related: #18089 added prepared harness storage. #11798 concerns the
separate legacy adapter and does not fix Runner reconnect metadata.

## Upstream status and backport scope

ACPX [0.21.1](https://github.com/openclaw/acpx/releases/tag/v0.21.1)
already replays session metadata on load and resume in its [released
client
implementation](https://github.com/openclaw/acpx/blob/v0.21.1/src/acp/client.ts).
This PR backports that behavior to the currently qualified 0.13.1
integration.

The released 0.21.1 runtime does not expose equivalents for all hooks
used by Runner's existing patch: verified executable spawning,
synchronous protocol admission guards, provider extension dispatch, and
response-delivery receipts. Upgrading requires a compatibility pass that
preserves these guarantees and removes local changes already covered
upstream. This backport does not add a new Paperclip-specific dependency
contract.

## What Changed

- Replay existing Claude native options on `session/load` and
`session/resume` through the same metadata builder used at creation.
Other providers keep their existing reconnect requests.
- Test both reconnect methods against the installed ACPX manager and a
local ACP wire fixture. Cover allowed tools, model, turn limit,
instructions, and both existing settings-source modes.
- Update exact source attestations and generated profile declarations
required by the shared ACPX patch. Keep historical fixtures unchanged.
- Document the reconnect contract. No new home mode, plugin policy, or
provider permission rule is added.

## Verification

- Confirmed the new load and resume tests fail before the patch because
metadata is absent.
- Applied the canonical patch to pristine package bytes and confirmed it
matches the tested runtime.
- Targeted installed-package model-selection and reconnect suite plus
changed Grok identity tests: 22 passed.
- Rechecked the four new reconnect cases against the cleanly applied
patch, with explicit expected values for all supplied options.
- Three targeted current-profile and revision-boundary assertions pass
locally. Updated the native Pi test digest; native compilation and
execution remain in CI.
- Maintained profile generators pass their consistency checks.
- GitHub CI is green, including typecheck, native Runner checks, package
contracts, packaged installation, build, and server/browser suites. One
unrelated server database-cleanup timeout passed on the bounded
failed-job rerun. No comprehensive local suite was run. Live
post-deployment acceptance remains pending.

## Risks

Claude reconnects now receive the same native settings sources and
options as creation. This corrects configuration loss without changing
caller policy. The shared dependency patch requires new source
identities for other attested profiles; their reconnect behavior is
unchanged. No database migration is required.

## Model Used

OpenAI Codex, GPT-6 family, with code and tool use. Exact deployment ID
and context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 01:45:18 -07:00
Nicky LeachandPaperclip 80a2b9284b Define durable runtime activity events (#18129)
## Thinking Path

> - Paperclip manages agents and tasks.
> - Runner reports durable run events through PRP.
> - Runtime clients need a typed record of reported activity.
> - The event must keep the normal run authority and read boundaries.
> - This pull request adds the generic runtime activity event contract.
> - Later PRs can publish and consume this contract without private
plugin coupling.

## Linked Issues or Issue Description

First feature prerequisite extracted from #18050. Runner publishing is
#18050; the dependent consumer is #18131. Related independent test
stability work: #18128. The parent search and review history is
preserved in [the verification
archive](https://github.com/paperclipai/paperclip/pull/18050#issuecomment-6489369676).

**Subsystem affected**

Runner event protocol, server run-event persistence and redaction, and
UI event taxonomy.

**Problem or motivation**

Core needs a durable, typed activity record tied to the authenticated
run. A text marker is not an event contract.

**Proposed solution**

Add `runtime.activity.recorded` as a P1 event with a closed `{
namespace, activityKey }` payload. Runner knows no plugin or panel
identity. Run/session identity, sequence and emission time stay in the
outer envelope; Core resolves company, task and agent through the
authorized run binding. Use the existing authenticated persistence,
acknowledgement, replay and redaction paths.

## What Changed

- Define and validate the event in PRP v1, v2 and v3. Update the
generated protocol artifacts and event catalog.
- Preserve saved and live event redaction. Test persistence, replay
deduplication and the existing run-read boundary.
- Register the event in the UI taxonomy without changing panel display
behavior.
- Advance the source-bound Copilot identity to 78. Retain all published
historical identity fixtures without changing their bytes.

## Verification

- Root `pnpm typecheck` and `pnpm build`: passed for the revised
activity contract.
- Node protocol checks: 14 passed. Provider identity and registry tests:
185 passed. Server tests: 103 passed. UI event registry: five passed.
- Maintained Grok and Copilot identity generator checks and `git diff
--check`: passed.
- The first activity-contract review scored 4/5 because the dependent
producer and readers still used the earlier contract. Both dependent PRs
are now updated and restacked; the finding is resolved and review is
running again.
- Initial extraction retained a consumer-only import in one server
suite. That suite failed to load. The consumer case and import were
moved out; the final three server files passed all 103 cases.
- Earlier panel-specific head `6137c50bc` had green CI and standard/Apex
5/5. Those scores do not qualify this revised activity contract. Fresh
CI and reviews are pending. Earlier combined results in the archive
apply only to their recorded source revisions.

## Risks

This change is additive. It adds no route, publisher, filesystem
transport, provider sandbox grant, or panel display behavior. Activation
hints grant no permission to read a plugin view. Provider identities
bind the changed protocol source; historical identities remain
decode-only. No schema migration or dependency change is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools and code
execution. The exact serving snapshot is not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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-29 00:32:12 -07:00
Devin FoleyandClaude Opus 5.5 522c653d56 fix(runner): retry stalled Pi Node archive downloads (#18126)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/230/changes/paperclip/230
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The master Docker image contains a runner provider pack, and the
pack contains the Pi agent runtime
> - The Pi materializer downloads a hash-pinned Node archive from
nodejs.org during the image build
> - That download has one 60 s timeout and no retry, so one stalled
transfer stops the full amd64 image build
> - Master Docker builds failed this way two times in two days, and the
failure did not identify the request
> - This pull request retries only transport failures of that download
and keeps every security gate
> - The benefit is fewer red master image builds from short nodejs.org
stalls, and a clear error when all attempts fail

## Linked Issues or Issue Description

No public issue exists. This is a bug report.

**What happened?**
The `Docker` workflow on `master` failed in the `build-and-push
(linux/amd64)` job at `Dockerfile:163` (`runner-provider-pack`).
`build-provider-pack.mjs` stopped with an uncaught `DOMException
[TimeoutError]: The operation was aborted due to timeout`. The arm64 job
of the same commit passed. The next master build passed without a code
change.
- https://github.com/paperclipai/paperclip/actions/runs/40686298026
(2026-10-28)
- https://github.com/paperclipai/paperclip/actions/runs/40808852599
(2026-10-29)

**Steps to reproduce**
1. Run `node
packages/paperclip-runner/scripts/materialize-pi-distribution.mjs
/tmp/pi-out` on linux-x64.
2. Make the transfer from nodejs.org stall for more than 60 s.
3. The script stops at once with an anonymous `TimeoutError`.

**Expected behavior**
A short network stall does not stop the build. If all attempts fail, the
error identifies the Pi Node download.

**Evidence**
In both failed jobs, the uncaught timeout came about 60 s after the last
provider-pack output line (61.18 s → 121.6 s, and 38.72 s → 99.15 s).
The Pi Node archive fetch is the only provider download with a 60 s
timeout. The Cursor and Copilot downloads use 120–180 s.

## What Changed

- `materialize-pi-distribution.mjs`: add `downloadPinnedPiNodeArchive`.
It tries the download up to 3 times. Each attempt has a new 60 s
timeout. The timeout covers the headers and the full body. The backoff
is 5 s, then 10 s.
- Only transport failures cause a retry: timeout, network `TypeError`,
HTTP 5xx and HTTP 429.
- These failures stop at once, with no retry: SHA-256 pin mismatch, the
128 MiB size bound, HTTP 4xx, a missing body, and cancellation. The
SHA-256 pin still checks every byte.
- The body of each rejected (non-2xx) response is canceled before the
next attempt, so a 5xx/429 reply does not hold its connection.
- Each failed attempt writes a warning to the build log, so a later
successful retry does not hide the failure. When all attempts fail, the
error is `Pinned Pi Node download failed after 3 attempts: <cause>`.
- `materialize-pi-distribution.test.mjs`: add tests for stalled headers
and a stalled body that end only when the per-attempt deadline signal
aborts, release of rejected responses before the next attempt, exhausted
attempts, HTTP 503, and the fail-closed cases.
- `package.json`: add `scripts/materialize-pi-distribution.test.mjs` to
the `test:typescript:prep` node:test list. Before this change, no CI
lane ran this test file.

## Verification

- `node --test
packages/paperclip-runner/scripts/materialize-pi-distribution.test.mjs`
→ 13 pass, 0 fail.
- Red checks: with the old materializer, the new tests fail. When the
body cancel is removed, the release test fails. When the deadline signal
is removed from the fetch call, the deadline tests fail.
- `cd packages/paperclip-runner && node
../../scripts/ci-profile/node-test.mjs
scripts/candidate-provider-pack.test.mjs
scripts/materialize-pi-distribution.test.mjs` → 20 pass, 0 fail.
- `node --check` passes on the changed script.
- I did not run the full `pnpm -r typecheck`, `pnpm test:run`, or `pnpm
build` locally, because the sandbox has no installed workspace
dependencies. The changed files are `.mjs` scripts and are not in the
runner `tsconfig.json`. CI runs the full checks.
- A reviewer can read the `Build and push by digest` log of the next
master Docker run. A transient stall now shows `Pinned Pi Node download
attempt 1/3 failed: ...; retrying`.

## Risks

- Low risk. The change affects only the Pi Node archive download. Two
callers use it: the Docker provider-pack build
(`candidate-provider-pack.mjs`) and `paperclipai runtime setup pi`
(`provision-pi.mjs`).
- The worst-case time before failure increases from 60 s to about 195 s
(3 × 60 s + 15 s of backoff). The Docker job has more time than this.
`provision-pi.mjs` has a 900 s setup deadline that it enforces through
`checkCancelled`. The download calls `checkCancelled` before each
attempt, so the deadline and SIGINT/SIGTERM still stop setup. A cancel
can wait for one backoff of at most 10 s.
- For `runtime setup pi`, a stall now prints one warning line on stderr
for each failed attempt. Normal operation prints nothing new.
- The retry does not weaken integrity. The same SHA-256 pin, size bound,
and `redirect: "error"` apply to each attempt. A mismatch does not cause
a retry.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with
tool use (shell, file edit, GitHub connector). It read the failed CI
logs, wrote the change and tests, and ran the tests locally.

## 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>
2026-10-28 22:31:36 -07:00
scotttongandPaperclip 71f0c0c99e feat: add opt-in Coordinator workspace for chat, tasks, and decisions (#17983)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/147/changes/paperclip/147
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People coordinate work through conversations, tasks, and requests
for input.
> - These surfaces must share task state and preserve the context of
each decision.
> - The existing workspace makes people switch surfaces to follow that
context.
> - This pull request adds an optional Coordinator workspace with linked
conversations, tasks, documents, and decisions.
> - Each person can enable it in Settings > Experimental and return to
the classic workspace.
> - The benefit is a coherent path from a request to an assigned task
and reviewed work.

## Linked Issues or Issue Description

**Subsystem affected**
UI, server, shared contracts, and database.

**Problem or motivation**
People need a consistent way to start tasks from agent conversations,
answer questions, review work, and return to the source context.
Decisions and task state must agree across these surfaces.

**Proposed solution**
Add a personal, default-off workspace experiment. Keep one conversation
per agent. Add task proposals, compact task and decision cards,
contextual document panels, and a Needs You queue with search, filters,
sorting, grouping, and history.

**Alternatives considered**
Replacing the classic workspace for everyone would remove the opt-out
path. Keeping separate decision state in each surface would create
conflicting answers. This change uses the existing canonical task and
interaction records instead.

**Roadmap alignment**
This supports the existing agent chat, task management, and human review
capabilities. It is an experimental presentation choice. The user
requested this isolated implementation after design review. No Discord
discussion is claimed.

## What Changed

- Add per-person workspace preferences, a default-off setting, and an
additive migration.
- Add Coordinator navigation, pinned destinations, task lists, agent
switching, and contextual panels.
- Link task suggestions and creation to the source conversation. Default
new task ownership to the current agent unless the user specifies
another owner.
- Share pending questions, decision receipts, exact review targets, and
history across tasks, chat, and Needs You.
- Preserve task access, assignment authorization, revision binding, and
required output review gates.
- Add compact document links, relative timestamps, composer controls,
and reduced-motion support for task and decision transitions.
- Add component stories, regression coverage, and capability-map
documentation.

## Verification

- Final head: `4b839aae1e314bd7e8635a766f1d205ff1c03ba6`, based on
master `8bc051245f77a47bee0f8ba45896b8bfa5922e0a`. Verified October 29,
2026 at 00:10 UTC: **MERGEABLE, 56 checks passed, four conditional
skips, no pending or failed checks**. [Current CI
run](https://github.com/paperclipai/paperclip/actions/runs/40790639688)
passed without a rerun on this head.
- Fresh Greptile **5/5**, zero new comments and zero open review
threads; Superagent passed with no suspicious changes.
[Checks](https://github.com/paperclipai/paperclip/pull/17983/checks).
- Local workspace typecheck/build passed after the latest rebase. The
final account-read patch passed UI typecheck/build and all 12 related
preference/settings tests, including a delayed real-client request
across account changes. Earlier scoped checks cover review
deduplication/replay, decision deep links, cross-surface state, access
boundaries, and migration replay.
- Local database/browser rechecks after the latest rebase were limited
by exhausted macOS shared-memory IDs: `initdb` failed before database
creation. The local run passed 31 UI/snapshot tests and skipped 24
database tests; those skips and the blocked local browser start are not
claimed as passes. The independent Linux CI database and browser checks
passed. No running dev database or host setting was changed.
- Upstream migration 0403 is preserved. Preferences and durable review
retry aliases are generated as replay-safe migrations
`0404_tense_silver_sable.sql` and `0405_harsh_avengers.sql`; five newest
snapshots are retained. Every detected conflict was rebased and pushed
before waiting for CI/review, as requested.
- The PR is unmerged. The active master ruleset still requires
code-owner approval for the changed Paperclip skill; no approval or rule
change was performed.

<details>
<summary>Earlier verification failures, integration history, and
evidence</summary>

These entries preserve prior checkpoints and failures; the current
acceptance result is above.

- Focused UI and server checks from the isolated build are recorded in
the implementation plan.
- Browser checks covered the opt-in shell, navigation, task/document
links, and decision card states. No new live provider trial is claimed
for this handoff.
- Current acceptance head: `4b839aae1e314bd7e8635a766f1d205ff1c03ba6`,
rebased onto master `8bc051245` immediately after its GitHub
review-repair migration took 0403. Preferences are generated as
idempotent `0404_tense_silver_sable.sql`, preserving upstream
SQL/journal/snapshot history and five newest snapshots. GitHub reports
MERGEABLE after the immediate lease-protected push. Scott's updated
instruction is to rebase and push every conflict resolution first,
without waiting for CI or Greptile; verification follows the push.
- The final reviewed feature tree was consolidated for repeatable
single-commit rebases. The complete previous commit history remains
reachable through local recovery ref
`codex/coordinator-recovery-before-rebase-20261028` (resolved snapshot
`0e1bbdf4e`). The actual rebase completed, and its tree hash exactly
matches that resolved snapshot. The force-with-lease required the known
remote head `0e6ef7c44`, protecting against concurrent branch changes.
No PR merge or permission/runner setting change occurred. Fresh
CI/review are in progress for the current head.
- `2001132fa` received Greptile 5/5 with one nonblocking account-switch
read finding. Current head detaches path-coalesced preference GETs and
disables HTTP caching, retaining React Query's account-scoped sharing. A
delayed real-client GET regression proves account B can load its saved
choice before account A responds, and A's late response only updates A's
cache. Preference/settings tests 12/12 and UI typecheck passed; its
review thread is resolved. Fresh current-head CI/reviews are pending.
The prior CI chat shard 3 ended with “The operation was canceled” and no
assertion failure ([job
123171595631](https://github.com/paperclipai/paperclip/actions/runs/40789688333/job/123171595631),
`/tmp/pr17983-2001132-chat3.log`); no code/timeout change is attributed
to that cancellation.
- `843e823b4` reached fresh Greptile 5/5 with zero comments/open threads
and Superagent pass. All browser tests including the repaired YAML shard
passed, and 54 checks passed. General server shard 9 ended with “The
operation was canceled” and no failed assertion; its test step was
marked cancelled (job
[123164350893](https://github.com/paperclipai/paperclip/actions/runs/40787501761/job/123164350893),
log `/tmp/pr17983-843e-server9.log`). A single unchanged-head rerun was
started after the workflow completed, but master moved while it ran. A
local nested-clone check timed out in its 30-second database-startup
hook and then failed cleanup before the 20 database cases ran; this is
retained as a local verification limit
(`/tmp/pr17983-843e-nested-clone-check.log`), not claimed as a pass or
proof of the CI cancellation cause.
- Following Scott's instruction, the new conflict was rebased and pushed
immediately without waiting for that rerun. Upstream's
`0403_natural_cerise.sql` is preserved; regenerated preferences and
retry-alias migrations are `0404_tense_silver_sable.sql` and
`0405_harsh_avengers.sql`, replay-safe with five newest snapshots
retained. The YAML helper conflict combines upstream's click and header
behavior with the editor-selection guard and injected regression.
Recovery ref `codex/coordinator-recovery-843e823b4` preserves pre-rebase
work. Current head is MERGEABLE. Full workspace typecheck/build passed;
UI and snapshot checks passed 31 tests, but 24 database tests were
skipped by the local support probe, and the local browser server could
not initialize PostgreSQL. A direct disposable `initdb` diagnostic
established the host limitation: `could not create shared memory
segment: No space left on device` (`shmget`, shared-memory IDs
exhausted, not disk space). No dev database or host setting was changed.
Diagnostics: `/tmp/pr17983-2001132-initdb-probe.log`,
`/tmp/pr17983-2001132-db-probe.log`; checks:
`/tmp/pr17983-2001132-tests.log`, `/tmp/pr17983-2001132-browser.log`,
`/tmp/pr17983-2001132-types.log`, `/tmp/pr17983-2001132-build.log`.
These local skipped/blocked checks are not claimed as passes; fresh CI
on independent runners is in progress.
- `d18f683cd` reached fresh Greptile 5/5 with zero comments/open threads
and Superagent pass, but [E2E shard
7](https://github.com/paperclipai/paperclip/actions/runs/40785966243/job/123159719925)
failed parsing an Advanced YAML clipboard read beginning with “Skip to
Main Content.” The log is retained at `/tmp/pr17983-d18f-e2e7.log`.
Current head hardens the test helper to verify editor focus and
selection, clear stale clipboard content, and require the YAML header at
the start of a fresh copy before parsing. Saved-state assertions and
timeouts are unchanged. All six Advanced YAML browser journeys passed on
a disposable local instance (41.0s); the exact lost-response journey
also passed with a one-time injected surrounding-page copy, verifying
rejection/reacquisition (17.6s). The precise browser focus/clipboard
timing in CI remains unproven; the observed invalid-read path is now
guarded and deterministically exercised. Logs:
`/tmp/pr17983-yaml-clipboard-scope-browser.log`,
`/tmp/pr17983-yaml-clipboard-injected-browser.log`. Fresh current-head
CI and reviews are pending.
- `19e6dcb0b` passed Superagent and Greptile 5/5, with one nonblocking
deep-link finding. Current head preserves attention links using
`?decisionId=`: the requested pending decision is rendered even beyond
the first 40 cards, focused and scrolled into view, then only that
parameter is consumed so later refreshes do not refocus. Other URL
parameters remain. Needs You tests 10/10 and UI typecheck passed; its
review thread is resolved. The preceding post-rebase regression run
passed 45/45 tests. Fresh current-head CI/reviews are pending.
- `6d772b7cc` reached Greptile 5/5 with zero comments/open threads and
Superagent pass. While 32 checks had passed, master moved and caused a
documentation conflict in `maps/feature-map/onboarding.md`. Rebased
immediately, preserving both onboarding paragraphs. The complete
four-commit branch was pushed as `19e6dcb0b` before waiting on
CI/review, per Scott's instruction. A transient Git index lock
interrupted the first continue; the command sequence briefly pushed
intermediate `34e298c07`, then the completed rebase was immediately
pushed. All feature and security/retry fixes are present; local recovery
ref `codex/coordinator-recovery-6d772b7cc` preserves the pre-rebase
history. The only tree differences from that ref are upstream's two
smoke-test files and the combined documentation paragraph. GitHub
reports MERGEABLE. Fresh current-head verification is in progress;
prior-head review results are not current acceptance.
- `21efa3120` passed Superagent but Greptile scored 4/5 for a valid
retry-key persistence bug: an acknowledged duplicate key could reopen a
resolved review. Current head adds an additive, replay-safe
`0404_light_swarm.sql` migration for indexed, task-scoped aliases from
acknowledged retry keys to the canonical interaction. Alias registration
and retry lookup occur under the existing task lock; payload/actor
mismatch still conflicts, and each canonical review permits at most 100
aliases. Original and acknowledged keys replay the terminal result
rather than creating a new gate. Five newest migration snapshots are
retained. Service/routes tests 165/165 passed; final quality review plus
migration replay/snapshot checks 25/25 passed; server typecheck passed.
The P1 thread is resolved in code; fresh current-head reviews and CI are
pending.
- `69c2c7543` passed 55 checks and Greptile 5/5 with no open Greptile
findings, but Superagent check
[123140675812](https://github.com/paperclipai/paperclip/pull/17983/checks?check_run_id=123140675812)
correctly flagged unbounded pending quality-card creation. Current head
fixes that under the existing task-row lock: equivalent requests with
fresh idempotency keys reuse the pending card; conflicting requests for
an unresolved deliverable return the existing interaction ID; pending
cards are capped at ten per task across all reviewers. Distinct outputs
remain independent, and already-answered items in a partially pending
batch can receive a fresh review. Added real-database concurrency,
cross-card duplicate, partial-answer, and hard-cap regressions. Quality
review 22/22 tests and final server typecheck passed; earlier
service/routes 163/163 tests passed before the final partial-answer
refinement. One added assertion initially expected a service HTTP error,
but duplicate keys are rejected earlier by the existing shared schema;
the assertion now verifies that validation. Fresh current-head
CI/reviews are pending; the action-required security result is not
treated as passed.
- `c9c575e5f` completed all 56 checks successfully with four conditional
skips, Greptile 5/5, and Superagent pass. Its two P2 review findings are
fixed in the current head: independently bound quality approvals now
each remain visible in attention; changing/clearing URL-backed
assignee/status filters updates the URL and survives task navigation.
Both review threads are resolved. Regression evidence: attention service
34/34 tests passed, CoordinatorTasks 20/20 passed, UI and server
typechecks and the full workspace build passed on `69c2c7543`. The first
new UI test run caught an assertion racing React Router's transition;
waiting for the navigation before asserting passes without weakening the
navigation/remount checks. These older-head green checks are not claimed
for the new fix commit.
- Preceding `0e6ef7c44` completed all 56 checks successfully with four
conditional skips, fresh Greptile 5/5 and no open findings, and passed
Superagent. A fifth migration-metadata collision arrived before the
final Runner job finished. Those green results are preserved as
prior-head evidence, not current acceptance.
- Previous fully verified migration head:
`0e6ef7c44696a377f35e69521b93587576374bd0`, integrating master
`f8226b051` after the fourth migration-number collision. Master added
terminal GitHub-response migration 0401 while the final native check
ran; upstream 0401 SQL/journal/snapshot is preserved unchanged, and
preferences are generated as idempotent `0402_yielding_blink.sql` on
top. Exactly the five newest snapshots remain. GitHub reports MERGEABLE
after the push. All 1,155 relevant
migration/review/interaction/native-execution/remote-assets tests,
workspace typecheck/build, migration guards and whitespace checks pass.
Fresh exact-head CI/Greptile/Superagent are pending.
- Immediately preceding head `36c67cf03` completed all 56 checks
successfully with four conditional skips, fresh Greptile 5/5 and no open
findings, plus passed Superagent security. No retry was needed for that
head's CI. Master advanced and introduced only a migration-metadata
conflict while its final native check ran, so that green result does not
establish acceptance of the current integration. Four consecutive
collisions (0398, 0399, 0400, 0401) during verification are retained as
concrete integration churn; a brief pause of competing migration merges
was requested, without assuming it happened or changing any repo
setting. The PR has not been merged.
- Prior fully verified head: `36c67cf03`, on the clean `30059c0ed`
integration of master `efd65c112`. The last Greptile P2 is fixed: Needs
attention retains the participant-agent scope through authoritative
server membership queries for each pending task, including historical
participation when another agent currently owns the task. It does not
approximate participation with current assignment or enumerate every
company task. The actual view-switch regression and all 31 focused
task/routing/collection tests, UI typecheck/build, token gates and
whitespace checks pass. Greptile completed a fresh 5/5 review on this
exact head (review 19) with zero new comments and no open review
threads. CI and Superagent remain in progress; no current-head CI
failure has been reported.
- Head `30059c0ed` received Greptile 5/5 with that one nonblocking
participant finding, now fixed. Superagent passed that head.
Current-base integration restored the ephemeral RunsOn fleet after a
superseded workflow retained queued aggregate jobs: normal cancellation
was insufficient; the single force-cancel request was interrupted but
readback confirmed that obsolete run cancelled and current CI began on
the trusted fleet. No cancellation retry or runner/security/workflow
changes were made. Its partial CI was superseded by the necessary
participant fix and is not current acceptance.
- Previous compatibility/base-sync head:
`30059c0ededc0eab4e04e8299a884f36db8b292f`, integrating master
`efd65c112` and the Inbox/workspace compatibility fixes. GitHub reports
MERGEABLE after the push. Coordinator keeps Inbox standalone under More
without rewriting the instance's Combined Inbox preference; opting out
restores that preference. Saved merged-Inbox URLs resolve to their
original owner, task status presets remain usable, and canonical
repeated `workspace` parameters retain scoped, deduplicated pagination
(including Needs attention). All 192 broader
routing/Inbox/sidebar/privacy/review tests and the final 16 task-page
tests pass, as do workspace typecheck/build, token gates and whitespace
checks. The two review threads are resolved. Fresh exact-head CI,
Greptile and Superagent results are pending.
- The preceding `d5b9be5bd` remained mergeable but its CI routing gate
intentionally fell back to GitHub-hosted runners: “stacked base merge
commit does not contain the current base branch.” All 45 downstream jobs
stayed queued. Current master was merged cleanly to refresh the pinned
base; no runner/security settings or workflow logic were changed.
Greptile scored that preceding head 4/5 with the two compatibility
findings fixed here. Its automatic Superagent scan was inconclusive at
checkout; the documented retry was still pending when superseded. Those
results do not establish acceptance of this current head.
- Previous approval/migration head:
`d5b9be5bd3b8d6b0437e42bf48138377f34fa67d`, integrating master
`ba5bba86d` and the stale-output approval correction. GitHub reports
MERGEABLE after the push. The fresh P1 finding is fixed: every submitted
item now validates and locks its bound output inside the resolution
transaction, whether or not it carries a required-quality-review
binding. Real database regressions verify that an advanced document
revision or deleted attachment refuses the entire batch without
recording approvals, and current ordinary output reviews still resolve.
All 272 combined migration/review/interaction tests pass; workspace
typecheck/build passed. Fresh exact-head Greptile and CI are pending.
The automatic Superagent scan ended inconclusive at checkout; one
documented on-demand retry is pending. These are explicit verification
limits, not passed security results. The P1 thread is resolved.
- Master consumed the next migration slot three times during this
verification pass: confirmation recovery took 0398, continuation
recovery took 0399, and GitHub acknowledgement recovery took 0400. Each
upstream SQL/journal/snapshot is preserved unchanged. Preferences are
now generated as idempotent `0401_white_lenny_balinger.sql` from
upstream 0400; exactly five snapshots remain, and replay coverage
locates this migration by table content. This is recorded concurrent
integration churn, not a claim that older green results apply to the
latest base.
- Head `ed3b68da9` fixed the two history/URL findings with 26 focused
regression tests, server/UI typechecks, workspace build and token gates
passing. Greptile then scored that head 4/5 with the stale-output P1
corrected in the current head. Its partial CI is superseded, not counted
as current acceptance.
- Previous filter-fix head: `ed3b68da9`, based on the `8458d39d9` merge
of master `063cfd438`. The two fresh Greptile findings are fixed:
history outcome filters now match recorded per-item verdicts in SQL
before pagination (mixed reviews remain in both applicable outcomes),
and same-page URL assignee changes/back/forward navigation update that
filter without clearing independent filters. All 26 focused
database/navigation/collection tests, server/UI typechecks, workspace
build, token gates and whitespace checks pass. The two review threads
are resolved. Fresh exact-head CI, Greptile and Superagent results are
pending.
- The `8458d39d9` migration integration also passed all 328 targeted
migration/interaction/confirmation tests, workspace typecheck/build and
Superagent security scan. Greptile scored that head 4/5 with the two
functional gaps fixed in the current head; those prior-head checks are
not current acceptance.
- Migration integration head:
`8458d39d9721f4cb312c2390070a0609f8cddd1a`, integrating master
`063cfd43813cabf18417605fb9eefb9aacf95c8d`. GitHub reports MERGEABLE
after the push. Master advanced twice during this conflict-resolution
pass: first its confirmation-recovery migration took 0398, then its
continuation-recovery migration took 0399. Both upstream migrations and
journal entries remain unchanged; Coordinator preferences are now
generated as idempotent `0400_sad_guardian.sql` from upstream's latest
snapshot. Exactly the five newest snapshots remain. The replay
regression now locates the table migration by content instead of
hardcoding a renumbered filename.
- All 328 targeted question/review/confirmation/migration tests passed
again after the second merge. Workspace typecheck/build and fresh
exact-head CI/reviews are in progress. The preceding `0c46f46d6` passed
workspace typecheck/build and Superagent security scan, but was
superseded because master consumed migration 0399 while those checks
ran. That prior-head result is not acceptance of the current head. No
production settings or runner/security permissions were changed, and the
PR has not been merged.
- Previous integration head: `0c46f46d6f2b23417ab872ce3cb6ff2673647287`,
integrating master `287b04d72f1b9fca1412e05435c75b8302ba0710`. GitHub
reports MERGEABLE after the push. The renewed conflicts were
`0398_snapshot.json`, `_journal.json`, and the top imports in
`issue-thread-interactions.ts`. Upstream's `0398` confirmation-recovery
index and journal history are preserved unchanged; Coordinator
preferences were regenerated as idempotent `0399_bouncy_miek.sql`, with
replay coverage updated and exactly the five newest snapshots retained.
Both terminal confirmation notifications and Coordinator task
assignment/required review behavior are preserved.
- All 328 targeted interaction/review/confirmation/migration tests pass,
as do workspace typecheck, map validation and whitespace checks. The
workspace build and fresh exact-head CI/Greptile/Superagent checks are
pending. The first migration-generation attempt hit the sandbox's local
IPC restriction before generating files; the unchanged authorized local
generation completed successfully. Prior-head green checks below do not
establish acceptance of this merge.
- Previous acceptance head: `8b7dcf739ed15afc51351fdfa0e0e5fbc75ab788`,
with master `1aa3a21ac` integrated and GitHub reporting MERGEABLE.
Greptile completed a fresh 5/5 review on this exact head with zero new
actionable findings and no open review threads. The [fresh CI
workflow](https://github.com/paperclipai/paperclip/actions/runs/40752864319)
completed SUCCESS on attempt 2 at 19:40:08 UTC, including all eight E2E
shards. Final completed check set: 55 succeeded, four conditional checks
skipped, zero pending/queued/running checks, and one
neutral/inconclusive Superagent scan. The auxiliary commitperclip review
and isolated native Runner compilation/cache-reuse check both passed.
This is not a claim that Superagent produced a passed security verdict.
GitHub still reports MERGEABLE against current master
`60b8089a44b4eaa37e627adbfdf2f130bda13335`.
- Current-head E2E: all eight shards and the aggregate passed, including
the previously failing YAML browser journey. Serialized server shard 9/9
failed: the protected YAML projection test exceeded its original
15-second timeout; its late update request then reached the next test's
reset mock (the captured payload is the prior test's model/label
update). All 88 tests in that exact unchanged file passed locally in
38.03 seconds, with no timeout or assertion changes. The original
slow-request cause remains unproven. CI failure log:
`/tmp/pr17983-8b7-serialized9.log`; local recovery:
`/tmp/pr17983-adapter-yaml-repro.log`. The single bounded unchanged
shard rerun passed, and the workflow completed SUCCESS. Rerun log:
`/tmp/pr17983-8b7-serialized9-rerun.log`. The initial failure is
retained; a passing retry does not establish its original slow-request
cause.
- Greptile scored preceding head `4873704be` 5/5 with one valid P2:
opened task decision records missed company-scoped live invalidation.
The current head uses the existing company decision prefix for
resolution and effect-completion events, and resets private record
payloads on access changes. Its thread is resolved. All 107 focused
record/live-update tests, UI typecheck/build, token checks and
whitespace checks pass.
- CI on `4873704be` failed E2E shard 7/8 in the Advanced YAML
lost-creation-response journey: its clipboard helper selected page text
starting with “Skip to Main Content” instead of YAML. The exact
unchanged journey passed in a disposable local browser instance (1 test,
17.1 seconds). No assertion, timeout or production behavior was
weakened; the original failure cause remains unproven. Failure log:
`/tmp/pr17983-487-e2e7.log`; local check:
`/tmp/pr17983-agent-yaml-repro.log`. The full unchanged Advanced YAML
browser suite also passed locally (6 tests, 37.8 seconds). Fresh
current-head CI subsequently passed this journey and all other E2E
shards.
- Both the automatic and one supported on-demand Superagent scan on
`4873704be` ended neutral/inconclusive: “Pinned PR scan merge-base
checkout failed or timed out.” These do not count as a passed security
verdict. The current head's automatic scan and one documented on-demand
retry also returned the identical neutral checkout failure, with zero
annotations or further diagnostics. This is an external scanner blocker,
not a passed security verdict. No security settings or permissions were
changed.
- Recorded decision links now render and focus the full source-task
record in both Classic and Coordinator, including recorded choice,
submitted inputs, and the existing effect-result resolver. Fresh
terminal records take precedence over older open-decision cache entries.
Context and account checks keep mismatched or inaccessible records out
of the DOM; no decision-history tab was added to tasks or chat. The
shared company live-run feed now drives live-only filtering, including
ended runs and terminal tasks with stale run entries. All 213 focused
tests, UI typecheck/build, token and whitespace checks pass; the final
focus follow-up passed all 188 task-detail tests and UI typecheck. The
first new navigation test failed because its test host omitted company
context; the host was corrected before the passing run.
- Previous integration head: `375c5e89516705050d94bab99336212841b2e6e1`
merges master `1aa3a21ac` after four additional upstream commits. The
sole conflict was competing imports in `server/src/services/issues.ts`;
both quality-review policy and inbound wake-notice notifications are
preserved. The PR-specific review import now sits beside
execution-policy imports instead of the frequently changing first line.
GitHub mergeability is rechecked after the push.
- On the combined master tree, workspace typecheck/build, all 153
affected UI tests, map validation, and whitespace checks pass. Four
server suites passed 77 tests; the fifth suite's module-import hook
timed out while broad verification was running. Its unchanged isolated
run passed all 41 tests in 7.2 seconds with the original timeout. This
records recovery without claiming the original import-timeout cause is
proven. CI on `375c5e895` passed every substantive job, including all
eight E2E shards and Superagent; Greptile found the two functional gaps
fixed in the current head. A short-lived `669d90876` commit added the
main fixes before the focused navigation follow-up.
- Immediately preceding head `9d9737b49` completed all 56 checks
successfully with four conditional skips, Greptile 5/5 and no open
findings, plus a successful Superagent scan. The signoff E2E shard
passed on its single accepted rerun; its initial cancellation/timing
failure is retained below. Master moved again while those checks ran,
requiring this final integration rather than treating the prior head's
green result as current acceptance.
- Previous head `9d9737b496911a6054d0ea22d1b42b28b115e9ab` includes
master `d30c8f42b842327ee1c18c41a2efd6ba623da5cd`; that head was
subsequently conflicted by moving master. The master merge preserved
durable account-bound writes and Coordinator UX. Workspace
typecheck/build, 416 focused UI tests, and 142 affected comment-route
tests passed. A stable full UI run on preceding head `938ad1665` passed
all 9,833 tests across 836 files; its final full workspace build also
passed.
- Greptile found nested proposal project inheritance and Classic
bound-revision links on `91be74952`. Both were fixed with 142
interaction-route tests, 113 focused UI tests, and UI/server typechecks.
Its next review identified a valid draft-preservation bug in the new
Classic loading UI. Head `9d9737b49` keeps loading/error notices outside
editors and annotations while preserving dirty drafts; 115 focused
review UI tests pass, including pending/failed revision loads and
continued draft editing. All related threads are resolved. Greptile
completed a fresh 5/5 review of
`9d9737b496911a6054d0ea22d1b42b28b115e9ab` with no open findings.
- CI on `938ad1665` exposed an integration regression with the newly
merged durable startup saves: the personal preference gate blocked the
task page before its first session lookup. The guarded title editor now
mounts while that lookup is pending, with presentation-specific tools
still gated. All 216 affected component tests pass. The unchanged
five-test `disconnect-write-recovery.spec.ts` browser suite passes
against a newly launched disposable local-trusted PostgreSQL instance on
port 33219, including the exact failed startup-save journey. No live
provider, hosted authentication or production proof is claimed. The
helper-owned test server exited and the port has no listener. UI
typecheck, built-browser assets, token and whitespace checks pass.
- Initial durable-write merge tests found duplicate imports and unscoped
draft fixtures, fixed before 416 focused tests passed. A sandbox
typecheck could not create its IPC socket; the supported rerun passed.
The first revision-link test used a wrong Return to latest button
assertion, corrected before the 113-test pass. The startup E2E
reproduction initially still failed because an outer shell gate also
blocked the page; the subsequent fix passed all five cases without
changing the test or its timeouts. A focused loading-header assertion
initially used an incorrect fixture title; correcting it preceded the
216-test pass. These failures remain recorded.
- Earlier routing gates fell back to GitHub-hosted runners while master
was moving or conflicted. Superseded queued runs were cancelled, then
the `938ad1665` routing gate explicitly selected the ephemeral RunsOn
fleet. Its CI actively executed and completed most tests; only the
diagnosed startup E2E shard and aggregate failed, alongside the valid
Greptile finding. Auxiliary GitHub-hosted workflows also completed
successfully on earlier heads, so queueing alone is not an
administrative blocker. Fresh [CI on
`9d9737b49`](https://github.com/paperclipai/paperclip/actions/runs/40744012678)
is the acceptance target; the previously failing startup E2E shard now
passes. A different signoff E2E shard failed during executor
resubmission when its fixture run was cancelled as
`issue_continuation_waiting_on_review`. The exact unchanged journey
passed locally (1 test, 46 seconds), and the preceding head with
identical server/signoff code passed that CI shard. This supports a
bounded rerun but does not establish the timing failure's root cause.
After the workflow finished, GitHub accepted one rerun of that failed
shard and its dependent aggregate; both passed, completing all checks on
that head. The failure log is retained at `/tmp/pr17983-9d9737-e2e7.log`
and the local reproduction at `/tmp/pr17983-signoff-repro.log`. No
assertion or timeout was weakened.
- On the first merge, full workspace typecheck/build, all 9,622 UI
tests, 267 tests across seven affected server suites, two migration
checks, map validation, token gates, and the PR diff whitespace check
passed. Greptile then found duplicate local task-search filtering and
lost completed item-review detail. Both are fixed, with 42 passing
focused UI tests and passing UI typecheck/build.
- A subsequent Greptile review found attachment confirmations without
working links and mobile history without a visible host. Confirmation
layouts now derive the authenticated immutable-content endpoint from the
attachment ID, and Needs You uses the existing full-screen mobile sheet.
All 119 focused tests pass, including missing/stale display URLs, both
review layouts, and both mobile history entry buttons. UI
typecheck/build and token checks pass. Full workspace typecheck/build
also pass after the second master merge.
- Greptile gave head 22f69c304 a 5/5 score with one non-blocking
desktop-history reopening finding. Head 6dd52b6d3 fixed it, passed all
nine history tests, UI typecheck/build, token gates, and the full
9,679-test UI suite, then received a fresh 5/5 review with zero open
findings. These are prior-head results; review on the master-sync commit
is pending.
- The chat and workspace CI jobs on head 22f69c304 were interrupted by
runner shutdown signals and cancellation before completing their tests.
Their logs do not report failing assertions. Those interrupted jobs are
not claimed as passes. The new head starts fresh runs.
- The first merge CI had a Slack session-sync idle assertion fail after
an unexpected database read. Its exact isolated reproduction passes, and
the chat CI shard passed on head 618c5a2a3. The original failure's cause
remains undetermined. The broader local reproduction, run concurrently
with full verification, instead encountered 21 timeout failures across
its two test chunks; it is not claimed as a passing full local server
run. A concurrent local UI run had eight failures (seven timeouts and
one delayed autosave assertion). The complete UI run on the final head
passed all 9,679 tests across 830 files with two workers; no test
timeout or assertion was weakened. This establishes recovery without
claiming that every earlier timeout's cause has been proved. An earlier
intermediate UI run also overlapped the second master merge and failed
the newly added Advanced-sidebar expectation, so it is not treated as
stable-tree evidence. The newly merged UI dependencies initially
required refreshing the local install from the upstream package
manifest; the generated local lockfile update is not committed, per
repository policy.
- Superagent returned neutral/inconclusive scans on the preceding heads
because its pinned merge-base checkout failed or timed out. The
available retry endpoint returned 404. These are not successful security
verdicts. The fresh scan on `91be74952` passed (PR scan passed; no
suspicious PR changes detected). The `938ad1665` scan again returned
neutral/inconclusive with the same pinned merge-base checkout error; the
check-suite rerun endpoint returned 404. The fresh `9d9737b49` scan
completed successfully at 18:22 UTC with no suspicious changes detected.
Earlier neutral scans are not counted as successful security verdicts.
- Prior head `57902152ac3218096fca669d33ff18400a2a86ae` passed 9,618 UI
tests across 826 files, received Greptile 5/5 with no open findings, and
completed CI with 56 passes and four conditional skips. These are
historical results, not acceptance of the latest merge commit.
- The first full build found generated capability-contract drift. The
generated outputs were refreshed. Initial sandbox runs could not open
local IPC sockets; verification was rerun with local test access.
- Current master was merged. The workspace preference migration was
regenerated after the existing migration history.
- The UI run first found two outdated expectations: early custom-answer
validation and the document access error copy. Both were corrected, and
the full UI suite then passed.
- The local server run found three failures in unchanged tests. The Muse
test passes with Python 3.13 instead of the host's Python 3.9. The two
workspace tests pass when their test process uses the expected master
default branch. These environment settings do not change application
behavior or global machine settings. The unsharded server run was
stopped after those reproductions; CI supplies the full sharded server
result. No successful full local server run is claimed.
- Skill inventory generation needs an external eval checkout, which is
absent locally. The existing generator functions refreshed only the live
skill inventory and its derived files. The checked-in eval inventory was
preserved. The inventory validation gate passes.
- Greptile found a dropped MCP review requirement, missing per-item
output links, generic item-review summaries, and a history-refresh
failure. The fixes have 32 passing database-backed server tests and
focused rendered-card tests. A follow-up partial-review finding was
corrected by forwarding the canonical mutation status before settling
the card. Attachments open through the authenticated immutable-content
route in both card layouts. The final focused UI set has 117 passing
tests, including these regressions.
- Both browser shards that first failed expected a disabled-chat
message. The copy was restored, and those shards passed in CI on the
next commit. The two journeys also passed locally. One local attempt
first timed out before feature disable while waiting for the provider's
initial message; its isolated reproduction passed. That earlier timing
failure remains recorded and is not presented as an explained
infrastructure failure.
- Serialized server shard 9 first failed during pnpm setup with
ECONNRESET, before dependencies or tests ran. Its single rerun passed
setup and all tests. The build and production runtime boot passed on the
first attempt, but that run's public-install step timed out during Pi
setup. The single build-job rerun passed compilation, runtime boot, and
clean public-install verification. Those setup scripts are unchanged by
this PR. The successful retry establishes recovery; the earlier Pi
timeout's underlying cause remains undetermined. The aggregate CI gate
is green: [workflow
run](https://github.com/paperclipai/paperclip/actions/runs/40637789695).

</details>

## Risks

- This touches shared task, interaction, and completion paths.
Regression tests must cover classic and experimental behavior,
authorization, duplicate answers, and stale review targets.
- The additive preference table must migrate before the setting is used.
The setting defaults off.
- The experiment changes navigation and message presentation. Canonical
task and document records remain the source of truth.
- The initial task brief and saved plan can repeat information. This
change fixes chronology; a broader redundancy policy remains a design
decision.

## Model Used

OpenAI GPT-6 Codex with reasoning and tool-assisted code editing, tests,
and browser verification. Earlier iterations used Codex models in this
task; their exact model IDs are not available in the current context.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used
- [x] I have checked ROADMAP.md
- [x] I have searched GitHub for duplicate or related PRs
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change
- [x] I have run relevant tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have 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 review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 17:20:01 -07:00
Nicky LeachandPaperclip c57af3c564 Reuse prepared Runner storage and installed skill selections (#18089)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/207/changes/paperclip/207
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and their work.
> - The native Runner prepares selected skills, instructions, and
provider storage.
> - Repeated preparation imports the company skill inventory and
rebuilds Claude storage.
> - Execution environments can already maintain prepared resources.
> - This pull request lets them reuse account storage while Core keeps
execution policy.
> - New retry runs resolve current skills and keep the failed attempt's
history.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Native Runner preparation and retry skill selection.

**Current behavior**

Explicit installed selections still trigger company inventory
reconciliation. Plugin preparation receives account identity only on
warm transitions. Claude's isolated mode requires a session-specific
configuration directory.

**Proposed behavior**

Skip inventory imports when explicit selections are installed, while
retaining current authorization and version resolution. Send account
identity on initial preparation. Allow an execution environment to
provide persistent Claude storage without enabling preconfigured
permission behavior. A new retry resolves current skill assignments.

**Reason and benefit**

Remove repeated preparation work without adding environment-specific
policy to Core. Related: #13984 describes a similar storage-lifetime
problem in the separate claude_local adapter; this PR does not change
that adapter.

## What Changed

- Derive Claude’s configuration path from the single authoritative
prepared-storage input; separately supplied CLAUDE_CONFIG_DIR values are
overridden.
- Add an explicit prepared Claude storage binding, forward it to the
sidecar, and retain recovery and provider lifetime fencing.
- Refresh Core-owned Claude settings after acquiring the lifetime lease.
Reuse environment-prepared skills.
- Reuse installed explicit skill selections and preserve
missing-selection initialization and current access checks.
- Reserve the prepared-home marker for environment provisioning; task
overrides are rejected and configured bindings are stripped before
native launch.
- Clear inherited skill selection snapshots on new retries. Keep
admitted execution recovery and failed attempt metadata.

## Verification

- Current single-input follow-up `8dbc2f6ec`: 154 focused Runner checks
pass with one existing skip; four Grok identity checks and four Pi
packaged-probe checks pass. Shared immutable source identities advance
to Grok10/Pi32/Copilot74. All56 current-head CI checks pass (four
intentionally skipped); standard and enhanced reviews are both5/5 with
no unresolved threads.
- Focused Runner sandbox tests: 29 passed. Focused environment tests: 16
passed.
- company-skills-empty-runtime: 10 passed.
- Plugin Runner and runtime selection database tests were attempted.
Local execution is blocked because embedded PostgreSQL cannot load
libzstd.1.dylib; these checks remain for CI.
- New database regressions cover installed-selection reuse, initial
account preparation, and retry snapshot removal.
- Prepared-home trust-boundary regressions: 4 targeted checks passed
(task schema, all env binding scopes, native executor).
- Focused Pi public-install probe checks: 4 passed. The build smoke
probe now asserts the current Pi 32 profile and exact digest.
- CI found and fixed retry-context TypeScript inference, stale Pi
identity fixtures, Docker source identity inputs, and the
skill-observability test’s old assumption that every selection imports
inventory. Cold and reused selection coverage remain.
- CI chat shard 2 initially failed three GitHub/Discord idle-database
assertions. An unchanged-head rerun passed; the original cause remains
unexplained.
- Runtime head `f5b53679a` passes all 56 current CI checks (four jobs
intentionally skipped), including the full build/public-install probe,
TypeScript, Rust, Runner and server matrices. Greptile is 5/5 with no
unresolved review threads.
- The requested enhanced review scored 5/5 on `f5b53679a`, with one
nonblocking documentation request. Documentation follow-up `1ac5d26a8`
adds only the documented existing ownership/0700 requirement; the thread
is resolved and all 56 current-head checks pass (four intentionally
skipped). The subsequent single-input runtime follow-up8dbc2f6ec
repeated the complete CI → standard5/5 → enhanced5/5 cycle successfully.
- Broader verification is delegated to GitHub CI as requested. The
initial policy check rejected a generated lockfile repair; that change
was removed because Core CI already resolves stale importer entries.

## Risks

Prepared storage must be provisioned by the execution environment before
launch. It is not credential isolation. Core replaces managed Claude
settings under the existing provider lease. No new per-run harness homes
are created by this option. New retries may select a newer skill
version; recovery of an already admitted provider execution keeps its
saved input.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and tool use. The exact model
revision 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
related context above
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change
- [x] I have run focused local tests; database and full verification
remain for CI as explained above
- [x] I have added or updated tests where applicable
- [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 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 17:09:24 -07: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 743698e700 fix(runner): preserve OpenCode bash process exit codes (#18076)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner stores structured tool events so people can inspect
actual work.
> - OpenCode puts a completed bash command's process exit in
`state.metadata.exit`.
> - The canonical event mapper only read `state.exit`, so a real nonzero
exit became unknown.
> - This pull request preserves the documented builtin bash exit and
rejects conflicting evidence.
> - The benefit is an accurate process exit without changing tool
completion or native run status.

## Linked Issues or Issue Description

**What happened?**

A completed OpenCode bash part with `state.metadata.exit: 37` produced
`exitCode: null`. The process result was present, but the canonical tool
event lost it. The pinned upstream [shell
result](https://github.com/anomalyco/opencode/blob/v1.18.34/packages/opencode/src/tool/shell.ts#L544-L552)
and [completed
part](https://github.com/anomalyco/opencode/blob/v1.18.34/packages/opencode/src/session/processor.ts#L160-L170)
establish the field path.

**Expected behavior**

The canonical event retains the numeric process exit from a completed
builtin bash part. A completed tool call can have a nonzero command
exit. Missing or invalid evidence must not become a successful command.

**Steps to reproduce**

1. Pass a `type: "tool"`, `tool: "bash"` part with completed state and
numeric `metadata.exit` to `canonicalProviderEventsFromOpenCodePart`.
2. Inspect `tool.execution.completed.payload.exitCode`.
3. Before this fix, the value is null. After this fix, it matches the
process exit.

**Paperclip version or commit**

Reproduced on master `f4f02880cae4f5fa54d47d39565ca99b6b72446d`.
Duplicate searches found no matching fix. Related PR #15715 concerns
OpenCode V2 transport and version support; it does not change this
mapper.

## What Changed

- Read numeric metadata exits only from completed builtin bash parts.
- Keep legacy numeric top-level exits. Return unknown when supplied
legacy evidence conflicts.
- Cover zero and nonzero exits, invalid values, foreign tools,
incomplete calls and conflicting receipts.
- Document the run-log field and the distinction between tool completion
and command success.

## Verification

- The regression suite first failed five assertions on the unchanged
mapper. All 53 provider-event tests now pass.
- A focused no-emit TypeScript check covers the changed mapper, its
tests and imported protocol validators.
- Tests use synthetic structured parts and real protocol validation. No
local database, provider, SDK build or live scenario was run.
- All 48 jobs in the normal PR workflow passed, including the required
`ci / verify` and `ci / e2e` gates. CI also executed all 53
provider-event tests.
- Greptile reviewed this exact head at 5/5 with no actionable findings.
The separate hosted quality-gate review also completed successfully.

## Risks

- Conflicting legacy and metadata exits now remain unknown for completed
builtin bash calls. This avoids selecting one inconsistent value as
proof.
- Other tools retain their existing legacy behavior. Output prose never
supplies an exit code.
- The change adds no schema field and changes no provider version,
budget, accounting, fixture or native run outcome.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning and terminal tools.
The session 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-28 15:11:22 -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
DottaandPaperclip 4808a3a2b1 fix(heartbeat): retry operator Stop after a transaction deadlock (#17895)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/69/changes/paperclip/69
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operator Stop must revoke task authority before it stops provider
execution.
> - Its transaction locks the task and then the run. A concurrent writer
can hold the run while it waits for the task.
> - PostgreSQL can abort the Stop transaction with a confirmed deadlock.
The cancel API then returns 500.
> - This pull request retries only that aborted database transaction, at
most three times.
> - Provider Stop and activity publication stay after commit, so the
retry cannot repeat those effects.

## Linked Issues or Issue Description

Refs #17639. Its agent-chat project browser test completed the product
assertions, then failed during cleanup when the cancel API returned 500.
A real PostgreSQL lock-cycle test reproduces the same `40P01` error in
the Stop transaction.

Related: #13911 addresses audit foreign-key lock contention. This change
handles a different concurrent run-writer path without changing the
schema or task/run lock order.

Stack base: #17639. This is a separate correctness repair for the sleep
migration stack, not another polling migration.

## What Changed

- Control the runner timeout regression fixture's clock so it reaches
the pending append before expiry; retain production cancellation and
late-append assertions.

- Retry the Stop authority transaction only after PostgreSQL reports
`40P01`. Make at most three attempts, with short bounded backoff.
- Discard rolled-back local run state, claim flags, and queued activity
publications before each retry. Re-read current authority under fresh
locks.
- Keep provider cancellation and activity publication outside the
retried transaction. Preserve other errors and the existing native
lock-conflict response.
- Add a real two-transaction deadlock test. Add server-side failure
tests for retry exhaustion and errors that must not retry.
- Let run-control tests use a validated disposable PostgreSQL database
URL.

## Verification

Published head: `60ba892ae9fc5faaf8cd0833694b4a66c13323c3`, targeting
master after #17639 merged at
`1ed0af41867ba40fd1d23292d395588d18c2fcbe`. The normal ancestry merge
preserves the complete five-path tested cancellation patch
byte-for-byte, including the review repair, and all four unrelated
current master paths. The production retry logic remains unchanged from
this slice's reviewed implementation; the follow-up adds coverage and
its audit.

- **228 distinct complete cases pass:** all 48 run-control cases and all
180 native-session runtime cases. The two new targeted cases are
included in 48 and are not counted again. Server typechecking, build and
module-boundary checks also pass.
- The new real PostgreSQL cases reach a failed native run's correlated
Stop claim, cancellation fence, board handoff retirement and activity
write before raising `40P01`. One case preserves retry authority and
commits exactly one cancellation activity/live notice. The other changes
coordinator authority between attempts, returns 409, preserves the
failed run and handoff, and performs no provider/workspace cleanup.
- A negative control removes only the publication-list reset. It fails
with two live notices for one durable activity. Production was restored
byte-for-byte before final validation. The existing actual
two-connection deadlock, bounded attempts, non-deadlock rejection and
post-commit provider behavior remain covered.
- Preserve the initial new-assertion typecheck failure (optional
live-event payload) and the corrected final pass. Service-local test
files are typechecked; `src/__tests__` is excluded. The negative-control
harness initially expected an untruncated Vitest assertion line; the
actual named 1-versus-2 failure and restoration were inspected before
correcting its result matcher.
- [Current-parent acceptance and failure
ledger](https://github.com/paperclipai/paperclip/blob/60ba892ae9fc5faaf8cd0833694b4a66c13323c3/doc/plans/2026-10-28-cancellation-deadlock-acceptance.md)
records current scope, commands, isolated fixtures, mutation evidence
and limits. Earlier combined-stack counts retain their original revision
scope. The existing controlled runner timeout/late-append fixture is
retained and passes within the complete 180-case runtime suite.
- This addresses the prior Ponytail request to exercise native claimed
state before deadlock rollback and re-evaluate authority afterward. The
advisory loop-invariant snapshot/named-attempt-bound note remains a
maintainability suggestion, not a runtime defect. No production loop
refactor or new worker duty is introduced.
- **All 58 current checks are clean; Greptile and Ponytail both rate
this exact head 5/5.** Ponytail explicitly confirms that the
native-claim coverage request is resolved and says Ship. The formerly
queued dependency/quality review workflow has completed successfully.
Old `fffc`/parent checks and reviews are not current passes; the former
pending Snyk status is not called successful. Actual failing Ponytail
findings must be fixed. Missing/stopped/paused turns without a verdict
are authorized nonblockers. Active unfinished reviews retain their
original per-head timer, with a 25-minute monitor cutoff respecting the
30-minute maximum.
- No full local repository matrix, live provider execution, external
alarm, physical host/database suspension or savings claim is made. No
schema, dependency, workflow, shared scheduler contract or shared OS
resource changes are introduced.

## Risks

- Persistent contention still returns an error after the third attempt.
This change does not promise to eliminate every possible lock cycle.
- Retrying a write after an ambiguous connection failure would be
unsafe. The retry accepts only PostgreSQL's confirmed deadlock abort
code; it does not accept transport errors.
- No schema or public API contract changes. Current task/run authority
and cancellation eligibility are checked again on each attempt.

## Model Used

OpenAI GPT-6 via Codex, with shell, GitHub CLI, TypeScript, PostgreSQL,
and Playwright tools. The exact serving model ID and context window are
not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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:46:58 -05:00
DottaandPaperclip 4f8104dec6 fix(runner): keep human input tool visible to Claude (#18046)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native task agents must create durable human questions and
approvals.
> - The request_human_input schema has an object root with a conditional
wrapped in allOf.
> - The pinned Claude client omits that tool from the API request in an
isolated gateway environment.
> - An equivalent direct conditional keeps the tool available and
preserves validation.
> - This pull request fixes the schema and tests discovery through the
real pinned client.

## Linked Issues or Issue Description

**What happened?**

A retained native Claude Plan attempt could save its Plan but received
`No such tool available: mcp__paperclip__request_human_input`. A local
comparison with Claude Code 2.1.286 reproduces the discovery failure
without a provider: the client offers the control tool but omits the
human-input tool. It offers both tools after this schema change.

**Expected behavior**

The client must offer the authorized human-input tool. Invalid question
forms must still fail validation.

**Steps to reproduce**

1. Serve the current request_human_input definition through Runner's
local MCP bridge.
2. Start the pinned Claude client with a local mock Messages API and
tool search disabled.
3. Inspect the API request's offered tools. Before the fix,
request_human_input is absent. After the fix, it is present.

Refs #18034 for the separate saved-Plan readback repair. This PR
addresses tool discovery. It does not reclassify or rerun the original
failed live attempts.

## What Changed

- Put the existing question-payload condition directly on the live and
scenario object schemas. A one-branch allOf wrapper is unnecessary.
- Add a regression through the pinned native Claude executable, real
Runner MCP bridge and loopback mock API. The test uses fake credentials
and executes no tools.
- Keep validation tests for mixed forms and malformed payloads. Add an
explicit missing-payload rejection.
- Refresh generated schema identity and the explicitly seeded catalog
fixture with the maintained generator. Historical live evidence is
unchanged.

## Verification

- Native discovery regression red: the control tool is present and
request_human_input is absent.
- Green: 92 tests pass across native discovery, Runner tool bridge, core
contracts and semantic tools. The final argument-visibility regression
and core contracts also pass together (21 tests).
- Runner package typecheck passes.
- Runner package build passes. Its first run found stale generated
contract identities; regeneration resolved that check. Both logs are
retained.
- No real provider request, paid eval, sandbox allocation or automatic
retry.
- Local verification is scoped to the Runner package. Full repository CI
must pass on this PR's exact head before merge. New live Plan acceptance
is still required.

## Risks

- The conditional has the same JSON Schema validation meaning. The
provider-facing object shape changes, so the generated catalog identity
changes.
- The native regression uses the optional platform CLI already required
by the pinned ACP profile. It does not establish provider billing, model
behavior, or full Plan acceptance.
- Optional case/workflow tool discovery is a separate confirmed gap
tracked in #18051. This human-input fix does not qualify those tools.
- No database migration, permission, budget, workflow, lockfile or UI
change.

## Model Used

- OpenAI Codex, GPT-6, with reasoning and code execution tools. The
exact serving variant and context window are not exposed in this
session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 11:30:15 -05: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 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 cff331f6ca fix(evals): retain local controller cost origin (#17990)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Its eval journals retain model costs and operating reservations
under one cap.
> - The operating policy records the controller's execution origin.
> - The schema currently accepts only GitHub-hosted and AWS Fleet
origins.
> - A local controller must therefore use an inaccurate label or fail
admission.
> - This PR adds the local origin and keeps the hosted-only schedule
gate.

## Linked Issues or Issue Description

Refs #17986. No duplicate open PR or issue was found in the
operating-overhead/local search.

**What existing behavior does this improve?**

The Product E2E operating allowance and its retained journal policy.

**Current behavior**

At master `40c1ab36cd`, an unscheduled local controller cannot set
`runner: "local"`. The generic allowance validator rejects it. Local
qualification can use the same accounting controls but cannot record its
origin correctly.

**Proposed behavior**

Accept the local origin in the generic allowance. Keep all component,
price, cap, expiry, and receipt rules. The scheduled validator still
requires `github-hosted` and rejects a local allowance.

**Reason and benefit**

Local qualification can retain an accurate execution origin without
claiming that its reservations are billed GitHub charges.

## What Changed

- Add `local` to the operating allowance's runner type and validator.
- Exercise local journal creation, model admission, retained overhead,
restart, and reconciliation in the existing boundary test.
- Check that a local allowance fails Product scheduled admission.
- Pin new hosted Runner controller admission to `github-hosted`.
Preserve original labels when reading historical manifests; those reads
cannot authorize a new worker.
- Exercise the hosted-origin rejection and historical/local reads in
both source and copied portable runtimes.
- Document the local label and its accounting limits.

## Verification

- Before the fix: the new local persistence case and schedule-boundary
assertion failed; eight tests passed.
- Focused ledger, overhead, operations, and scheduled finalization
tests: 71 passed across five files.
- Controlled Runner source and portable tests: 86 passed. The new
hosted-origin regression failed before the fix.
- Full Product support suite at the first commit: 4,524 passed, three
skipped, and one retained embedded PostgreSQL bootstrap failure. The
same database failure was previously reproduced on a clean baseline.
- Separate Node test phase on the host: 137 passed.
- Actual Linux controller: database lifecycle tests pass. After
installing its missing `zip` utility, the full Product suite has 4,527
passes and one Copilot parent-version coverage failure. That same
failure reproduces on clean master `40c1ab36cd` with the same Linux
filesystem and dependencies (14 passes, one failure). Copilot files are
unchanged. The initial seven ZIP-related failures and the watcher
failure remain retained.
- The final fresh Linux semantic check passes: `GOMEMLIMIT=2GiB GOGC=50
GOMAXPROCS=1 node node_modules/typescript/bin/tsc --singleThreaded -p
tests/runner-e2e/tsconfig.json`. The parallel compiler OOM is retained.
No semantic checks were omitted.
- Both fresh reviews are 5/5, with the addressed thread resolved. Hosted
Build first failed during unchanged Pi setup prefetch with an operation
timeout. One job rerun recovered; the original failure remains retained.
All 58 latest-head checks are now acceptable.
- No paid model requests, sandbox creation, schedule changes, or
historical journal edits.

## Risks

- The caller supplies this origin. It must describe the actual
controller.
- `local` does not prove zero compute cost, provide a default allowance,
or release a hold.
- Both maintained hosted admission paths require the GitHub-hosted
controller origin. A previously accepted hosted policy with an AWS/local
label now fails new admission. Historical reads preserve the original
evidence.

## Model Used

- OpenAI GPT-6 through Codex, with tool use and code execution. The
exact serving model ID and context window are not exposed in this
session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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 02:05:36 -05:00
DottaandPaperclip 6b9e5f3a80 fix(evals): enforce qualified ACPX profile admission before paid turns (#17964)
## Thinking Path

> - Paperclip coordinates agent work through Runner.
> - Controlled evals route model calls through a budget gateway.
> - The definitions pin each ACPX runtime identity.
> - A stale qualified profile currently reaches a paid turn before
scoring rejects it.
> - The Runner CLI already checks an exact expected profile before it
creates a provider.
> - This change forwards that existing admission argument through the
controller.
> - Profile drift can then stop before model spending.

## Linked Issues or Issue Description

Refs #17943 and #17929.

**What happened?**
The worker in run 40618022700 passed all four behavior checks and
retained three final request receipts. Its grader then rejected the old
Claude SDK pin. The controlled wrapper could not pass the existing
`--expected-acpx-profile` argument to the built CLI.

**What did you expect to happen?**
The built CLI must reject a stale expected profile before provider
creation.

**Steps to reproduce**
Run a controlled ACPX cell with a definition that pins a different SDK
from the built Runner. The old wrapper accepts only request and output
arguments. It cannot enforce the profile admission supplied by updated
definitions.

**Paperclip version**
The observed run used e4b30163bb.

**Deployment mode**
The controlled GitHub Actions Runner protocol workflow.

## What Changed

- Forward bounded expected-profile JSON through the controlled wrapper
to the same built CLI.
- Reject invalid objects, oversized arguments, and profiles on non-ACPX
requests before opening evidence.
- Exercise a real child boundary and the actual qualified Claude CLI
admission gate.
- Document the definition/controller compatibility requirement.

## Verification

- Controller suite: 77 tests passed. The new regressions fail against
the original wrapper.
- Hosted and portable controller suites: 8 tests passed.
- Actual eval-session CLI contract suite: 39 tests passed. A stale
qualified Claude SDK never creates a provider service.
- Runner package typecheck passed.
- The non-ACPX rejection guard also passed its focused regression after
review.
- No live provider request was made for this change.
- Full repository checks and current-head reviews run on this PR.

## Risks

- Updated definitions require this wrapper before they can pass the new
argument. Merge the controller first.
- Profile identity remains owned by the built Runner CLI. The controller
only forwards its existing argument.
- Existing callers that omit the argument retain their current behavior.
- Optional review suggestions to duplicate the expected-profile hash
into controller evidence and add a full built-CLI/controller integration
case are deferred. The pinned definition revision retains the expected
profile, and both controller entrypoints plus the actual CLI admission
boundary are covered. A compatibility error fails closed without a paid
fallback.

## Model Used

OpenAI Codex, GPT-6 family, with tool execution and extended reasoning.
The exact serving model ID and context window are not exposed in this
session.

## Checklist


- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [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:59:20 -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 38d08847b8 fix(runner): keep OpenRouter upstream keys in the parent proxy (#17949)
## Thinking Path

> - Paperclip manages agents and their work.
> - Paperclip Runner starts OpenCode with the selected provider and
model.
> - The native OpenRouter route passed the reusable upstream key into
the child environment.
> - A persisted-state scan found that key in an OpenCode database WAL.
The exact write operation is not known.
> - This pull request reuses the existing parent-held provider proxy for
that route.
> - The child receives a temporary loopback credential instead of the
upstream key.

## Linked Issues or Issue Description

**What happened?**

The native OpenRouter path passed `OPENROUTER_API_KEY` into the OpenCode
child. A real Product E2E persisted-state scan detected the key in the
child database WAL. The scan does not establish which operation wrote
it.

**Expected behavior**

The runner keeps the reusable upstream key in its own process. OpenCode
can call only the selected model through the session proxy.

**Steps to reproduce**

1. Start the OpenCode driver with an explicit or ambient synthetic
OpenRouter key.
2. Inspect the fake child configuration, environment, and persisted
provider values.
3. Send a request through the real loopback proxy and verify the
upstream authorization and exact model.

**Paperclip version or commit**

The regression is present on merged master
`813e808af462b6a6f9db38b6791e3bfe8465b51e`. This PR is rebased onto
merged master `d40f9ac377`.

**Deployment mode**

Built from source. The finding came from an AWS Product E2E job. The
regression tests use local synthetic servers and a fake child, with no
provider calls.

Related issue search found #16643 about general inherited environment
scope. This change addresses the narrower native OpenRouter path. No
duplicate custody PR was found. This PR must remain unmerged until
separately approved; it does not change the eval baseline or qualify a
new live result.

## What Changed

- Reuse the existing parent-held proxy for native `openrouter/` models.
- Remove the upstream key from the child environment and retain it in
diagnostic redaction.
- Keep the selected provider and exact model. Reject alternate-routing
fields before the upstream request. Use a session-lived loopback token.
- Preserve the effective explicit or ambient proxy bypass list when
adding loopback entries.
- Add explicit and ambient key regressions, upstream routing checks, and
child persistence checks.
- Document the boundary and its limits.

## Verification

- Final rebased head: full OpenCode driver suite, 64 synthetic tests
passed, and runner source TypeScript check passed. Original author run
had 61 passing tests before the new master tests.
- The two new explicit and ambient regressions fail on the old
implementation.
- Independent source review passed. The two new synthetic regressions
also passed independently. A separately filtered legacy pair hit fixture
selection/chmod ordering and is not claimed as a passing run.
- Tests use the real driver and proxy with a fake OpenCode child and
synthetic upstream transport. They check key exclusion, exact
URL/model/authentication, wrong-model and alternate-routing rejection,
proxy bypass preservation, redirect rejection, and proxy shutdown.
- The two advisory regressions failed before the correction: fallback
routing reached upstream, and ambient NO_PROXY was lost. The full
64-test driver suite and source TypeScript check pass after the
correction.
- No real OpenCode SDK/provider qualification was run. The original WAL
write mechanism remains unknown.
- Repo-wide typecheck, test:run, and build were not run locally because
local native/DB/model execution is excluded. Normal PR CI passed on head
`3e1903272ce65b92055ea70f8dc586d9aa5e0205`: typecheck/release registry,
general and serialized suites, runner static/Rust/Vitest checks, E2E
shards, build, and canary dry run. Greptile is 5/5 on that head.
Paperclip Review is neutral with no blocking findings; its two earlier
findings are fixed and resolved.

## Risks

The native OpenRouter route now uses the existing OpenAI-compatible
proxy transport. Synthetic tests do not prove every live SDK response
shape. The loopback token remains a credential, is redacted, and expires
with the session. This change does not claim isolation of every child
secret or persisted value.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) assisted source investigation,
implementation, synthetic tests, and review with tool use. No provider
model call was used for verification.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 20:57:19 -05:00
DottaandPaperclip e4b30163bb fix(evals): preserve the complete trusted controller artifact inventory (#17943)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/103/changes/paperclip/103
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages real agent work.
> - Controlled Runner evaluations record model spend and traces.
> - A trusted build creates one portable controller with a complete file
inventory.
> - GitHub artifact upload omitted one hidden dependency metadata file.
> - The next job correctly refused the incomplete inventory before any
paid worker started.
> - This change preserves all inventoried bytes without relaxing
verification.

## Linked Issues or Issue Description

Refs #17889, #17929.

**What happened?**
[Run
40585138437](https://github.com/paperclipai/paperclip/actions/runs/40585138437)
failed at copied controller verification. Its artifact contains 294
files; its signed inventory expects 295. The only missing file is
`server/node_modules/protobufjs/node_modules/@protobufjs/pool/.npmignore`.
No extra files exist. Every paid worker was skipped and no model request
ran.

**Expected behavior**
The trusted controller artifact preserves its full inventory, including
hidden package metadata. The strict verifier rejects any actual change
or missing file.

**Steps to reproduce**
Build the portable runtime, upload the directory with the action's
default hidden-file exclusion, then verify the downloaded artifact
against the original receipt.

## What Changed

- Enable hidden files only on the fresh trusted controller code upload.
- Download that exact upload and run a real artifact-service round-trip
test before any private preparation. The test fails if the upload drops
hidden files again; it tests the actual transport instead of matching a
YAML flag.
- Keep the strict byte inventory and trusted source/receipt checks.
- Document why this code artifact differs from private attempt evidence,
which still uses the protected archive.

## Verification

- Exact retained artifact comparison: one missing `.npmignore`, zero
extra files.
- `actionlint .github/workflows/runner-protocol-live-evals.yml` passed.
- Protocol workflow security tests: 14 passed.
- The artifact-service integration test is explicit-only locally. The
controlled workflow supplies the real downloaded artifact, trusted
source and receipt digest.
- No product runtime, provider routing or grading code changed. CI runs
broader checks. Fresh controlled workflow qualification follows merge.

## Risks

Hidden files are allowed only in the code-only output of the
provider-credential-free build. Raw private evidence and credentials do
not enter that upload. The artifact verifier still requires every file
and SHA-256 from the trusted receipt.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository inspection and
code execution. The exact serving 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 (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>
2026-10-27 20:55:18 -05:00
DottaandPaperclip 0d22e27dc4 fix(runner): preserve closed native startup diagnostics (#17962)
## Thinking Path

> - Paperclip runs agents through a controlled execution boundary.
> - Native Runner starts ACPX providers through a TypeScript sidecar and
a Rust transport.
> - That transport hides arbitrary provider messages because they can
contain credentials.
> - Grok admission failures currently have no stable code. Other startup
failures can also lose their owning stage.
> - A real native startup failure therefore reports only
`classification=unclassified`, even when the ordinary subscription hello
test succeeds.
> - This pull request preserves fixed failure categories without
forwarding provider text or changing admission policy.
> - The benefit is a useful next diagnostic result before another
functional repair or retry.

## Linked Issues or Issue Description

Refs #17922 and #17942.

**What happened?**

A native Grok session failed before its first tool. Runner assets passed
verification. The Rust rejection discarded the cause because only closed
error codes may cross that boundary. The existing admission guard used
plain errors. Startup errors outside that guard could also lose their
stage.

**Expected behavior**

Report a fixed Grok admission reason, or a fixed startup stage when no
known error code exists. Keep credentials, provider messages, session
IDs, and paths out of the classification. Keep the failure and cleanup
effective.

**Steps to reproduce**

1. Have a Grok ACP fixture return a session without its native effort
acknowledgement.
2. Start it through the real ACPX client and pass the failure through
the sidecar classifier.
3. Before this change, the result is `acpx_sidecar_command_failed`. Rust
reduces that to `unclassified`.
4. The same loss occurs for injected sandbox, credential, and runtime
admission failures.

## What Changed

- Give Grok effort admission errors fixed codes for missing
acknowledgement, model or effort mismatch, session mismatch, conflicting
configuration, drift, and invalid protocol use.
- Record closed host startup stages in a private weak map. Preserve the
original error object, cancellation, and resource cleanup.
- Prefer existing known error codes over a fallback stage. Ignore
arbitrary provider-supplied stage properties and messages.
- Map only exact new codes to Rust diagnostic categories. Add real
ACPX-client and sidecar-pipe regressions with secret canaries and
unknown-code controls.
- Bind the changed shared source and new diagnostic modules in Copilot
profile 70. Preserve profile 69 and earlier history.
- Document the diagnostic contract. There are no dependency, lockfile,
workflow, auth, model, permission, or retry-policy changes.

## Verification

- Red before the production change: four TypeScript cases lost the
native reason or host stage. A Rust case returned `unclassified` for the
new closed categories.
- Final focused checks: 320 tests passed: 241 across sidecar
classification, Grok admission, the real ACPX client, recovery, runtime
adapter, and Copilot installation; all 79 host integration tests also
passed in isolation. These include nine startup-stage cases, translated
errors, actual missing Pi skill materialization, missing Copilot/Cursor
credentials, and a missing workspace binding.
- Review follow-up: a translated Copilot rejection lost its stage, and a
real Pi skill-loading failure reported configuration. Both regressions
failed before the two-line repair and pass afterward. Stage recording
now follows provider translation and starts before Pi skill acquisition.
The current unpublished Copilot 70 identity was regenerated.
- Formal review follow-up: missing Copilot and Cursor credentials
reported configuration. Both cases failed before the two-line stage
repair and pass afterward. A missing-workspace case also verifies the
separate binding catch.
- Seven Rust unit checks and 17 sidecar transport integration checks
passed. The pipe checks preserve known categories and reject unknown
suffixes without disclosing the provider message.
- `pnpm -r typecheck` and `pnpm build` passed. Rust formatting and the
generated profile/source identity checks passed.
- Host integration history is retained: one complete 73-case host run
passed. Other batches hit credential-port ownership errors in different
existing cases; the four new stage regressions passed. The final 79-case
host run passed after the last review fix. The prior intermittent lease
failures remain recorded and are not claimed fixed here.
- `pnpm test:run` was attempted and stopped after repeated embedded
Postgres bootstrap failures. The same local database failure predates
this change. Full CI must pass before merge.
- A metadata-only probe with pinned Grok 1.0.13, private HOME, synthetic
credentials, a local catalog, and no inference passed fresh Grok
4.7/High admission and cold restore. This is supporting ABI evidence. It
does not prove live subscription execution.
- Initial CI history is retained: server shard 1 failed its unchanged
final rate-limit slot test (two requests allowed instead of one). No
server policy code changed here. The review follow-up requires fresh
full CI; this is not claimed fixed.
- Second CI history is retained: chat shard 2 failed the unchanged Slack
session-sync quiet-queue test (three selects during the quiet window).
The first rate-limit failure did not recur there. No chat or server
policy code changed in this PR. Final head
654bc5aa21 passed all 61 contexts (56
success, four intentional skips, one informational neutral review). Both
final-head reviews are 5/5 with no new findings; the Paperclip app
publishes its completed review as an informational neutral check.
- Live native acceptance is still pending. After deployment, retry the
original bounded task and inspect its actual shell output, exit status,
run result, and saved task state. This PR fixes the evidence gap; it
does not claim the startup incident is resolved.

## Risks

- Shared startup failures can now receive a stage category. The private
weak map cannot import provider-defined fields. Known error codes keep
priority.
- A category could point at the wrong stage. Tests inject failures at
the installation, sandbox, credential, and runtime boundaries. Existing
cancellation and cleanup tests remain in place.
- The Copilot profile identity changes because shared source changes.
Historical identities remain decodable and cannot authorize a current
launch.
- The next live failure may require another functional repair. Admission
remains closed until the requested configuration is verified.

## 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
environment failures are recorded above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 20:53:02 -05:00
DottaandPaperclip 7a8df30953 fix(runner): admit Grok effort through native session metadata (#17942)
## Thinking Path

> - Paperclip lets people manage AI agents for work.
> - Paperclip Runner must preserve each agent's model and thinking
effort.
> - The Grok migration in #17922 passes explicit effort to native
Runner.
> - The pinned Grok 1.0.13 CLI reports native session metadata instead
of standard ACP config options.
> - The standard effort guard rejects that valid session before the
first prompt.
> - This pull request binds model and effort on Grok session open and
verifies the native reply.
> - Restored sessions keep the selected effort instead of reverting to
Grok's default.

## Linked Issues or Issue Description

Related: https://github.com/paperclipai/paperclip/pull/17922

**What happened?**
A migrated Grok 4.7 agent with High effort fails at native session.open
before it can run a tool. Grok 1.0.13 has no standard configOptions
response and rejects session/set_config_option. Its native session
metadata supports the requested model and effort. A cold load also
resets effort to High unless the request supplies it again. The upgrade
banner also calls Grok “Codex”.

**Expected behavior**
The native session must acknowledge the selected model and effort before
a prompt. A cold restore must preserve both values. The upgrade banner
must describe the selected harness accurately.

**Steps to reproduce**
1. Upgrade a Grok agent to Paperclip Runner with explicit High effort.
2. Assign a bounded shell task. The pre-fix native session fails during
admission.
3. For the restore case, create a Low native session, close the process,
and load it without effort metadata. The pinned CLI reports High.

**Paperclip version or commit**
Observed at f60ac29cf1 with Grok 1.0.13.

**Deployment mode**
Cloud, with the board operator interface.

## What Changed

- Project the bound model and effort into native Grok session/new,
session/load, and session/resume metadata before transport writes and
observation.
- Require a correlated native acknowledgement with the exact model,
effort, and session identity. Reject conflicting metadata, selection
drift, stale connections, and prompts before admission.
- Connect lazy restored handles through read-only native session
inspection. Keep the existing process ownership and launch snapshot
checks.
- Replace Grok's unsupported standard config setter. Keep the existing
Claude effort path.
- Add behavioral guard cases and a real ACPX client fixture for fresh
and cold Low/High sessions. The fixture resets effort on restore if
metadata is absent, as the pinned CLI does.
- Publish Copilot profile v69 because its source identity includes the
shared runtime adapter. Preserve published v66/v67/v68 bytes and the
reviewed Grok v67 candidate as history. Keep old profiles closed for
launch.
- Explain the native protocol in the Grok Runner guide and use
provider-independent upgrade banner text.

## Verification

- Three native create/load/resume cases failed before the repair. The
pre-fix guard rejected the native metadata reply.
- Seven affected Runner test files: 234 tests passed after the master
merge. These include native Grok admission, the real ACPX transport
fixture, runtime ownership, Claude effort, and profile history.
- The review follow-up extends the same Low/High fixture through a
complete first turn after cold restore. It checks the repeated native
load, original session id, actual response event, and completed turn.
All 127 tests in the three affected Grok/adapter files passed again;
Runner typecheck and source identity checks also passed.
- All 167 existing agent form tests passed. Token gates and diff checks
passed.
- Workspace typecheck passed. Final Runner typecheck and generated
profile checks passed.
- Production `pnpm build` passed, including after the master conflict
resolution. Runner typecheck, profile history checks, and the 234
affected tests passed on the merged source. All 55 Rust ACPX library
tests also passed on the merged source.
- Real pinned Grok 1.0.13 metadata probes reproduced the unsupported
standard setter and native create/load/resume behavior. No model prompt
was sent. An earlier actual ACPX runtime probe passed fresh and cold
Low/High metadata checks. A repeat with an explicitly isolated HOME
failed authentication before session creation, so it does not count as
final live acceptance. The deterministic transport fixture is green; a
deployed shell task remains required.
- `pnpm test:run` did not complete locally. Embedded Postgres failed
during bootstrap after five attempts. This is the same local fixture
limitation recorded for #17922. Fresh PR CI must pass before merge.
- After deployment, retry the original bounded shell task with the saved
Grok 4.7/High configuration. Verify actual tool output, a successful
run, and Done state after reload.

- Final commit `810d84fd19728e7d798989582f26b05f69166db2`: all CI gates
passed. Greptile and the formal Paperclip review both reached 5/5. No
unresolved review threads remain.

## Risks

- This depends on the pinned Grok 1.0.13 native metadata format. Missing
or conflicting replies stop admission instead of silently changing
effort.
- Cold restores must make one read-only native inspection call before
admission. The existing handshake timeout and process ownership checks
still apply.
- The shared adapter changes Copilot's source identity. The new current
profile includes the final source hashes; the prior profile remains
decodable but cannot launch.
- This does not change the Grok CLI version, account selection, search
policy, dependency patch, or lockfile.

## Model Used

OpenAI Codex, GPT-6. The exact serving model ID and context window are
not exposed in this session. The agent used reasoning, code editing,
shell tools, and browser 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 17:53:58 -05:00
DottaandPaperclip 0a08d37aa0 feat(runner): recover controller authority without interrupting execution (#17097)
## Thinking Path

> - Paperclip manages agents and owns their business authority.
> - Runner owns execution transport, acknowledgements and replay.
> - A replacement controller must recover that transport without
starting another provider turn.
> - An external store can retain the required control records without
copying streamed text.
> - A duplicate local journal adds synchronous disk work without
providing the replacement server's authority.
> - This PR adds the optional recovery contract and its standalone
proof. Server adoption and browser delivery have separate owners.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

A surviving runner can reconnect to a replacement controller with its
admitted process, session and active turn.

**Current behavior**

Local controller files do not provide recovery on empty replacement
storage. Rewriting those files after an external checkpoint is installed
also blocks normal controller work.

**Proposed behavior**

An optional callback stores opaque checkpoints. The replacement restores
that checkpoint before it constructs the controller. Installing the
callback makes the external store authoritative. Local storage holds a
marker that requires restoration. Consumers without the callback retain
their file journal.

PR 1 of four: #17097 → #17439 → #17455 → #17456. Related work: #17390
and #17361. The pre-split reference remains
`codex/hot-upgrades-reference-2026-10-24`.

## What Changed

- Add opaque checkpoint encoding, restoration, incremental persistence
and authenticated sparse recovery cursors.
- Keep authentication, commands, semantic inputs and lifecycle events
behind their commit barriers. Share semantic-call ownership between live
dispatch and recovery.
- Keep streamed text out of recovery checkpoints. Preserve bounded
retention, original deadlines and admitted process identity.
- Stop normal local journal writes after external persistence is
installed. Fail closed on a local marker until external restoration
occurs. Preserve current master's staged file writes for standalone
consumers.
- Keep provider-native admission and authorization behind adapters.
Preserve historical Copilot attestations and bind the merged launch and
transport sources in v68; preserve published v66 and prior development
identities.
- Add the one-process scripted executor fixture and deterministic
outage, replay, failure and backpressure tests. Add no production test
endpoint or auxiliary process.

## Verification

The completion-recovery correction passes three restart regressions that
fail before its respective transport/driver fixes. All 230
controller/attestation cases, all 302 Codex transport cases in the full
repeat, and all three one-process fixture cases pass. The broader
Codex/Dot/Muse run passes 326 cases and times out one existing mid-goal
case; its isolated retry and complete Codex repeat pass on unchanged
source and binaries. The initial timeout remains recorded. Conformance
and replay parity pass.

Historical v65/v66 attestation bytes remain frozen; v67 binds the
changed transport. The local runner-only API-authority lane passes 2,027
cases but its 47 HTTP cases cannot initialize embedded Postgres on this
Mac. The integrated owned-database HTTP path is verified in PR 2. At
preceding head `0d8d1b8250`, the Actions workflow passes after one retry
of runner-service shutdowns. Greptile is 5/5 with no unresolved threads.
The interrupted attempt is retained. All checks on that preceding head
are terminal and green/neutral/skipped.

Run `pnpm --filter @paperclipai/paperclip-runner exec vitest run
src/control-plane/durable-prp-control-plane.test.ts
src/live/runnerd-codex-transport.test.ts --maxWorkers=1` and `node
packages/paperclip-runner/scripts/copilot-profile-identity.mjs --check`.

The [qualification
record](https://github.com/paperclipai/paperclip/blob/codex/hot-upgrades-qualification/doc/plans/2026-10-22-hot-upgrade-qualification.md)
retains exact revisions, failed attempts and qualification limits. The
local cost campaign observes zero hot-path local journal fsync calls. It
does not qualify a native harness or hosted deployment.

Master reconciliation `d5fc443626` preserves the published v66 and prior
development identity bytes and binds the combined transport in v68. All
290 focused runner/profile cases and runner typecheck pass. The first
sandboxed invocation cannot open loopback listeners; the permitted
repeat passes. Fresh CI and Greptile are pending for this updated head.

Current merge candidate `4fb3d1835b` also fixes public-reader
publication before external commit. New held/rejected-write cases fail
before correction and pass afterward. The full controller repeat passes
168 cases. The combined lane passes 390 other
recovery/transport/profile/fixture cases; its first two overlap fixture
failures are retained and corrected to observe callback entry instead of
provisional state. Runner TypeScript build and typecheck pass.
Current-head GitHub Actions is green and Greptile is 5/5 with all
threads resolved. The superseded master-reconciliation CI shutdown
remains recorded.

## Risks

The persistence callback is an acknowledgement barrier. Failure must
stop delivery. A consumer that installs external persistence must
restore its committed checkpoint before restarting; the marker is not a
recovery snapshot. Sparse display recovery does not reconstruct
acknowledged text or repeat execution. This slice has no Postgres
schema, application authorization or browser behavior.

## 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-27 17:10:32 -05:00
DottaandPaperclip 35820cf398 fix(evals): qualify Runner model receipts with separate operating reconciliation (#17929)
## Thinking Path

> - Paperclip must account for paid eval work.
> - The maintained Runner workflow distributes one immutable controller
manifest.
> - Its cost gate currently requires vendor proofs for every operating
charge.
> - Model-spend qualification must also work under an explicit policy
that keeps operating charges separate.
> - This PR applies the shared model-readiness policy to the hosted
controller.
> - It retains every operating hold and still rejects missing model
receipts and incomplete workers.

## Linked Issues or Issue Description

Refs #17928, #17889.

**What happened?**
Runner qualification requires full-lifecycle vendor operating proofs
even when the operator selects model-request readiness. That blocks the
model-token qualification path.

**Expected behavior**
An explicit `overhead.accountingReadiness: "model_requests"` policy
permits absent operating cost proofs. Supplied proofs still validate.
Complete final model receipts are required.

**Steps to reproduce**
Prepare a two-worker hosted manifest with the explicit policy and no
vendor cost proofs. Preserve missing-worker allocations, then complete
both workers and inspect the private archive summary. A second test
returns a provider refusal without terminal usage and requires failure
with the full hold.

## What Changed

- Apply the shared explicit policy to hosted capacity and observability
cost-proof admission.
- Preserve pricing windows, model bounds, immutable
source/request/runtime identities, trace quotas and every allocation.
- Reject zero or unresolved model requests in this policy, even if a
request has a provisional bound.
- Retain operating amounts and pending reconciliation through campaign
and private archive summaries.
- Document the separate model-readiness contract. Preserve strict
behavior when the field is absent.

## Verification

- Regression first failed at the original vendor-bound gate.
- All 80 controlled-eval Node checks pass, including source and copied
portable runtime checks, archived partial/missing workers, credential
exclusion and model receipt failure.
- Product readiness prerequisite #17928 has its own eval unit/typecheck
and full CI checks.
- No paid workflow, credential change or recurring activation is part of
this source PR.

## Risks

This opt-in policy does not prove a full-lifecycle operating-cost
ceiling. The report retains operating holds and pending reconciliation.
Default policies retain the existing vendor-proof gate. Source and
worker identity checks remain required. A model refusal without final
usage now fails readiness even if its reservation has a reviewed bound.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository inspection and
code execution. The exact serving 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 (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 15:41:07 -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 5982246771 fix(server): schedule custom-image setup expiry from committed changes (#17443)
## Thinking Path

> - Paperclip manages AI agent work and its execution environments.
> - Interactive image setup sessions must expire even when users leave.
> - The server currently scans these sessions on every maintenance tick.
> - Empty scans keep the instance and database active.
> - Existing session rows already record status and expiry.
> - This pull request uses transaction signals and the shared scheduler
for those rows.
> - Empty and completed setup history no longer create recurring cleanup
queries.

## Linked Issues or Issue Description

**What happened?**

The server checks custom-image setup expiry every heartbeat maintenance
tick, even when no active session exists.

**What did you expect?**

Session writes should update the next cleanup deadline. Existing
provider cancellation and cleanup ownership must remain intact. Empty
state should stay quiet.

**Steps to reproduce**

Run an instance with heartbeat scheduling enabled and no custom-image
setup sessions. Observe repeated setup-expiry reads.

Refs #17145. This is the first PR in the recurring server sleep stack.
Its base is master. The full requested scope and verification contract
are recorded in `doc/plans/2026-10-24-recurring-server-sleep-stack.md`.
Follow-up PRs target their predecessor and each own a separate reason
for recurring work.

## What Changed

- Carry the historical cleanup retry-observation fixture repair and its
existing external test-database hook at the stack foundation. Runtime
scheduling is unchanged.

- Carry the previously verified login-cleanup fixture settlement
correction at the stack foundation so every intermediate CI run receives
it. This is test-only maintenance; custom-image expiry behavior is
unchanged.

- Add a custom-image expiry worker to the existing delivery coordinator.
Remove its maintenance-tick scan.
- Signal initial creation, provider refresh, cancellation/failure, and
promotion inside their owning transaction.
- Keep the active-status predicate, earliest saved expiry, and provider
behavior in the custom-image service. Shared code gains only a queue
topic.
- Preserve startup recovery, bounded retries, concurrent write
generations, and drain deferral. No tables or external alarm changes.
- Add PostgreSQL lifecycle tests and repair this suite's database
cleanup callback. A dedicated external test URL permits disposable
PostgreSQL when the host cannot start another embedded cluster.

## Verification

Current head: `3507c6be1e054fdd93353d5dcf77d4899b44518f`. This remains a
single-duty PR stacked on master.

- Integrated pinned master `8548173fc9efdc0fa07644fb92dcc0b6851a95e5`
with normal merges. Every branch passed generated-schema checks and its
target-branch migration-order gate. Existing SQL is unchanged; the 25
stack migrations follow master’s new migration.
- Duty-specific producer coverage, lifecycle tests, and earlier failure
records:
[2026-10-08-instance-sleep-and-scheduler-inventory.md](https://github.com/paperclipai/paperclip/blob/3507c6be1e054fdd93353d5dcf77d4899b44518f/doc/plans/2026-10-08-instance-sleep-and-scheduler-inventory.md),
[2026-10-24-recurring-server-sleep-stack.md](https://github.com/paperclipai/paperclip/blob/3507c6be1e054fdd93353d5dcf77d4899b44518f/doc/plans/2026-10-24-recurring-server-sleep-stack.md).
- Combined tip `51e6cbe67979b55b340ea9f0f434c5b5c682ccd6`: **355
startup/cancellation/recovery/dispatch/preservation tests**, **75
connection-management tests**, and production server typechecking pass.
These combined checks do not mean every intermediate PR independently
ran the full repository suite.
- Real master-to-stack database upgrade passes: **379 unchanged prior
migration receipts plus 25 new migrations**, with the gateway
responsibility fixture preserved.
- Owning-branch checks: 84 runner installation/settlement cases plus
runner typechecking and generated TypeScript/Rust profile agreement; 253
GitHub review workflow cases. Stop-attribution and held-worker readiness
regressions failed before their fixes.
- Failure accounting: the initial combined run passed 349 cases and
failed six idle assertions in a reused preservation database containing
old cancelled runs. Repeating the combined command with a fresh
preservation database passed. Earlier invalid project selection, merge
import/type errors, and the interrupted full local suite are not counted
as passing checks.
- **Latest-head CI and review remain required.** Prior CI findings
include GitHub idle observation, route teardown, attention cleanup,
touch-picker E2E, workspace health, and voice-cleanup timing; local
passes do not erase those failures. No full local repository-suite,
deployed sleep, fleet cost, or live Copilot qualification claim is made.

## Risks

- Signals cover supported service producers sharing the DB owner.
Independent SQL and another process require the existing
restart/reconciliation contract.
- Failed provider cancellation retains the existing failed-session and
historical-cleanup behavior. This PR changes scheduling, not teardown
authority.
- Active rows without an expiry preserve the existing behavior; no
deadline is invented. Cloud sleep eligibility remains conservative.
- The worker remains in the existing heartbeat-enabled startup path. It
does not change disabled-scheduler behavior or prove deployed
suspension.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and code execution. The exact
serving model identifier and context window were not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#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

Review follow-up: Added a real producer commit during a paused deadline
read. Updated startup assertions for coordinator ownership and removed
added code comments. The three affected suites pass (102 tests). The
separate login-cleanup suite also passes locally (16 tests); its prior
CI consume test timed out, and the fresh complete CI run passed.
External PostgreSQL tests now use the repository guard for disposable
databases ending in `_test`.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 14:17:01 -05:00
DottaandPaperclip 8548173fc9 feat(evals): connect hosted Runner costs and traces (#17889)
## Thinking Path

> - Paperclip manages AI agents and measures their behavior with Runner
evaluations.
> - The cost controller, native tracing, private receipts and portable
runtime are on master.
> - The maintained live workflow still launches the provider CLI
directly.
> - Independent workers need one shared selection and disjoint budget
allocations.
> - Reports must keep unresolved allocations when a worker produces no
evidence.
> - This PR connects the maintained workflow to the existing controller
and private archive.
> - Operators can inspect known costs, conservative holds and trace
evidence before qualifying paid recurrence.

## Linked Issues or Issue Description

Refs #17452, #17469, #17493, #17506, #17523.

**Current behavior**

The live Runner workflow does not use the merged cost/tracing
controller. Attempt-only aggregation cannot reconstruct a campaign when
every worker archive is absent. Ordinary Actions artifacts in this
public repository are readable by authenticated public GitHub users.

**Proposed behavior**

Controlled runs prepare one manifest, bind every selected request,
enforce disjoint allocations and retain evidence in private storage. The
report starts from the full retained manifest. Missing workers keep
their allocations. The workflow rejects retries, unsupported providers,
changed requests and absent or stale operating bounds before provider
work.

**Reason and benefit**

The maintained workflow needs auditable costs and traces, including
failures and missing receipts, before paid recurrence can be qualified.

## What Changed

- Add controlled mode as the manual default and the only scheduled mode.
Legacy mode remains explicit for other manual provider qualifications.
- Prepare the full request selection and one shared manifest. Bind
current run, first attempt, code, definitions, executable hashes and
exact profile allocations.
- Verify the copied controller and manifest before provider credentials.
Require the controlled target to equal the trusted workflow revision
before private archive access.
- Reuse private archive retention for the controller policy, cell
attempts and canonical report. AWS credentials remain transfer-step
outputs. Controlled raw evidence is never uploaded as an Actions
artifact.
- Replay a retained manifest with partial or empty worker evidence.
Count operating holds once and preserve known partial charges.
- Pin the controller to an explicitly reviewed compatible lockfile
digest. Reject resolver or byte drift before a frozen, script-free
install into a job-local store. Record the lock digest in the runtime
receipt and verify it again in private preparation.
- Build the portable controller without secrets, private environment
access or OIDC. Private preparation verifies that artifact and performs
no dependency install. OIDC jobs use no mutable dependency resolution or
shared cache.
- Add synthetic source/copied-runtime tests, executable workflow
admission tests, private archive tests and an operator runbook.

## Verification

- Controller, campaign, portable runtime and workflow tests: 104 passed.
This includes real aggregation from an isolated reporter without source
dependencies, safe diagnostics, driver drift, distinct evidence binding
and reviewed-lock drift. Real private Codex/Claude requests also pass
through an independently verified copied runtime with fake transports.
- Private transport and workflow contracts: 35 passed. Executable/static
workflow guards: 13 passed.
- Paired private report tests: 166 passed; Evalbook discovery: 7 passed.
- `pnpm -r typecheck` and `pnpm build`: passed.
- `pnpm test:e2e:runner:typecheck`, `actionlint
.github/workflows/runner-protocol-live-evals.yml` and `git diff
--check`: passed.
- `pnpm test:run` hit repeated local embedded PostgreSQL initialization
failures in unrelated DB-dependent server tests. Its owned process tree
was stopped after preserving the log. This is a local verification
limitation; current-head CI remains required.
- An earlier head hit one unchanged Rust cleanup assertion. The exact
test passed locally and the final head passed the full Rust lane; the
initial failure log is retained.
- On the final head, one unchanged chat idle-queue assertion failed once
in CI. Its single scoped retry passed. All test jobs and the final
aggregate gate passed on commit
`2e328fa53dd296174d59d19f14f068aeeb0b82d8` (CI run 40535692048, attempt
2).
- No paid model, Braintrust or cloud calls. No live variables, secrets,
schedules or resources changed.

## Risks

- Controlled mode fails closed until a reviewed
`RUNNER_PROTOCOL_EVAL_CONTROLLER_POLICY_JSON` and a compatible private
eval SHA exist. `all` does not silently become a supported subset.
- The reviewed policy must cover setup, model requests, trace/gateway
processing, archive transfer and retained storage. Hash binding does not
establish vendor billing bounds. This PR does not enable recurrence or
release historical holds.
- The controlled policy must pin `controllerLockSha256`; it never
accepts a resolver-generated digest automatically. No lockfile is
committed. A changed compatible lock needs review.
- Legacy browser verification now requires the committed frozen
lockfile. A stale lockfile fails closed; controlled preparation has no
dependency install.
- Workflow cancellation can prevent the final report. The full manifest
is retained before provider work and remains the starting point for
reconciliation.
- The workflow exceeds 1,000 lines because the shared shard anchor,
dependencies, environment expressions and credential boundaries belong
to one declarative job graph. Request preparation, accounting, archive
safety and runtime verification stay in separately tested modules.

## Model Used

OpenAI Codex, GPT-6-based coding agent with tool use and code execution.
The host does not expose an exact deployment 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 the relevant tests locally and they pass; the broad
local suite limitation is documented above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green on the final head
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups;
the secondary reviewer is also 5/5
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 11:38:16 -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