Commit Graph
6096 Commits
Author SHA1 Message Date
DottaandPaperclip 2b2b5a43b7 fix(daytona): restore the recorded directory for file recovery (#18527)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A stopped sandbox can hold workspace files that still need a durable
copy.
> - File recovery must reopen the exact allocation and directory
recorded by the run.
> - Workspace preparation can place that directory below the allocation
root.
> - Daytona resume returned the allocation root even when recovery
needed the recorded child directory.
> - This pull request lets the file-recovery owner request that exact
directory.
> - Ordinary resume keeps its allocation-root behavior. The recovery
source checks stay strict.

## Linked Issues or Issue Description

**What happened?**

A stopped native run had a prepared remote workspace. The recovery
service stopped and retained its allocation. The next file-recovery step
failed with `source_binding_invalid` and `reopened_cwd_mismatch`.
Daytona resumed the correct allocation and matched its sentinel, but
returned the allocation root instead of the workspace directory recorded
on the lease.

**Expected behavior**

The file-recovery owner must reopen its exact recorded directory without
creating an allocation, an empty directory, or an agent turn. Ordinary
execution resume must keep returning the allocation root for normal
workspace preparation.

**Steps to reproduce**

1. Prepare a task workspace below a Daytona allocation root.
2. Stop and retain the allocation with unsaved workspace files.
3. Request source-bound file recovery.
4. Before this change, the provider returns the allocation root and the
strict cwd check rejects it.

**Paperclip version or commit**

Reproduced from `050365e09d88411960fc3bacc1c08c46c0d9b6fa`.

**Deployment mode**

Docker with the bundled Daytona provider. Local tests use synthetic
provider boundaries and disposable PostgreSQL.

Refs: #18517, #15749. Related retained-export work: #17916. That work
does not change the Daytona resume handler.

## What Changed

- Add an optional driver-only `requestedCwd` resume field to the SDK
contract and existing host forwarders.
- Set the field only after the owned file-recovery path verifies the
recorded source.
- Require Daytona to match the requested directory to the recorded lease
directory. Require a normalized absolute path without NUL bytes. Keep
the allocation and sentinel checks.
- Keep ordinary resume unchanged when the field is absent.
- Add provider, host, and real workspace-preparation regressions.
Document the separate directory contracts.

## Verification

- The original provider regression failed for reusable and ephemeral
leases. The scoped regression also failed to read a real retained file
from the wrong root. Ordinary resume controls passed before the fix.
- Current provider handler: **345/345 passed**. This includes
exact-directory, malformed, missing, foreign, sentinel, reusable,
ephemeral, ordinary-root, and real-file cases.
- Removing only the owned producer's cwd request makes its real
PostgreSQL regression fail with the original `reopened_cwd_mismatch`;
the source file was restored exactly afterward.
- Current host selection: **10/10 passed** against disposable PostgreSQL
17. It covers the inspected owner, sandbox forwarding, generic plugin
forwarding, normal resume without the field, same and later task
workspace preparation, and ownership rejection. The same-workspace
control retains saved bytes and does not append another workspace path.
- Current SDK and Daytona builds, server build, module boundaries, maps,
and diff checks passed. The server used its normal unchanged-Runner
cache. Its canonical input digest matched the previously verified build,
and the canonical assessor accepted the copied original stamp and
outputs. The changed SDK and server compiled from current source.
- Local package-wide validation exposed two unchanged 30-second timeouts
in the 145,000-member tar-listing cases. A single-file control
reproduced both timeouts. That test mocks this provider module. The
failures remain recorded; no timeout changed. The earlier package run
had 497 passes, two failures, and seven skips. It is historical evidence
from the abandoned broader resume experiment, not final-source package
acceptance.
- Initial host attempts timed out during database setup before any
assertion. The final host selection used the existing supported
pre-migrated disposable template. No test timeout changed.
- Greptile reviewed exact head
`8d0e577d1234ad394887255f13707c010dee6d24`: **5/5, no actionable issues,
zero review threads**. [Current
review](https://github.com/paperclipai/paperclip/pull/18527#issuecomment-6555253315).
- The official [Ponytail
review](https://github.com/paperclipai/paperclip/pull/18527#issuecomment-6555237850)
also assessed exact head `8d0e577d1234ad394887255f13707c010dee6d24`:
**5/5, no findings**. Its check is terminal neutral; its completed
source assessment is not a test-execution claim.
- [Primary
CI](https://github.com/paperclipai/paperclip/actions/runs/41286802674)
initially lost its spot runner in the UI/CLI workspace lane. The log
records an explicit shutdown signal and no test assertion result. UI,
CLI, lane scripts and dependencies are unchanged; the adjacent
identical-source baseline lane passed. The single failed-lane retry
passed at the same source. The initial failure is retained. All
exact-head CI gates are now green.
- No live repair or image deployment is claimed by this PR.

Commands:

```sh
node packages/plugins/sandbox-providers/daytona/node_modules/vitest/vitest.mjs run --config packages/plugins/sandbox-providers/daytona/vitest.config.ts packages/plugins/sandbox-providers/daytona/src/plugin.test.ts
node node_modules/vitest/vitest.mjs run --project @paperclipai/server server/src/services/workspace-recovery.test.ts server/src/__tests__/environment-runtime.test.ts -t 'recovers a protected retained source|owned export directory|prepares the (same|later) task workspace|does not reopen a retained source|resumes only the exact stopped sandbox lifecycle|explicit export directory'
pnpm -C packages/plugins/sandbox-providers/daytona build
pnpm --filter @paperclipai/server build
node scripts/check-module-boundaries.mjs
node scripts/check-maps.mjs
git diff --check
```

## Risks

- A provider that does not support the optional field can still return a
different directory. Recovery keeps failing closed on that mismatch.
- Ordinary resumes omit the field. The tests cover the same workspace
and a later task so that normal preparation does not gain an extra path
prefix.
- The field grants no source ownership, stop proof, file-persistence
proof, or execution authority. Existing allocation, company, task, run,
claim, and cwd checks remain in force.
- No schema migration, retry-policy change, model replay, or
historical-row repair is included. Existing failed attempts remain
historical facts. Deployed file recovery still needs its normal
admission and independent persistence and physical-stop receipts.

## Model Used

- OpenAI GPT-6 through Codex. Used reasoning, source inspection, tool
use, and code execution. The exact serving model identifier and context
window are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-01 02:47:30 -06:00
DottaandPaperclip 7e595fd055 test(e2e): verify native hiring, delegation and teammate reuse (#18351)
## Thinking Path

> - Paperclip manages real work by AI agents.
> - Daily QA must verify that work on the staging deployment.
> - Classic Agent Chat coverage already exercises hiring and teammate
reuse.
> - The deployment journey should share that behavior and its ownership
oracle.
> - Saved documents, exact callback replies and physical cleanup
establish success.
> - The corrected journey and complete daily suite now pass on QA.

## Linked Issues or Issue Description

**Subsystem affected**

Product E2E deployment journeys and their shared browser controls.

**Problem or motivation**

QA must prove that one newly hired teammate completes two different
tasks and returns both saved results to the lead conversation. Names,
chat claims and successful-run counts alone cannot establish authorship
or completion.

**Proposed solution**

Reuse the classic hiring oracle and production composer. Verify
immutable creation audits, initial assignment, current project and
ownership, saved document revisions, exact native authors, durable
callbacks and their own task links after reload. Bound execution to five
lead turns and two child turns.

**Alternatives considered**

A separate QA implementation would duplicate the classic journey. Name
matching or later reassignment would accept broken initial ownership.
Links elsewhere in the conversation cannot substitute for either
callback's own result link.

**Roadmap alignment**

This verifies existing features. Related merged repairs: #18389, #18465,
#18459, #18463, #18502, #18503, #18504, #18506, #18507 and #18514.
Separate dependency #18517 repairs file preservation after lifecycle
cancellation and is merged as Core `050365e`, which also contains
#18514. This primary PR now differs from that protected mainline in only
16 unchanged H harness/documentation paths; it adds no application
production delta. The measured QA deployment serves Core `050365e`, with
its matching bundled provider pack and unchanged approved model/ROM.

## What Changed

- Add the shared `hire-delegate-reuse` journey, catalog, types,
dispatch, launch fingerprints, journey-feature entries and
documentation. Hire one teammate, delegate a checklist, then reuse the
same teammate for a saved review. Require seven canonical native runs:
five lead and two child turns.
- Require exact company, lead, chat and native creation receipts. Both
tasks must be created for the intended teammate using immutable
creation-audit assignee fields. Independently verify current project and
ownership. Creation-time project is not recorded in that audit and is
not claimed by this assertion.
- Verify both current document revisions belong to the exact child runs
and preserve the original checklist.
- Use ordinary production rich-editor agent/project autocomplete
controls. Verify exact reference chips, then send once. Preserve the
shared default sender.
- Require each durable, run-owned callback reply to contain its own
exact completed-task link. Collect links through the actual production
Markdown renderer and issue-reference decoration, then apply the
existing company-scoped route authority. An unrelated table or code
fence cannot hide a rendered link; foreign, wrong-task and code-only
links remain failures.
- Preserve approved connection, account, grant and responsible-user
attribution. Verify the child's independent installation and retain the
immutable binding snapshot. Do not copy credentials or broaden grants.
- Record ownership before later observations can fail. Retry only typed
transient observation GET failures. Preserve authority and cleanup
failures.
- Retain all 14 daily journeys, the model matrix, deadlines, seven-run
cap and 500-cent aggregate allowance split 300/200.

## Verification

- **Current composed head:** `afa3f5552ab0c1a9f0ee7327dfa5665d57cc7bcb`.
It normally merges mainline `1e8e322` and exact #18517 source `adb1d4e`,
retaining the intermediate `b2d9eb4` and `6fd1042` ancestry. The only
merge conflict was the Playwright support registration; it is resolved
to the exact previously qualified union. All 16 H harness/documentation
paths are byte-identical to `5c0830f`; all four #18517 paths are
byte-identical to `adb1d4e`. Every other tracked path matches actual
protected mainline `050365e`. A clean merge preview of `050365e` and
this head equals the current head tree, so no additional source commit
is needed. GitHub's three-dot display still lists the four already
merged helper files because #18517 used a squash merge; those blobs
equal protected mainline and add no net application change. No journey,
oracle, cap or model change accompanies this composition. A final clean
merge preview on intervening mainline
`006d5691a6245d5a710e25ba3df6d609754e163a` preserves all unrelated
changes and adds exactly the same 16 measured H blobs, with no net App
production delta. That later mainline is not represented as the AppCore
measured by the QA run.
- **Local qualification:** 149/149 focused tests across six suites,
including the report-catalog case, and 11/11 real Chromium checks passed
on `b2d9eb4`. All H modules, browser inputs and parser/package
dependencies are byte-identical at `afa3f55`; those unchanged suites
were not repeated. Current-source transitive types, maps, module
boundaries and diff checks pass. Official Node24 QA runtime imports pass
again using exact public `afa3f55` and private `8671fa9`, with a clean
credential-free environment and network disabled. The initial local
report-catalog failure is retained: the child `tsx` process was denied
its local IPC socket before importing the report or writing an artifact.
The same source and selected case pass after correcting only sandbox IPC
permission; no source workaround or deselection was used.
- **Current canonical CI and reviews pass.** [CI
41275109691](https://github.com/paperclipai/paperclip/actions/runs/41275109691)
completed successfully at exact `afa3f55`: all 59 contexts are terminal
and clean (55 success, three skipped, one neutral). Fresh exact-head
Greptile and official Paperclip reviews both scored 5/5; all 27 review
threads are resolved with pagination complete. The official review is
static and its check is neutral; it did not execute tests or live QA. A
separate exact-head independent composition assessment found no
actionable issues at 4/5 confidence and performed no live actions.
**Fresh QA qualification passed: all 14 daily journeys, including the
corrected H7, passed against deployed Core `050365e`.** Prior check
conclusions and review scores retain their actual heads. The previous
`5c0830f` completed all 59 contexts cleanly, actual exact-head Greptile
and official Paperclip reviews both scored 5/5, and all 27 review
threads were resolved. Its separate independent journey-source review at
`2b803f08` remained 4/5 with a unit-helper authorship caveat.
Intermediate `b2d9eb4` received an actual exact-head Greptile 5/5 with
zero open findings, then was updated to compose the valid dependency
review fix before live QA. That score and its pending CI are not
attributed to `afa3f55`.
- Existing causal controls remain unchanged: invalid immutable assignee,
either missing callback link, foreign/code/wrong-task links and an
earlier handoff fail against the relevant prior source. Renderer
controls prove that tables and fenced code elsewhere in a valid callback
do not hide its actual task link. Both composer and document-navigation
browser registrations remain present.
- #18503 merged after its actual QA document case passed four canonical
checks and five phases, positively established zero native work, and
completed cleanup. Its measured files are unchanged in this composition.
#18506 and #18507 merged after their own checks; their causal
worker-settlement controls remain intact.
- #18514 is merged as `1e8e322`. It reproduces the selected-task
metadata-only-project startup failure against deployed `756599e` and
passes 19 real-PostgreSQL selected controls after repair. Both direct
and assembled baseline controls fail before it. Real source, explicit
selection, policy and workspace-isolation guards remain enforced. It is
included in measured Core `050365e`; fresh H7 reached and completed both
delegated native tasks.
- #18517 initial source `6fd1042` passed 320/320 focused and sibling
Stop/recovery tests, including 20 preservation controls. Its actual
official review was 4/5 and found a valid follow-up: the new
live-controller guard should wait for actual lease expiry rather than
repeat locked checks every 30 seconds. Both an already-live lease and a
real under-lock renewal reproduce that issue against `6fd1042`.
Corrected source `adb1d4e` passes all 22 preservation controls and 124
directly affected tests across three suites, exact-head server
build/stamp, typecheck and structural checks. It defers before locking
and rechecks renewed expiry afterward, preserving the transactional
owner guard. The old score/failure and successful owner tests remain
attributed to their actual sources. Independent exact-head review of
`adb1d4e` found no actionable issues at 4/5 confidence. This is
local/source evidence, not physical QA recovery. Its current [CI
41274963476](https://github.com/paperclipai/paperclip/actions/runs/41274963476)
completed successfully with all 59 contexts clean; both actual current
reviews are 5/5 with zero unresolved threads. It merged normally as
`050365e` after those gates. QA now runs that image. The historical
allocation is positively stopped and retained; its files-only export
remains a separately tracked repair, not a passing-test assertion.
- The historical [first H7
pass](https://pages.paperclip.ing/evals-qa-smoke-41226065043-1/) remains
attributed to public `5d3f143`, private `dabad62` and App `b7f1c37`: all
checks and five phases passed, seven native runs succeeded, both saved
documents and exact callbacks were verified, and physical cleanup
completed. An optional runtime-metadata receipt was inconclusive and was
not grade authority.

Material failed attempts remain failed:

| Attempt | Actual result and correction |
| --- | --- |
|
[41231853638](https://pages.paperclip.ing/evals-qa-smoke-41231853638-1/)
| 13 passed; hiring omitted initial teammate/project assignment and
started extra work. The production composer repair retains the ownership
negative. Later recovery stopped physical work without changing the
failed grade. |
|
[41238711372](https://pages.paperclip.ing/evals-qa-smoke-41238711372-1/)
| All seven native runs succeeded, but the final callback had no durable
chat reply. Cleanup passed. #18502 repairs premature completion-outbox
retargeting; the fresh measured H7 now verifies both durable, run-owned
callback replies and their own task links. |
|
[41253428446](https://pages.paperclip.ing/evals-qa-smoke-41253428446-1/)
| 12 passed; hiring rejected a mentioned metadata-only project before
delegation, and document reopening hit an immediate-control-probe race.
#18504 and #18503 repair those separate boundaries. Historical
missing-task absence remains quarantined; physical termination does not
manufacture absence evidence. |
|
[41266385118](https://pages.paperclip.ing/evals-qa-smoke-41266385118-1/)
| On `5c0830f` and App `756599e`, 13 passed, including the exact
composed document helper. Hiring created the correctly assigned task,
but its child admission failed before runtime selection because the
organizational project had no repository source. #18514 repairs that
selected-task boundary. The cancelled native lead retained an active
prepared-workspace lease; cleanup 41271035231 failed with
`owned_work_stop_unconfirmed`. #18517 addresses its file-preservation
admission. Launch 1110, original evidence and automatic Slack FAIL
remain failed. |
| [CI
41257779002](https://github.com/paperclipai/paperclip/actions/runs/41257779002)
/ [CI
41263476916](https://github.com/paperclipai/paperclip/actions/runs/41263476916)
| Existing enrollment and snapshot-retention fixtures observed
intermediate I/O before worker settlement. #18506 and #18507 have
controlled causal failures, complete-settlement observers and preserved
deadlines/negative controls. Runtime scheduling behavior is unchanged. |

**Fresh measured acceptance:** [QA run
41285131220](https://github.com/paperclipai/paperclip-cloud/actions/runs/41285131220)
and its [permanent
report](https://pages.paperclip.ing/evals-qa-smoke-41285131220-1/)
passed **14/14**, zero failed or incomplete, with all five phases and
complete cleanup for every case. The strict verifier independently
matched original grades, current provenance and completed manifests:
public harness `afa3f5552ab0c1a9f0ee7327dfa5665d57cc7bcb`, private
workflow `8671fa93e27501fabbfffa377bec6dea453b5db7`, AppCore
`050365e09d88411960fc3bacc1c08c46c0d9b6fa` and matching Cloud
image/provider pack. All model, ROM, deadline and run-budget controls
remained unchanged. All three workflow jobs completed successfully; the
automatic Slack notification reported PASS with links to this run. The
passing TestOps launch was closed normally after evidence verification.

The hiring case passed all 11 check entries across nine IDs and five
phases, with exactly five lead and two child native runs. Both saved
documents match their live current revision/body hashes and exact
hired-agent run attribution. The immutable original checklist remains
intact; the same teammate authored the review. Both own callback replies
contain their exact delegated task link. Independent canonical readback
confirmed all seven native runs succeeded and committed their accepted
result, assessment and decision, with no live owner and zero pending or
failed effects; each of the seven exact owned leases has its own bound
DESTROYED receipt and successful cleanup. All seven final snapshot
operations match their source run, workspace, task, epoch, SHA,
generation and export location. The four earlier lead snapshots are
retained SUPERSEDED ancestors of the current committed snapshot; the
latest lead and both child snapshots are COMMITTED. The initial
diagnostic required current COMMITTED status for every historical
snapshot and correctly remained false until the separate lineage
diagnostic established this supported supersession. The product oracle
and original grade were not changed. Canonical Suite metadata is
`qa-basics`; the daily plan was saved with its standard suite-only query
and synchronized, retaining all 14 ACTIVE cases.

The older failed allocation remains separately stopped, retained,
isolated from reuse and owned by terminated actors. That permits fresh
campaigns without replaying old work. Its same-allocation files export
is still unresolved and has separate bounded files-only recovery work;
it is not claimed by this successful campaign. Original failed grades,
reports and automatic FAIL notifications remain unchanged. No failed
result was closed, relabelled, hidden or retried unchanged to obtain
green.

## Risks

The journey requires Agent Chat, normal hiring permission, a scoped lead
and a provider that finalizes owned resources. Missing or extra work,
wrong ownership, absent saved documents, missing callbacks and
unconfirmed cleanup must fail.

The deployed app and bundled runner pack must match the verified Core.
The old run's cancellation ACK and terminal database row do not prove
physical termination or saved files. Its coordinator has no accepted
result or decision; pending-effect absence cannot be inferred from that
missing decision. File recovery must preserve the exact allocation and
original destroy disposition without a provider turn.

Current source checks, reviews, fresh H7 and full-14 aggregate all pass.
Canonical Suite metadata and actual 14-case daily-plan synchronization
were verified after closing the genuine passing launch. The original
failed allocation still has a separate files-export debt; its STOPPED
receipt is not a SAVED or DESTROYED claim.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
backend model ID or fixed context window. Used reasoning, repository
tools, TypeScript and browser test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change 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
- [x] Historical passes and material failed attempts retain their actual
source and outcome
- [x] The composed document helper passed normal QA with complete
cleanup on its actual source
- [x] The corrected hiring journey passes fresh normal H7 with complete
cleanup
- [x] The active hiring case has canonical Suite and daily-plan
membership after the passing launch is closed

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-01 02:33:59 -06:00
DottaandPaperclip 006d5691a6 feat(server): support volume-free web server handoff (#18518)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Its web server also owns controller admission and user commands.
> - A rolling deployment starts a replacement before the old server
exits.
> - Shared database state alone does not preserve local agent files,
browser chunks, or in-process commands.
> - This pull request adds an opt-in ephemeral server contract and a
local overlap test.
> - The benefit is a web server that can relinquish traffic and local
files without losing acknowledged work.

## Linked Issues or Issue Description

Refs #18403, #18327, #18335, #18341.

**Current behavior**

The control-plane web server still has local agent-file authority and
local command targets. A new container can miss saved bytes or send a
command to the wrong process. An existing browser tab also needs chunks
from its original build.

**Proposed behavior**

Eligible servers share only PostgreSQL, object storage and stable
secrets. A replacement waits for readiness. The old server drains
admitted requests, keeps owner commands available through handoff, and
releases controller leases. Explicit maintenance adopts existing files
before the volume is removed.

**Reason and benefit**

This is the application prerequisite for rolling app-only deployments.
Schema migrations and permanent multi-replica operation are outside this
change.

## What Changed

- Store agent-file manifests in PostgreSQL and immutable bytes in S3.
Treat local roots as disposable projections. Preserve existing
permission checks and edit conflicts.
- Add an explicit migration, eligibility and object-retention command to
the production runtime bundle.
- Add `/api/ready`, admitted-request drain, browser restart signaling
and retained immutable UI chunks.
- Carry transaction-aware work hints across controllers during handoff
and active execution. Keep listeners closed when idle.
- Deliver durable Stop and runtime responses to the execution owner.
Recheck request lifecycle and access before response dispatch.
- Reject local-only configuration in ephemeral mode. Keep the feature
disabled for existing installations by default.
- Add an isolated PostgreSQL/S3/proxy/browser deployment harness with
independent server homes and retained failure evidence.

## Verification

- All CI checks pass on `ce17b95019d3cf1cabd357d19b6d37f96782cc5c`:
workspace typecheck, build, Runner checks, server/general tests and
browser shards. Greptile reviewed the runtime changes at 5/5 with all
findings resolved; the final commit updates maps and the plan.
- Local targeted checks passed: coordinator 27; Stop/recovery 33;
PostgreSQL command delivery 6; route/workspace regressions 8; bootstrap
Stop 1; restart recovery 75. PostgreSQL command tests simulate the
provider edge.
- Local browser proof passed 91 reads and 19 saves; reconnect took
1,013ms. The tab opened Audit from S3 after deletion of A's whole
home/build. This uses compiled workspace code and local-trusted auth,
not released containers or live agents.
- Local workspace typecheck/build passed; current server and runtime
bundle passed. The earlier broad local suite was stopped after three
hours and is not a passing receipt. Its retained failures and isolated
reruns are documented in the plan.
- Stacked #18526 adds stricter graceful-exit proof, an unready
replacement control, live Runner qualification and a Stop handoff
correction. Hosted enablement remains gated on those results and Cloud
#1096. No hosted stack has been enabled.

## Risks

- Apply migration 0422 before enabling the feature. Existing data must
pass each owner's migration and eligibility checks. Do not discard a
volume based on a single migration page.
- Durable manifests remain authoritative after the opt-in is disabled.
Rolling back to a binary that ignores them is unsupported.
- Cold directory restoration and complete shutdown timing still need
qualification before enabling a hosted stack.
- Retained UI assets must cover the supported browser and rollback
window. Cleanup is explicit; no new idle maintenance polling is
introduced.
- This change does not claim production zero downtime or authorize a
fleet-wide enablement.

## Model Used

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

## 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>
nightly/v2026.1101.0-nightly.0 canary/v2026.1101.0-canary.6
2026-11-01 01:58:54 -06:00
DottaandPaperclip 050365e09d Preserve native workspace files after lifecycle Stop (#18517)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent termination must stop execution and preserve unfinished
workspace files.
> - A native run can acknowledge a lifecycle Stop, then finish without
an accepted result.
> - The file preservation worker required a board actor even when the
exact native Stop receipt was valid.
> - This left a prepared remote workspace allocated without a file
recovery action.
> - This pull request admits the exact audited receipt for file
preservation only.
> - The existing recovery service can then save the files and stop the
same allocation without another agent turn.

## Linked Issues or Issue Description

**What happened?**

A cancelled native run can have a terminal, unowned coordinator and a
prepared remote workspace. Agent lifecycle cancellation records a valid
run-only Stop receipt without a board user. The preservation worker
rejects that receipt because it uses the board Stop predicate. The
source lease remains active. A resolved execution watchdog does not
supply the missing file recovery action.

**Steps to reproduce**

Seed a cancelled native run with a terminal-failure coordinator, no
result or owner, an acknowledged and audited run-only Stop, and a
prepared remote workspace. Omit board attribution. Start the registered
cancellation preservation worker. Before this change, it records no
workspace recovery marker.

**Expected behavior**

Record file recovery for the exact bound allocation. Keep the cancelled
result, accounting, task state and watchdog history. Use the normal
recovery service to stop, save and clean up that allocation without
another provider turn.

**Paperclip version or commit**

Reproduced on source `1e8e32290c657227857aeda2620a73db52bab4f2` with
real local PostgreSQL 17. The observed deployment uses a sandbox
provider and remote workspace storage. Related current workspace work:
#18514. Public PR and issue searches found no duplicate repair.

## What Changed

- Expose the existing exact run-only Stop receipt check. Reject empty
audit identifiers.
- Use that receipt only in cancelled workspace preservation. Keep board
Stop and continuation checks unchanged.
- Defer preservation while the run still holds a live controller lease.
- Schedule that wait at the actual controller lease expiry. A lease
renewal observed under the preservation lock also sets the next
deadline.
- Add a PostgreSQL regression for the remote-workspace-only lifecycle
record, resolved watchdog history, normal recovery admission, ownership
controls, rollback and idle behavior.
- Document the separate file recovery obligation and its physical
cleanup limits.

## Verification

- Before the fix: the registered-worker PostgreSQL regression fails
because the file recovery marker is absent.
- After the original repair at `6fd1042efd`: 20/20 focused tests and all
five sibling suites pass, 320/320 tests. The exact-head server build and
typecheck pass.
- The repository reviewer then found that a live controller caused a
fixed 30-second retry. Both the existing-lease and real row-lock renewal
cases fail against that source. The new
`adb1d4eccdd48be4c86906d5bd111a6e39f20191` schedules the actual recorded
deadline before locking and after the locked reread. The lock still
enforces the ownership guard.
- At `adb1d4eccd`: all 22 focused PostgreSQL controls pass. The directly
affected retention and board receipt sibling suites also pass, 124/124
tests across three files. They prove no intermediate reads or
transactions before expiry, preservation after expiry, and no extra
execution. Server typecheck and the exact-head server build pass.
- Map checks, module boundary checks and `git diff --check` pass.
- Run `pnpm exec vitest run
server/src/services/native-runtime/native-cancelled-workspace-preservation.test.ts
server/src/services/native-runtime/native-failed-workspace-recovery.test.ts
server/src/services/acknowledged-native-stop.test.ts` with the supported
external test-database variable set to a disposable local PostgreSQL
database. The earlier broader run also covered run control and workspace
recovery.
- Exact-head [canonical
CI](https://github.com/paperclipai/paperclip/actions/runs/41274963476)
completed successfully. All 59 current-head checks are terminal with
zero failures; required `ci / verify` and `ci / e2e` pass. Both
[Greptile](https://github.com/paperclipai/paperclip/pull/18517#issuecomment-6553528545)
and the [repository
assessment](https://github.com/paperclipai/paperclip/pull/18517#issuecomment-6553542139)
reviewed exact `adb1d4eccd` at 5/5, with zero findings or unresolved
threads. The repository assessment's check concludes `NEUTRAL`; the
validated assessment itself is 5/5. Earlier reviews, including the valid
4/5 deadline finding at `6fd1042efd`, remain in review history. The
[earlier CI
run](https://github.com/paperclipai/paperclip/actions/runs/41273965963)
is also retained. No old result substitutes for a current-head gate.
- Real sandbox recovery and physical cleanup remain unverified. Earlier
failed QA outcomes remain failed. This PR changes no test grade or
historical row.
- Repo-wide local tests and typecheck were not run. The focused server
checks cover this change; canonical CI supplies the remaining repository
gates.

## Risks

- The newly admitted receipt permits only file preservation. It cannot
authorize a continuation, accept a native result or certify provider
termination.
- Recovery still requires exact company, task, run, lease, allocation
and workspace bindings. Accepted results and live owners remain with
their existing owners.
- Provider or storage failure can leave recovery pending. The source
must remain retained until saved-file and physical termination receipts
exist.

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

## Model Used

- OpenAI GPT-6 through Codex. Used reasoning, source inspection, tool
use and code execution. The exact serving model identifier and context
window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1101.0-canary.5
2026-11-01 00:17:46 -05:00
DottaandPaperclip 1e8e32290c Give metadata project tasks private remote workspaces (#18514)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A task can belong to a project without using that project's files.
> - The specification gives a task without a selected or configured
source its own private folder.
> - The remote source planner instead rejects such a task when its
project has no configured workspace.
> - This stops an ordinary delegated task before native execution
starts.
> - This pull request selects an empty, task-owned remote source for
that narrow default case.
> - Explicit source choices, existing workspace authority, and
repository requirements retain their current checks.

## Linked Issues or Issue Description

Refs #18504 and #18351. The earlier reference-project fix covered
additional project mentions. This fix covers the task's own
organizational project.

**What happened?**

A task in a project with no configured workspace fails with
`remote_workspace_source_unavailable`. Its project has no workspace
policy, its four workspace selection and binding fields are null, and it
requests no repository, branch, or local folder. The failure occurs
before native runtime selection. A derived project folder exists in the
project facade even when no source is configured; that derived path does
not grant file access.

**Expected behavior**

Use the task's private remote workspace. Keep the project on the task
for organization. Do not adopt the project folder, agent home, or
another repository. Preserve explicit workspace and source requirements.

**Steps to reproduce**

1. Create a project without configured workspaces or a workspace policy.
2. Assign a normal task in that project to a native sandbox agent. Leave
all workspace selections and bindings unset.
3. Start the task with remote workspace storage enabled.
4. On the prior source, observe the source-unavailable error before
allocation. On this source, observe a company-owned remote workspace
whose `sourceIssueId` is the task and whose filesystem project and
source IDs are null.

**Paperclip version or commit**

Reproduced against the deployed source planner at
`756599e4ea069c9338c320fe8846523d3dfb92a0`. This branch starts at
`987e0932bf66e703750cd04698b3c7e8993580a7`; the relevant planner and
preparation inputs at that parent match the deployed source.

**Deployment mode**

Native sandbox execution with remote workspace storage. The regression
tests use real PostgreSQL with the current migrations.

## What Changed

- Allow an implicit empty source only after a company-scoped query
confirms the project has no workspace rows and no explicit workspace
policy.
- Keep existing bindings, pending selections, explicit source choices,
Git requirements, and local folder choices outside this default.
- Add real PostgreSQL source controls and an assembled heartbeat
preparation control through workspace reservation and the environment
acquisition boundary.
- Clarify the existing task-owned folder contract in the implementation
specification.

## Verification

- Causal RED: the new source control and the assembled allocation
control both fail against the unchanged deployed planner with the
observed source-unavailable error.
- GREEN: 19 focused PostgreSQL controls pass across the source planner
and assembled heartbeat preparation suites. The allocation control
checks the persisted company/task owner, null filesystem project IDs,
private remote root, original organizational project, and unchanged
project and host sentinel files.
- Negative controls retain configured repository sources and reject a
configured source without a URL, an explicit missing source, an unknown
selection, a required project policy, a required branch, an explicit
local folder, a foreign project, and unsupported read-only project
sources.
- Current-source transitive TypeScript checks and `node
scripts/check-maps.mjs` pass. The map check is structural evidence only.
- Fresh exact-head Greptile is 5/5 with zero unresolved threads at
`680461e180232d0f4a057528617e39b64b4f0e3a`.
[Review](https://github.com/paperclipai/paperclip/pull/18514#issuecomment-6552946468).
The official [Paperclip
assessment](https://github.com/paperclipai/paperclip/pull/18514#issuecomment-6552931726)
is 4/5 and remains recorded unchanged. A separate non-author source
review found no actionable issue after the full producer/consumer trace,
with manual confidence 4/5. Neither static review ran the tests or
proved deployed native execution.
- Full repository tests, build, and type checks passed in [canonical
CI](https://github.com/paperclipai/paperclip/actions/runs/41269733360).
All 59 checks are terminal: 55 success, three skipped, and the official
Paperclip check neutral; no failed or pending checks. The successful
build checked out merge preview
`03dce9f9bc708e778dd214ca85dfa1ba58e0a806`, with parents current main
`9dbbfa4fb298448db83ace946b338bff321d8b2a` and this exact head. Its four
helper blobs match this head; the four added mainline document-harness
paths remain unchanged. Local tests use source aliases with the current
DB, shared, and Runner source, rather than borrowed generated
declarations.
- Actual QA staging qualification is pending deployment. The previous
failed journey and cleanup evidence remain failed; these local checks do
not relabel them.

### Review follow-up

- Fresh workspace retry: the normal producer sets `taskDirectory:true`
for this empty-source case.
[Heartbeat](https://github.com/paperclipai/paperclip/blob/680461e180232d0f4a057528617e39b64b4f0e3a/server/src/services/heartbeat.ts#L2288-L2296)
separates the saved filesystem project from the organizational project.
[Environment
selection](https://github.com/paperclipai/paperclip/blob/680461e180232d0f4a057528617e39b64b4f0e3a/server/src/services/heartbeat/environment-selection.ts#L506)
selects the fresh task directory. Preparation passes that flag, and the
planner's existing task-directory return runs before the new binding
guard. The proposed fresh failure omits that producer flag. The existing
fresh-intent and binding checks stay strict. This is source evidence,
not an extra runtime test claim.
- Empty policy object: the [public project policy
schema](https://github.com/paperclipai/paperclip/blob/680461e180232d0f4a057528617e39b64b4f0e3a/packages/shared/src/validators/project.ts#L24-L43)
requires `enabled:boolean`. The project PATCH schema makes outer fields
optional and does not make nested policy fields optional. A clear uses
`null`; `{}` is rejected. A defensive parser's treatment of unknown
stored data does not establish a valid `{}` producer. Keep the narrow
fallback closed for non-null policies.
- Boolean grouping: JavaScript evaluates the existing predicate as
`sourceId || (projectId && !implicitTaskDirectory)`. The explicit-source
and metadata-default controls cover those branches. The optional
parentheses suggestion does not identify a behavior change; this
reviewed source remains frozen.
- The official 4/5 assessment and its static verification limits remain
visible. The independent manual review withdrew its initial fresh-retry
concern after the full producer trace. Actual staging qualification
still requires deployment and a new real journey result.

## Risks

- The new query runs only for a source-less default admission. It reads
one authorized project and uses `NOT EXISTS` for that project's source
rows. It adds no recurring poll, write, provider call, or local folder
access.
- A project with an explicit workspace policy remains subject to the
prior source requirement. This conservative rule does not reinterpret
policy fields.
- The allocation control uses the real planner and PostgreSQL
reservation. It stops at environment acquisition, so it proves workspace
ownership rather than provider filesystem execution. Live staging
qualification is still required.
- No API, database schema, permission, model, budget, run limit, or QA
journey oracle changes are included.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tool use, and code
execution. This session does not expose a more precise backend model ID
or context-window size.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1101.0-canary.4
2026-10-31 23:09:30 -05:00
DottaandPaperclip f0ff466aaf fix(testops): wait for complete attachment evidence (#18509)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Product E2E evaluations check real user requests and their saved
results.
> - The TestOps reporter also verifies the uploaded result and
attachment evidence.
> - One failed attachment-row snapshot stopped the reader before its
existing observation allowance.
> - A later read with the same protected credential reference verified
the original result. The original failed subfield remains unknown.
> - This pull request handles attachment readiness within the existing
bound while preserving the complete final evidence predicate.
> - The reporter can wait for complete evidence without accepting
missing, inherited, or incorrect files.

## Linked Issues or Issue Description

Refs #18477 and #18470.

**What happened?**

The chat case passed its ten checks and cleanup in [run
41217990335](https://github.com/paperclipai/paperclip/actions/runs/41217990335),
but the final reader failed at `attachment_page / attachment_rows`. The
unchanged reader later verified that same retained result through the
protected reporting identity in [read-only run
41268693639](https://github.com/paperclipai/paperclip/actions/runs/41268693639).
This proves the observed snapshot differs. It does not identify which
original row subfield failed or prove an upload race.

The reader already permits twelve polls and 120 seconds for complete
result and attachment metadata. It nevertheless rejects `missed ===
true` immediately. That flag cannot satisfy complete evidence, but it
can be observed again within the existing allowance.

**Expected behavior**

Wait within the original limit for attachment evidence to become
complete. Accept only the same full source, case, status, cleanup,
attachment-name, media-type, byte-count, and non-missed predicate.
Reject malformed IDs and inherited rows immediately. Permanent missing
or incorrect evidence must still fail.

**Steps to reproduce**

1. Call the real verifier with otherwise valid responses and one
`missed: true` attachment.
2. Return the complete attachment on the second poll.
3. The old reader fails on the first snapshot. The regression now
reaches the original complete acceptance predicate on the second
snapshot.

**Paperclip version/commit**

Base `987e0932bf66e703750cd04698b3c7e8993580a7`.

**Deployment mode**

TestOps reporting observer after a Product E2E evaluation. This change
starts no model or app and changes no feature oracle.

## What Changed

- Move the strict `missed === true` condition from immediate structural
rejection into bounded readiness.
- Keep page shape, counts, unique positive IDs, inherited-row rejection,
and every source and case guard hard.
- Require the same complete final signature and status before success.
Keep twelve polls, five-second intervals, the 120-second deadline, and
request limits.
- Retain closed per-poll counts and readiness booleans on verification
and unverified failure. Clone failure observations so callers cannot
change retained diagnostics.
- Add seven focused regression and negative controls. Sync one existing
consumer test with the precise new failure phase and predicate.

## Verification

- Genuine parent RED: the real missed-then-complete verifier test failed
at the original attachment-row guard.
- API owner tests: 60 passed. Direct CLI, exporter, reporter, and
retained-reader consumer tests: 31 passed. Node 26.4.0.
- Permanent missing evidence reaches twelve polls and eleven waits, then
fails. An elapsed 120-second deadline stops after the first page.
Malformed IDs and inherited rows still fail immediately. Incorrect byte
counts never pass. Closed diagnostics exclude private fields and return
detached observation copies.
- Three Node syntax checks and `git diff --check` passed.
- Two review reproductions failed on the first PR head: a null row lost
its controlled invalid-ID error, and a final-GET deadline crossing lost
its exact readiness predicate. The corrected head preserves both
diagnostics. Null rows still fail immediately; no deadline or acceptance
condition changed.
- No local app, database, provider, native build, or new evaluation ran.
The MJS change needs no TypeScript emission.
- [Normal CI
41269715187](https://github.com/paperclipai/paperclip/actions/runs/41269715187)
passed on exact head `4e77c1220b0ba81e971591c1c7d28f9064e992cc`: 55
successes, three skipped checks, and one neutral review. Both required
checks passed. Greptile is 5/5 and review threads are resolved.
- The controlled normal TestOps-launched confirmation is pending merge.
The family unit roster runs the local controls; normal PR CI uses
separate runner suites, so CI green alone does not claim that roster ran
there.

## Risks

- A missed file may remain missing. The observer fails if complete
evidence does not arrive inside the original allowance.
- This is readiness handling, not a claim that `missed` caused the
historical failure. Prior passed case grades and failed reporting
workflows remain retained.
- The previous fixed retained diagnostic intentionally pins the original
helper. Its completed receipt remains valid; after this helper changes,
that old diagnostic fails closed instead of silently replaying a
different observer.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning, code editing, shell
tools, and independent source review. The host 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>
canary/v2026.1101.0-canary.3
2026-10-31 22:54:28 -05:00
DottaandPaperclip 9dbbfa4fb2 fix(qa): wait for task document controls after reload (#18503)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task documents keep saved work and its revision history with each
task.
> - The browser document journey must reopen the saved task and read the
revised document after reload.
> - Reload can finish before the task controls mount.
> - The helper checked visibility once and could wait for a tab launcher
inside a panel it had never opened.
> - This pull request waits for the existing usable controls before it
selects the normal UI path.
> - The saved content, revision, ownership and no-agent-work checks stay
unchanged.

## Linked Issues or Issue Description

Refs: #18356.

**What happened?**

The document case in QA run 41253428446 passed document creation and
revision-history checks, then failed during reopen or readback. The
preserved screen shows the revised document and revision 2 in chat. The
original result has the generic `journey_operation_failed` code. Its
exception stack was intentionally excluded, so the exact historical
failing instruction is not known.

A separate Chromium control reproduces a concrete navigation race in the
same helper. If task controls mount 200 ms after reload, the helper can
select `Open a new tab` before it opens the properties panel. That
control never becomes visible. The same race affects a delayed classic
document editor or an existing Artifacts tab.

**Expected behavior**

The helper waits for the current task's normal authoring or panel
controls. It then opens Artifacts through the same visible controls. A
task without document authoring must still fail. A stale body, stale
title or damaged revision history must still fail.

**Steps to reproduce**

1. Open a task from the Backlog list and reload it.
2. Delay mounting the task controls by 200 ms.
3. Run the unchanged document reopen helper with its properties panel
closed.
4. Observe that it waits for `Open a new tab` while `Show properties` is
visible.

**Paperclip version or commit**

Frozen source base: `b889ac39b7fbed558c5f4cfbbc2b73c4ca916810`. No
duplicate document reopen PR was found. The related document feature is
#18356.

## What Changed

- Wait for an existing authoring, properties, Artifacts or launcher
control before choosing the navigation path.
- Wait for usable panel content after opening properties.
- Add five credential-free Chromium controls for delayed collapsed,
Artifacts, launcher and classic layouts, plus missing-authoring
rejection.
- Keep the existing Backlog navigation test compatible with the new
readiness probes.
- Register the browser regression in the existing support suite. No
product code, model, budget, run cap or campaign deadline changed. The
existing document contract needs no documentation change.

## Verification

- Original failure is preserved. The [sanitized QA
report](https://pages.paperclip.ing/evals-qa-smoke-41253428446-1/)
records both partial checks and the failed journey. This PR does not
change that grade.
- Before the fix, the real Chromium control failed for delayed
collapsed, Artifacts and classic controls. The launcher path and
missing-authoring rejection passed. A 750 ms action timeout bounded this
diagnostic; final tests use the existing suite timeouts.
- Final Chromium: `node node_modules/@playwright/test/cli.js test
--config tests/runner-e2e/playwright-support.config.ts
task-document-navigation.spec.ts` — 5 passed.
- Document units: `node node_modules/vitest/vitest.mjs run --config
tests/runner-e2e/vitest.config.ts
tests/runner-e2e/product-journeys/task-document-flow.test.ts
tests/runner-e2e/product-journeys/task-document-evidence.test.ts
--maxWorkers 1` — 23 passed. This includes 19 negative content,
ownership and revision controls.
- Scoped strict TypeScript, map checks, token gates and diff checks
passed.
- Node 24 normal QA import preflight passed with network disabled.
- The entire `taskDocumentPersistence` function and the canonical
evidence module are byte-identical to the base. The existing exact
title/body checks, independent API reads, revision pointers and
no-agent-work checks remain in force.
- Repository-wide build, typecheck and tests were not run locally for
this four-file harness change. [Canonical CI
41255897484](https://github.com/paperclipai/paperclip/actions/runs/41255897484)
passed on exact head `ffc04500cb0728f6fbc8b3bc2e704c547015641d`: all 59
checks are terminal (55 success, 3 skipped, 1 neutral), with no failed
or pending checks. Greptile and Paperclip each gave this head 5/5 with
no findings. All review threads were checked; none are open and there is
no next page. The branch is CLEAN and MERGEABLE.
- Actual QA measurement now passes in [workflow
41266385118](https://github.com/paperclipai/paperclip-cloud/actions/runs/41266385118),
campaign `journey-1793502283113-8f658807`. The measured harness
`5c0830f693da2ccef062612146b76629a0177049` contains the three exact
reviewed document source/test blobs and unchanged canonical evidence
module from this head. The target was the QA cloud instance on App
`756599e4ea069c9338c320fe8846523d3dfb92a0`. All four canonical checks
and all five phases passed; the manifest is COMPLETE with evidence
cleanup complete and nothing pending. A positive no-agent-work check
establishes zero native work despite omitted raw run IDs. A separate
read-only verifier reread the exact original final grade and confirmed
the retained-result validator. Raw document snapshots were not retained;
content, revision and author proof comes from the executed unchanged
exact UI/API predicates. The full 14-case launch remains failed because
hiring failed separately; no aggregate pass is claimed.

## Risks

The historical exception was intentionally sanitized. The local control
proves this helper race, but cannot prove which instruction failed in
the prior QA attempt. The current staging measurement passes this
document case; the exact historical failing instruction remains
unproven. The new readiness waits use the existing assertion timeout and
campaign deadline. They do not accept missing controls or weaken
document evidence.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, code execution and browser
automation. The exact serving model revision 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

Live qualification: the document case is verified on QA with complete
cleanup. Historical failed results remain unchanged.

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-31 22:30:05 -05:00
DottaandPaperclip 987e0932bf test(testops): inspect a fixed retained chat result (#18477)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The chat feature evaluation checks a real task request on AWS.
> - The case passed, but its final TestOps reader rejected attachment
metadata.
> - The later browser view passes the same check. It uses a different
identity and time.
> - Another model run cannot explain that difference.
> - This pull request adds a fixed read-only check of the retained
measurement with the reporting API identity.
> - The check separates its own executor from the original measurement
and preserves the original grade.

## Linked Issues or Issue Description

Refs #18470 and #18462.

**What happened?**

The real chat case passed all ten checks and cleanup in [run
41217990335](https://github.com/paperclipai/paperclip/actions/runs/41217990335).
Final verification failed at `attachment_page / attachment_rows`. The
reader had already accepted the source, run, case, status, page counts,
and unique attachment IDs. Later interactive metadata had valid IDs and
false attachment flags. That later view does not explain the original
API caller failure.

**Expected behavior**

A read-only operation can inspect the same retained result with the
existing protected reporting identity. It must report the exact current
attachment flags without running a model, uploading results, or changing
the original grade.

**Steps to reproduce**

1. Read the closed failure from the linked evaluation run.
2. After this workflow is reviewed and deployed, dispatch its fixed
no-input operation on master.
3. Inspect its closed receipt. It records both the new executor and the
original measurement.

**Paperclip version/commit**

The retained measurement used
`e40de0c9e88210dc476dcf651461c0a8d1b98a59`.

**Deployment mode**

GitHub Actions metadata job with the existing protected reporting
environment. No app, database, provider, or AWS worker starts.

## What Changed

- Add one manual no-input workflow for the fixed retained measurement.
- Admit the live executor and the original run separately. Verify exact
selection and sanitized export artifact hashes before TestOps
authentication.
- Read only the five existing TestOps metadata routes with the existing
client. Its normal API-token session exchange is the only authentication
POST.
- Record closed per-row attachment types and flags. Replay the unchanged
verifier against the captured responses using historical context as
data. Keep the actual process environment unchanged.
- Add nine mock and archive-safety tests to the existing Node unit
roster.

## Verification

- `node --test
tests/runner-e2e/chat-feature-testops-retained-verification.node-test.mjs`:
9 passed on Node 26.4.0.
- Three Node syntax checks, actionlint, the relevant workflow policy
check, and `git diff --check` passed.
- The real pinned sanitized export ZIP passes the new safe-export
extractor and existing bound reader. The first local attempt used a
noncanonical `/var` temporary path and hit the existing canonical-path
guard; the canonical `/private/tmp` attempt passed without a source
change.
- Corrected a review finding in failure attribution. Only actual
authentication or protected GET errors now receive `apiFailure`.
Historical replay failures retain their original phase and predicate
diagnostics.
- Initial test run: eight passed and one test expected the generic
upload error instead of the existing specific job-run error. Corrected
that test expectation. No verifier behavior changed.
- Tests exercise separate identities, foreign source and actor
rejection, origin and artifact integrity, exact five GETs, all three
attachment-row refusals, secret redaction, wrong job/run/source, and
real archive traversal/symlink rejection.
- The unchanged API and export readers are source-pinned. Existing
evaluation and acceptance code is unchanged.
- [Normal CI
41220476243](https://github.com/paperclipai/paperclip/actions/runs/41220476243)
passed on exact head `b79e85f71567f662d6f3d680ec66ec49a132589a`: 55
successes, three skipped checks, and two neutral reviews. Both required
checks passed. Greptile is 5/5 and all review threads are resolved.
- The nine new controls are registered in the family unit command. The
separate normal PR-CI runner suites do not execute that roster, so their
green status is not proof these nine ran on Node 24. The manual workflow
explicitly runs them on Node 24 before any protected API read.
- The real protected API operation has not run. A separately approved
merge and metadata dispatch remain required. No model, app, database, or
native build ran locally.

## Risks

- The fixed artifacts can expire. Any absent or changed artifact fails
before TestOps authentication.
- The current protected response snapshot may differ from the original
failure-time state. The receipt states that limit and makes no
historical cause claim.
- This is a fixed diagnostic operation. It does not repair the original
workflow or grant authority to run another evaluation.
- The workflow uses the existing protected reporting token. It logs no
response body, unknown field, credential, or unknown URL. Only closed
receipts are retained.

## Model Used

OpenAI `gpt-6.1-sol`, through Codex, with reasoning, code editing, shell
tools, and source review. The host 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-31 22:16:20 -05:00
DottaandPaperclip d38cdf261a perf(ui): speed up Tasks and Inbox startup (#18492)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tasks and Inbox are the main entry points for that work.
> - Earlier changes made their data reads and row counts smaller.
> - Those changes remain, but shared controls now pull in the whole
task-detail bundle.
> - A cold open can also read a remembered organization before selecting
the one in the URL.
> - This pull request separates collection code and selects the
addressed organization first.
> - It warms task code after collection paint, so the next task open
stays fast.

## Linked Issues or Issue Description

Refs #17756, #18323, #16849, #17041, #17983, #17960, #18461.

**What happened?**

Tasks and Inbox still use their optimized index reads and row budgets.
However, small shared controls and hooks were placed in the task-detail
chunk. A collection had to download that whole chunk. The HTML also
preloaded it on every route. The original production profile loaded
about 6.5 MB of decoded JavaScript before useful rows, or 1.9 MB
transferred with compression.

Company bootstrap could select a different remembered organization
before Layout selected the URL's organization. This started unnecessary
company reads. A retained multi-company browser fixture reproduced two
attention-count requests for different companies.

**Expected behavior**

Show correctly scoped, stable collection rows without waiting for
task-detail code. Keep compact reads, bounded rendering, direct task
preloading, immediate New Task input, and fast follow-on navigation.

**Steps to reproduce**

1. Use a production UI build with Coordinator enabled and two active
organizations.
2. Remember one organization, then cold-open Tasks or Mine in the other.
3. Inspect startup script and company requests before the first useful
row.

The baseline UI revision is `91fdf02e95`. This is a UI change. It has no
API, schema, migration, or authorization changes.

## What Changed

- Group the static collection dependency trees above the task-detail
group. Keep the existing startup and task grouping strategy.
- Preload task detail and its static dependency closure early on direct
task and agent-chat URLs. Keep collection aliases out of that preload.
- Fetch the immutable task chunk at low priority after a collection
paints, or on a same-origin task-link hint. After a successful immutable
response is fully read, module-preload the cached chunk so it can
compile without executing. A failed HTTP probe skips module preload.
- Prefer an addressed active organization during bootstrap. Preserve
manual selection, archived-company handling, and account-scoped company
lists.
- Preserve a task reading anchor when a programmatic scroll event
reports an unchanged offset during restore reflow. Strengthen the Back
journey to wait for a completed collection navigation.
- Add production-browser checks for delayed indexes, correct company
scope, stable row geometry, failed speculation, and early direct-task
preload. Update collection verification notes and the feature map.

## Verification

Final source: `e402ab7fc6`; baseline UI: `91fdf02e95`.

- All **234 focused unit cases** and **44 production-browser journeys**
passed on the final source: 33 task journeys and 11 collection journeys.
Coverage includes compact history, saved cards, draft persistence,
avatar continuity, failed-probe recovery, delayed data, pagination, deep
links, desktop/mobile and reading-position restoration through Back.
Desktop and mobile screenshots were inspected.
- Workspace typecheck, full production build, map checks, token gates
and diff checks passed. The default local `pnpm test:run` still stops
before executing tests because the existing chat-test line selector
reports `No test found` (1,816 skipped). This is not a passed full local
test suite. Focused tests and remote CI remain separate evidence.
- Greptile reviewed the exact final commit at **5/5**, with zero open
review threads. Final code CI passed. The complete check inventory is
**55 successful, 3 skipped, 1 neutral**. The neutral result is the
separate Paperclip Review: its agent finished without completing an
assessment, so it is not a passing review score.

Five alternating baseline/candidate pairs per scenario, Chromium
151.0.7922.34, 1440×900, 4× CPU, 50ms latency, approximately 9Mbps down
/ 1.5Mbps up. Cold cases use fresh browser contexts with normal cache
writes enabled; warm cases use the same context and normal application
query cache. Both previews use the server's immutable hashed-asset cache
policy and uncached HTML, with real local feature settings and no
request interception. All task-owned builds and suites were stopped
during timing; other host activity was uncontrolled. Readiness requires
useful rows and editable search, or the readable task thread and
editable composer, followed by two animation frames.

| Journey | Baseline median (range) | PR median (range) | Median paired
saving |
| --- | --- | --- | --- |
| Cold Tasks | 3239 ms (3189–3333) | 2545 ms (2441–2682) | +752 ms |
| Cold Inbox | 3207 ms (3203–3268) | 2679 ms (2502–3062) | +541 ms |
| Warm Inbox | 717 ms (701–917) | 760 ms (745–768) | -47 ms |
| Warm Tasks | 1150 ms (1126–1207) | 1136 ms (1119–1174) | +18 ms |
| First task click | 943 ms (932–1008) | 1007 ms (976–1098) | -74 ms |
| Back to Tasks | 584 ms (568–617) | 566 ms (559–575) | +10 ms |
| Cold direct task control | 3389 ms (3377–3402) | 3415 ms (3395–3896) |
-13 ms |

All five pairs improved for each cold collection. The signed saving is
baseline minus candidate for each pair; it is distinct from the
difference of medians. Warm navigation is broadly similar. First task
click was 74ms slower by median paired difference. Direct-task median
paired difference was 13ms slower, with one slower 3.90s candidate
sample retained in the range; this is not a claimed direct-task speedup.

Completed script transfers by collection readiness fell from about
**1.91MB to 1.14MB** (Tasks), and **1.90MB to 1.14MB** (Inbox). Task
code warms after rows paint. At the test bandwidth, the removed 0.77MB
critical transfer represents roughly 0.65s of download time; CPU and
network overlap, so their savings are not added. Unthrottled loopback
API control medians stayed about 17–18ms in both variants. All 30 cold
samples had zero browser errors.

Rejected experiments remain separate: automatic splitting produced over
200 startup requests; disabling recursive grouping slowed direct tasks;
HTTP-only warming improved collection startup but slowed first task
opens. The final correction preloads direct dependencies and compiles
successfully cached code after paint. Routing disables HTTP caching, so
intercepted runs were kept as diagnostic evidence rather than used for
warm-cache acceptance; see [Playwright's cache
behavior](https://playwright.dev/docs/api/class-page#page-route). Vite
preview's default asset `no-cache` policy was also corrected to match
the shipped server before final measurement.


## Risks

- Bundle placement affects shared consumers. Browser checks cover
collections and task navigation; the full PR checks also cover other
routes.
- Code warming still transfers the task chunk if the user stays on a
populated collection. It moves that download past first paint and does
not execute it. This is a startup latency improvement, not a claim that
all eventual bytes disappear.
- A direct click before warming finishes still loads code on demand.
Direct task and chat URLs retain early module preload.
- Local browser evidence does not establish a deployed staging speedup.
This PR does not merge or deploy itself.

## Model Used

OpenAI GPT-6 (Codex), with reasoning, tool use and local code execution.
The context-window size is not exposed in this environment.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run the relevant tests locally and they pass (234 unit
cases and 44 browser journeys; the full-command 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 code CI gates are green (the separate Paperclip Review is
neutral because its agent did not complete an assessment)
- [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-31 22:12:41 -05:00
34f8d25089 fix(github): expose review finding categories (#18429)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - GitHub review bots submit structured assessments through task-bound
tools.
> - Each repository can set its own finding categories.
> - The schema accepts a string, but the server rejects values outside
the saved review policy.
> - Review instructions did not list the accepted values. The error did
not list them either.
> - This change gives agents the values before submission and keeps
server validation.

## Linked Issues or Issue Description

**What happened?**
Review submissions failed with an unknown finding category. The agent
corrected the assessment before publication. The sampled trace has two
rejections followed by a processed review. Historical tool inputs are
null. Authorized diagnostic inspection found no saved raw provider trace
for the representative run. The exact rejected values remain unknown.

**Expected behavior**
Agents can find the accepted categories before submission. Unknown
values still fail validation.

**Steps to reproduce**
Set a custom finding category. Start a review. Submit a different
category. Before this change, the instructions and error do not list the
accepted value.

## What Changed

- List configured categories in manual and automatic review
instructions.
- Return categories from the saved assessment policy in `begin_review`.
- Describe the dynamic constraint in the shared discovery schema. Keep
custom categories valid.
- List accepted values in category errors. Keep authorization and
publication checks.
- Add contract and database integration tests. Update documentation and
access maps.

### Hypothesis and thesis for a fix

The missing category guidance can cause avoidable submission retries. A
model can also ignore the policy returned by metadata reads; the
historical inputs do not establish which occurred. The repair belongs to
the GitHub review contract. Use the saved policy categories at review
start, explain the constraint, and retain server rejection. A fixed
global enum would reject valid custom categories.

## Verification

- Baseline `f1d7808`: two new contract assertions failed for missing
category guidance and error detail. The same assertions pass after the
change.
- `pnpm exec vitest run
server/src/services/chat-github-review-policy.test.ts
server/src/services/chat-github-tools.test.ts`: 41 passed.
- `pnpm exec vitest run
server/src/__tests__/chat-channels.integration.test.ts -t 'returns
snapshot finding categories'`: 1 passed. Real PostgreSQL and service
code; simulated GitHub HTTP. Checks policy changes, rejection before
publication, accepted custom category persistence, and processed
publication.
- `node scripts/check-maps.mjs`: passed. Structural evidence only.
- Shared TypeScript check passed. Server TypeScript checking was killed
by the 8 GiB memory limit, including a separate retry after the other
checks stopped.
- Full typecheck and build could not complete: `cargo` is absent. Full
tests were stopped after concurrent checks exhausted memory. CI must
supply the full checks.
- Follow-up compiler repair: the unchanged baseline reproduces TS2352 in
the category discovery test. Runtime matchers replace the unsafe schema
cast. They retain both guidance and custom-category assertions. The
repair is commit `0dcb94c676`, with current master merged at
`14d7052854`. The final head is
`c46b8f35add9255fc71be294d27f5a7865bcb47f`; the remaining code-comment
review finding was removed and resolved.
- Final-head CI: all gates pass, with no failed or pending checks.
Greptile gives this head 5/5 with no outstanding findings; the only
inline thread is resolved. The workspace test shard passed on one
bounded rerun after an earlier CLI child-server readiness timeout; no
code change was made for that rerun.
- The review host passed full recursive typecheck and build after the
compiler repair and master integration. Fresh database rechecks hit the
host PostgreSQL semaphore limit. The full local test command hit a
pre-existing chat line-selection failure before assertions. These local
limits do not replace the passing final-head CI evidence.
- No live model or GitHub publication at the changed revision. No
deployment or merge.

## Risks

- Instructions add policy text. An agent can still ignore it.
- Existing bot catalogs get the schema description when tools are
synchronized. Trusted review instructions and `begin_review` also expose
categories.
- The service test uses simulated GitHub HTTP. It does not prove that
deployed agents avoid retries.

## Model Used

The original worker used OpenAI `gpt-6.1-sol` through Codex with
reasoning, tool use, and code execution. A later Codex review repaired
the test compiler error. That review runtime exposes GPT-6 but no exact
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: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Dotta <bippadotta@protonmail.com>
Co-authored-by: cryppadotta <34892728+cryppadotta@users.noreply.github.com>
2026-10-31 22:06:32 -05:00
DottaandPaperclip e09f40888a fix(recovery): preserve native task access during resolution (#18489)
## Thinking Path

> - Paperclip controls agent execution and task ownership.
> - A native run needs its task binding until it reports its result.
> - Direct task updates already reject self-status changes that remove
this binding.
> - Recovery resolution can also change the source task status.
> - That route did not use the same protection.
> - This change rejects the unsafe status change before the task or
recovery receipt changes.
> - The run can then use semantic completion while normal recovery
permissions remain effective.

## Linked Issues or Issue Description

Refs #18411.

**What happened?**

A running native owner can resolve an older recovery action with
`sourceIssueStatus: "in_review"` or `"done"`. The request succeeds and
changes its own task status. That can release the execution binding
before the run reports. Later task tools fail with
`paperclip_runner_tool_binding_not_authorized`.

**Expected behavior**

Return a conflict before the task status or action receipt changes. Tell
the run to report through `paperclip_finish` or `paperclip_block`.
Preserve unchanged-status resolution, Board recovery, legacy-agent
behavior, and the existing conversation and handoff rules.

**Steps to reproduce**

1. Give a running native owner the task execution lock and an older
recovery action.
2. Call `POST /api/issues/{id}/recovery-actions/resolve` as that run.
Use `outcome: "restored"` and `sourceIssueStatus: "in_review"`.
3. Before this fix, the route returns 200 and changes the status. After
this fix, it returns 409 with `native_run_status_reported_by_finish` and
makes no task or action mutation.

## What Changed

- Reuse the existing native self-status guard inside recovery
resolution's source-task transaction.
- Let the guard receive the requested status from either route contract.
- Add HTTP route regressions for rejected review/completion transitions
and continued task editing after rejection.
- Cover unchanged-status native resolution, Board recovery and
legacy-agent resolution.
- Update execution semantics and both recovery maps.

## Verification

- Baseline `91fdf02`: the two new rejection cases fail because the real
Express route returns 200. Three safety cases pass.
- Fixed source: all 198 tests in
`server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts`
pass.
- `node scripts/check-maps.mjs` passes. This is structural evidence.
- Greptile and Paperclip Review both give the integrated head 5/5 with
no actionable findings.
- Full recursive typecheck, full build, and a repeat of all 198 route
tests pass at integrated head
`0fa104dfb240500acd01303cd446363ea39c6c75`. All current-head CI gates
pass (55 successful checks/statuses; no failed or pending checks).
- The full local `pnpm test:run` command fails in chat-test line
selection with `No test found`, before assertions. This also occurs with
the unchanged master chat test file. It is not a passing full local
suite.
- The route tests use the real route, validation and guard. They mock
service and database boundaries. The observed hosted failure establishes
the original mechanism. Fixed-source live provider acceptance remains
unverified. No deployment or merge is part of this PR.

## Risks

- A native owner now receives a conflict for a previously accepted
recovery status change. It must use the existing semantic result path.
- This prevents a new binding loss. It does not prove that an old remote
executor stopped or recover missing provider state.
- Board, legacy, conversation and handoff behavior retains existing
authority. The regression includes representative allowed paths.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (198 focused route cases;
the full local command has the recorded selection failure)
- [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-31 22:06:08 -05:00
DottaandPaperclip c38844eafa test: observe complete workspace retention cleanup (#18507)
## Thinking Path

> - Paperclip manages AI agents and preserves their work.
> - Remote workspace retention removes saved objects after their last
pin clears.
> - The retention worker deletes each object before it commits the final
snapshot state.
> - The parent-revisit test treats the first object deletion as
completion of all work.
> - That valid intermediate state can fail the next-deadline assertion.
> - This pull request observes complete storage, database, and worker
settlement within the existing bound.
> - The test still fails if the parent is not revisited after the child
releases its pin.

## Linked Issues or Issue Description

Refs: #18351
Refs: #18506

**What happened?**

[The server6 CI
job](https://github.com/paperclipai/paperclip/actions/runs/41263476916/job/124721633674)
failed at `remote-workspace-snapshot-retention.test.ts:248`. The test
expected a null retention deadline after the first parent object
disappeared. The parent could still have its second object and a
`delete_requested` row. The worker was not finished.

**Expected behavior**

The test must wait for both parent objects, both snapshot rows, and the
retention worker to finish. It must retain the four-second bound and
40ms observation interval.

**Steps to reproduce**

1. Use the parent/unfinished-child fixture in the retention test.
2. Hold the second parent-object deletion after the first object is
removed.
3. Read the old assertion while the parent row remains
`delete_requested`.
4. The old assertion receives `1793361600000` instead of null. Release
the hold and observe the completed state.

**Paperclip version or commit**

The failed CI checkout was `ab849702a78f6bb619b1527596cd52db402d9189`.
This test-only repair starts from actual mainline
`b110271c9b2fd6dd5a1beb119e7f0663385df8b9`. The relevant test, retention
service, coordinator, storage, test-helper, and configuration blobs
match the failed checkout and mainline
`756599e4ea069c9338c320fe8846523d3dfb92a0`.

**Deployment mode**

Built-from-source server tests. The local controls used one disposable
PostgreSQL17 instance and local disk storage. They used no deployed
company or model.

## What Changed

- Observe both parent objects and the exact parent and child database
rows in one bounded assertion.
- Require deleted rows with cleared deadlines, zero active tracked work,
and no coordinator wake before the test ends.
- Keep the original four-second timeout and 40ms interval. Production
retention and scheduling code stay unchanged.

## Verification

- All17 tests in `remote-workspace-snapshot-retention.test.ts` passed on
Node24 with current-source aliases, current migrations, and a disposable
PostgreSQL17 database.
- At immutable head `1e7eeb422be260bfaf752792596f8cdd126fff8d`, the
second-deletion hold control also passed all17 file tests. Removing only
the parent-revisit signal still failed the affected case within four
seconds. The owned database container was stopped and its automatic
removal was verified.
- Normal checkout command: `pnpm --filter @paperclipai/server exec
vitest run src/services/remote-workspace-snapshot-retention.test.ts
--reporter=verbose`.
- Four bounded controls used the exact failed CI source: unchanged
baseline PASS; held second deletion with the old assertion RED; the same
held state with complete-settlement observation GREEN; removed
parent-revisit signal RED under the original four-second limit.
- The held state proved: first parent object absent, second present,
child row deleted, parent row `delete_requested`, non-null deadline, and
active worker. This proves a reachable observer bug. The exact
interleaving in the historical CI job was not recorded and remains
unknown.
- The same case passed at mainline756 in [the canonical readiness
control](https://github.com/paperclipai/paperclip/actions/runs/41260612021/job/124712930107).
Source identity and a passing control alone do not establish cause; the
held-state control supplies that evidence.
- `git diff --check` passed. The net source change is one test file,
with no added comments or runtime changes.
- Final exact head `1e7eeb422be260bfaf752792596f8cdd126fff8d`:
[canonical
CI41264965700](https://github.com/paperclipai/paperclip/actions/runs/41264965700)
completed successfully. All57 checks are terminal and clean, with no
pending or failed checks. This includes the aggregate verify and Snyk
gates. The PR is mergeable and clean. No old failed job was retried.
- [Greptile reviewed this exact full head
at5/5](https://github.com/paperclipai/paperclip/pull/18507#issuecomment-6552310742),
with no actionable findings and zero open review threads. Complete
thread pagination was checked.
- [The current Paperclip assessment
is4/5](https://github.com/paperclipai/paperclip/pull/18507#issuecomment-6552292204),
with a final full-head footer. Its check conclusion is neutral. It calls
the fix correct and identifies one minor, non-blocking concern about a
process-wide active-work counter. This score remains4/5; it is not
represented as5/5.

## Risks

The assertion is stricter because it checks complete deletion and worker
settlement. A real missing revisit, retained object, unresolved row, or
continuing worker must still fail. The bound is unchanged. No schema,
API, production storage, scheduler, or deployed configuration changes
are included. No user-facing command or behavior changed, so no product
documentation update is needed.

The Paperclip review notes that `idleWorkSnapshot().active` is
process-wide. The current test configuration uses fork isolation, one
worker, and serial tests, so the counter is scoped to this fixture in
the present test run. We retain it because deleted rows and an empty
wake queue can be observed before the coordinator finishes its active
work. If test isolation or fixture concurrency changes, this assertion
will need a worker-specific settlement check. This is the review's
accepted non-blocking limitation; it is not waived or scored as
resolved5/5.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, source inspection, code
execution, and tool use. The session does not expose a more specific
backend model ID or context-window size; neither is inferred.

## 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>
canary/v2026.1101.0-canary.2
2026-10-31 21:54:42 -05:00
DottaandPaperclip b110271c9b test: observe GitHub enrollment after worker settlement (#18506)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub connection events use a worker that must return to quiet
after it drains an event.
> - The integration test checks that work with real PostgreSQL and
signed loopback requests.
> - The loopback server can receive an ACK before the worker completes
that request.
> - The test reads the next deadline too early and can reject valid work
in progress.
> - This pull request waits for the observed work state without moving
the fake clock.
> - It keeps the exact work counts, identity checks, deadline bound and
quietness checks.

## Linked Issues or Issue Description

Refs #18395 and #18351. This is a test-only repair for the event-worker
integration fixture.

**What happened?**

[CI run
41257779002](https://github.com/paperclipai/paperclip/actions/runs/41257779002/job/124704574485)
failed at the replacement follow-up deadline assertion.
`coordinator.nextWakeAt()` was `null` after the server received the
second ACK. The worker can still be waiting for that ACK response at
this point.

**Expected behavior**

Wait for the worker to expose a deadline or finish the exact expected
follow-up. Do not drive fake time during an observation. Require the
scheduled follow-up to stay within five seconds of the first
observation. Keep one empty follow-up, the new identity and no I/O after
the worker becomes quiet.

**Steps to reproduce**

1. Run the existing enrollment integration test on the original CI merge
`a1e25444a95f3698c3761cd1796bd1e11567224c`.
2. Hold only the second loopback ACK response after its server counter
increments.
3. The original deadline assertion fails while the worker remains
active.

**Paperclip version or commit**

The causal control used the exact CI merge above. This repair starts
from verified master `66e8fab9447aa21350f87ddec79fcd027f3e23ad`. The
fixture and relevant worker files match the earlier `b889` inputs. The
original failure remains preserved. The controlled race does not prove
the unique historical scheduling of that CI attempt.

## What Changed

- Use bounded real I/O yields for observations. Assert that the fake
clock stays fixed during each observation.
- Advance fake time only to actual pending follow-up deadlines. Keep one
fixed five-second reference for each drain.
- Accept an already finished follow-up only when the exact expected
lease count is present. Quietness must still follow.
- Hold the replacement ACK on a Promise gate in the existing test.
Release it during normal work and in cleanup. This keeps a deterministic
regression without a sleep.
- Keep the signed request, identity replacement, exact lease counts,
25-minute no-I/O checks and 30-second test budget.

## Verification

- Original CI: one assertion failure at line 126; 2,619 other tests
passed in that lane. It was not a test timeout or host failure.
- Earlier controls: the same test and relevant worker inputs passed in
two fresh CI lanes. Both used zero Turbo cache hits. Input identity
alone is not the cause proof.
- Causal controls on the original CI source: unchanged baseline passed;
held ACK failed at the original assertion with active work; a settlement
barrier passed all original assertions; a missing second hint still
failed.
- Final patch with real PostgreSQL 17 and current source migrations: the
direct test passes, including its deterministic ACK gate. An extra 750
ms ACK delay also passes. The missing-second-hint negative still fails
at the expected observation.
- Focused command: `pnpm exec vitest run --project server
server/src/__tests__/github-connection-enrollment-work.test.ts`. Local
checks used current-source package aliases and one disposable loopback
PostgreSQL instance. The test creates a unique database and no user
data.
- Fresh Greptile review is 5/5 for
`519c3fd4a99bf77aea7b085b67c38701358fef95`. The exact head has no open
review threads. The current Paperclip assessment is also 5/5 with a
final response footer for that full commit. Its check conclusion is
neutral.
- [Canonical CI
41260540629](https://github.com/paperclipai/paperclip/actions/runs/41260540629)
completed successfully for the exact head. All 57 checks are terminal
with no failures or pending checks. This includes `ci / verify` and
Snyk. The PR is mergeable and clean.
- `git diff --check` passes. Full repository typecheck, tests and build
are delegated to fresh PR CI. No QA journey, model run, deployment or CI
retry was performed for this repair.

## Risks

This change affects one integration fixture. Production worker logic,
schedules and deadlines do not change. The observer retains a one-second
real-time bound and the test retains its 30-second budget. The test
still fails on missing work, extra work, a late deadline, a wrong
identity or I/O after quiet. The database and HTTP server remain owned
by the fixture.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
backend model ID or fixed context window. Used reasoning, repository
tools and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run the 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
(test-only behavior; described here)
- [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>
canary/v2026.1101.0-canary.1
2026-10-31 20:40:35 -05:00
DottaandPaperclip 756599e4ea fix(workspaces): keep project references without source folders (#18504)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents can receive project references in normal task and chat
messages.
> - Remote workspace preparation checks those references before a native
run starts.
> - A project with no workspace source has no folder to attach.
> - The current check rejects that project as an unsupported read-only
folder.
> - This pull request keeps the project reference and reports the
missing source without attaching files.
> - Projects with configured sources keep the current remote access
restrictions.

## Linked Issues or Issue Description

Refs #18403 and #18351. This is a product prerequisite for the hiring
journey. It changes no journey code.

**What happened?**

A native chat run failed before execution when its message referenced an
authorized project with zero configured workspaces. The error was
`workspace_validation_failed`: “This remote runtime cannot safely
provide read-only project folders.” The project had no repository or
checkout. The failed QA run and original grade remain preserved.

**Expected behavior**

Keep the task workspace when a referenced project has no configured
source. Report that no project folder was attached. Continue to reject
configured cross-project sources that require an unsupported read-only
mount.

**Steps to reproduce**

1. Use a native remote task folder with multi-project references
enabled.
2. Mention a same-company project that has no configured workspaces in a
normal comment.
3. Prepare the run workspace.

**Paperclip version or commit**

Reproduced on `b889ac39b7fbed558c5f4cfbbc2b73c4ca916810` with the real
workspace resolver and PostgreSQL migrations. The staging failure was
recorded in workflow
[41253428446](https://github.com/paperclipai/paperclip-cloud/actions/runs/41253428446).

## What Changed

- Distinguish authorized project references with a known empty workspace
list from configured sources.
- Return a resolution warning and failure receipt for an absent source.
Do not attach a folder or create a workspace.
- Preserve project authorization, company filtering, the disabled
remote-source gate, and the read-only restriction for configured
sources.
- Add real PostgreSQL regression cases and document the reference
contract.

## Verification

- Causal RED on unchanged `b889`: the metadata-only project case failed
with the same read-only error. The real repository negative already
passed.
- GREEN: eight PostgreSQL cases pass. They cover an absent source with
the remote-source switch both on and off, a saved existing workspace, a
repository, a configured source without a repository URL, the disabled
remote gate, mixed references, and a foreign company.
- The existing assembled workspace test also passes: a real read-only
project source is rejected before reservation or environment
acquisition. Total: 9 selected tests pass; 119 unrelated tests were not
selected.
- Tests use PostgreSQL 17 and the current source migrations. The local
Vitest configuration selects current DB, shared, and Runner sources
because the borrowed dependency output predates the remote workspace
feature.
- Current-source TypeScript checking of both changed TypeScript files
and their dependency graph passes. It uses the repository's real Express
actor declaration.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Canonical reproduction: `pnpm exec vitest run --project server
server/src/services/heartbeat/remote-workspace-source.test.ts` with the
existing embedded PostgreSQL support or
`PAPERCLIP_TEST_POSTGRES_ADMIN_URL` set to a disposable test cluster.
- Historical `0f2b` passed all 59 CI checks. A separate non-author
manual source audit reported no actionable findings at confidence 4/5;
it did not rerun tests or qualify live QA. The official 4/5 review
requested a flag-scope test and saved-workspace control. This
test-and-documentation update adds both, with production source bytes
unchanged.
- Current-head canonical [CI
41258109282](https://github.com/paperclipai/paperclip/actions/runs/41258109282)
passed: all 59 checks are terminal (55 success, 3 skipped, 1 neutral),
with no failures or pending checks. Build and typecheck passed. The
eight-case regression file passed in the canonical Linux server 1/12
lane. Its checkout `6f69ccca70d10e78885b133fb54a80940bf175a5` has
parents `b889` and this exact head; its tree equals this head.
- Fresh Greptile and official Ponytail assessments each give 5/5 for
exact `27660027d12ff31427d611019e90dabfb6d8503a`, with zero unresolved
review threads. The separate manual audit remains 4/5.
- Live QA remains pending on a reviewed app build. This regression proof
does not claim that the hiring journey passed.

## Risks

A project source could be added after project hydration. This change
uses the same run-preparation source snapshot as the existing
authorization and source check. It only permits a positively known empty
workspace list. Configured sources, unknown shapes, foreign projects,
and existing execution authority keep their current checks. No schema,
credentials, provider, model, budget, or filesystem permissions change.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
backend model ID or fixed context window. Used reasoning, repository
tools, TypeScript and test execution.

## Checklist

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

> - Paperclip must perform work and report its outcome accurately.
> - A chat response and its delegated or operator-owned work are
separate stages.
> - Native chat contracts instead required literal completion of the
user's whole request.
> - Agents kept searching or waiting even when a truthful handoff should
finish the response.
> - OpenCode also has separate acknowledgement backlog and
empty-response failure paths.
> - This PR aligns chat completion with its current stage and makes
OpenCode completion truthful.

## Linked Issues or Issue Description

Refs #18098 for retained OpenCode evidence and #18377 for separate eval
setup, oracle and reporting repairs.

**What happened?** Real pinned OpenCode 1.18.34 reproduced an MCP
timeout behind 800 text fragments. Pilot
[41222196525](https://github.com/paperclipai/paperclip/actions/runs/41222196525)
separately exposed a fabricated successful reply after a reasoning-only
response. Later restart attempts timed out without an answer. Their
native criterion literally required restarting the instance, although
the chat instructions and authority required an operator handoff.
General authority guidance alone did not resolve it.

**Expected behavior:** A standing chat completes its current authorized
response. It performs and verifies permitted actions, verifies delegated
handoffs, or explains the specific unavailable action and operator path.
The worker's task remains separate. Ordinary execution tasks must still
complete their requested work. Empty provider responses must not become
invented success.

**Version and reproduction:** Actual pinned OpenCode and native Rust
Runner, with retained full-stack AWS attempts. Product baseline master
`51ea624344`. This PR adds no historical catalog to master.

## What Changed

- Build standing-chat completion contracts from the server-owned
conversation identity. Scope each current request to the response stage;
preserve request text, criterion IDs, order, human-response scope and
source revisions. Require verified authorized actions and truthful
handoffs. Ordinary task contracts stay strict. Existing admitted inputs
retain their saved contract during recovery; new contract content uses
the existing revision/hash mechanism.
- Guide prospective defaults to their owning resource and preserve
existing work unless backfill is requested. Guide unavailable
board/operator operations to the supported handoff. These are general
chat instructions with no eval identities or expected answers.
- Batch adjacent assistant text for at most 50 ms and 4,000 UTF-8 bytes.
Preserve text, metadata and order; flush before non-text frames and
shutdown.
- Give an empty OpenCode response one correction within its existing
turn, model, reasoning, context and deadline. Accept actual completed
answer parts with incomplete headers. Preserve actual active tool work,
bound idle evidence grace and fail truthfully if correction stays empty.
- Reject empty OpenCode terminals in Rust without actual prose or an
accepted semantic result. Never invent successful replies or evidence.
Refresh generated project-discovery contracts.
- Preserve accurate public API-discovery descriptions for existing
project defaults and managed instance restart operations, including
their field scope and authority limits.

## Verification

**Qualified: [pilot
41256592937](https://github.com/paperclipai/paperclip/actions/runs/41256592937)
passes 3/3, with all 35 independent checks passing.**

| Case | Checks | Full case duration | Evidence and cleanup |
| --- | --- | --- | --- |
| Instance restart | 9/9 | 140.1 s | complete |
| Project defaults | 11/11 | 204.2 s | complete |
| Project work | 15/15 | 204.0 s | complete |

All three are original-attempt results from source
`c51e079f7f2364305b131ffd549e263ff78c5335`, containing the exact product
files from `13c2b61f31d873a475ea0c3c026b19926ff42301`. Actual saved
conversation contracts were inspected, as were ordinary native worker
contracts where present. Each protected archive includes the actual API
state and final PNG; cleanup completes. Original queries,
`openrouter/deepseek/deepseek-v4.1-flash-1017`, finite case clocks,
concurrency one and zero eval retries are preserved. Earlier passes do
not transfer into this qualification.

Both current heads pass all checks: product **62** (56 success, one
neutral, five skipped), catalog **56** (54 success, one neutral, one
skipped). Both have exact-head Greptile **5/5**, zero unresolved review
threads and clean mergeability. The three trusted private-evidence
protocol files remain byte-identical to the dispatch workflow. Raw
evidence stays protected.

- **2,044 API discovery tests pass.** Red controls showed that “restart
instance” selected unrelated drain/settings operations and “save project
defaults” selected repository replacement. Accurate public summaries now
rank the existing operations correctly; route registration preserves
descriptions. No endpoint, permission or field behavior changes.
- **112 real-database, authenticated HTTP, native Runner and OpenAPI
consumer tests pass locally**, using disposable task-owned Docker
PostgreSQL. It was removed afterward; shared IPC was untouched. These
cover persisted contract selection, admitted native input and the model
envelope together. The isolated CI suites also pass.
- **77 focused contract/input/context tests pass.** Red controls catch
the wrong conversation predicate; canonical identity requires both agent
and user IDs, including the actual heartbeat projection. Ordinary tasks,
agent-only issues and planner tasks remain strict. Coalesced requests
preserve criterion identities, source hashes and human-response scope.
- **144 OpenCode driver tests pass**; native core **441 pass, one
ignored**; packaging **56 pass, six skipped**. Server typecheck and
build pass.
- Real pinned OpenCode/native Runner: a delayed 25-second
acknowledgement completes within the original 30-second MCP deadline.
The text-fragment control changes 817 notifications / 54.1 seconds /
timeout to 45 / 19.0 seconds / accepted finish. Separate fast,
six-minute and real authenticated API probes complete 32 tool calls plus
finish. These do not reproduce every remaining historical MCP timeout,
and no common cause is claimed for all such failures.

Retained failures remain attributed to their original source. Earlier
runs exposed fabricated empty-response success, prospective-default
backfill, a literal whole-task chat criterion, fixture readiness and
oracle/reporting defects. The immediately preceding
[41250502608](https://github.com/paperclipai/paperclip/actions/runs/41250502608),
product `c0bf249807` / source `7b1de24ce1`, is **1/3**: work 15/15;
restart 4/9 with the repaired contract actually admitted but no answer;
defaults timed out before settlement, then exceeded the unchanged 256
MiB original-evidence allowance. Defaults domain behavior on that
attempt remains inconclusive. #18377 retains the full attempt ledger,
including missing archives and pre-paid cancellations. The fresh 3/3
establishes these selected outcomes; it does not establish full-catalog
reliability.

## Risks

The shared contract change applies to standing native chats across
providers. It changes model instructions and completion scope, while
permission, approval and review gates remain enforced by their existing
owners. Incorrect model claims remain possible; the product evals
independently require actual mutations, native work and delivery. The
correction adds at most one provider request within the existing
deadline; text batching can delay adjacent text by 50 ms. Three
qualified attempts do not establish full-catalog reliability.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, tool use, code
execution and live eval tooling. Exact hosted model revision and
context-window size are not exposed.

## Checklist

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

- [x] Final same-source three-cell pilot passes 3/3 with required
evidence and cleanup

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1101.0-canary.0
2026-10-31 19:52:42 -05:00
DottaandPaperclip b889ac39b7 fix: serialize native completion replies and bounded retries (#18502)
## Thinking Path

> - Paperclip manages agents and their work.
> - A delegated task reports its result to the source conversation
through a durable completion outbox.
> - Native execution can succeed before the presentation worker saves
the accepted final reply.
> - The outbox treated that short interval as a missing answer and
cleared the target run.
> - The presentation worker then rejected the valid answer because its
delivery no longer belonged to that run.
> - This change retains the existing target for one fixed presentation
grace while accepted presentation is pending.
> - The existing presentation owner can save the reply without another
model run or more budget.

## Linked Issues or Issue Description

**What happened?**

A completion-delivery retry can run immediately after a native callback
succeeds. It clears the callback's delivery target before the
presentation worker saves the accepted answer. The reply then fails with
`chat_completion_superseded`. A daily run limit correctly blocks the
unnecessary replacement run, leaving the conversation active without its
saved answer.

**Expected behavior**

The outbox must retain its current target and attempt while that exact
native run has accepted presentation work. The existing presentation
worker must save the answer once, acknowledge the delivery, and settle
the conversation. Existing actor, session, result, digest, budget and
retry checks must remain enforced.

**Steps to reproduce**

1. Accept a native DONE result and current-turn final message for a
completion callback.
2. Run its due completion-outbox handler after terminal projection but
before reply presentation.
3. Run the existing presentation worker. Before this fix it rejects the
reply because the outbox has cleared the target.

**Paperclip version or commit**

Reproduced on `b7f1c3769c00a107ffe4128b48b0ef8cc452cf3f` through the
real PostgreSQL outbox and presentation services. The reported failure
remains preserved. A new QA run is required after deployment; local
tests do not qualify the deployed fix.

Related: #17696 schedules accepted-response recovery. #18118 preserves
canonical completion receipts. #18364 handles provider output and
response-stage contracts. Those changes do not protect the
completion-outbox target during this interval.

## What Changed

- Defer a new execution attempt when the existing selector finds pending
presentation for the same company, conversation, run and agent.
- Retain the queued delivery target and attempt with an atomic
compare-and-set. Await the existing scoped worker notification before
that write in the same transaction.
- Serialize retry with reply insertion under the existing
child-task-first lock. Recheck locked task Done state and the delivery's
stable completion-event version, status, target, attempt and exact
lease. A delivered, retargeted or newer-claim winner prevents another
wake. Admit the next attempt only after the winning transaction commits
and releases its locks.
- Limit presentation grace to five existing one-minute delivery leases,
measured from the original run `finishedAt`. Clamp both the delivery
lease and the native retry deadline to that immutable limit. Repeated
sweeps cannot extend it. After expiry, resume the existing retry,
exhaustion and daily-limit checks.
- Keep publication authority in the existing materializer. The candidate
query only defers a retry. Read the freshly reloaded delivery status,
target and saved receipt after acquiring its child-task lock.
- Fence both hold and retry writes with the exact claimed event version,
attempt and lease. A stalled old hold cannot overwrite a newer lease.
- Keep completion-event identity separate from mutable task ownership
versions. Ordinary Done reassignment preserves its existing completion
event; a real reopen retains normal supersession.
- Add real PostgreSQL coverage for the observed ordering, outer commit
and rollback, one saved reply, conversation settlement, idle SQL, retry
boundaries and superseded deliveries.
- Document the completion-outbox and presentation contract.

## Verification

- Before the fix, the real PostgreSQL regression fails with
`chat_completion_superseded` in `existingChatCompletionReply` when the
outbox handles the terminal run first. After the fix, the same test
passes without a new model wake.
- Focused command: `vitest run --project @paperclipai/server
server/src/services/native-runtime/agent-chat-response-recovery.test.ts
server/src/__tests__/chat-completion-delivery.test.ts` — **95 pass** on
`45f53a8c32fcca0bbdacf717286d37e30c1ba308`, using a disposable database
on an owned local PostgreSQL 17 container.
- Controls preserve retries for failed, cancelled, missing-final,
missing-accepted-result, old-generation, foreign-company and
foreign-agent targets. Reset or superseded task versions retain
supersession. Digest and external-context declines never authorize a
reply, never extend the fixed window, and leave it at exact expiry. An
external native deadline cannot extend the limit. A valid reply at the
last millisecond saves once without another model run.
- The first reviewed head `b6f9c484b9567bc60af6d684c04e00058c1048ed`
received Greptile 5/5 but an independent 3/5 review correctly found an
unbounded hold. Three new real PostgreSQL controls failed on that
source. This head adds the fixed bound and makes them pass. The earlier
review, controls and CI remain retained; its review score does not
qualify the new head.
- The bounded predecessor `7300d2a978a5c4b3c13d85899bed3e98ae3c49fa`
received an independent 4/5 review that correctly found an
expiry-versus-in-flight-reply race. A real PostgreSQL advisory gate
reproduced it after reply authority checked the delivery but before
insertion. The retry lock and exact claim CAS now make that control
pass. Both orderings, outer rollback, delivered/retargeted/superseded
winners and competing lease claims pass. The next-wake test can acquire
both parent and child locks, proving dispatch occurs after release. The
valid 4/5 review and failing control remain retained.
- At `39dd86e8f51d937cf382b2757736e0477201d21d`, both reviews found
valid remaining defects: the reply helper still used its pre-lock
delivery snapshot, and ordinary Done reassignment could stall a delivery
by changing the task version. Four real PostgreSQL controls fail on that
source and pass here: concurrent retry-first, a newly saved receipt
after waiting, and reassignment within grace or at expiry. A real reopen
through the issue service still supersedes the old event.
- A later coordinator review found the hold CAS still lacked the attempt
and lease fences already present on retry. A real PostgreSQL producer
barrier reproduced an old hold shortening a newer claim from 120 seconds
to 60 seconds. The same exact claim fences now prevent that overwrite.
This failed control is retained; no old run was blindly retried.
- The real worker saves one exact run-owned reply and acknowledges the
delivery only after outer commit. An outer rollback publishes no reply.
After settlement, advancing the scheduler clock by 60 seconds causes no
further SQL.
- Module boundaries, map structure, `git diff --check` and the canonical
server build (including TypeScript and Runner vendor preparation) pass.
The first local build stopped in the host package-manager setup; the
installed pinned pnpm completed the build. Full repository typecheck,
test and build gates pass in current-head CI; they have not all been run
locally.
- Final local checks also caught a test cleanup type error (TS2677) and
one 94/95 readiness failure: the worker saves its comment before
post-commit conversation settlement finishes. The test-only follow-up
removes an invalid cleanup type predicate and waits on the existing
bounded worker-quiet check before reading final state. All assertions
and the same five-second bound remain. Source
`45f53a8c32fcca0bbdacf717286d37e30c1ba308` passes all 95 cases and the
canonical server build. The earlier failures are retained.
- The final policy cleanup removes only 15 newly added narrative comment
lines (seven service, eight test), as required by CONTRIBUTING.md. Both
TypeScript AST signatures and `removeComments=true` emitted JavaScript
are identical to tested source `45f53a8c32`. This was checked with the
TypeScript 6.0.3 API and the installed native TypeScript 7.0.2 compiler.
Assertions, timeouts and behavior are unchanged; the 95 tests were not
repeated for identical compiled code.
- The superseded `45f53a8c32` CI run recorded two 15-second timeouts in
attention-retention cases. That failure remains retained. The test and
its ten inspected owner or support files are identical on the tested
master revisions. The canonical base run passes all 53 attention cases,
and the comparison PR passes the same server lane, including those two
cases in 9.3 and 9.8 seconds. This does not establish the timeout cause.
Current-head CI is a new run after the required comment cleanup, not a
retry of the failed source.
- The optional Paperclip review bot ended neutral without a completed
assessment because its execution paused. That result is not an approval.
A separate [independent read-only
audit](https://github.com/paperclipai/paperclip/pull/18502#issuecomment-6550216227)
reports 5/5 confidence on exact head
`9cfd3f74c69cc7a2da7b4ee5d1fca80f15d4af0c`, with no findings. Its manual
assessment does not replace or relabel the incomplete bot result.
- Current head `9cfd3f74c69cc7a2da7b4ee5d1fca80f15d4af0c` has a fresh
Greptile 5/5 review with no open threads. [CI run
41249007430](https://github.com/paperclipai/paperclip/actions/runs/41249007430)
passes all primary jobs and both required gates (`ci / verify` and `ci /
e2e`). All 59 PR contexts are terminal, with no failed contexts. The
actual CI checkout is `18db9e2750d6a799f26b5b8ba31bcccbea254227`, which
combines master `681f7b77262a9df6c1b4aad55291bf960061e491` with this
exact head. Fresh QA verification on the deployed application remains
required before claiming the live failure is fixed.

## Risks

A candidate can retain a delivery whose stricter presentation checks
still prevent publication, but only within the fixed five-minute window.
The existing worker keeps publication authority. If a valid reply
remains unavailable at expiry, the normal callback retry may require
another admitted model run; the original result and completed child work
remain preserved. Existing retry, exhaustion, model-run and spending
limits still apply. Failed or cancelled execution and genuinely missing
accepted output retain the existing retry path.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, tool use and
code execution. The runtime does not expose the exact hosted revision 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>
canary/v2026.1031.0-canary.18
2026-10-31 18:07:41 -05:00
DottaandPaperclip 681f7b7726 perf(server): retire aggregate maintenance polling (#18425)
Reviewed and verified at 901c4c4bdc.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.17
2026-10-31 17:22:31 -05:00
DottaandPaperclip 9ca9af544a Drive remaining live run and resource recovery from durable work (#18419)
Reviewed and verified at 6a4c193906.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.16
2026-10-31 16:00:35 -05:00
DottaandPaperclip eb12cfc96b perf(github): activate connection work from events and deadlines (#18395)
Reviewed and verified at f77620b9a4.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 15:38:43 -05:00
DottaandPaperclip 5e4cc01073 feat(workspaces): keep remote files off the webserver disk (#18403)
Keep native sandbox workspace files independent of the webserver disk. Use encrypted saved versions and Postgres ownership so a replacement server can recover files and continue work. Enable the path by default for new eligible workspaces when durable storage is configured.

Preserve explicit opt-outs and existing host workspaces. Include safe snapshot repair, Files access, import, migration and retention. Bound saved-Files resources, preserve imported Git recovery, reject unfinished Git operations, publish immutable concurrent captures, and verify permanent object-version deletion.

Validated 471 targeted local controls, build/typechecks, all 40 CI partitions, fresh Greptile 5/5 and security review. The PR records original failed attempts and scoped retries.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.15
2026-10-31 14:54:01 -05:00
DottaandPaperclip 75fa37f30f fix(server): expire native backups from retention deadlines (#18380)
Reviewed and verified at 5b137b5cda.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 14:31:31 -05:00
DottaandPaperclip 453f5fbb78 perf(external-objects): schedule scoped refresh obligations (#18384)
Reviewed and verified at 3e58e12f87.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.14
2026-10-31 14:09:24 -05:00
DottaandPaperclip 5bc029bf6c test: wait for native work and accounting before Stop redirect (#18463)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Product E2E journeys test the browser, native work and saved
outcomes on a selected deployment.
> - The Stop journey must interrupt real work before it sends a new
direction.
> - Its old boundary accepted a turn-start event before any command or
usage report.
> - A stopped attempt with incomplete usage correctly blocks later work
under the existing budget policy.
> - This pull request waits for a live native command and bound usage,
then checks actual accounting settlement before it sends the redirect.
> - The provider reports first usage after its initial command
completes, so the fixture finishes a harmless readiness call before the
long interruptible hold.
> - The benefit is a stronger test of Stop and continuation with the
same three-run limit.

## Linked Issues or Issue Description

Refs: #18098, #18345, #18354. Related accounting work: #18035.
Integrated upstream prerequisites: #18387, #18465 and #18409. Duplicate
selector PR #18472 was closed as superseded by actual merged #18409.

**What happened?**

A QA attempt clicked Stop soon after a native turn started. The owned
event stream had no command or usage report. Its cancelled run retained
incomplete accounting. The saved redirect received a skipped wake, and
no third run started. The budget guard must keep that missing usage
visible.

**Expected behavior**

The journey must first prove that actual native work is active and that
its current turn has reported complete usage. The fixture must finish a
harmless readiness command before it starts a separate bounded hold.
After Stop and physical cleanup, it must verify a complete accounting
receipt and saved settlement before sending the redirect.

**Steps to reproduce**

The fresh staging attempt failed before Stop because its first 90-second
command ended before the provider emitted its first complete usage. Its
only later eligible commands lasted less than one second. The controlled
browser sequence reproduces that ordering without accepting it.
Completed readiness usage followed by a separate still-active hold
qualifies under the unchanged oracle. Startup alone, command alone,
usage alone, partial usage, incomplete accounting and a missing
settlement timestamp still hold the next action.

## What Changed

- Request a harmless `printf` readiness command first. Wait for its
result, then request `sleep 90` exactly once in a separate shell call
before file edits. This gives the provider an opportunity to emit
current-turn usage before the interruptible hold.
- Reuse the strict native-command observer. Require a bound current-turn
complete usage report with valid nonzero token counts. Reject stale,
partial, foreign and semantic-tool evidence.
- Wait for the stopped run's complete accounting receipt,
`accountingReceiptReady: true`, `costAccountingPending: false` and a
valid saved settlement time before redirecting. A receipt already ready
before Stop is intentional only when the exact cancelled run is actually
accounted with no pending debt; no source/sequence advance or callback
clock order is assumed.
- Exclude canonical raw, partial and complete `item.completed` usage
only when the API row and PRP envelope match the authoritative owned
run, company and agent, and their source event ID, instance ID and
positive sequence agree. Missing context keeps the strict work check. A
self-consistent accounting source can change after Stop. Keep the
original snapshot and reject real tools, turns, messages and other item
events, including productive output from a new source.
- Retain private boundary and accounting proof. Source and sequence
observations do not impose unsupported controller or clock order.
Include the new oracle in the suite definition hash. Keep existing
success-check IDs, exact three runs, model, budget, deadline, Stop proof
and final outcome checks.
- Reuse one binding validator in the active-work boundary and post-Stop
filter. Pre-Stop keeps its current Runner/current-turn restriction. Add
focused evidence tests and a standalone Chromium/control-API sequence
check. The optional pre-Stop hook leaves existing classic callers
unchanged; they do not call the accounting filter.

## Verification

- Current source is `47578138ad357fc11b8b346bfada36d6aa5ab484`, one
narrow fixture commit on reviewed
`b9668ccfba61c59eb496ba18269aee06e2921d8f`. Only the prompt constant,
two ordering controls, the existing Chromium sequence and the journey
documentation changed. All oracle functions, run counts, model, budget,
deadline and check IDs are byte-identical to b966. There is no new
upstream merge or app change.
- Fresh staging failure is preserved in the [sanitized
report](https://pages.paperclip.ing/evals-qa-smoke-41227920892-1/). It
measured harness `5d3f143d0aed4dc7cf472b7891ea3d4d95ab843b` against app
`b7f1c3769c00a107ffe4128b48b0ef8cc452cf3f`; the reviewed Stop helpers
and its flow were unchanged in that harness. The original grade has
`stop_boundary_already_settled`, two succeeded native runs, and complete
cleanup. Authentication, setup, collection and cleanup passed; the
journey failed. This attempt remains failed.
- Causal timing evidence: the first shell command started at event108
and completed at111 about 90 seconds later. The first structured
complete current-turn usage arrived at113, after the hold ended.
Replaying the exact retained event metadata never qualifies that hold.
The only later eligible command intervals lasted about 0.90 and 0.18
seconds. The emitter publishes positive usage when the provider sends
its assistant-message usage update. The fixture now completes a harmless
first call before requesting the long hold; no usage is supplied or
invented by setup.
- On current source, all 137 focused tests and journey contracts passed.
Use `node node_modules/vitest/vitest.mjs run --config
tests/runner-e2e/vitest.config.ts
product-journeys/stop-redirect-evidence.test.ts
product-journeys/agent-evidence.test.ts
product-journeys/active-followup.test.ts native-event-envelope.test.ts
product-journeys/contracts.test.ts --maxWorkers 1`. New controls reject
every prefix when first usage arrives only after the hold completes.
They accept the same-turn sequence of completed readiness, genuine
complete usage and a separate active hold, and reject it after that hold
completes.
- Manual Chromium qualification passed: `node --import
./cli/node_modules/tsx/dist/loader.mjs
tests/runner-e2e/stop-redirect-boundary.browser.mjs`. The browser does
not click Stop for the failed ordering or completed readiness alone. It
clicks once for a separate active hold with bound usage. It sends one
redirect only after actual settlement. Foreign usage, productive output
and missing accounting still fail. This isolated control uses controlled
responses and does not call a model or the deployed app.
- Strict scoped TypeScript, maps, diff and secret checks passed. The
official credential-free Node24 QA runtime-import preflight passed
without network access. Full local E2E typing previously encountered old
borrowed workspace declarations; clean CI typecheck passed on b966. A
full local repository build/test was not repeated for this four-file
fixture change. Fresh canonical CI must supply the clean full gates.
- Historical binding proof remains valid: the exact old d499 filter
failed 17 of the final61 Stop tests. The shared validator checks
authoritative run/company/agent plus consistent row/envelope source
identity. Bound raw/partial/complete accounting is allowed after Stop,
including a consistent source change; productive output remains strict.
Pre-Stop still requires its current Runner and turn, complete nonzero
usage and a running command.
- Historical b966 CI `41224054720` passed all59 terminal checks, with
exact-head Greptile and Paperclip Review each5/5 and no open findings.
These are not approvals of current475. Current475 has fresh exact-head
Greptile5/5 and Paperclip Review5/5, with zero unresolved findings and
no omitted thread pages. Canonical CI
[`41229185200`](https://github.com/paperclipai/paperclip/actions/runs/41229185200)
passed on exact475. All59 checks are terminal:55 success,3 expected
skips and1 optional neutral review, with zero failed or pending checks.
No old job was retried. Fresh normal staging run41229965802 passed. Its
[sanitized
report](https://pages.paperclip.ing/evals-qa-smoke-41229965802-1/)
agrees with the independently read final original grade:11 checks, all5
phases, exactly3 native runs and cleanup passed. The final manifest is
complete, with cleanup complete and no pending evidence. Smoke, report
publication and Slack outcome jobs all succeeded.
- The live pass measured harness
`6be20bef6d0c5077adc1ae99562ad84e756ab167` against app
`b7f1c3769c00a107ffe4128b48b0ef8cc452cf3f`. Its Stop oracle, flow,
shared binding validator, unit cases and Chromium control are
byte-identical to reviewed475. The shared agent-flow file adds only the
hiring import and early hiring dispatch; all remaining bytes match. This
records the actual harness and app identities separately.
- Canonical run readback confirmed the first run succeeded, the second
was cancelled and the third succeeded. The cancelled run had a ready
native-producer accounting receipt, no pending accounting and a saved
settlement time. After verified file copyback, Core queued final
destruction and followed its normal five-minute cleanup backoff. The
exact lease naturally reached expired/cleanup-success with a bound
destroyed receipt before the third run started. No operator cleanup,
source change, timeout extension or workflow retry was used. The earlier
failed staging attempt remains failed.
- Current475 is ready for the normal reviewed merge and QA admission
process. Source stays frozen; merge and configuration changes belong to
that process.

## Risks

- Some provider profiles may not expose a valid current-turn usage
report while the command runs. The stronger boundary fails closed in
that case.
- Accounting may remain incomplete after Stop. The redirect stays unsent
within the original deadline. This change does not waive missing debt,
treat it as zero, raise a budget or change provider behavior.
- This repairs the test boundary. It does not prove or repair a general
provider shutdown-usage issue. A separate local late-usage ordering
control is not attributed to this QA incident.

## Model Used

- OpenAI Codex, GPT-6 family. The exact deployment variant and
context-window size are not exposed in this session. Used code
reasoning, repository tools, test execution and browser automation.

## 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-31 13:49:02 -05:00
DottaandPaperclip c32ecf6657 fix(server): schedule only outstanding merge confirmations (#18382)
Reviewed and verified at bc22051c56.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 13:44:46 -05:00
Nicky Leach 6484f96c28 fix(workspaces): inspect storage only when needed (#18410) 2026-10-31 11:43:18 -07:00
DottaandPaperclip 9a3f395737 fix(server): settle routine history without idle scans (#18399)
Reviewed and verified at 0b65f490d9.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.13
2026-10-31 13:19:31 -05:00
Dotta 3937215a05 Qualify explicit native written references in the basic question journey (#18459)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Basic task journeys must prove that people can answer an agent and
receive saved work.
> - The question journey asks for a choice, then a typed reference, then
a saved note.
> - A native choice card can offer a real written-answer control as well
as predefined options.
> - The old observer rejected that form before a person could type the
reference.
> - This pull request accepts that explicit native control and keeps
exact answer and work evidence.
> - The separate text-only and named-tool qualifications keep their
stricter contracts.

## Linked Issues or Issue Description

Refs #18346 and #18456. The integration inherits the reviewed fixture
prerequisite #18387 and Agent Chat recovery #18465 through their actual
merged parent. The producer fix in #18456 is separate from this basic
journey contract correction. Public duplicate PR and issue searches
found no other correction for this form equivalence.

**What happened?**
The basic question journey requires the reference card to have
`answerMode: text`. It rejects a native single-select card even when its
canonical form explicitly enables a written answer. This makes the
observer test a widget shape in addition to the requested behavior.

**Expected behavior**
The person must make a real choice and type the complete reference. A
native card with an explicit written-answer control can satisfy the
second step. Selecting a predefined option cannot satisfy it. The agent
must resume the bound work and save both actual answers in its own task
document. The document must survive reload.

**Steps to reproduce**
Use the focused recording and real QuestionForm browser test in this PR.
Keep the reference as a single-select native question with one
predefined option and `customAnswer.enabled: true`. The previous grader
rejects `question-resume.forms`. The previous browser helper rejects
`single_select` before it uses the written-answer control.

**Paperclip version / commit**
Original source base `f2db909393de124caf6a5380a52d4e0e1d621661`. Current
integration `a417fd827347ed6f7998774a9de6aee70b76d867` merges exactly
`12b0cc630471ee151ec5bc8e41a34f09236d6723` into reviewed question source
`faec4ce6d775a34d303d200987e4e84d6dc26caf`. The scheduled failure on
`82d15946c5844d3ae41c6ade62fa224053f20a9a` remains a failure. Its saved
card had no canonical written-answer capability and would still fail
this change. The retained normalized events do not prove whether the
original provider flag was omitted or false.

**Deployment mode**
Attached native task journeys, including QA Cloud. This PR changes the
observer and grader. It does not change the app, provider prompt, model,
budget, timeouts, cleanup, or runtime deployment.

## What Changed

- Accept one provider-bound single-select reference card with explicit
canonical custom answers and valid, distinct options. Keep pure-text
reference support.
- Make the browser select the actual written-answer control and fill the
real rich input. Opt in only for the basic question journey.
- Keep the exact no-option typed response, immutable card, board actor,
native request and continuation, saved agent document, reload, model,
environment, checkpoints, and existing one-to-three-run checks.
- Reject missing or disabled custom capability, inferred legacy
capability, malformed or extra questions, foreign native identities,
changed cards, substituted options, and wrong or missing reference text.
- Add a real production QuestionForm and TaskChatRichInput Chromium
probe. It first selects a predefined option, then proves the helper
clears it and submits only the exact custom text.
- Document the contract correction and preserve the historical failed
attempt and its separate cleanup outcome. Keep necessary-question and
named-tool documentation qualification unchanged.

## Verification

- Before the observer change, the focused grader regression failed only
the new valid-written-reference case; the other 108 cases passed.
- Before the browser helper change, real Chromium passed the text
control and four rejection controls but failed the valid native
written-answer control at the old pure-text assertion.
- Initial focused Runner E2E unit selection at `af07f4de`: **256 passed
across 9 files**. This includes question/resumption, clarification
evidence/flow/collection/deadline, necessary question, documentation,
contracts, and report catalog tests.
- Initial real Chromium selection at `af07f4de`: **12 passed**. Six new
production QuestionForm/control checks and all six existing
document-readiness checks pass. No form or rich-input component is
mocked.
- Historical test-only head `faec4ce6d775a34d303d200987e4e84d6dc26caf`
adds a direct canonical-absent legacy `freeText` grader negative and
renders the actual legacy presentation in the browser. All four
production helper blobs remain identical to the reviewed head. A
temporary legacy inference mutant makes the new negative fail. After
restoring production source, **179 focused unit tests and all 6 real
QuestionForm checks pass**. The six document-readiness specs and their
helper are unchanged.
- Original [CI run
41205748589](https://github.com/paperclipai/paperclip/actions/runs/41205748589)
failed the staged-listen Runner handoff test; that failure is preserved
and was not retried. Its Runner source closure was identical to an
earlier passing canonical lane. The symptom also recurred on other heads
and is tracked independently; no infrastructure attribution or live pass
is claimed.
- Current integration `a417fd827347ed6f7998774a9de6aee70b76d867`
preserves **all 12 question files byte-for-byte** from faec. Every other
tracked path is identical to exact merged parent
`12b0cc630471ee151ec5bc8e41a34f09236d6723`, which contains actual
prerequisite `baf651c8d0122efc93f3ef03e891919eeb666215`. There is no
manual conflict resolution or additional production edit.
- On that integrated head: **257 focused Vitest tests across 9 files,
206 required Node source/reporter tests, and 12 real Chromium tests
pass**. Map/module-boundary checks and catalog discovery pass. The
actual `--preview` command passes with a synthetic question target and
an intentionally unavailable adapter; it performs no credential read,
adapter loading, provisioning or model call. It retains maxRuns3, a
600000ms campaign bound and zero retries.
- Exact-head [CI run
41210806950](https://github.com/paperclipai/paperclip/actions/runs/41210806950)
passes, including official typecheck, build, all eight browser shards,
both Runner Vitest lanes and aggregate verify. All 59 current PR
contexts are terminal with no failures. Fresh [Greptile
summary](https://github.com/paperclipai/paperclip/pull/18459#issuecomment-6543878408)
explicitly reviews `a417fd827347ed6f7998774a9de6aee70b76d867` at 5/5
with no findings; its exact-head check succeeds and all threads are
resolved. No fresh deployed journey pass is claimed yet.
- Catalog discovery lists the existing question journey. Map checks and
module-boundary checks pass. Diff checks pass.
- `tsc -p tests/runner-e2e/tsconfig.json` was attempted. The fresh
integrated checkout still lacks compiled Runner, plugin SDK, and adapter
declarations. The attempted local check reports 344 diagnostic lines
from dependency/type closure and zero diagnostics in all 12
question-owned paths. Official exact-head CI establishes the full
typecheck/build gates. Full repository build, typecheck, and test suites
were not repeated locally for this observer change.
- The first broad local report selection lacked the CLI loader and then
hit sandbox IPC restrictions. Locked dependency installation and an
authorized local IPC run resolved those setup errors; the full selected
256 tests pass. The initial localhost probe also needed the normal
local-listen permission.
- No fresh QA pass is claimed. The coordinator must qualify the final
reviewed runtime and harness together. Prior failed results remain
preserved.

## Risks

The basic journey accepts one additional form with explicit native
provenance. It still rejects the original closed card without a
written-answer capability. The separate producer default fix must reach
the selected remote provider pack before it can affect a deployed run.
Local browser and grader tests do not prove that artifact served or that
a model completed the live journey. Existing cleanup and physical-stop
obligations remain separate.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, source inspection, browser
testing, and code execution. The host does not expose the exact
underlying model version 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 available version and
capability details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
related work above
- [x] I have described the issue in-PR following the bug 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 or instance-derived details
- [x] I have run the selected tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-10-31 13:16:40 -05:00
DottaandPaperclip 91fdf02e95 perf(tasks): defer completed transcripts on compact opens (#18461)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task conversations must show the saved instruction and recent
replies quickly.
> - Compact task reads already limit the saved message window.
> - The conversation still waits for completed run transcripts even when
a saved reply contains the result.
> - Removing that wait alone can insert activity after the reader starts
reading.
> - This pull request defers that output until the reader opens history
and keeps required output in the initial reveal.
> - The benefit is a useful conversation sooner, with a stable first
layout and a working composer.

## Linked Issues or Issue Description

Refs #17593, #18092, #18312, #18358, #18422.

**What happened?**

Opening a task with a long saved investigation can wait for native
events or legacy logs before showing its existing replies. A slow
transcript request can hold the conversation behind the loading screen
until the 15-second fallback.

**Expected behavior**

Show the bounded saved conversation without reading completed output
that already has a usable saved reply. Keep that output available
through the existing history controls.

**Steps to reproduce**

1. Create a task with many completed runs and long saved agent replies.
2. Delay its run events and logs.
3. Open the compact task directly. Before this change, the transcript
read blocks the saved replies and composer.

## What Changed

- Defer completed successful run transcripts on compact task opens when
a usable saved reply is present. Load that output through the existing
history controls.
- Keep required output on the initial path: live and failed runs,
yielded runs, pending interactions, placeholder/progress-only replies,
explicit anchors, chats, and full history. Retain output already
selected during this visit when its run completes.
- Keep saved plans visible when their owning run output is deferred or
still loading.
- Keep the same composer and draft through history expansion. Offer
**More run output** when a single saved run has deferred output.
- Position same-task comment links after their target arrives. Wait only
for a missing target, with a 15-second limit. Unrelated stalled metadata
cannot block an available target after the reveal deadline.
- Preserve the reading anchor when a queued scroll event arrives during
a properties-pane width transition.
- Add a 200-reply/200-run PostgreSQL browser fixture with a saved plan,
covering both task views on desktop and mobile. Correct stale browser
setup for current routes and the shared mobile scroller.
- Remove a random company-prefix collision in the isolated privacy test
fixture that failed during CI.

## Verification

- Final revision `fba3f2fcbb`: 386 focused thread/scroller unit cases
and all 32 production-browser journeys passed. The browser cases cover
both task views on desktop/mobile, saved plans, delayed transcripts,
history, comment links, Back, drafts, retry, avatar continuity, media
and pane resizing. The 25 privacy fixture cases also passed against
PostgreSQL.
- Workspace typecheck and full build passed with Node 24. A broader
local UI run passed 10,220 cases across 849 files before the final
navigation/plan review fixes; the changed components were then rechecked
in the 386-case focused run.
- Five alternating pairs compared master `12b0cc6304` with this
revision, using 200 long saved replies and 200 completed native runs.
Both production UI builds used the same loopback API/database, Chromium
151.0.7922.34, 1440 × 900, fresh browser contexts, service workers
blocked, no CPU throttle, and a controlled 3-second events/log delay.
Builds and other suites were stopped during measurement. No page errors
occurred.

| Useful conversation + editable composer | Baseline median (range) |
Fixed median (range) |
| --- | --- | --- |
| Cold direct open | 3.570s (3.538–3.616s) | 1.056s (1.022–1.141s) |
| Task-list navigation | 3.373s (3.342–3.394s) | 0.899s (0.885–0.915s) |
| Back | 22ms (22–25ms) | 25ms (25–28ms) |

- Median paired savings: 2.519s cold, 2.470s from the list.
Completed-output requests: two per baseline sample, zero per fixed
sample. Recent-comments API control medians were 13.6ms for both, with
ranges 12.1–18.7ms and 11.6–50.8ms. No Back improvement is claimed; an
earlier revision's run also included one 1-second Back outlier, retained
in the local evidence.
- The full local default test command did **not** pass: it stopped on
the existing chat test line-selection error. After restoring embedded
PostgreSQL library symlinks omitted by an install with scripts disabled,
Node 24 passed 672 cases in the first two chat shards, then failed to
select the third. This is separate from the passing focused suites and
remote CI.
- Earlier CI failures were addressed: the privacy prefix collision is
fixed; the delegated task-completion reply case passed locally after
merging master's reply-recovery fix (#18465). Browser fixture
corrections retain the original behavior assertions. Red tests
reproduced the loading, navigation, resize and saved-plan regressions
before their fixes.
- Map, module-boundary, token-gate and added-line token checks passed.
The full-tree token scan still finds pre-existing active-username
fixtures; this PR adds zero forbidden token lines.
- Greptile: **5/5**, final revision, all four review threads resolved.
The final-revision PR CI workflow passed, including build, typecheck,
all server/chat/workspace test shards, all eight E2E shards, and every
Runner lane. GitHub reports 55 successful checks and three skipped
checks. The separate **Paperclip Review** check remains queued with
**Waiting for the assigned agent**; it has not produced an assessment
and has not been bypassed. The branch has no merge conflicts.

## Risks

- The default compact task omits completed transcript details when the
saved result is sufficient. The reader must open history to inspect
them.
- Required structural data remains inside the initial reveal boundary.
Slow server responses for that data remain visible latency.
- Link positioning falls back after 15 seconds when its target never
arrives. The conversation remains readable.
- The measurements use a controlled local delay. They do not establish a
deployed staging speedup.
- No API, schema, authorization, or migration changes.

## Model Used

OpenAI Codex, GPT-6, with 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
- [ ] I have run tests locally and they pass (focused suites pass; the
full default wrapper has the existing selection error 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
- [ ] All Paperclip CI gates are green (code CI passed; the separate
assigned-agent Paperclip Review remains queued)
- [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-31 12:56:06 -05:00
DottaandPaperclip dce383c733 perf(server): stop recurring attention retention scans (#18388)
Reviewed and verified at a61af9888e.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.12
2026-10-31 12:28:40 -05:00
DottaandPaperclip b6b57079b9 fix: evaluate status cards on committed changes and deadlines (#18401)
Reviewed and verified at 21795e222a.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.11
2026-10-31 11:41:59 -05:00
DottaandPaperclip e40de0c9e8 perf(ci): refresh test weights and narrow graph dependencies (#18464)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Contributors need fast, reliable CI feedback.
> - Diff-aware CI selects test files and partitions them into runner
jobs.
> - Stale cost estimates put several slow suites on the same runner.
Broad imports also couple small tests to large modules.
> - This PR refreshes test costs, runs independent graph discovery in
parallel, and narrows three dependency boundaries.
> - Selection safeguards and CODEOWNER-only AWS routing stay in force.

## Linked Issues or Issue Description

Refs #18398. This follows the audit of [PR #18427's verification
run](https://github.com/paperclipai/paperclip/actions/runs/41169978784).

The audit found 403 selected general-server files without timing
weights. Three suites measured at 232s, 122s and 116s shared one shard
because each received a roughly 2s fallback weight. Local graph
discovery across four projects took 43.7s serially and 21.7s with two
workers. A reverse-order repeat took 37.7s serially and 22.6s with two
workers. Both comparisons produced identical selection results. This is
a local measurement, not a claim about production CI speed.

## What Changed

- Refresh general-server costs for 1,285 of 1,309 current files and
serialized costs for all 163 files from two successful protected-master
Cloud readiness runs. Retain prior costs for unmeasured files, including
dedicated chat and native-runner suites.
- Record passing server file costs, including collection, setup and
environment preparation. A weekly hosted workflow validates trusted
source runs and opens a timing-only PR. It tests shard coverage, pauses
while a refresh PR is open, and never merges automatically.
- Discover at most two project graphs concurrently in isolated,
heap-limited Node processes. Cache repeated inventory reads within one
selection. Worker errors and timeouts retain the full task plan.
- Fetch only the merge commit and parents for the selector. A real
shallow-clone regression proves the complete diff still includes more
than 300 files, renames and deletions.
- Share the identical log viewer and run details between both
AgentDetail pages. The viewer test imports the shared implementation and
runs each of its 13 distinct cases once.
- Extract the pure API error class while preserving the API client's
public exports. Import delivery work signals through their existing
narrow DB export.

## Verification

- PASS: `pnpm -r typecheck` and `pnpm build`.
- PASS: 284 CI selection, timing, shallow-diff, sharding and routing
tests.
- PASS: 74 further cache, routing and graph-proof tests.
- PASS: 94 targeted UI assertions across the viewer, run invocation, API
errors/client and progress helpers. All 76 assertions in the 12 server
suites made independently selectable also pass.
- PASS: `pnpm check:token-gates`, module-boundary checks, YAML parsing
and `git diff --check`.
- PASS: [Full PR CI and required `ci / verify`
aggregate](https://github.com/paperclipai/paperclip/actions/runs/41206683345),
including all 12 general-server shards, all nine serialized shards,
workspace groups, chat suites, Runner lanes and build checks.
- PASS: [GitHub hosted real-workspace selector and cache/routing
qualification](https://github.com/paperclipai/paperclip/actions/runs/41206683205).
- PASS: Both Greptile and Paperclip reviews are 5/5 with no actionable
findings or inline comments on `7dc65c51b8`. The PR has no merge
conflicts.
- PASS: The production refresh parser accepted all 107 structured
file-cost records from a real successful server CI job, including
setup/loading cost.
- Local `pnpm test:run` completed all six chat shards successfully. The
duplicate monolithic local run was stopped after the complete remote
suite passed; it was not completed locally.

The focused log-viewer command improved from 18.84s (26 duplicate
variant cases) to 8.49s (all 13 distinct behavior cases). The dependency
audit confirms 12 server files and the API-error test no longer need
conservative always-run retention. Repartitioning the audited PR with
the new costs changes the slowest shard from 810s to 591s of summed
historical test execution (1,124 of 1,142 files measured). This is a
workload simulation, not measured new CI wall time.

## Risks

- Two graph processes use more peak memory. Each has a 2 GiB heap limit
and a three-minute timeout. Any failure preserves the original task
plan. Real workspace qualification runs in GitHub CI.
- Historical logs contain test/hook costs only. New reporter records add
loading/setup costs after merge. The manifests identify measurement
coverage and source runs. These weights change placement, never
permission to skip tests.
- Runner load adds timing noise. The refresh uses medians and requires
at least 90% measurement coverage in each lane.
- GitHub may require approval to run checks on a PR created with
`GITHUB_TOKEN`. Refreshes remain reviewable and do not merge themselves.
- The shared viewer is a mechanical extraction. Both pages retain their
existing exports, and the behavior assertions remain covered. AWS runner
authorization is unchanged.

## Model Used

OpenAI Codex, GPT-6, with repository inspection, reasoning, code
execution and GitHub tools. The exact deployment ID and context-window
size were not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub references)
- [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 (focused checks and six
chat shards; complete suite passed in CI as detailed 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-31 11:05:12 -05:00
DottaandPaperclip bacbab2bc1 test(testops): retain safe verification failure predicates (#18470)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat feature evaluations send their original results to TestOps.
> - A final reader checks the stored case, run, source, status, and
attachments.
> - Two real chat cases passed, but the final reader returned a generic
mismatch.
> - Later server responses passed the same reader, so they do not
explain the earlier failure.
> - This change records the exact failed predicate without recording
field values.
> - The next failure can be diagnosed in its actual caller context.

## Linked Issues or Issue Description

Refs #18462, #18394, and #18322. The current base includes the
independent browser-fixture fix in #18409.

**What happened?**

The post-upload reader returned `chat_testops_upload_mismatch`. Its
closed artifact had no phase or field detail. The original evaluation
and TestOps case passed. Later responses from the same five endpoints
passed the unchanged reader. Those later interactive responses do not
prove what the protected API caller received at failure time.

An earlier CI run also exposed a flat-text browser-fixture mismatch.
Current master independently fixes that assertion in #18409. This branch
adopts that complete upstream test; the final PR diff contains only the
two diagnostic files.

**Expected behavior**

Keep every report-reader acceptance check. Report a fixed phase, failed
predicate names, match booleans, and field type names. Do not record
response values, credentials, unknown URLs, or traces.

**Steps to reproduce**

1. Supply a missing case ID, a conflicting job ID, or a wrong export
field to the reader.
2. Project the failure with `failureProjection`.
3. The parent returns only the generic error code. This change also
identifies the failed check and distinguishes a missing field from a
value of the wrong type.

**Paperclip version or commit**

The latest retained failure used
47f81e850b. The branch now includes
current master `3ee4c5b6138da82d0b1f51aa010540561bf43c22`. The upstream
API is unchanged.

**Deployment mode**

GitHub Actions and AWS, with TestOps reporting.

## What Changed

- Add private diagnostics to the existing same-code failure throws.
- Emit only fixed names, booleans, and closed type names through the
existing failure projection.
- Copy projected metadata so a caller cannot change the stored
diagnostic.
- Add failure-path, missing-versus-conflicting-field, and
secret-redaction controls.

## Verification

- Five new controls fail against the original parent module. A combined
early-mismatch/null-entry control also fails against the first
diagnostic implementation. Null-safe diagnostic traversal preserves that
known failure.
- `node --test tests/runner-e2e/chat-feature-testops-api.test.mjs`: 53
passed.
- The existing CLI, reporter facade, and exporter tests: 22 passed.
- Both changed MJS files pass `node --check`. `git diff --check` passes.
- The earlier browser-fixture failure remains recorded. The owning test
is now byte-identical to the independently shipped base fix in #18409.
No browser-test or production-file delta remains in this PR.
- Removing the private diagnostics and restoring the ten original throws
reconstructs the entire parent API file byte for byte. Acceptance
expressions, API order, deadlines, and successful output are unchanged.
- All five retained current server responses still produce VERIFIED.
Successful output matches the parent output byte for byte. These
responses used interactive authentication at a later time; the original
protected-token failure remains unexplained.
- Local checks used Node 26.4. Normal CI
[41213493964](https://github.com/paperclipai/paperclip/actions/runs/41213493964),
attempt 1, passed on 78a40d6b67. Both
required checks passed, including browser e2e. The adopted upstream
browser shard passed. Greptile is 5/5 on this head, and all review
threads are resolved.
- Full local typecheck, build, app, database, native SDK, provider, and
model runs were not run. The diagnostic slice uses pure tests, mocks,
and file-system controls.
- No public command or user-facing behavior changes. No documentation
update is needed.

## Risks

- A diagnostic must not expose a sensitive value. A private WeakMap,
fixed field names, boolean checks, and closed type names limit the
output. Tests include synthetic secret strings and mutation attempts.
- Diagnostic checks mirror validation to keep the original guards byte
for byte. Future validation edits must update the paired diagnostic and
its targeted controls. This is a known maintenance tradeoff.
- This patch does not explain or erase either historical reader failure.
It changes no Product E2E grade, model, retry, source guard, API route,
workflow, or deadline.
- Live failure diagnostics remain unqualified until a later authorized
run uses this code.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, with reasoning, source inspection, and code
execution. The host does not expose the 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 (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-31 11:04:56 -05:00
DottaandPaperclip b7f1c3769c feat(native): record verified provider-pack session admission (#18469)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Remote native sessions can use an installed pack or a retained
earlier pack.
> - The current app revision does not identify the pack that a session
admitted.
> - Core already verifies the selected pack and binds its launch
artifacts.
> - Normal run records lack a closed receipt for that admitted
selection.
> - This pull request records that receipt after session admission and
attachment.
> - Operators can compare the actual Core admission identity with their
expected pack.

## Linked Issues or Issue Description

Refs #17749 for protected provider-pack selection and #18343 for
retained controller recovery. The related OpenCode producer repair is
#18456. Those changes do not publish the closed run receipt added here.
A search found no existing `nativeProviderPackAdmission` PR.

**What happened?**

Core can admit a compatible installed provider pack with a source
revision that differs from the current app. A retained session can also
keep its original pack. The normal run record does not show the admitted
pack digest, proxy digest, and source revision. An expected launch path
or current app revision cannot fill that evidence gap.

**Expected behavior**

The run has a closed, server-owned receipt after actual session
admission and attachment. The first receipt remains immutable history. A
separate current-proof state verifies only the actual current admission
epoch. Retained recovery needs positive original provenance, and missing
legacy evidence stays unknown.

**Steps to reproduce**

1. Select and verify an installed pack whose digest differs from the
current app pack.
2. Open the native session successfully.
3. Inspect the normal run profile for a bound admission receipt.

**Paperclip version or commit**

The original selected base was
`8bcc5a01edd5d87540401521e6f30d3df43e1848`. The branch now includes
exact actual prerequisite parent
`3ee4c5b6138da82d0b1f51aa010540561bf43c22`; the PR diff against it is
the five receipt, executor, test and documentation files.

**Deployment mode**

Core remote native execution with provider-pack selection and retained
session attachment.

## What Changed

- Retain the verified selected pack identity only after a backend
returns the matching admitted session.
- Publish `runnerProfileJson.nativeProviderPackAdmission` from the
session callback after attachment succeeds.
- Mark the receipt with `stage: session_admitted` and `authority:
core_verified_selection`.
- Store bound company, agent, run, session, runner, logical
`runnerEnvironmentLeaseId`, pack digest, OpenCode proxy digest, and
source revision fields. Retained attachments identify
`inheritedFromRunId`. The logical Runner scope is distinct from the
physical environment lease.
- Lock the current coordinator claim before the profile write. Check
owner, attempt, generation, controller boot, lease expiry, phase, and
absence of an accepted result. Merge JSON fields without replacing other
profile data.
- Restore retained metadata only from the exact prior closed Core
receipt, positively verified prior state and matching retained binding.
Capture same-run prior provenance from the locked claim row before
invalidation; cross-run recovery reads only the exact source. Legacy
absence remains unknown while recovery continues.
- Preserve the first receipt as history. Atomically mark a new opaque
admission epoch pending in the existing mandatory claim transaction.
Publish current verification only for the matching claim and epoch after
actual attachment; changed or unsupported admission becomes unknown
without blocking authorized execution.
- Preserve synchronous session publication and quarantine ordering
before the best-effort receipt write. Fresh replacement selects its
newly verified pack; a captured retained-process flag cannot relabel the
replacement with an older pack. Preserve the existing private pack
authority even when a local dirty revision is ineligible for the closed
receipt.
- Add focused admission, recovery, identity, PostgreSQL ownership, lock,
and JSON-preservation tests. Document the receipt contract.

## Verification

- RED: the actual managed-backend path verified and admitted an
installed pack but had no closed metadata. Failed open published no
evidence. Additional controls fail when retained recovery invents
missing history or dirty-revision eligibility gates the existing private
authority.
- RED calibration: removing mandatory pending invalidation fails the
actual pre-admission control; reusing the retained flag for fresh
replacement falsely restores the old pack. Removing the epoch fence
fails the real PostgreSQL stale-callback case; reintroducing a
receipt-specific execution error fails both authorized
Runner/logical-lease replacement controls.
- GREEN: 49 focused Core tests, all 33 admission identity/transaction
tests (20 pure and 13 PostgreSQL), and all 23 existing private-authority
tests passed on exact integrated head
`165a9096cf3e0d34d2db1e6b52960ad4ac0ad132`. No all-skipped run is
counted.
- Final test-only head `11ac34baf00552a5d322b5f5f1a8e491859cacec` adds
the positive executor-callback SQL-writer wiring control, exact
session/identity/claim/epoch assertions, profile preservation, and
null-session zero-write check. Removing only the production writer call
makes it fail on a missing receipt. All70 focused identity/Core tests
pass with this closure; production code, the13 PostgreSQL tests and
the23 private-authority tests are byte-identical to the qualified165
source (106 distinct passing controls across the combined proof).
- The PostgreSQL tests used an owned loopback-only cached Postgres 17
container with the supported `PAPERCLIP_TEST_POSTGRES_ADMIN_URL` helper
and aliases to current DB/shared source. The container was removed
afterward. They cover immutable history, JSON preservation, stale claims
and epochs, expired leases, terminal runs, changed/unsupported
replacements, and a failed write retaining pending proof.
- Historical pushed `f7f12fe` CI executed all 24 earlier admission
tests, including nine PostgreSQL cases, in server5. Its warm-quarantine
failure exposed the new hook-ordering issue fixed here. The same run
also encountered a six-character UUID fixture-prefix collision and the
independently repaired cached issue-link browser selector; those
historical failures are not claimed as green.
- Node 24.22.2 and Vitest 5.0.3. The credential-free normal QA runtime
import preflight passes with networking disabled. Map contracts, token
gates and `git diff --check` pass.
- Local TypeScript validation still sees stale borrowed Runner/shared
declaration mismatches outside the changed ranges. No diagnostics remain
in the new helper or changed test/hook ranges; clean current-head CI is
required.
- Repository-wide typecheck, full tests and build were not completed
locally. A full local executor attempt reached this host's unsupported
native PostgreSQL listener and was interrupted; its result is not
counted. Canonical run `41214512239`, attempt 2, is successful on exact
final head `11ac34baf00552a5d322b5f5f1a8e491859cacec`. All 59 checks are
terminal: 55 success, 3 skipped and 1 neutral; none failed or pending.
The actual Linux suites execute all 33 admission tests (including 13
PostgreSQL cases) and all 1,022 executor tests successfully. The
[original five failures and bounded unchanged-source
controls](https://github.com/paperclipai/paperclip/pull/18469#issuecomment-6545593767)
remain preserved. One failed-only request was made; GitHub expanded the
reusable workflow call and dependents. No second request was made. Fresh
exact-head Greptile review is 5/5, all review threads are resolved, and
the PR is mergeable.
- These local results claim no live provider admission, rollout or
recovery.

## Risks

- The authority is Core's verified selection plus successful session
admission. It is not an independent provider statement or continuous
runtime measurement.
- Receipt fields cannot grant execution or replace the existing
provider, process, lease, workspace, or recovery checks.
- Legacy missing receipts and unavailable database reads remain unknown.
The current release cannot label an older admitted pack.
- The closed receipt requires a clean, 40-character hexadecimal source
revision. Verified local `-dirty` packs still execute and retain their
existing private recovery authority; their closed admission proof stays
`unknown`, so it cannot certify an immutable source revision.
- The first receipt is historical. Consumers must require current state
`verified`; pending or unknown cannot certify the current pack. Changed
Runner scope or pack evidence does not add execution policy.
- A receipt save failure leaves the atomically invalidated state
pending. The existing artifact authority, cancellation, workspace and
process checks remain responsible for execution safety.
- The receipt adds no manifest, environment, credential, or filesystem
path to the run record.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code editing, and tool
use. The session does not expose an exact model build ID or
context-window capacity.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub references)
- [x] My branch name describes the change and contains no internal
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>
canary/v2026.1031.0-canary.10
2026-10-31 10:59:24 -05:00
Devin FoleyandPaperclip 51ea624344 fix(server): reject a native run's own task status change (#18411)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native runs (the Paperclip Runner) report their outcome with
`paperclip_finish` or `paperclip_block`, and the status arbiter then
sets the task status
> - Every runner tool, `paperclip_finish` included, requires that the
task's `executionRunId` is the current run
> - When the run sends its own status change through `PATCH
/api/issues/{id}` (for example with `call_api`), the issue update clears
`executionRunId` and `checkoutRunId`, so the run removes its own
execution lock
> - After that, every tool call fails, the run cannot report, same-run
recovery spends its retries, and the task goes to `blocked`
> - This pull request rejects that status change with a 409 before it
commits, and the message tells the run to report with `paperclip_finish`
or `paperclip_block`
> - The benefit is that the run corrects itself in the same turn, and
the task does not get stuck

## Linked Issues or Issue Description

No public issue exists. This is the bug description.

**What happened?**

An agent on the Paperclip Runner followed task instructions that said
"set the task to `in_review` and keep it assigned to yourself" while it
waited on a scheduled monitor. It sent `call_api` with `PATCH
/api/issues/{id}` and `{ "status": "in_review" }`. The server applied
the change and cleared the execution lock. Then:

1. `get_task`, `set_task_monitor`, and `paperclip_finish` all failed the
run binding check. The provider saw only "Paperclip semantic operation
failed", or the monitor-wait message from `paperclip_finish`.
2. The `call_api` receipt for the PATCH showed `status: null, outcome:
unknown`, because the authority check after the response failed when the
lock was gone.
3. The session ended with no semantic result. Exact-checkpoint resume
ran out of retries (`native_session_retry_exhausted`), and recovery
would not replay the run because the mutation outcome was unknown. The
task went to `blocked`.

This occurred on each check where the agent tried the status change.
Runs that did not try it completed normally.

**Expected behavior**

A native run that holds the task's execution lock cannot remove its own
lock. It gets a clear, actionable error and reports its outcome through
`paperclip_finish` or `paperclip_block`.

**Steps to reproduce**

1. Assign a task to an agent that uses the Paperclip Runner (native
runtime).
2. While the run executes, have it send `call_api` with `PATCH
/api/issues/{id}` and `{ "status": "in_review" }` for its own task.
3. Look at the next tool calls of the run. They fail, `paperclip_finish`
cannot complete, and recovery blocks the task.

**Paperclip version or commit**

`master` at 493e229d93.

## What Changed

- `server/src/routes/issues.ts`: add
`assertNativeRunKeepsOwnExecutionLock` to `PATCH /issues/:id`. The guard
returns 409 `native_run_status_reported_by_finish` when all of these are
true:
- the actor is the assigned agent, and its run is the task's execution
or checkout run
  - the run is `native` and `running`
  - the request changes the status and keeps the assignment
  - the task is not a conversation
- The 409 message names `paperclip_finish` (`needs_review`, `done`, or
`yielded` with a `monitor` continuation) and `paperclip_block`.
`call_api` returns HTTP denials as data, so the provider can read the
message.
- Conversation tasks are out of scope. A conversation turn settles from
its final reply (`nativeConversationReplyResult`), not from a runner
tool. So a reply that moves its conversation to `in_review` still
settles, and that contract stays.
- When the request also carries blockers, the guard first runs
`assertOnboardingFirstTaskDependenciesAllowed`. A blocker that the
dependency rules reject keeps its specific 400. Every other case gets
the 409, including `{ "status": "todo", "blockedByIssueIds": [] }`.
- `server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts`:
add 14 cases. They cover rejection for `in_review`, `done`, and
`blocked` (also with an explicit self-assignment, an empty blocker list,
and a real blocker), and the onboarding 400 that wins over the 409.
Pass-through cases assert a 200, the patched status, and one update for:
other field edits, legacy runs, native runs without the lock, stopped
runs, handoffs to a human (after a confirmed stop), conversation
replies, and board users.

## Verification

- `npx vitest run
server/src/__tests__/issue-agent-mutation-ownership-routes.test.ts`
passes (193 tests).
- With the guard disabled, the 4 rejection cases fail. With the `native`
runtime condition removed, the legacy pass-through case fails. The tests
pin both sides.
- `chat-project-tools` and `onboarding-first-task-admission` pass (74
tests). These are the integration suites that caught the first version
of the guard in CI.
- `npx vitest run` on `issue-queued-comments-routes`,
`task-workspace-binding`, and `issue-recovery-actions` together with the
ownership suite passes (455 tests).
- `npx tsc --noEmit -p server/tsconfig.json` is clean after `pnpm
--filter @paperclipai/paperclip-runner build`.

## Risks

- Behavior changes only for native runs that change the status of the
task whose execution lock they hold. That change always stranded the run
before this PR, so no working flow depends on it.
- Legacy adapters, board users, agent handoffs or reassignments, and
conversation tasks do not change.
- Other validation errors that run later (in the service update) are
replaced by the 409 for these requests. Each request is still rejected,
and the 409 points the run to `paperclip_finish` or `paperclip_block`.
The onboarding parent-blocker error keeps its 400, because the guard
runs that check first.
- If a request names the current assignee with a reference that is not
its id, the guard does not apply, and the request follows the earlier
rules.
- No migration.

Related gaps this PR does not change:
- The authority check after the response turns a committed mutation into
`outcome: unknown`.
- The runner hides tool binding errors as "Paperclip semantic operation
failed".
- The `paperclip_finish` monitor-wait error does not say that the run
lost its lock.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, in Claude Code with
tool use (shell, file edits, test runs). It did the root-cause analysis
from run events and the activity log, wrote the code and tests, and ran
local 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
- [ ] 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-31 08:44:44 -07:00
DottaandPaperclip 3ee4c5b613 Make saved execution receipt recovery react to durable work (#18409)
Reviewed and verified at 8f306e0a6e.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.9
2026-10-31 10:03:59 -05:00
DottaandPaperclip 42fd568cf8 Drive issue recovery from committed changes and exact deadlines (#18402)
Reviewed and verified at 11b49125db.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 09:41:27 -05:00
Dotta 12b0cc6304 fix(chat): recover committed native Agent Chat replies (#18465)
## Thinking Path

> - Paperclip manages agent work and keeps its results available to
users.
> - Agent Chat needs a visible reply before the conversation can wait
for more input.
> - Native result commitment and reply presentation are separate
obligations.
> - A completed conversation can retain a valid final message without a
saved reply.
> - Existing reply recovery excludes these completed conversation turns.
> - This pull request repairs that persistence gap through the existing
recovery worker.

## Linked Issues or Issue Description

**What happened?**

A native Agent Chat turn completed successfully and saved its workspace.
Its accepted result and final assistant message were durable, but no
reply appeared in the conversation. The chat stayed active. The
deployment hiring journey in #18351 then reached its deadline while
waiting for the first reply.

**Expected behavior**

Recover the exact accepted turn's final reply once, then use normal
conversation settlement. Keep later user input active. Do not run the
agent again or replace a selected or deleted reply.

**Steps to reproduce**

1. Create an active conversation with one admitted native turn.
2. Commit an accepted DONE result and a final-channel assistant message
for that exact run, session and turn.
3. Finish workspace finalization before live heartbeat reply
presentation. Leave no saved reply.
4. Run normal response recovery. Before this fix it finds no
conversation candidate and leaves the chat active.

**Paperclip version or commit**

Reproduced with actual services at frozen master
`8bcc5a01edd5d87540401521e6f30d3df43e1848`. The production predicate
also exists in the deployed revision that exposed the failure.

Related work: #18351. The broader receipt and recovery work in #18118
and #18409 does not touch these source files.

## What Changed

- Discover unanswered committed Agent Chat turns through the existing
native response presentation worker.
- Recheck company, agent, responsible user, current execution and
conversation generation under the normal transaction locks.
- Require the accepted result digest and an exact final message from the
same native run, session and accepted turn. Keep external publication
authority separate.
- Commit the reply and presentation receipt before normal conversation
settlement. Later input stays active. Recovery does not repeat agent
work.
- Preserve skip decisions and selected or deleted replies. Add database
controls for foreign identity, stale sessions, partial commitment,
duplicates and ordinary internal task behavior.
- Document the recovery boundary in the developer guide.

## Verification

- Real-service RED/GREEN uses all 418 canonical migrations in isolated
PGlite and the exact new regression fixture. Before the fix: zero
candidates, no reply, recovery returns false and the chat stays active.
After the fix: one candidate, one exact reply, recovery returns true and
the chat waits. A repeat returns false and creates no second reply.
- All 20 canonical regression cases pass locally through a fixture-only
PGlite bridge. Only local database provisioning and `createDb` selection
differ from the normal embedded PostgreSQL fixture. Production services,
SQL queries, transactions, protocol validation and assertions remain
real. Linux embedded PostgreSQL CI is required before merge.
- Focused current-source no-emit typing passes for both production
modules and the new regression file, with normal Express augmentation
and source aliases. The broader local presentation/ownership and
conversation-settlement PGlite bridge run was interrupted before it
reported results; it is not counted as a pass. No repository-wide local
build is claimed from borrowed workspace dependencies. Clean-build CI
and canonical PostgreSQL consumer tests remain required.
- `git diff --check` and the scoped source/test secret scan pass. No
captured run data, credentials or private target identities are
committed.
- No live journey retry, deployment, configuration change or test-plan
admission was performed. The original failed journey remains failed;
this production fix still needs deployed qualification through the
unchanged journey.

- Current-head [canonical Linux
CI](https://github.com/paperclipai/paperclip/actions/runs/41207018345)
passed all 57 terminal checks with no failure or pending check. The new
20-case database regression actually passed in [server shard
8](https://github.com/paperclipai/paperclip/actions/runs/41207018345/job/124555006090),
at 13:59:25 UTC (2,643 ms). Typecheck, build and the existing consumer
lanes passed. Fresh [Greptile
review](https://github.com/paperclipai/paperclip/pull/18465#issuecomment-6544208002)
on exact `f32a432e10b377ae6277d6f728995d5fedcf9d7b` is 5/5; the
review-thread inventory is empty with no pagination. No live deployment
or journey pass is claimed by these checks.

## Risks

Eligible active conversations can gain a previously missing reply.
Recovery accepts only the exact saved final message under its accepted
result and current conversation identity. It does not run a model,
repeat hiring or change a prior test grade. Reply persistence precedes
waiting-state settlement; existing conversation recovery retains
ownership of a later interrupted settlement. No schema or public API
changes are included.

## Model Used

OpenAI Codex, GPT-6 family. The session does not expose a more specific
backend model ID or fixed context window. Used reasoning, repository
tools, TypeScript and real database test execution.

## Checklist

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

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 09:07:52 -05:00
DottaandPaperclip f46c8071fb fix(ui): make the Coordinator composer footer opaque (#18455)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - The Coordinator workspace shows a task transcript and a message
composer.
> - The composer footer can cover part of the transcript on desktop.
> - The footer has a transparent background, so text shows through
accessory panels and gaps.
> - This pull request gives the footer a solid background from the
active theme.
> - Users can read the composer controls without text from the
transcript behind them.

## Linked Issues or Issue Description

**What happened?**
The Coordinator composer footer lets transcript text show through the
area above the message field.

**Expected behavior**
The full footer has a solid surface in light and dark themes.

**Steps to reproduce**
1. Enable the Coordinator workspace.
2. Open a task with enough messages to scroll.
3. Show a composer accessory, such as queued messages or a pending
question.
4. Scroll the transcript behind the footer on desktop.

**Paperclip version or commit**
Base commit: f2db909393.

**Deployment mode**
Built from source. The change affects the Coordinator workspace.

Related work: https://github.com/paperclipai/paperclip/pull/17983 added
the workspace. Searches for an opaque or transparent composer fix found
no duplicate.

## What Changed

- Use `var(--background)` for the full Coordinator composer footer.
- Keep the outer footer square so transcript text cannot show at its
corners.
- Block clicks through the footer gaps. Forward wheel input from these
gaps to the transcript.
- Keep editor scrolling, zoom input, and the classic workspace behavior.
- Add regression tests for the footer surface, wheel input, and canceled
forwarded events.
- Keep wheel modifier keys. Use the font size to calculate horizontal
distance for line-mode input.
- Remove the old comment that describes a transparent footer.

## Verification

- Passed: 173 tests in `TaskChatComposerDock`, `TaskChatComposerStyles`,
`TaskChatComposer`, `TaskChatQueuedMessages`, and `TaskMessageScroller`.
- The surface and wheel tests fail on the previous implementation and
pass with this change.
- The latest wheel tests reproduce lost modifier keys and excessive
horizontal distance on the prior commit. The cancellation test fails
when the cancellation guard is removed.
- Passed: `pnpm check:token-gates` and `git diff --check`.
- Passed: local Chromium checks with the production dock and built UI
CSS in light and dark themes at desktop and mobile sizes. The checks
cover solid corners, blocked clicks in footer gaps, wheel input, message
entry, and horizontal overflow.
- The browser fixture reproduces the hidden-control click when the old
pointer rules are restored. These are local fixture checks, not a
deployed acceptance result.
- Passed: `pnpm --filter @paperclipai/ui typecheck` and `pnpm --filter
@paperclipai/ui build`.
- Full local `pnpm -r typecheck` and `pnpm build` could not finish
because Cargo is absent from this environment. The full local test run
was stopped without a complete result after these missing prerequisites
were confirmed. Full CI now passes on the current commit.

- Passed: [full
CI](https://github.com/paperclipai/paperclip/actions/runs/41205893876)
on commit `37feaef28`. Greptile and Paperclip both gave this commit 5/5.
Both review threads are resolved.
- Paperclip review found hidden clicks through footer gaps and exposed
corners. This change addresses both findings. The first CI quality
review required a regression test. This change adds those tests. The
later review requested a cancellation test and better horizontal wheel
handling. This change addresses both items.

## Risks

- Low risk. The CSS selector applies only inside the Coordinator
workspace.
- The footer now captures clicks across its full area. Wheel input in
empty footer space still scrolls the transcript.
- The dock forwards wheel input to the transcript handler so
earlier-history loading still receives that input.
- No API, data, or migration changes.

## Model Used

- OpenAI Codex, based on GPT-6 (`gpt-6`), with reasoning, tool use, and
code execution. The runtime does not expose its context window. The
model ID for the original saved CSS patch is not retained in the task
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-31 08:59:41 -05:00
DottaandPaperclip 47f81e850b fix(testops): verify unexpanded result job runs (#18462)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat feature evaluations send their results to TestOps.
> - The final reader checks the result against its current GitHub run.
> - A real result omitted the nested job object and had no presentation
links.
> - The reader rejected that passed result after a successful upload.
> - This change joins the embedded job-run ID to the separate job-run
response.
> - The reader keeps the source, case, status, and attachment checks.

## Linked Issues or Issue Description

Refs #18394 and #18322.

**What happened?**

The native chat test and cleanup passed. TestOps stored a passed result
and three attachments. The final read-only step failed with
`chat_testops_upload_mismatch`. The result response had a job-run ID,
launch ID, and current GitHub run URL. It did not include the nested job
object. Its presentation links were empty.

**Expected behavior**

The reader must accept that response when the separate job-run response
proves the exact job, launch, and current GitHub run. It must reject
conflicting identity or source data.

**Steps to reproduce**

1. Return a valid result with an unexpanded job run and empty links.
2. Return the matching full job run from the existing job-run endpoint.
3. Call `verifyChatUpload`. The old reader rejects the result.

**Paperclip version or commit**

Observed on c2971badde. The fix starts
from ab51cabbbd.

**Deployment mode**

GitHub Actions and AWS. This defect is in the TestOps report reader.

## What Changed

- Join the exact embedded job-run ID to the separately checked job-run
response.
- Accept empty presentation links. Reject conflicting known run and
commit links when present.
- Reject conflicting embedded job fields.
- Add regressions for the observed response and wrong job, run, launch,
and source data.

## Verification

- Three new tests fail against the parent reader.
- `node --test tests/runner-e2e/chat-feature-testops-api.test.mjs`: 47
passed.
- `node --test tests/runner-e2e/testops-chat-reporter.test.mjs`: 14
passed.
- Both changed files pass `node --check`. `git diff --check` passes.
- Local checks used Node 26.4. Normal CI must check the workflow
runtime.
- Full local typecheck, build, app, database, SDK, and provider runs
were not run. This two-file MJS fix uses pure tests and mocks.
- Normal CI
[41205375203](https://github.com/paperclipai/paperclip/actions/runs/41205375203),
attempt 1, passed on c7b5bf3238. Both required checks passed. Greptile
is 5/5. The optional automated coverage note has a recorded disposition
and is resolved.
- The original feature verdict, backend pass, and failed final reader
step remain separate. This change does not regrade that run.

## Risks

- Empty presentation links do not prove a server commit link. Source
identity comes from the trusted current GitHub context, selection, and
bound export.
- The separate job-run response remains required. All case, status,
attachment, and deadline checks remain active.
- The new reader has not yet run against the live service. CI and a
later authorized run must qualify delivery.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, with reasoning, source inspection, and code
execution. The host does not expose the 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 (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>
canary/v2026.1031.0-canary.8
2026-10-31 08:54:03 -05:00
DottaandPaperclip 8bcc5a01ed fix(runner): preserve OpenCode written-answer defaults (#18456)
## Thinking Path

> - Paperclip lets people answer questions while native agent work is
active.
> - Runner drivers translate provider question forms and answers into
the shared contract.
> - Pinned OpenCode 1.18.34 enables written answers when `custom` is
omitted.
> - The driver required explicit `true`, so it removed that input from
ordinary native questions.
> - The same branch could override a native opt-out or add a separate
custom field to a text-only question.
> - This pull request preserves the native default, explicit opt-out,
original choices, and exact answer delivery.

## Linked Issues or Issue Description

**What happened?**

A native OpenCode question with choices and no `custom` field loses its
written-answer control in Paperclip. The pinned provider enables that
control by default. A legacy alias can also override native
`custom:false`. A question with no choices and `custom:true` is rejected
because the driver adds a separate custom field to text mode.

**Expected behavior**

Follow the [pinned OpenCode question
contract](https://github.com/anomalyco/opencode/blob/v1.18.34/packages/schema/src/v1/question.ts).
Preserve the written-answer default for choices. Honor native
`custom:false`. Keep optionless questions text-only. Preserve every
supplied choice and return the exact written answer to the same native
request.

**Steps to reproduce**

Use the normalizer regression or the local OpenCode driver fixture. Emit
a native question with choices and omit `custom`. The unfixed driver
omits `customAnswer`; its existing written-answer roundtrip assertion
fails. The separate negative controls reproduce native opt-out
precedence and text-only normalization errors.

**Paperclip version or commit**

Reproduced on main `f2db909393de124caf6a5380a52d4e0e1d621661`, with
pinned `opencode-ai@1.18.34`.

## What Changed

- Apply the native `custom` flag first, then the legacy alias, then the
pinned default of `true`.
- Add a separate custom field only when choices exist. Keep optionless
questions text-only.
- Add default, opt-out, alias, and exact response validation
regressions. Make the driver fixture omit the optional native flag and
retain its exact custom-answer roundtrip assertion.
- Document the pinned native behavior.

## Verification

- Before the fix, the real normalizer fails three targeted assertions:
omitted custom input, native opt-out precedence, and optionless text
with `custom:true`.
- The local driver subprocess regression also fails before the fix. Its
native request omits `custom`, and the driver drops the expected
written-answer control.
- After the fix, all **79 tests in three files pass**: the new nine-case
normalizer suite, the full 65-case OpenCode driver suite, and the five
question-set response tests. The driver sends the unchanged written
answer in the provider's ordered answer array and records one terminal
request resolution.
- Runner TypeScript check passes. A first attempt lacked the isolated
eval-kernel declarations; building that local dependency resolved the
setup gap. Locked dependencies were installed from the existing cache
with scripts disabled.
- Diff checks pass. Exact-head [canonical CI run
41203866644](https://github.com/paperclipai/paperclip/actions/runs/41203866644)
passes build, typecheck, release registry, Runner checks, server tests,
and all eight E2E shards at `72b21207e8590b78e24fe2cef4e3f6c374be53a4`.
All current PR checks are terminal with no failures. Storybook is
skipped for this scope and Paperclip Review is neutral. Full repository
checks were not repeated locally for this narrow provider translation
change.
- [Fresh Greptile
review](https://github.com/paperclipai/paperclip/pull/18456#issuecomment-6543742512)
gives 5/5 on that exact head with no actionable findings. All review
threads are addressed. GitHub reports `MERGEABLE` and `CLEAN`.
- Local tests use a controlled provider fixture. They do not establish a
paid model pass or attribute a deployment incident without its original
native arguments. No QA run, runtime deployment, protected pin, journey
oracle, prompt, budget, run bound, or model setting changed.

## Risks

Native OpenCode choices now expose the written-answer control that the
provider already enables by default. Explicit native opt-out wins over
the legacy alias, and disabled custom responses remain rejected.
Existing choice IDs and labels remain unchanged. Deployed users need the
repaired Runner artifact through the normal delivery path. Local driver
proof does not replace deployed journey qualification.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, source inspection, and code
execution. The host does not expose the exact underlying model version
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 available 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; none repairs
this native default
- [x] I have described the issue in-PR following the bug 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 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
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-31 08:27:33 -05:00
DottaandPaperclip 12d8c3043e fix(native): fence retries when replaying an audited Stop (#18457)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runs keep Stop intent and retry state in durable records.
> - A provider error can leave a failed retry with an earlier
acknowledged Stop.
> - The replay path returned the existing receipt before it closed that
retry.
> - This pull request applies the existing retry fence to the validated
replay.
> - The same Stop can settle without another provider cancellation or a
new receipt.

## Linked Issues or Issue Description

Refs #14733 for the related caller-bound Stop contract. This change
covers a later retry that already has a Stop acknowledgement. The older
CI-only #14743 is not a production delivery PR.

**What happened?**

A failed native run can have a retryable coordinator and an earlier
audited Stop. A repeat Stop returns the old acknowledgement without
moving the coordinator to `terminal_failure`. The final
failed-to-cancelled transition requires that fence, so the Stop cannot
settle through that path.

**Expected behavior**

A valid replay closes the same retry and keeps the original intent and
acknowledgement. It does not send a second provider cancellation.
Physical stop and workspace cleanup still require their own evidence.

**Steps to reproduce**

1. Store a failed native run with a `retryable_failure` coordinator.
2. Store a matching run-scoped Stop with a dispatched acknowledgement
and audit IDs.
3. Call `cancelNativeSession` for that same run and inspect the
coordinator.

**Paperclip version or commit**

Reproduced on public master `f2db909393de124caf6a5380a52d4e0e1d621661`.

**Deployment mode**

Core native execution. The regression uses the real cancellation
executor with controlled persistence and provider boundaries.

## What Changed

- Reuse the existing guarded coordinator fence for a validated Stop
replay.
- Test repeated replay, unchanged receipts, one fence, and no second
provider cancellation.
- Reject foreign company, run, issue, scope, effect, and missing-audit
receipts before any write.
- Check that an acknowledged Stop with an unconfirmed remote lease still
fails the physical-stop guard.
- Document the separate retry fence and physical-cleanup requirements.

## Verification

- RED on the selected public base: the new executor case returned
success but left the coordinator in `retryable_failure` with a future
retry. One case executed and failed for that assertion.
- GREEN: 62 focused tests passed across
`native-session-executor.test.ts` and
`native-cancellation-request.test.ts`. These include ownership, caller
conflict, changed-phase, and receipt controls.
- Command from `server/`: `node ../node_modules/vitest/vitest.mjs run
src/services/native-runtime/native-session-executor.test.ts
src/services/native-runtime/native-cancellation-request.test.ts -t
'native session cancellation|caller-bound native cancellation|failed
native retry caller admission'`.
- Canonical Linux CI passed all 1,018 executor cases and all 32
caller-cancellation cases. The exact file completion lines are in
[server shard
2](https://github.com/paperclipai/paperclip/actions/runs/41203989386/job/124545366271)
and [server shard
10](https://github.com/paperclipai/paperclip/actions/runs/41203989386/job/124545366219).
- Node 24.22.2 and Vitest 5.0.3. Map contract checks and `git diff
--check` pass.
- Local dependencies are linked from an existing checkout. Full local
TypeScript validation reports older Runner/shared declarations that lack
current Kimi and continuity APIs. The changed ranges have no
diagnostics. The canonical clean CI Typecheck + Release Registry gate
passed.
- A broader two-file run was stopped when an unchanged integration case
tried to start embedded Postgres and hit the host listen restriction. It
is not a passing full-suite result. No host settings or other services
were changed.
- Repository-wide `pnpm -r typecheck`, `pnpm test:run`, and `pnpm build`
were not completed locally. Current-head CI passed against clean source
and dependencies.
- Fresh [Greptile
review](https://github.com/paperclipai/paperclip/pull/18457#issuecomment-6543772487)
on `dbc1c1a5b71450194d568725592969660864cb5a`: 5/5 with no actionable
findings. The review-thread inventory has no threads and no pagination.
Full [current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41203989386)
passed: 59 terminal checks, 55 successful, 3 skipped, and 1 neutral. No
failure or pending check remains. Merge status is CLEAN. No live
recovery, rollout, or physical termination is claimed.

## Risks

- A wrong or stale Stop must not close another retry. Existing
run/coordinator locks, caller checks, receipt binding, and the final
compare-and-set remain in place.
- This fix changes logical retry settlement only. Provider termination,
workspace preservation, lease cleanup, and continuation gates remain
separate.
- The regression controls persistence and provider boundaries. It does
not establish the physical state of a remote provider.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code editing, and tool
use. The session does not expose an exact model build ID or
context-window capacity.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub references)
- [x] My branch name describes the change and contains no internal
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-31 08:25:16 -05:00
DottaandPaperclip ab51cabbbd test: await async outcomes and drive saved deadlines deterministically (#18416)
Reviewed and verified at ab0b15d234.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 08:18:15 -05:00
DottaandPaperclip f2db909393 fix(ui): retain startup autosave through session recovery (#18412)
Reviewed and verified at a8783f8ace.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-31 07:51:09 -05:00
DottaandPaperclip c2971badde perf(server): recover independent native replies concurrently (#18421)
## Thinking Path

> - Paperclip manages work for AI agents.
> - A native run can commit its result before its reply is saved.
> - The response recovery worker saves replies from those committed
results.
> - It checks each candidate in series, so one task can delay unrelated
tasks.
> - This pull request checks up to four independent tasks at once.
> - Each task keeps serial checks, and the existing coordinator owns
retries and shutdown.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Recovery of committed native task replies.

**Current behavior**

The worker checks one candidate at a time in a batch of up to 25. A
database lock or a slow read for one task delays replies for other
tasks.

**Proposed behavior**

Check up to four company-and-task groups at once. Check candidates
within each group in their existing order. Keep the current batch limit
and company selection.

**Reason and benefit**

A ready task reply can be saved while another task waits for a database
lock. The change reduces waiting under a reply backlog.

**Breaking changes**

Replies for different tasks can be saved in a different order. There are
no API or schema changes. Other deadline workers keep serial dispatch.

Related work: #17696 adds the recovery worker. #17501 reduces its read
payloads. #18367 adds its timing spans. These changes are already
merged. The PR search found no open change that adds this concurrency.

## What Changed

- Add optional keyed concurrency to the shared scoped deadline worker.
- Enable a limit of four for native response recovery, keyed by company
and task.
- Await all active checks before the pass ends. Retain per-candidate
failure backoff, drain behavior and pending work.
- Test concurrency limits, task order, company separation, drain/resume,
shutdown, retries and idle wake behavior.
- Add a PostgreSQL regression that holds one task's finalization row
lock while a second task saves its exact accepted reply.
- Document the worker's concurrency and sleep contract.

## Verification

- The PostgreSQL lock regression fails with serial dispatch. It passes
with this change. Both accepted replies are saved once after the lock is
released.
- `pnpm exec vitest run
server/src/__tests__/scoped-deadline-work.test.ts
server/src/__tests__/delivery-work-coordinator.test.ts
server/src/__tests__/company-work-batch.test.ts
server/src/__tests__/deadline-work.test.ts
server/src/services/execution-preparation-timing.test.ts` — 55 tests
pass.
- `pnpm exec vitest run
server/src/services/presentation-ownership-read.test.ts` with its
documented dedicated PostgreSQL URL — 21 tests pass. The disposable
database was dropped.
- `pnpm -r typecheck` — passes.
- `pnpm build` — passes.
- One matched local replay with 25 older pending replies and one fresh
reply used the real worker, a 10-connection PostgreSQL pool and 8 ms
delay in each network direction. The saved fresh reply was first
observed after 29.193 s with serial dispatch and 9.798 s with this
change. All 26 replies were saved exactly once in both runs, with no
worker errors. Both disposable databases were dropped. This is one
synthetic workload pair, not a staging measurement.
- `pnpm test:run` was attempted. Embedded PostgreSQL could not
initialize its template after five attempts, so the broad run was
stopped. The changed PostgreSQL tests pass on the separate local server.
Remote CI is green. This PR does not claim a measured staging speedup.

- The [first CI browser
shard](https://github.com/paperclipai/paperclip/actions/runs/41162257463/job/124422204506)
failed during company cleanup after its task assertions and empty-run
check passed. Company deletion hit the
`activity_log_company_id_companies_id_fk` constraint. The fixture uses
paused process agents and reported no runs. The one failed-jobs rerun
passed all 45 browser tests. All CI checks are now green.

## Risks

- Four checks can use more database connections than serial recovery.
The limit applies to this queue only; the batch limit stays at 25.
- The shared helper has more dispatch logic. Its default remains serial.
Tests cover task order, retry deadlines, drain and waiting for active
checks during shutdown.
- This improves reply recovery under backlog or lock contention. It does
not establish a target for total agent-turn latency.

## Model Used

OpenAI Codex, based on GPT-6, with code editing, tool use and local test
execution. This session does not expose a more specific model ID or
context-window size.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-31 07:39:53 -05:00
DottaandPaperclip d5766e4074 perf(chat): scope task questions and batch inbox queue checks (#18422)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Standing chats show recent messages and current task questions.
> - Recent-message pagination bounds history work, but it does not bound
question work.
> - The question read built the full company attention feed before it
selected the chat's tasks.
> - Each feed read also checked seeded queue membership with one insert
per item.
> - This pull request scopes question collection in the attention owner
and batches queue membership checks.
> - Chats keep their current question cards and initial layout while
doing less work.

## Linked Issues or Issue Description

Follow-up to #18358 and #18323. Related work: #18312.

**What happened?**

A hosted standing chat remained slow after recent-message pagination
shipped. On commit `4eaa435bf4`, an embedded-browser reload made the
conversation usable at about 8.6 seconds. Recent comments finished at
about 1.9 seconds. The pending-question request held the initial reveal
until about 8.4 seconds. That request called the complete company
attention feed and then filtered its results. The separate badge summary
also did broad work.

**Expected behavior**

Chat question cost should depend on the relevant tasks. Reading an
existing queue must not require a separate insert for every member.
Current access and decision policy must remain in force.

**Steps to reproduce**

1. Create a standing chat with questions on tasks assigned to its agent.
2. Add many unrelated tasks and pending questions to the company.
3. Open the chat from a fresh application cache.
4. Compare recent-comment arrival with the pending-question response and
content reveal.

**Paperclip version or commit**

Baseline: `909e29dd071b1aeeb24c2933af049da90a6066d3`. Its affected
services match the observed hosted revision `4eaa435bf4`.

## What Changed

- Add an internal task-question projection to the attention service.
Filter pending interactions by company, task IDs and question kind
before card enrichment.
- Keep the same access, audience, dismissal, queue, snooze, retention,
archive and training-example logic. Ranks are local to the returned
question list.
- Use the projection from the conversation receipt service. Keep current
chat audience and session checks there.
- Batch seeded membership inserts in groups of 500. Keep the queue lock,
conflict protection, audit events and activity logging for each new
membership. Existing members produce no new audit records.
- Add real PostgreSQL regression cases and a reproducible paired
benchmark. No schema migration or UI reveal change is needed.

## Verification

- `pnpm -r typecheck` passed. The final server typecheck also passed
after the queue change.
- `pnpm build` passed.
- Real PostgreSQL service coverage: 57 attention and chat-handoff tests
passed. Seven queue-route tests passed, including concurrent reads,
mixed existing/new items, duplicates, disabled seeds and audit
preservation.
- Red/green proof: the unrelated-attention regression fails with the
baseline conversation implementation and passes with the scoped read.
- `node scripts/check-module-boundaries.mjs` and `git diff --check`
passed.
- Full `pnpm test:run` was attempted and stopped with exit 130 after
embedded PostgreSQL startup failures and 17 failures in the untouched
native-session executor suite. It is not a local pass. The focused
Docker/PostgreSQL results above completed before Docker Desktop became
unavailable. A direct native PostgreSQL probe identified the host
semaphore limit (`could not create semaphores: No space left on
device`). No shared kernel settings or other test clusters were changed.
[Full
CI](https://github.com/paperclipai/paperclip/actions/runs/41162314995)
passed on `2809f096b3fb2c01b44a96a1b82a27809c9359df`, including all
eight browser shards. Final status: 55 successful checks/statuses, three
skipped and one neutral. Greptile is 5/5 with no findings or unresolved
threads. The fresh local browser retest is blocked because Docker
Desktop cannot start and native PostgreSQL cannot allocate semaphores.
The original hosted reproduction above is complete; no candidate browser
pass is claimed.

Local service benchmark: PostgreSQL 17.11, two relevant tasks, five
alternating pairs per scenario, after warmup. These are local service
timings, not a claim about deployed latency.

| Fixture | Read | Baseline median (range) | Candidate median (range) |
SQL calls |
| --- | --- | --- | --- | --- |
| 1,000 unrelated tasks/questions | Chat questions | 670 ms (632–1,905)
| 12 ms (11–15) | 1,076 → 22 |
| 1,000 unrelated tasks/questions | Company badge summary | 641 ms
(622–717) | 167 ms (161–171) | 1,068 → 69 |
| Small company | Chat questions | 38 ms (37–52) | 13 ms (12–16) | 52 →
22 |
| Small company | Company badge summary | 34 ms (33–39) | 34 ms (32–40)
| 44 → 43 |

All question fields and ordering matched, except rank is relative to the
scoped list. Summary fields matched except the generation timestamp. The
interaction plan changed from 1,002 selected rows to two rows through
the existing company/issue/status index. The benchmark loads baseline
attention, conversation and queue modules together so the queue change
cannot contaminate the baseline.

```sh
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-chat-questions.ts \
  --baseline-ref=909e29dd07 --unrelated=1000
```

## Risks

- Scoped and complete feeds must share policy. This change reuses the
same attention collection and finalization path and tests dismissals,
named audiences, snoozing, archives and private access.
- Batched inserts must audit only new members. The concurrent PostgreSQL
test checks unique membership and one event/activity record per new item
across batch boundaries.
- Full inbox summaries still collect the company feed. The small-company
summary timing is unchanged. Other chat requests and transcript
hydration can still contribute to hosted latency.
- The first reveal still waits for question cards to preserve layout.
This follow-up has not been deployed, so its hosted effect remains
unverified.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository tools, code
execution and browser profiling. 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
#` 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-31 07:37:47 -05:00
DottaandPaperclip 492d537340 fix(native): recover controllers across webserver replacement (#18343)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Native execution runs in a remote Runner while the webserver owns
its controller.
> - Encrypted PRP checkpoints and session snapshots already survive a
webserver restart in Postgres.
> - Ordinary warm and per-turn admission still needs local markers and
supervisor metadata to find that state.
> - Replacing the webserver with an empty native controller directory
can therefore lose a usable retained session.
> - This change adds bounded recovery metadata to the existing snapshot
transaction and reconstructs local projections from the selected durable
source.
> - The benefit is native execution continuity across webserver
replacement, with the existing ownership and agent lifecycle policies.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Native remote controller recovery and retained-session continuation
during a webserver upgrade.

**Subsystem affected**

server/ — native runtime, checkpoint persistence, recovery scheduling
and internal upgrade reporting. Product E2E qualification also changes.

**Current behavior**

Without both the local PRP marker and supervisor file, normal
continuation can return before discovering the saved Postgres
checkpoint. The snapshot already exists in Postgres, but its local reuse
compatibility envelope cannot be reconstructed.

**Proposed behavior**

Select the existing durable source, validate its identity and ownership,
restore its PRP state and supervisor projection, then use normal
authenticated admission. Missing or inconsistent evidence holds
recovery. It does not authorize fresh provider work.

**Reason and benefit**

A replacement webserver must recover active execution and later continue
its retained session without the old server's native files. This is one
component of deployment continuity. HTTP traffic switching, workspace
storage migration and Railway rollout remain separate.

**Breaking changes**

No new public endpoint, schema migration or database pool. The private
run-profile envelope is additive. Disk-independent rollback also
requires a reader for the staged controller format and compact
checkpoint part; the first production release containing these readers
is the floor. Older file-backed sessions need an owner checkpoint or the
bounded internal importer.

**Additional context**

Related foundations: #17401, #17916, #17254, #14621, #14622. The
implementation contract and open acceptance gates are in [the dated
plan](doc/plans/2026-10-30-native-controller-checkpoints.md).

## What Changed

- Persist a versioned recovery envelope, at most 4 KiB, beside the
redacted session snapshot in its existing transaction. Keep it out of
public run projections.
- Compare frozen admission separately from prepared attachment
instructions during staged recovery, preserving exact
template/identity/authority checks.
- Bound the existing lazy checkpoint pool at three connections after
measured two-slot burst backlog; keep request/renewal capacities and SQL
operation counts unchanged. The tuning is a separate commit.
- Discover and restore the exact selected retained source without local
native markers. Preserve the 32-candidate window, progress barriers and
current authority checks.
- Fence snapshot and result writes. Acquire coordinator, issue and run
locks in order and check expiry after lock waits. Combine snapshot
ownership/read work into one statement.
- Reuse existing recovery deadlines and drain/resume scheduling.
Retained-owner waits preserve the original unstarted run and actual
lease deadline. Stop, ownership and provider-progress fences precede
deferral. Add bounded native evidence reporting, retained-source import
and retention protection.
- Admit a settled warm source with an authenticated idle goal-read
suffix while retaining active-work and mixed-authority holds.
- Permit lifecycle `turn.stop` checkpoints after accepted results under
existing ownership fences. Claim the existing successor coordinator
before retiring the old warm session, and stage shared attachments only
after verified retirement. Preserve omitted isolated-home defaults and
existing fresh skill-selection order during recovery without hiding real
configuration changes.
- Carry the exact durable six-field PRP binding during active recovery
after a healthy warm handoff. Keep the Runner mismatch guard and
preserve opaque attachment IDs.
- Preserve an already verified active or idle warm process during remote
preparation; revalidate its proof/liveness and retain later
authenticated PRP attachment. Ordinary resumed leases retain suspension
checks.
- Drain retained source events under their original authority, reconcile
immutable source accounting and block unknown source tool dispatch
before target work.
- Persist compact staged handoff intent through authenticated adoption
and recover direct/listener command-loss windows without another Runner
or duplicate attachment.
- Rebuild suspended lifecycle receipts for resumed prepared tasks, and
retry missing lifecycle reads after partial PRP materialization without
overwriting contradictory evidence.
- Add normal warm/per-turn diskless continuation coverage, real Postgres
races and SQL-cost checks. Add a reproducible paired load workload.
- Give only the explicit outage fixture a 15-minute provider idle
window, with a red/green catalog regression preserving all production
timing and lifecycle policies.
- Publish the goal-less task-session pointer in the existing
post-acceptance terminal checkpoint transaction, with current ownership,
accepted-result, reset and newer-progress fences. Keep a private bound
receipt so late completion cannot duplicate or resurrect publication.
- Use a retained warm sandbox in the dedicated continuity fixture, and
accept an exact output token followed by an explanation. Keep the strict
identity oracle.
- Extend the explicit Daytona cell to a five-minute active outage and
another replacement after completion. Require retained provider
identity, a new tool receipt and a useful follow-up result. Add an owned
loopback Postgres E2E fixture for hosts that cannot start embedded
Postgres.

## Verification

**Merge recommendation — `fc68584ce6231a02e47ecd743f55b036ccea034f`:
ready for the qualified native-controller component.** Full CI, fresh
review, local application paths, controlled performance qualification
and the strict live Linux/Daytona case pass. Independent resource
cleanup is complete. Broader rollout, browser reconnection and the
unexecuted transport/platform combinations remain integration gates.
Integrated 484 passed full local recursive typecheck/build and ordinary
active→completion→cache-loss→C component qualification. Fresh review
then found a valid attached-wake failure: preparation appends attachment
instructions before the verifier compares execution to the frozen
admission. 9f4 fixes that by separately checking the pre-preparation
admission and exact prepared execution. Both hashes are captured
privately per admission; the full template, identity, configuration and
authority checks remain. Its regression fails before the fix; 36 focused
cases, 42 staged source/target cases and server typecheck pass
afterward. The review thread is resolved. Exact-head full CI passes
([run
41168228822](https://github.com/paperclipai/paperclip/actions/runs/41168228822):
48 successful jobs, one intended skip); the complete `pnpm test:run`
partitions are forced, with the five native suites in the Runner lane.
This is not a claim that an unsharded local command passed. The fresh
exact-head Greptile check succeeds with 5/5 and all six threads
resolved.

The original two-connection database comparison closes **steady PASS and
burst FAIL**. Every relative CPU/WAL/request-p99 gate passes and all
operations/ownership remain correct, but candidate arm 3 drains in
1,015.99 ms and baseline arm 4 in 1,059.67 ms against the unchanged
1,000 ms absolute gate. Those results remain failed. A separate 2→3→4→2
diagnostic reproduces drain times 1,051.57 / 956.79 / 882.02 / 1,065.72
ms: three is the smallest tested passing cap, and the repeated two-cap
failure survives run-order/cache effects.

Separately reviewable `fc68584ce6` changes the existing lazy checkpoint
pool default to three connections. Request capacity stays ten and
liveness two; idle release, shutdown fencing, transaction counts and
pool count are unchanged. Thirteen DB lifecycle/cap tests and DB
typecheck pass. Full recursive typecheck/build pass at exact fc68584,
with the matching server build stamp. The final paired native
feature-cost comparison explicitly uses the **same cap-three policy and
common current DB factory in both variants**; its baseline is
controlled, not the unmodified historical cap-two configuration.
Original gates and workload counts remain unchanged. The one strict
Linux/Daytona case started at 04:40:56 UTC only after both new profiles
passed; it passed on the first attempt with all 49 workflow checks.
Independent cleanup confirms all three owned sandboxes absent, owned
Postgres/controllers/observer gone, VM terminated, root volume absent
and ephemeral SSH key/agent removed.

**Final controlled cap-three qualification: PASS.** Baseline native
implementation `59da15066a` and candidate `fc68584ce6` use the same
current DB factory and checkpoint policy (request/liveness/checkpoint =
10/2/3). Eight 65-second ABBA arms cover 300 controllers and 10,000
historical tasks. All correctness, absolute and 10% relative gates pass;
original cap-two failures remain unchanged.

| Mode | DB CPU µs/op, baseline → candidate | WAL B/op, baseline →
candidate | DB-request p99 ms, baseline → candidate | Maximum drain |
| --- | --- | --- | --- | --- |
| Steady | 542.40 → 554.83 (+2.29%) | 1509.01 → 1558.27 (+3.26%) |
107.11 → 111.90 (+4.48%) | 26.35 ms |
| Burst | 1036.36 → 1063.11 (+2.58%) | 4153.12 → 4317.64 (+3.96%) |
103.736 → 103.841 (+0.10%) | 930.14 ms |

Every matched arm preserves operation/statement/transaction counts,
including 3,900 PRP and 3,900 snapshot transactions. All three actual
pools are included; there are zero lost owners, missed lease deadlines,
dropped operations or errors. Peak Postgres CPU is 18.31%/9.47% of two
cores and memory 614.29/684.42 MiB (steady/burst). The benchmark uses
one Node process simulating 300 controllers; it does not qualify
two-webserver overlap, HTTP latency or hosted capacity. Its observer SQL
contributes to measured database CPU. The original unmodified cap-two
baseline is separately retained as failed; this cap-three comparison is
explicitly controlled.

The exact final-source 8/512/8,192-chunk test also passes: zero recovery
SQL, transactions or changed rows in each text-only interval, zero idle
SQL, seven lifecycle transactions and twelve changed rows per sample.
Existing lease traffic remains separate. The final ordinary managed
application replay passes active recovery, completion, native-cache
removal and C continuation; its UNKNOWN local debug-daemon provenance
and partial instruction-observer limits remain recorded. The live case
uses the attested Linux producer instead.


**Live qualification: PASS, one attempt, no retries.** Campaign
`native-controller-retained-fix-fc68584ce6-ec2-20261031T044055Z` started
04:40:56 UTC on the exact final Linux webserver source; suite definition
hash `12f9bb97823c1537e43f0398e7cddf39890f77bce7b413ca4dfd944f4a30e5d5`.
The existing immutable image and attested Bookworm Runner artifact are
unchanged.

- A was SIGKILLed and its native cache discarded. B started after
300,149 ms, naturally acquired generation 2, authenticated at 316,624 ms
and resumed at 317,682 ms within the original 420,000 ms grace. The same
active run, Runner, provider PID/start fingerprint and one
submitted/started/accepted turn were preserved; one final
result/terminal and workspace finalization completed, with no
retry/recovery action.
- After active and queued completion, B was SIGKILLed and its native
cache discarded again. C received exactly one ordinary task-comment API
follow-up, completed a new tool and produced a useful reply while
preserving native/provider/Runner identities. This closes the earlier
failed post-C gate. A separate C OS-process PID field was not exported;
the physical-PID proof is specifically A→B.
- Four distinct results were accepted and published; all four
finalizations committed at attempt 1, all four accounting-v2 projections
settled, and the task-session pointer advanced to C. The coordinator
independently checked these facts and all 49 canonical checks against
the sanitized receipts.
- Canonical cleanup passed and independent checks confirmed three exact
sandbox 404s plus complete inventory/zero owned remnants, no owned PG or
controller/observer processes, EC2 terminated, root volume absent, and
the ephemeral SSH key/agent removed by 04:54:25 UTC.

Live scope is classic remote Codex warm continuity with non-native
storage dependencies available. Prepared-task completed B→C, full
per-turn application disk loss, browser reconnection, two-server load
and overall Railway/HTTP continuity were not live-qualified here.
Earlier failed campaigns and the original cap-two burst failure remain
failed historical evidence. A report-renderer cache setup failure was
preserved; the normal sanitizer subsequently succeeded with an explicit
cache path and a new output directory, without changing validators.


The repair keeps retained events under their original six-field
authority until persistence and accounting accept them. Unknown semantic
effects stay unresolved. A compact staged target survives source
bootstrap, cached-command delivery and authenticated handoff, including
an uncertain commit response. Direct and same-guest-listener recovery
require the verified original Runner and the exact endpoint. Target
snapshot publication marks readiness in memory, with retirement
coalesced into an existing command write. Headers contain only the
staged descriptor/digest; a prequeue template is written once as a
changed checkpoint part and then recovered from the existing
command/receipt. No second session snapshot transaction, streaming SQL
path, new pool or recurring idle scan is added.

| Current repair gate | Evidence and scope |
| --- | --- |
| Source-tail regression | Real Runner protocol RED reproduced
attachment rejection. Frozen core/transport pass five source-tail cases:
source usage attribution, held persistence/no premature ACK, lost commit
response plus cache loss, unknown semantic hold and accounting rejection
hold. |
| Handoff loss windows | Direct and listener modes pass
queued/prepared/activated/completed boundaries (eight cells), preserving
the actual Runner/provider process. Missing adoption proof and changed
endpoints reject recovery. |
| Compact storage | A 31 KiB attachment grant writes its separate part
once, leaves it unchanged across source snapshots and removes it at
queueing. Headers do not duplicate the grant. |
| Accounting | 21 real-Postgres usage tests and 19 source-binding tests
pass. Recovery hydrates immutable source receipts without resetting
their producer or billing classification; conflicting/incomplete usage
holds. |
| Admission and malformed evidence | Driver 16, staged evidence 42,
restart classifier 27 and source usage 19 focused cases pass. Four
malformed-file regressions pass at d6a7, whose executor is
byte-identical at 484, and server typecheck passes. Full executor file:
990 pass; 16 embedded-Postgres `initdb` setup failures before
assertions, retained separately. |
| Required checks | Exact fc68584 recursive typecheck and build pass
locally, with matching server stamp. Forced full CI succeeds (48 jobs
pass, one intended skip); all PR checks are clean. Maps/token gates pass
for their unchanged source surfaces. Fresh exact-head Greptile is 5/5,
all six threads resolved. |
| Ordinary application path | Exact fc68584 managed component passes
active recovery after natural expiry, completion, native-cache loss and
ordinary C continuation. Production bytes match before/after; temporary
fixtures restored and owned DB/services cleaned. UNKNOWN local
debug-daemon/partial instruction-observer limits remain; the separate
live case uses the attested Linux producer. |
| Producer | Locked Bookworm build from exact 5b7 Rust tree
d03e494217, equal to final fc68584 Rust
source. SHA-256
65b8f8cfdd6099e9ad24f1ca154e8a260777269cc82f6e23c6e6a180c531eaaf;
38,515,328 bytes. Actual Debian 12 execution and live admission pass.
Controller/admission/DB changes do not relabel the producer source. |
| Historical cap-two comparison | Exact 59da baseline vs 5b7 candidate,
300 controllers/10,000 history, ABBA 4×65 s per mode, all three actual
pools and real snapshots. Steady CPU/op 541.36→554.64 µs (+2.45%);
WAL/op 1512.13→1560.99 B (+3.23%); DB-request p99 102.78→105.99 ms
(+3.12%): PASS. Burst CPU/op +4.71%, WAL/op +5.29%, p99 −0.10% pass
relative gates, but absolute drains above fail. Identical operation/SQL
counts, zero lost leases/drops/errors. One Node process simulates 300
controllers; this does not qualify two-webserver overlap or HTTP
capacity. |
| Live acceptance | Strict final-source Linux classic Codex case passes
1/1 on attempt 1, all 49 checks. Active recovery within grace and useful
retained C continuation succeed; four
accepted/published/committed/settled outcomes. Independent provider,
PG/process, VM/root and SSH cleanup complete. Prepared/task and broader
rollout limits are explicit above. |

**Historical qualification snapshot through `9eb9ac6`.** The head at
this snapshot was `9eb9ac6f9e312f3ebe8040f5a7565e88ae8824f3`. Server and
Runner package sources are byte-identical to `283e05ffaa`; the two later
commits change the explicitly scoped qualification and its documentation
only. It includes master through the storage-owner fix
`45a3a92e6dc52d20923b9aa34a22fee2ec5443f9` (#18357). At that snapshot,
CI/review passed but the strict post-C native recovery gate failed; the
PR stayed draft and required another native repair. Prior `39a4343` CI
and review passed, but its full live workflow failed; that grade remains
unchanged. The first repaired `435ccd2` live attempt failed before any
injected outage. It exposed a legitimate terminal snapshot before result
acceptance; no accepted result ID or publication receipt was observed.
Its canonical report remains 0/1 `candidate_failure`, with cleanup
passed and independent provider absence confirmed. `0862062` defers
publication until result acceptance and fixes the fresh review's
coordinator/issue lock-order finding. Both failures have deterministic
real-Postgres regressions. The `0862062` live attempt then proved
accepted-result publication but failed active recovery: a resumed-lease
preparation guard demanded suspension after the exact live Runner was
already verified for adoption. `64c0b746` preserves that verified
active/idle-warm process, revalidates its proof/liveness, and keeps
ordinary suspension checks and later PRP authentication. Its live run
passed preparation but exposed a second active-warm boundary: all
durable binding fields matched except opaque turn/item attachment IDs,
which the server had regenerated. `7a203274` carries the complete
verified six-field binding and keeps the strict Runner mismatch guard.
Its cloud case then passed active adoption, completion, publication and
accounting. The queued continuation exposed accepted-result retirement
writes and an implicit-home fingerprint drift; both are fixed with
deterministic regressions in `39a4343` before this fresh full
qualification.

The prior live case exposed a real publication gap. A goal-less native
turn could persist its accepted result and terminal snapshot before
provider cleanup, while the task-session pointer was still empty. Normal
later admission then selected a fresh session. The fix publishes that
pointer and a private bound receipt in the **existing post-acceptance
terminal checkpoint transaction**, before cleanup. Earlier terminal
observations persist without a handled receipt or continuation pointer.
No result-acceptance or snapshot transaction was added. The late
completion path recognizes the receipt. This also prevents a late
callback from restoring a pointer after a user reset. Goal/control
publication keeps its existing owner.

The dedicated Daytona fixture now uses the existing warm/reusable
environment. Its sandbox, Runner and provider storage must survive. The
former generic per-turn fixture disposed the sandbox after completion
and kept provider-history backup bytes under the discarded directory.
Whole per-turn disk-loss acceptance therefore has a separate
provider-backup storage dependency. It remains distinct from the passing
native per-turn component checks with backup storage available. The
60-second lease, 300-second outage and 420-second grace are unchanged.

| Gate | Current repair evidence |
| --- | --- |
| Assembled regression | Baseline fails with an accepted result and
terminal snapshot but a NULL task pointer while real provider cleanup is
held. The fix passes normal continuation and reset cases, with no
pointer seeding. Exact merged `92b7447` passed 2/2 twice, including
after normal package TypeScript output refresh. Production files are
byte-identical at frozen `435ccd2`. |
| Persistence and concurrency | 19 helper/transaction cases and all 59
existing control-port cases pass on `0862062`. They cover bound result
IDs, reset/newer epochs, Stop, lock waits and expiry, receipt replay,
missing stubs, foreign bindings and atomic 4 KiB rollback. Existing
snapshot transaction count stays one. The new tests reproduce the exact
live missing-result-ID error and the inverse replay/status lock order
against `435ccd2`, then pass after the correction. Replayed results
still reject stale generations. |
| Completion | All 32 completion-boundary tests pass on merged
`92b7447`; the source is unchanged at `435ccd2`. Native result-shaped
session metadata is preserved. |
| Qualification fixture | A valid review report reproduced three
rejected correct replies. Exact token-boundary matching fixes them. 140
focused E2E/catalog cases and Product E2E typecheck pass. Wrong tokens,
marker prefixes/suffixes and wrong authors remain rejected;
retained-identity checks are unchanged. |
| Required checks | Full recursive typecheck and standard build passed
at `435ccd2`. Both exact commands also passed on `0862062`, with its
exact server build stamp; both also pass on `7a203274`, with its exact
server build stamp. Fresh `0862062` Greptile passed 5/5, with zero
unresolved threads. The `64c0b746` normal CI then passed all 49 jobs (48
success, one expected skip) and Greptile passed 5/5 with zero unresolved
findings. The `7a203274` normal CI also passed 48 jobs with one expected
skip, with fresh Greptile 5/5 and zero unresolved findings. Current
`39a4343` recursive typecheck and standard build both pass with
persisted exit codes and its exact build stamp; fresh Greptile is 5/5
with zero unresolved findings. Its normal CI completed successfully: 48
jobs passed and one expected job skipped. The fresh live result remains
separately failed. The `0862062` normal CI had 46 passing jobs, one
expected skip, one worker communication failure and its aggregate
failure; GitHub states the self-hosted runner lost communication. No
failed assertion or specific OOM/spot cause was established, and no
blind retry was used. |
| PostgreSQL supplement | One corrected all-pool pair at the preceding
repair passed 300-controller/10,000-history correctness and absolute
gates. SQL 76,590→75,990; transactions 9,013→8,713; UPDATE rows 11,613
each; 300 correct pointer writes each. PG CPU 31.99→30.46 s, WAL
70.36→67.87 MB, request p99 100.98→103.12 ms. This is one pair, not a
repeated improvement claim or an exact `0862062` CPU measurement. Its
two later changes defer premature publication and reorder existing
locks; they add no transaction, stream/idle writer, pool or timer. The
first collapsed-pool attempt remains invalid and retained. This is not
an exact final-head CPU/WAL measurement; later fixes change ordering,
identity selection and in-memory skill replacement without adding
snapshot transactions, pools, stream writes or idle SQL. |
| Live publication proof (`0862062`) | Baseline run
`06fcc806-f186-4190-9b57-087b61d75533` accepted result
`58f912dc-94d9-4b4d-bd3d-d5f689c83fd3`; the publication receipt names
the same result, the task pointer has parameters and `lastRunId`
matches, and the normalized native identity matches the following active
run. Accounting v2 settled. |
| Active recovery (`0862062`) | **FAIL.** SIGKILL/cache discard at
23:07:28.666 UTC; hold 300,000.859 ms; B ready at 308,896.486 ms;
natural generation-2 ownership at 312,906 ms. At about 319 s,
preparation failed `runner_harness_state_mismatch:
resumed_not_suspended`. No authenticated after-receipt passed within 420
s. Exact original Runner PID 668/start/fingerprint was independently
still alive; provider auto-stop was 15 minutes. No retained C follow-up
qualified. Canonical 0/1 `cleanup_failure`/cleanup-failed report remains
failed; subsequent independent cleanup deleted all three owned resources
with exact 404s and confirmed full intended-account inventory with zero
owned resources. |
| Verified adoption preparation (`64c0b746`) | 91 focused cases pass,
including actual preparation for four active providers and a distinct
prior/current warm proof. Unproved resumed state, dead process and stale
warm owner remain rejected. The earlier options-only fixture missed this
gate. No spawn, backup restore or PRP-authentication bypass was added.
Server typecheck passes. |
| Active warm identity (`64c0b746`) | **FAIL.** B claimed generation 2
at 312,995 ms. Preparation passed, then strict PRP recovery rejected the
generated attachment IDs at about 319 s. The saved and desired Runner,
lease, normalized session and run IDs matched; only
`turn_attachment_…`/`item_attachment_…` differed from generated
`turn-<run>`/`item-<run>`. Canonical 0/1 cleanup-failed report remains
failed; independent cleanup confirmed deletion/404s and zero owned
provider resources. |
| Six-field identity repair (`7a203274`) | Actual server-factory
regression RED4→GREEN38. A real Rust Runner test passes healthy first
run → random-ID warm handoff → held active second run → restored
controller. It verifies a new live authenticated connection, exact
identity, same Runner/provider OS identities, no duplicate launch/turn,
and no redispatch or invented receipt for an uncertain tool. The
synthetic wrong pair still fails the unchanged guard. This protocol case
does not claim business completion. Server and Runner typechecks pass. |
| Active recovery/completion (`7a203274`) | **PASS for the active
component.** Full five-minute SIGKILL/cache-loss hold. B ready at
308,936.651 ms; natural generation 2 observed 312,979 ms; authenticated
at 317,720 ms and resumed processing at 318,527 ms. Same run
`1e1ccb00-0728-4935-97da-57562d81cb42`, Runner
`246f73f7-a689-4177-a9c2-7ce711d63aed`, remote PID 669/start
23:48:27.470, provider lease/session and one submitted turn. Accepted
result `49097529-5310-4ac3-af95-5bf9b91d19f4`, publication, finalization
and accounting v2 all settled. |
| Full workflow (`7a203274`) | **FAIL, preserved.** Queued
late-requirement run `5e61f38d-c7d1-4fc1-bcbf-bce9d46ce4eb` failed
`runner did not durably suspend before checkpoint` before outage 2.
Canonical 0/1 candidate failure, cleanup passed, evidence valid. C
retention was not exercised. Independent provider absence,
controllers/PG cleanup, EC2 termination and root-volume absence all
confirmed; closed receipt SHA-256
`676a3b15eb9937b6bf995c36fb8666c88964d509e5ceb9109fb02da0aa2bc909`. |
| Retirement and stable configuration (`39a4343`) | Real Runner +
Postgres RED reproduced the exact suspension failure and nine owner
rejections. `turn.stop` is now lifecycle checkpoint maintenance under
unchanged owner/result/generation fences. GREEN25/25 proves actual
persisted suspension, exact identity and completed stop/drain/suspend;
unaccepted, foreign, stale and new-work negatives remain rejected. Two
default-home fingerprint REDs become GREEN9/9; explicit mode changes
still invalidate. No global matching exemption or historical fingerprint
rewrite. |
| Fresh full Daytona warm cell (`39a4343`) | **FAIL, preserved.**
Launched 00:15:29 UTC with automatic retries disabled. Active adoption
passed: actual offline hold 300,000.848 ms; B ready 309,922.155 ms;
natural generation 2 at 311,821 ms; authenticated 317,989 ms; resumed
330,440 ms. Same run `3e126819-e786-4b3b-b923-c975cf4f5b79`, Runner
`4079138a-8d7c-44a4-8558-07a5411d1f55`, PID 668/start and
provider/session identities. Accepted result
`08e504af-4dec-48a8-bf05-bf0a32280559` and publication passed. Queued
run `31d168c9-7ab9-4700-abb6-fafb90912237` failed the same strict
suspension error before outage 2. Its row selected a new native
identity, but no new third provider process or invocation was observed.
Recovery-time configuration still reset only `adapterConfig`; native
provider, context and workspace subtrees were unchanged. Canonical 0/1
candidate failure, evidence valid, normal cleanup passed; all campaign
provider/PG/process resources independently absent. Closed campaign
receipt SHA-256
`5e7d6281c13c812f3a946667f97f3c7d339b5ad86a3a819bd185b2fa73bc4a19`;
EC2/SSH remain temporarily held for the concrete follow-up repair.
Original 60/300/420-second limits and strict queued/second-replacement
checks remain unchanged. Direct-process path; no new live prepared-task
claim. |
| Native retirement authority (`283e05ffaa`) | Exact `39a4343` facade
regression RED3→GREEN9. The successor now uses its existing production
coordinator claim and prompt renewal before strict retirement. A real
Runner/Postgres case starts in the actual native-observed/unclaimed
phase, claims through production code, then closes and durably suspends
the predecessor in 1.657 s. All 25 real-Postgres cases pass;
unclaimed/foreign writers remain rejected. Shared attachment staging
stays after retirement; Stop and denied claims neither close nor stage.
No new claim or SQL path was added. |
| Configuration continuity (`283e05ffaa`) | Real shared/project-primary
environment selection → configuration with four skill versions
reproduces `reset: true`, changed category exactly `adapterConfig`,
after a Postgres JSONB read. Pinned restoration had reordered the
generated preference while actual runtime skills stayed identical.
Replacing existing pinned rows in place preserves the original fresh
name/key order and fingerprint. The assembled regression passes, as do
three existing pinned-version/rename/alias cases and server typecheck.
Genuine model/skill-selection changes still invalidate. No
fingerprint-format change or broad compatibility exemption. |
| Final production repair (`283e05ffaa`) | Full recursive
typecheck/build and [normal
CI](https://github.com/paperclipai/paperclip/actions/runs/41151145106)
PASS: 48 jobs plus one expected skip. Fresh review 5/5, zero unresolved
threads. Live baseline, recovered run and queued continuation all
succeeded, each accepted/published/committed once with accounting v2
settled. Their native/provider identities and configuration fingerprint
match; both recovery and continuation report no reset, no changed
categories and task-session reuse. Active outage/authentication remains
within original timing. |
| Browser-dependent continuation (`283e05ffaa`, definition 6) | **Whole
cell FAIL, preserved.** After B was killed at 00:46:38.928 and its cache
discarded, C became ready in 9,151.410 ms. `openParent()` then hit a
30-second `page.goto`/DOMContentLoaded timeout before posting the final
request. No fourth native run or C continuation was exercised. Cause of
navigation timeout is unknown. C task had no execution lock, queued
comments, handoff or recovery blocker; all three prior runs were
committed/accounted. Normal cleanup passed; independent provider
absence, controller/PG cleanup, EC2 termination and exact root-volume
absence confirmed. Sanitized report bundle SHA-256
`2a3b841d62efb2ae30ef14f96a431ac4fa7fe3a782f1144831512f78edc65022`. |
| Native API continuation qualification (`9eb9ac6f9e`, definition 7) |
**FAIL, preserved.** The real post-C API request dispatched run
`c71fbb18-f979-4fe4-93ce-9c4be46dbf21`, which failed
`native_session_interrupted` / `native_session_recovery_failed` at
01:10:00.640 UTC. It selected the same normalized native identity,
Runner and checkpoint-provider identity as the three succeeded turns. No
C result was accepted; pending accounting remains explicit. Active
recovery passed: actual offline hold 300,001.098 ms, B ready 308,335.019
ms, natural generation 2 observed 311,818 ms, authenticated 315,540 ms,
resumed 316,612 ms. Queued continuation succeeded/accepted/published. B
was then killed/cache discarded at 01:09:34.500 and C ready in 8,783.803
ms. Original classifier `transient_infrastructure`, whole-case failure
and cleanup passed are unchanged; that classifier does not establish the
root cause. All owned provider/PG/process resources, EC2, root volume
and SSH agent independently absent. Closed receipt SHA-256
`7f21ac4a22efc07b849fa7e17866083b6127b3321af12671b4fc054ce57039a9`;
sanitized bundle
`71ffef14a30a553e008320a31840a6d6c0de85c1bfdb60f783fdb53a6aae812a`.
Exact backend detail is unavailable in approved structured evidence. |
| Current required checks (`9eb9ac6f9e`) | Recursive typecheck, standard
build and exact build stamp PASS. [Normal
CI](https://github.com/paperclipai/paperclip/actions/runs/41152908417)
PASS: 48 jobs plus one expected skip. Fresh Greptile 5/5, latest edited
summary checked, zero unresolved threads. Exact8/512/8,192 stream probes
again report zero recovery SQL/transactions/rows and settled-idle SQL;
seven control transactions/twelve changed rows each, with 36 separate
legitimate renewals in the longest case. CI success does not supersede
the failed live C gate. |

The completion supplement observed secondary request/liveness/checkpoint
transaction p99 increases of 23.0%/45.7%/15.6% in its single pair.
Renewal p99 stayed below 0.865 s, with 900 successful renewals per arm
and no lost leases. The named pool caps stayed 10+2+2. An aggregate
activity sample peaked at 15 non-observer entries without backend-type
classification, so no claim is made that all were client connections. No
sampled lock episodes does not establish zero lock waits.

Twelve pure reader/selector cases also pass with the new adjacent
receipt. This is not another executed process rollback. Development
reader `5cf7aead` can parse the recovery state, but its old run-detail
redactor can expose receipt IDs/outcome to an authorized run reader. The
first production release containing recovery readers, complete
attachment-identity handling and both private-field redactions is the
rollback floor. The implicit-home fix prevents new recovery-time
fingerprint drift; it does not rewrite previously stored fingerprints
from failed candidates. The development probe is not a published
supported rollback target.

Latest actual `0862062` Runner tests independently passed 8/512/8,192
text chunks with zero recovery SQL, transactions and changed rows, plus
zero settled-idle SQL. All three observed seven setup/control
transactions and twelve changed rows. The 8,192-chunk case separately
recorded 31 legitimate lease-renewal statements, with no lost lease.
These are component SQL observations, not a production CPU/WAL claim.
The new adoption and identity branches affect recovery preparation only.
The `64c0b746`, `7a203274` and exact `39a4343` CI independently passed
all three stream sizes with the same zero-SQL/idle result; each latest
8,192-chunk case recorded 36 separate renewal statements. Exact
`39a4343` Runner 2/2 passed 133 files / 2,317 tests plus two skips; its
separate native group passed 150 tests plus eight skips.

The first API fixture revision omitted the mandatory final screenshot;
this was caught before paid launch and allocated no provider/model work.
The correction captures the actual retained Chromium page with an
explicit unqualified-browser label, without changing the standard report
validator.

Automatic approval review rejected exporting raw private API/workflow
snapshots because of sensitive payloads and insufficient
destination-specific authorization. Sanitized reports and
bound/hash-only receipts are retained; raw snapshots were not copied
through another channel. This does not change the failed grade.

Repair characterization also preserves its failed attempts. An
unconditional staging relocation broke three existing same-scope
scripted cases; the final implementation defers staging only for an
actual superseded warm scope, and all nine order/race cases pass. One
baseline transform overlapped an edit and is explicitly invalid; the
actual immutable `39a4343` loader then produced the three genuine REDs.
The independent task-directory hypothesis produced a RED but was
excluded by the live shared-workspace evidence; no directory policy
change was landed. A shared-workspace fixture authorization omission was
corrected separately from the four-skill semantic RED.

Setup failures are retained separately from semantic outcomes. These
include an old host port after the owned Postgres fixture restarted and
a sandbox-denied TSX IPC pipe. The supported external-Postgres run
passed, and the final exact recursive typecheck passes with normal
process permissions. Seven stale declaration errors after the master
merge cleared after compiling the actual merged SDK/Runner TypeScript
sources. No declarations were edited by hand.

<details>
<summary>Earlier qualification measurements and failed attempts
(historical, before this repair)</summary>

**Historical blocked gate (before the repair below).** Final native
implementation is `abed921e12d543b62f57a56435419c0dafb0bc33`; current
branch head is `af9e2d157dcc349e55374ad186c9be2d6cb96bf9`. The two later
commits change only qualification fixtures, their matcher and
documentation; `server/` and `packages/` are unchanged. It includes
master through `fd008979f5794fda3d5f54151d36acd31d0de140`.

The live Daytona measurement proves five-minute active recovery,
once-only completion and accounting, but **fails retained-session
identity after the second replacement**. The saved checkpoint and
recovery metadata exist. The task-session pointer remains empty, and
ordinary admission creates new native/provider sessions. The exact
skipped publication boundary remains unproven. A useful saved-file
result alone does not satisfy retained-session continuation. This
application-path gap blocks merge independently of CI.

A separate new-master CI failure is owned by the storage workstream (fix
in #18357). No storage guard, session-identity oracle, lease/grace limit
or provider result was relaxed.

| Gate | Observed result and exact scope |
| --- | --- |
| Distinct source recovery and compatible rollback | PASS at A
`5cf7aead09a2d9c7e2f2929d761f535ef3c1d798` → B
`5ea45f8d17e33c9a62bd79982dcf0375b07733d0` → fresh B → A. Four
controller processes, natural 60-second lease expiry, absent native
projections before replacements, three succeeded/committed unique
results, one provider thread, unchanged Runner identity, and strict idle
cleanup. 177.782 seconds. |
| Immutable installed native component | PASS at installed A
`5cf7aead09a2d9c7e2f2929d761f535ef3c1d798` → installed B
`eaef0d56552c087aaa4fa68a8655282ffbd12667` → fresh B → A. Each
controller imports its contained compiled server and DB. Three unique
committed results, stable Runner/thread, no extra provider restart on
same-contract rollback, strict cleanup. 106.672 seconds. This is
compiled component proof, separate from full CLI-native application
acceptance. |
| Normal public CLI startup | PASS for B
`eaef0d56552c087aaa4fa68a8655282ffbd12667`, Node 24.22.1, darwin-arm64:
fresh external DB, 415 migrations, health ready, root HTML 200, company
POST 201 plus GET readback. The installed tree remained unchanged after
execution. |
| Five-minute component outage | Actual controller absence 300,168 ms.
Natural generation-2 claim at 407.196 seconds after crash, same provider
attempt and Runner, original run succeeded/committed. The larger
540-second case timed out before its retained follow-ups, so it is an
active-adoption pass, not a complete four-controller pass. The complete
short source/installed cases above independently cover follow-up and
rollback. |
| Drain/resume review regression | Fixed in
`226f03e736d1ee99fea1762ab32ea3a8a9241c20`. Five facade-level cases
pass: overdue normal/restart waits, future timer cancellation, another
facade resuming the original owner, and transient retry. Against exact
prior scheduler `5ea45f8d17e33c9a62bd79982dcf0375b07733d0`, four fail
and one passes. The later head changes documentation only. |
| Final corrected-fixture Daytona | **PARTIAL: active recovery PASS;
retained identity FAIL**, exact live source `0b6afc499f`. A was
SIGKILLed and native cache discarded; actual offline hold 300,000.375
ms. B was ready at 308,326.961 ms, naturally claimed generation 2 at
312,059 ms, authenticated at 315,996 ms and resumed processing at
316,519 ms, within the original 420-second boundary. The same run,
Runner PID/start, session, lease and event prefix survived; one turn
submitted. Original execution succeeded and settled accounting. After
completion, B was killed and its native cache discarded; C was ready in
9,077.779 ms. C executed the saved project and returned correct
`queue_r`, with all four runs succeeded/accounted. However, native and
true provider-session identities changed: the unchanged retained oracle
fails. No whole-workflow pass is claimed. |
| Prior matched-producer Daytona | FAILED at exact `abed921e12`. The
matching current-source Runner passed normal admission, completed the
first task and settled its accounting. During the active revision, A was
SIGKILLed and its native cache discarded. Actual offline hold was
300,000.727 ms; B was ready at 308,304 ms and naturally claimed
generation 2 at 309,651 ms. At about 318 seconds, the remote process
check reported `process_not_running` for the original admitted Runner.
No authenticated after-receipt or retained follow-up passed. The current
failure is preserved; no automatic retry, lease/grace relaxation, debt
edit or provider replay is used. Bounded forensic read found preserved
exact-bound state with no recoverable failure, a transport-reset
diagnostic and no terminal delivery; this supports external process loss
without proving the exact cause. The sandbox had a five-minute auto-stop
policy, conflicting with the required surviving-sandbox assumption.
Owned cleanup precedes the separate corrected-fixture case. |

**Live retained-session boundary.** Prior completed run `3806…` and C
follow-up `8adf1df3-6744-40bf-b35d-100451f29d9f` both have database
session snapshots and `nativeControllerRecovery`. Their tool
fingerprint, provider configuration, workspace descriptor,
runtime-context digest, driver and work mode match. There is no recorded
force-fresh/workspace-selection change, and this is an ordinary task
rather than a conversation-generation reset. The same issue/agent
task-session row has `session_params_json: null` and `last_run_id: null`
from baseline time. Both native normalized UUID and actual provider
session/thread hashes differ after C. Full application admission
therefore did not select the retained source. No fallback to file
execution or relaxed identity comparison is accepted as proof of
continuity.

**Independent cleanup completed.** Full current-account provider
inventory confirms no resources owned by either final fixture, with
exact-ID absence checks. Owned controllers and campaign Postgres are
stopped/removed. EC2 `i-01551c09af098dde5` is terminated, its
delete-on-termination root volume returned `InvalidVolume.NotFound` at
22:14:08 UTC, and the temporary SSH key/agent were removed. The
canonical failed report and immutable oracle input are retained. Closed
qualification receipt SHA-256:
`b4b5fefce287ebfdbf2cc2238efaad62d8ad485aed0e9c0628ae95dbc18a8575`.

**Original measurement and grader repair remain separate.** The C reply
contains the requested marker followed by a newline and the correct
output. The old workflow waited for one literal space, so its normal
receipt collection stalled; that original attempt was closed and its
canonical `cleanup_failure`/interrupted result is preserved. Commit
`af9e2d157d` repairs only this reply predicate, with 144 focused cases,
E2E typecheck, discovery and diff checks passing. Ordinary string
matching stays literal. The corrected predicate accepts the saved reply,
but the unchanged retained-identity oracle still fails. Pure
active-recovery grading of the captured measurement passes 7/7; this is
not a rewritten passing campaign.

The sandbox idle-window conflict was corrected only for this explicit
fixture (15 minutes). Actual baseline and later sandbox metadata confirm
that policy; the original active box was disposed before a post-gate
policy read, so its 15-minute setting is established by the normal
create/environment configuration rather than an after-read of that box.
Production native lifecycle and the 60/300/420-second constants remain
unchanged.

The development compatibility reader A is a genuine backport commit
based on `59ff89a18fe1312b5f0bb908439bbdb1237b0252`, with the required
idle-goal reader fixes. It is not a previously published release. Its
older executor differs from B. The rollback floor must include this
reader capability. The source component cases admitted the Linux ARM64
Runner packaged at `59ff89a18fe1312b5f0bb908439bbdb1237b0252`; the
installed component case admitted the `5cf7aead` package. Their Runner
bytes are identical: SHA-256
`b1f04caa1ce04e720dec7eb62ede170eb3621948c0849b8f305ea5c5116bced8`. Each
admitted artifact remained unchanged throughout its case.

[Final public package
build](https://github.com/paperclipai/paperclip/actions/runs/41121460635)
and [reader-floor
build](https://github.com/paperclipai/paperclip/actions/runs/41122170506)
both passed all four daemon builds, package assembly and both Darwin
clean consumers. Both Linux ARM consumers failed before provider work
with the same existing local Codex permission-profile error: bubblewrap
attempts `activity.fifo/.git` and reports “Not a directory.” This
matched baseline failure remains open; it is not a native remote
continuity pass. Full post-run tree and build-stamp revalidation also
passed after the compiled native case. The installed component trees are
A `c29114c1bf71c5af00f761aeb9e3d84ed3d3075b9f5600dee3ef2543eb2b6ec5` and
B `eda575505373a3bdc630fa4919862b359791fe3a7ef637961a25b73b38efe4b0`.

**Controlled PostgreSQL qualification passed.**
Baseline/candidate/candidate/baseline workloads used 300 controllers,
10,000 historical tasks, real snapshot/encrypted PRP writes and
unchanged pools. PostgreSQL and client were each limited to two CPUs and
1536 MiB on an isolated eight-vCPU Linux host.

| Workload | PG CPU per operation | WAL per operation | Database request
p99 |
| --- | ---: | ---: | ---: |
| Steady | +1.18% | +1.81% | +1.91% |
| Aligned burst | +3.40% | +2.56% | +3.81% |
| Two logical servers | +3.11% | +2.56% | +9.68% |

All arms passed absolute/correctness gates with unchanged control
transaction counts, no dropped operations and no owner loss. Overlap p99
has little margin below the relative threshold. It uses two clients in
one Node process, not two HTTP servers. [Closed measurements and
limitations](doc/plans/2026-10-30-native-controller-qualification-evidence.json)
and exact-source reproduction patches are retained. [Earlier
contended-host
failures](doc/plans/2026-10-30-native-controller-load-evidence.json)
remain unchanged. The production DB-claim probe claimed 300 owners in
2.84 seconds and restored/committed controls and snapshots in 8.74
seconds, with zero owner loss or settled-idle SQL; its provider
references were synthetic. The measured checkpoint/snapshot/renewal
paths retain the same persistence behavior after integration; later
accounting and business writes have separate owners.

Actual Runner stream tests at `da8c7f6e1837ddd896dfe83a7524812fee813487`
passed 8/512/8,192 chunks: zero recovery SQL, transactions and changed
rows during text intervals; zero settled-idle SQL. Each retained seven
control transactions and twelve changed records. Existing renewal SQL
was measured separately. The guard/scheduler fixes add no stream path,
pool or recurring idle scan.

The live fixture used current-source producer SHA-256
`f0000c90cb83880191479da639201e659aa6ce0fc7d67c859faa172ec977849e`, a
normal locked exact-head build with pinned Rust 1.97.1 in Bookworm.
Actual network-isolated, read-only ABI execution passed (GLIBC
requirement 2.34 against runtime 2.36). The immutable base image
remained
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:36069788f53c51f228764fa36180575443dfb5d1f84a342d7c0daceb28dc61cc`,
source `a0ef3ce7`. This was an unpublished development producer,
explicitly distinct from the base image and admitted before the fresh
fixture began. The earlier host build failed ABI preflight before
admission. The preceding old-producer fixture completed its initial task
but lacked the usage-basis marker required by current master; it
remained pending/unpriced and correctly paused. It was independently
cleaned without debt or budget changes. Two preceding local Linux setup
attempts OOM-killed before provider allocation, and their cleanup
passed. These attempts remain separate from the final recovery failure.

**Failures retained and resolved separately.** The earlier `98f05fc`
probe rejected a valid settled PRP v2 goal suffix; `eaef0d5` fixed that
reader and the fresh follow-up passed. Later component cleanup failures
were traced by a scoped exception observer to the fixture adapter
rejecting directory downloads. A bounded owned-directory transfer with
exact-byte/mode preflight corrected the fixture; source and installed
strict-cleanup cases then passed. No production guard was relaxed. The
initial local integrated control-port run hit its 30-second embedded
Postgres startup hook before executing 59 cases; 18 other focused cases
passed. A bounded rerun used a fresh owned external Postgres fixture,
applied normal migrations before Vitest, and passed all 59 cases with
the original timeouts unchanged. Its container and data were removed;
the failed attempt remains retained.

The additional opt-in full Product E2E Vitest run is not green: 5,313
passed, seven failed and three skipped. An actual `abed921e12` archive
with the same dependencies, Node and IPC permissions reproduces all
seven failures with the same reasons. Five are unchanged
workflow-policy/profile-pin assertions, including Pi profile version 37
versus the test pin 35. Two database suites failed during embedded
Postgres startup before their assertions; semaphore exhaustion is
confirmed in the observer log. The observer passes its supported
external-Postgres rerun with original timeouts and source unchanged. The
controller-database client-kill/postmaster assertions remain unexecuted
after `initdb` bootstrap failure; no external override is supported. The
unit launcher stopped before its Node-test phase, which was then run
independently and passed 181/181. The original failed full run is
preserved. These results remain distinct from the passing focused checks
and normal repository CI. The first local Product E2E typecheck also
encountered stale compiled Runner declarations; a genuine package-local
TypeScript compile refreshed them and the unchanged check passed,
without a dependency install or producer rebuild.

Earlier [Daytona campaign
41108162900](https://github.com/paperclipai/paperclip/actions/runs/41108162900)
failed at sandbox creation before any agent, with the underlying
provider error unavailable. Its [sanitized
report](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-41108162900-2/index.html)
remains a `cleanup_failure`. Both old creation names are absent in the
current authenticated account, but the old CI account identity was not
retained, so account equivalence is unproven. The subsequent exact
`eaef0d5` source Product E2E attempt passed image/agent setup and the
initial project, then held the controller offline for 300,003.7 ms. Its
Mac supervisor failed owned-process inspection before B readiness; no
adoption passed. Full current-company lease/label checks, provider
deletion, exact-ID 404s and complete inventory confirmed cleanup of that
attempt. Its local server and owned Postgres stopped. The prior AWS
campaigns and database qualification VM were terminated with root
volumes removed.

The old admitted test Runner lacks the newer usage-basis marker
introduced on master. The integrated component B turns retained
unpriced, incomplete accounting obligations with `costAccountingPending:
true` and no settled charge. The compatibility-reader A turn used its
legacy receipt interpretation but likewise retained pending accounting
and no settlement timestamp. This proves obligation preservation, not a
whole-run accounting migration. Runner/receiver release ordering remains
governed by the usage owner's contract.

At native implementation `abed921e12d543b62f57a56435419c0dafb0bc33`,
Greptile was 5/5 with zero unresolved threads and CI completed with 54
successful checks and five expected skips. At `0b6afc499f`, Greptile
again passed 5/5 with zero unresolved threads, but CI ended with 51
successful checks, five skips and three failures. Server 9/12 fails a
deterministic managed-skills maintenance assertion newly inherited from
master `198218bf` in merge `c80e00ad`; that test is absent from the PR
head, and the storage owner has the explicit-StorageService fix in
#18357. Runner 2/2 passed 2,283 unit cases but its runner received a
shutdown signal during the long stream probe; its cancelled step and
aggregate failure are preserved. No blind retry was used. Current
`af9e2d157d` checks are pending; the matcher-only change passes 144
focused cases and Product E2E typecheck. Earlier scheduling-sensitive CI
failures and the interrupted unsharded local test run remain recorded in
the dated plan. CI runs the repository's normal test partitions. Final
verification does not claim Railway rollout, uninterrupted HTTP service
or whole-webserver filesystem loss.

</details>

## Risks

- The task-pointer repair passes its assembled regression. The first
live repair exposed pre-acceptance ordering and the fresh review exposed
a replay lock-order issue; both are fixed and pass real Postgres tests
at `0862062`. The following live attempt exposed the
verified-running-versus-suspended preparation gate. Its narrow fix
passes 91 focused cases at `64c0b746`. The next live case exposed
synthetic attachment IDs; `7a203274` fixes that field selection and
passes real Runner authentication. The subsequent queued continuation
exposed strict retirement maintenance and a false default-home change;
`39a4343` fixes both with real Runner/Postgres and fingerprint
regressions. The `39a4343` live continuation failed again despite green
CI. `283e05ffaa` repairs the actual native-observed admission ordering
and reproduces/fixes the JSONB skill-order fingerprint drift. Both pass
targeted real-Postgres regressions and the live active plus queued
paths. The definition 6 post-C browser navigation timed out before
admission. Explicit definition 7 now verifies native continuation
through the ordinary comment API; its strict post-C native gate failed
after a real dispatch and remains historical failed evidence. The final
fc68584 repair now passes its fresh strict 49-check Linux/Daytona
campaign; the prior failed grades remain unchanged. Browser reconnection
is handed to its own workstream with the original failed evidence. No
prior failed campaign is reclassified as passing.
- Incorrect checkpoint/source binding or stale ownership could duplicate
external work. Missing evidence remains a hold; existing receipt and
finalization owners keep uncertain effects unresolved.
- Recovery must retain maintenance writes after accepted results without
allowing a stale business turn to write. Real lock-wait and generation
tests cover that boundary.
- The current two-connection paired burst profile fails its absolute
drain gate in both baseline and candidate, despite passing relative load
gates and all correctness checks. A causal capacity diagnostic selected
three slots; the final controlled cap-three profiles pass unchanged
thresholds. Full application replacement and two-server overlap capacity
remain separate. There is no new streaming writer, pool or recurring
idle scan.
- The remote sandbox and Runner must survive the recovery window.
Provider auto-stop is a separate lifetime bound from reconnect grace;
the explicit qualification fixture uses a longer idle window.
- Workspace and provider backup availability remain external
dependencies. This PR does not certify whole-webserver filesystem loss,
uninterrupted HTTP service or a Railway rollout.

## Model Used

Implementation and initial verification used OpenAI GPT-6 through Codex;
the initial hosted snapshot was not exposed. The follow-up qualification
used three OpenAI `gpt-6.1-sol` workers coordinated through Codex, with
repository tools, code execution, CI and scoped test infrastructure.
Context-window size is not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (focused and exact-source
application/cost checks pass; full forced CI passes; earlier local
embedded-PG setup failures remain recorded)
- [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 (exact fc68584 full CI and
auxiliary checks pass; forced complete test partitions)
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
(exact fc68584 check and edited summary pass; all six threads resolved)
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.7
2026-10-31 07:33:52 -05:00
DottaandPaperclip 322fa6b65c fix(ui): restore task document authoring and add persistence journey (#18356)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Task documents keep versioned work beside each conversation.
> - The default chat interface could read general documents but hid
their editor.
> - People also need unfinished edits to survive a tab switch or reload.
> - This pull request restores the shared editor in Artifacts.
> - A portable browser journey checks exact saved content and revision
history.
> - The benefit is a usable document flow with independent deployment
checks.

## Linked Issues or Issue Description

**What happened?**

A person using the default task interface could read a general task
document but could not create or edit one. The existing editor was
available in Classic mode. A pending create could also leave newer text
as a new form after its editor unmounted, causing a conflict against the
person's own successful creation.

**Expected behavior**

A person can create and edit general documents through Artifacts.
Titles, bodies and revision history persist after reopening and
reloading the task. Unfinished text survives tab switches. A successful
create makes retained newer text an edit of that confirmed revision.
Later writes from another actor still cause a conflict.

**Steps to reproduce**

1. Open an ordinary task in the default chat interface, then open
Artifacts.
2. Try to create a general document. The previous interface has no
authoring control.
3. With authoring restored, submit a new document, keep typing, and
switch to Properties before the request finishes.
4. Reopen Artifacts. The previous draft path restores a new form despite
the successful create.

Related public work: #17598 adds document copy/download and #18157 adds
image galleries. The selected actual merged parent is
`f1d780838218f975064f38333946805e0ec103a5` from #18427. It includes the
stable profile-entry ordering repair and the exact recovery-fixture
prerequisite. The resulting PR diff contains 32 document and reporting
files.

## What Changed

- Reuse `IssueDocumentsSection` for general documents in default-chat
Artifacts. Keep Classic authoring in its existing task body. Ordinary
tasks, conversations and Coordinator mode share the same editor options
and signed-in permission wrapper.
- Preserve Plans, file-review documents, attachments, uploads and work
products. Hide duplicate general-document cards. Use the same
general-document key rules for visible rows, validation and refused
writes.
- Forward image uploads, mentions, references, author maps and feedback
to both editor mounts. Keep empty mention/project values stable while
queries load.
- Back up unfinished forms within their signed-in account, task and
editor scope. Preserve text entered before its key. Record a successful
create on its matching retained newer buffer, including after unmount or
an early reopen. Preserve newer title/body edits, real remote conflicts
and matching cancellation cleanup.
- Add the model-free `task-document-persistence` journey. Setup creates
only an owned empty backlog task. The browser creates and edits the
document; normal APIs independently check company, task, actor, exact
content and both revision records.
- Reopen the owned task through the explicit Backlog view, then reload
it. Require exact UI readback and zero native runs. Add only the Doc
registration, definition-hash inputs, report mapping and four closed
checks to the shared harness.
- Count explicit zero-run browser receipts after private journey
metadata is removed for publication. Preserve missing billing evidence,
positive usage and native/protocol accounting.
- Update browser assertions for the restored inline editor while
retaining exact download bytes, revision collisions, paused-state and
no-run checks. Update the feature map, usage docs and shared editor
stories.

## Verification

- Latest focused checks use official Node 24.22.2: 568 journey, catalog,
report, billing and attempt-accounting tests across 25 suites pass. All
four admitted journeys remain registered. The seven relevant UI suites
pass 529 tests, including the task-page container after the parent
merge. Maps, token gates, the PR-scope diff check and the owned
credential-pattern scan pass. The normal QA import preflight also passes
with an empty environment and network access blocked.
- Billing regression: before the repair, the explicit empty public
receipt counted one run, and two positive-usage receipts were discarded
by browser metadata. Those three cases fail before and pass after the
repair. Two additional red regressions cover aggregate usage beside an
empty run list. That ambiguous shape now keeps an unavailable receipt
and a minimum count of one. Missing receipts retain unavailable billing,
and native/protocol one-or-more run totals retain their measurements.
- The previous fresh CI run failed its unchanged snapshot-only recovery
fixture: one global sweep did not call its callback. The original
failure remains recorded. An isolated PGlite probe with all canonical
migrations exercises the real reconciler: it processes two earlier
sources, then reaches the owned third source on the next sweep. It
preserves source evidence, files and run IDs. This proves bounded
pagination, not full native snapshot repair.
- Local native recovery tests could not start PostgreSQL because the
host semaphore limit was reached. That run executed zero cases.
Canonical Linux CI later passed all 143 fixture cases, including the
original snapshot-only case and the new competing-candidate control. The
exact fixture repair is now inherited from #18427 and is absent from
this PR diff.
- The portable oracle rejects 19 stale, missing, foreign or incorrect
outcomes. Result validation also rejects model/provider metadata and
native runs for this case.
- Five real Artifacts-to-Properties unmount regressions fail before the
repair and pass after it. They cover both editor modes, reopening before
and after completion, later typing, and a foreign revision that must
still conflict. The edit-storage failure case also checks that Cancel
clears the promoted fallback copy.
- UI coverage includes default chat, Classic, conversations,
Coordinator, Plan rendering, document-card deduplication, reserved keys,
pending-query stability, permissions and rich editor options.
- Earlier real browser checks passed five upload cases and two
artifact-arrival cases. They retain exact CSV bytes, original/revised
content, collision, paused-state and no-run assertions. Current-head
normal CI runs the updated browser suites again.
- The branch merges only the selected actual parent
`f1d780838218f975064f38333946805e0ec103a5`. The merge has no conflicts
or manual resolution. The SQL service and recovery fixture match that
parent exactly. The own document editor, persistence flow, saved-state
oracle and billing repair retain their previously qualified source
blobs. Follow-up, clarification, question/resumption, screenshot helpers
and the Steering map are byte-identical to the merged parent. Existing
project/search/question/follow-up registrations remain present.
- Required document source blobs remain exact: Doc UI
`22e80663b053363e5f75e1432dd9043dc0e70243`, its unmount tests
`16f3f4ed0dc9b11aaff129e06e6cf2bbf4522713`, readiness helper
`800a747284db19b8484650b6759e8bd1f356839d`, and budget service
`3a15d489f0aa55c22e8f7fe6a6bc6a0e14e5914e`.
- Local typing is limited by borrowed declarations from another
checkout. They omit current `skill_test` and sandbox creation-operation
fields. No dependency declarations or repository config were changed.
The authoritative clean CI Typecheck + Release Registry gate passes on
exact head `2ffce29827ae170420d740940c1c069c7225a74c`.
- Full monorepo typecheck, tests and build were not run locally.
Borrowed build declarations from another checkout limit local typing.
Authoritative [clean
CI](https://github.com/paperclipai/paperclip/actions/runs/41171717008)
passes on exact head `82d15946c5844d3ae41c6ade62fa224053f20a9a`: 55
successful checks, 3 skipped and 1 neutral, with zero pending or failed
checks. Typecheck, build, Runner, server and browser lanes pass.
Greptile gives that same head a fresh 5/5. All 15 review threads are
resolved, with no further thread page. The PR is mergeable and clean.
- Failure history remains recorded. The earlier recovery failure was
repaired with a bounded, owned-source fixture. A later CI worker shut
down after 2,375 Runner unit tests passed. Its one authorized narrow
retry passed those tests and all five native integration suites. The
separate AgentConfig browser failure was reproduced and fixed by the
merged #18427 parent. These earlier passes do not replace current-head
CI.
- Final-source live qualification passed on exact harness and served
application `82d15946c5844d3ae41c6ade62fa224053f20a9a`. QA run
`41177696858` completed all four closed checks and all five phases with
zero native runs. Cleanup passed; the durable manifest is complete with
no pending evidence. The coordinator verified the original grade and
manifest.
- The [public qualification
report](https://pages.paperclip.ing/evals-qa-smoke-41177696858-1/)
records zero agent runs, empty run IDs and empty run usage. Pricing
remains unavailable and billing remains incomplete; the report does not
claim measured zero cost.
- The earlier harness `36c8d9ddd76d0b7ddb28a9a6c674d9e538f6df88` pass
against application `2ffce29827ae170420d740940c1c069c7225a74c` remains
historical evidence. It is separate from the final-source measurement
above.
- The selected parent brings profile-entry ordering, proactive chat, a
database migration, Runner updates, and task-page chat/read behavior.
Its new task-page container is included in the final application
measurement. The coordinator retains the original evidence and owns the
primary merge and daily-plan admission.

## Risks

Artifacts now mounts the existing shared editor. Its autosave, conflict,
revision, annotation and server access contracts remain in place. Tests
cover both interface modes, shared scopes, later remote writes and
unavailable edit storage. Plans and generated file-review documents keep
their existing flows. The PR adds no database schema or API change. The
shared billing repair requires explicit captured empty run IDs and an
unambiguous usage object containing only an empty run list for public
browser-only receipts. Other fields beside an empty list keep
conservative unavailable billing. Missing measurements remain
unavailable. Contradicting positive usage remains counted. The inherited
recovery fixture keeps the production sweep limit and its source,
readback and no-agent-work assertions.

The live journey must fail when authoring controls or saved outcomes are
absent. It must not create the expected document through setup APIs or
switch to another interface to pass. Final deployment verification must
retain the actual app and harness revisions separately.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1031.0-canary.6 nightly/v2026.1031.0-nightly.0
2026-10-31 01:49:24 -05:00
DottaandPaperclip f1d7808382 fix(tools): stabilize tied profile entry order (#18427)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Advanced YAML editor reads shared tool profiles through their
owning service.
> - The editor must preserve hidden settings and reject real concurrent
changes.
> - Batch-created entries share a creation time. Queries sorted only by
that time can return the same entries in a different order.
> - The editor can then report a false concurrent tool change before it
sends a profile binding request.
> - This pull request adds an ID tie-breaker to profile entry reads.
> - The benefit is a stable saved configuration without removing the
concurrent-change guard.

## Linked Issues or Issue Description

Refs #18356. Related: #18168.

**What happened?**

The compact YAML browser case failed at its second save. Save stayed
enabled and the profile binding write did not occur. The original CI
artifact has no response bodies. It does not establish the exact entry
order from that run.

A controlled browser test reproduced this failure. It changed only the
order of 30 equal-time entries in the second preflight response. The
client reported `tools changed while you were editing. Reload saved
before saving.` No binding request followed. A separate first-save
response barrier showed that the pending-save guard worked.

**Expected behavior**

Reads of unchanged entries must have a stable order. Real entry changes
must still trigger the existing configuration checks. Entry order does
not set policy precedence; exclusions still win over matching includes.

**Steps to reproduce**

Create a profile with entries that share one creation time. Read the
profile, change the physical row layout in a disposable PostgreSQL
database, and read it again. The old service has no tie-breaker for
these entries. The new regression fails against that service.

## What Changed

- Sort list and detail entry reads by creation time, then ID, in the
profile service. These reads supply saved configuration snapshots. Other
reads retain their existing behavior.
- Add one real PostgreSQL regression. It changes heap layout in both
directions, checks stable list and detail values, preserves
chronological ordering, checks company boundaries, and checks
include/exclude results and a real entry change.
- Include the exact test-only recovery prerequisite from commit
`36c8d9ddd76d0b7ddb28a9a6c674d9e538f6df88`. Its file blob is unchanged.
It removes a one-sweep fixture assumption while keeping bounded recovery
assertions. No document UI or journey code is imported.

## Verification

- Base: one frozen public master snapshot,
`8c9dd1e4445e58cc9ca08076dfe9c0b27038d6ee`. The affected service,
schema, projection, resolver, and save guard match the failed CI merge
`94d98d5c75c8f331aad4bfab2111ee587b0c63fe`.
- RED: the new real PostgreSQL test fails on the old service. Both
physical layouts were verified before the ordering assertion failed.
- GREEN: `cd server && pnpm exec vitest run
src/__tests__/tool-profile-entry-order.test.ts
src/__tests__/tool-profile-entry-validation.test.ts` — 18 tests pass
with real PostgreSQL 17.
- GREEN: `cd ui && pnpm exec vitest run
src/lib/agent-configuration/save.test.ts
src/lib/agent-configuration-yaml.test.ts --maxWorkers 1` — 51 tests
pass.
- GREEN: one focused Chromium treatment of the original compact YAML
case passes. The treatment changes the actual disposable database heap
after the first save. It does not transform HTTP responses. The 30
equal-time entries stay identical through the API, the second bind
returns 201, and the original hidden-setting and disabled-Save
assertions pass.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Local tests use Node 24, a macOS source server, Chromium, and an
isolated loopback PostgreSQL 17 container. The server and container are
stopped. Private traces and control source are retained outside Git.
These controls do not prove a deployed Cloud result.
- A review follow-up removes two unnecessary query changes. Fresh real
PostgreSQL verification still passes all 18 tests. The list/detail
queries and browser path are unchanged from the passing heap-reorder
treatment.
- Prior head `59edcade203d6a05923955f5a0118e62c7e549c5` had a separate
browser failure in run `41169427774`:
`disconnect-write-recovery.spec.ts:204` kept the original title after a
mocked session lookup failure. Its relevant test and UI source are
unchanged from the base. The cause is unresolved. The two removed query
changes do not repair it. The original log and artifact are retained; no
unchanged job retry was issued. On the current head, this case passes in
14.3 seconds. The compact YAML case also passes in 11.2 seconds. The
later success does not establish the prior failure cause.
- Final exact head: `81c584aeac116b9d7a126b55dc99d5f6c70c195f`. [CI run
41169978784](https://github.com/paperclipai/paperclip/actions/runs/41169978784)
completes with success: all 47 workflow jobs are terminal, and all 57 PR
check/status entries are green or accepted neutral/skipped states. Full
typecheck, build, Runner checks, security checks, and `ci / verify`
pass. They were not repeated as broad local commands because the shared
host is under load.
- The new PostgreSQL regression also passes in Linux CI in 911 ms.
Server shard 12 has 1,839 passing tests. Browser shard 3 has 45 passing
tests, including the original compact YAML case.
- Fresh Greptile and Paperclip reviews both give this exact head 5/5
with no findings. All review threads are resolved. The branch is
mergeable and clean.

## Risks

- Entries with the same creation time now use ID order. Their prior
relative order was undefined. Entries with different creation times keep
their existing order.
- The query still sorts the same rows and adds one key to the sort. It
adds no query, polling, schema change, or migration.
- The configuration equality and concurrent-change checks are unchanged.
This fix does not ignore real tool changes.
- The original CI response order is unknown. The regression proves a
permitted ordering defect and the matching failure mechanism, not the
unique historical cause.

## Model Used

- OpenAI Codex, based on GPT-6, with reasoning, source inspection,
terminal tools, and browser test execution. 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>
canary/v2026.1031.0-canary.5
2026-10-31 00:07:06 -05:00
Devin FoleyandClaude Opus 5.5 978ffb6e11 fix(adapter-utils): tolerate entries removed during workspace snapshots (#18426)
Treat ENOENT from lstat, readlink, content hashing or opendir of a listed non-root entry as an absent entry during workspace snapshot walks. A concurrent restore can rename its temporary merge file between the directory listing and the read. A missing capture root and all other errors still fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
canary/v2026.1031.0-canary.4
2026-10-30 21:53:19 -07:00