Commit Graph
2490 Commits
Author SHA1 Message Date
bbcf5dfe98 fix(heartbeat): renew legacy controller leases on a private pool (#17032)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A legacy (non-native) agent run keeps a controller lease on its
`heartbeat_runs` row. The server renews the lease every 10 seconds. If
no renewal succeeds in 60 seconds, the watchdog stops the run with
`renewal_deadline`.
> - #16359 added timings to lease-loss reports. The first staging event
with these timings shows `deadlineLateMs=0`, `renewalPendingMs=50000`,
and 108 renewals in about 22.5 minutes, where about 135 are expected.
Thus the event loop was not blocked. One renewal UPDATE was in flight
for 50 seconds, and renewals were slow for a long time before the loss.
> - The agent had exited with code 0. The run was in post-execution
`sync_back`. Other runs on the same host completed. No code path held a
lock on the run row across slow work. A later `instruction_save` UPDATE
on the same row completed while the earlier renewal was still pending,
so a row-lock wait does not explain the stall.
> - postgres.js 3.4.9 sends a new query to a busy connection when no
connection is idle (`handler` → `go(busy.shift(), query)` in
`src/index.js`). The query waits behind the statement that is in flight
on that connection. The renewal had no timeout, and the `pending` flag
stopped all later renewals. Thus one slow unrelated statement on the
shared pool can stop a healthy run.
> - This pull request moves lease renewal to a small private pool,
bounds each attempt with a statement timeout, and retries a timed-out
attempt until the existing lease deadline.
> - The benefit is that slow application queries on the shared pool can
no longer cancel a healthy legacy run.

## Linked Issues or Issue Description

Refs #16359 (lease-loss timings that identified this cause)
Refs #16358 (pre-dispatch lease loss becomes retryable; different path)
Refs #16917 (open: keeps a clean adapter result after a lease lapsed; it
does not prevent the loss)
Refs #13389 (open: host sleep / late timers; different cause)

**What happened?**
A staging legacy `claude_local` run was cancelled with `Legacy
controller lease lost (renewal_deadline)` after the agent exited with
code 0. The timings show that the deadline timer ran on time, and one
renewal UPDATE was pending for 50 seconds.

**Expected behavior**
A live controller keeps its lease. Slow unrelated database work does not
cancel the run.

**Steps to reproduce**
1. Create a database client with one pooled connection.
2. Start `select pg_sleep(5)` on that client.
3. Call `watchLegacyControllerLease(...).assertOwned()` with the same
client.
4. Before this change, the renewal waits about 5 seconds behind
`pg_sleep`. With a long enough slow statement, the lease deadline stops
the run.

## What Changed

- `packages/db`: Add `livenessDb(db)`. It gives each `createDb` client a
private pool of at most 2 connections
(`application_name=paperclip-controller-lease`). The pool is created on
first use. Test doubles and transactions get the original client back.
- `packages/db`: Add `closeLivenessDb(db, timeoutSeconds)`. The server
calls it in `closeDatabaseClients`, so shutdown and failed startup end
the private pool too.
- `legacy-controller-lease.ts`: The watchdog renews in a transaction on
the private pool. Each attempt sets a transaction-local
`statement_timeout` of 10 seconds. A timed-out attempt (`57014`) is
retried. After a successful retry, the local deadline is measured from
that attempt's start, because that attempt's UPDATE wrote the fresh 60
second lease. The existing 60 second deadline, the abort race, and the
`renewal_rejected` / `renewal_error` attribution do not change.
`renewLegacyControllerLease` itself does not change, so the
runtime-selection caller inside its own transaction is not affected.
- Tests: a saturated shared pool no longer delays renewal; a renewal
that times out on a locked run row retries and keeps the lease; the
private pool is cached per client, has its own `application_name`, and
closes; after a 45 second timed-out attempt and a successful retry, the
next deadline is a full 60 seconds after the retry. The existing test
doubles now model the transaction.
- `docs/deploy/database.md`: Count the up to 2 extra connections per
server process when you size `max_connections`.

## Verification

- `cd server && npx vitest run
src/services/legacy-controller-lease.test.ts`: 20 passed, on embedded
Postgres.
- Red/green: with the old `legacy-controller-lease.ts` and the new
tests, the saturated-pool test fails with `expected 5018 to be less than
2000`. With the fix, it passes.
- Red/green for the retry deadline: with the deadline measured from the
first attempt, the retry-deadline test fails (`expected true to be
false`) because the run is aborted 15 seconds after the retry. With the
fix, it passes.
- Mutation check: when the timeout retry is removed, the locked-row test
fails with `canceling statement due to statement timeout`.
- `npx vitest run src/__tests__/heartbeat-process-recovery.test.ts -t
"lease|dispatch|controller|interaction"`: 43 passed.
- `npx vitest run src/services/heartbeat/run-completion.test.ts
src/__tests__/heartbeat-orphaned-active-lease-sweep.test.ts`: 53 passed.
- `npx vitest run src/__tests__/server-startup-feedback-export.test.ts`:
passed.
- `cd packages/db && npx vitest run src/work-signals.test.ts
src/client-options.test.ts src/client-teardown-registry.test.ts`: 24
passed. `npx tsc --noEmit` for `packages/db` passed.
- Not run locally: the full server `tsc` and the full server suite. The
sandbox has a 4 GB memory limit, and `tsc` was killed (exit 137). CI is
the gate for the server typecheck, the full tests, and the build.

## Risks

