Commit Graph
1917 Commits
Author SHA1 Message Date
DottaandPaperclip 8161f2a813 fix(server): wake tool-review card repair from committed changes (#17468)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tool requests and invocations store the execution outcome. Review
cards show that outcome.
> - The maintenance tick repeatedly joins these tables even when every
card matches.
> - Committed changes can wake repair. Existing rows can restore work
after restart.
> - A large company backlog also needs a bounded pass so other companies
and shutdown can proceed.
> - This PR uses the shared coordinator for scoped repair, continuation
and failure deadlines. Settled history becomes quiet.

## Linked Issues or Issue Description

**What happened?**

The aggregate maintenance tick scans tool-review projections on every
tick. Matching terminal history still causes database work. A company
with many stale cards can also hold one worker in an unlimited drain.

**What did you expect?**

Relevant writes and startup should wake repair. Failed or unresolved
cards should retain recovery. Matching history should cause no recurring
SQL. Each normal worker pass should honor drain and shutdown.

**Steps to reproduce**

Start an instance with completed tool requests and matching cards. Leave
it idle. The old maintenance tick keeps querying for mismatches. A large
mismatch backlog also drains without a row limit or cancellation check.

This is slice 07 of the sleep migration. It now targets master after
#17458 landed. Related owners are pending expiry #17453 and approved
recovery #17454. Their execution duties remain separate from card
repair. The prior open-PR search found no duplicate projection
migration.

## What Changed

- Register company-scoped projection repair with the existing delivery
coordinator. Remove its recurring aggregate-tick scan.
- Signal through the existing review-write transaction owner and linked
interaction mutations. Ordinary unlinked confirmations do not wake
repair.
- Keep interpretation, locks, current-state checks, activity and
continuation callbacks in the gateway. A repair never repeats a provider
tool call.
- Limit each normal worker pass to 500 rows. Check abort and admission
between rows. Save company progress through truncated and failed passes
so blocked early pages cannot hide later cards.
- Schedule truncated work after one second. Back off unresolved cards
from thirty seconds to five minutes; fresh committed hints reset the
delay. Clear obsolete cursors after empty reconstruction.
- Skip repeated company discovery for scoped hints and the extra
candidate query on an empty sweep with no saved cursor. Attempted or
resumed passes still verify remaining mismatches because reflection
returns no settlement result.
- Add generated migration `0386_steady_epoch.sql` for the existing
`(company_id, interaction_id)` lookup. Use the existing concurrent-index
executor. Add no table.

## Verification

Current candidate: `d4706fbf2a04a00ade30181eb1bd9322e8455818`. All 222
cases in the full gateway/projection/interruption, startup and
scoped-deadline suites pass without skips after the query/retry
efficiency repair; server types and build pass. A single committed
company hint with matching retained history and a separate empty direct
sweep each perform one candidate query. The unresolved-card regression
failed before repair and now verifies backoff through the five-minute
cap, prompt producer activation and quiet after settlement. An initial
assertion incorrectly assumed an entire approval emitted one wake; its
separate real writes require isolating the single-hint measurement.

The earlier master integration `fe6e10629b` additionally established the
following evidence before this efficiency follow-up:

- **320 cases pass** across full gateway/projection/interruption,
startup, scoped-deadline, narrowed identity-read and authenticated
gateway HTTP suites. The HTTP selection includes all 81 cases.
- **Six real PostgreSQL regressions failed before their fixes:** pass
bounds, abort, drain, progress past unprojectable pages, progress past
failed pages, and first repair after empty reconstruction. The complete
owning selection passes all 220 cases.
- Server production typechecking and build pass. Generated index
migration, snapshot drift and numbering/safety checks pass. The five
newest snapshots remain; master journal entries are unchanged.
- A real missing-link query on 30,000 history rows changed from a
sequential scan that filtered all 30,000 rows and touched 429 buffers to
the new index with two buffers. Both treatments returned no rows.
- Normal master integration preserves 35 independent performance files
exactly. The gateway also retains master's narrowed identity read.

Commands include `pnpm --filter @paperclipai/server typecheck`, `pnpm
--filter @paperclipai/server build`, and server Vitest selections for
`tool-gateway-service`, `server-startup-feedback-export`,
`scoped-deadline-work`, `run-identity-projections`, and
`connection-management.integration`, with separate PostgreSQL test
fixtures.

[The behavior and failure audit](doc/idle-tool-review-projection.md)
records the producer contract, earlier fixture failures, index
measurement, red/green regressions and integration evidence. Fresh
current-head CI and Greptile/Ponytail remain required before merge.

## Risks

- Signals use the existing single-active-writer database owner. Another
replica or independent SQL writer needs a wake contract.
- An already issued database query or reflection finishes before
cancellation takes effect. Checks between rows bound further dispatch.
- Legacy manual/global and disabled-scheduler one-shot repairs keep
their complete-sweep behavior. The normal coordinator worker always
supplies its row budget and admission controls.
- Unprojectable cards and thrown failures retain recovery with a
five-minute backoff cap. The company mismatch query still grows with
terminal history. Empty history does not retain a recurring scan.
- The index migration uses concurrent creation and the existing
invalid-index recovery path. Prior SQL and journal entries remain
unchanged.
- Cloud sleep eligibility and external-wake coverage do not change.
Local worker quiet is not proof of host or database 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 17:09:31 -05:00
DottaandPaperclip f6bc653f7f fix(server): schedule interrupted tool claims by their deadlines (#17458)
## Thinking Path

> - Paperclip governs tool execution and keeps durable approval records.
> - An interrupted execution may have produced an external effect
without a saved final request state.
> - The maintenance tick currently scans executing requests even when
none exist.
> - Every executing claim already has a ten-minute stale deadline.
> - This PR schedules that deadline from committed claim changes and
clears it after settlement.
> - Recovery preserves saved provider outcomes and quarantines unknown
outcomes without another provider call.

## Linked Issues or Issue Description

Refs #17454. This is the sixth recurring-server sleep slice, stacked on
`codex/sleep-05-approved-tool-recovery`.

**Problem**
The aggregate maintenance tick repeatedly searches for stale executing
tool requests. Its settlement can overwrite a saved successful
invocation with an unknown-outcome failure after a crash between
invocation and request writes.

**Proposed Solution**
Use the existing review notification boundary and shared scheduler. Read
the earliest executing claim deadline through a partial index. At that
deadline, lock invocation then request, recheck claim identity, and
atomically settle from the saved outcome or quarantine the unknown
outcome.

**Alternatives Considered**
A longer polling interval still queries empty work. A new queue would
duplicate existing records. Replaying an interrupted call can duplicate
an external effect. Treating every stale request as unknown discards
already saved outcomes.

## What Changed

- Coalesce sequential review notifications for up to 30 seconds while
preserving already loaded recovery deadlines. Do not schedule scans when
no notification or execution deadline remains.

- Extract interrupted-execution deadline lookup and settlement into the
owning tool-review service.
- Register its worker at startup. Use committed claim/result changes to
update the existing ten-minute deadline; retry failed settlement after
30 seconds.
- Preserve terminal invocation results, reasons, and completion times
when repairing request state.
- Settle uncertain request/invocation state atomically with the existing
unknown-outcome reason, without dispatching a provider call.
- Notify all gateway claim and settlement paths through the existing
review transaction helper. Keep framework wiring and the shared
scheduler free of provider-specific behavior.
- Add an idempotent concurrent partial index for executing deadlines.
Preserve the combined manual sweep and scheduler-disabled startup pass.
- Remove interrupted scanning from the aggregate tick. Interaction
projection repair remains the next separate duty.

## Verification

Current head: `648d8a9a64ded15deeeb331545b92a12d69e277d`. The final
commit changes no files and requests CI after the master retarget. A
preceding run appeared while that trigger was being published; it was
observational delay, not an established CI outage. No test rerun or
bypass was used to turn a failure green. Source remains identical to the
198-test passing integration, apart from the already recorded ledger
update. Fresh checks and both automated reviews must qualify this
current head before merge.


Current master-targeted head:
`d55e44b376555e4926bb2c2a0e4dcfb431324162`. Parent #17454 landed as
`77295faebc8`; a normal merge reconciles that squash. Every conflicted
master file was checked against the already-integrated parent, and all
matched byte-for-byte. Each interruption-only hunk was retained; the
complete integrated source tree matched the 198-test passing
`848f1b87b3` exactly before the sole final documentation update. All
master migration journal entries are unchanged, with only this PR's
executing-deadline index appended. Server types pass. Fresh CI and
current-head Greptile/Ponytail are required before the next authorized
merge.


Latest published integration:
`848f1b87b3a6646ae4e56e8ab142f64889d7a69c`, normally merging
approved-recovery parent `23868c1751`. All 198
gateway/interruption/startup/deadline cases and server production
typechecking pass. Both parent approval fixes and all interruption tests
are retained. The two merge conflicts preserved the interruption import
alongside the parent's claim-bound hash helper and preserved the
parameterized historical test helpers. This remains stacked on #17454;
fresh CI and both automated review gates are required after integration.


- Review documentation correction at
`c985eb9d1b48a481909de6a1c2d89d7af11bfc03`: the focused real-PostgreSQL
interruption-worker selection passes all 16 cases; 124 unrelated cases
were filtered out. The docs now correctly name 16 cases and six saved
terminal statuses. No production behavior changed in the correction.
Fresh remote CI/review is pending after integrating the verified parent.

Approved delegated Test-tab calls now evaluate caller and target
policies in the existing claim transaction. Real HTTP regressions first
showed a missing caller charge and shared-limit self-rejection. All 78
connection-management cases and 92 gateway cases now pass on the owning
branch, along with server production typechecking. All 78
connection-management cases also pass at combined tip
`d25f830db89c1623bff3547bfc68015c1c66e0cf`. The three new cases cover
shared charges, separate charges, rollback on denial, duplicate
approval, and rejection of a later authorized call. Intermediate
counter/identity fixture failures and a reused-database Slack collision
are recorded in [the owning
audit](https://github.com/paperclipai/paperclip/blob/f6a5949fb726f71c247950714adecb275655284f/doc/idle-approved-tool-recovery.md#delegated-test-tab-admission-after-policy-changes).
The earlier combined checks below remain evidence for their stated
revisions. Current-head CI and review remain required.

Current head: `f6a5949fb726f71c247950714adecb275655284f`. This remains a
single-duty PR stacked on #17454.

- 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-24-recurring-server-sleep-stack.md](https://github.com/paperclipai/paperclip/blob/eaac8d343e5ef4d2c13cdf7cb7607cb5a498e9a2/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 the existing single-active-writer database owner.
Independent writers and replicas need an explicit wake contract.
- The ten-minute policy is unchanged. A provider call that outlives its
claim remains an uncertain outcome; this worker never retries the
external call.
- Interaction projection follows authoritative settlement outside its
transaction. Its separate existing repair duty still handles an
interrupted projection.
- Non-executing review writes can cause one empty reconciliation.
Without an executing claim or failed attempt, no recurring deadline
remains.
- Cloud eligibility and external-alarm coverage remain conservative.
Worker quiet does not prove actual host or database 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 16:33:30 -05:00
DottaandPaperclip 77295faebc fix(server): recover approved tool actions from committed changes (#17454)
## Thinking Path

> - Paperclip manages agent work and its governed tool calls.
> - A human approval can persist before the approving process dispatches
the tool.
> - Recovery currently scans approved requests on every maintenance
tick.
> - Completed and deliberately inert approvals do not owe another
execution.
> - Test-tab approval also needs a shared execution claim before
recovery can safely race the foreground path.
> - This PR wakes recovery from committed changes and retries only
unresolved approvals.
> - Idle history becomes quiet while existing approval and execution
checks remain with the gateway.

## Linked Issues or Issue Description

Refs #17453. This is the fifth slice of the recurring-server sleep
migration, stacked on `codex/sleep-04-tool-review-expiry`.

**Problem**
Approved tool requests are scanned periodically even when no executable
work remains. The Test-tab foreground path lacks the request claim
needed to admit concurrent recovery safely.

**Proposed Solution**
Use the existing transaction-aware review notification boundary and
shared deadline worker. Keep signed-payload interpretation, current
policy and target checks, and provider dispatch in the gateway. Share a
claim between Test-tab foreground and recovery, then persist both
authoritative outcome rows atomically.

**Alternatives Considered**
A longer interval still scans idle history. A new durable queue would
duplicate existing request/invocation state. Dispatching Test-tab
approvals without a claim risks duplicate external calls.

## What Changed

- Recheck both principals for delegated Test-tab approvals. Save their
rate receipts in the same claim transaction, share only the same bucket,
and roll back new charges on denial.

- Preserve delegated gateway authorization and both issuer/target rate
receipts inside the existing claimed-invocation transaction; retain the
durable actor during approved replay.

- Expire stale managed connector payloads before consuming approved-tool
admission.

- Persist current rate-policy charges and their invocation receipts
atomically before dispatch, preserving exact approval claim fencing and
read-only preflight.

- Recover approved requests at startup and after committed review
changes; retry only unresolved approvals.
- Leave legacy agent approvals without execute-on-approve intent inert.
Repair completed Test-tab history without another provider call.
- Fence Test-tab execution and outcome settlement with an atomic claim
shared by both callers. Revalidate the approved target and current
policy before dispatch.
- Keep provider calls outside database transactions. Retain quarantine
for interrupted execution and unknown outcomes.
- Add a concurrent, idempotent partial index for approved-request
pagination. Reuse the parent's company-scoped review signals and shared
scoped deadline worker.
- Remove approved scanning from the aggregate tick. Preserve the public
combined sweep and scheduler-disabled startup behavior.
- Document producer ownership, quiet states, lifecycle behavior, and
remaining recovery duties.

## Verification

Latest published head: `23868c1751c100a27f58087f7ce16b93c52d4eba`,
targeting master. The review-found delegated gateway pool deadlock is
repaired by passing the admission transaction through token and
issuer-authority reads. Foreground and recovery each reproduced the
deadlock with a one-connection pool; all three constrained-pool cases,
including revoked authority, now pass. All 81 HTTP integration cases
pass. The historical foreground rate-slot regression also reproduced
before its repair; verified preview hashes are accepted only by
read-only preflight, while consuming admission still requires the
complete identity under the exact claim. Five full suites passed 329
cases; the gateway service then passed all 141 cases after two
additional mixed historical hash controls. Production types/build passed
before the final normal integration of master `35820cf398` (including
independent Grok/Runner changes); integration validation is running.
Initial fixture/assertion errors and the prior E2E
restoration/cancellation deadlock remain recorded in [the owning
audit](doc/idle-approved-tool-recovery.md#gateway-admission-uses-its-transaction-connection).
Fresh-head CI, Greptile 5/5, and passing Ponytail are still required
before merge.


- Master landing reconciliation at
`8dfe3958db6e4e8a0b7499f3f5be0a396ca77361` after #17453 merged:
production and server test files are byte-identical to the accepted
320-case repair. The landed migration journal prefix is unchanged, and
#17928's independent eval reporting changes are preserved. Fresh CI and
reviews on this exact head are required before merge.

- Historical-identity repair published at
`096b7c7198c3ca864aca9377e261cbaa0a8aad6f` (production/test source
identical to integrated acceptance
`81231824d773a79fc50c835eccf7d9b3977e79fc`): all 320 accepted gateway,
policy, startup, preparation-timing and authenticated HTTP management
cases pass. Server types and the production server build pass. Four real
historical sensitive-argument regressions failed before repair;
invalid-signature, foreign-hash and stale-claim controls remain denied
without dispatch or identity changes. Both agent and Test-tab calls
deliver the original signed arguments once, and new rate policies still
apply.
- The first integrated combined run passed 319 cases and hit a Slack bot
ownership collision left in a reused HTTP test database. The guard
correctly returned 409. The full 78-case HTTP suite passed on a fresh
dedicated fixture without product or assertion changes. Earlier
fixture-construction errors are distinguished from the four real
regressions in the audit document. Fresh remote CI and reviews remain
required.

- Parent reconciliation at `736e7f56097055e21ce13b4e45d9033391483af8`:
299 cases pass (221 full gateway/policy/startup cases and 78
assembled-server connection management cases), with no skipped cases.
Server types pass. This includes real delegated Test-tab approval
admission for newly added shared and caller rate rules. Fresh remote CI
and Greptile review remain required.

Approved delegated Test-tab calls now evaluate caller and target
policies in the existing claim transaction. Real HTTP regressions first
showed a missing caller charge and shared-limit self-rejection. All 78
connection-management cases and 92 gateway cases now pass on the owning
branch, along with server production typechecking. All 78
connection-management cases also pass at combined tip
`d25f830db89c1623bff3547bfc68015c1c66e0cf`. The three new cases cover
shared charges, separate charges, rollback on denial, duplicate
approval, and rejection of a later authorized call. Intermediate
counter/identity fixture failures and a reused-database Slack collision
are recorded in [the owning
audit](https://github.com/paperclipai/paperclip/blob/bcca5b006976a471f4afd1f70c4031aa40a2b3f7/doc/idle-approved-tool-recovery.md#delegated-test-tab-admission-after-policy-changes).
The earlier combined checks below remain evidence for their stated
revisions. Current-head CI and review remain required.

Current head: `bcca5b006976a471f4afd1f70c4031aa40a2b3f7`. This remains a
single-duty PR stacked on #17453.

- 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-24-recurring-server-sleep-stack.md](https://github.com/paperclipai/paperclip/blob/a021467f04d22be42ee5b0c87b6583b2300a62a9/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

- Notifications cover the existing database-owner, single-active-writer
contract. Independent SQL writers and other replicas need an explicit
wake path.
- Unknown provider outcomes cannot be replayed safely. Failed result
persistence retains an executing claim and the existing stale-execution
quarantine.
- Interrupted execution and terminal interaction projection repair
remain periodic until their separate slices. This PR changes only
approved recovery.
- A pending-only review write can trigger one empty approved-recovery
pass. Settled idle work schedules no further scan.
- The partial index uses the existing top-level concurrent migration
executor. Snapshot pruning follows repository policy.
- Cloud sleep eligibility and external alarm coverage remain unchanged.
Worker quiet is not proof of deployed instance 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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 16:10:44 -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
DottaandPaperclip d108aeeaaf fix(server): schedule pending tool-review expiry from committed changes (#17453)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Governed tools can wait for a human review before execution.
> - Pending reviews already save a deadline and must reject approval
after expiry.
> - The server currently scans for expired reviews on every maintenance
tick.
> - Empty scans keep the database active without advancing work.
> - This pull request schedules pending review expiry from committed
changes and saved deadlines.
> - Configured idle state and resolved history no longer cause this
expiry scan.

## Linked Issues or Issue Description

**What happened?**

The combined tool review sweep repeatedly queries pending expiry even
when no pending request has a deadline.

**What did you expect?**

Signing or resolving a request should update the expiry schedule. A
saved expiry should trigger settlement. Once no expiry remains, this
duty should stop querying.

**Steps to reproduce**

Start a claimed instance with heartbeat scheduling enabled. Leave it
idle with no pending tool reviews. Observe pending-review expiry
discovery in the maintenance sweep.

Stacked on #17450; earlier slices are #17446 and #17443. These all reuse
the delivery and transaction foundations from #15625. This PR owns
pending-review expiry only. Approved-action recovery,
interrupted-execution quarantine, and terminal interaction projection
repair remain separate migrations. No duplicate pending-review expiry
migration was found in the open PR search; credential lifetime changes
in #17221 and #17274 concern the parent credential slice.

## What Changed

- Replace repeated company review-deadline aggregates with an indexed
single-row lookup. Add and replay a concurrent covering-index migration
and generate combined snapshots throughout the stack.

- Extract pending-expiry selection and settlement into its owning
service. Keep provider execution and interaction publication with the
gateway.
- Signal deadline assignment and pending resolution inside the owning
SQL transaction. Preserve outer commit/rollback and central uncertainty
handling.
- Register company expiry deadlines with the shared scoped coordinator.
Reconstruct on startup; normal producer hints reload only their company.
Preserve writes during drain and concurrent reconciliation.
- Settle request expiry and invocation failure atomically. Keep
interaction projection recovery in the existing separate sweep.
- Remove pending-expiry scanning from the main tick. Preserve the
combined manual API and startup-only behavior when scheduling is
disabled.
- Add a partial pending-expiry index through an idempotent concurrent
migration. No queue table is added.
- Document supported producers, quiet states, remaining duties, and
external wake limits.

## Verification

- CI run `40574661575` at `f5c935d1b89877033eb82bf890f867baeb372ef3`
lost the runners for general-server shard 9/12 and E2E shard 2/8 at
20:09:03 UTC. Both job logs explicitly show a runner shutdown signal
followed by cancellation; no test assertion failure was reported by
those jobs. A single infrastructure retry is justified once the run
completes; it has not been issued yet. Both current-head reviews are
5/5, and CI must still be green before merge.

- Current master landing at `f5c935d1b89877033eb82bf890f867baeb372ef3`:
128 complete gateway expiry, startup, scoped deadline and
preparation-timing cases pass with no skips. Server types and the
production server build pass. Landed tracing changes from #17918 are
preserved. The master migration journal prefix remains semantically
identical, with only this PR's two migrations added. Fresh remote
CI/review is required before merge.

- Parent reconciliation at `17539e2a6cf8ac4922b3cbe06af6df361bfe5665`:
116 tests pass across the full tool gateway service, startup and scoped
deadline suites against a dedicated migrated PostgreSQL database. No
cases were skipped. Server typecheck passes. Fresh remote CI and review
are pending.

Current head: `ec28076f825e76a267f05517ff0c44a3e2283ce7`. This remains a
single-duty PR stacked on #17450.

- 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-24-recurring-server-sleep-stack.md](https://github.com/paperclipai/paperclip/blob/ec28076f825e76a267f05517ff0c44a3e2283ce7/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

- All supported producers must share the database signal owner.
Independent SQL writers and other replicas need a live notification
contract; startup alone does not cover them.
- A crash after authoritative expiry and before interaction projection
still relies on the existing projection-repair duty. That duty,
approved-action recovery, and uncertain execution recovery remain
periodic in this slice.
- Unknown external outcomes remain quarantined. Provider calls stay
outside SQL transactions. Expiry is still checked before approving a
request even if physical cleanup waits during drain.
- The new index uses the existing top-level migration executor because
PostgreSQL concurrent index creation cannot run in a file-wide
transaction. Snapshot pruning follows the repository rule.
- This establishes worker quiet and reactivation, not deployed host
suspension. Existing Cloud idle-safety and external alarm coverage
remain unchanged.

## 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

Latest-head CI is now green after one evidence-backed retry. Greptile is
5/5 and all review threads are resolved.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 15:26:19 -05:00
DottaandPaperclip 5398275d2a fix(server): schedule gateway credential expiry from committed changes (#17450)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The tool gateway stores credentials for sessions and named gateways.
> - Those credentials already contain expiry dates.
> - The server repeatedly scans their tables even when no expiry work
exists.
> - Creation signals and saved deadlines can drive cleanup without idle
scans.
> - This PR registers that work with the existing coordinator.
> - Authentication continues to reject expired credentials independently
of physical cleanup.

## Linked Issues or Issue Description

Refs #17446, #17221, #17274. This is the third sleep-migration slice,
stacked on #17446.

**What problem does this solve?**
Gateway credential cleanup queries PostgreSQL on every maintenance tick,
including empty tables and retained non-expiring tokens.

**What is the proposed solution?**
Signal expiring token/session creation from its transaction. Restore the
earliest saved expiry at startup. Retry only while cleanup or
reconciliation remains outstanding.

**Why is this useful?**
Configured idle gateways no longer create recurring expiry traffic.
Existing credential data remains the durable source of truth.

Related work: #17221 and #17274 change run-token lifetime and cleanup
eligibility. They remain separate. This PR preserves current master
authorization and deletion rules. When those PRs are combined, update
the deadline query and signals to match their new operator-token expiry
predicate; run-token idle markers must not keep this worker scanning.
Retain the separate run-liveness reaper and run both regression suites.
Text mergeability is insufficient evidence for that integration.

## What Changed

- Make the credential test clock follow real scheduled work without
overshooting future-expiry assertions; production behavior is unchanged
by this fixture follow-up.

- Coalesce sequential credential notifications within the former cleanup
cadence, preserve loaded expiry deadlines and immediate authentication
rejection, and bound scheduled deletion to 500 rows per pass.

- Added transaction-aware intent before the two existing credential
inserts. Non-expiring named tokens do not signal expiry work.
- Added earliest-expiry selection in the gateway service and a narrow
registration wrapper for the shared deadline helper.
- Removed gateway credential cleanup from the aggregate maintenance
tick. Startup reconstructs saved deadlines. Heartbeat-disabled instances
retain their startup-only cleanup behavior.
- Preserved expiry/revocation checks, run authorization, audit behavior,
and the existing 500-token cleanup batch limit.
- Added real PostgreSQL tests and a lifecycle/producer document.
Tool-action review recovery remains a separate slice.

- Drain all expired session/token pages in explicit and
scheduler-disabled startup cleanup, while retaining one-page scheduled
passes and authentication enforcement.

## Verification

- At `907098cd3656bac59c60220c73b085d0349d4b5f`, all 290 Runner
transport tests pass locally (including all seven prepared-environment
variants). CI run `40570815360` attempt 1 had one provider-drain
settlement failure in the `close-attachment` case; the identical source
passed the preceding CI lane. A single failed-job rerun is in progress.
The failure remains recorded; no shutdown assertion or production
behavior was changed to suppress it.

- Master landing reconciliation at
`907098cd3656bac59c60220c73b085d0349d4b5f` after #17446 merged: all
production and test files are byte-identical to
`24318d9b99ee7f044a864ff3981fc1929bf3e509`, where the 150-case
acceptance and server types passed. Only commit ancestry and the plan's
merged status changed. Fresh CI/review is pending on this head.

- Parent reconciliation at `24318d9b99ee7f044a864ff3981fc1929bf3e509`:
150 affected tests pass across gateway credential expiry, the complete
tool gateway suite, custom-image worker and startup. The accepted
PostgreSQL runs skip no cases. Server types pass. Existing direct tests
cover sequential-write coalescing and saved-deadline precedence; the
older Ponytail finding needs a fresh review. Remote CI is pending.

Current head: `10c85a5eaa288867aa2997a27aee5f675c2a713d`. This remains a
single-duty PR stacked on #17446.

- 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/10c85a5eaa288867aa2997a27aee5f675c2a713d/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/10c85a5eaa288867aa2997a27aee5f675c2a713d/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

- Shared-owner signals cover supported local producers. Independent SQL
writers or another replica need a separate ingress contract; startup
recovery is not live discovery.
- This is scheduling only. The open run-token lifetime PRs need semantic
integration as described above before combining their behavior.
- Expiry cleanup can wait during drain; authentication still enforces
expiry on use. Existing Cloud safety gates are preserved. Local
deadlines do not prove external wake coverage or deployed suspension.
- Revocation does not move expiry. Non-expiring tokens remain retained
by design; this PR does not invent a retention deadline.

## 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

Latest-head CI is now green after one evidence-backed retry. Greptile is
5/5 and all review threads are resolved.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 14:58:11 -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
DottaandPaperclip bd382eee53 fix(recovery): explain retained source verification failures (#17773)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Workspace recovery must prove the identity of retained work before
it uses an allocation.
> - The verifier rejects several different contracts with the same
`source_binding_invalid` code.
> - A saved Retry can therefore stop before file preservation without
enough evidence for a safe repair.
> - Operators need a bounded observation of the selected source without
another attempt or weaker guards.
> - This pull request records closed failure reasons and adds an
explicit read-only inspection on the run page.
> - The benefit is a precise next diagnostic step while the saved work,
intent, and ownership fences remain intact.

## Linked Issues or Issue Description

Refs: #17741, #17053. This is a diagnostic follow-up. It does not change
recovery admission or the retained-source acceptance policy.

**What happened?**

A retained-source recovery exhausted in `verify_execution` with only
`source_binding_invalid`. Run and task diagnostics could not distinguish
an invalid reference, lease policy, source binding, or reopened
allocation. The normal recovery-actions read can also revalidate
recovery state, so it was not a safe substitute for a current read-only
inspection.

**Expected behavior**

Record an allowlisted reason at the rejected guard. Allow a reader to
inspect one exact task/run/action without changing its attempts, saved
input, receipts, or ownership. Clearly separate the recorded failure
from current identity observations.

**Steps to reproduce**

1. Prepare a terminal native run with a retained-source action and a
lease policy of `reuse_by_environment`.
2. Attempt source verification. The guard must still reject that policy.
3. Open the failed run and choose Inspect recovery, then Inspect current
source. The diagnostic should name `lease_policy_not_retained` and the
allowlisted policy.

## What Changed

- Split existing source-binding guards into closed reason codes. Keep
each acceptance predicate and physical recovery action unchanged.
- Persist validated, path-free reason/policy detail with future system
recovery failures. Keep historical generic records compatible.
- Add an explicit query on the existing task recovery-actions GET. Exact
company/task/run/action selection bypasses read revalidation. Run
selection lists at most 20 actions; inspection stops before per-lease
lookup when a record has more than eight sources.
- Add a manual inspection control on native export-failure run pages.
Keep resolved retained actions inspectable. Show recorded failure and
current recorded-source identity separately.
- Update execution semantics and feature/access recipes. The shared type
is the normalized server/UI contract; it contains no provider payload or
secret.

## Verification

- RED: the prior verifier failed both reason assertions for rejected
warm policy and foreign-run lease binding. GREEN: the final focused
source/HTTP, system-state, and UI suites pass 23 tests. The UI follow-up
passes 8 tests after the review fixes.
- HTTP tests prove exact selection, cross-company denial,
resolved-action access, reused-allocation rejection, redaction, and
unchanged actions, runs, leases, tasks, wakeup receipts, workspace
operations, and activity. A nine-source case proves bounded inspection
while the existing worker verifier still accepts all nine valid sources.
- Review follow-up: show allowlisted saved detail beside a changed
current observation, preserve all listed actions, and follow
exact-action selection in verified/limited/error tests. The prior
component fails the saved/current drift regression in an in-memory RED
control; the current component passes. UI typecheck/build pass again.
- `pnpm -r typecheck` and `pnpm build` pass. Token gates, maps, module
boundaries, and `git diff --check` pass.
- Rebased onto master `46de15ff4b` without conflicts. Range-diff proves
both diagnostic commits are unchanged. On new head
`a7e2bc87fcea75e76b6b736304d1287257f71174`, all 23 focused tests, full
typecheck/build, token gates, maps, and module checks pass again. Both
fresh reviews are 5/5 with zero unresolved threads. Final exact-head
GitHub status is CLEAN: 55 success, 2 skipped, 1 neutral, no pending
checks or failures. The [ci / verify
aggregate](https://github.com/paperclipai/paperclip/actions/runs/40387002325/job/121802415824)
passed in eight seconds. All test/build/typecheck/E2E lanes passed.
- Existing full workspace recovery suite: 56/56 pass (103.5 seconds)
before the byte-equivalent rebase. `pnpm test:run` hit repeated embedded
PostgreSQL initialization failure before database-suite assertions and
was stopped. No full local suite pass is claimed. The owned external
`_test` database provided the focused HTTP/source verification. The
prior browser attempt also stalled at Network.enable before its click;
that attempt did not establish browser acceptance.
- Current-head local browser acceptance passes through the actual run
page: Inspect recovery lists the exact action, Inspect current source
shows recorded generic failure separately from the current rejected
policy, and reload resets inspection to the explicit control. Explicit
selection works again after reload. The app used isolated data, an empty
inherited environment, a paused synthetic agent, and no provider
credentials. Final state remains failed/exhausted with zero attempts,
zero wakeup receipts, zero workspace operations, and unchanged original
generic failure. The local app and temporary tab were stopped. This
proves the diagnostic journey, not the deployed source's actual lease
policy or its recovery.
- Final merge verification at
`a7e2bc87fcea75e76b6b736304d1287257f71174`: GitHub reports CLEAN and
mergeable. Both repository-required checks, `ci / verify` and `ci /
e2e`, pass, as does the exact-head Greptile check (5/5, zero unresolved
threads). The separate [Entire
trail](https://entire.com/gh/paperclipai/paperclip/trails/7) has no
recorded reviewer approval; no such approval is claimed. It is not a
configured GitHub merge gate.
- Initial local setup failures were distinct from product assertions:
localhost sandbox EPERM required scoped local access; a browser harness
import path was corrected. A test UUID type inference error and
historical native-export UI selection gap were corrected before the
green run. The live task remains blocked; this diagnostic does not claim
it recovered.

## Risks

- This change improves evidence. It does not prove provider termination,
local descriptor integrity, or successful file preservation, and it does
not repair the original source.
- Current inspection spans multiple database reads. It is an
observation, not a historical cause or execution authority. It performs
no provider/filesystem calls and starts no retry or executor.
- The optional persisted detail is backward compatible. Unknown values
and extra fields are excluded. Oversized source lists remain uninspected
through this explicit diagnostic path; physical recovery rules do not
change.

## Model Used

OpenAI Codex based on GPT-6, with code execution and browser tools. The
exact serving model ID and context window were not exposed in this
session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 08:21:28 -05:00
DottaandPaperclip 0c9d10d695 feat(connections): complete saved setup guidance and coverage maps (#17739)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Product and agent access maps describe the same capability IDs.
> - Agent connection management changes the callable operations and
permission boundaries.
> - Reviewers need an operation inventory that distinguishes API access,
human handoffs, and fixture evidence.
> - This pull request adds saved setup screens and updates the maps for
#17737.
> - The benefit is that users and contributors can inspect the coverage
and remaining boundaries.

## Linked Issues or Issue Description

**Subsystem affected**

Product and permission documentation, saved authentication setup UI and
consent metadata, and product/agent access maps.

**Problem or motivation**

The current maps describe board-only management paths. They need to
match delegated connection management and distinguish administration
from ordinary tool execution.

**Proposed solution**

Record route operations, required grants, responsible-user limits,
transport, saved authentication handoffs, provider-fixture evidence, and
explicit local-operator boundaries for every connection family.

**Roadmap alignment**

This is the documentation companion to #17737. It covers existing
Connected Apps, governed MCP gateways, chat channels, and
personal/shared AI accounts. It uses existing server setup operations
and adds their saved handoffs to the existing UI.

## What Changed

- Show saved AI sign-in and connection setup handoffs in the existing
UI.
- Open GitHub import and rotation links at the required human step.
Resume a committed rotation after reload without asking for another
secret.
- Restore saved Google service choices for the addressed user while
preserving newer consent. Successful direct/cloud consent records its
own timestamp, independently of refresh or lease writes; existing
refresh paths preserve it.
- Update product, implementation, and permission-default documentation.
- Reconcile app permissions, connection setup, chat channels,
profiles/gateways, and model account coverage.
- Use matching capability IDs in the product and agent access maps.
- Label source-reviewed operations separately from fixture-tested
operations and live provider setup.

- Preserve catalog creator attribution under the responsible user, with
the actual agent still recorded. This follow-up moved from the
implementation to keep both reviews below 100 files. This companion now
changes 38 files, including the preserved Vercel personal-credential and
OAuth callback attribution follow-ups alongside consent and catalog
ownership.

- Name the addressed-human browser-session and consent step for Slack
managed authorization and installation. Preserve source-only evidence
for those individual operations.

## Verification

- Current companion head: `04d40cdd605452d91cf4931476eb292a210825af`,
including implementation `2ecd6451d0` and master `ea727dc3c2`, 38 files.
All intended companion files survive: 35 are byte-identical to the
previous companion; two chat maps and qualification add current
evidence. Exact-head Superagent passed and Paperclip Review supplied an
actual neutral5/5 assessment with no findings and explicit
no-independent-runtime/live/current-CI verification limits. Exact-head
Greptile also completed at5/5 with no findings; both formerly failed
shards and their verification aggregate passed on attempt2; full
exact-head Linux CI workflow40446969603 completed SUCCESS. All current
checks and statuses are terminal clean, with no unresolved findings.
This PR remains dependent on #17737 and needs fresh checks after its
required post-squash replay. The preceding 605 head’s reviews are
historical after this update. Older b0ea Linux workflow success after
its single rerun also remains historical.
- Earlier preserved-stack verification passed **2,165 tests**: 70
assembled-server actual-auth scenarios, 27 OpenAPI contracts, 2,022
native API tests and 46 saved GitHub wizard cases in fresh PostgreSQL.
The parent also passed **141 existing gateway/policy tests**. Workspace
typecheck/build, maps and token gates passed. The initial typecheck IPC
denial and all material intermediate regressions remain in the
qualification record; no full local sweep or live provider setup is
claimed.
- Operation maps now cover issuer/target gateway policy intersection and
post-approval revocation, bounded activity pagination through
private-only windows, and native local-login encrypted receipts. The
companion preserves the Vercel OAuth callback ownership change with its
existing credential ownership follow-up.

- Parent CI has one retained connection-intent e2e failure from a
periodic-recovery timing race. GitHub refused the first job-rerun
attempt while its workflow was nonterminal. Once completed, the single
failed-job rerun was accepted as attempt 2 and passed, including the
full parent Linux workflow.

- Companion Linux server shard 4/12 retained a cleanup-idleness timeout
in `login-cleanup-work.test.ts` (active work was still 1 after its
five-second wait). The same unchanged cleanup suite passed all 16 cases
in the parent Linux job 121950185096 and all 16 cases locally against a
fresh disposable PostgreSQL database. Relevant cleanup/reaper/scheduling
runtime code is unchanged. The single unchanged-code failed-job rerun
was accepted as **attempt 2** on the previous `b0ea3c940f` head
(workflow 40431671705). The failed shard and complete Linux workflow
passed on attempt 2; no additional unchanged-code rerun was used for
this failure. The first local attempt failed the existing dedicated
`_test` database-name guard before running tests; the correctly named
fixture passed without weakening the guard.

- **Earlier 82 GitHub UI tests passed**. All three new replacement cases
were red before the fix. A confirmed unchanged generation preserves the
earlier copy; a changed or unreadable generation blocks copying and
reconnecting. An explicit status check can restore the copy when it is
still current. All earlier import, rotation, verification, and retry
states remain covered.
- The complete stack passed **82 API/OpenAPI tests** in fresh
PostgreSQL, including 55 scenarios with real agent keys, run JWTs, human
sessions, production defaults, persistence, and deterministic providers.
The parent also passed **60 Copilot installation tests**, preserving
published v62 and binding combined guidance as v63.
- **Earlier 10 focused Google/OAuth tests passed**: eight picker cases
and two local-HTTP protocol cases proving consent metadata survives
concurrent token refresh. The refresh and legacy UI cases were red
before the fix. These protocol fixtures use the existing injected board
actor and do not count as agent-authenticated proof.
- Workspace typecheck/build passed after the consent change; normal
migration generation reported no SQL changes for the additive JSON
metadata. The parent's latest caller-authorization correction passed
server typecheck/build. Map validation and token gates passed. Maps
cover 35 areas and 192 capability IDs. The specification names migration
`0380_broken_aqueduct.sql`.
- The test-call operation maps now record the full caller/target tool
access decision (profiles, policies, and explicit grants), credential
identity for every auth label, approval, and rate checks. The
profile-only precondition was removed after the new permitted-access
cases failed; those cases and the no-auth identity regression now pass.
Saved test status requires its originating principal and current
linked-task access; actual key/JWT privacy-denial evidence is recorded.
- Tool-connection activity is now operation-verified: 100 events over
two tasks require two capability decisions and at most two run captures
(previously 100/102), preserve private-event filtering, and deny the
next request after audit revocation. The regression was red before the
fix.
- Cloud enrollment creation and callback entries now name
instance-administrator and company/principal checks. The callback is a
browser return with HTML or a 303 redirect. Status reads retain their
separate board-actor rule.
- Operation maps identify the API, transport, authorization, evidence,
and human/operator boundaries. Structural checks do not establish live
provider behavior. Earlier failures and fixture corrections remain in
`doc/plans/2026-10-13-connection-api-parity.md`.
- An earlier companion head (`26edbe17`) received an actual Paperclip
Review assessment of 5/5 with no actionable findings, published with
neutral status. That review did not run tests or confirm CI, and it is
historical for this new head. The prior incomplete execution result is
not counted as a passed assessment. Fresh review remains pending. The
duplicate enrollment findings have explanatory replies and are resolved.
- The latest implementation correction passed all 55 actual-auth
scenarios and 27 OpenAPI contracts (separate commands). It repairs
unavailable old credential material, preserves fresh import versus
configured reconnect links, and distinguishes credential field
sets/completion modes in handoff keys. The new fresh-link and collision
cases were red before the fix. All 41 GitHub wizard tests now pass,
including filling the fresh saved handoff and asserting App import
rather than reconnect; UI typecheck, maps and token gates also pass.
Qualification retains the earlier failures and an incorrect OpenAPI
filename that selected only the integration module before the correct
separate contract run.
- Configured GitHub credential-entry links carry canonical requested
fields and all/any mode. The form displays and submits those values
through human reconnect while retaining other saved credentials. Two
webhook/client-secret cases were red before the fix; combined all/any
and legacy-link cases also pass. The current UI fixes the old bf760912
baseline referenced by the duplicate main review finding.
- After merging master baec3abd67 and regenerating migration0380, the
complete stack passed **128 tests** (55 actual-auth, 27 OpenAPI and 46
GitHub wizard cases), workspace typecheck/build, maps and token gates.
Eight current Google UI cases also passed. The two local-HTTP OAuth
cases could not initialize embedded PostgreSQL in this fresh attempt, so
that attempt is not a protocol pass; the earlier ten-case evidence is
historical and fresh Linux CI remains required.
- The reproduced Linux automatic-Slack challenge failure is fixed by
retaining verification only for the same signing fingerprint and
callback URL; all eight neighboring provider compatibility cases pass.
Qualification also retains the uncommitted GitHub field variant that
failed initial-secret compatibility before the extension was narrowed to
reconnect, and the first unmigrated external-database diagnostic.
Upstream 0379 remains intact; normal generation/pruning produced
additive/idempotent 0380, with repeated application verified.
- Both PRs must ship together. The user authorized merging when checks
pass. Merge #17737 first, replay only this companion's changes onto
master, retarget this PR, and require fresh current-head CI and review
before its squash merge.

- The updated maps distinguish authorized bot-token/API-key setup from
human verification-key entry and forbid generic channel secret-reference
replacement. Actual key/JWT security baselines were red before both
guards; all 82 API/OpenAPI cases, eight native receipt protections, and
49 policy-service tests now pass. The qualification record preserves the
initial lifecycle/fixture/union-assertion diagnostics and the preceding
Linux CI assertion failures. Maps pass on this updated stack. Fresh
exact-head CI and reviews remain required.

- The parent now preserves a per-field credential-change boundary before
retiring saved credential-entry cards. Old health, unchanged entry,
unrelated repair and retries cannot bypass it. Current authority is
checked before and inside credential persistence; a real provider-time
revocation regression was red before the fix. Final 82 API/OpenAPI
tests, four neighboring lifecycle cases, and server typecheck/build
pass. Maps pass, and qualification retains the hidden-metadata fixture
failure and the measured minute-boundary rate-test failure. Production
rate behavior is unchanged; only the relevant test Date clock is fixed.

- After the current master/parent refresh, all **341 affected UI
cases**, combined workspace typecheck/build, maps and token gates pass.
The updated parent also passed **97 actual-auth/OpenAPI cases**, **141
gateway/policy cases** and **61 profile installation cases**. Published
upstream Copilotv62/v63 remain unchanged; combined guidance is now v64
(`sha256:22e31f95ef972bcead98a4a707c9f33433558fd111e390e027a2bbb4346e112a`).
Qualification retains the initial source-identity failure and fixture
port/migration setup failures. No full local sweep, fresh local OAuth
protocol run or live acceptance is claimed; fresh Linux CI must qualify
this successor.

- Latest review follow-up: the parent fixes caller-policy bypass in
Slack tests/invitations and premature identity-handoff completion. The
maps now name caller/target Block/Ask/rate intersection, one charge for
a shared bucket, and the addressed human’s exact current identity link.
Parent verification passes all **99 actual-auth/OpenAPI tests**,
typecheck and build. The preserved combined companion passes the four
focused tests (including twelve Slack policy/recipient combinations and
the actual human OAuth confirmation path), workspace typecheck/build and
maps. The 50 embedded-PG continuation cases were skipped locally because
their database could not start; fresh Linux CI remains required. All
material red/intermediate results and corrected-fixture evidence are
retained in the qualification record.

- Current `04d40cdd60` CI workflow40446969603 retained two new failures:
server1/12 `workspace-runtime.test.ts` could not reach a fixture
subprocess’s health endpoint within its ten-second readiness window
(job122001926052), and chat2/3 `wakes Slack session sync from
publication commit and leaves settled action queues quiet` observed one
select after its idle predicate (job122001925936). Both same cases
passed in parent `2ecd6451d0` Linux jobs122001920494/122001920581. The
runtime and queue implementations are unchanged by this companion. Both
failing cases also pass unchanged locally: two real-subprocess runtime
readiness/reuse tests and the exact Slack quietness assertion against a
fresh migrated PostgreSQL database. Logs:
`/tmp/parity-04d-server1-failure.log`,
`/tmp/parity-04d-chat2-failure.log`,
`/tmp/parity-2ecd-server1-green.log`,
`/tmp/parity-2ecd-chat2-green.log`,
`/tmp/parity-04d-runtime-qualified.log`,
`/tmp/parity-04d-chat-quiet-qualified.log`. The single standard
unchanged-code failed-job rerun was **accepted as attempt2** on the
unchanged exact head at `2026-10-27T04:24:30.513973+00:00` after the
workflow completed. Both new failure retry allowances are now
**consumed**; both failed shards and the complete Linux workflow have
now passed on attempt2, including the verification aggregate. No
additional unchanged-code rerun will be requested for either failure. No
timing, assertion, idle-work guard or policy was weakened. If either
case fails again, investigate/fix rather than rerun again. The older
5b/b0ea rerun allowances remain consumed and separate.

## Risks

- Saved handoff links depend on the API changes in #17737, including the
nonsecret credential-generation metadata. Both PRs must ship together.
- A map can overstate operation coverage. Entries identify their
evidence and retain human authentication and trusted-host limits.
- Structural map checks do not prove live provider behavior.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — focused UI/guidance and
map checks
- [x] I have added or updated tests where applicable — saved setup UI
tests and map validation apply
- [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 — exact `04d40cdd60` full Linux
CI completed SUCCESS on attempt2; all current checks/statuses are
terminal clean, with an actual neutral5/5 Paperclip assessment
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups —
exact `04d40cdd60` review completed with no findings
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

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

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

## Linked Issues or Issue Description

**Subsystem affected**

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

**Problem or motivation**

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

**Proposed solution**

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

**Roadmap alignment**

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

## What Changed

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

## Verification

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

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 08:20:24 -05:00
Devin FoleyandPaperclip 0cb3fc7db5 fix(runner): retain ACPX transport failure details (#17837)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Runner reports provider failures to the execution and
recovery services.
> - Those services read the terminal event's structured `error` field.
> - The ACPX transport-failure path wrote its code and message only at
the top level.
> - The session facade therefore replaced that cause with `error: null`
and the generic message "Provider turn failed".
> - This pull request uses the existing structured error contract while
retaining the old fields.
> - Recovery can retain the actual redacted cause without reopening the
failed provider or assuming a retry is safe.

## Linked Issues or Issue Description

**What happened?**

A native ACPX run can lose its failure details between runnerd and the
session facade. The transport-failure producer emits a failed turn with
top-level `code` and `message`. The facade reads `error`. The server
receives a generic provider failure and cannot use the original cause to
explain or classify recovery.

**Expected behavior**

Retain the transport code and redacted cause in the structured terminal
error. Keep failed sessions closed, provider termination unproven, and
automatic replay disabled.

**Steps to reproduce**

1. Open a native ACPX session and start a turn.
2. Send malformed activity from the sidecar after it acknowledges the
turn.
3. Poll the native provider events.
4. Observe that `turn.failed.error` is absent even though the producer
has a transport code and cause.

Refs: #16366, #17543. Those changes cover legacy process-session
diagnostics and session-ensure errors. This change repairs the native
ACPX polling terminal contract.

## What Changed

- Add the existing transport code and redacted message to the terminal
event's structured `error` field.
- Mark that error as non-recoverable. Keep the previous top-level fields
for existing readers.
- Add a real sidecar fault fixture and a native-provider regression. It
checks one failed terminal, retained error details, a closed session,
and no provider reopening.
- Document the failure contract and verification scope in execution
semantics and the recovery map.

## Verification

- Red: the new fault test failed because the structured transport error
code was null on the original code.
- Green: all 26 native-provider integration tests pass with the fix.
- Three session-facade terminal tests and three native-runtime
provider-failure classification tests pass.
- `pnpm -r typecheck` and `pnpm build` pass.
- Hosted test partitions, native Runner checks, typecheck, build,
browser shards and canary passed. Two final aggregate jobs received no
runner for several minutes. The first CI attempt was cancelled after
saving its status, and only those two cancelled jobs were resubmitted.
Both aggregate jobs passed on attempt 2. The current head has 55
successful checks, four expected skips and successful Snyk status.
- `git diff --check`, `node scripts/check-module-boundaries.mjs`, and
`node scripts/check-maps.mjs` pass.
- The full local Vitest suite is not run for this patch. The local
filesystem fell below 500 MiB free during verification. The preceding
full-suite attempt crashed embedded PostgreSQL; focused checks and CI
are used without claiming that attempt passed.
- Live incident: verified the exact predecessor sandbox was destroyed
and workspace recovery completed. An audited user retry through the
normal task-retry service started one new native run. That attempt
preserved the original question but failed before provider startup with
a missing workspace-sync descriptor binding. The startup race is fixed
separately in #17838. A later audited retry completed successfully,
saved its useful answer and restored its workspace. The agent API
handoff failed; an audited operator repair through the normal issue
service completed the required user assignment in Review without
repeating the comment or provider work. This verifies recovery admission
on the existing deployment; the new Runner change is not deployed yet.
- Evidence limit: the historical terminal had `error: null` and its raw
sidecar frame was not retained. Fault injection proves this producer
defect and the same loss of diagnostics. It does not establish which
transport fault caused the historical turn to end.

## Risks

- Recovery now receives a specific transport failure code. The error
remains non-recoverable and `providerTerminalObserved` remains false.
Stop proof, effect reconciliation, workspace preservation, retry limits,
and normal execution authority still govern any successor.
- This change preserves diagnostics. It does not make a malformed or
lost provider connection healthy.
- No schema migration, credentials, provider selection, or model
settings change.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 21:34:29 -07:00
commitperclip[bot] 2d72f2c4c0 fix: Serialize ACPX session record saves per record to stop overlapping renames (EPERM on Windows) (#16925)
> [!NOTE]
> Opened by Prospector's automated issue-fix pipeline. A maintainer
reviews and decides; nothing here merges on its own.

## Thinking Path

- Issue #15346 reports a defect in paperclipai/paperclip.
- Root cause, as the fixing agent read it: ACPX saves one session record
from several writers (live checkpoint timer, turn end, finalize, close)
with no coordination; each save renames a temp file onto the same record
file, and on Windows overlapping renames onto one file fail with EPERM.
All of these saves go through Paperclip's session-store wrapper, which
forwarded them concurrently.
- This pull request: Serialize ACPX session record saves per record to
stop overlapping renames (EPERM on Windows)

## What Changed

-
`packages/adapter-utils/src/acpx-engine/ephemeral-session-environment.ts`:
Every ACPX save in Paperclip passes through this wrapper, so it now puts
all saves of one record id in a single queue (a promise chain shared by
all wrappers in the process). Saves of one record never overlap and keep
their order; a failed save still returns its own error and does not
block the next one; saves of different records still run in parallel.

## Verification

- Reproducing test(s), added in this PR:
`packages/adapter-utils/src/acpx-engine/ephemeral-session-environment.test.ts`
- They fail on the base commit and pass with the fix, each twice in a
fresh sandbox.
- 3 independent attempts wrote 3 reproductions; this fix passes every
one of them.
- The repository's compile command passes with the fix applied.
- 3 existing test file(s) near the change pass.
- The full test suite passes except for the 246 file(s) that already
fail on the base commit.

## Risks

- Written by an automated pipeline, not a person: review it as you would
an outside contribution.
- Risk tier of the touched paths: 2.
- The scope reviewer found it also changes, beyond the report: save()
called when no earlier save of that record is pending
- The scope reviewer found it also changes, beyond the report:
persistedStore.save throwing synchronously
- The scope reviewer found it also changes, beyond the report: Records
with missing/undefined acpxRecordId
- The scope reviewer found it also changes, beyond the report: save()
for different record ids

## Model Used

- opus, sonnet (Anthropic Claude, via Claude Code), writing and checking
the change in an isolated sandbox.

## Linked Issues

Fixes #15346

Other pull requests that name #15346:
- #15370 (closed): fix(acpx): serialize session file saves and clean
failed temporary writes

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [ ] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with 'Fixes: #' / 'Closes
#' / 'Refs #' OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub '#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
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

<!-- prospector:issue-fix v1 issue=15346 base=1c07b5903b1b
report=4fe3fefc8864e00f -->

Co-authored-by: commitperclip[bot] <284812584+commitperclip[bot]@users.noreply.github.com>
2026-10-26 20:55:37 -07:00
Andrii Furmanets 61ecc93033 fix: count a recovered shutdown interrupt as recovered (#15031)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The dashboard success rate counts recovered runs as successes
> - A run is recovered when a later retry in its chain succeeds
> - The summary puts `failed` and `timed_out` into recovered
> - An `interrupted` run, including `server_shutdown_interrupted`, falls
through to other
> - The success rate stays down after the retry succeeds
> - This pull request counts a recovered interrupt in recovered, not in
other
> - The benefit is that a shutdown that was retried successfully no
longer looks like a failed day

## Linked Issues or Issue Description

No open issue covers this. I searched open and closed issues and pull
requests.

**What happened?**

`dashboardService.summary` puts only `failed` and `timed_out` into the
recovered bucket. An `interrupted` run, including
`server_shutdown_interrupted`, goes to other even when `recovered` is
set. The success rate uses `succeeded + recovered`, so the day stays low
after a successful retry.

**Expected behavior**

When the recovered flag is set, count `interrupted` in recovered. An
interrupt with no successful retry stays in other.

**Steps to reproduce**

1. Record an interrupted run with error code
`server_shutdown_interrupted`.
2. Record a succeeded retry of that run.
3. Open the dashboard summary for that day.
4. Observe that the interrupt is in other and the success rate does not
include it.

**Paperclip version or commit**

master at 215586d127

**Deployment mode**

Local dev (pnpm dev)

## What Changed

- When a run is recovered, count status `interrupted` in the recovered
bucket.
- Leave an unrecovered interrupt in other.
- Add a service test for a recovered shutdown and a stranded shutdown.

## Verification

- `pnpm exec vitest run src/__tests__/dashboard-service.test.ts --config
vitest.config.ts` in `server`
- Result: 1 file passed, 5 tests passed

## Risks

- Low risk. Unrecovered interrupts stay in other. Failed and timed-out
runs keep the same buckets.

## Model Used

- No model runtime is part of this change.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] I have updated relevant documentation to reflect my changes
- [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
2026-10-26 20:52:47 -07:00
mdc2122andmdc2122 8153061d71 fix(pi-local): strip inherited server PAPERCLIP_* env from pi_local processes (#14503)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The `pi_local` adapter spawns the Pi CLI as a child process for
agent runs, environment tests, and model discovery
> - Each of these three paths builds the child env with `{
...process.env, ...env }`, so the child inherits the full server
environment
> - The server environment can hold server-only `PAPERCLIP_*` secrets
and config paths, such as `PAPERCLIP_AGENT_JWT_SECRET`,
`PAPERCLIP_TOOL_ACTION_SIGNING_SECRET`, and
`PAPERCLIP_SECRETS_MASTER_KEY_FILE`
> - `@paperclipai/adapter-utils` already has
`sanitizeInheritedPaperclipEnv`, and the shared `runChildProcess` path
uses it for its base env. `pi_local` passes its pre-merged env as
`opts.env`, which `runChildProcess` spreads over that sanitized base, so
the inherited server values come back
> - This pull request routes the three `pi_local` merges through
`sanitizeInheritedPaperclipEnv`
> - The benefit is that `pi_local` agent processes no longer receive
server secrets. This is a security hardening change.

## Linked Issues or Issue Description

No issue exists. This is a bug report in the in-PR format.

**What happened?**

A `pi_local` agent process receives the inherited `PAPERCLIP_*`
variables of the Paperclip server process. An env dump from inside a
`pi_local` run showed `PAPERCLIP_AGENT_JWT_SECRET`,
`PAPERCLIP_TOOL_ACTION_SIGNING_SECRET`,
`PAPERCLIP_SECRETS_MASTER_KEY_FILE`, and server config path variables.
The agent process can read these values.

**Expected behavior**

The `pi_local` child env drops inherited server `PAPERCLIP_*` variables,
the same as the shared `runChildProcess` path. Only
`PAPERCLIP_RUNTIME_API_URL`, `PAPERCLIP_LISTEN_HOST`, and
`PAPERCLIP_LISTEN_PORT` stay inherited. The run-scoped variables that
the adapter sets (for example `PAPERCLIP_AGENT_ID` and
`PAPERCLIP_API_KEY`) and the adapter-configured env still reach the
child.

**Steps to reproduce**

1. Start the Paperclip server with `PAPERCLIP_AGENT_JWT_SECRET` set in
its environment.
2. Run a `pi_local` agent whose command writes `process.env` to a file.
3. Read the file. `PAPERCLIP_AGENT_JWT_SECRET` is present.

**Agent adapter(s) involved**

`pi_local` only.

**Additional context**

Other CLI adapters appear to merge `process.env` into the child env in a
similar way (for example in some `execute.ts` and `test.ts` files). This
pull request does not change them. It keeps the scope to `pi_local`.

Related: #3030 and #12870 also touch inherited agent env. This pull
request is independent of #14479.

## What Changed

- `packages/adapters/pi-local/src/server/execute.ts`: the run env and
the runtime env that the adapter logs now start from
`sanitizeInheritedPaperclipEnv(process.env)` instead of `process.env`.
- `packages/adapters/pi-local/src/server/test.ts`: the environment test
env now starts from `sanitizeInheritedPaperclipEnv(process.env)`.
- `packages/adapters/pi-local/src/server/models.ts`: the model discovery
env (`pi --list-models`) now starts from
`sanitizeInheritedPaperclipEnv(process.env)`.
- `server/src/__tests__/pi-local-execute.test.ts`: add a regression
test. The test sets three server secrets on `process.env`, runs
`execute` with a fake Pi command that dumps its env, and checks that the
secrets are absent. It also checks that the adapter-configured env and
the run-scoped `PAPERCLIP_AGENT_ID` and `PAPERCLIP_API_KEY` are present.

## Verification

- `cd server && npx vitest run src/__tests__/pi-local-execute.test.ts
src/__tests__/pi-local-adapter-environment.test.ts
src/__tests__/pi-local-skill-sync.test.ts`: 7 tests pass.
- The new test fails without the source change (the secret assertion
fails) and passes with it.
- `npx vitest run packages/adapters/pi-local`: 42 tests pass.
- `pnpm --filter @paperclipai/adapter-pi-local typecheck`: pass.
- `cd server && tsc --noEmit` (after `pnpm --filter
@paperclipai/plugin-sdk ensure-build-deps`): pass.

- Follow-up coverage observes real child environments from direct model
discovery, agent execution, and `testEnvironment`. Each path omits
inherited secrets and retains the permitted runtime/listen variables and
configured env. Removing either the model-discovery or environment-probe
sanitizer independently makes the regression fail. All 49 scoped tests
and both direct typechecks pass.

## Risks

- Low risk. A `pi_local` setup that relied on an inherited server
`PAPERCLIP_*` variable (other than the three kept keys) no longer gets
it. Such a value can still be set in the adapter `env` config. This is
the same behavior as the shared `runChildProcess` path.

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

## Model Used

- OpenAI GPT-6.1 Sol, exact runtime model ID
`gpt6sol-cliproxy/gpt-6.1-sol`, with tool use and code execution.
Context-window and thinking-level metadata are not exposed. The prior
model and human-review disclosure was not substantiated by available
runtime metadata.

## 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: mdc2122 <259970464+mdc2122@users.noreply.github.com>
2026-10-26 20:49:07 -07:00
DottaandPaperclip dcfc2acfa8 Preserve complete bounded OpenCode MCP tool results (#17825)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/34/changes/paperclip/34
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages AI agents and their governed tools.
> - Native OpenCode receives tool results through a Runner-owned MCP
bridge.
> - The bridge cut serialized results at 64 KiB, even inside a JSON
string.
> - A tool could finish while its saved OpenCode output lost files and
receipts.
> - Native app results already use bounded results and saved-result
pages.
> - This change preserves complete JSON within a bounded output limit.
> - Agents can read the result without repeating the completed action.

## Linked Issues or Issue Description

**What happened?**

The OpenCode MCP bridge sliced serialized JSON at 65,536 characters. A
large file-list result became invalid JSON in OpenCode's saved output.
The tool execution itself had completed.

**Expected behavior**

The bridge must deliver complete bounded JSON. A delivery limit must
produce an explicit error, rather than a partial success value. A
repeated call identity must not execute the action again.

**Steps to reproduce**

1. Return a structured result with 27 file entries and duplicated
text/data representations larger than 64 KiB.
2. Call the tool through the actual HTTP MCP bridge.
3. Parse the returned text as JSON. The old source fails at position
65,536.

Related: #17740 changed assigned-tool catalog delivery. This PR repairs
result delivery and does not change the tool catalog or authority.

## What Changed

- Replace JSON slicing with complete serialization and a 1 MiB UTF-8
output limit.
- Bound serialization traversal, including escaped strings and many
small fields.
- Keep the existing native 500 KB result/page and saved-artifact
contracts.
- Report oversized delivery with a warning that the action may already
have completed. Keep call-identity replay on the original execution.
- Add real HTTP regressions and document the transport limit.

## Verification

- Red before fix: the large-result HTTP regression fails with an
unterminated JSON string at position 65,536.
- 91 focused MCP, OpenCode driver and continuation assertions pass on
Node 24.22.1. They cover escaped UTF-8 pages, oversized delivery,
authentication, cancellation and duplicate-call execution.
- Workspace typecheck and build pass.
- Actual native Rust → fixed MCP bridge → OpenCode 1.18.34 →
`openrouter/deepseek/deepseek-v4.1-flash-1017` passed with a public
synthetic 27-file result. One assigned read produced a 281,375-byte
saved JSON file. The model used Bash/Python to parse all filenames and
both unpredictable receipt fields. One finish completed the turn.
- The native probe used a synthetic gateway and a mocked completion
acknowledgment. It does not prove hosted deployment, board finalization
or a particular upstream model vendor.
- The full default test attempt is failed/incomplete. It was stopped
after repeated embedded PostgreSQL bootstrap failures and skipped
database suites. Its 15 warm-workspace cases pass unchanged on isolated
PostgreSQL 18. A controlled default-database rerun fails before the test
body when embedded PostgreSQL cannot start after five attempts. The test
source is byte-identical to the base commit. The failed attempt remains
recorded.
- The final test-only commit checks a 500 KB escaped producer page
inside the actual controller text envelope. The production bridge hash
still matches the native proof. Its 91 focused tests and package
TypeScript check pass.

- Current-head verification (`73d18ca2`): 53 CI checks passed and two
conditional Storybook checks skipped. Greptile is 5/5 on this exact head
with no review threads. The failed/incomplete full local attempt and the
controlled passing suites above remain separate evidence.

## Risks

- Larger complete results use more bounded serialization memory than the
old truncated output.
- A bridge result above 1 MiB fails delivery. Native app results and
saved-result pages are bounded at 500 KB before this bridge. The
existing artifact protocol handles larger results.
- A failed delivery cannot prove whether an upstream action took effect.
The error forbids repeating it, and identical call identities retain the
original execution.
- This change does not alter model routing, admitted tools, credentials
or trust policy. Hosted rollout and incident recovery remain separate
verification steps.

## Model Used

- OpenAI `gpt-6.1-sol`, with reasoning, tool use and code execution. The
session did not expose an authoritative context-window size. Native
acceptance used the exact DeepSeek model named above.

## 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 local tests and they pass; the full
local-suite environment 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
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 22:23:05 -05:00
DottaandPaperclip 208a093d19 fix(chat): preserve resumed review waits and retry newer saved input (#17725)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/36/changes/paperclip/36
<!-- entire-trail-link-end -->

## Thinking Path

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

## Linked Issues or Issue Description

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

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

## What Changed

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

## Verification

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 22:22:47 -05:00
DottaandPaperclip 4336b9ee02 fix(db): reserve transactions before checking pipeline capacity (#17831)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Interactive requests share a PostgreSQL connection pool with
background work.
> - Prepared queries can queue behind a slow query on a busy connection.
> - Disabling pipelining lets queued work use the next free connection.
> - The driver skips its transaction reservation callback when the
pipeline limit is zero.
> - This pull request runs that callback before the capacity check.
> - Operators can test a pool without pipelining while transactions
retain their connection ownership.

## Linked Issues or Issue Description

**What happened?**

With `PGMAX_PIPELINE=0`, postgres.js 3.4.9 skips `onexecute` in its
short-circuit capacity check. A transaction then lacks its reserved
connection. Real PostgreSQL reproduces `UNSAFE_TRANSACTION` through the
app client and an undefined connection error through the raw driver.
This prevents safe use of the existing setting to reduce query queue
delays.

**Expected behavior**

A transaction must reserve its connection regardless of pipeline
capacity. Commit, rollback, savepoints, and disconnect recovery must
preserve their existing contracts.

**Steps to reproduce**

1. Use the pre-change driver patch from
`e61ee4b005f8e13f64af15f69cb62305dd869f82`.
2. Start disposable PostgreSQL and run the `no-pipeline` scenario in
`packages/db/src/__fixtures__/postgres-connection-recovery.mjs` with
`TEST_DATABASE_URL`, `DRIVER_FORMAT=esm`, and
`RECOVERY_CASE=no-pipeline`.
3. Observe the transaction failure. Apply this patch and repeat with
both `esm` and `cjs`.

Refs #13643, which introduced the existing connection recovery patch.
Searched related open and closed driver PRs. This change extends that
patch and preserves its disconnect safeguards.

## What Changed

- Move the transaction reservation callback before the pipeline capacity
check in both driver distributions.
- Add real PostgreSQL regressions for commits, concurrent transaction
reads, isolation, rollback, savepoints, reserved connections, and
progress on a freed pool connection.
- Document the existing `PGMAX_PIPELINE=0` setting and its driver
prerequisite. Keep the default pipeline limit unchanged.

## Verification

- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Real PostgreSQL 18.6 in an owned, disposable Docker container: the old
patch fails the new transaction scenario in both ESM and CommonJS. The
corrected patch passes all 18 scenarios, including all 12 existing
disconnect recovery cases. The container was removed afterward.
- Local service benchmark: actual `createDb` with prepared statements,
two warmed connections, two controlled advisory lock waits, and the
complete three-query `getDefaultCompanyGoal` path. Two warmups and five
alternating measured samples per setting. Pipeline 100: median 413.44
ms, range 413.33–416.10 ms. Pipeline 0 with the patch: median 12.22 ms,
range 11.86–12.57 ms. Complete SQL, bindings, and results match. Five of
five reads finish while the unrelated slow query remains blocked. These
are synthetic local queue measurements, not hosted latency claims.
- App client compatibility on real PostgreSQL: commit, concurrent
transaction reads, rollback, nested savepoint rollback, dedicated
connections, and liveness connections passed.
- `pnpm test:run`: attempted, then stopped after repeated local embedded
PostgreSQL startup failures caused by the host semaphore limit. This is
an incomplete local full-suite run, not a pass. The focused driver
checks above used disposable Docker PostgreSQL instead. The initial
sandbox attempt also stopped before test execution because tsx could not
bind its IPC socket. Final CI results will be recorded here.
- Current head `72039f71f63530300bf241475d42e857297dfb90`: Greptile and
Paperclip review are both 5/5. All three earlier findings are resolved.
[CI run
40431567516](https://github.com/paperclipai/paperclip/actions/runs/40431567516)
ran the complete validation matrix. The database lane passed all 265
tests, including all 18 real PostgreSQL driver regressions. One cleanup
timer case timed out in server shard 6/12; its isolated real-PostgreSQL
reproduction passed once and failed once, while five runs with the
pre-change driver passed. That evidence is retained and does not
establish the timer failure's cause. A single CI retry of the failed
shard passed. The final aggregate `ci / verify` gate is waiting for a
runner. Its first queued request did not start for more than 14 minutes.
A guarded queue reset confirmed that it was the only unfinished job and
that every test job had passed; attempt 3 restarts only that gate. No
test result was replaced or bypassed. The required gate must pass before
merge.

## Risks

- This changes a shared driver callback order. Both module formats and
existing disconnect recovery are covered by real database tests.
- This PR does not change pool size, enable the setting by default,
retry SQL, or change schemas. Disabling pipelining may reduce batch
throughput. Operators must compare the workload before retaining that
setting.
- The local queue benchmark proves the mechanism. Hosted request
improvement still needs acceptance after the patched image is deployed.

## Model Used

OpenAI GPT-6 in Codex, with code execution and browser developer 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
- [ ] 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 03:00:01 +00:00
Nicky Leach e61ee4b005 fix(runner): preserve Claude user settings trust in HOME (#17826) 2026-10-26 18:02:15 -07:00
Nicky Leach baec3abd67 Authorize background project Git with explicit Connector consent (#17798) 2026-10-26 17:22:49 -07:00
6874fed05c feat(adapters): refresh model catalogs and sandbox CLI pins (Oct 23 audit) (#17809)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/26/changes/paperclip/26
<!-- entire-trail-link-end -->

## Thinking Path

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

## Linked Issues or Issue Description

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

**What happened?**

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

**Expected behavior**

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

**Proposed change**

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

## What Changed

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

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

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

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 16:32:13 -07:00
Devin Foleyanddevinfoley cfed739f81 fix(external-objects): stop reporting GitHub rate limits as unreachable (#17792)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/11/changes/paperclip/11
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app that people use to manage AI agents
for work.
> - Paperclip shows the status of external objects, such as GitHub pull
requests and issues.
> - A background sweep refreshes these objects and resolves a GitHub
credential.
> - The sweep read a credential only from a company secret with a
well-known name.
> - An instance without that secret made anonymous GitHub API calls.
Anonymous calls are limited to 60 per hour.
> - When the limit was reached, the sweep showed "unreachable" for
objects that it could not refresh.
> - A server environment token is instance-wide, so it must not expose a
private repository that a company cannot see.
> - This pull request reads a server token for public repositories,
reports a rate limit as its own state, and shows a warning on the pill.
> - The benefit is an accurate status, fewer misleading failures, and no
cross-company private data.

## Linked Issues or Issue Description

No public GitHub issue exists. The sections below describe the bug.

**What happened?**

The board showed "unreachable" for many GitHub links, even after a
related fix was deployed.

**Expected behavior**

The board should show "unreachable" only for real network failures. It
should show a rate limit as its own state and retry later.

**Steps to reproduce**

1. Use an instance with no GitHub token company secret and no server
token.
2. Let the external-object sweep make more than 60 anonymous GitHub
requests in one hour.
3. Open a task with GitHub links.

**Paperclip version or commit**

master (commit a67a18c at report time).

**Deployment mode**

Self-hosted server.

## What Changed

- Add `resolveGitHubApiCredential` in
`server/src/services/git-credentials.ts`. It reads a company secret with
a well-known name, then falls back to the server environment token
(`GITHUB_TOKEN`/`GH_TOKEN`), and it reports the credential `source`.
- Use the source in the GitHub external-object provider and in
`github-commit-details.ts`. A `server_env` token is limited to public
repositories. A private repository resolves only with a company
credential; otherwise the object reports `auth_required` and does not
fetch the private object.
- Add a `rate_limited` liveness state in
`packages/shared/src/constants.ts`.
- Classify a 403 with `x-ratelimit-remaining: 0`, a 429 response, and a
rate-limited repo probe as `rate_limited` instead of `unreachable`.
- Show `rate_limited` in the UI filter, icon, label, tone, overlay, and
badge maps.
- Make `ExternalObjectPill` and `ExternalObjectStatusIcon` prefer a
liveness warning icon and tone, so a rate-limited object shows a warning
even when the last status was healthy.
- Add tests for the credential source, the public-only server token, the
company-scoped private repository, and the rate-limited pill tone.

## Verification

- `vitest run server/src/__tests__/external-objects-service.test.ts
server/src/__tests__/git-credentials.test.ts
server/src/__tests__/github-commit-details.test.ts
server/src/__tests__/work-products.test.ts` — pass, with the new scoping
and credential-source tests.
- `vitest run ui/src/lib/external-objects.test.ts
ui/src/lib/issue-filters.test.ts
ui/src/components/ExternalObjectPill.test.tsx
ui/src/components/MarkdownExternalLink.test.tsx` — pass, with the new
rate-limited pill test.
- `pnpm --filter @paperclipai/shared typecheck` — pass. The full
monorepo `tsc` (server and ui) is killed by the 4GB memory cap of this
sandbox; the authoritative CI Typecheck gate runs it instead.
- One test in `git-credentials.test.ts` fails in this sandbox only. The
test "credential helper execution (real git, no network) ... env-carried
token" reads a global GitHub credential helper in the sandbox. The test
fails the same way on the base without this change.

## Risks

- Low risk. The change adds a liveness state and a credential source. It
does not change existing terminal verdicts.
- A server-environment token cannot resolve a private repository. This
is intentional. An operator who needs private repositories must add a
GitHub token as a company secret. The object then reports
`auth_required` with that instruction.
- `rate_limited` is a new value in `EXTERNAL_OBJECT_LIVENESS_STATES`. An
old client ignores an unknown value.

## Model Used

- Provider: DeepSeek (OpenRouter).
- Exact model ID: `openrouter/deepseek/deepseek-v4.1-flash`.
- Capabilities: tool use and code execution in the Paperclip runner.

## 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 similar open and closed PRs and
confirmed this is not a duplicate
- [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
- [ ] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-10-26 16:13:04 -07:00
DottaandPaperclip 27a87c0f22 perf(runner): keep routine journal flushes off the server thread (#17813)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runners persist incoming events in the server process.
> - Routine progress and usage events can cause many full journal
writes.
> - Synchronous file flushes stop that process from serving unrelated
requests.
> - Output deltas already use asynchronous writes, but other frequent
events still block.
> - This pull request stages routine events privately and publishes them
after persistence.
> - Critical lifecycle events keep their existing ordering.

## Linked Issues or Issue Description

Refs: #17745, #17514.

**What happened?**

Page navigation, task saves, and archive requests stalled during native
runner output. A post-fix CPU profile still spent about 7 seconds of a
19-second window in synchronous event journal flushes. Progress and
usage events caused much of this traffic.

**Expected behavior**

Routine event file writes must let unrelated HTTP requests run. The
durable cursor must advance only after persistence. Completion and
semantic tool admission must retain their ordering.

**Steps to reproduce**

Run a native task that emits frequent tool progress and usage events.
Send HTTP requests while its volume flushes are slow. The controlled
tests hold a real file flush and send a real HTTP request during that
hold.

**Paperclip version or commit**

Reproduced after #17745 on master.

## What Changed

- Stage priority 1 and 2 event snapshots with asynchronous file writes
and flushes.
- Keep candidate events out of the public in-memory journal until the
durable commit finishes.
- Include a pending event in a command's existing durable write. Command
bursts do not cause repeated event writes or business callbacks.
- Reject stale candidates after an authenticated connection replaces
their owner.
- Keep priority 0 events, all run and turn lifecycle events, and
semantic tool input persistence synchronous, including terminals labeled
priority 1.
- Extend slow-volume tests for progress, usage, critical events,
concurrent commands, reconnects, write failures, drain, and replay.
- Update the durable event delivery documentation.

## Verification

- Controlled regression: the previous implementation failed the new
progress and usage slow-flush cases and exposed pending delta state. The
updated implementation passes all sixteen controlled cases.
- All 137 durable control-plane tests and three saved-continuation cases
pass. The continuation cases use the actual Rust bridge.
- Review regressions failed before the correction: a priority-1 terminal
took the asynchronous path and command writes did not absorb the pending
event. The correction passes these tests, a two-command burst with one
staged write, and a directory-flush failure after command/event rename.
- An authority-boundary regression also failed before its correction.
Explicit snapshot transactions now retire pending coalescing, so a later
command cannot publish an older event; the test verifies replay after
restart.
- An initial version made lifecycle events asynchronous too. The
saved-continuation tests caught missing final run receipts at
completion. Keeping priority 0 events synchronous fixes those failures.
This version does not claim asynchronous lifecycle support.
- Repository typecheck and build pass locally after the review fixes. At
the previous head `886f2b961f035071bd947b5116b1f7a2727ec17f`, run
`40404783081` passed the full CI suite, including 4,024 package runner
tests and 96 native-runtime tests. Final-head CI run `40409537748`,
attempt 2, passed. All 46 substantive jobs and both aggregate gates
succeeded. Runner lanes passed 4,032 package tests and 96 native-runtime
tests. The retry carried forward the successful substantive jobs from
attempt 1 and completed both aggregate gates.
- Greptile reviewed final head
`735245931450810246e3008231a29fd56d615f67` at 5/5 with no actionable
findings. The separate Paperclip review execution ended neutrally
without a new assessment. Its earlier command-churn finding is fixed and
its outdated thread is resolved; the documentation and priority-1
coverage comments are also addressed.
- The local wider runner suite passed 449 of 450 tests. The
retained-terminal replay case fails on both this candidate and unchanged
master at the same maintenance-proof check. Both local runs leave an old
terminal receipt pending behind the event backlog. These failed runs
remain recorded; they are not counted as passes.
- The broad local test command also failed one unchanged
workspace-runtime port-allocation case. That case passed in isolation.
Its cause is unresolved. The broad local run was stopped after the
complete CI test groups passed; no full local-suite pass is claimed.
- Live staging acceptance remains pending.
- The tests hold a real `FileHandle.sync`, verify an actual HTTP
response during the hold, and check disk and memory cursors. They also
verify command preservation and idempotent replay.

## Risks

- Asynchronous writes add time for concurrent commands or reconnects to
arrive. Commands absorb the event in their existing write. Revision
checks prevent stale publication. Other authority changes leave the
unacknowledged event for replay instead of retrying full snapshot
writes.
- ACKs still wait for the file flush, atomic rename, and directory
flush. Write errors still fence further writes until reload.
- Critical commits, JSON serialization, rename, and directory flushes
still run synchronously. A command's coalesced event uses that command's
existing synchronous commit. This change does not eliminate every
possible source of latency.
- No schema, API, dependency, or wire contract changes are required.

## Model Used

OpenAI GPT-6 in Codex, with reasoning, tool use, and code execution. The
session does not expose a more specific 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 tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 18:01:00 -05:00
Nicky LeachandPaperclip 835966dec8 Prepare agent-owned environments during hiring (#17761)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/1/changes/paperclip/1
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages agents and their execution environments.
> - New agent setup saves an inactive agent before model connection
tests.
> - Some plugins need that agent to prepare its execution resource.
> - The wizard tested without the agent ID, while the setup hold
prevented preparation.
> - Environment changes also discarded the selected model account.
> - This change prepares the saved draft during setup and keeps normal
execution held.
> - Users can test the prepared resource before they finish hiring.

## Linked Issues or Issue Description

**What happened?**

An agent-owned plugin environment could not acquire a test lease during
hiring. Changing environments also returned the user to Connect and
cleared the selected account.

**Expected behavior**

Keep the selected account, invalidate its test, and prepare the saved
agent resource in the background. Test that same agent before finishing
setup.

**Steps to reproduce**

1. Start a new Claude or Codex agent and select a saved account.
2. Change to an agent-owned plugin environment.
3. Try to finish setup or reconnect the account.

Related: #17750 defers probes until after hire submission. This change
implements preparation during the wizard instead. The related PR search
and ROADMAP review found no other implementation of this setup
preparation path.

## What Changed

- Add the optional `requiresAgent` driver declaration. Require agent
lifecycle participation when it is set.
- Prepare saved drafts on creation or environment changes. Keep the
setup hold and wait in `verifying` without background verification
scans.
- Bind tests to the saved agent. Return a warning without allocating a
lease when the required agent is absent or still preparing.
- Preserve the account and configuration step when the environment
changes. Save the selection and invalidate the old test.
- Show active preparation and support authorized retries. Keep approval,
company, budget, and normal task admission controls.
- Document the contract and cover lifecycle, lease, manifest, and wizard
behavior.

## Verification

- Server and UI TypeScript checks passed.
- 112 wizard and setup helper tests passed. The shared manifest suite
passed.
- 123 lifecycle, policy, lease, and environment-test API cases passed
after the approval-gate fix. The diagnostic and driver suites and all 80
agent adapter route tests also passed.
- Token gates, module boundaries, map validation, and whitespace checks
passed.
- All 66 lifecycle/policy cases passed after the stopping-draft
permission fix. The new real-DB route case verifies creator success,
other-creator denial, and refusal to complete a hire while stopping.
- Full workspace typecheck and build were attempted. Both stop at the
unchanged Rust Runner step because Cargo is not installed on this host.
- CI on 43be3c93d passed all automated checks, including full test
shards, typecheck, build, Rust checks, browser suites, and canary
checks:
https://github.com/paperclipai/paperclip/actions/runs/40368174530.
- The full local repository test command was started. Two unchanged
workspace tests assume Git's initial branch is master; this host
defaults to main. Both fail in isolation under the host default and pass
with process-scoped init.defaultBranch=master. The broad run was stopped
after those confirmed fixture failures; CI supplies the full clean
check.
- Early new-test failures were fixture collisions and an unscoped sweep
assertion; the fixtures and assertion were corrected. One route-suite
load raced with SDK output regeneration; rebuilding first and running
the suite afterward passed.
- Initial CI exposed a route mock missing the new prerequisite lookup.
The fixture was updated and a real HTTP no-lease case was added; all 54
cases in that route suite pass. Security review identified allocation
before required approval; the new approval gate and its tests address
it.
- CI on 50b5a08af reported 32 of 33 expected calls in the unchanged
cleanup-history scheduling test. Its isolated case passed locally
without cleanup-code changes; the original failure remains recorded and
the final CI run passes on the current head.
- Standard Greptile reviewed 43be3c93d at 5/5. A subsequent deeper
review identified runner selection, stale detail reads, error retention,
and test file size issues; 70343387b addresses all four with resolved
threads. Standard review returned 5/5 on that commit and again on
rebased head fda42c5ab. The rebase preserves master's new managed
environment skill declarations alongside requiresAgent. Full CI on
fda42c5ab passes: 55 successful checks, two intentional skips, no
failures. Run:
https://github.com/paperclipai/paperclip/actions/runs/40405121641.
- After those fixes, 133 UI tests and 61 lifecycle/policy cases pass;
all eight focused UI regressions fail against the previous
implementation and pass with the fix. Token, map, and whitespace gates
pass. The stale-read fixture initially omitted the setup URL because
navigation is mocked; following the URL activates the real detail query
and reproduces the race.
- UI TypeScript passes. This host's server dependency links now point to
a separate scratch checkout lacking requiresAgent, so the ordinary
server check reports that missing property. A no-emit check pinned to
this branch's shared declarations passes; it disables declaration
generation and supplies explicit local type roots. The first temporary
configuration lacked those type roots; the corrected configuration
passes. CI remains the full workspace verification.
- After rebasing onto 8373d7867, all 133 UI, 61 lifecycle/policy, and 44
manifest cases pass again, as do UI TypeScript, token, map, and
whitespace checks. The server no-emit check now hits three mismatched
SDK/Runner declarations from the scratch dependency links; these are
outside this change. Full CI builds the complete dependency set.
- Review cycle: the first Apex review scored 3/5 with four findings. All
were fixed together, the branch was rebased to resolve a schema
conflict, full CI and standard Greptile passed, and a second Apex review
returned 5/5 on fda42c5ab with zero new comments. All six review threads
are resolved, and the PR is conflict-free. Review:
https://github.com/paperclipai/paperclip/pull/17761#issuecomment-6422635718.
- No live provider resource was created and no deployment was performed.

## Risks

Plugins must opt in and ship a compatible declaration. Companies
requiring hire approval keep drafts paused and defer allocation and
verification until approval. Other companies prepare drafts during the
wizard under their existing agent-creation authority; the setup hold
still blocks ordinary work. Preparation uses existing lifecycle
ownership, retry, and cleanup paths. The open wizard polls only while
preparation or stopping is active. No database migration is required.

## Model Used

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

## 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 using the bug report fields
- [x] I have not referenced internal or instance-local issues or links
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run the targeted tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented the risks
- [x] All Paperclip gates are green — 55 successful checks and two
intentional skips on fda42c5ab
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 15:21:47 -07:00
Nicky LeachandPaperclip c7c12dbc79 Support plugin panels in task sidebars (#17796)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task side panels keep live work beside the conversation.
> - Plugins can already provide agent detail tabs.
> - Those tabs have no generic way to appear beside the task that is
using the agent.
> - This pull request adds an optional task-side-panel declaration to
agent detail tabs.
> - The plugin owns the label, component and availability. Core supplies
the task's running agent.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Access to plugin-contributed live views from task chat.

**Subsystem affected**

Plugin manifest validation, slot discovery, and task side-panel
UI/state.

**Current behavior**

Agent detail-tab contributions appear on agent pages. A task cannot
offer the same view through a plugin-owned availability decision.

**Proposed behavior**

An agent detail tab can declare `taskSidePanel: { availabilityPath }`.
Core substitutes the running agent into the plugin-local path. A
declared board GET route scoped to that agent returns `{ available:
boolean }`. Available contributions appear in desktop and mobile task
side panels.

**Reason and benefit**

Keep the task and its live plugin views together. Preserve plugin
ownership of provider protocols and product behavior. Core contains no
concrete plugin identifiers, routes, labels or readiness rules.

**Breaking changes**

None. The field is optional. Existing contributions remain unchanged.
Missing, disabled or unavailable plugins add no panel.

**Additional context**

Related: #17111 established the agent detail-tab and scoped API
extension surfaces. Roadmap and related PR searches found no duplicate
of this extension.

## What Changed

- Extend the manifest with optional task-panel metadata. Validate safe
plugin-local paths and require a declared board GET route with
agent-scoped authorization.
- Discover and load only opted-in agent contributions. Poll their
generic availability responses and mount the existing components with
agent context.
- Add generic panel tabs, launcher entries, dismissal and inactive-view
removal in desktop/mobile task chat.
- Reuse the existing live-run polling guard so idle tasks with a healthy
live connection stop polling.
- Add provider-neutral fixtures, schema/authorization tests, task tests
and SDK/feature documentation.

## Verification

- PASS: 301 focused tests including the full task-detail file, generic
panel discovery, persistence, slot loading and manifest validation.
Regressions cover POST-before-GET route order, mobile drawer dismissal,
recovery without focus and the absence of the hidden desktop task panel
on mobile.
- PASS: UI and shared-package typechecks; production UI build; token
gates, feature-map and module-boundary checks; diff and secrets/PII
review.
- PASS on final head: all 795 UI files / 9,186 tests, and all 95
shared-package files / 1,038 tests. Commands: `node
node_modules/vitest/vitest.mjs run --project @paperclipai/ui
--maxWorkers 3` and the corresponding `--project @paperclipai/shared`
command with local socket access.
- On the final head, server shards 7/12 and 10/12 and workspace shard
a-1/2 were interrupted by runner shutdown/communication loss. GitHub
reported infrastructure failures; no assertion failure was surfaced in
the available diagnostics. The queued summary was cancelled, then `gh
run rerun --failed` successfully requested retries for only those three
jobs. They are currently queued for CI runners; the 50 successful checks
remain passing. Interrupted attempts are not counted as passing.
[Final-head CI and
retry](https://github.com/paperclipai/paperclip/actions/runs/40396870920).
- Earlier verification exposed an empty-panel rerender loop, which was
fixed. The sandboxed combined run also failed five shared port-registry
tests because it could not bind loopback listeners; the full shared
rerun with socket access passed. These earlier failures are retained
here rather than reported as passing runs.
- Full workspace typecheck/build were attempted with pinned pnpm 9 after
resolving the initial local package-manager setup. Both stop at the
unchanged Runner Rust step because `cargo` is not installed. Full local
workspace checks are not reported as passing; final CI must provide
those broader checks.
- No live provider or plugin-specific transport acceptance is claimed by
Core's synthetic fixtures.

## Risks

- Availability is polled every three seconds only while an authorized
running agent exists. Plugins own the side effects and meaning of that
read.
- A view uses the running agent's context. It is not a separate per-task
resource.
- Optional metadata adds no backend endpoint or permission bypass. The
host requires existing board and agent authorization.
- Reverting the optional contract and UI integration removes task panels
without a data migration.

## Model Used

OpenAI Codex (GPT-6), with reasoning, repository tools and code
execution. The exact backend snapshot ID and context window size are not
exposed by this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue in-PR following the relevant issue
template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
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 any risks above
- [ ] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

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

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

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

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 21:39:04 +00:00
Nicky LeachandPaperclip 4ff493fb40 feat(plugins): include managed skills for selected environments (#17774)
## Thinking Path

> - Paperclip manages agents and their execution environments.
> - Plugins can vendor company skills and provide environments.
> - Environment tools need their instructions before the provider
starts.
> - Persistent computers also need those skills before any run begins.
> - This change adds environment requirements to normal skill selection
and lifecycle synchronization.
> - Plugin names prevent ambiguity, and required skills take delivery
precedence without deleting company data.

## Linked Issues or Issue Description

**Problem or motivation**

An environment can provide desktop tools while its agent receives no
instructions for those tools. A first-run-only import also leaves idle
computers without required skills. Same-name company skills can make
provider discovery ambiguous.

**Proposed solution**

Let plugin environment drivers declare their managed `skillKeys`.
Install missing requirements during lifecycle reconciliation or new-run
preparation. Deliver updates through the durable runtime event journal.
Give managed imports stable plugin names and report shadowed
assignments.

**Alternatives considered**

ROM links do not make a skill a normal Paperclip selection. Polling
duplicates the existing lifecycle delivery queue. Replacing a same-name
company record would destroy independent data and assignments.

**Roadmap alignment**

This extends the shipped Plugin system and Skills Manager. The existing
related-PR search found no duplicate contract.

## What Changed

- Validate `environmentDrivers[].skillKeys` as unique references to the
same plugin's managed skills. Require a ready, enabled plugin with
`skills.managed` authority.
- Resolve company-scoped skills before version capture. Preserve
explicit pins, company edits, and saved recovery selections. Serialize
concurrent first installs.
- Allow lifecycle callers to request missing-skill installation through
`agents.getRuntime`. Ordinary task and recovery reads do not install new
declarations. Pass task-selected environment IDs through the SDK.
- Add SQL migration `0378_environment_skill_runtime_hooks`. Required
skill edits, effective default changes, environment changes, and plugin
requirement changes enqueue durable runtime events. Reuse lifecycle
delivery and retries; add no polling.
- Import managed defaults as `plugin-<short-plugin-id>-<skill-slug>`,
including the SKILL.md name. Preserve canonical keys. Keep same-name
company records separate without counter suffixes.
- Required environment skills win delivery over same-name company
assignments. Preserve saved assignments and library content. Record
shadowed and winning keys in run warnings, run snapshots, and plugin
runtime state. Removing the environment requirement restores the
ordinary assignment.
- Document the contract for `driver: "plugin"`. Other drivers and
plugins without requirements keep existing behavior. Existing managed
copies retain edits and names until reset.

## Verification

- Latest targeted local checks: environment skills (5), managed skills
(9), heartbeat execution configuration (27), and SDK worker RPC host
(23): **65 tests passed** (including the targeted schema-drift check).
Disposable PostgreSQL exercised the migration, first install before any
run, concurrent lifecycle reads, implicit edit events, inherited
defaults, rollback, plugin requirement changes, shadowing, preserved
records, version capture, and recovery.
- Review follow-up also verifies case-insensitive/runtime-name aliases,
recovery of a task-mentioned shadowed skill, preserved quoted/multiline
YAML, and zero runtime events for repeated local-folder settings writes.
- Migration numbering and safety checks passed. Whitespace and
secret/PII scans passed.
- Earlier targeted manifest validation passed (43 tests). No validator
behavior changed in this follow-up.
- Broad tests, typecheck, build and end-to-end verification passed in
[GitHub
CI](https://github.com/paperclipai/paperclip/actions/runs/40387647219)
for current head `ce57f2a4d`. Greptile is 5/5 with no unresolved
threads. The [commitperclip review
check](https://github.com/paperclipai/paperclip/actions/runs/40387646208)
also passed after restoring its required duplicate-search checkbox.
- Earlier attempts found a SQL alias collision, an unparenthesized CASE
expression, and fixture assumptions about bundled catalog rows and YAML
quoting. These were corrected before the passing checks. The first broad
CI run also exposed a schema-drift check that assumed every journal
entry had a schema snapshot; it now reads the latest actual snapshot, so
SQL-only migrations need no invented snapshot. A test callback
replacement also affected an unrelated fixture; it was restored before
the final passing execution-configuration suite. Sandbox runs could not
start PostgreSQL; the reported database tests used local socket access.

## Risks

- Apply migration 0378 before using the updated lifecycle contract. It
adds trigger functions and event producers; it does not rewrite agent
assignments or skill content.
- Required environment skills take precedence over same-name
assignments, including task-selected skills. Both library records
remain. Run warnings identify omissions.
- Company edits are preserved. Plugin upgrades do not reset installed
content or rename existing copies. Explicit reset adopts current
defaults.
- Namespaced library slugs can be shared by distinct canonical records.
Callers must use IDs or canonical keys when a slug is ambiguous.
- No live provider request or deployment was performed. The downstream
plugin must be built against this Core revision. Persistent-home
synchronization retains its existing edit-conflict and retry behavior.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, and code
execution. The exact model identifier and context-window size are not
exposed in this task context.

## Checklist

- [x] Thinking path and issue description included
- [x] Model and available capabilities recorded
- [x] Roadmap and related PRs checked
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] Public references only; no internal issue IDs or instance URLs
- [x] Targeted local tests pass; broad verification delegated to GitHub
CI
- [x] New behavior covered and documentation updated
- [x] Current-head CI green and Greptile 5/5 with no unresolved comments

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:11:35 -07:00
DottaandPaperclip 507dc70be2 fix(evals): bind hosted controller admission to the first attempt (#17523)
Bind hosted controller admission to the repository, GitHub run, first attempt, workflow revision and selected execution before credential reads or provider launch. Keep offline evidence replay independent of the current worker environment. Preserve the single-project boundary editor and refresh project-access data with agent-detail updates.

Verified head: 1e588f75fe.
Validation: 74 synthetic source/portable controller tests, 98 focused UI tests and token gates passed before the ancestry-only final sync; four hosted/portable regressions pass again with unchanged eval and UI repair trees. Final exact-head full CI passed (40387856225), and Greptile reviewed this head at 5/5 with zero unresolved findings. The optional secondary Paperclip Review is paused and not counted as completed. No paid work or schedule changes.

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

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

## Linked Issues or Issue Description

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:43:12 -05:00
DottaandPaperclip f1922d95e1 test(runner): qualify the OpenCode discovery fixture on Linux (#17757)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Runner tests must exercise the same verified launch boundary as real
providers.
> - The assigned-tool test from #17740 used an executable JavaScript
script as its OpenCode fixture.
> - Linux launches verified executable bytes from a sealed, unlinked
memory file.
> - Node cannot reopen that deleted script path. Cleanup then hid the
startup error.
> - This pull request uses the native fixture wrapper already used by
the adjacent OpenCode integration test.

## Linked Issues or Issue Description

Refs #17740. Related fixture qualification work: #14529.

**What happened?**

The merged-source Cloud readiness job failed twice in the new
assigned-tool integration test. Linux could not start the script fixture
from the verified executable file. The later cleanup error hid the
original `ENOENT` error for `/memfd:paperclip-verified-launch
(deleted)`.

**Expected behavior**

The test must pass through the real Rust Runner, OpenCode proxy, and
HTTP MCP bridge on Linux. It must also report the original error if
cleanup fails.

**Steps to reproduce**

Run `vitest run src/live/runnerd-opencode-assigned-tools.test.ts` in the
Runner package with its Linux binary and built proxy. The original
fixture fails during startup. The native wrapper passes the
assigned-tool assertions and durable close.

## What Changed

- Launch the existing JavaScript server fixture through a native
wrapper.
- Qualify an owned Node copy on Linux with strict file permissions.
- Bundle the current production proxy into the test's temporary
directory. The test no longer skips when shared `dist` output is absent.
- Preserve both the original error and a cleanup error.
- Remove the temporary fixture even when setup fails.

## Verification

- Reproduced the failure in a local Linux container with the exact
merged Runner binary from the published Core image.
- The same Linux test passes after this change. It checks the assigned
discovery call, the completion call, and successful durable close.
- The updated test passes on macOS.
- A real Linux compiler-failure probe leaves zero fixture directories
behind.
- `pnpm -r typecheck` and `pnpm build`: passed.
- Runner TypeScript checks pass after the cleanup review change.
- Full technical CI passed on
`6ee1865af3310f13523b11407f9e41879832f543`.
- Fresh Greptile review: 5/5, with no unresolved findings.
- Fresh Paperclip Review published 5/5 on
`6ee1865af3310f13523b11407f9e41879832f543`, with no actionable findings.
- The optional Entire assessment remains pending because this branch has
no assessed Entire Change. The maintainer approved merging after CI and
both reviews pass.
- The full local test suite was not repeated. Earlier attempts hit host
PostgreSQL semaphore limits. CI provides the full suite check.

## Risks

Low risk. This changes one test fixture. Runtime behavior and launch
verification stay the same. The test now needs the C compiler already
required by the adjacent native fixture tests.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:36:22 -05:00
DottaandPaperclip 8c702d59db feat(evals): package a portable Runner controller runtime (#17506)
Package a verified portable Runner eval controller with complete bounded file receipts, copied dependency closure, private evidence replay and symlink-safe CLI entrypoints. Preserve fail-closed cost holds, native trace receipts and all parent security repairs.

Verified head: 1c892ff464.
Validation: 72 synthetic source/portable tests pass after current-master sync. Full current-head CI passed (40386180906); Greptile reviewed this exact head at5/5, with zero unresolved findings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 14:32:46 -05:00
DottaandPaperclip 5061ab7b35 perf(ui): speed up task and inbox cold opens (#17756)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task lists and inboxes are the main entry points to that work.
> - Cold opens fetch overlapping task lists, task descriptions, and run
details before useful rows settle.
> - Independent responses can insert rows above content that a person
has started to read.
> - This pull request loads a small task index first and adds details
only for visible rows.
> - It keeps row order and geometry stable while those details arrive.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Cold opens of Tasks and Inbox, including the shared navigation badge.

**Subsystem affected**

Server list reads, shared response contracts, and the React UI.

**Current behavior**

The badge fetches full task bodies. Mine fetches several overlapping
lists. Historical diagnostics and row metadata add work before the first
useful list. A fast failed-run response can appear before task rows,
then move down when tasks arrive.

**Proposed behavior**

Load the selected inbox source and its required context together. Use an
index without task descriptions or recovery diagnostics. Fetch
diagnostic details for up to 50 visible rows. Keep skeletons, recovery
indicators, external status, and live metadata in fixed space.

**Reason and benefit**

Reduce work on a cold open and prevent loading-induced row movement. On
the same 100 local fixture tasks, the compact response was 262,441
decoded bytes and the index was 110,909 bytes. This comparison excludes
compression and is not a page latency benchmark.

**Breaking changes**

Existing full and compact responses remain available. New index/row
projections are opt-in and marked as partial data. Mine keeps its
existing most-recent-100 display limit, now selected on the server.
Existing filters and group preferences remain in the client. No database
migration.

**Additional context**

Refs: #17593. Related: #13095, #17428, #13803. This change addresses
collection overfetch and layout stability. It does not replace the
blocked-inbox query work or the database activity-index work.

## What Changed

- Add authorized index and row projections, with bounded task and parent
ID batches.
- Replace badge list downloads with unread IDs and aggregate counts.
Preserve actor privacy, dismissals, and local archive behavior.
- Load only the selected inbox source, plus bounded parent and
failed-run context. Return only relevant failures from the bounded run
window.
- Batch hierarchy reads, including at most one authorized child per
collapsed parent in one request. Collapsed markers do not consume the
expanded row budget, and partial descendant counts are not shown as
totals. Enrich visible rows without replacing membership, ordering,
titles, or read state.
- Reserve row geometry on desktop and mobile. Reveal the initial inbox
only after its sources settle. Preserve legacy task-list reads.
- Start collection module downloads during access checks. Keep partial
rows out of the task-detail cache.
- Keep ETags and concurrent request sharing for the new projections, but
skip the short server response TTL so archive undo sees fresh state.

## Verification

- On final head `ef6afb2a56`, the full CI workflow passed, including
build, typecheck, server/workspace/runner suites, and all eight browser
shards. A server shard reported **1,489 passing tests** before runner
shutdown canceled the job; its single infrastructure retry passed. Both
Greptile and Paperclip Review are **5/5**, with zero unresolved review
threads.
- The optional external **Entire Gates** check remains `unassessed`
because it has no active assessed Change for this comparison. Entire is
not set up in this checkout. The repository ruleset requires `ci /
verify` and `ci / e2e`; both passed. No gate configuration was changed.

- Passed workspace typecheck after the final API batching change. The
full production build also passed on the final commit; the exact-retry
E2E run built the shipped UI.
- Passed token gates and map validation. The final batch-preview pass
has 91 passing route/hierarchy/component tests, including privacy,
request bounds, 30 collapsed parents in one read, and a 120-child parent
alongside a sibling.
- Passed the 166-test focused UI/inbox/badge run, 47 additional UI
regression tests, and 34 issue-list route tests. The latest regressions
cover low-trust agent badge IDs, cold company selection, 30
description-only Mine matches with archive actions, retrying optional
row details, and collapsed/expanded siblings.
- The full local `pnpm test:run` spanned the rebase and reported
failures in five suites before it was stopped; it is not claimed as a
complete pass. A fresh serial rerun of all five suites passed
**452/452** tests (tool gateway, native resume, project repositories,
workspace recovery, and runner selection). Full current-commit coverage
is checked by CI.
- Real browser: delayed index and row-detail responses on Tasks and
Mine. The first placeholder and first row had the same origin and
44-pixel height. Twelve rows on each page had zero position, height, or
title-width change after recovery details arrived.
- Real browser: reviewed long titles and recovery status at a 390 by 844
viewport. Task text stays on one line and recovery uses a compact
indicator.
- Three fresh document loads per page on final commit `260893bf92`, with
HTTP cache retained on a warm local development server: Tasks
1.031–1.190 seconds; Mine 0.999–1.193 seconds. Browser-control overhead
is included. These values must not be compared directly with staging
latency or the earlier local samples taken during a full test run.
- The browser archive test exposed stale results after Undo. The new
projections now bypass the server TTL; immediate-mutation regression
tests pass. The final browser retry passed: Archive followed by Undo
restored exactly one row and the badge count.

- CI exposed a hook-order crash when company selection resolved after
the first inbox render. The hook now runs before the empty-company
return. All seven affected exact-retry and legacy-continuation browser
scenarios pass locally after the fix.
- Real browser review regressions: 97 description-only source matches
retained Archive actions; deliberately failed optional row reads
displayed a retry notice while all 12 observed row positions and heights
stayed unchanged. Retry restored the recovery indicator. Network fault
injection was removed.

- The final production build and workspace typecheck passed. Final
focused verification passed 153 UI/helper tests and 26 heartbeat privacy
route tests. Final review regressions cover newer diagnostics arriving
during the index read, reloading diagnostics when the same task ID
changes version, optional source failure/retry without hiding available
rows, and required external-status filter failure. The latest-failures
route test verifies bounded selection, agent filtering, success
suppressing an older failure, and private-run redaction.
- Real browser: deliberately failed the run source, then retried it.
Twelve available task rows kept the same position and 44-pixel height
before, during, and after retry. No loading skeleton replaced them.
Fault injection was removed.
- Hierarchy review decision: the cold-open barrier stays because
inserting ancestors or expanded children after revealing index rows
would cause layout shifts. Existing hierarchy context now survives
subsequent requests, with a regression proving a new ancestor read does
not blank the list. The bounded recursive tree read can still add
latency for unusually deep expanded trees.

- Tasks now handles a failed external-status filter with an explicit
error and Retry, suppressing a false empty state. All 52 Tasks component
tests pass, including failure-to-success retry. One existing large-tree
test timed out while workspace typechecking ran concurrently; the whole
component suite passed when rerun without that competing work. Workspace
typecheck, the full production build, and token gates passed for this
fix.

## Risks

- Saved filters and grouping still operate on the existing bounded
collection. This is not a new global server pagination model.
- Fixed row slots reduce available title width. Long titles remain
accessible through task navigation.
- Recovery and related diagnostics arrive after core rows. Their
responses cannot replace ordering fields, and stale versions are
rejected.
- Index/row requests now revalidate against current data instead of a
short server TTL. They still share concurrent reads and use ETags.
- This has not been deployed by this pull request. Staging latency must
be measured after deployment under comparable conditions.

## Model Used

OpenAI Codex, GPT-6 family. The exact runtime model ID and
context-window size are not exposed in this session. Used code editing,
terminal execution, and real-browser diagnostics.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:29:20 -05:00
DottaandPaperclip 313c1db2c3 fix(evals): share bounded request policy with qualification (#17765)
## Thinking Path

> - Paperclip manages agents and their work.
> - Product E2E evaluations send model work through a gateway with cost
limits.
> - The gateway checks the request body before it reserves money or
contacts a provider.
> - A qualification probe needs that same check before it records a
spending-cap denial.
> - Namespace support already exists. Qualification must share that
policy without sending a paid request.
> - This pull request exposes the pure request validator and bounds the
supported local tool definitions.
> - The benefit is one request policy for qualification and forwarding.

## Linked Issues or Issue Description

Refs: #17452, #17469.

**What happened?**

The request validator was private to `forwardEvalRequest`. A
qualification caller could not reuse the request policy before
admission. A separate check could accept a request body that forwarding
rejects before a reservation.

**Expected behavior**

Qualification and forwarding use the same pure validator. One-level
OpenAI namespaces with local function or custom tools remain supported.
Invalid tool definitions fail before accounting or transport work.

**Steps to reproduce**

Use the synthetic native-daemon request fixture in
`eval-gateway.test.ts`. It has seven local function tools and one
namespace with five local function tools. Call the shared validator,
then forward through the fake provider. Run the malformed namespace and
tool-count cases to check rejection before side effects.

The namespace behavior follows the [OpenAI function-calling
guide](https://developers.openai.com/api/docs/guides/function-calling).
This change preserves the one-level contract introduced in #17452 and
hardened in #17469.

## What Changed

- Export `boundedEvalPayload` with credential-free route fields.
`forwardEvalRequest` calls that function.
- Keep one namespace level with function or custom leaves. Require exact
leaf types, nonblank string leaf names, and a closed namespace wrapper.
- Limit OpenAI tool definitions to 1,024 per request. Count namespace
wrappers and their children.
- Add native-daemon-shaped forwarding coverage, malformed and hosted
tool rejection, count and depth boundaries, and Anthropic compatibility
checks.
- Document the shared qualification policy in the Product E2E security
guide.
- Compile the real observability validator in the test parent. The owned
CLI fixture imports JavaScript, so its process group does not include a
test-only TypeScript compiler service. The parent resolves the compiler
from the root package, which declares that dependency. Production
cleanup checks and attempt deadlines stay intact.

## Verification

- `pnpm exec vitest run --config tests/runner-e2e/vitest.config.ts
eval-gateway.test.ts cost-ledger.test.ts provider-usage.test.ts
operating-overhead.test.ts operations.test.ts`: 173 passed.
- `pnpm test:e2e:runner:typecheck`: passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- Separate Node support checks: 137 passed.
- `pnpm test:e2e:runner:unit`: 4,271 passed, two skipped, four failed in
unchanged Daytona image and Pi catalog contracts. The same four failures
reproduce on untouched base commit
`a67a18c171816b097f46eae78fc58c7e55c9c565` (79 passed, four failed in
those files).
- `pnpm test:run`: interrupted and incomplete after required CI
completed. Initial database startup failed because this checkout omitted
the embedded PostgreSQL package postinstall aliases. The package
hydrator restored them, and 14 real database checks passed. Earlier
failures and the full output remain preserved; this local full run is
not counted as passing verification. Its owned process group exited
after SIGINT, with no owned survivors.
- An offline full native authentication probe used the real Rust daemon
and pinned Codex 0.160.0 Darwin SDK. The same captured request failed
the older operations policy before reservation and reached a mock
reservation with this policy. The OS sandbox allowed loopback only. It
used synthetic credentials, retained no raw model payload, and made no
provider calls.
- Controller fixture suite: 70 passed. Three cold comparisons each
confirmed that the old child started an owned compiler service and the
corrected child did not. On Darwin the old compiler also exited cleanly,
so this does not prove the exact historical Linux process race. Fresh
Linux CI is required.
- Independent review passed. The private qualification integration
passed 14 exact-source compatibility checks and 67 shared-source tests
without provider calls.

- Required GitHub CI checks passed on the current head. The separate
Entire approval gate still awaits an eligible reviewer; the delegated
author account's explicitly AI-assisted approval does not satisfy it.

## Risks

Requests with more than 1,024 OpenAI tool definitions or extra namespace
wrapper fields now fail closed. New provider schema fields will need
review. Anthropic tool handling, model prices, billing restrictions,
output caps, and reservation ordering remain unchanged. This offline
request-policy proof does not establish a completed model turn or Linux
or Cloud onboarding acceptance.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model identifier and
context window are not exposed in this session. The model used
reasoning, tools, and code execution.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 14:14:47 -05:00
DottaandPaperclip 125ddcabe5 perf(runner): keep event journal writes off the HTTP thread (#17745)
## Thinking Path

> - Paperclip lets people manage AI agents and their work.
> - The HTTP server also owns durable Runner state.
> - Each committed event rewrites and flushes that state on the HTTP
thread.
> - Large journals and slow writes delay unrelated navigation and saves.
> - Event acknowledgements must still wait for durable storage.
> - This PR stages output writes asynchronously and joins them before
writer replacement.
> - The board can serve requests while Runner output waits for storage.

## Linked Issues or Issue Description

Refs: #17507. Related: #17514 reduces writes per event burst. This PR
moves individual output writes and file flushes outside the HTTP thread.

**What happened?**
A live CPU profile spent about three seconds of a 13-second sample
serializing and synchronously writing Runner state. Representative
journals were about 9 MB. Unrelated task requests had multi-second
delays.

**Expected behavior**
A slow output-journal write must leave unrelated HTTP requests
responsive. An event must not be acknowledged before it is durable.

**Steps to reproduce**
Hold an authenticated output event's file flush in the durable protocol
test. Send an unrelated HTTP request during that flush. Also save a
command, reconnect, or retire the controller during the write.

## What Changed

- Stage `item.delta` snapshots with asynchronous file writes and file
flushes. Keep lifecycle, control, authentication, and tool events
synchronous so transport readers observe durable boundaries.
- Fence publication by saved revision. An older snapshot cannot replace
newer commands or connection state. A failed write fences the writer.
- Write compact JSON and share private-file checks. Existing journals
remain readable.
- Stop external ingress before joining admitted writes. Checkpoint only
after retirement succeeds. Close reports a failed detach consistently
and releases notification consumers.
- Add real HTTP and Rust transport cases for held writes, reconnects,
commands, failure, restart, close, and timeout.
- Add immutable Copilot source identity v61 for the changed shared
transport. Preserve v60, historical decoding, exact-current launch
checks, and qualification flags. No new live Copilot qualification is
claimed.

## Verification

- Head `6f5c92e778`: workspace `pnpm -r typecheck` and `pnpm build`
passed. All CI gates passed in [run
40356159484](https://github.com/paperclipai/paperclip/actions/runs/40356159484),
including both full Runner shards. Fresh Greptile review is 5/5; all
findings are resolved.
- Current-base focused verification passed 300 cases across protocol,
real Rust restart/continuation, permission, backend, and
immutable-profile suites. The complete transport suite also passed 286
cases before the base refresh.
- Earlier iterations exposed lifecycle visibility, late writer
publication, and close-order failures. Controlled regressions reproduced
each before repair. CI also found missing test-peer drain methods and a
stale source fingerprint; both are corrected. An older broad local test
run was stopped after its source was superseded. No full local-suite
pass is claimed; full coverage passed in isolated CI.
- A synthetic 9 MB journal comparison used 20 writes per sample and
concurrent HTTP probes, with alternating baseline/treatment order. HTTP
median changed from 31 ms to 2–3 ms; p95 changed from 51–85 ms to 12–21
ms. Parsed output was equal. The asynchronous loop served 125–153 probes
versus 19–20, and took longer overall (992–1069 ms versus 675–678 ms).
This proves local I/O responsiveness, not deployed application latency.
- Deployment and live save/archive acceptance remain pending.

## Risks

Persistence interleavings affect restart authority. The tests cover
concurrent commands, replacement, failed storage, and reopening the
journal. JSON serialization, atomic rename, directory flush, and
control-event writes remain synchronous. This change still rewrites
whole journals. Incomplete retirement retains recovery evidence and
fails the close. A new exact-current Copilot source identity can reject
an older launch identity; historical decoding remains available. No
migration is required.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, tool use, SSH and browser
diagnostics, code editing, and test execution. The exact serving model
suffix and context-window size are not exposed in this session.

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

**Paperclip version or commit**

Source checkout based on current `master`.

**Deployment mode**

Native local or sandbox execution with OpenCode 1.18.34.

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

## What Changed

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

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

## Verification

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

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

## Risks

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

## Model Used

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

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 10:29:51 -05:00
DottaandPaperclip ad861a7f94 fix(runner): allow bounded controller admission before welcome (#17735)
## Thinking Path

> - Paperclip manages AI agents and preserves their work across
execution failures.
> - Native Runner authentication exchanges a one-use bootstrap ticket
for a connection lease.
> - The controller must admit the connection and persist that lease
before it sends welcome.
> - Runnerd waited only two seconds for welcome, even when its
connection setup budget allowed more time.
> - A slow valid welcome therefore looked like a consumed-ticket failure
before provider work could start.
> - This pull request uses the existing ten-second connection setup
budget for welcome.
> - The benefit is reliable startup during bounded controller delays,
with the same authentication and replay checks.

## Linked Issues or Issue Description

**What happened?**

A valid native Runner bootstrap can fail while the controller completes
admission. The runner then reports `bootstrap connection failed closed;
provide a fresh one-use ticket`. A later recovery attempt can report an
indeterminate authority and hide the startup error behind a finalization
deadline.

**Expected behavior**

A valid welcome can arrive within the connection setup budget. An
earlier execution or reconnect deadline still ends the wait. A missing
or invalid welcome never permits bootstrap-ticket replay.

**Steps to reproduce**

1. Run the real Runner WebSocket transport against an authenticated
controller.
2. Hold the welcome for three seconds after the client proof arrives.
3. Before this change, authentication fails with `WebSocket
authentication message deadline elapsed` and `bootstrap_maybe_consumed:
true`.
4. With this change, the runner accepts the bound lease and restores the
normal read timeout.

**Paperclip version or commit**

Reproduced against `a1f77821b9` before the production change.

**Agent adapter(s) involved**

Native Paperclip Runner. The transport is shared by its provider
drivers.

Related: #17401 reduces repeated work in warm-recovery admission. This
change covers delayed welcome delivery for fresh authentication too. It
does not replace that optimization. #17594 addresses a separate lifetime
failure after controller outages.

## What Changed

- Use the ten-second connection setup budget for the authenticated
welcome.
- Keep the execution/reconnect deadline as an earlier bound.
- Add real WebSocket regressions for a delayed welcome and a shorter
lifecycle deadline.
- Add a real Runner process test proving a delayed admission starts one
provider and keeps it through two turns.
- Document the startup contract and its recovery verification scope.

## Verification

- Red: the delayed-welcome regression failed against unchanged
production code with a message deadline and `bootstrap_maybe_consumed:
true`.
- Green: all 402 Runner core library tests pass. The suite includes
authentication, ticket fencing after a lost welcome, identity rejection,
replay, and no repeated provider effects.
- Map and module checks pass.
- Workspace `pnpm -r typecheck` and `pnpm build` pass. The new process
integration test passes (one provider process, one thread, two turns,
suspended with an empty outbox).
- Live acceptance at this branch's production Runner build passes on
macOS arm64 with pinned OpenCode 1.18.34 and
`openrouter/deepseek/deepseek-v4.1-flash-1017`: delay admission by three
seconds, create a file, suspend, resume the same provider session under
a fresh run authority, read the first file, and write a second file.
Both useful outputs match exactly; final runner state is suspended.
- Preserved setup failures: a non-pinned executable was rejected, and
the debug binary exceeded cold provider startup admission. The pinned
executable and release binary passed. The first harness also tried to
reuse a completed task object; the follow-up used the normal resume
path. Exactly two paid model turns ran.
- The full local `pnpm test:run` was attempted and stopped after the Mac
exhausted PostgreSQL semaphore capacity (`could not create semaphores`);
it is not a local full-suite pass.
- Current-head CI is green at
`df5d5494c9f9f444114aaf12e095a554110d2e14`: all checks passing or
non-applicably skipped, zero failures or pending checks. The additional
Superagent security scan triggered by ready-for-review also passed.
These include all general/serialized test shards, Runner Rust/Vitest,
E2E, typecheck, build, and the final verify gate. Greptile reviewed that
exact commit at 5/5 with no findings or inline comments.
- This proves the actual native Runner/provider path locally. It does
not prove rollout or recovery on a hosted Linux/amd64 execution
environment.

## Risks

- A stalled welcome can take up to eight seconds longer to fail when the
configured lifecycle allows it. Shorter execution/reconnect deadlines
still take precedence.
- Authentication proofs, credential expiry, identity binding, and
one-use-ticket fencing remain enforced.
- This does not repair provider-side grammar errors or authorize replay
of an indeterminate historical run. Recovery of existing work requires
the normal stopped-owner and retained-state checks.
- No schema or migration change. A new Runner binary must reach the
execution host before this change affects remote runs.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
execution, and browser tools. The exact serving submodel identifier and
context window were not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 10:25:59 -05:00
DottaandPaperclip bbe1016d81 feat(evals): retain bounded native tracing in the Runner controller (#17493)
Retain bounded native tracing in the Runner controller with attempt-bound relays, private export receipts, offline cost replay, conservative holds and bounded failure diagnostics.

Verified exact head 5cb991421e: full hosted CI, fresh Greptile 5/5, zero unresolved threads, 70 local controller tests including actual Codex/Claude CLI observability validators. Secondary review has no must-fix or should-fix findings and records optional coverage follow-ups. No paid evals or schedule changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 10:22:42 -05:00
DottaandPaperclip 3f91d58dd5 fix(ci): provide Copilot auth only to protected paid eval cells (#17743)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Paid runner evals test real provider integrations.
> - Copilot cells use the saved-token connection path.
> - The two trusted workflows did not pass the Copilot credential to
those cells.
> - This PR supplies it only when the selected cell needs it.
> - Existing environment and actor gates protect access in this public
repository.

## Linked Issues or Issue Description

Related: #15705 and #15706. A search found no open PR that adds this
workflow credential binding.

**Describe the bug**

Copilot Product and direct-protocol eval cells require
`COPILOT_GITHUB_TOKEN`. The protected paid workflows do not currently
pass that environment secret to the selected execution step.

**Expected behavior**

Only a selected Copilot cell receives this credential. Ordinary PR,
build, catalog, image and reporting jobs receive none.

**Steps to reproduce**

Dispatch the trusted full-stack workflow for one Copilot cell.
Credential validation fails before the task starts, although the
protected environment can hold a valid token.

**Environment**

GitHub Actions in the public `paperclipai/paperclip` repository, with
the reviewed workflow on `master` and the `runner-e2e-paid` environment.

## What Changed

- Pass `COPILOT_GITHUB_TOKEN` in the paid Product and direct-protocol
execution steps, only when `matrix.credentialName` selects it.
- Add the missing Copilot protocol-catalog credential mapping and verify
it reaches the selected execution matrix.
- Add security checks for the selected-cell binding and bounded
protected-job scope. Extend the scan that rejects provider credentials
in unrelated workflows.
- Document the Copilot credential scope. No secret values, account data
or private test evidence are in this PR.

## Verification

- Product workflow security: 16 tests passed on this head.
- Protocol catalog and workflow security: 21 tests passed, including the
Copilot matrix regression reproduced red before its fix.
- Current-head required `ci / verify` and `ci / e2e` are green. Greptile
is 5/5 with zero unresolved review threads.
- The first CI attempt retained runner-shutdown failures; one failed-job
retry passed on the unchanged head. Both attempts remain in [the CI
run](https://github.com/paperclipai/paperclip/actions/runs/40342429106).
- `git diff --check` passed.
- A selected-credential scan found zero matching secret values in the
seven changed files.
- The environment setting was separately checked: `master` only,
required approval from existing allowlisted code owners, and
administrator bypass disabled. The new secret exists only at environment
scope; no repository-wide duplicate was created.
- The packaged Copilot runtime verified the selected token and the
explicit model without a model prompt. A fresh local UI journey then
created an agent, completed its first task and verified the downloaded
artifact and cleanup.

## Risks

The selected paid cells gain access to one additional environment
credential. Missing credentials still fail closed. Default-branch
checks, initiating/rerunning actor checks, protected environment access
and per-cell credential selection remain in place. This PR adds no
trigger and gives no credential to builds or ordinary PR checks.

## Model Used

OpenAI Codex, based on GPT-6, with repository tools and browser
regression tests. The exact runtime model identifier is not exposed in
this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 10:17:14 -05:00
DottaandPaperclip 49bd7a4ba6 feat(evals): retain portable Runner controller evidence (#17469)
Retain private Runner request evidence for offline cost reconciliation. Bound post-child reads, reject hidden paid tools, exclude configured credentials, bind incomplete results, and replace redacted proof atomically.

Verified at f5c1791623: full hosted CI, Greptile 5/5, secondary review summary 5/5, no unresolved threads. No paid evals or schedule changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 09:50:58 -05:00
DottaandPaperclip a1f77821b9 perf(tasks): show recent conversation before historical activity (#17593)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A task page must show the instruction and current conversation
quickly.
> - The current page waits for related task data and historical run
transcripts.
> - These reads grow with task history, even when the reader only needs
the latest answer.
> - This pull request gives cold opens a small initial view and loads
older history on demand.
> - Messages and runs observed while the page stays open remain visible.
> - The benefit is a readable task before historical diagnostics finish
loading.

## Linked Issues or Issue Description

Related: #14667 and #16229. The first changes the reveal gate and scroll
anchors. The second adds general history pagination. This PR adds a core
task read and a folded recent-conversation view. It preserves the
default full-read API contracts. The shared files will need coordination
if either related PR lands first.

**What existing behavior does this improve?**

Cold opening an ordinary task with a long conversation or large run
logs.

**Current behavior**

Task enrichment and historical transcripts delay the readable
conversation. A cold open can fetch several megabytes of tool activity
before revealing saved messages.

**Proposed behavior**

Show the task instruction, recent saved replies, latest human input, and
the latest run's conversation data first. Fetch older messages and full
run activity when the reader chooses **More messages**. Retain new
messages while the page stays open.

## What Changed

- Add an authorized core issue view that skips related enrichment. Keep
enrichment on the existing detail read. Share task mutation, rollback
and invalidation updates with the core cache.
- Add a bounded recent-comment read. Preserve the first human
instruction when no description exists, including legacy rows with a
NULL author type. Keep company and task access checks and comment
redaction.
- Add optional recent activity and run-summary views. Fetch original
input receipts for visible comments separately so delivered messages
stay out of the queue. Reconcile watched unfinished runs after a
reconnect beyond the preview window, removing deleted runs after
reconciliation.
- Filter the latest native run's initial events to assistant messages,
request lifecycles and terminal results. Full event reads remain
available on expansion. Legacy fallback reads use a small tail extended
to the first complete record. HTTP cancellation aborts the storage read.
- Retain observed messages across cursor catch-up and new runs. Apply
local cancellation and deletion to both caches and their task aliases.
Refetch locally seeded history pages on expansion. Preserve expansion
across identifier and UUID links. Keep deep links, classic tasks and
Agent Chat on their existing full-history path.
- Update API documentation, design guidance, capability maps and
regression coverage.

## Verification

- Final acceptance on `9ea0b15ae44d9f6d2c9a9f824b4835f299f92979`: all CI
gates passed, including server/UI tests, all eight browser shards,
runner checks, full typecheck and build. [Final CI
run](https://github.com/paperclipai/paperclip/actions/runs/40326990328).
GitHub reports 55 successful checks, two intentionally skipped checks,
and one neutral Paperclip Review check described below. No checks are
pending or failed; Greptile is 5/5 and no review threads remain open.
- October 26 merge update: merged current `master`. The only conflict
was in task-page imports; both the compact-history hook and the new
live-update hooks remain. All CI tests and build jobs passed on
`044fd6733d`. Fresh review found canceled-comment cache drift, legacy
human-comment filtering, send-then-expand truncation, and partial legacy
log records. These defects were fixed in `af3d66a5bd`.
- Review-fix verification: 470 tests pass across ten affected suites,
including all six PostgreSQL cold-open tests without a helper override.
Cancellation/delete and send-then-expand regression tests failed before
the fixes and pass afterward. Coverage includes task identifier/UUID
reopen, stale in-flight reads, legacy NULL author types, local-file and
object-storage tails cut inside UTF-8 text, route forwarding, and
request cancellation. Full workspace typecheck and production build,
token gates, map validation and diff checks pass.
- Follow-up review found that a failed expanded legacy read lost its
record-alignment state on retry. `9ea0b15ae4` commits the expanded
window only after a successful read. The new regression fails before the
fix and passes afterward; all 19 transcript tests, UI typecheck, UI
build and token gates pass. Greptile reviewed this commit at 5/5 with no
actionable findings, and all review threads are resolved.
- The final Paperclip Review check ended neutral because its execution
did not complete; no passing Paperclip assessment is claimed. Its
earlier four concrete findings were fixed and regression-tested.
Greptile and the security scans completed successfully on the final
commit.
- The preceding `af3d66a5bd` CI run was canceled when superseded by the
retry fix. Its server shard 11 check briefly reported failure, but the
job API records cancellation and its test step passed all 1,750 tests.
This superseded run is not used as final CI acceptance.
- 549 focused tests pass on the final implementation across nine task
UI, activity-route, OpenAPI and PostgreSQL suites. These cover pending
history, desktop/mobile visibility, expansion, retained runs, message
bursts, cancellation recovery and queued-comment removal in both views.
- Legacy expansion keeps the latest answer visible while fetching and
deduplicating older output.
- Five PostgreSQL tests pass for core access denial, recent comments,
missing-description instructions, event paging and bounded activity/run
reads. macOS could not start another PostgreSQL cluster because it
exhausted its semaphore limit. These tests used a separate disposable
database on an existing local server through a temporary test setup
override. The helper was restored afterward.
- Full workspace typecheck and build pass with the final state fixes, as
do token gates and capability-map validation.
- Token gates, capability-map validation and `git diff --check` pass.
- Browser proof used a disposable task with 80 comments and six large
run histories. The cold view showed the instruction and recent exchange.
**More messages** revealed older comments. Navigation away and back
preserved expansion.
- Local HTTP sample: core 50 ms, recent comments 24 ms, recent run
summaries 17 ms. The latest native conversation response was 839 JSON
characters / 8 ms; its full event response was 1,099,005 / 86 ms.
Browser content paint was 1.34 seconds with development assets cached.
These are local observations, not staging latency claims.
- The first CI run passed every job except four board-send browser cases
and the review threshold. Those browser fixtures only mocked the old
comments endpoint; they now serve both recent and full reads, retaining
all message and attachment assertions. Both initial review findings were
fixed with regression tests. The next CI run passed every job. The
deeper review identified core-cache mutation, older delivery receipt and
retained run-status gaps; those are now fixed with regression coverage.
Final review is 5/5 with zero unresolved findings. Final-head CI
initially failed one unchanged runner shutdown test
(`runnerd-codex-transport.test.ts`, timeout-attachment case) with
`NativeSessionCloseUnrecoverableError`; all other CI jobs passed. The
same runner code passed on 971a762f80. A targeted local reproduction
also failed during provider drain. The failure is outside the changed
task loading paths; its underlying cause remains unresolved. The single
failed-job retry passed on the same head; this demonstrates recovery,
not a root-cause fix. All CI gates passed on the previous implementation
head `9004f94f28`: [CI run and
retry](https://github.com/paperclipai/paperclip/actions/runs/40192334629).
- `pnpm test:run` was attempted and stopped after repeated embedded
PostgreSQL startup failures. The native session suite recorded 15
database-related failures; other database suites could not start. No
complete local suite pass is claimed.

## Risks

- The compact view intentionally omits older diagnostics until
expansion. Existing open questions and approvals still use the current
interaction and run paths.
- Previously observed comment and activity rows remain cached while
open. The newest preview and incoming cursor pages refresh; this does
not add a general historical-edit synchronization protocol.
- Recent views are optional. Existing full API callers retain their
response shape and behavior. No migration is required.
- A legacy tail can exceed the requested byte limit by the prefix of its
first log record. Backward reads stop at the preceding record boundary
and honor cancellation.
- Staging has not been deployed or qualified with this change. Instance
startup latency is separate from task history loading.
- The related open PRs touch the same task-history files.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository editing, shell
tools and browser testing. The exact serving model identifier and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 08:11:39 -05:00
DottaandPaperclip 41c42895fa feat(evals): enforce fixed Runner request allocations (#17452)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Runner evals execute real provider harnesses against maintained
fixtures.
> - Turn-level usage arrives after requests have already spent money.
> - Parallel cells need distinct allowances before requests start.
> - Missing output must preserve the remaining allowance and any known
charges.
> - This pull request adds a controller that reuses the existing request
ledger and gateway.
> - It makes a bounded local Runner attempt reviewable before hosted
scheduling is enabled.

## Linked Issues or Issue Description

Refs #17440. That PR added the explicit Runner gateway route. This PR
owns request admission and retained campaign accounting for that route.

The existing hosted matrix is not enabled or changed here. Its global
allocation, rerun rejection, and private evidence archive remain
separate integration work.

## What Changed

- Validate a trusted manifest with exact request, CLI, package, daemon,
model, and source identities. Assign each selected cell a distinct
allowance. Count operating overhead once. Reject allocations above the
campaign limit before launch.
- Run native Codex or ACPX Claude through the shared request proxy and
append-only ledger. Pass only the proxy credential to the child. Refuse
local attempt reuse and preserve existing output files.
- Close gateway admission on cancellation. Retain the ledger, receipts,
route descriptor, child result, and cleanup evidence outside the
disposable workspace.
- Recompute campaign accounting from retained ledgers. Missing or
invalid final evidence holds the full cell allowance while preserving
known charges. Reports distinguish provisional and incomplete costs.
- Accept namespaces containing only local function/custom tools. Disable
web search in the controlled Codex profile. Continue to reject hosted
tools, including tools hidden inside a namespace.
- Add controller tests to the existing Runner static test path and
document this source-checkout entry point.

## Verification

- 20 controller tests pass. They use real child processes, local HTTP,
and the actual ledger. Cases cover reservations before dispatch,
concurrent cell isolation, caps, cancellation, replay rejection, lost
artifacts, changed receipts, and Braintrust Claude routing. Upstream
responses are synthetic.
- 52 shared gateway tests and 55 Runner CLI tests pass. The namespace
acceptance and web-search configuration regressions failed before the
repair and pass afterward.
- Runner TypeScript/Rust checks, Runner build, shared E2E typecheck, and
`git diff --check` pass.
- The first actual-harness probe found that Codex advertised both a
local tool namespace and web search. It reached no upstream transport.
That failure is retained; the compatibility repair does not allow paid
hosted tools.
- An earlier test failure showed that separate dynamic imports created
different admission-error classes. The shared runtime bridge now loads
one module graph. Another regression showed that a missing final report
hid known ledger charges; the collector now preserves those charges.
- The repaired actual-harness probe passed its control checks for native
Codex and ACPX Claude: each reached exactly one synthetic upstream
request after the ledger reservation; both retained the unresolved hold
and route evidence; both recorded clean process exit. A scan of 41
retained files found no synthetic upstream credential. Deliberate
provider rejection preserved the failed Codex turn and Claude timeout;
these are not semantic passes. Prices, operating bounds, and the package
archive identity in this probe were synthetic.
- Review regressions reproduced lost request/receipt evidence, lost
admission metadata, executable replacement after verification, and a
SIGTERM-resistant descendant surviving the CLI. The repairs now pass.
Executable bytes are staged before launch; a trusted Node resolution
hook preserves relative imports. A symlink-path regression also failed
before its repair and now passes. The final staged native probe repeated
both one-request checks successfully.
- Full current-head
[CI](https://github.com/paperclipai/paperclip/actions/runs/40115932485)
passed on `4781487215116afd10a415d4db53b1ec8e004dd5`: all 58 check runs
and the legacy status are successful, neutral, or skipped. Greptile and
Paperclip both reviewed this commit at 5/5. All five finding threads are
fixed and resolved. No paid provider request ran during this change.

## Risks

- This is a trusted source-checkout controller, not a published package
command. It needs the repository's installed shared cost dependencies.
- The manifest declares reviewed prices and full-lifecycle bounds.
Synthetic tests do not qualify real prices, invoices, storage, or
Braintrust metering.
- The attempt-directory guard is local. Hosted fanout still needs unique
global allocations, rerun rejection, and durable private retention. Do
not enable the existing matrix on this change alone.
- Forced child termination can leave cleanup unverified. That attempt
remains incomplete and holds its full allocation. These checks do not
claim a host security boundary against an adversarial target.
- The current private publisher does not archive the separate controller
directory. Native trace relay, private report integration, and live
qualification remain open.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-26 07:53:57 -05:00
Devin FoleyandPaperclip 1a3f604097 fix(db): honor the prepared-statement opt-in for ORM queries (#17673)
Drizzle calls Postgres.js unsafe queries, which disable preparation unless
per-query options enable it. The existing client-level opt-in therefore
does not prepare ORM queries.

Honor explicit true across root and child clients. Preserve defaults,
per-query options, lazy execution, and driver error handling. Document the
pooler capability requirement.

Test with 92 selected database and connection checks, workspace typechecks,
server and database builds, and a read-only hosted ORM protocol probe.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 18:17:43 -07:00
Devin FoleyandPaperclip 34409a92c4 fix(native-runtime): stop failover backups from carrying throwaway provider state (#17618)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

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

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

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

## What Changed

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

No code comments were added.

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

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

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

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 09:01:24 -05:00
Devin FoleyandPaperclip efa2724f9a fix(db): pace bounded response capture output (#17564)
Close database response measurement at its existing deadline, then emit the bounded metadata at 64 records per second. Preserve group indices, counts, privacy, and query/transaction outcomes. Stop the unreferenced timer when the output queue is empty.

Validation: 32 capture and real PostgreSQL tests, full build and typecheck, exact-head Greptile 5/5 (medium), full green CI, and no unresolved comments. A 2,200-query fixture reconciles all 2,048 groups and its summary; dedicated-pool coverage awaits deferred output.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 00:11:41 -07:00
Devin FoleyandPaperclip a12329b8a9 fix(db): complete bounded response attribution (#17537)
Raise bounded database-response attribution to 2048 groups and add numbered 128-entry log pages. Preserve the overflow bucket and exact completed-call and byte totals. Document complete page retrieval and validation.

Verified with 30 focused tests, the full build, and typecheck. All CI checks pass. Exact-head Greptile is 5/5 at Medium impact with no unresolved comments.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-24 19:34:31 -07:00