- Each server process can open up to 2 more Postgres connections.
Deployments that are at their `max_connections` limit must allow for
them. The docs now say this.
- A renewal attempt is now 4 statements (BEGIN, `set_config`, UPDATE,
COMMIT) instead of 1. Each statement is a short primary-key operation on
a dedicated connection.
- If many runs wait on locked run rows at the same time, renewals for
other runs can queue on the 2 private connections. The 10 second
statement timeout limits each wait, which is less than the 60 second
lease.
- Behavior for a real lease loss does not change. A rejected renewal and
a non-timeout error still stop the run at once, and the 60 second
deadline still applies.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used through Claude
Code in agent mode with tool use (shell, file edit, and test execution).
A read-only subagent helped with code 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: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:13:53 -07:00
Nicky LeachandPaperclip e5351b240a Verify native Runner setup through plugin tasks (#17029)
## Thinking Path

> - Paperclip manages work for AI agents.
> - An environment plugin can own a Runner task.
> - The merged launch-preparation contract lets the execution owner
build the provider configuration.
> - Core still needs a task process owner and a setup test that uses
that configuration.
> - This PR connects the task API to the Runner process-owner contract.
> - Operators can test a plugin environment before Core sends it task
work.

## Linked Issues or Issue Description

**Subsystem affected**

Runner, plugin SDK, and agent environment tests.

**Problem or motivation**

A task-only environment cannot use the shell-based setup path. Core must
verify the Runner hello exchange and process cleanup through dedicated
task operations.

**Proposed solution**

Add a lease-bound task driver and use it for a bounded setup probe. Keep
heartbeat admission and task execution in #16978. This PR follows the
merged launch-preparation contract in #16997.

**Alternatives considered**

A provider declaration alone cannot prove that Runner and the provider
connect. A shell bridge would give the plugin an unnecessary command
interface.

## What Changed

- Pass structured Runner launch data to process owners. Support an
external connection and explicit detach.
- Add typed launch authentication checks and checkpoint operations.
Check lease, run, project, and retained-task authority.
- Connect launch preparation, PRP, termination proof, and credential
handoff to the task driver. Reject local environment overrides during
installed-account setup. Pass saved-account identity and credential home
directly from Core.
- Run a short-lived setup probe through the existing agent environment
test API. Require a verified provider hello and cleanup. Keep saved
Copilot account checks metadata-only through a dedicated task operation.
- Update the Copilot source identity because the shared transport source
changed. Keep provider behavior and the earlier identity fixture.

## Verification

- CI passes on `f987adec7`: 55 successful checks and 5 expected skips.
Standard Greptile and Apex are both 5/5 with no open findings. The
branch merges cleanly with current master.
- Repository typecheck and build pass after the rebase onto the
workspace-provider contract. Server typecheck and build also pass after
the final setup fix.
- The 110 focused lease, SDK, setup, Copilot, and route cases pass after
the rebase. All 14 setup cases pass after the final change. These
include a real local Runner with a test provider. The saved-agent
model-discovery case also passes.
- Apex found that Core's relative workspace marker failed the driver
path check, and non-Codex sessions omitted the observed model. Both
failures were reproduced and fixed. The probe leaves physical workspace
selection to plugin preparation. The transport reads each provider's
observed model and exposes it to the driver. All 14 setup cases, 6
transport peer cases, and both existing real Runner/OpenCode cases pass.
Runner build and server typecheck pass.
- The coverage audit removed two redundant cases, repeated fixture code,
and two extra real Runner launches. It kept authorization, credential
selection, cancellation, lost replies, termination proof, checkpoint
identity, and provider setup checks.
- The Copilot source-identity check passes. The added-line secret and
PII scan passes. The unmerged v52 attestation was regenerated after the
shared transport fix.
- CI on `13faeff02` caught one stale Copilot digest assertion after
attestation regeneration. The literal now matches the candidate
attestation, and all 49 installation cases pass. That CI lane otherwise
passed 1,818 cases.
- An earlier CI run hit an unchanged UI toast timing test. The separate
fix is tracked in #16952. Current CI passes that shard. CI also caught a
stale model-discovery assertion in this change; the assertion is fixed.
- The local full-suite run was stopped when master changed. The final CI
run supplies exact-head full-suite validation. No live Cloud or provider
test was run.

## Risks

- Native hello tests require a saved Core account or the installed
account. Local environment overrides are unsupported for
installed-account probes and fail before the provider runs.
- A native task provider must declare launch preparation and
authentication-check version 1. It must keep the checked configuration
fixed through submission. Core rejects providers that cannot make this
guarantee.
- A lost task reply does not prove process termination. Core retains
grants until the provider proves termination and Core saves required
state.
- This PR does not enable native heartbeat dispatch through plugin
environments. Cloud deployment and live provider validation remain
separate.

## Model Used

OpenAI Codex, GPT-6. The exact model ID and context window are not
exposed in this session. Tool use includes code editing, local tests,
and the GitHub CLI.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have 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 issue
details
- [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
- [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-20 18:13:09 -07:00
Nicky LeachandPaperclip 79b2bf78dd Create agent records when onboarding names are submitted (#17005)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Core onboarding selects an agent and connects its provider account.
> - The current flow creates the agent record after authentication.
> - Setup needs a stable agent identity as soon as the user submits its
name.
> - This PR saves a paused setup record on name submission and finishes
the hire on that same record.
> - The existing sandbox authentication and approval paths continue to
apply.

## Linked Issues or Issue Description

**Subsystem affected**

Core agent lifecycle, shared validators, and onboarding UI.

**Current behavior**

Onboarding creates the database record at the final hire step. Earlier
authentication and saved setup have no agent record.

**Proposed behavior**

Create a paused agent with a setup hold when the user submits its name.
Do this before adapter selection or authentication. Update that same
record after adapter selection. Reuse its ID on retries and saved setup.
Finish that record through the existing hire path.

**Reason and benefit**

Give setup a stable identity without coupling this refactor to computer
provisioning or a new execution backend.

**Breaking changes**

Incomplete setup now leaves an inactive agent record. Existing clients
can still create and hire agents without the new optional fields. The
sandbox authentication flow and API key support remain in place.

**Additional context**

Requested Core-only refactor. Related work: #15422 changes runner
defaults. This PR preserves those choices. No duplicate early-record
refactor was found in the issue and PR search.

## What Changed

- Save the agent when the user submits its name in both onboarding entry
points. Use a provisional adapter until the user chooses one. Reopen
name-only drafts at adapter selection.
- Add retry-safe setup creation and same-record hire completion. Keep
approval checks at final hire.
- Save and restore setup configuration in both onboarding entry points.
Show Finish setup for paused setup agents.
- Restrict setup changes to authorized board users. Block generic resume
until setup finishes.
- Add lifecycle, authorization, connection, and UI coverage. Update the
specification and feature maps.

## Verification

- Latest focused server run: 126 lifecycle and AI-connection tests
passed after the Apex fixes. An earlier broader run passed 301
lifecycle, instruction, adapter-validation, and AI-connection tests.
Earlier authentication, retry, cross-company, and direct-create
regressions also passed.
- Name-save verification: 336 tests across the wizard, naming dialog,
New agent, action-button, and wizard-step suites passed. Coverage
includes retry identity, repeated submission, closing during a save,
saved-model restoration, and a disabled process adapter.
- Shared, server, and UI TypeScript checks passed. The latest UI package
check and direct server TypeScript check passed. The server package
preparation command could not finish locally because Cargo is
unavailable; full build preparation runs in CI. Map checks, token gates,
and `git diff --check` passed; each pushed diff was scanned for
credentials and PII.
- All six onboarding browser tests passed together with installed Chrome
against a fresh throwaway instance after the Apex fixes. They include
numbered duplicate names, first-time Copilot without a connected
account, and Grok’s saved model. They verify early persistence in both
entry points, closing and reopening a name-only draft, same-record
adapter selection, sandbox sign-in, login reload, and failed-connection
gating. Provider responses are simulated; Core persistence is real.
- Regression coverage includes incomplete Copilot creation versus final
validation, Kimi settings through redacted responses, stale local
drafts, company switches during creation, saved environments, and
provider changes with personal/shared old bindings.
- Apex found five name-only setup gaps: numbered names, early Copilot
account validation, the Grok model default, same-name draft ownership,
and provisional runner restoration. The fixes preserve server names,
defer implicit account binding until hire, set Grok’s model, avoid
name-based reuse of unfinished records, and restore Auto for pending
adapter choices. UI, database, and browser regressions cover these
cases.
- Standard Greptile found a Grok provider mismatch in the new adapter
save. The save now uses ACPX with the Grok profile. Both the 129-test
dialog/setup run and a real-API browser regression passed after the fix.
The first browser attempt stopped on an ambiguous empty-roster button
selector; it now scopes the click to the toolbar.
- Moving the save point exposed a saved-model reset and timing
assumptions in the same-name and portal fixtures. The source choice now
preserves the restored model, and tests cover same-name recovery without
a second hire.
- Initial CI exposed direct-create compatibility, concurrent setup
effects, fixture assumptions, and a missing-fields assumption in the
provider-validation guard. These were fixed and verified locally. Review
findings were addressed with authorization, recovery,
credential-persistence, and restored-configuration regressions.
- The final desktop capture passed after host resource cleanup. A repeat
first failed before Core started because macOS had exhausted
shared-memory IDs. Standalone PostgreSQL initialization reproduced the
same error. Releasing only unattached control segments from this task’s
stopped test databases allowed the unchanged revision to pass. No Core
or system setting changed.
- Local database tests required port access outside the sandbox. Missing
declared development dependencies were supplied outside the branch. No
live provider sign-in was tested locally.
- [Full monorepo
CI](https://github.com/paperclipai/paperclip/actions/runs/39522434236)
is green on `82b82fec189a172a885d4dd565ae2f4a18c73efc`. Standard
Greptile scored 5/5 with zero new comments (check `118969424903`). The
subsequent Apex review also scored 5/5 with zero new comments (check
`118972866331`) on that same commit. All review threads are resolved.
- The separate Superagent Security scan returned neutral/inconclusive
because its pinned merge-base checkout failed or timed out. GitHub
returned 404 for check and suite rerun requests. This is not a
successful security scan; the CI workflow and other security checks
passed.

## Risks

- Users can leave inactive setup records behind, including after name
submission alone. These records cannot run until hire completes.
- Setup completion touches hiring and approval boundaries. Tests cover
retries, company isolation, creator permissions, and approval snapshots.
- An uncertain credential-save result retains its new secret reference
for retry. A confirmed client rejection removes only credentials staged
by that attempt.
- No schema migration or VM provisioning change is required.
Agent-computer integration is out of scope.

## Model Used

OpenAI Codex, based on GPT-6, with repository search, code editing, and
tool execution. The exact deployment ID and context window are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 18:08:57 -07:00
DottaandPaperclip d33b40a5c3 fix: recover saved work and provide reliable task Retry (#16965)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The control plane must retain work when an execution or workspace
export fails.
> - Retained-workspace holds can leave saved input waiting with no
usable Retry action.
> - Users cannot verify process ownership or repair provider
allocations.
> - This pull request gives system recovery a durable budget and gives
each deliberate Retry a durable intent.
> - Safe recovery can preserve files, settle an accepted result, or
prepare an independent workspace.
> - One task state keeps infrastructure diagnostics out of the ordinary
conversation while preserving real permission and approval gates.

## Linked Issues or Issue Description

**What happened?**

A task with a retained workspace can show recovery, failed-run and
saved-message warnings at the same time. Historical runs without native
workspace descriptors cannot use the native restore path. Old recovery
metadata can prevent a new attempt even when an independent workspace
would be safe.

**Expected behavior**

Paperclip owns bounded infrastructure retries and file preservation. A
user can request another attempt with ordinary Retry. Thinking appears
immediately. The service preserves completed effects and current user
controls. It does not claim that starting fresh recovered the old files.

**Steps to reproduce**

1. Retain a failed run and its workspace after export or process-stop
failure.
2. Save a follow-up while the recovery hold is active.
3. Open the task and try to continue without infrastructure credentials
or operator certification.

Refs #16906, #16835, #16883. This extends their recovery and receipt
contracts. Related work: #16962 and #16963.

## What Changed

- Add task-level Retry with company-scoped authorization, all-status
idempotency and durable admission before physical work. Keep exact-run
Retry compatible.
- Add typed recovery phases, finite persisted backoff, historical
adoption and durable local failure diagnostics.
- Preserve native workspaces or verified historical snapshots. Admit an
independent fresh workspace only after execution containment. Keep
old-source preservation and cleanup obligations separate.
- Carry completed publication and API receipts forward. Fence uncertain
mutation retries across replacement runs. Preserve connected-chat
identity and authorization.
- Re-enter normal dispatch for saved input. Reuse accepted results
through the existing finalizer.
- Use one task interruption projection across the thread, composer and
task list. Show optimistic Thinking, ordinary Retry and genuine user
gates.
- Add PostgreSQL, filesystem, API, browser-fixture and controlled
provider coverage. Document the behavior and update the feature/access
maps.

## Verification

- All GitHub Actions CI jobs pass on
`6d8c6d27d50586d8548b31d03b47f6d73a0ee11d`: typecheck, all
server/chat/workspace and serialized suites, Runner checks, eight
browser shards, canary and build. The required merge gate passes.
- Greptile reviewed the final commit at 5/5, with no actionable findings
or unresolved review threads. Its two earlier P1 findings are fixed.
- Full recursive typecheck and build pass locally on the final commit.
All 16 task Retry cases pass against isolated real PostgreSQL. The
unrelated-success case and both stale Retry cases fail on the previous
code and pass after the fix.
- The corrected gateway fixture passes its uncertain-mutation and
independent-read case. Four real HTTP API cases pass for definite
403/422 rejection, completed-effect reuse, and uncertain-effect fences
across deliberate and automatic retries. These focused gateway/API
checks used a temporary database lifecycle harness on an existing
healthy local PostgreSQL process. The standard repository helper is
unchanged.
- Earlier qualification covers 291 task UI cases, saved-file copyback
and ancestry, current Agent Chat ownership races, nine chat Retry API
browser cases, and six assembled browser recovery fixtures. A real
API/PostgreSQL/native-runner journey showed Thinking in 25 ms despite a
delayed response, admitted one successor in a separate workspace,
retained original files, and survived reload.
- The controlled Daytona test interrupts export, joins the controller,
restarts it in a separate process, and verifies one agent start, one
external sentinel operation, retained file contents and no premature
cleanup. It does not establish abrupt-kill or live LLM/GitHub
acceptance.
- The full local `pnpm test:run` was attempted and was not green: an
OAuth row-lock timing assertion failed, and a later suite exhausted
macOS PostgreSQL semaphores. The ten OAuth timing cases passed on rerun
against a separate database. Later embedded database initialization
failures remain recorded; the final CI matrix passes.
- Security scanning passed on production-code commit
`63953edf069b111c6becc3144dffa6deb52f68b5`. Its only successor changes
one test-fixture identity line. The final scan is neutral/inconclusive
because its pinned merge-base checkout failed or timed out. Both rerun
API requests returned 404, so no fresh successful scan is claimed.
Socket and Snyk checks pass on the final head.
- The optional Paperclip Review remains queued behind an earlier run in
workspace finalization. Its prior completed assessment was incomplete
because a comparison tool was blocked by the platform filter. It is not
counted as a completed code review. GitHub does not require this check
for merge.
- Hosted acceptance remains pending deployment. Local and CI results do
not establish recovery of a hosted task or its retained files.

## Risks

- Recovery changes span admission, physical ownership and dispatch.
Incorrect evidence could permit overlapping work. Existing physical
locks and authoritative stop requirements remain in place.
- The migration adds concurrent indexes. It requires the existing
top-level migration runner and retries incomplete index creation safely.
- A fresh attempt can complete while old-source preservation remains
unresolved. The service retains that obligation and does not report
those files as recovered.
- Unknown tool mutations remain blocked until their authoritative
receipt owner resolves them. Generic upstream tools have no universal
result-query protocol.
- Recovery and diagnostics stay inside the stack. No Cloud incident
endpoint, notification worker or new outbound reporting channel is
included.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose a more specific
model version or context-window size. The model used reasoning, shell
execution, source editing and browser tools. No model subagents were
used for this implementation.

## 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; the full
local run 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-20 19:58:53 -05:00
DottaandPaperclip 6c9b87d092 trace(server): expose repository admission waits (#17040)
## Thinking Path

> - Paperclip manages work performed by AI agents.
> - The controller prepares a task workspace before it starts a provider
turn.
> - Repository admission also runs when a checkout already exists.
> - One observed reuse took 16.877 seconds. Its child spans explained
only 3.556 seconds.
> - The missing detail covered repeated authority checks, catalog work,
and publication waits.
> - This change exposes those operations under the existing execution
attempt.
> - Operators can expand the slow phase before choosing a performance
fix.

## Linked Issues or Issue Description

Refs #16963, #16330, and #16515. The provider-routing work in #17019 has
a different scope.

**What existing behavior does this improve?**

Repository-admission traces for new and reused checkouts.

**Subsystem affected**

server/ orchestration and operator-configured OpenTelemetry tracing.

**Current behavior**

The admission span can contain a long interval without child spans.
Existing project checks, HTTP requests, and checkout lookup do not
explain current-task checks, database awaits, credential refresh, or
publication locks.

**Proposed behavior**

Expose nested spans for current binding and task access, individual
identity reads, catalog construction, credentials, grant transactions,
filesystem validation, Git inspection, and directory-lock acquisition,
work, and release.

**Reason and benefit**

The trace can distinguish repeated checks, remote calls, database
awaits, and directory contention. A database-await span includes driver,
network, pool, and server time. It is not isolated SQL execution time.

**Breaking changes**

None. No API, schema, permission, retry, lock, or repository behavior
changes.

## What Changed

- Add fixed admission phases beneath the existing execution attempt.
Keep the existing project, checkout, and HTTP detail.
- Trace current-task authorization stages only under workspace access.
Unrelated decisions cannot consume that detail budget before admission.
- Trace GitHub catalog reads, credentials, provider metadata, grant row
locking and writes, transaction settlement, and webhook work.
- Separate directory-lock acquisition, the protected operation, and
release without changing the adapter lock contract.
- Document the hierarchy and timing limits. Keep endpoint gating, span
caps, and hashed run correlation. Add no span attributes or exception
text.

## Verification

- Nine new tests passed with real PostgreSQL, real Git, and SDK-exported
spans. They cover directory contention, grant-row blocking, all three
binding checks, reuse without cloning, dirty files, private-task denial,
receipt repair, conflict retry, endpoint-off behavior, and parent IDs.
- Twenty earlier unrelated authorization decisions do not exhaust the
admission detail budget.
- Existing authorization and trust suites: 105 tests passed. Existing
timing/context suites: 26 tests passed. Existing repository-access
tests: 6 tests passed.
- `pnpm -r typecheck` and `pnpm build` passed on commit
`5a986d8c86644dfb7ee39b3b832e2d7c86532598`.
- `pnpm test:run` could not complete locally. The temporary
five-connection cluster returned `sorry, too many clients already` in
chat fixtures, and the run was interrupted. It is not a pass. The
complete standard CI workflow passed on the same commit, including all
12 server shards and all three chat shards.
- Final current-head checks: 54 success, two neutral, two skipped, zero
pending or failing. The [CI
aggregate](https://github.com/paperclipai/paperclip/actions/runs/39522187940/job/118971261973)
passed.
[Greptile](https://github.com/paperclipai/paperclip/pull/17040#issuecomment-6305066520)
and [Paperclip
Review](https://github.com/paperclipai/paperclip/pull/17040#issuecomment-6305017182)
both assessed this exact commit at 5/5 with no actionable findings or
unresolved threads.
- `node scripts/check-module-boundaries.mjs` and `git diff --check`
passed.
- This macOS host exhausted its SysV semaphore quota. Database tests
used a temporary command-scoped initdb preload with five connections,
fewer workers, and a larger lock table. No repository test
infrastructure or shared host settings changed. Initial skipped tests,
focused-fixture failures, and clock-order assertion failures were
corrected and rerun; they are not counted as passes. The complete local
run remained connection-limited and was interrupted.
- Local SDK export proves parentage and privacy. Hosted Honeycomb
ingestion remains unverified until deployment. No deployment occurred.

## Risks

Span recording requires an operator-configured OTLP endpoint. Each fixed
detail name remains capped at 16 occurrences per attempt. Later
operations still execute under their enclosing phase. Timing wrappers
preserve the existing operations and their errors. No migration is
required. The change does not itself reduce admission latency.

## Model Used

OpenAI Codex, based on GPT-6, with tool use, code execution, and
delegated agents. The exact hosted 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-20 19:50:51 -05:00
Nicky LeachandPaperclip 8b4ab65b1c Add plugin-owned project storage and task workspaces (#17001)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tasks can use isolated repository workspaces.
> - Core currently prepares those repositories on its own filesystem.
> - A storage provider may only expose repositories inside remote agent
computers.
> - Project storage and task workspace preparation must have one
provider owner.
> - This pull request adds that contract and keeps execution as a
separate plugin interface.
> - Core keeps authorization, durable task bindings, and lifecycle
fences.

## Linked Issues or Issue Description

**Subsystem affected**

Plugin SDK, project workspace policy, heartbeat preparation, execution
leases, and workspace lifecycle.

**Problem or motivation**

Core cannot prepare a task workspace when its repository storage is
unavailable on the Core host. An execution lease must not be required
just to prepare persistent storage.

**Proposed solution**

Let one plugin provide project resource lifecycle and workspace prepare,
inspect, restore, and remove behavior. Core reserves a task workspace
before it calls the plugin. The plugin returns an opaque durable
reference. The matching execution plugin receives that reference on its
task RPC.

**Alternatives considered**

Preparing repositories on Core would require a provider mount on Core.
Preparing them only during task launch would tie persistent workspace
lifecycle to execution leases and agent availability.

**Roadmap alignment**

This extends the remote provider model in ROADMAP.md. Related execution
work is in #16978. This PR does not replace that task bridge. Native
execution of managed storage requires the bridge; this change fails
closed when it is absent.

## What Changed

- Add one storage provider declaration with supported modes/strategies,
a capability, a validated RPC contract, and a test harness.
- Persist provider ownership, repository revision, and
execution-workspace identity before external effects. Reconcile retries
with a stable operation ID.
- Prepare provider storage before environment acquisition. Keep Core
filesystem preparation out of this path.
- Pin the durable reference to the matching execution plugin and
validate the lease binding before task dispatch.
- Route inspection, reopen, and removal through the existing lifecycle
process. Keep local data when remote recovery is uncertain.
- Keep the application database pool free during lifecycle locks.
Preserve pending workspace selections, validate source edits before
retirement, and retry unfinished closed storage cleanup.
- Protect provider metadata and live repository sources from caller
edits. Storage edits retire only closed records with confirmed removal;
retired records cannot reopen.

## Verification

- Current head `8214b3ca5`: all 25 provider lifecycle tests pass with
`maxConnections=1`. They cover preparation, inspection, reopening,
removal, a paused provider with responsive ordinary SQL and a competing
source edit, pending selection preservation, rejected source edits,
cleanup retry scheduling, and providers that cache operation results,
and committed cleanup notifications for storage intent and recovered
state.
- Final frozen-tree lifecycle run on `8214b3ca5`: all 318 tests passed
in 10 files, covering workspace services, reopen, compaction, task
binding, project sources, heartbeat preparation, display caching, and
source locks.
- Direct server `tsc --noEmit` passes. The SDK build and all 128 SDK
tests passed during initial verification; later SDK changes are
documentation only.
- Full CI on the previous head `ec5c7209a` passed all 55 applicable
checks; 2 conditional checks skipped. Standard Greptile reviewed current
head `342e6d9c3` at 5/5 with no unresolved threads. All 55 applicable CI
checks passed on `342e6d9c3`; 2 conditional checks skipped. The Slack
browser and CLI startup jobs passed on their single unchanged-head
rerun. Its Apex review returned 4/5 with one pending-restoration issue.
Commit `1b58943b1` reconciles that durable intent before cleanup,
advances the generation without reopening the Core row, and blocks
direct removal or retirement while intent remains unresolved. Standard
Greptile reviewed `1b58943b1` at 5/5 with no new findings. All 54
applicable CI checks passed on `1b58943b1`; 3 conditional checks
skipped. The chat job passed on its single unchanged-head rerun. Apex
then returned 4/5 for a missing cleanup wake after recovery. Commit
`8214b3ca5` atomically registers cleanup intent before storage intent
and recovery-result writes. Its provider test observes real committed
notification hints and the visible advanced generation. Standard
Greptile reviewed `8214b3ca5` at 5/5 with no new findings. All 55
applicable current-head CI checks passed on the first run; 2 conditional
checks skipped. Final Apex verification completed at 5/5 on this exact
head: 38 files reviewed, no new comments, and no unresolved threads. The
PR is ready for review and mergeable.
- The first Apex review found five issues after a standard 5/5:
application-pool starvation, stale pending selections, retirement during
rejected source edits, lost cleanup retries, and reused inspection
identities. Commits `6d72e7fd4` and `342e6d9c3` fix each with regression
coverage. Archive lock waits use dedicated connections, and source edits
fail promptly if the lifecycle is busy. Retirement compares normalized
values. The normalized-source regression initially failed with the
raw-value comparison; after moving the check after normalization, a
clean provider-suite rerun passed all 24 tests at that stage. Those
threads are resolved; the earlier Apex 0/5 is not a passing acceptance
result.
- Earlier local integration attempts could not bind localhost inside the
sandbox. The same suites passed with permission to start local
PostgreSQL.
- The earlier broad local `pnpm test:run` overlapped edits and reported
stale-revision and checkout-path/Git-fixture failures. It was not a
final-tree result. Full CI subsequently passed; the original local
failure remains part of verification history.
- Local repository-wide typecheck/build cannot complete because `cargo`
is unavailable. Direct server TypeScript checks and affected tests pass;
full Rust and build validation comes from CI.
- An earlier browser run on `ff918c5a8` failed in the unchanged
case-filter journey: expected “Done,” received “All statuses,” with an
announcement handler recorded during the assertion. The cause is not
confirmed. [The failed
job](https://github.com/paperclipai/paperclip/actions/runs/39500611857/job/118896954508)
remains verification history. The unchanged shard passed in the next
full CI run on `ec5c7209a`; no UI or fixture change was made.
- Current-head browser shard 2 failed waiting five seconds for the
mocked Slack setup Success heading. This PR changes neither that UI nor
its fixture. [The failed
job](https://github.com/paperclipai/paperclip/actions/runs/39506070513/job/118916021232)
remains verification evidence. The cause is not confirmed; the single
unchanged-shard rerun passed; no UI or fixture change was made, and the
original cause remains unconfirmed.
- The workspace test shard passed its 3,978 general tests, then its CLI
company-import/export fixture timed out after 30 seconds waiting for
startup health before creating any company or workspace. [The failed
job](https://github.com/paperclipai/paperclip/actions/runs/39506070513/job/118916021855)
remains verification history. The child reached external-PostgreSQL
startup without exiting or reporting an exception. Its cause is not
confirmed; the single unchanged-job rerun passed, including the CLI
fixture. No startup or fixture change was made, and the original cause
remains unconfirmed.
- The new cached-removal regression initially failed because its fake
worker advertised availability for unrelated fixture plugins, so another
workspace changed its fake checkout state. Worker availability now
matches the fixture plugin; the complete 25-test provider suite passes.
- On `1b58943b1`, the chat shard timed out polling for one conversation
after an authorized GitHub description edit. [The failed
job](https://github.com/paperclipai/paperclip/actions/runs/39510521657/job/118930193418)
remains evidence. The exact case passes locally against PostgreSQL (1
passed, 1,380 unrelated cases skipped), and this PR changes neither that
test nor its handler. The original cause is unconfirmed; the single
unchanged-job CI rerun passed without a code or fixture change. The
original cause remains unconfirmed.
- The diff was checked for credentials, private references, and
generated artifacts.

## Risks

This is an additive provider contract with no database migration.
Existing projects keep their local behavior unless their policy selects
a storage plugin. A selected provider must be ready and enabled. Unknown
or unsafe cleanup fails closed.

Managed native execution depends on #16978. Core refuses a host Runner
fallback. Providers must fence lifecycle generations, preserve ambiguous
retries, and report remote recovery honestly. Provider-specific live
storage and guest mount qualification remain separate from these Core
contract tests.

## Model Used

OpenAI Codex (GPT-6), with repository inspection, code execution, and
tests. The exact model variant was not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either 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 (affected suites; broad-run
limits 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-20 16:35:33 -07:00
Devin FoleyandPaperclip 572bef4ba7 fix: omit re-downloadable Codex remote plugins from failover backups (#17026)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native Codex sessions in remote sandboxes copy the sandbox's Codex
home into a host-side failover backup after every turn
> - Ephemeral sandboxes restore that backup at the start of every turn,
so its size affects both disk use and turn latency
> - Most of each backup is remote plugin data that Codex itself treats
as a cache and re-downloads on startup
> - This pull request leaves that data out of Codex checkpoints, keeping
everything a resumed session needs
> - The benefit is backups roughly 80–90% smaller, less data moved per
turn, and much slower disk growth

## Linked Issues or Issue Description

Bug report described in-PR (bug report template). Related: #16866
(expires failover backups after their issues close).

**What happened?**
Failover backups grow quickly because each Codex checkpoint includes
`$CODEX_HOME` remote plugin data. On one instance, 204 backups held 22.1
GB:
- `codex-home/plugins/cache/openai-curated-remote`: 8.3 GB (about 29 MB
per backup);
- `codex-home/cache/remote_plugin_catalog`: 6.1 GB (one 38 MB catalog
file per backup);
- `codex-home/sessions` (the conversation history): 0.31 GB.

About 80 new backups (9.8 GB) were written per day. Ephemeral sandboxes
also copy all of this into a fresh sandbox before each turn.

**Expected behavior**
Checkpoints keep what a resumed session needs and omit data that Codex
re-downloads itself.

**Steps to reproduce**
1. Run a Codex agent with ChatGPT auth in a remote sandbox environment.
2. Inspect
`<instance>/runtime/paperclip-runner/durable-sessions/*/failover-backups/current/codex-home`.
3. Most bytes are under `plugins/cache/openai-curated-remote` and
`cache/remote_plugin_catalog`.

**Paperclip version or commit:** `master` at f89c37791c.
**Deployment mode:** server with remote sandbox environments.
**Agent adapter(s) involved:** Codex (native app-server and ACPX).

## What Changed

- **`server/src/services/native-runtime/native-session-executor.ts`:**
Codex checkpoints (direct and under ACPX) now also exclude:
- `plugins/cache/<marketplace>` for Codex's six remote marketplaces
(`openai-curated-remote`, `created-by-me-remote`, `workspace-directory`,
`workspace-shared-with-me`, `workspace-shared-with-me-private`,
`workspace-shared-with-me-unlisted`);
  - `cache/remote_plugin_catalog`;
- `plugins/.remote-plugin-install-staging`, and
`.remote-plugin-install-staging` (the location older Codex versions
use).
- **Still kept:** local and bundled plugin caches, `plugins/data`, the
Apps tool cache (`cache/codex_apps_tools`, which avoids waiting up to 30
s for the Apps MCP server), session rollouts, and the state databases.
- **Tests:** a real-tar checkpoint test covers kept and omitted entries;
the profile expectations are updated.
- **`doc/recoverable-disk-cleanup.md`:** describes what Codex failover
copies omit and the first-turn effect.
- No code comments were added.

**Why the omitted data is safe to drop** (Codex source at commit
d4e03acb):
- **Server-side source of truth:** the installed remote plugin list
comes from the server (`/backend-api/ps/plugins/installed`) and is held
in memory; these directories are not the source of truth.
- **Self-healing startup:** at `app-server` startup, a background task
reconciles missing bundles and force-refreshes the catalog
(`core-plugins/src/manager.rs`, `remote_installed_plugin_sync.rs`).
- **No path dependencies:** rollouts and state store plugin ids, not
paths into these directories.

## Verification

- `pnpm exec vitest run
src/services/native-runtime/native-session-executor.test.ts` (in
`server/`): 766 passed.
- **Mutation check:** dropping one remote marketplace from the exclusion
list fails both the new checkpoint test and the profile test.
- `pnpm run typecheck` (in `server/`): pass.
- **Manual resume with Codex CLI 0.162.1 and ChatGPT auth:**
1. Started a session in a fresh `CODEX_HOME`. This downloaded 28 MB of
remote plugins.
  2. Copied the home without the excluded entries: 34 MB became 4.9 MB.
3. Ran `codex exec resume --last`. It recalled the conversation in 3 s,
and the remote plugins were re-downloaded in the background without
errors.
- **Compatibility:** restore compares only top-level directory names
(`compatibleNativeHarnessBackupManifests`), so existing backups that
still contain the plugins restore unchanged.

## Risks

- **First turn after a restore:** remote plugin skills and tools can be
missing until the background download finishes, typically seconds. Codex
leaves an unavailable remote plugin out of a turn; it does not fail the
turn. Later turns include it.
- **Network and auth:** re-downloading requires ChatGPT auth and network
access from the sandbox, which remote plugins require anyway, since
Codex fetches the installed list from the server on every start.
- **Per-turn download:** ephemeral sandboxes download the remote plugin
bundles each turn, about 28 MB in the observed case, in the background.
In exchange, about 90 MB less is copied from the host before each turn.
- **Rollback:** revert.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), 1M context, through Claude Code
with tool use (shell, file edits, tests, Codex source reading, a local
Codex resume test, read-only measurements on a live instance).

## 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-20 16:01:48 -07:00
DottaandPaperclip 15176963b1 fix: stop idle skill-source polling (#17008)
## Thinking Path

> - Paperclip manages agent work and the skills that agents use.
> - Project repositories create durable import jobs, and installed
sources can refresh automatically.
> - The server queried these records every five seconds, even when no
work existed.
> - Idle tenant databases need to stop receiving those discovery
queries.
> - This change uses the existing transaction notifications and delivery
coordinator.
> - Saved refresh, retry, and lease deadlines determine when the worker
runs next.
> - Cloud does not yet wake these deadlines, so outstanding skill work
retains the instance.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Skill-source background synchronization. This continues the idle-work
migrations in #15625 and #17000. A search found no overlapping open
polling-removal PR.

**Current behavior**
On master `b11010b0d4`, startup installs a five-second skill-source
interval and also calls it from the external-object scheduler. Each
sweep queries active companies, import capacity, pending imports, and
automatic refreshes.

**Proposed behavior**
Run at startup, after a relevant transaction settles, or at a saved
deadline. Stay SQL-quiet when no eligible work remains. Preserve import
admission, authorization, atomic claims, retry backoff, and the existing
five-minute upstream check.

**Reason and benefit**
Remove recurring database activity from inactive tenant instances
without requiring new tables or a new scheduler.

## What Changed

- Replace both recurring skill-sync calls with one delivery-coordinator
registration.
- Notify from attachment/detachment, source creation/settings/manual
refresh/disconnection, project/company deletion, and company status
changes, including budget resume.
- Restore the earliest eligible `nextSyncAt` or lease-expiry deadline.
Due backlogs and conflicts retry after five seconds; no idle recovery
cadence remains.
- Admit deferred imports again after a batch frees capacity. Preserve
requests through drain, standby, restart, and commits during a sweep.
- Add sleep-safety predicates for imports and eligible automatic sources
until Cloud supports these deadlines.
- Document the lifecycle and process-local writer contract. No schema or
API changes.
- Guard external test database URLs before migrations or cleanup:
require a `_test` database name and reject database/options overrides.

## Verification

- 147 targeted tests pass: 39 server-startup tests, 14 new
real-PostgreSQL lifecycle tests, 20 shared coordinator/scheduler tests,
63 existing import/refresh/retry regression tests, and 11 test-database
guard cases.
- CI exposed a stale startup mock without the new `start` method. The
fixture is updated and all 39 startup tests pass locally.
- Tests exercise real enqueue/settings/company-reactivation producers,
nested commit, rollback, saved retry/lease restart, manual refresh
failure, capacity admission, concurrent commit, shutdown cancellation,
and SQL quiet after startup or pause.
- Sleep-safety tests reject sleep for future imports and automatic
refreshes, and accept inactive retained state.
- `pnpm -r typecheck` and `pnpm build` pass.
- `pnpm test:run` was attempted and stopped after repeated
embedded-PostgreSQL startup failures in unrelated suites. The two
existing import/refresh suites initially skipped for the same host
limitation; after adding explicit disposable-database options, all 63
regression tests passed against PostgreSQL 17. Full CI passed on
`ddb3ee51369baa8c7153bae9fd88efb8b903f2bc`: 55 successful checks, one
neutral review check, and two intentional skips.

## Risks

- Notifications are process-local. Independent SQL writers and separate
live replicas do not wake this worker; startup reconstructs persisted
work.
- Enabled automatic sources still contact GitHub every five minutes.
Their upstream changes have no event ingress here.
- Cloud scheduled wakes currently cover routines and issue monitors, not
skill sync. This change retains instances with outstanding skill
obligations. It does not claim measured host/database suspension or
fleet savings.
- No change to source authorization, installed content on failure, or
existing claim semantics.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, and code
execution. The host does not expose an exact model revision or
context-window size 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-20 16:21:42 -05:00
DottaandPaperclip cb2d6e80d3 perf: stop polling idle Muse maintenance (#17000)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Muse connects an external worker to a Paperclip agent.
> - Its maintenance loop scans the database every five seconds, even
without bindings.
> - These empty scans prevent an otherwise idle database from sleeping.
> - The shared delivery coordinator can react to committed writes and
saved deadlines.
> - This change uses that coordinator and retains recovery for
unfinished assignments.
> - Idle Muse maintenance can now stop querying the database.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Muse qualification, OAuth authority, and terminal assignment
maintenance.

**Current behavior**

A claimed instance runs two empty scans every five seconds even when
Muse has no bindings. This produces about 34,560 unnecessary queries per
day. Warm standby suppression from #16974 does not cover claimed
instances.

**Proposed behavior**

Recover once at startup. Wake after relevant transactions settle.
Schedule qualification expiry at its saved deadline. Retain five-second
recovery only for failures and unfinished assignments.

**Reason and benefit**

Remove recurring database traffic from idle Muse maintenance while
preserving authority checks and recovery. Reuse the database work signal
foundation from #15625 without adding tables.

## What Changed

- Register Muse maintenance with the shared delivery coordinator and its
idle admission rules.
- Signal pairing, OAuth attachment and revocation, qualification
changes, and new assignments before transaction writes. The existing
transaction layer waits for outer commit.
- Restore qualification deadlines from persisted bindings. Retry failed
sweeps and unfinished assignments.
- Add PostgreSQL tests for idle quiet, nested commit, rollback,
deadlines, standby, drain, and failure recovery. Verify signals from
actual Muse producers. Preserve startup, newly committed work, and
failed sweep retries across idle drain without SQL polling.
- Document the remaining recovery cadence and sleep limitations.

## Verification

- `pnpm -r typecheck`: passed before rebase. Server typechecking also
passed after rebase and the drain fix.
- `pnpm build`: passed before rebase.
- Final change: 33 maintenance, delivery coordinator, and scheduler
tests passed. Maintenance used a fresh disposable PostgreSQL 17
database.
- Muse control-plane tests: 254 passed against the same disposable
database.
- `pnpm test:run`: attempted, then stopped after repeated embedded
PostgreSQL startup failures from this host's semaphore limit.
Native-session, Muse, and AI-connection suites could not create local
clusters. The complete suite runs in CI.
- `git diff --check`: passed.
- Final commit `e106cbf20d`: all CI gates passed, including complete
test suites, E2E, build, production bundle boot, public-install smoke
test, and canary dry run. Greptile and Paperclip source reviews both
rated 5/5, with no unresolved findings.

The focused suites accept `PAPERCLIP_MUSE_MAINTENANCE_TEST_DATABASE_URL`
and `PAPERCLIP_MUSE_CONTROL_TEST_DATABASE_URL`. Use a disposable test
database; fixtures remove test data.

## Risks

- Unfinished assignments retain five-second recovery. This change
removes idle polling, not all Muse polling.
- Signals are process-local. Independent database writers need explicit
integration. Startup recovers persisted state.
- Qualification deadlines depend on the running process. Existing
durable Muse sleep blockers remain unchanged.
- The receiver keeps its batching timer. An empty buffer already makes
no database calls.
- No schema migration or API change.

## Model Used

OpenAI Codex, GPT-6 family, with code execution and repository tools.
The exact model version 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 suites; full local
run has the environment limitation 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-20 14:20:59 -05:00
Devin FoleyandPaperclip a2d26a83fe fix(inbox): keep automatic work out of Mine by default
Keep channel and routine attribution out of Mine unless the person participates directly, is assigned the task, or receives a current addressed request. Apply the same source rules to unread state, archives, and task notifications. Preserve direct comments and current human action requests.

Restore the two expressions damaged by redaction during the earlier master merge.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 13:46:10 -05:00
Nicky LeachandPaperclip dc6dd23ea4 Add plugin Runner preparation task contract (#16993)
## Thinking Path

> - Paperclip manages work for AI agents.
> - Environment plugins can own Runner tasks.
> - Core selects provider policy and runtime assignments.
> - The execution environment must resolve its own paths and
configuration.
> - The task API needs a preparation exchange before execution.
> - This PR adds that exchange under the existing lease authority.

## Linked Issues or Issue Description

**Problem or motivation**
The environment task API can start a Runner. It cannot return a prepared
provider configuration from Core requirements.

**Proposed solution**
Add a versioned `prepare` request and `prepared` result. Keep the
provider configuration bound to its task and requirements. Check the
same company, run, project, and retained-session authority as
submission.

**Alternatives considered**
A shell preparation command would expose execution details in the API.
Provider-specific ownership flags would spread this contract across
backends.

**Roadmap alignment**
This extends the existing plugin and remote execution APIs. It does not
add a separate execution system.

Refs #16977, #15406. The prerequisite #16977 is merged. This PR now
targets master. Runner transport and provider implementations follow
separately.

## What Changed

- Add strict launch requirements and prepared result schemas.
- Add the preparation capability version and saved configuration ID.
- Apply existing lease and resource checks to preparation.
- Document idempotency, cancellation, recovery, and cleanup
requirements.

## Verification

- `pnpm -r typecheck` passed.
- Plugin SDK build passed.
- All 55 Dot Runner and native Codex server integration tests passed
with Cargo available on PATH.
- All 18 environment task runtime tests passed. These include
preparation dispatch, inactive leases, wrong run identity, unauthorized
projects, result identity, and unknown command rejection.
- The broader root suite on the parent refactor finished with 22,420
passing tests, seven failed tests in unchanged Git and diagnostic code,
and two suite setup errors because Cargo was absent from its PATH. This
PR does not claim a passing full root suite.
- No live provider calls or deployment were run. 
- Standard Greptile and Apex each scored commit
`d3ac15906240b7066f5ff505ed2ffd9ef5dd43c1` 5/5. There are no unresolved
review threads.
- All 55 CI checks passed. Two optional checks were skipped. The branch
is ready and mergeable against master.
- A fresh master fetch and merge-base check passed immediately before
the Apex request.

## Risks

- This defines a new optional worker operation. Existing providers keep
their current operations.
- A provider must validate policy and resource bindings. Schema
validation alone does not validate a concrete provider descriptor.
- This PR defines the exchange. It does not connect native execution to
a preparation provider.

## Model Used

- OpenAI Codex, GPT-6. Reasoning and repository tools. The exact serving
model identifier and context 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-20 11:41:49 -07:00
DottaandPaperclip 505e1a5582 feat(cases): add persistent workflows with same-task agent handoffs (#16959)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - An agent workflow needs persistent facts and a safe way to transfer
work.
> - Creating a task for each phase splits the objective, discussion,
workspace, and review policy.
> - A case can retain the facts while one primary task moves between
agents.
> - Transfers must survive process failure and preserve private access,
budgets, and completion gates.
> - This pull request adds durable case handoffs, native case tools, and
read-only case pages.
> - Prompts describe the workflow. Existing task controls decide when
work can run and finish.

## Linked Issues or Issue Description

**Problem or motivation**

Prompt-driven agent teams need a persistent record that can move through
triage, implementation, verification, and correction. Ordinary
reassignment does not provide a durable instruction, safe release
barrier, or recoverable delivery receipt for an agent handing off its
own running task.

**Proposed solution**

Extend standalone cases with one primary task, a descriptive phase,
retained access sources, and a handoff ledger. Apply assignments after
source execution and workspace settlement. Deliver each transfer through
the existing durable wake queue. Provide `create_case`, `read_case`,
`update_case`, and `handoff_case` in the native runner. Creation
requires kickoff and explicit workflow text. An explicit handoff to
`done` closes the case when normal task completion is accepted.

**Alternatives considered**

Do not add a workflow engine, filesystem queue, configured state graph,
or one task per phase. The workflow document combines transition prose
with an optional Mermaid `stateDiagram-v2` map. The server does not
execute the diagram. The Pipelines experiment removed on master stays
removed.

**Roadmap alignment**

This extends Agent Reviews and Approvals, Enforced Outcomes, Bounded Run
Recovery, and Activity Log attribution. Existing approval, review,
budget, privacy, workspace, and responsible-user rules remain
authoritative.

Related work: [ordinary handoff wake
recovery](https://github.com/paperclipai/paperclip/pull/15019). This
feature adds a separate persisted case-handoff receipt and release
barrier.

## What Changed

- Add case routing fields, retained access sources, durable handoff
history, delivery leases, and replay-safe migrations.
- Keep the same primary task across agent phases. Preserve each
returning agent's own session and the task's workspace.
- Fence outgoing mutations, wait for provider and workspace release, and
recover delivery without duplicate task comments or runs. Recheck
current assignment permissions as the original caller before applying a
delayed transfer. Scope a run Stop to that run’s own handoff intents, so
repeated old Stop requests preserve newer work. Cancelling terminal
intent without a source run also requires fenced current task ownership,
including native retries and preparation with an old checkout. For Cloud
callers, revalidate current stack membership with an uncached Cloud RPC
and derive owner elevation from the current managed setting.
- Keep case reads, documents, assets, Audit, and live events inside
retained task/project permissions.
- Add native case creation/read/update/handoff tools. Store required
workflow text and initial documents on the first task. Page oversized
case facts and referenced document bodies through the dedicated tool
with bounded UTF-8 JSON, current routing versions, snapshot conflicts,
and current source authorization on every page.
- Add read-only case lists and detail pages, task-style list controls,
compact dotted field tables, linked handoff tasks, and case filters in
Audit.
- Add native/legacy integration tests, migration/restart tests, browser
coverage, and bounded live receipt fixtures. Extend the trusted sandbox
condition to cover the new subscription fixture profile.
- Hide obsolete paused-agent warnings on completed or cancelled task
threads.
- Synchronize the company-switch settings test with React effects after
a CI failure. Preserve its security assertions and production remount
behavior.

## Verification

The branch directly includes master `9ef434fe79`. The required `ci /
verify` and `ci / e2e` gates pass on head `765fccd67c`. [Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/39464348614)
passes typecheck, build, tests, and all eight browser shards. Security
checks pass. [Greptile gives this exact head
5/5](https://github.com/paperclipai/paperclip/pull/16959#issuecomment-6291156549),
with no unresolved review threads. The optional Paperclip Review check
remains queued because its assigned agent is paused. It is not a
required branch check. No check result was overridden.

Local workspace typecheck and build pass after the master merge, along
with database migration checks, token gates, map checks, Storybook
catalog checks, and the Copilot profile identity check. Standard builds
refresh Runner vendor output. Focused checks pass 2,008
API/paging/context tests and 7 strict case protocol tests. The final
commit changes one test fixture only; its ten tests, UI typecheck, and
token gates pass. No production source changed in that commit.

On current head `765fccd67c`, all **194 critical workflow tests**
executed and passed with no skipped tests in those files:

- 38 Stop/ownership tests, including board completion intent, native
retries, stale Stop, and preparation with an old checkout.
- 2 actual legacy process/HTTP handoff tests, including scratch failure,
a closed-stdio child that continues writing, and recovery through a
fresh worker after the process group stops.
- 5 migration tests, including SQL column metadata, preserved null
authority context, and all six prior-numbering receipts.
- 3 process-settlement and 5 scratch tests.
- 88 handoff-service, 18 heartbeat handoff, and 21 native case-tool
integration tests.
- 7 bounded case/document-read projection tests and 7 strict
protocol-contract tests.

The current CI checkout was `fed65d49`, merging `765fccd67c` into master
`9ef434fe79`. Its new document regressions reconstruct exact
Unicode/escaped bodies and revisions through real native authority and
authenticated HTTP with generic API tools disabled. They cover
case-owned, primary-task, and linked-task documents; routing on every
page; stale document snapshots; access loss and unlinking;
unrelated/foreign/private sources; system documents; and quarantined
content. Active-task document tools retain their existing behavior.
These are current-head test results from the first CI attempt; the
browser-only retry did not rerun these suites.

The full `64fdd3403f` CI failed one separate settings test: after a
company switch, it observed an unsettled API-key draft. The production
component and test were unchanged from prior green source. Production
switches remount both keyed settings layers; the test directly reused an
unkeyed view and used a timer tick instead of waiting for React effects.
The final commit replaces that fixture synchronization with React `act`.
The exact secret-clearing assertions and all timeouts remain unchanged.
The original assertion failure remains recorded; no unchanged retry was
used. The narrow unchanged baseline and fixed fixture each pass 10
tests.

The upstream result-paging merge preserves case capture namespaces and
current asset privacy. Its API integration suite executed 39 of 41 tests
successfully, with two skipped; the optional assigned-result PRP
integration test was skipped. Neither skipped suite is counted in the
194 critical tests or as live provider proof.

All 361 upstream migration entries and SQL bodies remain unchanged. Six
case migrations follow master as 0363–0368 with identical SQL hashes.
Official Drizzle generators produced the combined metadata and five
retained snapshots. Generation reports no schema changes, and the
snapshot drift test passes. The earlier `ce361ae5d0` CI passed on
attempt 1, including its then-current 179 critical tests. Fresh review
later identified unusable document references with generic API tools
disabled; the bounded document reads and ten additional authenticated
HTTP tests address that finding.

The full local `pnpm test:run` attempt was cancelled after this Mac
exhausted PostgreSQL semaphore capacity; it is **not** counted as a
pass. Later database attempts also stopped before assertions or skipped,
including one sandbox socket denial. Two original stale-Stop regressions
did reproduce the bug against the old source. A REST serialization
assertion passed after two preserved database-startup failures. No test
timeout was increased. All 194 assertions listed above executed and
passed in current-head CI. The complete 385-file, 3,963-test UI shard
also passed after the fixture repair.

A configured-provider receipt workflow passed 13 backend checks across
triage → implementation → verification → correction → done, using one
task and four work runs. The saved receipt is revision 2 with total 6
USD; case and task both closed. The original canonical attempt remains
failed because its browser assertion confused the terminal destination
with completed-task tooltips. The corrected full browser verifier passed
on the same retained database and original runs, with no additional
provider calls. The last clean-build browser readback is on
`6a86c54a53`; later changes affect recovery, authorization, bounded
reads, and settlement. Accounted work cost is a $1.010574 rate-card
estimate; provider billing and setup-probe usage are unavailable.

Copilot profile 49 passed the unchanged seven-fixture private protocol
pack (46/46 checks, no retries) and the product file-edit canary after
master's completion-replay change. All 60 bound implementation hashes
remain unchanged on the current source. Historical profile-47/48
identities and results remain intact. See the [profile-49 compatibility
record](https://github.com/paperclipai/paperclip/blob/codex/persistent-case-handoffs/doc/plans/2026-10-20-copilot-completion-recovery-compatibility-v49.json).
This is bounded compatibility evidence, not a fresh full matrix,
installed-package product test, or Daytona rollout.

Preserved CI failures and retries:

- On `20662930ac`, Slack managed setup failed a five-second success
assertion after reload. Its test/application path was unchanged from a
prior green head. One unchanged-source retry passed all 25 tests in that
shard; no source or timeout changed.
- On `9402b4f17a`, two CI workers received shutdown signals at 15:24:19
UTC. Neither log had an assertion failure before interruption. One
unchanged-source retry of each passed all Runner static checks and all
32 tests in browser shard 6; both aggregates passed. The next head,
`7b4374edaf`, passed all CI without retries.
- On `295f289b5a`, serialized shard 9 timed out during its first
device-login test, then the next test found an active login lease.
Direct login/test paths were unchanged from a prior green head. Cold
import plus a timed-out async body using the next test's mutable
actor/store is the supported fixture-race explanation; no request trace
proves that sequence. The original failure remains recorded. One
unchanged-source retry passed all 294 tests in 19 files, including all
41 device-login tests. No login source or timeout changed. The
subsequent `ce361ae5d0` CI passed without retries.
- On `64fdd3403f`, one company-switch settings assertion observed an
unsettled draft. The final test-only commit uses React `act` without
changing assertions, timeouts, or production code. On `765fccd67c`, all
ten settings tests and the complete 385-file, 3,963-test UI shard
passed.
- On `765fccd67c`, browser shard 3 completed the split-handoff
assertions, then cleanup received HTTP 500 from run cancellation after a
one-second PostgreSQL row-lock timeout. The extra chat run was reporting
completed work while teardown began. Cleanup stopped before restoring a
global experiment flag, causing a later assertion to fail. Relevant
production and test paths are unchanged from an earlier green commit.
Stop's lock order is consistent, and no nested self-lock was found; the
exact PostgreSQL blocker was not recorded. One unchanged-shard retry
passed. The original failure, trace, and downstream flag failure remain
recorded. No Stop implementation, cleanup assertion, or timeout changed.
The retry supports intermittent cleanup contention; it does not identify
the original blocking transaction.


## Risks

- Local process transfers require host-owned PID/group absence. Missing
or uncertain termination evidence keeps delivery pending, independently
of scratch setup.
- Handoff admission and task cancellation share execution ownership. New
regression tests cover temporary holds, late source writes, and
uncertain provider termination.
- Retained private sources use an intersection of existing permissions.
This intentionally fails closed when a source is missing or an existing
task cannot preserve that boundary.
- Migrations add tables and indexes. They preserve master history and
can replay over prior feature installs. Migration 0368 adds nullable
internal authorization provenance with no default or authority backfill.
Historical transfers still awaiting release without this context fail
closed; an operator must cancel them and request a new handoff.
- Delayed Cloud handoffs depend on the current Cloud membership RPC. An
unavailable, ambiguous, expired, or mismatched response holds the
handoff for retry; it does not reuse cached authority or grant access.
- Bounded reads reload and reauthorize the selected projection per page.
Underlying work grows with the data size and number of pages. Changed
data or routing requires restarting from offset zero without the old
snapshot.
- Phase names and workflow diagrams remain advisory. They do not satisfy
review or approval gates.
- This is a large, cross-cutting PR. The maintainer requested one PR for
the whole feature; the commits separate data, runtime, UI, and
qualification work.

## Model Used

OpenAI Codex, GPT-6 family, with tool use, code execution, and delegated
code review. The exact deployment model ID and context-window size were
not exposed in the session. Live fixture agents used the explicitly
configured provider model recorded in their test evidence.

## 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-20 12:46:14 -05:00
DottaandPaperclip 9225796a4e fix(runner): page oversized assigned tool results (#16980)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agents receive assigned app-tool results through the durable
Runner protocol.
> - The assigned-tool bridge returned complete provider responses
without a size bound.
> - A large response could exceed the encrypted command limit after the
upstream call had completed.
> - The provider then waited for a result that the controller could not
deliver.
> - This pull request saves large governed responses and returns a small
reference with a scoped page reader.
> - Agents can retrieve the full result without repeating the original
action.

## Linked Issues or Issue Description

**What happened?**

Large app-tool responses could leave native tool calls pending even
though the upstream service completed. The durable command limit is
about 510 KiB. The assigned-tool bridge did not account for that limit.
A 720,048-byte regression response failed the delivery-size assertion
before this change.

**Expected behavior**

Deliver a bounded response and a way to retrieve all saved content. Keep
the original action at one execution. Preserve task, agent, company,
responsible-user, and current-run access checks.

**Steps to reproduce**

1. Run a native agent with an assigned tool that returns more than 510
KiB of JSON.
2. Let the upstream tool complete.
3. Observe that the original bridge returns the oversized object
directly, so the durable controller cannot queue its result.

Related: #14734 preserves uncertain tool outcomes across shutdown and
restart. This change keeps that protection. #16517 handles native MCP
content projection on a different transport; it does not bound native
assigned-tool results.

## What Changed

- Save governed assigned-tool responses above 500,000 encoded bytes
using the existing response asset storage, quotas, and audit path.
- Add `read_tool_result` for UTF-8 JSON pages from the same task and
agent. Each encoded page is capped at 500,000 bytes, including JSON
escaping and metadata, with remaining content available through the next
byte offset. It works when generic API tools are disabled.
- Reuse existing authenticated asset reads and responsible-user checks.
Retrieval does not invoke the upstream service.
- Preserve uncertain delivery if storage fails after an action
completes.
- Add regression, fault, authorization, and opt-in live Codex checks.
Document the transport and access contract.

## Verification

- Red: the original integration regression returned 720,048 bytes
against unchanged production code and failed its bounded-response
assertion. The follow-up regression also showed that a 480 KB result was
unnecessarily saved under the original 24 KiB policy.
- Green: results through 500,000 encoded bytes stay inline. Larger
responses are saved in full. Real HTTP integration tests reconstruct the
complete Unicode result after controller recreation in exactly two
pages, in both standard and low-trust configurations, with one upstream
execution.
- The encoded-size boundary and escape-heavy Unicode tests verify that
every page fits 500,000 bytes, cursors advance on valid UTF-8
boundaries, and concatenating pages exactly reconstructs the original
JSON. Storage-failure tests preserve an uncertain outcome without
repeating the action.
- The focused unit/API run passes 1,957 tests; the changed real HTTP
tests pass. `pnpm -r typecheck`, `pnpm build`, `node
scripts/check-maps.mjs`, and `git diff --check` pass.
- Real Codex acceptance passes with `gpt-6.1-sol` through Codex CLI
0.160.0 and native Runner, on macOS ARM64 with `low_trust_review` and
generic API tools disabled. Codex requests every page in order, receives
all 660,098 original bytes, and returns the final verification field.
The two encoded pages are 500,000 and 160,543 bytes; the upstream
operation executes once. Runner closes successfully in a 34.1-second
probe. Only the disposable database's connection/worker counts were
reduced to fit the host's remaining semaphore capacity.
- The native-PRP regression also passes with escape-heavy Unicode pages
over 1 MB in total and a separate inline result containing 200,000
backslashes. A scripted provider verifies both complete results by
SHA-256. It proves the intermediate text wrapper can exceed 700 KB
because the native transport decodes it before queuing the bounded PRP
result; every result object stays within 500,000 encoded bytes. Native
binaries are required for the local run, preventing a silent skip.
- A second real-Codex probe with escaped Unicode, quotes, backslashes,
newlines, and NULs also passes: every original byte of a 720,098-byte
JSON response is retrieved in two encoded pages of 500,000 and 460,543
bytes. The model returns the final field, the upstream call executes
once, and Runner closes in 32.6 seconds. This uses the same production
source with only the synthetic fixture content varied.
- The live probe exercises real PRP, persistence, and authenticated
asset reads. It does not claim the original staging task resumed or full
heartbeat checkpoint acceptance.
- Earlier broader local testing passed 103 tests but could not start the
second database for the existing `rejects a stale source-run question
over public HTTP and accepts it from the next run` test. Extending its
timeout exposed PostgreSQL initialization failure on this
semaphore-exhausted host. The earlier local `pnpm test:run` attempt was
interrupted and is not claimed as passing. Full CI passes on current
head `cd32237ee5429765b8f349402ac3c79cceec3e6b`. GitHub reports 55
successful checks, two skipped Storybook checks, and one neutral
Paperclip agent review. Greptile is 5/5 on this head with no review
threads.
- Additional Paperclip agent review is incomplete: it withdrew the
earlier double-escaping finding after inspecting the native regression,
found no new actionable defects, and reported stalled large-source reads
prevented independent inspection of the transport decoder. Its neutral
assessment is [recorded
here](https://github.com/paperclipai/paperclip/pull/16980#issuecomment-6295579705).
This limitation remains separate from the passing local native
transport, real Codex acceptance, full CI, and Greptile results.

## Risks

- Large responses now consume existing response-storage quota and
require page reads. Larger pages use more provider context. Results are
preserved in full; each encoded page leaves about 22 KiB below the PRP
command limit for the command envelope.
- A storage failure after execution retains an uncertain delivery
outcome. The bridge must not report that the upstream action failed or
invite a replay.
- The dedicated reader grants access only to saved responses for the
current task and agent. The asset route also checks the original
responsible user.
- Runner command limits and receipt rules remain unchanged. No migration
or separate Runner protocol rollout is required.
- This PR does not deploy the repair or resume an existing blocked task.

## Model Used

OpenAI Codex (GPT-6), with reasoning, tool use, and code execution. The
exact serving model ID and context-window size are not exposed in this
session. The opt-in acceptance probe requests `gpt-6.1-sol` through
Codex CLI 0.160.0.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass for the changed behavior
(focused unit/API, real HTTP, and real Codex acceptance); the broader
local database 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-20 11:52:59 -05:00
DottaandPaperclip 2c96f76780 feat(connections): add model-backed prompt injection prevention
Add opt-in OpenRouter checks at existing tool-result boundaries with regex fallback, service accounting, and settings on Connections. Make migration 0362 safe to replay over existing or partially applied schema state.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 11:32:25 -05:00
Nicky LeachandPaperclip 33cc567f75 Add lease-scoped Runner task hooks to environment plugins (#15406)
## Thinking Path

> - Paperclip coordinates AI agents and their runs.
> - Environment plugins own remote capacity.
> - A plugin needs a typed API to start and stop its installed Runner.
> - Core must derive authority from the saved lease.
> - A lost reply or controller restart must not lose cleanup authority.
> - This PR adds the worker contract and the host task service.
> - Native execution and Runner changes are separate PRs.

## Linked Issues or Issue Description

**Subsystem affected**

Plugin SDK and environment lease services.

**Current behavior**

Environment plugins have no typed Runner task hook. Core cannot dispatch
these tasks or recover their credential handoff through a saved lease.

**Proposed behavior**

Add validated task operations, worker negotiation, company and project
checks, retained-session authorization, and durable cleanup. Keep
credentials out of lease metadata.

**Additional context**

This PR is the first part of a smaller series. Runner installed-home
support is in #16977. Native execution and setup are in #16978. Both are
stacked drafts. This PR does not enable native plugin execution, change
default environments, add a route, or add a database migration.

## What Changed

- Add `supportsTasks` and `onEnvironmentTask` with seven typed
operations.
- Validate worker requests and responses. Reject shell commands and file
transfer operations.
- Pin dispatch and cleanup to the saved company, lease, plugin, and
driver.
- Authorize projects and retained sessions. Validate the current run
separately from the retained PRP identity.
- Save dispatch before the provider call. Fence admission during
cleanup. Require observed process termination.
- Save account writeback authority on the lease. Recover Codex refreshes
through the existing account and secret services.
- Document the task API. Keep the Runner, heartbeat, setup, workspace,
and provider changes in later PRs.

## Verification

- Full `pnpm -r typecheck` and `pnpm build` passed on the separated API
scope.
- 201 focused tests passed: SDK worker dispatch, task validation,
PostgreSQL task lineage, credential recovery, and existing environment
cleanup.
- The lineage test covers a third run, repeated same-run replacements, a
stale submitting run, and exact termination receipts.
- Initial commands hit sandbox socket/IPC restrictions. The permitted
runs executed PostgreSQL and passed. A typecheck attempt lacked Cargo in
PATH; the run with the installed toolchain passed.
- The earlier combined implementation had a full local run with 22,286
passing tests, 120 skips, and eight failed assertions. Task fixture
failures were fixed before this split. Remaining host Git and
temporary-path assertions are recorded in the previous PR revision. This
split does not claim a fresh full local suite pass.
- The standard Greptile review scored this API head 5/5 with no
unresolved threads. CI is green. The single Apex review also scored this
head 5/5 with no actionable findings.
- Fresh API CI lost a self-hosted runner during server shard 9. GitHub
reported lost communication, with no failed test step. The affected jobs
passed on retry without code changes.
- CI on the prior combined head failed an unchanged workspace dev-server
readiness case. No unrelated test fix is included here. Fresh CI is
required for this smaller head.
- This scope does not run a provider or a Cloud test. The user owns
deployment and the intermediate Cloud test.

## Risks

- The API is opt-in. Native plugin execution requires the later
integrations.
- Providers must make task submission idempotent and prove descendant
termination.
- A failed status read or credential export keeps the lease available
for cleanup.
- Codex refresh writeback requires the same active grant, secret
reference, and session epoch. Revocation or account replacement discards
the old refresh.

## Model Used

OpenAI GPT-6 through Codex. Used source inspection, code execution,
tests, and GitHub tools. The exact served model ID and context-window
size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run local checks and recorded failures and their results
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-20 09:14:23 -07:00
DottaandPaperclip 98d17da1e2 Fix native monitor dispatch and finalization recovery (#16975)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs persist their results and workspace before they release
execution.
> - A task monitor must wait for that settlement before it starts the
next run.
> - The scheduler checked provider status but did not check unfinished
finalization.
> - A timer could dispatch too early, then its old finalizer could no
longer find the consumed schedule.
> - This pull request delays dispatch and reconciles prior delivery from
server records.
> - The task can continue without repeating the provider turn or
removing a newer run's ownership.

## Linked Issues or Issue Description

**What happened?**

A native run saved a yielded monitor result while workspace finalization
needed recovery. Its timer dispatched after the provider stopped. The
follow-up failed because the earlier run still held workspace recovery.
The old finalizer then retried `monitor_wait_authority_lost`
indefinitely.

**Expected behavior**

Timer dispatch waits for native finalization. If an older timer already
dispatched, the finalizer uses its saved scheduling receipt and admitted
successor to settle the old result. It preserves current task state and
ownership.

**Steps to reproduce**

1. Schedule a task monitor from a native run and save a yielded result.
2. Leave native finalization retryable after the provider reaches a
terminal state.
3. Let the monitor become due. Before this change, the scheduler
consumes it.
4. Restore workspace persistence and retry the old finalizer. Before
this change, the missing schedule leaves it retryable.

**Paperclip version or commit**

Reproduced against master `34be1b831bcaba070264ae8d214ceffe6a8f9eab`.

**Deployment mode**

Self-hosted server built from source, with PostgreSQL and the native
runner. Related recent recovery work: #16962 and #16963. No duplicate
repair found for this failure.

## What Changed

- Scheduled and manual monitor dispatch wait for unfinished native
finalization. If the monitor expires during workspace recovery, the
accepted result can settle into the persisted schedule, and the
scheduler then applies its existing expiry policy. New monitor-wait
results still require an unexpired, unexhausted schedule.
- A narrow reader joins the run's server-issued monitor receipt to its
durable wake and admitted successor.
- The finalizer and locked status commit verify that evidence and
preserve current task ownership. They do not create another wake.
- Monitor delivery participates in assessment identity, so recovery can
replace a prior error decision without violating the decision ledger's
uniqueness constraints.
- PostgreSQL regressions cover saved-result replay, active successors,
wrong task or agent, missing receipts, unadmitted wakes, ownership
races, and failed workspace persistence.
- The execution contract and verification maps describe the recovery
boundary.

## Verification

- Red: the saved monitor regression remained `retryable_failure` instead
of `committed` on unpatched code.
- Red: the scheduler admitted a wake while terminal-run finalization
remained retryable.
- Red/green: two PostgreSQL cases reproduce timeout during workspace
recovery for scheduled and manual checks. Before the review repair, both
remain `retryable_failure` with `monitor_wait_authority_lost`.
Afterward, both commit, apply board escalation once, preserve the saved
result, and enqueue zero provider wakes. New completion still rejects
the expired schedule.
- Typecheck: `pnpm -r typecheck` passed.
- Build: `pnpm build` passed.
- Maps: `node scripts/check-maps.mjs` passed.
- Review: Greptile 5/5 and Ponytail Paperclip Review 5/5 on the current
head, with no unresolved findings. Both reviews are static; execution
evidence is recorded separately above and below.
- Linux staging: the original repair passed 170 tests across monitor
integration, scheduling, status arbitration, and workspace finalization.
The expanded suite passes all 172 tests, including both new timeout
regressions.
- Live acceptance: deployed the original repair to the authorized Linux
ARM64 self-hosted instance. The stranded saved result finalized
automatically; the original task then completed through normal
admission, with its final answer persisted after browser reload. The
other original task was already complete and its external delivery was
verified without repeating it.
- The initial Mac regression run passed 68 tests, but three suites
failed during embedded PostgreSQL startup. A subsequent focused run
confirmed the host had exhausted its PostgreSQL semaphore allowance.
Linux verification uses isolated databases; the local failure logs
remain preserved.
- The local full test suite is not claimed as passed. It is blocked by
the same PostgreSQL startup limitation; full-suite CI passed on head
`8bc29d1b7783446f397b858e558083570a96bb66`
([run](https://github.com/paperclipai/paperclip/actions/runs/39447913466)).

## Risks

- A delivery match must not grant new execution authority. The lookup
requires the original run's server receipt and a matching company,
agent, task, wake, and admitted successor. The locked commit rejects
old-run checkout ownership and permits no status effects.
- Workspace persistence must succeed before settlement. Its existing
failure path remains effective.
- The scheduler waits while a native finalizer is unfinished. Workspace
recovery must settle before dispatch; elapsed monitor limits transfer to
the existing scheduler recovery policy instead of stranding the result.
Neither settlement path renews a deadline or changes budget, approval,
pause, or provider authority.
- No schema, migration, credential, or provider configuration change.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 10:58:41 -05:00
Devin FoleyandPaperclip 24758b9da1 Avoid loading tool schemas for effective assignments (#16969)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tool profiles define which tools an agent can use.
> - Run preparation and connection checks resolve these assignments from
the database.
> - These callers need tool IDs and names, but the existing lookup also
reads complete schemas and provider metadata.
> - Repeated lookups transfer data that these callers discard.
> - This pull request adds a small assignment projection through the
same permission resolver.
> - The benefit is less database transfer and JSON work with current
permission checks and the same public response.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Effective tool assignment reads during run preparation, native runtime
setup, and connection policy checks.

**Subsystem affected**

server/ — tool access and orchestration services.

**Current behavior**

Internal callers use the public effective-profile lookup. Its catalog
query reads complete tool rows, including input schemas, output schemas,
annotations, and provider metadata. These callers only use catalog IDs
and names.

**Proposed behavior**

Internal callers use an assignment lookup that selects catalog identity
and selector fields. Both lookups share one resolver. The public
effective-profile endpoint keeps its complete definitions.

**Reason and benefit**

Large catalogs increase database transfer and JSON work for every
assignment lookup. The smaller query avoids that payload without caching
permissions or changing query frequency.

**Breaking changes**

None. No route, schema, migration, permission rule, or public response
changes.

Related: Refs #16761, Refs #16723. The former narrows profile summary
reads. The latter changes how the gateway presents tool definitions.
Neither narrows this internal effective-assignment lookup.

## What Changed

- Share effective-profile resolution between full definitions and
assignment records.
- Select the existing catalog identity and selector projection for
internal assignments.
- Use the assignment lookup in run preparation, native runtime setup,
and connection policy checks.
- Add real PostgreSQL tests for selectors, exclusions, current profile
and binding state, company boundaries, and returned payload size.
- Document the database read contract.

## Verification

- Five focused test files passed: 521 tests. They cover tool access,
connection intents, runtime preparation, native runtime context, and the
new assignment lookup.
- `pnpm -r typecheck` passed.
- `pnpm check:module-boundaries` passed.
- The PostgreSQL fixture compares the full authorization result with the
assignment result. It checks all selector types, excludes removed tools,
and observes catalog, profile, and binding changes on later calls.
- The payload test measures rows returned by PostgreSQL before
application mapping. With large schema and annotation fields, the
assignment result is less than 1% of the full catalog payload. This is a
synthetic fixture result, not a fleet savings estimate.
- `pnpm build` passed.
- The full local suite is in progress. It found two Git fixture failures
that also reproduce on unchanged master with `init.defaultBranch=main`.
Both pass with a process-only `init.defaultBranch=master` setting. The
global Git configuration was not changed. This earlier failure remains
recorded; it is not counted as a clean first pass.
- Apex review: 5/5, no actionable comments. All 54 CI checks passed; two
conditional jobs were skipped.
- The broader local run also reached two UI test timeouts and one
adapter test timeout. All three passed when rerun in isolation with
unchanged source. The exact cause of these timeouts is not established.
No UI or adapter implementation is changed by this PR. The CLI
import/export journey passes its assertions but its local teardown fails
with `ENOTEMPTY` while a runtime context asset is written. Its CI check
passed. The complete local suite is not reported as a clean pass.

## Risks

- Both lookups share permission resolution. Existing tool access tests
and result parity checks cover that extraction.
- Future assignment callers must use the fields in the smaller result.
Typechecking rejects attempts to read full schemas from it.
- The lookup still scans the active company catalog and resolves current
connections on every call. This change reduces returned bytes; it does
not reduce query count or introduce a cache.
- No database migration or operational configuration change is required.

## Model Used

- OpenAI GPT-6 through Codex, with tool-assisted source inspection,
implementation, and test execution. The exact model variant and context
window are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 08:42:59 -07:00
Devin FoleyandPaperclip ba3bdd0675 Keep Muse maintenance idle on unclaimed warm instances (#16974)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Cloud keeps unclaimed applications warm so new users can enter
quickly.
> - Empty warm applications use an existing standby predicate to skip
recurring database work.
> - Muse maintenance starts without that predicate and scans its tables
every five seconds.
> - These scans keep an empty database active even when no Muse binding
exists.
> - This pull request applies the existing standby predicate to Muse
startup and recurring maintenance.
> - The benefit is idle database compute while the application stays
warm, with normal maintenance after claim.

## Linked Issues or Issue Description

**What happened?**

`createApp` starts Muse maintenance without the warm standby guard used
by other background services. The worker updates qualification evidence
at startup and reads binding tables every five seconds, including on an
empty unclaimed instance.

**Expected behavior**

An unclaimed warm application must not run recurring database work. Muse
maintenance must resume after the signed claim, without a process
restart.

**Steps to reproduce**

1. Start the maintenance service with background work disabled.
2. Advance the timer beyond several five-second sweeps.
3. Observe database calls from the original implementation despite the
disabled state.

The new regression test uses real PostgreSQL. The original source fails
its zero-query assertion; the patched source passes.

**Paperclip version or commit**

Reproduced on `813e808af46` before this fix. Related: Refs #16448.

## What Changed

- Pass the Cloud standby predicate to Muse maintenance.
- Admit both the startup evidence update and recurring sweeps only when
background work is enabled.
- Mark startup evidence once, before reconciliation. Retry that write
after a database failure.
- Add PostgreSQL tests for standby, claim, later ticks, default deadline
enforcement, and startup-write failure.
- Document the maintenance boundary.

## Verification

- Five focused test files passed: 278 tests. They cover Muse
maintenance, Muse control and qualification routes, and Cloud standby
behavior.
- Controlled regression: the new standby test fails against the original
maintenance source. The patched source was restored after the
comparison.
- The new PostgreSQL test advances ten minutes while admission is closed
and observes zero database operations. It opens admission and verifies
the persisted qualification evidence update and reconciliation. Later
sweeps retain a single successful startup update.
- `pnpm check:module-boundaries` passed.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- All 54 CI checks passed; two conditional jobs were skipped.
- Apex review: 5/5, no actionable comments or unresolved threads.
- The full local test command is still running. The focused tests,
workspace typecheck, build, and complete CI matrix above are the
finished checks.

## Risks

- Claimed workspaces retain existing Muse maintenance. The app gate
depends only on warm standby. It does not suppress deadline enforcement
or terminal cleanup during idle task drain.
- Work resumes on the next five-second maintenance tick after claim.
Request-driven work remains available through the existing claim path.
- The receiver keeps its existing lifecycle. Its empty pending-contact
map causes no database writes in standby.
- No database migration, provider configuration, or authority rule
changes.
- Broker and receiver effects are mocked in the new maintenance tests.
The database operations are real. Existing Muse control tests cover the
broker boundary; no live Muse provider qualification is claimed.

## Model Used

- OpenAI GPT-6 through Codex, with tool-assisted source inspection,
implementation, and test execution. The exact model variant and context
window are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 08:42:42 -07:00
DottaandPaperclip 4b05795712 fix(github): reuse review instructions across native turns (#16971)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub events continue an ordinary task and can reuse its provider
conversation.
> - Each automatic event appended the full review policy and PR
description.
> - Native GitHub follow-ups also repeated task history because only
Slack used the compact path.
> - This pull request separates admitted review configuration from
commit updates.
> - A verified resume sends the current messages and changed
configuration. A fresh session gets full context.
> - This reduces repeated input while retaining review rules and current
tool checks.

## Linked Issues or Issue Description

Refs #13959, #16645, #16901.

**What happened?**

Opening a PR and pushing twice stored three full review prompts. A later
native turn repeated all three in a retained provider conversation.

**Expected behavior**

A new event supplies its commit and event data. The harness delivers
stable review instructions once per retained conversation and
configuration. Fresh sessions receive full instructions.

**Steps to reproduce**

1. Enable automatic GitHub reviews for a repository.
2. Open a PR, let the review finish, and push two new commits.
3. Inspect task messages and the native submitted envelopes. Before this
fix, the policy and old requests repeat.

## What Changed

- Store compact automatic event messages. Fetch the PR description
through the existing metadata tool when needed.
- Load review instructions from processed deliveries bound to the
company, task, agent, and source comments. Preserve each admitted policy
snapshot.
- Use the existing verified native continuation path for complete GitHub
text batches. Deliver configuration changes using a key over endpoint,
PR conversation, revision, and instructions.
- Keep full bootstrap input for fresh sessions and failed resume,
including board follow-ups with no new GitHub event. Retain existing
framing for incomplete batches, attachments, interactions, and recovery.
- Keep the same configuration identity across automatic review,
discussion, and automatic review. Coalesced requests use the last
accepted request's admitted policy.
- Add regression and database coverage. Update the execution contract
and verification recipe.

## Verification

- Red: the new event-size regression failed because policy and PR body
repeated. The GitHub continuation regression failed because it returned
no compact prompt.
- Green: focused policy, continuation, native input, and adapter prompt
tests passed (231 tests). Native resume/fresh-bootstrap cases passed (9
tests).
- The signed-webhook/database case passed at `6296168253`. It checks
configuration edits, queued older snapshots, coalesced policy selection,
discussion continuity, board follow-ups, and company/task/agent/comment
boundaries. The private PostgreSQL template used 12 connections because
the host reached its semaphore limit with the default settings.
- The earlier broad channel/session integration run passed 1,432 tests.
Later review fixes invalidated that run. The latest focused database
case passed after those fixes.
- Reviewer regressions failed against the previous lookup, then passed
with the fix: a mixed-revision batch delivered multiple policies, and a
discussion lost the configuration identity. The board
wake-to-rendered-prompt regression also failed before repair.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` passed on the final source.
- Full local `pnpm test:run` exposed follow-up/fixture failures during
development. Those cases are fixed and pass separately. The stale run
was stopped after source edits. Full-suite validation for the final
commit passed in CI.
- All required CI checks passed for `6296168253`, including tests,
typechecks, build, and clean public npm install checks. The two
unrelated Storybook checks were skipped.
- A live two-turn Codex smoke could not start: the local macOS sandbox
helper rejected execution of the installed Codex 0.153.4 binary. No live
GitHub/provider acceptance or deployment is claimed.

## Risks

Skipping instructions is safe only after a verified checkpoint resume
with the correct previous run. The full bootstrap remains available if
resume fails. Changed or previously unknown configuration is sent again.
Tests cover these cases. Tool authorization and publication checks still
run under the current server policy. No database migration is required.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
deployment model identifier and context window are not exposed in this
session. No delegated agents were used.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 10:39:17 -05:00
Devin FoleyandPaperclip 1f3695ac67 fix: expire native session failover backups after their issues close (#16866)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native agent sessions that run in a remote sandbox keep a host-side
failover copy of the sandbox's harness state, so a replacement sandbox
can resume the conversation
> - Each session keeps that copy forever, and one copy can reach several
gigabytes
> - On a busy instance these copies fill the volume, and no existing
cleanup touches them
> - Once a session's work is closed, its copy matters only if someone
reopens that work later
> - This pull request expires the copy after the session's issues have
been closed for a configurable window, and makes a reopened issue start
a fresh session
> - The benefit is bounded disk use without breaking active,
recoverable, or leased sessions

## Linked Issues or Issue Description

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

**What happened?**
After every remote turn, `checkpointRemoteRunner` writes the sandbox's
runner state and provider session home (for example `codex-home`) to
`durable-sessions/<scope>/failover-backups/current`. Only the same
session's next checkpoint replaces it. No code path deletes a session's
copy when the session ends, its issue closes, or its agent goes away, so
the instance volume fills. On one instance:
- 246 sessions held 17 GB of copies, 84 of them older than a week;
- 24 new sessions added 5 GB in a single day, one copy alone 3.2 GB.

**Expected behavior**
Disk used by failover copies stays bounded. A copy is kept while its
session can still resume (open issue, live run, pending recovery, or
live lease), and expires once the session's issues have been closed for
a while. A reopened issue then starts a fresh native session, instead of
failing with `runner_harness_backup_unavailable` on a replacement
sandbox.

**Steps to reproduce**
1. Run agents with a native runtime in a remote sandbox environment.
2. Let them complete many issues.
3. Watch
`<instance>/runtime/paperclip-runner/durable-sessions/*/failover-backups/current`
grow without bound after the issues close.

**Paperclip version or commit:** `master` at 9179d8dcc3.
**Deployment mode:** server with remote sandbox environments.
**Agent adapter(s) involved:** not adapter-specific (core bug); observed
with Codex sessions.

**Breaking changes**
- Reopening an issue that has been closed for longer than the window
(default 7 days) starts a fresh agent session instead of resuming the
old conversation.
- Disable with
`PAPERCLIP_NATIVE_HARNESS_BACKUP_EXPIRATION_ENABLED=false`, or lengthen
the window with `PAPERCLIP_NATIVE_HARNESS_BACKUP_EXPIRATION_DAYS`.

## What Changed

-
**`server/src/services/native-runtime/native-harness-backup-expiration.ts`
(new):** the sweep. It checks at most 200 sessions and expires at most
50 per batch, continuing from a cursor. A copy expires only when all of
these hold:
- every issue the session ran on is `done` or `cancelled`, closed before
the window;
  - the copy was written before the window;
  - no run of the session is queued, running, or unfinished;
- every native run finalization of the session is settled (`committed`
or `terminal_failure`), with no recovery state or lease owner;
- no `active`, `released`, `retained`, or `pending_cleanup` environment
lease references the copy (by backup stamp, session run, or recorded
lease);
- the session is not executing, initializing, warm, or closing in this
process, and its directory has no pending cleanup activation.
- **One transaction:** the database checks share-lock the issues and
delete the agent task session that points at the session, so a reopened
issue cannot resume the expired session.
- **Atomic, non-blocking removal:** the copy is renamed to
`failover-backups/.retiring-<UUID>`, and a final check looks for a run
of the session. If one appeared, or the check throws, the rename is
undone. Only a confirmed copy becomes `.expired-<UUID>` and is deleted
with asynchronous file operations, so a multi-gigabyte removal does not
block the event loop. A later sweep restores an unconfirmed
`.retiring-*` copy when `current` is missing, drops it when a newer
`current` exists, and finishes an interrupted deletion. The rest of the
session directory is kept.
- **`native-session-executor.ts`:** exports
`nativeSessionScopeDigestIsBusy`, which checks the in-process executing,
initializing, warm, and closing session maps.
- **`native-harness-backup-stamp.ts`:** exports the state base path the
sweep scans.
- **`config.ts` and `index.ts`:** three environment controls
(`_ENABLED`, `_DRY_RUN`, `_DAYS`) and the scheduled sweep. It starts two
minutes after boot, honors shutdown, standby, and idle drain, and logs
candidates, reclaimed bytes, cleared task sessions, and skip reasons.
- **Docs:** `doc/recoverable-disk-cleanup.md` describes the sweep;
`doc/DEVELOPING.md` lists the variables.
- No code comments were added.

## Verification

- `pnpm exec vitest run
src/__tests__/native-harness-backup-expiration.test.ts
src/__tests__/native-harness-backup-expiration-config.test.ts` (in
`server/`): 30 passed, 24 of them against embedded Postgres plus 6
config tests. Cases:
- expiry for done and cancelled issues, including clearing the task
session;
- each keep condition: open issue, recently closed, live run, pending
finalization, recovery in progress, live lease, recent copy, cleanup
activation, in-process session;
  - settled finalizations and expired leases do not block;
  - dry run changes nothing;
  - bounded batches continue across ticks;
- an interrupted deletion is finished, and an unconfirmed retiring copy
is restored or dropped;
  - the configured clock controls the closed window.
- **Mutation checks:** treating `in_progress` as closed, ignoring live
leases, ignoring the configured clock, or not restoring a retiring copy
each fail the corresponding tests.
- `pnpm exec vitest run native-harness-backup config` (in `server/`): 19
files, 293 tests passed.
- `pnpm run typecheck` (in `server/`): pass.
- **Real server:** after building and bundling,
`scripts/server-boot-smoke.sh node server/dist-runtime/index.mjs`
reached healthy.
- **Manual equivalent on a live instance:** applying these checks by
hand (with a 3-day window) to 242 copies freed 7.1 GB. Most of the
remainder belonged to open issues or live leases.

## Risks

- **Reopen after the window:** the agent starts a fresh session and
loses the old conversation's provider history. Issue comments,
documents, and work products are unaffected.
- **Race with a wake:** the checks share-lock the issues, so a reopen
waits for the transaction. A run created for the session between commit
and rename is caught by the post-rename check, which restores the copy.
Such a run would find no task session and start fresh.
- **Missing owner run:** if the owning run row is gone (for example,
after an agent was deleted), the copy is kept, because the sweep cannot
prove the session is closed.
- **Untouched:** quarantined session roots and `continuity-breaks`
archives are not touched by this change.
- **Rollback:** set
`PAPERCLIP_NATIVE_HARNESS_BACKUP_EXPIRATION_ENABLED=false`, or revert.
Expired copies cannot be restored.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), 1M context, through Claude Code
with tool use (shell, file edits, local builds, tests and boots,
read-only measurements on a live instance).

## 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-20 07:57:43 -07:00
DottaandPaperclip 813e808af4 Remove filesystem history authorization from workspace preparation (#16963)
Remove physical-root source/reader authorization and sticky directory classifications from workspace preparation. Preserve current task/run authority, app-record privacy, credential authorization, containment, and lifecycle/publication integrity.

Validate replacement selections against persisted new inputs and refresh verified checkout ownership so bounded reuse survives earlier workspace relocation. Add real PostgreSQL/Git regressions, a reproducible history-scaling benchmark, and documentation.

Full CI passed all 48 jobs and Greptile scored 5/5 at 3d5da6c259. Five preparation-guard medians improved from 20,512.99 ms to 52.22 ms on the 8,500-workspace fixture; these are not end-to-end startup timings.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-20 09:19:59 -05:00
DottaandPaperclip 92b238137b Connect and configure GitHub Copilot through Apps (#15705)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Apps and AI Connections store credentials and govern access to agent
runtimes.
> - Users need a supported saved-token connection and config values that
survive save and reopen.
> - The release must preserve saved-token access and task lifecycle
guarantees.
> - This pull request will connect Copilot through the normal Apps and
AI Connections path.
> - The benefit is a reviewable part of the Copilot production release.

## Linked Issues or Issue Description

Refs #15701 and #15703. Supersedes setup work in #15562. Base: #15703.
Next: #15706.

## What Changed

- Require configuration update authority before Copilot
credential-bearing model discovery; default to the saved environment and
preserve explicit selection for editors.

- Keep Copilot discovery passive during reconnect reconciliation;
refresh on explicit opening, account/environment changes and reconnect.

- Add GitHub AI token connections with encrypted storage, ownership,
grants and audit logging.
- Keep repository access separate from Copilot runtime authentication.
- Probe the selected environment without sending a model prompt and
preserve authenticated model selection through save/reopen.
- Keep fresh execution admission consistent with normal Copilot setup;
persist task model choices without changing provider or permission
policy.
- Refresh authenticated models after reconnecting the same saved Copilot
account, including recovery from a previous authentication error.
- Apply the additive provider-default constraint migration through the
normal generated migration workflow.

## Verification

Runtime #15701 is merged at `d855e550ad8d2a267312983f26457aabf5393c3a`.
History #15703 is merged at `df80616d98119cbf5abd40549794d9980a5fabf6`.
Remaining source
[`42bcbd61299655f7e37aabe6bb5f19bba770ad1d`](https://github.com/paperclipai/paperclip/commit/42bcbd61299655f7e37aabe6bb5f19bba770ad1d)
contains the four-file authorization repair. The remaining PR trees
preserve six nonoverlapping files from the newer public mainline
managed-settings fix and the CI-owned lockfile. No unrelated provider is
enabled.

The security finding is repaired: existing-agent discovery requires
`agent_config:update` before connection selection or token resolution.
The saved environment is the default. Authorized editors can select a
prospective environment. Both denied board-viewer and agent-reader
regressions fail on the original source. All49 route tests and server
typecheck pass with the fix. Denied requests perform no connection
selection, credential resolution or probe. Current-head security scans
pass on both remaining PRs; the repaired thread is resolved.

Copilot CLI1.0.88 and profile47 retain digest
`sha256:55044aa235e88b3fe36ec8a556ee1e3382590870aab907e4462ef7d64af49cea`.
The [qualification
record](https://github.com/paperclipai/paperclip/blob/42bcbd61299655f7e37aabe6bb5f19bba770ad1d/doc/plans/2026-10-20-copilot-qualification-v47.json)
reports20/20 Product cells,154 assertions and7/7 protocol cases,46
assertions against frozen normal installed source
`c2616370800f5f6df45246b0890ba35a7cd2faab`. The exact qualification
model is `gpt-5.6-luna`. Every passing Product case confirms cleanup.
Original failures remain recorded; automatic behavior retries are
disabled. The route-only authorization repair changes no bound
runtime/profile bytes and does not relabel the frozen campaign.

The ordinary installed remote journey passed saved-token selection,
model discovery, normal UI save/reopen, metadata-only Test, completed
task, accepted receipt and exact19-byte browser download. An open model
catalog caused no additional discovery requests during117seconds. Actual
installed runtime smokes passed on macOS ARM64, macOS x64 under Rosetta
and native Linux x64 on Daytona. Raw token browser entry was not
exercised; encrypted connection creation used the normal API.

The first Daytona file attempt timed out during delayed semantic
dispatch; its precise stalled layer remains unresolved. Independent
ordinary remote delivery and the other19 Product cells passed before one
instrumented recheck passed8/8 with unchanged source,prompt,assertions
and deadlines. No causal latency repair is claimed.

Before the authorization repair, all four final PR heads passed required
verify/E2E and fresh Greptile5/5 reviews with zero unresolved threads.
Current-head CI/review is running for the two repaired heads. Local
focused checks retain129 connection,59 runner,72 shared-eval and88
recovery/workspace passes, plus migration safety and token gates. The
additive Copilot migration is361; released master history is preserved.

[Cloud normal-package
run39414239704](https://github.com/paperclipai/paperclip/actions/runs/39414239704)
builds the pre-security source4f3f. All four native producers and Linux
package assembly pass; the final clean installed consumers are
finishing. All18 retained archives match their hashes;37,863 regular
files contain zero selected credentials. That package does not contain
the later route repair. The actual final published package must include
it and pass the local/Daytona live canaries. The frozen Daytona image
remains published and independently verified. No separate full-image
scan is claimed. Docker builds run in the cloud.

**Remaining:** current-head CI/review, setup and qualification merges,
final publication, and ordinary local/Daytona canaries against the
actual shipped package. The user explicitly authorizes the maintainer
review override; CI remains a merge gate. No production deployment is
claimed. Provider USD remains unknown and GitHub-attributed.

## Risks

Bad credentials, missing entitlement, runtime installation and
unavailable models must remain distinct failures. A connection must not
adopt ambient credentials. The constraint migration changes accepted
provider values, with no credential-storage migration.

Current-master NewAgent fixture extraction is retained. Copilot cases
use that shared support and test both passive discovery and explicit
reconnect under the same setup lifecycle.

The onboarding retry regression shares the component suite’s
saved-connection, authenticated-model, draft, agent-list, hire and
render lifecycle fixtures. Keeping it beside the existing onboarding
failures makes adoption versus duplicate hire observable under the same
lifecycle; this is the concrete cohesion reason for the existing large
test file.

## Model Used

OpenAI Codex, based on GPT-6. The exact serving model ID and context
window are not exposed in this task. Used for code changes, review and
tool-assisted verification.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each task prepares its workspace before it starts the provider.
> - Source preparation holds a transaction-scoped advisory lock on a
dedicated database connection.
> - Preparation can use other connections and the filesystem for longer
than PostgreSQL allows that lock connection to stay idle.
> - PostgreSQL then closes the connection and releases the lock while
preparation still runs.
> - This pull request reuses the workspace lock keepalive during source
preparation.
> - Slow preparation retains exclusion and returns its original result
or error.

## Linked Issues or Issue Description

**What happened?**

Tasks failed during workspace preparation with `CONNECTION_CLOSED` at
the configured 60-second idle transaction timeout. No provider had
started. A live retry showed the source-lock transaction idle while
authorization reads ran on another connection. Its advisory-lock key
matched the task's source-preparation key. PostgreSQL closed that
transaction at the timeout.

The same defect remains on current master. A real PostgreSQL regression
also shows that another preparation can enter after the timeout while
the original callback still runs.

**Expected behavior**

Source preparation must keep its advisory lock until the callback and
any pending keepalive query finish. The ordinary pool must remain
usable. The original preparation result or failure must survive.

**Steps to reproduce**

1. Set `idle_in_transaction_session_timeout` to one second in a
disposable PostgreSQL database.
2. Call `withIsolatedRepositorySourceLock` and keep its callback active
for longer than one second without querying the lock connection.
3. Try to acquire the same source lock from another operation.
4. On the old code, the second operation enters and the first
transaction fails with `CONNECTION_CLOSED`.

**Paperclip version or commit**

Reproduced on source at `cde944ed75648adfb569e86133adc8b118b55dd6`. The
repair is rebased onto `d855e550ad`.

**Additional context**

Refs #16340. That change introduced the keepalive for workspace
copyback. This PR applies the existing helper to the source-preparation
transaction.

## What Changed

- Read the configured idle timeout in the same query that acquires the
source lock.
- Keep that dedicated connection active during source preparation with
the existing helper.
- Add two real PostgreSQL regressions for exclusion, company
independence, a one-slot ordinary pool, nested acquisition, cleanup, and
preservation of callback errors.
- Update the execution contract and workspace verification maps.

## Verification

- Red before the production edit: both new tests failed. A competing
operation entered after the lock expired. A callback failure was
replaced by `CONNECTION_CLOSED`.
- Green after the repair: 86 tests passed across the source lock, source
admission, keepalive, and heartbeat workspace preparation suites.
- `pnpm -r typecheck`, `pnpm build`, and `node scripts/check-maps.mjs`
passed on final commit `2b5000ce25`.
- `git diff --check` passed. The lockfile is unchanged.
- After rebase, the same 86 focused tests passed. The two source-lock
tests passed again after the review cleanup change.
- Live acceptance on `7df94d7a06`: a fresh local instance on macOS
arm64, Node v26.4.0, native Codex `gpt-6.1-sol`, and permission mode
`never`. PostgreSQL had a one-second idle transaction timeout. A
temporary Git wrapper delayed repository reads by four seconds.
Workspace preparation after environment acquisition took 8,297 ms. The
real task completed, wrote and attached the correct line-count/SHA-256
report, reached `done` with native phase `committed`, and cleared its
execution lock. The attachment matched the workspace file and survived
browser reload. No dedicated lock connections remained.
- The live probe initially used `gpt-5.4`, which the ChatGPT account
rejected. Selecting the reported task model, `gpt-6.1-sol`, resolved
that readiness failure. The local Claude CLI has no login, so no live
Claude run is claimed.
- Full CI passed on `2b5000ce25`: all general, chat, workspace,
serialized-server, Runner, and E2E test shards, plus typecheck, build,
and canary packaging. Both Greptile and Paperclip Review rated this
commit 5/5 with no open findings. The Paperclip check concluded neutral;
two unrelated visual checks were skipped.
- The duplicate local `pnpm test:run` serial invocation was stopped with
SIGINT after the complete CI test shards passed. It did not finish
locally; no local full-suite pass is claimed. Local proof consists of
the focused real PostgreSQL tests, typecheck, build, map checks, and the
real task above.
- The final commit changes test teardown only; production code matches
the live acceptance commit.
- Initial sandbox runs could not open test database ports or build IPC
sockets. The same commands ran with local process access. The frozen
install also found an existing manifest/lockfile mismatch; dependency
resolution was local and the lockfile was restored.

## Risks

- The lock connection sends one small query per keepalive interval. The
helper derives that interval from the configured timeout and caps it at
30 seconds. It does no polling when the timeout is disabled.
- The helper joins an in-flight query before the transaction ends. A
slow database can therefore delay cleanup.
- This change does not disable database deadlines, retry preparation, or
recover an unexpected connection loss. It preserves existing admission
checks and company/source lock keys.
- Deployment and recovery of the reported tasks remain separate from
code verification.

## Model Used

OpenAI GPT-6 through Codex, with repository tools, code execution, and
browser verification. The exact served model variant and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 07:01:17 -05:00
DottaandPaperclip d855e550ad Finish Copilot native runtime on current master (#15701)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Paperclip Runner controls provider processes, permissions and task
completion.
> - Copilot needs its pinned distribution, native message identities and
accepted semantic completion receipts.
> - The release must preserve saved-token access and task lifecycle
guarantees.
> - This pull request will keep the current completion and recovery
fixes while adding the Copilot runtime.
> - The benefit is a reviewable part of the Copilot production release.

## Linked Issues or Issue Description

Refs #14434. Supersedes the runtime work in #15560. This is the first PR
in the stack; #15703, #15705 and #15706 follow. Related alternative
adapter work: #15881. This change uses the shared Runner path.

## What Changed

- Pin Copilot CLI 1.0.88 and bind the integrated implementation as
profile45.
- Keep native instruction, permission, receipt, process ownership and
cancellation boundaries.
- Preserve current master completion continuation and remote
verification behavior. Other provider release identities stay unchanged.

## Verification

Final reviewed source
[`4f3f1af807d2ed21adabb04c2f27f4df9c4bc8d5`](https://github.com/paperclipai/paperclip/commit/4f3f1af807d2ed21adabb04c2f27f4df9c4bc8d5)
includes master `cde944ed75648adfb569e86133adc8b118b55dd6`. The combined
four-part PR tree matches it except for the CI-owned lockfile. Every
prior public PR head remains an ancestor. Released master migrations
remain unchanged; Copilot adds migration361. No unrelated provider is
enabled.

Copilot CLI1.0.88 and profile47 retain digest
`sha256:55044aa235e88b3fe36ec8a556ee1e3382590870aab907e4462ef7d64af49cea`.
The pending qualification marker is removed. The [qualification
record](https://github.com/paperclipai/paperclip/blob/4f3f1af807d2ed21adabb04c2f27f4df9c4bc8d5/doc/plans/2026-10-20-copilot-qualification-v47.json)
reports **20/20 Product cells,154 assertions;7/7 protocol cases,46
assertions** against frozen installed application
`c2616370800f5f6df45246b0890ba35a7cd2faab`. Both environments use the
exact authenticated model `gpt-5.6-luna`. Every passing Product case
confirms cleanup. Automatic behavior retries are disabled. Original
failed attempts remain recorded.

The ordinary installed remote journey passed saved-token selection,
authenticated model discovery, normal UI save/reopen, metadata-only
Test, task completion, accepted receipt and an exact19-byte browser
download. An open model catalog caused no new discovery requests
during117seconds. Actual installed runtime smokes passed on macOS ARM64,
macOS x64 under Rosetta and native Linux x64 on Daytona. Raw token
browser entry was not exercised; the encrypted connection was created
through the normal API.

The original Daytona file attempt timed out during delayed semantic
dispatch. Its precise stalled layer remains unresolved. Independent
ordinary delivery and the other19 cells passed before one instrumented
recheck passed8/8 with unchanged source,prompt,assertions and deadlines.
No causal latency repair is claimed.

After current-master reconciliation,129 connection tests,59 runner
tests,72 shared eval tests and88 recovery/workspace tests pass.
Migration generation/safety, unchanged profile identity and UI token
gates pass. Prior required CI was green. Fresh exact-head required CI
and E2E are green for all four updated heads. Each has a fresh
Greptile5/5 review and zero unresolved review threads. The [final
normal-package cloud
build](https://github.com/paperclipai/paperclip/actions/runs/39414239704)
is running. Recursive typecheck,full CI test shards,build and all8
browser shards pass. These checks cover the final source; no additional
local full-suite pass is claimed.

The [frozen image
build](https://github.com/paperclipai/paperclip/actions/runs/39334401638)
and [original normal package
build](https://github.com/paperclipai/paperclip/actions/runs/39334407471)
passed. The exact image is published and independently retrieved
anonymously. No separate full-image scan is claimed. All18 original
normal archives were scanned with zero selected credentials. Docker
builds run in the cloud. Provider USD remains unknown and
GitHub-attributed.

**Qualification is complete on the recorded frozen build. Normal
protected merge, automatic master canary publication and final
shipped-package local/Daytona canaries remain. No production deployment
is claimed.**

## Risks

Shared Runner behavior can affect active tasks. Exact profile admission
rejects stale runtime identities. The final campaign and installed
canaries remain release gates.

## Model Used

OpenAI Codex, based on GPT-6. The exact serving model ID and context
window are not exposed in this task. Used for code changes, review and
tool-assisted verification.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] 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-20 06:31:47 -05:00
DottaandPaperclip fc0d390d98 fix: enforce Cloud-enabled features on every managed stack (#16953)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Cloud sets managed feature values for each tenant stack.
> - Staging lets admins change experimental features.
> - The staging exception also let old tenant false values override
Cloud true values.
> - This could disable required features such as isolated workspaces.
> - This pull request keeps every Cloud-enabled feature on and rejects
attempts to disable it.
> - The same rule applies to staging, production, and managed stacks
without a hostname.

## Linked Issues or Issue Description

Refs: #16876

**What happened?**

The staging override added in #16876 treats managed true values as
editable defaults. A stored tenant false value can disable a feature
that Cloud enables. Settings writes also accept attempts to disable
Cloud-enabled features.

**Expected behavior**

If Cloud sets a feature to true, the tenant reads true and cannot turn
it off. This applies to every managed stack. Staging can still change
allowed experiments that Cloud has not enabled.

**Steps to reproduce**

1. Set a managed staging primary hostname and enable isolated workspaces
in `PAPERCLIP_MANAGED_CONFIG`.
2. Start with `enableIsolatedWorkspaces: false` in the tenant settings
row.
3. Read `/api/instance/settings/experimental`. Before this fix, staging
returns false.
4. Try to PATCH that flag to false. After this fix, the API returns 403
without saving, and reads return true with managed control metadata.

**Paperclip version or commit**

Reproduced against master at `cde944ed75648adfb569e86133adc8b118b55dd6`.

## What Changed

- Keep managed true values in the staging read overlay. They override
old tenant values and lock the existing UI controls.
- Reject attempts to set any Cloud-enabled feature to false before
writing settings.
- Cover every managed feature in service tests across staging,
production, and an absent hostname. Add real-service HTTP tests for
isolation on staging and production.
- Update operator documentation and the feature and access maps.

## Verification

- Confirmed the new service regression fails before the fix: staging
returns stored false, and writes can attempt to disable enabled flags.
- Passed all six focused settings suites: 168 tests. Passed the final
route and overlay suites after adding the HTTP regression: 109 tests.
- Passed existing experimental settings UI tests: 54 tests. These cover
the existing managed-control behavior.
- Passed `node scripts/check-maps.mjs` and `git diff --check`.
- Passed `pnpm -r typecheck` and `pnpm build`. The first typecheck used
an install that did not honor locked versions and hit an unrelated
`@pierre/diffs` API mismatch. Reinstalling from the lockfile resolved
it; no lockfile changes are included.
- Full CI passed on `f43136812a92ec838a24f0c423270e4fbd997c28`: 55
successful checks, one neutral review check, and two expected skips.
This includes typecheck, build, general and serialized tests, runner
checks, and E2E shards. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/39411907756).
- The duplicate local `pnpm test:run` was stopped after the complete CI
matrix passed. It is not counted as a completed local full-suite pass.
- Greptile reviewed `f43136812a92ec838a24f0c423270e4fbd997c28`: 5/5 with
no outstanding findings. The only finding on the first review was the
repository rule against new code comments; those comments were removed.

## Risks

- Staging users can no longer disable a feature that Cloud enables. This
is the intended behavior.
- Clients that send a stale full settings form containing false for a
Cloud-enabled feature receive 403 and must reload.
- No database migration is needed. Stored false values remain in the
database, but cannot override an active Cloud true value.
- Cloud-disabled staging experiments remain editable. Production
restrictions and self-hosted settings remain unchanged.

## Model Used

- OpenAI Codex, `gpt-6.1-sol`, with reasoning, repository tools, 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
- [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-20 06:14:52 -05:00
DottaandPaperclip cde944ed75 fix(workspaces): keep retained readers valid after cross-task wake coalescing (#16928)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Before a run starts, repository admission checks every retained
reader of the physical repository root and of overlapping roots.
> - Each retained reader records the run, task, agent and responsible
user that the server admitted.
> - A wake for another task can coalesce into a running run. The merge
replaces `contextSnapshot.issueId` and `taskId` with the other task.
> - The retained-reader check used that mutable context task before the
run's immutable task binding. The old reader then looked like a changed
identity.
> - When a later run admits an overlapping root, such as a shared
project checkout that contains earlier task worktrees, every admission
on that root fails. The root stays blocked and no operator action can
repair it.
> - This pull request accepts a retained reader when its task matches
the run's immutable binding or its current context task.
> - The benefit is that legitimate wake coalescing no longer blocks a
shared root, and missing or truly mismatched identities still fail
closed.

## Linked Issues or Issue Description

Refs #16717 and #16832. Those cover retained readers whose run, agent or
task was deleted. This pull request covers a different cause: every
identity still exists, but wake coalescing changed the run's context
task. #16832 keeps identity mismatches fail-closed, so it does not fix
this case. Both pull requests change the same condition in
`execution-workspace-root-readers.ts`. The pull request that merges
second must rebase.

**What happened?**
A scheduled routine run failed in setup with `Repository root retains a
reader whose identity is no longer available` (403). Every later run of
the routine failed in the same way, for eight hours in a row. Two
earlier runs of the same agent were the retained readers. Each run
started for its own task and recorded its reader. About 10 to 16 minutes
later, a monitor wake for a different task coalesced into the running
run with reason `issue_execution_same_name`.
`mergeCoalescedContextSnapshot` set `contextSnapshot.issueId` to the
other task. `heartbeat_runs.issue_id` stayed on the original task,
because the `heartbeat_runs_set_scope_kind` trigger makes the binding
immutable. The readers were on per-task worktree roots, so nothing
failed at first. Then the routine's tasks changed to the shared project
checkout. That root contains those worktrees, so admission loaded the
two readers, compared them with the changed context task, and threw.

**Expected behavior**
A retained reader stays valid while its run, agent, task and responsible
user still exist and still match what the server admitted. A context
change from wake coalescing must not make the reader unavailable. A
reader whose task matches neither the run's binding nor its context must
still be rejected.

**Steps to reproduce**
1. Admit run R for task A on a nested root, for example
`<checkout>/.paperclip/worktrees/a`.
2. Coalesce a wake for task B into R. `contextSnapshot.issueId` becomes
B. `heartbeat_runs.issue_id` stays A.
3. Admit or publish another task on the parent root `<checkout>`.
4. Observe the 403 `Repository root retains a reader whose identity is
no longer available`. Every later admission on that root fails in the
same way.

**Paperclip version or commit**
Reproduced on `master` at b44871098 with the new regression test.

## What Changed

- Add `runRetainsIssueIdentity(run, issueId)` in
`server/src/services/execution-workspace-root-readers.ts`. It accepts
the previous derived identity (`nativeIssueId ?? context issueId ??
context taskId ?? issueId`) or the immutable binding (`nativeIssueId ??
issueId`).
- Use the helper for the three retained-run identity checks:
`loadRepositoryRootReaders`, `requiresAnonymousRepositoryAcquisition`
and `assertRootProjectTrust`.
- Add a real PostgreSQL regression. A reader on a nested worktree root
is admitted for task A. The test builds the coalesced context with the
real `mergeCoalescedContextSnapshot`. Publication on the parent root
must succeed. A reader whose task matches neither the binding nor the
context must still fail.
- Move one existing row. The old "rejects" test changed only the context
task, which is now the legitimate coalescing case. The test now changes
the reader's recorded task to a different existing task, so the mismatch
path still fails closed.
- Update the retained-reader contract in `doc/DATABASE.md`.

## Verification

- Red before the fix: `pnpm exec vitest run --project
@paperclipai/server --maxWorkers=1 --fileParallelism=false
server/src/__tests__/repository-root-reader-queries.test.ts` fails 1 of
9 tests. The new test passes its first publication. It fails after the
coalesced context with `Repository root retains a reader whose identity
is no longer available` (403), which is the production error.
- Green after the fix: the same command passes 9 of 9 tests.
- One intermediate attempt failed and is kept here. My first test draft
changed `heartbeat_runs.issue_id`. The database trigger rejected it with
`run task binding is immutable`. That rejection confirms the binding
this fix relies on. The final test uses a separate run for the negative
case.
- Related suites: `task-workspace-repositories*.test.ts`,
`task-workspace-source-copy-privacy.test.ts`,
`project-workspace-root-provenance.test.ts`,
`workspace-authorization-query.test.ts`,
`execution-transaction-timing.test.ts`,
`execution-workspace-reopen.test.ts`, `file-resources.test.ts`,
`heartbeat-project-repositories.test.ts`,
`heartbeat-workspace-source-trust.test.ts` and
`heartbeat/workspace-preparation.test.ts`. All 13 files pass on the
fixed head. The first invocation passed 8 files. The other 5 files
failed to import `@paperclipai/plugin-sdk`, because its `dist` was not
built in this fresh checkout. That run reported 37 failed tests, all
from the import error, not from this change. After `pnpm --filter
@paperclipai/plugin-sdk... build`, the same 5 files passed 206 of 206
tests.
- Production evidence (read-only SQL on the affected instance): exactly
two readers in the company fail the current check. Both are on the
blocked root. For both, `heartbeat_runs.issue_id` equals the reader's
task and the context task is a different task after a coalesced
`issue_execution_same_name` wake. Both pass the new rule, so the blocked
root recovers after deployment without data repair.
- Not run: full `pnpm -r typecheck`, `pnpm test:run` and `pnpm build`.
The sandbox has 4 GB of memory. CI runs these checks.

## Risks

- The rule now also accepts a reader whose task equals the run's
immutable binding while the context points to another task. The binding
is the run's privacy binding. The database sets it at insert and does
not let it change, and it requires `native_issue_id` to agree with it.
The reader's own recorded task is still the authorization context.
- The rule keeps the previous context identity. A run that coalesced a
wake before it started and then coalesced another one later could still
produce an unavailable reader. I did not find that sequence in the
affected data. The cross-task coalesce targets a run that already holds
the other task's execution lock, and that happens after admission.
- No schema, migration or API change.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`) through Claude Code in a Paperclip
agent run, with tool use, code execution and read-only SQL diagnostics.
The context window and reasoning settings are managed by the runtime.

## Checklist

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

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 22:40:25 -05:00
b448710986 fix: derive startup warmth from per-layer reuse evidence (#16908)
## Thinking Path

> - Paperclip helps people manage AI agents and inspect their work.
> - Agent startup can reuse a lease, workspace, Runner, process, or
session.
> - A session ID can remain the same when other resources are new.
> - The old cold/warm label did not show these separate decisions.
> - This pull request records closed reuse receipts and derives labels
from them.
> - Reports now show partial reuse and missing evidence.

## Linked Issues or Issue Description

Refs #11685. That issue tracks a specific ACPX fingerprint repair. This
change records reuse evidence across startup resources. It does not
repeat that repair.

**What existing behavior does this improve?**

Startup labels in the operator trace and Product E2E reports.

**Current behavior**

A cached runtime or a continuous session can suggest a warm startup even
when workspace staging or provider launch work occurs.

**Proposed behavior**

Record each layer's reuse decision and a closed reason. Record observed
provider launch counts. Use `warm`, `cold`, `partial_reuse`, or
`unknown` from those receipts. Keep old runs unknown when they have no
receipts.

## What Changed

- Add local run-log receipts for the lease, workspace, Runner, provider
process, and provider session.
- Count physical ACPX launches, including respawns. Preserve the reason
for a new process.
- Reuse native workspace adoption and session lifecycle evidence. Keep
native and bridged remote provider-process reuse and launch counts
unknown where physical evidence is absent.
- Show the per-run summary in retained results and the dashboard. Keep
missing legacy values explicit.
- Set the legacy trace boolean only for fully evidenced cold or warm
startup. Keep the operator OTLP gate. Add no first-party Telemetry.
- Test full reuse, workspace invalidation, two direct provider launches
with session continuity, and report generation.
- Start the final diagnostic write without waiting for persistence. Keep
lease cleanup independent of a stalled event sink.
- Keep remote provider evidence unknown after runtime setup fails or the
host relay starts twice.
- Align a stale Pi support-test expectation with current master profile
28 and its suite fingerprint. Keep the qualification rules unchanged.

## Verification

- Passed: all 319 runtime, startup-timing, reuse-summary, and native
workspace-history tests. Disposable local Git tests used the native Git
binary.
- Passed on the current commit: all 2,768 Runner E2E support tests
across 128 files. This includes report and history tests for generated
HTML and normalized JSON.
- Passed: `pnpm --filter @paperclipai/adapter-utils typecheck`.
- Passed on `df60f8dbdbfcb6d80c84cd3bf563f8d58b2f9f03`: all PR CI gates,
including repository typecheck and build, all test shards, and browser
tests. Both automated reviews are 5/5. GitHub reports 55 successful
checks, one neutral review, and two skipped Storybook checks.
- The first server shard run failed because an unchanged
workspace-runtime fixture did not accept health connections within 10
seconds. Its isolated local test and the single failed-jobs rerun both
pass. This establishes recovery; the cause of the first timeout remains
unknown.
- Passed in the hosted source run on this exact commit: recursive
typecheck, token gates, the large Runner E2E typecheck, Runner E2E unit
tests, and build. The retained `source.txt` matches this PR head.
- The extra unsharded `pnpm test:run` reached its 60-minute limit (exit
124). It has no complete verdict. The broad workflow therefore reports
failure. No assertion-failure marker appears in the retained partial
log. Full-suite acceptance uses the passing canonical PR CI partitions.
A read-only inventory check found no gaps across 1,023 general server
files, 161 serialized suites, and 20 workspace projects. The separate
chat/native Runner lanes cover the excluded server files. No tests or
timeouts were weakened. The local environment has 4 GiB of memory. Use
CI for the large Runner E2E typecheck.
- The initial report tests failed because the harness could not resolve
package imports from the repository root. Relative source imports fixed
that failure.
- The first broad local run had timeouts from the environment Git
bridge. Native Git resolves the ancestry timeout and all runtime tests
pass. The added report fixture lacked its required screenshot; the
corrected report tests pass. A stale master assertion expected Pi
profile 27, while the generated profile is 28. Updated its expectation
and exact suite fingerprint; all 78 targeted support tests pass. The
clean full support run passes all 2,768 tests.
- The three review regression cases failed before repair. They showed
remote counts of zero and two, and a completed run that waited for the
final diagnostic sink. They now pass. The stalled-sink case keeps
persistence pending while the run returns, both bridge stops run once,
and the staging lock map becomes empty.
- Hosted evidence for this commit: [source
verification](https://github.com/paperclipai/paperclip/actions/runs/39335475416),
[retained command logs and status
table](https://github.com/paperclipai/paperclip/actions/runs/39335475416/artifacts/12228829282).
All listed commands exited zero except the incomplete unsharded test
command described above.
- The physical-launch test drives the executor's spawn callback twice.
The native workspace test uses real Git repositories and verifies reuse
and invalidation. These are deterministic tests, not a paid provider
qualification campaign.

## Risks

- Consumers must handle `partial_reuse` and `unknown`. Partial evidence
no longer produces a legacy cold/warm boolean.
- Native and remote bridged provider process evidence is still
unavailable on some paths. The report shows unknown values for those
paths.
- Receipt emission is best effort. Missing receipts reduce confidence in
a label and must not change execution or settlement.
- No schema migration, first-party Telemetry event, or endpoint default
changes are included.

## Model Used

OpenAI Codex, based on GPT-6, used reasoning, repository tools, and code
execution. The exact provider model ID and context window are not
exposed to this session. The existing implementation checkpoint was
preserved from the earlier agent run.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-10-19 21:52:57 -05:00
DottaandPaperclip bc091f0a21 fix(recovery): recover retained workspaces before saved messages (#16906)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A stopped run can leave useful files in its original sandbox.
> - The server keeps that sandbox when it cannot confirm file copyback.
> - The task can then save new user input but offers no safe way to
recover the files.
> - A retry of the old agent turn can repeat work that already finished.
> - This pull request recovers files through the existing workspace
owner and delivers only saved human input.
> - The user can recover a task without certifying infrastructure facts
or losing completed work.

## Linked Issues or Issue Description

Refs #16883 and #16835 for publication receipts and verified process
termination.
Related: #16478 clears stale holds after copyback already succeeded.
This change performs the missing export and records its proof. #16901
manages the main GitHub response comment and does not perform workspace
repair.

**What happened?**

A failed run retained its workspace. A later user message stayed saved
behind a file-repair hold. The task asked the user to verify process
termination and file recovery but offered no repair control. Sending a
message could show an optimistic Working state and move the task to Todo
before admission succeeded.

**Expected behavior**

The harness should recover the original files when it can prove
ownership and termination. It should preserve newer edits and completed
operations. Only waiting user input may start another turn. Missing
evidence must keep the source held with a specific explanation.

**Steps to reproduce**

1. Interrupt a sandbox run before workspace finalization succeeds.
2. Retain its exact allocation and save a user follow-up.
3. Observe the file-repair hold and missing end-user repair path.

## What Changed

- Add source-bound background recovery for native and legacy runs. An
accepted native result is not required.
- Share the physical copyback lock and durable owner. Resume only the
exact stopped allocation, export files, verify persistence and obtain a
fresh stop receipt.
- Persist retry limits and idempotent requests on the existing recovery
record. Limit each server to two background exports. Add an indexed
candidate scan and a separate cleanup obligation.
- Add a task-editor recovery endpoint. Deny agents and viewers. Reject
caller-supplied stop or repair claims.
- Deliver waiting human input once through ordinary admission. Preserve
pause, approval, budget and assignment gates. Require historical
conversational-adapter evidence for legacy-to-Runner continuation.
- Include exact GitHub publication receipts in continuation context.
Preserve unknown effects and the original failed run.
- Show observed recovery progress, a transient-failure retry action and
specific service blockers. Keep saved messages visible. Suppress false
startup feedback and implicit Todo promotion behind a file hold. Hide
unavailable workspace links.
- Update execution semantics, capability maps and production-component
stories.

## Verification

- Red: the original read model failed the new recovery-progress
assertion; the other 23 checks in that file passed.
- Passed: recovery regressions with 28 cases with real PostgreSQL,
files, tar and Git operations. Lifecycle provider calls are controlled
test boundaries. Coverage includes native/legacy export, concurrent
owners, rollback after export, interrupted archive export with a new
database connection, lost replies, historical discovery, durable retry
limits, separate cleanup and saved-input delivery. The actual candidate
query uses its partial index with 3,000 unrelated history rows. A first
automatic repair can bind verified old-controller stop proof without an
accepted native result. Review also reproduced and fixed export-only
continuation and cleanup lost after a committed repair. Cleanup remains
discoverable without waiting input and after task reconciliation.
- Passed: two GitHub integration cases verify that continuation context
carries the existing publication receipt and does not write another
response. Company and task boundaries are checked.
- Passed: 293 continuation, workspace-sync, platform-receipt and OpenAPI
checks. After file repair, actual dispatch retains pause, cancellation,
approval, real budget-policy and assignment gates.
- Passed: 174 route checks, including editor admission, agent/viewer
denial and rejection of fabricated repair claims.
- Passed: 351 task detail, workspace properties and comment-reopen
checks after updating the new read boundaries and asynchronous
workspace-link expectations. Two new route cases keep held tasks Blocked
when a comment is saved.
- Passed: 265 task-thread and recovery-notice checks. The broader
continuation suite also passed; its new legacy migration case first
exposed a gap that the focused recovery suite now covers.
- Passed after rebase: `pnpm -r typecheck` and `pnpm build`. The later
master merge adds an unrelated permission migration; recovery migration
generation and safety checks passed after the merge.
- Passed: token gates, module boundaries, map structure and migration
checks. The recovery index is migration 0360 after current master.
- Browser: inspected the production recovery component and its
retry-to-queued transition with fixture data. The first dev dependency
load failed; a reload after optimization resolved it. This is UI
evidence, not a live provider recovery claim.
- Every test shard passed on final commit `bbbc09efb4`. The older local
`pnpm test:run` was stopped after the complete CI test matrix passed.
Local full typecheck and production build passed. The first CI build
compiled and booted, then lost its runner during the clean public
npm-install check. An isolated retry passed the build, production boot
and clean public npm-install verification.
- Greptile reviewed final commit `bbbc09efb4` at 5/5. All review threads
are resolved.
- The change is not deployed. Hosted recovery remains unverified until
the served revision includes this change.

## Risks

- Recovery crosses process, provider and persistence boundaries. Missing
or mismatched ownership, stop, descriptor or file evidence keeps the
hold. It never selects a replacement allocation or silently starts over.
- File recovery does not certify external action outcomes or authorize
replay. New input still uses normal execution admission.
- Historical sources without sufficient durable evidence can remain
blocked. Destructive reconstruction stays separate.
- The index migration is idempotent. It changes no task data. Snapshot
pruning follows repository policy.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, with code execution and browser tools.
`gpt-6-astra` assisted earlier investigation. 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-19 21:51:46 -05:00
DottaandPaperclip 3b8324a233 fix(github): keep one main PR review comment and reconcile stopped work (#16901)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub connections send review requests to an assigned agent.
> - A PR needs one main comment that shows its current review state.
> - The response ledger used one comment per incoming request. Pushes
and follow-up messages created more placeholders.
> - Thread subscriptions also accepted requests addressed to external
bots. Recovery could leave an acknowledged request without a final
notice.
> - This pull request shares the main PR comment, filters other
recipients, and reconciles stopped work.

## Linked Issues or Issue Description

Related: #16874 showed the repeated placeholders. #15416 introduced the
per-request response path. The prior summary path used one PR-level
marker.

**What happened?**

Repeated pushes created new main PR comments. A subscribed `@greptile
review` message also woke the Paperclip bot. If execution stopped before
staging a milestone, its comment could keep claiming that work was
active.

**Expected behavior**

One bot keeps one main comment per PR. Progress and review results
update it. A message addressed to another recipient does not wake the
bot unless it also explicitly mentions this bot. Stopped work gets an
accurate notice.

**Steps to reproduce**

1. Accept two review requests in one PR conversation.
2. Add `@greptile review` to that subscribed conversation.
3. Fail the assigned run before it stages a milestone. Run channel
maintenance.

## What Changed

- Add a durable main PR response target. Keep per-request receipts and
the existing publication lease.
- Recover the target from App-owned provider markers. Adopt older
placeholders and point verified duplicates to the current review.
- Use a queued notice before a PR run starts. Preserve version ordering
and final responses.
- Filter leading mentions addressed to another recipient. Explicit
mentions of this bot take precedence. Incidental mentions keep normal
thread behavior.
- Reconcile acknowledged requests after terminal execution. Show paused
state for saved requests on a blocked task. Preserve newer work and
confirmed or uncertain tool delivery.
- Keep a request open when its stale acknowledgement is suppressed.
Close placeholders after replies published elsewhere. Retire old
coalesced placeholders before replacing their receipts. Resolve native
request identity when legacy wake fields are absent.
- Update guidance, connection documentation, and feature/access maps.

## Verification

- Red: all three behavioral regressions failed on the original code. A
second review created a second comment; an external-bot request was
processed; stopped execution retained its working placeholder.
- Green: the same three cases passed after the fixes.
- Review regressions also failed before their repairs: a delayed
acknowledgement closed a new request; normal and stored formal-review
receipts left a live placeholder; coalesced completion lost a duplicate
receipt; native terminal work without legacy wake fields stayed queued.
All 13 combined regression and safety cases passed after repair.
- The same legacy receipt-loss bug was also reproduced in the
superseded-acknowledgement branch. Its four affected cases passed after
adding retirement before that receipt replacement.
- A further review regression reproduced paused requests rejecting
resumed progress and skipping stopped-run cleanup. Four cases failed
before repair; all eight resume and neighboring safety cases passed
afterward. Both paused-notice branches keep the request open.
- Repeated paused maintenance reproduced two needless GitHub edits. The
writer now skips an identical complete comment body. Nine affected cases
passed, covering repeated maintenance, resumption, stopped work, final
assessment preservation, and main-comment reuse.
- Safety cases cover lost receipts, legacy adoption, newer progress,
published assessments, provider-verified mention aliases, and old
replies that must not complete new requests.
- `pnpm -r typecheck`, `pnpm build`, map validation, and module
boundaries passed. The server TypeScript check passed after the final
repair. The broader local GitHub workflow and policy run passed 188
tests. Full CI passed on the final commit
(`554979d79285b68bcbf90cd639e3d2d053f4ea4b`), including all three chat
shards, server/workspace/Runner suites, typecheck, build, and E2E gates.
Greptile is 5/5 with no open review findings. One serialized job
received a runner shutdown signal mid-test; its single retry passed.
- Preserved failure evidence: the first CI run exposed an overbroad
recipient filter and an old queued-text assertion. The next commit
passed all three CI chat shards. Greptile then found the receipt
transitions covered by the new regressions above. Local full-suite runs
were stopped when those defects required source changes; no clean full
local pass is claimed.
- Tests use real PostgreSQL and controlled provider responses. They do
not establish a live GitHub App rollout. The original instance needs the
fixed server before its comments change.

## Risks

- Leading mentions now select a recipient even when that account has no
Paperclip connection. A leading human mention also selects that person.
Mid-message incidental mentions retain normal subscription behavior.
- Existing comment adoption edits only comments proven by this
endpoint's request ledger or prior summary marker and App identity.
Deleted and replaced comments remain protected.
- Failure cleanup uses current authority and does not replace newer
progress or unresolved provider writes. It does not restart failed
execution.
- No schema migration is required.

## Model Used

OpenAI Codex, GPT-6. The exact serving model ID and context-window size
are not exposed in this session. The model used reasoning, tools, code
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 (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-19 21:51:20 -05:00
DottaandPaperclip 16689de291 fix: add one-click retry for restricted workspace setup (#16909)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tasks need a clear way to resume after a setup failure.
> - A shared repository can contain another task that the assigned agent
cannot read.
> - Paperclip correctly stops before the agent starts, but the user must
then understand workspace settings to recover.
> - This pull request gives that failure a single Retry button and
selects a clean copy of the configured repository through normal
admission.
> - The task keeps its assigned agent and execution settings, while
access checks and existing work remain protected.

## Linked Issues or Issue Description

Related: #16895 classifies the restricted source failure. This change
adds the user recovery action. #16906 handles retained files after
execution; this change handles a setup failure before execution starts.

**What existing behavior does this improve?**

Recovery of a task whose shared repository includes a task workspace the
assigned agent cannot read.

**Current behavior**

The task stops before provider work and asks the user to understand
workspace choices or access grants.

**Proposed behavior**

Show Retry above the task message box, independent of loaded
conversation history. One click requests one attempt using a clean
checkout of the configured remote. Show Retrying while the request is
pending. Show an error only if the request fails.

**Reason and benefit**

The user can resume work without understanding repository isolation or
changing access to another task.

**Breaking changes**

None. The recovery source value is server-owned. The public workspace
selection request does not accept it. No migration is required.

## What Changed

- Add one Retry control above the composer in both task conversation
views. It stays available when an older notice is outside the loaded
comment pages.
- Bind recovery to the latest failed run, current assignee, and recorded
proof that provider work did not start.
- Use the existing atomic recovery route and pending workspace
selection. Normal admission clears the old session and creates the
isolated checkout.
- Choose a fresh task-owned branch for recovery, including fixed project
branches, existing task branches, and adapter branch overrides. Preserve
the model, environment, setup commands, pending user workspace choices,
previous files, and all execution gates.
- Update execution documentation and both workspace maps.

## Verification

- Passed all 461 tests in the eight affected database, Git, HTTP,
workspace binding, and conversation suites after the review fixes. An
additional 292 tests passed after the final compatibility fixes,
including IssueDetail and recovery action routing.
- Concurrent HTTP retries produce one wakeup. Paused projects and runs
that started provider work reject recovery without changing the
workspace.
- Real Git tests exclude private files, private commits, and unpublished
original files from the clean checkout, preserve the original, and
exercise reuse, cleanup, and reopen.
- Verified in a running local app: a task failed twice, displayed only
Retry, and reached Done after one click. A second browser test put the
failure notice behind 501 newer comments and used a fixed project
branch. Retry stayed visible and the task reached Done. The
credential-free process worker used the selected checkout and wrote its
result there. This does not claim a live model-provider run.
- The first manual fixture lacked a responsible-user membership and
failed after successful workspace recovery. Corrected the fixture,
retained that failure evidence, and verified the full flow with ordinary
authorization.
- Full typecheck, build, token gates, and map checks passed. The full
local suite was stopped after review changed its source during
execution; current-head CI provides the complete suite result.
- An earlier unrelated peer-comment read test hit a socket hangup. The
next complete affected-suite run passed; the first failure is retained
in local evidence.
- Current-head CI hit an unchanged runner credential-concurrency test
failure. That lane passed on the preceding commit, and all 42 credential
tests passed locally. The original failed job is retained; the one-time
rerun passed. All latest-head CI checks are green (55 success, 2
skipped, 1 neutral), and Greptile is 5/5 with both review threads
resolved.

## Risks

- A remote repository outage can still prevent the next attempt. Retry
does not grant access or copy unpublished files from the old checkout.
- Recovery accepts only the latest recorded pre-provider failure and
preserves normal execution gates. This limits duplicate work and stale
recovery requests.
- No database migration, dependency, or lockfile change.
- The first review found fixed-branch retry loops and dependence on
paginated notice history. Both had failing regressions before the fixes
and now pass targeted tests and the combined browser journey.
- Full CI then caught assumptions about missing run evidence and
unrelated recovery actions. The final changes tolerate absent evidence
and scope the new lookup to board-owned actions with valid run IDs. The
previously failing suites now pass locally.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution, and browser verification. The exact serving model ID and
context window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 21:49:44 -05:00
DottaandPaperclip d9bcf4dfe8 fix(auth): let Cloud stack admins manage experimental settings (#16907)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People use experimental settings to opt into product features.
> - Cloud stack Admins can manage their company, but cannot save an
experiment.
> - Requiring an Owner role adds unrelated privileges to this workflow.
> - This pull request gives trusted Cloud stack Admins permission to
update experiments.
> - Other instance administration and platform settings keep their
existing checks.

## Linked Issues or Issue Description

**What happened?**

A person with the Cloud stack Admin role receives “Instance admin access
required” when they enable an experimental setting, such as Fast
responses.

**Expected behavior**

Cloud stack Admins can save editable experimental settings. This
permission does not grant general instance-admin authority. Members,
Support users, and agents cannot change experiments. Cloud-managed and
operator-hidden settings remain protected.

**Steps to reproduce**

1. Sign into a Cloud staging workspace as a stack Admin.
2. Open Settings → Experimental.
3. Enable Experimental fast responses.
4. Observe the permission error instead of a saved setting.

**Additional context**

Related: #10343 introduced computed Owner elevation. #15748 added Fast
responses and the company Connections settings page. The roadmap and
existing PRs were checked. This is a small authorization fix for the
existing settings path.

## What Changed

- Derive experiment-management authority from the current trusted Cloud
stack Admin role on each request.
- Apply that authority only to the experimental settings PATCH route.
Keep general settings, environment defaults, and task drain restricted
to instance admins.
- Preserve existing hidden-setting checks, managed feature restrictions,
and activity records.
- Add role and role-downgrade regressions, allowed and denied route
cases, staging coverage, and updated OpenAPI and access documentation.

## Verification

- Before the fix, the Admin fast-response request returned 403 and the
new role assertions failed. The first sandboxed HTTP run could not bind
local sockets; the regression run outside that sandbox reached the
expected authorization failures.
- Focused Cloud actor, settings route, managed-overlay, and health
tests: 149 passed.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- `pnpm -r typecheck` and `pnpm build` pass.
- Greptile reviewed commit `7c33b90066121f03183579d2fae2650755e025e4` at
5/5. Its one style finding is fixed and resolved.
- The full local `pnpm test:run` did not pass. It reported two early
collection failures before workspace build outputs were ready and a
15-second timeout in the unchanged AgentMail recovery test. The run was
stopped after those failures while the full CI suite continued. No full
local-suite pass is claimed.
- The first current-head CI attempt failed the unchanged Runner test
“preserves a real listening process and its marker when a health RPC
times out” with `runner_remote_process_identity_unavailable` /
`process_identity_changed`. The test passes in a local isolated run.
This recovery does not establish the CI failure's cause. [Failed
job](https://github.com/paperclipai/paperclip/actions/runs/39332989655/job/118336142261).
The failed shard passed on its single rerun. The failure cause remains
unconfirmed. All CI checks on commit
`7c33b90066121f03183579d2fae2650755e025e4` are now green. [Final CI
run](https://github.com/paperclipai/paperclip/actions/runs/39332989655).
- No deployed staging behavior is claimed. Manual acceptance after
deployment: as a stack Admin, enable Fast responses, reload, and confirm
Connections appears. Confirm Members and Support users still cannot save
experiments.

## Risks

- This intentionally extends experimental settings write access to Cloud
stack Admins. It does not persist an instance-admin role or expand other
instance controls.
- Production retains its existing managed feature policy. Staging
retains its editable experiment allowlist and protected execution and
owner-elevation settings.
- No database migration or UI change is required.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution, and browser inspection. The runtime does not expose an exact
model snapshot or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [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-19 21:48:00 -05:00
DottaandPaperclip e5927e1db9 fix: give commentary its own default read permission (#16903)
## Thinking Path

> - Paperclip lets people manage AI agents and inspect their work.
> - Commentary collects agent suggestions and complaints for company
members.
> - Commentary used the permission for detailed agent-action audits.
> - Owners, admins and viewers could therefore receive a permission
error when they opened Commentary.
> - This pull request gives commentary its own permission and enables it
for all human company roles.
> - Members can read feedback while task privacy and detailed audit
access keep their own checks.

## Linked Issues or Issue Description

Refs #16884, which added the Commentary browser. A search found no open
PR for this permission fix.

**What happened?**

Commentary returned `Missing permission: audit:view_agent_actions` for
company members without the detailed audit grant. Default owners, admins
and viewers did not receive that grant.

**Expected behavior**

All human company roles can read commentary by default. A separate
`commentary:view` permission controls this access. Private source tasks
remain private. Commentary access does not grant detailed agent-action
audits or CSV exports.

**Steps to reproduce**

1. Sign in as an active company owner, admin or viewer without
`audit:view_agent_actions`.
2. Open Audit, then Commentary.
3. Observe the permission error before this change.

**Paperclip version or commit**

Base commit: `7c58ea07b2`.

**Deployment mode**

Authenticated server or Cloud tenant.

## What Changed

- Add `commentary:view` to the shared permission contract and all human
role defaults.
- Require that permission for commentary list and detail reads.
- Add an idempotent upgrade migration for existing active human members.
Preserve existing grants and scopes.
- Add the commentary default when approving saved human invitation
grants that omit it, including pre-upgrade invitations. Preserve
explicit commentary scopes.
- Add regression coverage for role defaults, permission removal, audit
separation, private tasks and migration replay.
- Update the API description, specifications, database notes and access
maps.

## Verification

- Passed 68 tests across commentary reads, role grants, old-invitation
HTTP acceptance, migration replay, agent audit routes, access services
and migration snapshot drift under the repository's locked dependencies.
- Confirmed the new role and read tests failed before the
implementation.
- `node scripts/check-maps.mjs` passed.
- Migration numbering and safety checks passed during the build.
- Full `pnpm -r typecheck` and `pnpm build` passed locally after the
invitation fix.
- The final-commit CI matrix passed, including all test shards,
typecheck, build, public-install checks and canary smoke. The redundant
local `pnpm test:run` was stopped after the full CI matrix completed;
the 68 focused local regressions passed separately.
- The first install bypassed the stale lockfile and selected a newer
diff-viewer API. The initial typecheck and build failed in that
unrelated plugin. Installing the locked versions cleared both failures;
the tracked lockfile is unchanged.
- The first locked-dependency regression run hit the 15-second limit
while importing the audit route graph in its first test. Moving that
import into suite setup fixed the timeout; all 58 regressions then
passed.
- Greptile found that pre-upgrade invitations retain old grant lists.
New helper and HTTP regressions reproduced this gap before the fix, then
passed after approval added the missing commentary default.
- Greptile reviewed the final commit at 5/5 with no remaining actionable
findings. Its earlier thread is resolved.
- No UI code changed. The permission tests use real disposable
PostgreSQL databases and HTTP routes.

## Risks

- The upgrade deliberately enables commentary for every existing active
human company member, including viewers. Existing commentary grants
retain their saved scopes.
- Source-task privacy still filters previews, counts, searches and full
messages. Agent-authenticated browsing remains denied.
- Agent-action audit grants, detailed filters and CSV export permissions
keep their current behavior.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository editing and
command execution. The exact runtime 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-19 16:58:17 -05:00
DottaandPaperclip 4970d5ed3d fix(skills): unblock agent attachment and preserve Latest selections (#16899)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators attach company skills to agents from the skill library.
> - Attachment first reads the agent's skill snapshot to preserve other
assignments.
> - That read materialized and validated repository files for the entire
library, even in read-only mode.
> - The response also treated resolved runtime versions as stored pins.
Saving could then fail with beta pins disabled.
> - This pull request makes version-cache inspection lightweight and
returns the stored assignment choices.
> - The benefit is a responsive attachment flow that preserves Latest
and explicit pins.

## Linked Issues or Issue Description

**What happened?**

Adding a repository skill to an agent could stall before the save
request. The prerequisite snapshot read projected or checked every file
in every installed repository skill. Once it returned, an existing
Latest assignment could become a version pin in the save payload. The
server then rejected that save when beta skill pins were disabled.

**Expected behavior**

Reading assignments must not prepare all repository snapshots for
execution. Adding a skill must preserve the other assignments and their
Latest or pinned choices.

**Steps to reproduce**

1. Install repository-backed skills with stored immutable versions and
cold disk caches.
2. Assign one repository skill to a Claude agent with Latest selected.
Leave beta skill pins disabled.
3. Open another skill, select Add to agent, choose the same agent, and
save.
4. Observe the expensive prerequisite read and the beta-pin rejection
after that read completes.

**Paperclip version or commit**

Reproduced from master at `ac9459bae3329395f10bc81c638a374eef152baa`.

**Deployment mode**

Observed in hosted staging. Reproduced with a disposable local instance,
embedded PostgreSQL, and the Claude local adapter on macOS arm64 with
Node 26.4.0.

Related: https://github.com/paperclipai/paperclip/pull/9995 adds a
separate read-only assignment endpoint for peer-agent access. This fix
keeps the existing configuration-gated snapshot and its permissions.

## What Changed

- Respect read-only listing for current and pinned version caches. Check
directory and entrypoint safety without projecting repository contents,
reading all support files, or updating cache access records.
- Keep complete snapshot restoration and byte validation at run
preparation. Missing caches are restored from stored data. Corrupted
files are repaired there.
- Return stored assignment version choices in both list and sync
responses. Keep runtime version details in the snapshot entries.
- Add database-backed regressions for cold and warm reads, pinned
versions, execution repair, and unsafe entrypoints. Add HTTP regressions
for save round trips and explicit pins.
- Update developer documentation and verification recipes.

## Verification

- Red: both latest and pinned read-only cache regressions failed on the
original code. The original code created caches during listing.
- Red: the HTTP save-roundtrip regression returned 400 with the beta-pin
error. The explicit-pin regression also failed.
- Green: the updated API and cache suites passed all 145 tests. The
three related company-skill service suites also passed.
- Real browser: attached a repository skill to a paused test agent with
another repository skill already set to Latest and beta pins disabled.
The success toast appeared. The skill's Agents tab retained the
assignment after reload. API reads confirmed both assignments remained
unpinned and no repository version caches were created.
- Local synthetic fixture: six skills share a 606-file repository
snapshot. A cold HTTP skill-list request completed in 241 ms. This is
local evidence, not a staging latency measurement.
- Real service comparison on that fixture: the baseline cold list wrote
3,648 version/cache files. A warm baseline list read 3,642 version files
and wrote six access records (457 ms). The fixed warm list read and
wrote zero version/cache files (61 ms). Both services returned the same
16 library entries.
- `pnpm -r typecheck` passed. The final API edit also passed the server
typecheck.
- `pnpm build` passed.
- `node scripts/check-maps.mjs` and `git diff --check` passed.
- The broad `pnpm test:run` invocation reported six failures in the
untouched `tool-gateway-service.test.ts` suite. An isolated rerun passed
all 59 tests. The broad run was stopped after recording those failures,
so it is not a green full-local result. The PR CI matrix separately
passed those suites. Greptile completed on the current commit with 5/5,
zero comments, and no open threads.
- One CI shard was interrupted by runner shutdown, with no failed
assertion in its log. A single failed-job retry passed on the same
commit. The aggregate CI gate passed. All current-head PR checks are
complete with no failing or pending checks.
- This PR does not claim that the fix has been deployed to staging.

## Risks

- Settings reads check cache locations and entrypoints. They defer full
support-file validation to execution. Regression tests verify that
execution still repairs corrupt bytes and restores missing versions.
- The response now distinguishes stored pins from resolved runtime
versions. Explicit historical pins remain intact. Company,
configuration, connector, and beta-pin authorization gates keep their
existing behavior.
- No schema migration or dependency change.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code execution, and
browser tools. The exact runtime build ID and context-window size are
not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 16:33:02 -05:00
DottaandPaperclip 7c58ea07b2 fix(issues): guard prepared task promotion by status version (#16893)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Integrations can prepare a backlog task before its assigned agent
starts.
> - A person can change its status or assignment during preparation.
> - An unconditional promotion can replace that newer decision.
> - Safe promotion needs a saved revision that includes every assignment
path.
> - This pull request checks that revision under the task row lock and
derives policy cleanup from the locked row.
> - The benefit is safe initialization recovery with the existing
company, task, and run authority.

## Linked Issues or Issue Description

Prerequisite #16896 has merged. This PR now targets master and contains
only the conditional promotion API. The prerequisite fixed the confirmed
baseline first-upload browser regression.

**What happened?**

A client that saves a task's initial documents and then sends an
unconditional status update can override a concurrent status or
assignment decision. The update validator previously dropped an expected
version, so clients could not make this promotion conditional. Some
direct assignment and release paths also did not advance the revision.

**Expected behavior**

A prepared task moves from backlog to todo only if its original status
and assignment revision still matches. A stale request returns 409
before a task mutation, audit publication, or wake. Policy cleanup
preserves unrelated saved settings.

**Steps to reproduce**

1. Create a backlog task and save its statusVersion before preparing it.
2. Release its assignment, or change an assignee and then restore that
assignee.
3. Send `{ "status": "todo", "expectedStatusVersion": <original
revision> }` to its PATCH endpoint.
4. The stale promotion must return 409. A matching revision on an
unchanged backlog task must succeed.

Duplicate and related PR searches found no existing prepared-task
promotion fix.

## What Changed

- Accept an optional nonnegative expectedStatusVersion for exactly a
status-only backlog-to-todo promotion. Reject extra public fields before
parsing can discard them.
- Check the current revision and backlog state under the issue row lock.
Reject stale requests before checkout adoption or execution-control
effects.
- Add SQL migration 0358 to advance the revision for both assignee
fields at the database boundary. Release, administrative release, direct
writes, and assignment round trips now invalidate an old version.
- Derive guarded policy cleanup from the locked row. Preserve review
limits and protected authorization when removing a monitor. Reject
derived ownership changes or review decisions.
- Add schema, real HTTP/PostgreSQL, concurrency, migration replay, and
policy regression coverage. Update the response type, OpenAPI, developer
docs, and access map.

## Verification

- Red before the initial fix: stale requests returned 200 instead of
409, validation removed the expected version, and a stale active task
could adopt a checkout.
- Review found two further defects. Four new release/direct-assignment
tests showed unchanged revisions. The real HTTP/service test returned
422 for a valid two-field promotion after monitor cleanup. Helper tests
also proved that cleanup lost valid review limits and protected
authorization. All now pass after focused repairs.
- Green: 124 route and policy tests, including 7 real Express/PostgreSQL
cases, 37 existing route tests, and 80 policy/helper tests. The real
row-lock race preserves a policy edit committed while promotion waits.
- Green: all 23 database client tests, plus 9 focused assignment and
replay checks. Historical migration 0227 receipt recovery cannot remove
the new assignment trigger. Reapplying migration 0358 leaves existing
rows unchanged and installs one trigger. Combined status/assignment
writes increment once; unchanged assignees do not increment.
- Earlier verification passed all 218 schema/route/service cases and the
generated OpenAPI capability test. Rebased focused regressions passed
all 27 selected cases. Final server TypeScript passed after all repairs;
shared TypeScript passed. Migration safety/numbering, five-snapshot
retention, map validation, and diff checks pass.
- The baseline browser attachment case failed twice on the earlier head.
Separate #16896 proved the lost-composer cause, passed 335 component
tests and the real first-upload journey, and has green CI with a 5/5
review. No assertion or timeout was weakened.
- Some early local checks were blocked by missing or stale sibling
dependency artifacts. This worktree now has its own frozen offline
install and standard SDK prerequisites. The failures and successful
reruns remain in the task evidence.
- Before rebasing, head `3304bb00de6ad6a248b5e046c008072ad20ac8f5`
passed all CI (55 successful checks and one neutral), Greptile 5/5, and
a secondary source review at 5/5 with no unresolved findings. The
secondary reviewer did not execute project tests, inspect CI, or
exercise a live agent journey. Earlier incomplete and must-fix
assessments remain visible; both established findings are repaired
above.
- After #16896 merged, all five CAS commits were rebased onto master
`87d9386ae637c652d1fed09d2046be1bcaeb413b`. Migration 0358 was
regenerated because master added another 0357. Range comparison shows no
other change to the CAS patches; inherited UI commits are absent. The
original head is preserved locally.
- Rebased head `1c0264e51a280b1dbf597725a7e42e72d4be1b1b` passes all 124
route/policy tests, 9 selected assignment/promotion tests, and all 24
database client/snapshot-drift tests. Database build, migration checks,
generated snapshot linkage, five-snapshot retention (0354–0358), maps,
and diff checks pass. Fresh-head CI and review are pending. No
deployment or live agent journey was performed for this API.

## Risks

- The guard supports prepared backlog promotion only. Other statuses or
mixed public mutation fields return 422. A stale revision or non-backlog
row returns 409.
- Preserve the original version from a server that already advertises
this guard before initialization. Older versions did not track every
assignment path. Reconcile older or uncertain initialization instead of
fetching a new revision and blindly retrying.
- Migration 0358 is SQL-only and idempotent. It adds no table, column,
or task backfill. Its separate trigger survives historical
status-migration replay.
- Existing authorization and unguarded updates remain in place. Guarded
promotion does not provide a general lifecycle or review-stage control
API.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model ID and context
window are not exposed by this session. Used tool calls, code execution,
and test-first regression verification.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work.
> - One-shot task monitors request future work through the normal
heartbeat queue.
> - Queue admission can hold execution until recovery or ownership is
reconciled.
> - The scheduler retained those monitor schedules but recorded no
monitor diagnostic.
> - Agents could repeatedly reschedule the same blocked check without
seeing why it did not run.
> - This pull request records safe deferral and failure activity while
retaining all execution gates.
> - Agents and operators can inspect the actual blocker and use its
existing recovery path.

## Linked Issues or Issue Description

Related: #15556 handles transient monitor client errors. #14590 handles
parked monitor wakes. This change records the diagnosis when queue
admission defers or fails; it does not change their admission or monitor
consumption policies.

**What happened?**

A due monitor on a task with an unresolved execution-recovery hold was
claimed, passed to queue admission, and released without monitor
activity. The saved monitor continued to look scheduled. Unexpected
dispatch errors had the same audit gap. Repeated rearming could not
clear the recovery hold.

**Expected behavior**

Keep the monitor and the recovery hold. Record the reason that prevented
its wake. Do not execute uncertain work or consume an attempt. Limit
repeated identical diagnostics. If audit storage fails, release the
claim so a later tick can retry.

**Steps to reproduce**

1. Schedule a due monitor on an agent-owned task in progress.
2. Add an active recovery action for an interrupted legacy execution.
3. Run the monitor scheduler twice. No provider may start while the hold
remains.
4. Before this fix, neither attempt writes monitor deferral activity.
5. Resolve the hold through its existing recovery path. The saved
monitor can then request one wake.

**Paperclip version or commit**

Reproduced on master 5739a53f5f with real PostgreSQL and the assembled
heartbeat service.

**Deployment mode**

Built from source. This affects the server monitor scheduler.

## What Changed

- Pass the existing execution blocker cause to the monitor scheduler
through a server-owned diagnostic callback.
- Record issue.monitor_deferred for held admission and
issue.monitor_dispatch_failed for unexpected admission failures.
- Keep activity to known reason codes and allowlisted blocker causes. Do
not copy raw provider messages.
- Fence claim release and activity against replacement, reassignment,
completion and competing scheduler instances.
- Limit identical activity for one schedule and cause to one record per
five minutes.
- Keep claim release functional when diagnostic storage fails.
- Update execution documentation and the task verification maps.

## Verification

- Red: explains held monitor dispatch without replaying uncertain
execution failed because it expected one deferral activity row and
received none. The fixture used the real queue, persisted source run and
recovery action.
- Red: records bounded dispatch failure diagnostics while retaining the
schedule failed because no failure activity was recorded.
- Green: both regressions pass after the fix. The held-source test
proves no successor while held, no monitor attempt consumed, and one
wake after explicit hold resolution.
- Passed: all 43 tests in heartbeat/scheduling.test.ts and
issue-monitor-scheduler.test.ts, with at most two workers.
- Additional coverage uses real PostgreSQL for diagnostic rate limits,
replacement races and an audit-insert trigger failure. Audit failure
must not retain the monitor claim. Private error and unknown blocker
text do not reach activity.
- Passed: node scripts/check-maps.mjs and git diff --check.
- Greptile: 5/5 with no actionable issues on
1d0aec738c.
- Latest-head checks: 55 successful, two skipped, and one neutral. No
check remains pending or failed. The branch has no merge conflict.
Paperclip Review ended neutral because its agent did not return a
complete assessment; it is not counted as a validated review pass.
- The dependency added on deferral is one bounded recent activity query
and at most one audit insert. Successful admission adds no new database
read. Existing queue authority checks still decide admission.
- The process fixtures validate queue admission and persisted state.
They log workspace setup errors after admission; this report does not
claim a live provider turn succeeded or that an existing deployment was
repaired.
- Passed: pnpm --dir server exec tsc --noEmit. The wrapper typecheck was
stopped because it started a redundant cold native Runner build. Full
repository checks run in PR CI; no local full-suite or full-build pass
is claimed.

## Risks

- Audit work must not strand a monitor. The storage-failure regression
verifies that rollback is followed by a claim-fenced release.
- Recovery holds still require their current reconciliation path. This
change makes their effect visible and does not bypass ownership, budget,
pause, Stop or company checks.
- Activity can be stale after a later repair, so each entry includes the
checked time and the exact saved deadline. A replacement cannot inherit
an old dispatch diagnostic.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use and code execution.
The exact runtime model suffix 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-19 16:11:31 -05:00
DottaandPaperclip 370fb50ad4 fix(mcp): keep sibling tools available after transient calls (#16890)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use remote MCP tools through a governed gateway.
> - The gateway lists tools only while their shared connection is
healthy.
> - One failed call currently marks the whole connection as unhealthy.
> - Later calls to healthy sibling tools then fail with
`tool_not_found`.
> - This pull request keeps non-authentication call failures on their
invocation.
> - Agents can continue their work while credential and access gates
remain in force.

## Linked Issues or Issue Description

Refs #10147.

Related work: #15462 fixed oversized and malformed response handling.
#15448 covers timeout and JSON-RPC health handling together with
separate SSE and catalog discovery changes. Its patch still marks fetch
failures and HTTP failures as connection errors. #15325 proposed a
transport failure counter; it has merge conflicts and has not changed
since October 6. #11910 is an older timeout fix with merge conflicts.
This PR covers the remaining fetch and HTTP failure paths on current
master, with the same narrow call-health rule for timeouts and JSON-RPC
failures. It does not include the SSE or discovery changes from #15448.
The timeout session-reset check follows the recovery case discussed in
#15448.

**What happened?**

A shared remote MCP connection works until one call has a network
failure, timeout, HTTP 503, or JSON-RPC error. Every later call on that
connection returns `tool_not_found`, including healthy sibling tools.
Connection setup then asks for user attention even though the failure
did not prove that credentials need repair.

**Expected behavior**

The original invocation retains its failure. Authorized sibling tools
remain callable. The gateway does not replay an ambiguous action. HTTP
401/403, missing credentials, and explicit insufficient scope keep their
access gates.

**Steps to reproduce**

1. Give an agent access to two read tools on one remote MCP connection.
2. Make one tool fail with a network error or HTTP 503.
3. Call the other tool in the same gateway session.
4. Before this fix, the second call fails with `tool_not_found` before
provider dispatch.

**Paperclip version or commit**

`master` at `e6dcd1e8e9`. The regression runs against source with
synthetic data.

**Deployment mode**

Any deployment that uses a shared remote MCP connection. This is a core
gateway issue.

## What Changed

- Preserve connection health after a network failure, timeout,
non-authentication HTTP error, or JSON-RPC error from one tool call.
- Retain HTTP 401/403 and insufficient-scope health gates.
- Retain HTTP 401/403 gates during MCP initialization and its
initialized notification, with HTTP 503 controls for both stages.
- Discard only the upstream session used by a network failure or
timeout. Let the next explicit call initialize again.
- Add sibling-tool regression cases, authentication controls, and real
HTTP header/body timeout checks.
- Update runtime recovery guidance and the feature and access maps.

## Verification

- Red: the four new sibling-tool cases failed on the original
implementation. Each second call returned HTTP 404 with
`tool_not_found`. HTTP 401/403 control cases passed.
- Green: the same six-case selection passed after the production change:
`pnpm --filter @paperclipai/server exec vitest run
src/__tests__/tool-gateway-service.test.ts -t 'keeps sibling MCP tools
usable|keeps the connection blocked' --maxWorkers=1`.
- The regression checks the actual gateway and embedded PostgreSQL. The
injected provider fault preserves the call boundary. It checks failure
recording, no automatic replay, catalog retention, and successful
sibling dispatch.
- The real local HTTP fixture checks cancellation before headers and
during a body, then a successful explicit call with a fresh MCP session.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Complete nearby suites pass: 166 tests across
`tool-gateway-service.test.ts`, `tool-gateway.test.ts`,
`remote-mcp-protocol.test.ts`, and `mcp-http.test.ts`, with one test
worker.
- `pnpm --filter @paperclipai/server exec tsc --noEmit` passes after
refreshing Runner TypeScript declarations. The first package typecheck
used declarations from before the rebase and failed two unchanged
native-session call sites; rebuilding that dependency resolved both
errors.
- The rebased head also passes all 11 selected
sibling/authentication/session regressions.
- Review regression red: setup-stage HTTP 401/403 controls failed
because connection health stayed `ok`; the two setup-stage HTTP 503
controls passed. Green: all six setup controls and the complete 166-test
nearby run pass. The fix separately handles typed initialization
authentication failures and preserves the existing caller error. The
server compiler also passes after this change.
- Full repository CI passes on
`256a65ccc302c1c31a80e87f1f91411d955028de`: typecheck, build, test
shards, Runner checks, browser checks, Canary dry run, and aggregate
gates. All checks are terminal: 55 successful, 2 expected skips, and the
separate Paperclip Review check is neutral. Greptile is 5/5 on this
exact head, with no open findings.
- Full repository checks were run in CI. Local verification in this
worktree used the focused suites and server compiler to keep parallel
work bounded.
- This change has no live provider or staging deployment proof.

## Risks

- A provider that remains unavailable can stay listed until a health
check detects the outage. Each call still fails with its original
controlled reason code.
- No automatic retry occurs because a failed remote action may already
have run.
- Already unhealthy connections still need a successful health check
after an upgrade.
- No schema, credential policy, or permission contract changes.

## Model Used

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

## 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-19 16:11:15 -05:00
DottaandPaperclip 24067a16b5 fix(workspaces): classify restricted shared repository admission (#16895)
## Thinking Path

> - Paperclip manages agents, their tasks, and their saved work.
> - Workspace preparation must check access before an agent starts.
> - A shared project checkout can contain another task's private
worktree.
> - The access guard correctly rejects a run that cannot read that work.
> - The isolated-source path reports this as a configuration blocker
after #16545.
> - Shared project repository admission missed that classification and
returned a generic setup failure.
> - This change uses the same blocker at that boundary so recovery names
the required workspace repair.

## Linked Issues or Issue Description

Refs #16545 and #16095. The open retained-reader repair in #16832
addresses deleted identities, a separate condition.

**What happened?**

A task reused a shared project workspace. Another worktree in that
checkout retained a private task that the run could not read. Repository
admission rejected access before provider startup. The run reported
`setup_failed`, and recovery showed a generic no-live-execution notice.

**Expected behavior**

Keep the access denial. Report `configuration_incomplete` with reason
`workspace_source_restricted`. Preserve the workspace and files. Give
the owner the existing workspace repair action. Do not queue an
automatic failure retry or report this expected blocker as an unexpected
Sentry failure.

**Steps to reproduce**

1. Bind a task to a shared project checkout.
2. Add a private task worktree beneath that checkout.
3. Continue the shared task as an agent that cannot read the private
task.
4. Inspect the run result and recovery action.

**Version and deployment**

Reproduced in the full heartbeat service from source revision
`06d4fe3121`, with PostgreSQL and real Git worktrees on macOS. The
provider never starts. The regression also covers the existing
Git-worktree path.

## What Changed

- Apply the existing restricted-source classifier to task repository
admission.
- Extend the heartbeat regression to shared project workspaces.
- Assert one run and one recovery action, no provider start, no
unexpected Sentry report, and preserved binding and files.
- Update the workspace documentation and both capability maps.

## Verification

- Red: the shared project regression returned `setup_failed`; the
Git-worktree control passed.
- Green: the same two cases pass after the change.
- `node scripts/check-maps.mjs` and `git diff --check` passed.
- Current head `e26cdd45da76c6edaa1622856f9c69e9f48b81fb`: 55 successful
checks, one neutral check, two skipped Storybook checks. Greptile 5/5,
no review threads, mergeable.
- All 337 tests passed across `heartbeat-workspace-branch-containment`,
`heartbeat/workspace-preparation`, `run-failure-report`, and
`recovery/stranded-notice`.
- `pnpm -r typecheck` and `pnpm build` passed. All full current-head CI
suites passed in [run
39315969013](https://github.com/paperclipai/paperclip/actions/runs/39315969013).
The duplicate local full Vitest run was stopped after 11 minutes when CI
completed; it has no local full-suite completion claim. The 337 affected
local tests completed successfully.
- Running-app acceptance at `e26cdd45da76c6edaa1622856f9c69e9f48b81fb`:
a synthetic private Git worktree caused the shared task to stop with the
visible Workspace source restricted notice and no process start. The
normal workspace API selected a separate task directory. Resolving the
recovery action resumed the same assignee. A real process fixture
completed, the output persisted after reload, and both source files
remained intact. Checkout and execution locks cleared. There were no
automatic failure retries.
- The first recovered process wrote its report to the command cwd. This
was a fixture output-path mistake. The corrected fixture reads the
selected workspace from the authenticated API before writing. One
explicit additional admission verified that output. The record retains
both successful process runs and the earlier configuration-blocked run.
This is local process-adapter acceptance, not live Codex/provider
qualification.
- Staging diagnosis confirmed a retained private source and failure
before provider startup. The original task has not been recovered. The
deployed UI hides its workspace selector, and no authenticated
task-write API is available in this session. No live Codex recovery is
claimed.

## Risks

The same exact 403 denial is now a configuration blocker during shared
repository admission. Other failures retain their original type. Access
policy, cloning, credentials, provider execution, and workspace contents
do not change. An existing task still requires a permitted workspace
repair before it can run.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and browser
tools. The exact deployment 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-19 16:03:16 -05:00
DottaandPaperclip ac9459bae3 feat: configure company agent observability (#16874)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Companies use several agent harnesses and execution environments.
> - Operators need one place to select where native agent logs and
traces go.
> - An inference proxy would add a dependency to the agent request path.
> - This pull request supplies native OpenTelemetry settings to managed
Codex and Claude Code processes.
> - Company secrets protect destination credentials. Export failure does
not change the task result.

## Linked Issues or Issue Description

**Subsystem affected**

Company settings, shared contracts, database, server, adapters, and
runner.

**Problem or motivation**

An operator cannot configure a company destination for native agent logs
and traces. Manual harness configuration is hard to apply across local
and remote execution.

**Proposed solution**

Add one company destination: Braintrust or a custom OTLP HTTP/protobuf
endpoint. Apply a transient snapshot when execution preparation starts.
Keep credentials out of API reads, task environment manifests, recovery
files, and command arguments. Replace a warm process when its export
settings change and preserve its conversation.

**Alternatives considered**

Multiple destinations can use a user-operated collector for fan-out.
This change does not add a collector, an inference proxy, or transcript
scraping.

**Roadmap alignment**

This extends company settings, secret management, and support for
multiple harnesses. The maintainer requested this implementation.
Searches for observability and Braintrust found no duplicate company
destination feature. Related infrastructure tracing work in #16236 has a
separate content-free contract.

## What Changed

- Add strict schemas, revision checks, encrypted secret storage,
activity records, and board-only settings routes.
- Add explicit synthetic logs and traces tests with a bounded HTTP
request and sanitized results.
- Supply native Codex configuration and Claude Code environment values
through local and remote launch paths.
- Preserve Codex login refresh through the existing managed credential
link. Retain unsaved drafts across background reads. Require complete
custom header re-entry when the endpoint origin changes.
- Separate process export compatibility from conversation identity.
Isolate generated Codex configuration and preserve resumable sessions,
including remote home refresh after export changes.
- Advance the immutable Pi/Copilot source attestations for shared
environment and sidecar code changes. Keep their provider payloads
unchanged and retain prior identities for decoding.
- Redact destination credentials throughout launch diagnostics and HTTP
logs.
- Add the production settings form, Storybook states and journey,
documentation, and feature/access map entries.

## Verification

- Real managed local Codex 0.160.0 and Claude Code 2.1.286 tasks
exported to Braintrust. API readback and the Braintrust UI showed the
test records. A real remote Daytona Codex task exported through the
legacy `exec` path.
- Live tests exercised content capture off, export disabled, warm
conversation reuse, and a destination that accepted connections but
never replied. Agent work succeeded and export requests stopped at the
configured three-second timeout. The UI connection test returned “Test
payload accepted”; the saved API key stayed masked after reload.
- All current-head CI test lanes, typechecks, packaging/build checks,
and required aggregates passed on
`71e994b2be9c8fb6d6e938a4ad7cf4c95fdafe31` ([CI
run](https://github.com/paperclipai/paperclip/actions/runs/39319194318)).
Greptile completed on that exact commit at 5/5, with zero unresolved
review threads. The additional optional Paperclip Review check remains
queued waiting for its assigned agent.
- Local workspace typecheck and build passed. Focused verification
included 239 combined runner tests, 789 API/native-session tests, 107
Codex home/ACP/sandbox-site tests, 204 feature/privacy tests, and the
affected Rust suites. Migration, token, map, Storybook catalog, and
Storybook build checks passed during acceptance. These checks ran at the
relevant implementation or merge boundary; the current-head CI is the
complete final gate.
- Managed AI credential projections now receive enabled and disabled
company export settings; genuine caller-owned Codex homes remain
untouched. Two regressions reproduced the skip before the repair. All
276 engine/lifecycle tests and adapter-utils typecheck pass afterward.
The launched TOML retains provider/MCP settings, credential continuity,
and redaction.
- Settings saves, removal, and the real company-deletion owner acquire
secret mutation ownership before database locks. PostgreSQL NOWAIT
probes cover all three paths; concurrent save/rotation/removal/deletion
requests settle correctly. The affected suites passed 137 tests,
followed by all 32 service/connection cases after expanded deletion
coverage. Server and Codex adapter typechecks pass.
- Codex source profiles use the effective CLI argument list. A spawned
fixture CLI reproduced both ignored-argument failures; all three
precedence/fallback cases now pass.
- Real tar staging reproduced remote conversation loss in both API-key
and subscription modes before the repair. Both now pass: changing
managed settings preserves sessions, archives, native indexes, and
refreshed subscription credentials. A corrupt upload preserves the prior
config and conversation.
- Preserved failure evidence: initial CI caught stale Pi/Copilot source
attestations, a missing test-harness helper, and packaging fixture/probe
mismatches; those were corrected and covered by focused checks.
Superseded heads had intermittent attachment-composer timeouts despite
successful uploads; [the original trace and screenshot remain
available](https://github.com/paperclipai/paperclip/actions/runs/39309701089/artifacts/12215109203).
The same attachment case passed on the final head: [25/25 tests in shard
3](https://github.com/paperclipai/paperclip/actions/runs/39319194318/job/118288637051).
- A connection-fault fixture also exposed a stale pooled socket after
its hang case; closing fixture responses isolated scenarios and the full
affected suite passed.
- The broad local test run was not clean: database resource failures,
timeouts, an older cached module graph, and a stale optional-resource
manifest assumption were recorded. Focused checks passed after the
documented fixes. This does not establish a clean full local pass.
- Native remote Codex, remote Claude, and the full ACPX Codex bridge
remain unqualified. The direct Codex resume test does not establish full
bridge acceptance.

## Risks

- Native exporters perform network requests from each execution
environment. A server connection test does not prove remote
reachability.
- Prompts, assistant responses, and tool content are enabled by default
when supported. Native caps and harness-specific controls still apply.
- Caller-owned Codex homes are unsupported for automatic configuration
and remain untouched.
- Native harnesses and their tool processes can inspect export
credentials. The settings form and documentation advise using
ingestion-scoped credentials. Retained headers remain bound to their
saved scheme, host, and port; changing origin requires fresh values or
removal.
- Migration 0357 adds a company-scoped row and secret reference. It is
safe to reapply. Secret removal and company deletion use the existing
secret lifecycle.
- Slow or unavailable destinations must not block task settlement.
Export settings take effect at the next execution preparation boundary.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [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-19 15:36:04 -05:00
DottaandPaperclip 8a3d2cb04f fix(recovery): avoid recursive holds for undispatched waits (#16894)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Queue admission must stop work while a previous execution needs
recovery.
> - The final dispatch gate can cancel a queued run before it starts.
> - Legacy recovery treats this known wait as an unknown provider
outcome and creates another hold.
> - The extra hold can survive repair of the original execution and
leave saved messages stuck.
> - This pull request uses one database proof to prevent the extra
incident and recognize old false holds.
> - Saved input can then pass through normal admission with the original
work and safety gates intact.

## Linked Issues or Issue Description

Refs #15483.

**What happened?**

The dispatcher writes an `execution_reconciliation_required`
cancellation when an existing recovery hold denies a queued run. No
runtime is selected and no provider starts. Legacy recovery later
creates a `legacy_execution_requires_reconciliation` action for that
cancelled admission. Its settled `replay: blocked` record remains an
effective hold after the real source recovery finishes. The task has
saved messages but no eligible Retry or Continue action.

**Expected behavior**

A verified admission denial stays a wait. It must not create another
provider-outcome incident. Existing false incidents must stop blocking
after the server verifies their recorded source. Real execution,
uncertain outcomes and file recovery stay held. The harness determines
these infrastructure facts; the user does not certify them in a form.

**Steps to reproduce**

1. Persist a queued-run gate cancellation with its task-bound
`executionWait` receipt and no execution authority or resource evidence.
2. Run legacy reconciliation. On the old code, it creates a second
incident.
3. Persist the old incident as resolved with replay blocked, then clear
the original source hold.
4. Restart queue recovery with saved user messages. On the old code, no
successor is admitted.

Related work: #15965 covers other pre-start dispatch cancellations but
explicitly excludes this existing-hold code and leaves historical holds
unchanged. #16634 covers stale-cancel classification and queue drain,
without re-evaluating historical effective holds. #15383 covers an
operator Stop during conversation startup. This change addresses the
existing-hold receipt and its persisted false incident; it does not copy
those broader changes.

## What Changed

- Add one database proof for a legacy admission denied by an existing
execution hold. Require the exact dispatcher receipt, matching task
identity, no runtime or process claim, no lease or finalization
coordinator, and no execution events.
- Use the proof before legacy recovery creates an incident and when it
computes effective historical holds. Keep the old audit rows.
- Preserve source file obligations and the original recovery action.
Keep the normal queue, pause, ownership, company and budget checks.
- Add real PostgreSQL regressions for incident prevention, old state,
concurrent queue recovery, message order, conflicting evidence and scope
boundaries.
- Update the execution contract and both recovery maps.

## Verification

- Red: the regression on unfixed source fails on incident
classification, historical hold projection and actual periodic
saved-message admission. The other 24 safety cases pass.
- Green: all 27 new database cases pass. Two safety assertions were
aligned with the existing contract: daily limits stop dispatch after
queue promotion; a human comment can intentionally reopen a terminal
task. The final regression checks the real daily dispatch gate and agent
pause.
- Existing `explicit-native-continuation.test.ts`: 255 tests pass.
Existing legacy recovery and PostgreSQL dispatcher suites: 61 tests
pass.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs` and
`git diff --check` pass.
- GitHub PR CI run `39313204660` passed on
`ef6009e656b7c9b4c788480dce322874565960ac`. All 54 successful check-runs
and the Snyk status are green. Two optional Storybook checks were
skipped. The independent Paperclip Review completed with a neutral check
and a 5/5 assessment with no findings. Greptile also reports 5/5 on the
same commit. There are no unresolved review threads.
- `pnpm test:run` is still running locally. Its overall result is
pending; no full local suite pass is claimed. The exact-head GitHub CI
suite passed.
- A read-only probe of an affected hosted task verifies the same
database proof and projects no false blocker with the working source. No
live rows were changed. Deployment and a real resumed provider run
remain unverified.

## Risks

- An incorrect exclusion could admit work with uncertain effects. The
proof fails closed on missing receipts, source mismatches,
runtime/process ownership, any retained lease, coordinator, execution
event or file obligation. Real upstream file recovery remains blocking
in the regression.
- The effective-hold query adds indexed existence checks scoped to the
recorded run and company. It makes no provider calls and performs no
database repair writes.
- Historical audit records keep their recorded outcome. Only their
effective blocking status changes when the server can prove the
admission never ran.
- No schema, permission, credential or UI form changes are included.
Live recovery still needs verification after rollout.

## Model Used

OpenAI Codex, model ID `gpt-6.1-sol`, with reasoning, tool use and code
execution.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 15:26:39 -05:00
Nicky LeachandPaperclip 313fb265db feat(plugins): invalidate runtimes when connector access changes (#16605)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Runtime preparation depends on access and credential state as well
as tool definitions.
> - Grant, membership, secret, and endpoint changes need committed
invalidation.
> - Their writers must acquire locks before journal fanout can lock
agent rows.
> - This pull request adds access hooks with the corresponding
transaction guards.
> - Plugins can refresh preparation immediately while task-time
authorization remains authoritative.

## Linked Issues or Issue Description

**What happened?**

Grant changes, credential rotation and revocation, company access
changes, and connector endpoint configuration do not request runtime
synchronization. Journal fanout exposes lock inversions between
credential persistence, access cleanup, and connection assignment
writers.

**Expected behavior**

Committed access changes request runtime preparation without polling or
credential values in the journal. Agent-specific secret bindings and new
personal delegations affect their target agent. Company access changes
remain conservative. Provider bookkeeping does not create preparation
work.

**Steps to reproduce**

1. Change an audience, delegation, membership permission, referenced
credential, vault configuration, or endpoint instruction.
2. Expect a committed runtime event in the correct company and scope.
3. Run reconnect, credential refresh, SSH setup, or membership cleanup
concurrently with related writes.
4. Expect both operations to preserve access checks and finish without a
lock-order cycle.

**Additional context**

Final feature extraction from #16503. The earlier slices, #16604, and
the separate delivery-test correction #16871 are merged. This PR is now
the active change against master. The rebase preserves the merged
assignment and definition recipient rules, Unicode selector semantics,
and profile/reference transaction guards.

## What Changed

- Add migration 0356 for grants, audiences, delegation,
membership/permissions, secret bindings, referenced credentials and
vaults, and chat/email endpoint configuration.
- Keep events content-free. Ignore health, delivery, publication, Vercel
verification, and GitHub webhook bookkeeping while retaining credential
and repository-access changes.
- Target agent secret bindings and all personal delegation changes to
their old and new target agents. Coalesce delegation changes per
transaction.
- Lock existing grants before connections and credential persistence in
OAuth and cleanup writers.
- Reject superseded refresh leases before rotating stored credentials.
Ignore lease acquisition and release when access metadata is unchanged.
- Serialize audience replacement, validate membership, and preserve
unchanged audiences.
- Lock membership before permission-only saves and grant before Railway
SSH setup. Individual delegation revocation locks its grant and target.
Whole-grant and membership cleanup lock company recipients before
deleting scoped delegations.
- Lock grants and connection inputs before static-key reconnect writes.
Lock company agents before cascading secret deletion; use a nonblocking
secret lock and bounded retries to avoid a new cycle with credential
writers.
- Add PostgreSQL concurrency coverage for access writers and endpoint
publication/configuration behavior.
- Preserve the owner lock for plugin instance-secret removal; these
secrets cannot use ordinary bindings.
- Align Slack search refresh, callbacks, and disconnect with
grant-before-connection locking. Recheck newly discovered grants without
waiting before provider work.
- Retry complete membership transactions when a credential deletion
candidate is busy. Cover all four cleanup entry points and process
company access in ID order.
- Document final invalidation coverage and task-time authorization
boundaries.

## Verification

- Current head: `78aace55bef7f52bc5742b131e0b3961eb5c0f11`. All 1,061
tests across 23 affected suites pass. The named Slack authorization
integration scenario also passes; it exercises authorization, refresh,
disconnect, and rejection of a late callback. Server/database
typechecks, migration safety and numbering, five-snapshot retention,
feature maps, and diff checks pass. The complete PR diff was reviewed
for secrets and personal data before push. Final acceptance: [CI run
39308303837, attempt
2](https://github.com/paperclipai/paperclip/actions/runs/39308303837) is
green, with 55 successful checks and two optional Storybook skips. The
current-head Greptile reassessment returned **Apex 5/5** at 19:16 UTC on
2026-10-19. Its full summary reports no actionable issues. Security
passed, all threads are resolved, and GitHub reports no merge conflicts.
The reassessment was requested as a standard review after the fixes;
Greptile retained the Apex tier.
- On this head, [CI run
39308303837](https://github.com/paperclipai/paperclip/actions/runs/39308303837)
failed the unchanged adapter-utils HTTP/2 fixture with `EADDRINUSE`
before READY. Its closed probe left a port handoff race. That test and
its gateway are byte-identical on master. No upstream fix was found. The
deterministic fixture correction is isolated in #16888; no adapter test
changes are included here. The failed jobs recovered on retry without a
feature source change. The original failure remains documented here, and
#16888 carries the fixture correction separately. That retry
demonstrates recovery; the held-probe negative control establishes the
port handoff race.
- Rebased onto master `194fc11406`, including merged #16604 and #16871.
Replayed only the access-hook commit. Resolved OAuth, test, and
documentation conflicts while retaining both sets of tests. Migration
0356 preserves the merged assignment/definition recipient rules, Unicode
selector semantics, and profile/reference guards.
- Apex returned 3/5 on `0fb65bc27`. Negative controls reproduce its
Slack delegation and member-cleanup deadlocks (`40P01`) and unwanted
Vercel/GitHub bookkeeping events. Slack grant writers now take their
locks before the connection. A separate late-grant control reproduces
`40P01` without the post-lock recheck; the complete guard passes. All
four membership cleanup commands retry from a fresh transaction when the
credential is busy. Tests verify successful cleanup and no journal rows
from failed attempts. Credential IDs and repository-access changes still
notify runtimes.
- Earlier review corrections remain covered: static-key reconnect and
cascading secret removal each reproduce `40P01` without their guards.
Grant lease acquisition/release is ignored. Secret removal releases
agent locks when a credential writer is busy. Instance-secret removal
retains the owner lock and passes its public plugin API contention
regression. Delegation updates and revocations target old/new agents;
unrelated-peer, coalescing, unchanged-update, and rollback cases pass.
Three negative controls verify the required whole-grant and membership
cleanup guards after narrowing delegation scope.
- Preserve prior acceptance failures: the first rebased 20-suite run
passed 1,025/1,026; its only failure was a draft uninstall fixture
blocking a random peer. Blocking the assigned agent corrected that
assumption, and all 44 access/assignment tests passed. Later, all 1,044
tests across 21 suites, [CI run
39302185527](https://github.com/paperclipai/paperclip/actions/runs/39302185527),
standard Greptile 5/5, and security passed on `0fb65bc27`. That did not
clear the later Apex findings described above. Draft run 38975428081
failed a server shard; its cause was not re-investigated. A later green
run does not establish that earlier cause.
- Local fixture corrections are recorded separately from product
failures: an assignment filename filter initially matched no file; the
actual suite was included in full runs. A delegation fixture omitted its
required creator, and a guard run omitted a query import. The new
global-access cleanup fixture now uses its own user to avoid earlier
fixtures' memberships. All were corrected before publishing their final
iterations.
- Local checks target affected services and real PostgreSQL boundaries.
A full local build and repository-wide test run were not performed.
Hosted CI supplies broader verification. Provider responses in tests are
controlled; live provider behavior was not qualified.

## Risks

Migration 0356 adds triggers without changing table schema. Apply it
through the normal migration flow. Most access changes retain
synchronous company-wide invalidation. Company fanout takes O(eligible
company agents) locks and journal rows, without a fanout ceiling or
mutation quota. Agent secret bindings and individual delegation changes
retain narrower recipients. Events contain no credentials.

Physical removal of non-instance secrets takes ordered locks on all
company agents before cascading into bindings. This costs O(company
agents) locks even for an otherwise unreferenced secret. Instance
secrets cannot use ordinary bindings and retain their owner lock. A busy
secret lock releases the transaction guards and retries up to three
times. Continued contention returns a retryable conflict. Provider
deletion stays outside that transaction; a retry resumes removal of an
already disabled secret.

Membership cleanup uses nonblocking credential guards and retries the
full membership transaction. Slack search adds two grant queries, scoped
to the subject and connection. Its retries occur before provider work or
credential persistence. Each retry loop is limited to three attempts.
Invalidation requests preparation; task-time authorization and provider
session activation remain authoritative. Provider calls use fixtures; no
live provider qualification is claimed.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository inspection, code
execution, and testing. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 12:49:11 -07:00
DottaandPaperclip e6dcd1e8e9 feat: add Commentary to Audit with filters and shareable messages (#16884)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents can submit suggestions and complaints while they work.
> - Operators currently need database access to read those messages.
> - That makes it hard to find feedback from one agent or share a
specific message.
> - This pull request adds a standard Commentary tab in Audit.
> - Operators can filter messages, browse 50 at a time, and share links
to full message dialogs.

## Linked Issues or Issue Description

Refs #15367, which added feedback storage and agent submission. The
duplicate search found no open PR for a commentary reader.

**Subsystem affected**

Server, shared API contracts, and the board UI.

**Problem or motivation**

Agent suggestions and complaints are stored but have no board reader.
Operators must query the database to inspect feedback.

**Proposed solution**

Add Commentary to Audit without an experimental toggle. Show previews,
agent and message-type filters, text search, and 50-message pages.
Opening a row updates the URL. A copied URL opens the full message with
its agent, task, and run context.

**Alternatives considered**

Direct database queries remain useful for operators, but do not provide
a normal product workflow. An experimental setting would add setup to a
read-only audit page.

**Roadmap alignment**

This completes the operator view for the existing feedback feature. It
supports human oversight and does not change agent execution or task
ownership.

## What Changed

- Add company-scoped, board-only list and detail endpoints with audit
permission and source-task privacy checks.
- Return bounded previews and counts. Fetch full bodies only when a
message opens.
- Add the Commentary tab, search, filters, 50-row pagination, and
URL-based selection. Audit tab destinations work in both layouts, with a
classic sidebar entry for Commentary.
- Add production Storybook examples for populated, filtered, linked,
long, paginated, empty, loading, failed, denied, mobile, and light
states.
- Update API documentation and the feature and agent access maps.

## Verification

- Final head `abc4a251c14cfbfec007542214beec528f2b18bf`: 55 checks pass;
two conditional Storybook checks are skipped. The PR workflow is
successful. Greptile is 5/5 with all findings resolved.
- Focused database, HTTP, submission, OpenAPI, and UI regression tests
cover company isolation, task privacy, filter bounds, 50-row pagination,
and copied message links.
- Browser Storybook journeys cover row opening, direct links, combined
filters, search, and pagination. Storybook uses synthetic API fixtures;
database authorization is tested separately.
- Token gates, feature maps, and Storybook catalog validation pass.
- `pnpm -r typecheck`, `pnpm build`, and `pnpm build-storybook` pass on
the rebased branch. All 80 focused tests and all 37 Audit tests pass,
including the real App route table in both layouts, task
grant/revocation through HTTP, deleted-task privacy, and URL UI
regressions. The full suite passes in the parallel PR CI matrix. The
local serial full-suite run was stopped before completion after checking
the recorded 94-minute serial duration. Local focused tests, workspace
typecheck, production build, and final server/UI checks pass.
- The linked-message Storybook test initially asserted against the
loading dialog. It now waits for the message body; both direct-link and
row-open journeys pass.
- Native and legacy deleted-task privacy regressions failed before the
fix and pass afterward. The reader checks the run task binding after the
task foreign key clears.
- A rapid search-then-agent-filter browser regression reproduced the
search overwriting the selected agent. The pending search now restarts
when URL filters change. The same browser test passes with both filters
applied.
- CI found two existing AuditHub assertions that still expected five
tabs. They now assert the six-tab model and selected-company Commentary
rendering. All 37 Audit tests pass. All other test and build jobs passed
before this test-only correction.

- The [agent-chat attachment browser
test](https://github.com/paperclipai/paperclip/actions/runs/39307881171/job/118250189664)
timed out waiting for an attachment preview. The [same shard passed on
the prior
head](https://github.com/paperclipai/paperclip/actions/runs/39306658703/job/118245498343)
with identical application code; the intervening change only updates
AuditHub unit tests. The single retry passed on the same head. The
precise cause of the earlier failure remains unconfirmed.

## Risks

- Commentary may contain sensitive task context. The reader requires
board access and audit permission, and filters source-task visibility
before returning previews, counts, or full bodies.
- Text search scans stored message bodies. Pages are bounded and full
bodies are fetched on demand.
- Offset pagination can shift if new messages arrive while paging.
Ordering uses timestamp and ID for stable ties.
- No database migration or agent submission behavior changes are
required.

## Model Used

- OpenAI Codex, GPT-6 family, with reasoning, tool use, browser
interaction, and code execution. The exact backend model ID and
context-window size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 14:21:13 -05:00
d747752496 fix(runner): record why an OpenCode turn fails when opencode serve stops (#16863)
When `opencode serve` stops during a turn, the OpenCode driver now fails the
active turn itself with a closed-vocabulary cause (server exit code or known
signal, allowlisted socket error code, HTTP status, or closed stream) instead
of leaving runnerd to close it with `error: null`. The proxy flushes stdout
before a fatal exit so the failed turn reaches runnerd, and the server records
OpenCode failed turns as `nativeTurnFailure` (live and persisted-recovery
paths) so the run-failure diagnostic names the cause. Provider text is never
copied. Run status, retries and recovery behaviour do not change.

Co-Authored-By: Paperclip Sentry triage <Paperclip-Paperclip@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:20:24 -07:00
DottaandPaperclip 8193abb936 feat(claude): default qualified macOS and Linux targets to Paperclip Runner (#15997)
## Thinking Path

> - Paperclip must run the selected agent on its selected host.
> - Claude needs verified packages for each supported target.
> - A Mac controller must select the correct Linux provider pack.
> - New defaults must follow package and execution evidence.
> - This PR adds Claude platform packaging and target-specific pack
selection.
> - Existing Codex Linux ARM64 behavior remains intact.

## Linked Issues or Issue Description

Refs #15683. This PR depends on #15993 and #15994. Related scope: #15422
and #15224.

## What Changed

- Reuse the merged four-target daemon producer/consumer matrix. Add
target-owned Linux provider packs and carry their immutable identities
through release assembly and vendoring.
- Reuse master’s landed pinned Claude SDK ARM64 executable admission and
retain package-integrity, architecture and no-follow admission.
- Select target-specific remote packs so Mac controllers can use Linux
hosts without a development pack override.
- Preserve read-only runtime context on SSH startup and resume without
accepting unverified old content.
- Check ordinary installed Claude readiness without injected package
authority. Retain Codex and Linux x64 consumer checks.
- Extend Claude automatic target selection for the remaining qualified
package targets. Retain unsupported-platform and external-override
behavior.
- Qualify managed Daytona snapshot names through provider IDs during
Claude Connect. Pin native acquisition to the measured ID. Preserve a
revocation marker after failed probes or target edits, and block native
acquisition until requalification instead of falling back to a mutable
name. Preserve immutable-image proof, company and account boundaries,
and Legacy acquisition.

## Verification

- Reconciled with master `9179d8dcc3e908c217fde4f63c9d08ccf8132eeb`
through the prerequisite stack, retaining the merged startup fix and
latest Codex Linux ARM64 behavior.
- [Four-target exact-source package
qualification](https://github.com/paperclipai/paperclip/actions/runs/39267321383)
passed on source `04e0202ca81387b17cbe7fd094a8338648356fe9`: all four
native builds, public-package assembly, Linux x64 verification and clean
installed consumers on Apple Silicon, Intel Mac and Linux ARM64. The
later master reconciliation adds shared OpenRouter attribution and
changes runtime source. This historical result keeps its original source
identity; [later
qualification](https://github.com/paperclipai/paperclip/actions/runs/39281100929)
passed at `dca62c7aeb4b45f0dd91a8e18d386a16a2658ef8`. It predates the
subsequent TypeScript startup fix.
- Fresh local product acceptance on integrated source
`b2c9fe43f9cd3bc5dd9d22552da0148845ba71a4` completed a useful file and
follow-up through native Claude/Opus 5.5, High effort and the API-key
connection. Both actual browser downloads were independently checked;
the revision preserves the original body and session continuity. Total
task estimates: $0.518432800. Ordinary web and API creation saved
defaults with the native experiment disabled.
- Local focused verification passed 993 startup/session tests, 243 UI
tests, 12 workflow security tests, direct server/UI TypeScript checks,
and token/palette gates before the last review changes. Initial
DB-backed snapshot pin/revocation coverage passed 18 cases; the final
serial route suites pass 122 credential/permission and 232
snapshot/environment cases after correcting a test hook timeout.
Current-head cloud suites pass.
- Preserved the failed pre-provider local fixture and its full pending
reservation. The successful fixture has no unpriced or pending usage.
Historical failed Cloud journeys, accounting holds, source identities
and subscription limitations remain in the dated plan.
- All Docker/Rust release production was performed in cloud CI. No local
Docker image was built. An inadvertently invoked local Rust prerequisite
was stopped.
- Current-head cloud CI is green. All three stack PRs have fresh
Greptile 5/5 reviews and zero unresolved review threads. Required
typecheck, test and build gates ran in cloud CI; Docker work stayed
remote. Earlier failed checks remain in their original runs.

- The final master merge preserves task-loading, permission,
skill-retention and OpenRouter changes. Pi uses a fresh combined profile
27, preserving both historical profile-24 declarations; Copilot remains
profile 22. Focused protocol checks passed 155 cases (one skipped), the
updated Pi attestation check passed 18 (one skipped), and 91
evaluation/catalog checks passed.

- Latest-application manual continuation passed in 37.942 seconds on
`695e5c005a85bddc8711d3fcddcaf6b7e1fb64d0`, with High effort, native
Opus 5.5, Anthropic API attribution, the same resumed Claude session, an
independently checked 635-byte file and persisted Done status. It uses
the earlier verified Mac daemon; the preceding-source package
qualification passed at `dca62c7aeb4b45f0dd91a8e18d386a16a2658ef8`. That
package run predates the small TypeScript startup fix and is not
relabeled as qualification for it.
- Upgrade limitation: changed compiled sidecar identity rejected old
durable launch state and recovery hit session-open bounds before
eventually resuming. That attempt was operator-cancelled and retained;
the successful manual continuation does not qualify seamless upgrades.

- Local latency profile, Opus 5.5/High unchanged: three alternating
real-ACP loopback samples per variant reduce median provider-ready time
from 5.081s to 4.034s. The matched real API task startup improves from
5.533s to 4.348s, but total reply time changes from 17.933s to 20.221s
because agent work varies. This establishes a startup saving of about
one second, not a consistent total-reply speedup. A real candidate
follow-up passed in 20.146s and resumed the same saved session. The
loopback fixture makes no external model requests; failed initial probes
remain retained.
- The startup change passes 107 focused runtime/effort/lease tests, 53
profile checks (one skipped), TypeScript checking and the
TypeScript-only runtime build. Native hire fixture checks pass 70 tests;
their first local run retained a socket-hangup failure and stale
OpenCode expectation, both accounted for before the passing rerun.
Broader required checks run in cloud CI.

## Risks

- **Experience needs improvement:** successful connection setup still
shows “Connection needs attention” because runtime checks are deferred.
Cold provider-pack upload took 122–126 seconds per run while the task
mainly showed “Thinking.” The tested Core-only preview excludes private
Cloud UI plugins; this is not full Cloud distribution or subscription
qualification. Desktop dark theme was tested; mobile and comprehensive
accessibility were not. The portable report validates, but gallery
interaction could not be inspected because host preview was queued.

- The optional supply-chain scan returned neutral/inconclusive because
GitHub Actions package coverage and infrastructure parsing are
unavailable. It is not counted as a successful supply-chain
qualification. Exact package, daemon and image integrity checks passed.
- A stale, missing or wrong-architecture pack must fail admission. It
must not change runner or target silently.
- Provider-pack source changes invalidate affected earlier execution
results. Existing unknown-cost and cleanup holds remain intact.
- Live subscription execution remains unverified under the API-key
qualification direction. Built-in authentication flows are retained.
ARM64 cloud-image production is deferred. Merge and production
deployment remain separate.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution and browser testing. The exact serving model ID and
context-window size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] Focused local tests and final cloud verification 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-19 14:17:24 -05:00
DottaandPaperclip 45b67f1d93 feat: default new Apple Silicon Claude agents to Paperclip Runner (#15993)
## Thinking Path

> - Paperclip lets users choose an agent harness and account.
> - The server resolves the runner for new agents.
> - Claude still needs the same ordinary native-default journey as
Codex.
> - Existing agents must retain their runner, model and account.
> - This PR defaults new Apple Silicon Claude agents to Paperclip Runner
with Opus 5.5.
> - Users can connect and work without a runner override.

## Linked Issues or Issue Description

Refs #15683. This PR depends on #15994 and precedes #15997. Related
scope: #15422, #13978 and #15224.

## What Changed

- Resolve new Apple Silicon Claude agents to `paperclip_runner`,
`provider: acpx`, `acpxAgent: claude`. Keep explicit Legacy, models,
provider routing and saved execution.
- Use `claude-opus-5-5` for ordinary Claude defaults and retain explicit
overrides.
- Reuse existing API-key/subscription connections, credential storage
and checks. Generalize the shared Advanced runner control with Claude
branding.
- Carry configured effort into the shared v9 contract. Preserve
compatible permissions, instructions, skills, timeouts and session
behavior. Require Legacy for unsupported settings.
- Qualify a new immutable managed Claude target at explicit Connect
through the existing permission-gated probe. Use fresh scoped discovery
for test and hire. Discard stale results and require an explicit Connect
after settings change.
- Retain merged Codex onboarding recovery, auth preparation,
import/effort corrections and Grok Bot gates.
- Check the Claude first-task wizard's saved default directly. Update
configuration/runtime documentation and exact Opus 5.5 accounting.

- Align hire fixtures with the merged host-environment restriction.
Native agent-authenticated hires cannot inject host env settings; both
creation endpoints verify that no extra agent is saved.

## Verification

- Updated onto master `9179d8dcc3e908c217fde4f63c9d08ccf8132eeb` through
#15994. Native input v9 carries effort while preserving v7 home modes
and v8 Muse. Codex defaults remain unchanged.
- Focused local verification passed 285 server tests, 323 UI tests, 124
setup/registry tests, and two v9 permission-pin transport cases. Direct
server/UI TypeScript checks passed. An initial 30-second hook timeout
was resolved by serial verification with a longer hook budget: all 122
credential/permission cases and 232 snapshot/environment cases pass.
Direct server TypeScript checking also passes.
- Ordinary web creation with the experiment disabled saved native
Claude, Opus 5.5 and High effort without runner/model overrides. The
actual product task and follow-up both succeeded on integrated source
`b2c9fe43f9cd3bc5dd9d22552da0148845ba71a4` with the cloud-built daemon
from `04e0202ca81387b17cbe7fd094a8338648356fe9`. The final master
reconciliation also changes shared runtime source. Historical proof
retains its source identity; a final-source cloud qualification is
running before refreshing the preview daemon.
- Both actual browser downloads were checked: v1 has three sections/six
checkboxes (451 bytes); v2 preserves the original body and adds two
Rollback checks (612 bytes). The original attachment stayed
byte-identical. The follow-up records session resume and the same
provider session. Total estimated API usage: $0.518432800, with no
pending/unpriced usage in the successful fixture.
- Fixed the live-discovered setup incompatibility: native API-key
validation no longer depends on the global Legacy Claude CLI. The
existing provider endpoint verifies the key without a paid prompt;
subscription/custom routing probes remain intact.
- Fixed security review's native-hire credential redirection:
agent-supplied URLs, proxy/launch settings and other host environment
controls are rejected before inheritance. Native credential references
remain supported and partial edits use the saved harness. Added
create/hire/update regression coverage.
- Current-head cloud CI is green. All three stack PRs have fresh
Greptile 5/5 reviews and zero unresolved review threads. Required
typecheck, test and build gates ran in cloud CI; Docker work stayed
remote. Earlier failed checks remain in their original runs.
- Docker and native release builds ran in cloud infrastructure. An
inadvertent local Rust prerequisite was stopped; no local Docker build
was run.

- The final master merge preserves task-loading, permission,
skill-retention and OpenRouter changes. Pi uses a fresh combined profile
27, preserving both historical profile-24 declarations; Copilot remains
profile 22. Focused protocol checks passed 155 cases (one skipped), the
updated Pi attestation check passed 18 (one skipped), and 91
evaluation/catalog checks passed.

- Latest-application manual continuation passed in 37.942 seconds on
`695e5c005a85bddc8711d3fcddcaf6b7e1fb64d0`, with High effort, native
Opus 5.5, Anthropic API attribution, the same resumed Claude session, an
independently checked 635-byte file and persisted Done status. It uses
the earlier verified Mac daemon; the preceding-source package
qualification passed at `dca62c7aeb4b45f0dd91a8e18d386a16a2658ef8`. That
package run predates the small TypeScript startup fix and is not
relabeled as qualification for it.
- Upgrade limitation: changed compiled sidecar identity rejected old
durable launch state and recovery hit session-open bounds before
eventually resuming. That attempt was operator-cancelled and retained;
the successful manual continuation does not qualify seamless upgrades.

- Local latency profile, Opus 5.5/High unchanged: three alternating
real-ACP loopback samples per variant reduce median provider-ready time
from 5.081s to 4.034s. The matched real API task startup improves from
5.533s to 4.348s, but total reply time changes from 17.933s to 20.221s
because agent work varies. This establishes a startup saving of about
one second, not a consistent total-reply speedup. A real candidate
follow-up passed in 20.146s and resumed the same saved session. The
loopback fixture makes no external model requests; failed initial probes
remain retained.
- The startup change passes 107 focused runtime/effort/lease tests, 53
profile checks (one skipped), TypeScript checking and the
TypeScript-only runtime build. Native hire fixture checks pass 70 tests;
their first local run retained a socket-hangup failure and stale
OpenCode expectation, both accounted for before the passing rerun.
Broader required checks run in cloud CI.

## Risks

- Missing packages, authentication rejection, unsupported settings and
unavailable models must fail explicitly. Existing agents retain saved
execution; explicit runner changes use existing revision/session
invalidation.
- Subscription follow-up remains unverified; remaining live acceptance
uses API keys per human steering. Historical accounting holds and the
separate $50 ceiling remain intact.
- The subscription acceptance limit remains explicit for review. No
Claude database migration is introduced.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository tools, code
execution and browser testing. The exact serving model ID and
context-window size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] Focused local tests and final cloud verification 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-19 13:58:52 -05:00
DottaandPaperclip 9e8a9f28d5 fix(github): recover long publications from durable receipts (#16883)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents publish GitHub reviews through governed tools.
> - GitHub can accept a publication before the caller receives its
result.
> - Exact retries must return the existing publication receipt.
> - The gateway compared a shortened audit hash with a complete request
hash.
> - Long reviews therefore failed the retry check even when their
content was unchanged.
> - This pull request checks the complete saved publication and returns
its current receipt.
> - Agents can confirm their work without another provider write.

## Linked Issues or Issue Description

Refs #16284, which added durable publication recovery. Refs #16275,
which extended the GitHub tool deadline.

**What happened?**

An exact review retry returned an idempotency conflict after GitHub had
published the review. The invocation hash uses an audit preview that
shortens strings to 500 characters and arrays to 50 entries. The gateway
compared that hash with the complete request hash. The earlier retry
tests used short assessments.

**Expected behavior**

An unchanged request returns its durable receipt. Changed content,
changed authority, or a missing publication must not cause another
write.

**Steps to reproduce**

1. Submit a review with a summary and rationale longer than 500
characters.
2. Let publication finish after a short caller deadline.
3. Repeat the exact request. Before this fix, the gateway returns an
idempotency conflict.

**Paperclip version or commit**

Reproduced on master at `c5226daf7a37559ddc007446681717791d80a223`.

## What Changed

- Use the durable publication's complete request check for GitHub
retries. Keep run, agent, task, connection, tool, and current authority
checks.
- Return the saved receipt through normal gateway validation and
bookkeeping. Leave pending provider work to the durable worker.
- Refuse retries without a saved publication. Keep existing invocation
keys and audit previews unchanged.
- Cover long reviews, comments, progress updates, text suffix changes,
nested coverage changes, pending receipts, missing publications, and
revoked access.
- Document the recovery contract and verification recipes.

## Verification

- Red: both long-review receipt cases failed on unchanged production
code with the expected idempotency conflict.
- Green: all 144 GitHub review workflow tests passed on the final
source. This includes long reviews, comments, progress updates, pending
and missing receipts, revoked policy, and the native assigned-tool entry
point.
- Server and workspace typechecks passed. The production build passed.
- Map checks passed. These are structural checks.
- The first broad run found an incorrect new fixture assumption: its
discovery query returned two review tools. The fixture now selects the
exact submission tool. An existing description-edit polling test also
timed out; it passed separately without a production change, then passed
in the complete 144-test rerun. Both earlier failures remain recorded.
- Final commit `7cdcdc3a1ac79cb4ed77510a32d795228e3315e8` passed all 55
CI checks. Two optional Storybook jobs were skipped. [Complete CI
run](https://github.com/paperclipai/paperclip/actions/runs/39304187397).
Greptile is 5/5 on this exact commit, with zero unresolved review
threads.
- The earlier local full-suite attempt was stopped after the fixture
correction. The final local full-suite attempt was stopped after
complete final-head CI passed. No complete local full-suite pass is
claimed; full-suite acceptance uses the current-head CI matrix.
- Provider responses are controlled fixtures. Native assigned-tool
coverage uses the production gateway and disposable PostgreSQL. No live
GitHub fault injection, deployment, or historical task recovery is
claimed.

## Risks

A pending receipt remains pending. It does not complete the task. Caller
retries no longer dispatch provider work; the durable worker retains
that responsibility. A missing durable publication returns a conflict
because the gateway cannot establish the original write's outcome.
Existing approval and revocation checks remain effective. No database
migration or audit hash change is required.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [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-19 13:54:42 -05:00
DottaandPaperclip c5226daf7a fix(cloud): enable experimental toggles on staging (#16876)
Allow instance admins to change approved experimental feature controls on managed Cloud staging. Preserve production restrictions and managed access and execution policy.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-19 13:04:07 -05:00
Nicky LeachandPaperclip 194fc11406 feat(plugins): invalidate runtimes when tool definitions change (#16604)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Lifecycle plugins must refresh runtime preparation when tool
definitions change.
> - Standing assignments alone do not cover catalogs, profile entries,
or policies.
> - New journal hooks must preserve the order used by setup
finalization.
> - This pull request adds tool-definition invalidation and its required
writer guards.
> - It leaves credentials and provider access changes for the next
independent capability.

## Linked Issues or Issue Description

**What happened?**

Catalog, profile-entry, policy, gateway, and connection-configuration
changes do not request agent runtime synchronization. A new
profile-entry trigger also exposes a deletion/finalization deadlock if
the child row is changed before its parent is locked.

**Expected behavior**

Committed tool-definition changes advance runtime revisions without
polling. Bookkeeping does not. Entry changes and profile replacement use
a consistent parent/reference lock order and commit atomically.

**Steps to reproduce**

1. Change a catalog descriptor, profile entry, policy, or connection
configuration.
2. Expect committed runtime events for the affected agents.
3. Run profile-entry deletion concurrently with setup finalization while
both wait for an agent row.
4. Expect both operations to complete without PostgreSQL deadlock 40P01.

**Additional context**

Extracted from #16503. Catalog publication #16602 and standing
assignments #16603 are merged. This PR is rebased onto master and is the
active review. It addresses the original Apex profile-entry deletion
finding. Credential/access hooks #16605 remain a draft without review
requests.

## What Changed

- Add migration 0355 for application/connection configuration, catalog,
profile-entry, policy, and MCP gateway invalidation.
- Preserve transaction coalescing and ignore health bookkeeping and
trust-rule usage counters.
- Keep credential-only fields outside this migration's coverage.
- Preserve merged recipient scoping for bindings and installations.
Profile-entry edits resolve old/new standing profile bindings. Policy
edits resolve old/new agent selectors with their intersection/list
semantics.
- Lock old and new profile-entry references before parent profiles and
child mutations. Recheck the reference set under the parent lock, retry
changed snapshots up to three times, and merge unspecified fields from
the locked profile.
- Make entry add/edit/delete and profile replacement transactional,
including validation and profile reads on the reserved connection.
- Lock policy rows in ID order and change priorities in one statement so
scoped agent locks are ordered across the full set.
- Lock the managed profile before connection removal deletes its entries
in the same transaction.
- Update assignment tests whose old absence assertions are superseded by
expanded configuration coverage.
- Document the supported capability and the remaining credential/access
boundary.

## Verification

- Final head: `809fcb11794bfb12c545af0a2f96ab9bc2b570a2`. It is rebased
onto master with merged #16623. GitHub reports no merge conflicts. [CI
run
39293925136](https://github.com/paperclipai/paperclip/actions/runs/39293925136)
has 55 successful checks and two optional Storybook skips.
- Standard Greptile returned an independent 5/5. The final Apex review
returned 5/5 on this exact head at 17:47 UTC on 2026-10-19. Its summary
explicitly clears this PR for merge independently of draft #16605. The
security scan passed. All review threads are resolved.
- Two real-PostgreSQL negative controls reproduce `40P01` without the
old-reference guard or the concurrent-snapshot check. Both regression
tests pass with the final correction. Server typecheck, migration safety
and numbering, five-snapshot retention, journal history, feature maps,
and diff checks pass. The actual PR diff was scanned for secrets and
personal data before push.
- The final 15-suite local run passed 821/822 tests. The one failure was
in the unchanged runtime-delivery test: a startup callback changed its
global callback count during an independent transaction. The test-only
correction is isolated in #16871. That PR passes all 17 runtime-hook
tests, server types, hosted CI, and standard Greptile 5/5. Its
notification-disabled control fails at the independent event-delivery
assertion. No changes from #16871 are included here; this feature head
passes hosted CI independently.
- Earlier affected-suite runs passed 814 tests after rebase and 820
tests after recipient and whitespace corrections. Four affected suites
passed 514 tests before the second reference-contention regression was
added. Single-connection tests cover entry add, edit, delete, and
replacement. Validation and profile reads use the reserved transaction
connection.
- Review fixes have negative controls: the old code hangs with a
one-connection pool; parent-lock omissions deadlock entry deletion or
app removal against setup finalization; per-row policy reorder deadlocks
under contention; unscoped triggers journal unrelated peers; default SQL
trimming misses JavaScript whitespace. Corrected cases pass. Selector
tests cover all 25 ECMAScript whitespace characters. Recipient tests
cover repeated edits, old/new targets, ignored bindings, rollback,
coalescing, and company scope. The definition suite now has 28 cases.
- Earlier standard scores that depended on #16605 were not accepted as
independent clearance. The first Apex review returned 4/5 for
replacement versus application deletion. The final correction locks old
and new references, checks the reference set again under the parent
lock, and retries before any mutation. The final independent reviews
clear that correction.
- Preserve prior failures for acceptance: draft run 38975432017 had
failures whose causes were not re-investigated. Run 38990400765 exposed
the unrelated durable-resume watchdog race, fixed in merged #16623. In
run 39287657148, two jobs reported cancellation without a failed-test
summary; the cause remains unknown. Both passed on retry without source
changes. Initial local fixtures and SQL bindings also needed correction:
an internal helper name was replaced with public `archiveConnection`,
unchanged priorities were changed to exercise reorder, a driver
timestamp was bound as ISO text, and a superseded company-fanout
assertion was updated. These recovered checks do not establish a cause
for the unexplained CI failures.
- Local checks target the affected services and real database
boundaries. A full local build and repository-wide test run were not
performed. Hosted CI supplies the broader checks. Provider responses in
tests are controlled; live provider behavior was not qualified.

## Risks

Migration 0355 adds statement triggers without changing table schema.
Apply it through the normal migration flow. A tool-definition event can
advance a runtime revision without changing the bounded assignment
snapshot. Consumers still need authorized readers for definitions.
Credential-only changes, grants, secrets, and endpoints remain for the
access-hook migration. Profile replacement now rolls back as a unit if
any entry fails. Binding and install notifications retain scoped
recipients. Profile-entry changes use standing bindings, and policies
use old/new agent selectors. Unscoped policies, company-bound profiles,
and other conservative definition changes retain synchronous
transaction-atomic company-wide fanout: O(eligible company agents) locks
and journal storage, without a fanout ceiling or mutation quota. This
retains the accepted tradeoff from #16603 for company-wide changes.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository inspection, code
execution, and testing. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 10:56:08 -07:00
Nicky LeachandPaperclip 4d8770f6dd test(plugins): assert runtime delivery by event identity (#16871)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Plugins receive committed runtime events without polling.
> - The delivery test checks that an independent writer is visible after
commit.
> - Startup baseline callbacks can still arrive during that transaction.
> - A total callback count mixes startup work with the event under test.
> - This pull request checks the transaction's specific event ID
instead.

## Linked Issues or Issue Description

**What happened?**

The runtime-delivery test failed during #16604 verification. It expected
one callback before an independent transaction committed, but received
two. The test waits for a total callback count derived before startup
baseline delivery is known to be complete. An older baseline event can
arrive during the transaction and fail that assertion.

The failing test and delivery implementation are unchanged from master.
This PR isolates the test-only correction from #16604.

**Expected behavior**

The event created by the independent transaction is absent from
delivered callbacks before commit. That exact event arrives after
commit. Other committed startup callbacks can arrive at any time.

**Steps to reproduce**

1. Start lifecycle delivery with startup events still pending.
2. Begin an independent agent update after the expected callback count
is first reached.
3. Let a baseline callback arrive before that transaction commits.
4. The old global-count assertion fails even though the transaction's
event is not delivered early.

**Additional context**

Scoped maintenance follow-up for #16604. No runtime behavior or feature
files change here. #16605 remains a draft without review requests.

## What Changed

- Read the new journal event ID inside the independent writer's
transaction.
- Assert that this ID is not delivered before commit.
- Wait for that same ID after commit and check its company, resource,
and type.
- Remove the total callback-count assumption.
- Wait for the company startup baseline, its acknowledgments, and
coordinator idleness. Flush earlier listener notifications with a
barrier, then wait for that barrier wake to settle before the
independent write.

## Verification

- The earlier full feature run passed 821/822 tests and failed this
exact count assertion with two callbacks instead of one. That failure
remains recorded in #16604.
- The failing test file is byte-identical on the reviewed feature head
and master. Neither the profile-replacement correction nor this PR
changes the delivery implementation.
- `pnpm exec vitest run
server/src/__tests__/agent-runtime-hooks.test.ts`: all 17 tests pass
with the event-ID assertion.
- `pnpm --filter @paperclipai/server typecheck`: passed.
- Standard Greptile initially returned 4/5: startup delivery could still
hide a missing independent wake. The correction adds observable startup
acknowledgment, listener flushing, and coordinator idleness. All 17
runtime-hook tests and server typechecking pass with it. A negative
control drops runtime notifications while forwarding the barrier and
fails the after-commit delivery assertion; startup work cannot mask that
loss.
- `git diff --check` and the full PR diff scan for secrets and personal
data passed.
- Full local build and repository-wide tests were not run for this
test-only correction. At `714a74bf0991617c9ad85ce17bae22c533d1ed22`,
hosted CI run 39295664656 passed: all 55 checks succeeded, with two
optional Storybook checks skipped. Standard Greptile returned 5/5, the
security scan passed, all review threads are resolved, and the branch is
mergeable against master. The tests use real PostgreSQL and controlled
plugin callbacks; live provider behavior is not qualified.

## Risks

Test-only change. The commit boundary assertion remains: the new event
ID must be absent inside the transaction and present after commit.
Existing startup callbacks no longer count as early delivery of a
different event. Runtime notification and retry behavior are unchanged.

## Model Used

OpenAI Codex, GPT-6, with reasoning, repository inspection, code
execution, and testing. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 10:55:37 -07:00
DottaandPaperclip 985d3b12b6 fix(runner): explain rejected task monitor arguments (#16868)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use task monitors to resume work after a future check.
> - The runner rejects monitor arguments that fail the tool schema.
> - It returned a generic error with no field or repair guidance.
> - An agent could treat a repairable call as a scheduling outage and
block its task.
> - This pull request adds safe repair guidance and shows the nested
request shape.
> - Agents can correct the call and confirm a saved schedule before they
yield.

## Linked Issues or Issue Description

Refs: #15446, #16686.

**What happened?**

A rejected native `set_task_monitor` call returned `invalid_tool_call`
with only “Paperclip rejected this semantic tool call.” The agent could
not identify the invalid field. A retry could fail again and leave
unfinished work without a scheduled wake.

**Expected behavior**

Reject invalid arguments before any mutation. Give the provider bounded
schema locations and clear repair guidance. A corrected call must save a
monitor and allow one wake without duplicate effects.

**Steps to reproduce**

1. Call `set_task_monitor` with `idempotencyKey`, `nextCheckAt`, and
`notes` at the top level.
2. The schema rejects the call because scheduling fields belong inside
`monitor`.
3. Before this change, the provider received no guidance about the
required shape.

**Paperclip version or commit**

Reproduced against master `35c75b56d4` with a failing Rust regression.

**Deployment mode**

Source checkout. This affects the native runner tool bridge.

## What Changed

- Add monitor-specific repair guidance to the runner's existing safe
schema error path.
- Keep feedback within 512 bytes and omit submitted values and unknown
field names.
- Show the nested monitor request in the production tool description.
Refresh generated contracts and catalog identities.
- Test flat and nested invalid input, private value handling, and
unchanged authorization errors.
- Test rejection, correction with the same key, saved schedule and
audit, receipt replay, and one timer wake with real PostgreSQL and the
native tool authority.
- Update execution documentation and the task verification recipes.

## Verification

- Red/green: the Rust provider error regression failed on master because
monitor repair guidance was absent. It passed after the fix.
- Passed: 29 PostgreSQL monitor and scheduler integration tests. These
use the real tool authority and scheduler, with a no-op process agent
for wake delivery.
- Passed: the native Codex server vertical-slice test. It runs the
rebuilt Runner binary with a fake provider and checks durable results
and session resume.
- Passed: map structure checks, Rust formatting, and `git diff --check`.
- Passed locally: full repository `pnpm -r typecheck`, `pnpm build`, and
all 392 Rust library unit tests.
- Passed on commit `3b667ad24763c1828edd48f56ef7a10766aeb946`: [CI run
39290889768](https://github.com/paperclipai/paperclip/actions/runs/39290889768),
including all server, Runner, serialized, browser, typecheck, build, and
canary gates. Across the PR, 56 checks passed and four conditional
checks were skipped. No check remains pending or failed.
- Greptile: 5/5 on that exact commit. The check concluded success, with
no review comments or unresolved threads.
- The duplicate local `pnpm test:run` attempt did not complete. It was
stopped after the full CI suite passed; it is not counted as a local
full-suite pass.
- The first PostgreSQL attempt could not bind localhost inside the shell
sandbox. It passed with normal localhost access. The first broader Rust
attempt had 37 socket-permission failures and 355 passes; all 392 passed
with localhost access and no code change.
- Live model recovery was not run. Local execution policy did not
authorize an extra acceptance run through the signed-in provider
account. This PR does not include a deployment or recovery of an
existing task.

## Risks

- Error feedback must not reveal submitted values. Tests cover private
values, unknown keys, nested constraints, length bounds, and unchanged
generic authorization errors.
- This changes guidance only. It does not relax the schema, retry calls
automatically, or change scheduling authority.
- A new runner binary and refreshed provider contract must reach the
target instance before agents receive this guidance.

## Model Used

OpenAI Codex, GPT-6, with reasoning, tool use, and code execution. The
exact runtime 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-19 12:37:28 -05:00
DottaandPaperclip 3e5a9f5afe perf(ui): load recent tasks with bounded summaries (#16851)
Replace passive recent-task detail reads with bounded, authorized summaries. Keep account isolation, stored history, task actions, and live recovery behavior.

Overlap access checks with shell settings and avoid duplicate session and health reads on the first healthy socket opening. Retain domain reconciliation.

Add focused coverage and local performance evidence. Isolate the existing cache capacity test from entry expiry on slow CI runners.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-19 12:13:28 -05:00