Commit Graph
90 Commits
Author SHA1 Message Date
Nicky LeachandClaude Opus 5.5 abc270ee4c fix(runner): attest upstream releases and bind ACPX uniformly for every harness (#18325)
## Thinking Path

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

## Linked Issues or Issue Description

Refs #18237, #18212, #17972.

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 09:10:50 -07:00
Nicky Leach fba0ab8162 fix(runner): preserve GitHub helpers and Codex probe policy (#18212) 2026-10-30 07:42:10 -07:00
Nicky LeachandClaude Opus 5.5 fa760dbce4 fix(runner): reuse image packs only with matching contract digest (#18237)
## Thinking Path

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

## Linked Issues or Issue Description

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

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

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

## Model Used

Anthropic Claude Opus 5.5 (`claude-opus-5-5`) through Claude Code in the
desktop app, with repository tools, shell execution and research
subagents. The session does not expose the context window size.

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 22:55:11 -07:00
Nicky Leach a8e07500db fix(runner): preserve runtime activity through the native bridge (#18239) 2026-10-29 18:36:04 -07:00
Nicky LeachandPaperclip 1d571de5f9 Add shared native turn attribution boundaries (#18213)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

## What Changed

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

## Verification

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

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

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

## Risks

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

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and local code/tool
execution. The exact runtime model ID and context-window size are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 17:45:56 -07:00
Devin FoleyandClaude Opus 5.5 16816d45e6 fix(runner): keep OpenCode thread/read within runnerd's frame limit (#18218)
## Thinking Path

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

## Linked Issues or Issue Description

**What happened?**

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

**Steps to reproduce**

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

**Expected behavior**

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

**Root cause**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

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

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

## Linked Issues or Issue Description

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

**Agent or provider**

Google Antigravity ACP 1.4.3.

**Why this adapter is useful**

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

**How the agent is invoked**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-29 16:36:12 -05:00
Nicky LeachandPaperclip 27be859044 Record runtime activity under Runner authority (#18050)
## Thinking Path

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

## Linked Issues or Issue Description

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

**Subsystem affected**

Runner activity recording and provider command environments.

**Problem or motivation**

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

**Proposed solution**

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

## What Changed

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

## Verification

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

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

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

**Paperclip version or commit**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Codex <noreply@openai.com>
2026-10-29 04:24:57 -05:00
Nicky LeachandPaperclip aa75ec9d56 Replay Claude native options on ACP reconnect (#18135)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

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

## Upstream status and backport scope

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

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

**Subsystem affected**

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

**Problem or motivation**

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

**Proposed solution**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

## Thinking Path

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

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Native Runner preparation and retry skill selection.

**Current behavior**

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

**Proposed behavior**

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

**Reason and benefit**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

OpenAI Codex, GPT-6 family, with reasoning and tool use. The exact model
revision is not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 17:09:24 -07:00
DottaandPaperclip 356c7de9b7 fix(runner): bind Grok packs to current admission source (#17972)
## Thinking Path

> - Paperclip manages agents and their work.
> - Native agents use verified Runner and provider-pack artifacts.
> - A protected installed pack can be reused when its selected provider
profile matches.
> - Grok kept profile 1 when its sidecar gained effort, search, and
startup diagnostics.
> - An older Grok sidecar can therefore pass compatibility and reject
the new session fields before provider startup.
> - This PR binds the current Grok profile to its admission source so a
fresh run selects the current verified pack.

## Linked Issues or Issue Description

Refs: #17922, #17942, #17962. Related installation contract: #14024. No
duplicate repair was found.

**What happened?**

The selected Grok profile digest stayed unchanged across native session
contract changes. The installed-pack verifier correctly compared that
digest, but the unchanged value let a pre-effort sidecar satisfy a
current controller. That old parser rejects `grokEffort` and
`grokDisableWebSearch` before the new startup diagnostics run.

**Expected behavior**

A fresh Grok run must use a pack that supports its current session
contract. Source-only app changes must still permit warm reuse when the
selected Grok profile matches. Reattachment must keep its exact admitted
artifact authority.

**Steps to reproduce**

1. Retain a protected pack with published Grok profile 1 and ACPX
interface 1.
2. Upgrade the controller to the native effort and search contract.
3. Start Grok 4.7 with High effort and disabled web search.
4. The old profile passes installed-pack compatibility, but its sidecar
rejects the new fields.

**Paperclip version or commit**

Reproduced from master at `09ad9adce2cf4742944353a3707a2f908e9bb35e`.

## What Changed

- Advance Grok to profile 7. Keep historical versions 1–6 decodable and
keep the Grok 1.0.13 runtime pin.
- Stamp the Grok admission source identity into a generated launcher
comment. Keep the existing physical command-byte digest check unchanged.
Bind effort/search/credential handling, sidecar admission, and Rust
backend/session/diagnostic source.
- Check the source attestation in the existing TypeScript/Rust profile
build gate. Keep its required fixture in the Docker context. Refuse to
overwrite a versioned identity after source changes.
- Add regression coverage for rejecting the old pack, current-profile
warm reuse, exact historical recovery authority, and actual sidecar
dispatch of Grok 4.7 High with both search policies.
- Re-attest Copilot as profile 71 because its bound shared recovery
decoder now retains Grok 6. Preserve Copilot 70 and all earlier
identities. Keep the compatibility algorithm, other provider identities,
dependencies, lockfile, and workflows unchanged.

## Verification

- The production installed-pack regression failed before the profile
update: the old Grok pack was accepted. It now passes.
- 105 server manifest, artifact, archive, and authority tests passed.
- 246 Runner profile, physical launcher integrity, Grok
effort/search/credential, and actual sidecar process tests passed; six
existing platform cases were skipped.
- 31 Node packaging and identity tests passed, including an actual
generator CLI regression that preserves all authority files when a
versioned identity would change.
- 55 Rust ACPX unit tests and 17 real sidecar pipe tests passed. After
the final profile declaration, all 55 unit checks passed again.
- Final `pnpm -r typecheck` and `pnpm build` passed at the final source.
- CI on the preceding head caught Copilot’s stale attestation for the
shared recovery decoder. The same current-source test failed locally,
then passed after profile 71 was generated with version 70 retained. All
106 affected Copilot/profile checks pass. Final head
`78e6d76fc52f492371e15574482b3641735a6d89` passed the full CI workflow;
the failed prior job log is retained.
- Review follow-up: mutating the Rust backend’s actual Grok descriptor
field left the prior identity unchanged. This regression failed before
binding `acpx_provider_backend.rs` and passes afterward. Profile 7
retains the prior versioned fixture and recovery decoder. All 179
affected Runner checks and 75 focused server pack/manifest checks passed
after this change.
- `pnpm test:run` hit the recorded embedded PostgreSQL bootstrap failure
after five attempts. The full run also exposed a current-release fixture
with the historical Grok digest; it now reads the current profile. Its
11 focused manifest tests now pass. The failed local run log is
retained; final exact-head CI passed.
- The same filtered-context Docker build that failed CI now passes
locally after adding its required source fixture.
- A separate probe used the built sidecar in a private HOME with no
credentials. It admitted the current profile and the new Grok fields,
then returned the closed working-directory rejection before provider
launch or inference.
- A historical parser probe reproduced the pre-effort sidecar rejection.
These probes establish the contract boundary; they do not establish
native subscription task acceptance.
- Initial restricted local ownership tests failed because loopback
listeners were denied. The same tests passed with loopback access. One
new dispatcher fixture first lacked required instructions; the completed
request passed. These setup failures are retained in local evidence.
- Live native task acceptance remains pending deployment. Earlier
deployed attempts failed before tool output. No successful native shell
proof is claimed.

- Final exact-head merge gate: all 62 contexts are clean (57 success,
four intentional skips, one informational neutral formal review).
Greptile and Paperclip reviews are both 5/5, with no unresolved
actionable threads. The formal review uses the existing report-only
neutral policy.

## Risks

- The first fresh Grok run after upgrade may need to stage the current
provider pack. Matching current profiles keep their existing reuse path.
- Fresh admission rejects older Grok profile identities. Historical
decoding and exact reattachment authority remain separate; this change
does not reinterpret an old identity or replace an active session's
pack.
- Future changes to bound source require a new Grok profile attestation.
The build gate fails if the checked-in identity is stale.
- Model, effort, search, credential, approval, and retry policy are
unchanged.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-28 07:15:13 -05:00
DottaandPaperclip 38d08847b8 fix(runner): keep OpenRouter upstream keys in the parent proxy (#17949)
## Thinking Path

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

## Linked Issues or Issue Description

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

**Paperclip version or commit**

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

**Deployment mode**

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 20:57:19 -05:00
DottaandPaperclip 0d22e27dc4 fix(runner): preserve closed native startup diagnostics (#17962)
## Thinking Path

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

## Linked Issues or Issue Description

Refs #17922 and #17942.

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

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

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

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

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

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

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

## What Changed

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

## Verification

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

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

## Risks

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

## Model Used

OpenAI Codex, GPT-6. The exact serving model ID and context window are
not exposed in this session. The agent used reasoning, code editing,
shell tools, and browser tools.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 17:53:58 -05:00
DottaandPaperclip 0a08d37aa0 feat(runner): recover controller authority without interrupting execution (#17097)
## Thinking Path

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

## Linked Issues or Issue Description

**What existing behavior does this improve?**

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

**Current behavior**

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

**Proposed behavior**

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

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

## What Changed

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

## Verification

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

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 17:10:32 -05:00
DottaandPaperclip f60ac29cf1 fix(runner): migrate Grok Build with native reasoning effort (#17922)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Harness selection maps supported agents to Paperclip Runner.
> - The native Runner already supports Grok Build, but its migration
mapping excludes Grok.
> - Grok agents also have a thinking-effort setting that the native
execution contract does not carry.
> - This pull request adds the migration path and preserves explicit
Grok effort through startup and resume.
> - Operators can upgrade an existing Grok agent without silently losing
its model, account, or effort.

## Linked Issues or Issue Description

**What happened?**

Existing Grok Build agents have no Runner selector or upgrade action.
Adding only the mapping would route conversion through the Codex
fallback and lose Grok execution semantics. Native execution also
ignores the legacy reasoning-effort field.

**Expected behavior**

A qualified Grok agent can explicitly upgrade. The saved model, account,
instructions, history, and supported effort remain intact. Unsupported
legacy settings fail before saving. The provider must acknowledge the
selected effort before inference.

**Steps to reproduce**

1. Open the runtime page of an existing Grok Build agent on a qualified
Linux x64 or macOS ARM64 computer.
2. Observe that the Runner selector and upgrade action are absent.
3. Compare the native execution input with the saved legacy
reasoning-effort setting.

Related work: #13882 introduced native Grok Build. #15422 covers the
earlier default-runner work. This change extends the current shared
selection contract.

## What Changed

- Add the Grok harness mapping, qualified platform limits, upgrade
action, and company-scoped computer qualification.
- Translate Grok settings to ACPX without changing the selected account
or explicit model. Resolve the legacy default model to the native
default. Preserve the effective legacy search policy. Reject
incompatible command, argument, permission, and turn-limit settings.
- Add native execution input v10 for explicit Grok effort and search
policy. Preserve historical schemas. Enforce disabled search through
Grok requirements and bind it across startup and recovery.
- Apply and verify ACP `reasoning_effort` before prompting. Bind the
value to provider descriptors, checkpoints, runtime identity, and resume
checks.
- Use the Grok catalog and effort choices in the task composer. Apply
task model and effort overrides while retaining the agent account and
search policy. Update runtime controls, portability/default handling,
documentation, and capability maps.
- Advance Pi and Copilot source attestations for changed shared
transport and recovery code. Keep historical identities intact and
update all Rust integration fixtures.

## Verification

- Migration and review regressions were reproduced before the fixes.
Coverage includes the Grok mapping, default model, explicit effort,
implicit search policy, task overrides, and incompatible legacy
settings. The broad migration, route, immutable-input, and composer
check passed 478 tests. The final catalog and task-input check passed
135 tests.
- Runner startup, recovery, search policy, and profile checks passed 361
tests, with one platform skip. The final source-identity,
search-admission, and transport event-pump check passed 89 tests.
- All 757 Rust workspace tests passed for the broad implementation.
After the final source attestation update, all 55 ACPX profile/session
tests passed.
- `pnpm -r typecheck` and `pnpm build` passed for the implementation.
Server and Runner typecheck passed after the final production change.
Server `tsc --noEmit` passed after the final test-fixture change. Docker
context integrity, token gates, maps, generated protocol data, and
replay goldens passed.
- The v10 startup fixture initially used an ambient local Grok login and
failed on CI. An explicitly empty credential home reproduced all four
failures. The fixture now supplies a synthetic key and a private empty
home. A separate case checks that missing credentials fail closed. All
seven selected Grok v10 and Claude v9 startup cases pass without host
credentials.
- The full local suite could not complete because embedded PostgreSQL
failed before database-backed fixture setup. The broad executor-suite
attempt hit the same limit and was stopped. Neither attempt is counted
as passing. Current-head CI must verify those paths before merge.
- Earlier CI found missing Rust input fields, stale source attestations
and exact fixture pins, a missing Docker context entry, and an outdated
import expectation. Those failures were fixed and checked locally. The
CI logs retain the original failures.
- Different earlier CI runs also failed unchanged cleanup pagination,
device-login timeout, and chat lost-response recovery cases. Later
attempts passed the cleanup and login cases without changes to those
implementations. Their causes remain unproven. The original evidence
remains in [the first
run](https://github.com/paperclipai/paperclip/actions/runs/40563402840),
[the login
run](https://github.com/paperclipai/paperclip/actions/runs/40571128328),
and [the chat
run](https://github.com/paperclipai/paperclip/actions/runs/40573072163).
A passing retry does not establish a root-cause fix.
- Both reviews rate current head
`16fba9b4cdf12bc7945e6628912e79da42959f35` 5/5. All current-head CI
gates pass in [run
40576580699](https://github.com/paperclipai/paperclip/actions/runs/40576580699).
All 60 check runs completed cleanly, including the four intentional
skips and the neutral 5/5 Paperclip review. The legacy security status
is successful. No review threads remain unresolved.
- Staging migration and a real shell task are pending deployment. This
PR does not claim full Grok provider qualification. Reviewers can verify
the operator path by upgrading a qualified Grok agent, checking its
saved model and effort, and running a shell task through native
execution.

## Risks

- Explicit effort and search policy require the matching Runner and
sidecar build. Older immutable execution inputs keep their existing
schemas.
- Providers that omit or reject the selected effort fail before a
prompt. Unsupported effort does not fall back silently.
- Existing agents retain their saved runner until an explicit change.
New Grok agents use native execution only on qualified platforms.
- Grok token and cost reporting remain unverified, as before.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 15:28:42 -05:00
3cd3af5d75 Trace native preparation and OpenCode execution phases (#17918)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each native run prepares its workspace and skills, then starts its
provider.
> - A long preparation span does not show whether inventory refresh, a
cache lock, repository reads, or file checks caused the delay.
> - One hosted run spent 81 seconds in this phase. The same deployed
service and pinned files took 2.55 seconds in a separate diagnostic
process.
> - Another hosted turn spent 69 seconds before its first output. A
matched public-workspace local model replay took 7.64 seconds.
> - We need skill preparation and provider-internal measurements before
choosing another fix.
> - This pull request adds skill spans, a real-service benchmark, and
opt-in filtered provider timing.
> - The benefit is a faster and more precise diagnosis loop.

## Linked Issues or Issue Description

Refs #17620. That PR owns the batched read optimization. This PR adds
diagnostics and does not change its read policy.
Refs #17907. That PR protects long cache lock transactions from the
database idle timeout.

**What happened?**

Native skill configuration can take much longer than matched standalone
resolution. Provider execution also has long gaps with no internal
timings. Existing spans cannot separate inventory refresh, cache
acquisition, repository reads, context loading, Git snapshots, or model
streaming.

**Expected behavior**

An operator-configured trace shows these phases under the existing run
context. Without an OTLP endpoint, the new spans stay off. A local
benchmark can reproduce the service path with real PostgreSQL, files, an
agent actor, and a responsible user.

**Steps to reproduce**

1. Run `pnpm --filter @paperclipai/server exec tsx
scripts/benchmark-native-skill-preparation.ts --actor=agent
--staging-shape=true`.
2. Inspect cold and warm phase timings, SQL counts, and file
verification results.
3. Set the existing operator OTLP configuration and add
`--export-otlp=true` to inspect the same hierarchy in the collector.

## What Changed

- Add bounded skill inventory, refresh wait, cache acquisition, row,
version, repository, file check, and consumer spans.
- Keep the existing endpoint gate, attribute allowlist, cache locks,
authorization, file validation, and durable pin boundary.
- Add a standalone benchmark with a full repository fixture, immutable
snapshot input, calibrated local transport delay, and optional OTLP
export.
- Verify every delivered file and executable bit outside the timed
section. Create its fixture agent through the lifecycle API.
- Add an opt-in authenticated loopback sink for OpenCode. Discard raw
attributes, logs and content. Retain only closed phase names and
timestamps.
- Carry one bounded diagnostic batch through the real proxy, Rust
normalization, durable journal and server trace projection. Group
provider phases under their execution parent.
- Freeze the Date clock in an existing delegated Slack rate-limit test.
This fixes a CI failure when consecutive requests cross a rate-window
boundary. It does not change rate-limit behavior.
- Document phase boundaries and the difference between SDK startup and
confirmed ingestion.

## Verification

- Skill service, runtime selection, concurrency, cache and timing
suites: 122 tests passed with real PostgreSQL and migrations.
Enabled-span integration tests also passed. They verify parent
relationships and a real advisory-lock timeout.
- A captured 208-file repository produced 209 verified runtime files.
The benchmark uses real agent and responsible-user authorization. The
lifecycle fixture correction passed with the staging-shaped inventory.
- Affected OpenCode driver, collector and transport tests: 72 passed.
The tests cover authentication, content removal, size/count bounds,
disabled behavior and the rebuilt native Runner boundary. One Rust
projection test and 18 server trace tests also passed. A held run-log
sink proves that a full 128-span diagnostic batch adds no duplicate
database writes before terminal consumption.
- The two CI-failing delegated Slack rate-limit cases passed against
real PostgreSQL with only the Date clock frozen.
- Runner TypeScript and server TypeScript checks passed. Rust formatting
and module-boundary checks passed.
- Real Honeycomb readback confirmed the 14-span skill waterfall and a
40-span provider waterfall. Provider phases have the correct execution
parent. The provider export uses synthetic model replies and is
instrumentation proof only.
- Earlier full local checks failed on missing package-local executables,
then on the default Node heap and a missing generated service worker.
The dependency links were repaired. The server check passed with a
larger heap. The full local test attempt could not start embedded
PostgreSQL on this host and was stopped after retaining its failures;
real database coverage uses an isolated database on an existing local
server. These attempts do not count as a full local pass.
- CI on the prior revision passed typecheck, build, Runner and all E2E
shards. It failed the benchmark lifecycle boundary and one existing
rate-window test. Those fixes passed CI. A later Runner assertion
exposed the Copilot source identity pin on the shared transport file.
The diagnostic flag now uses the existing configured-environment
projection, preserving that file byte-for-byte. All 66 selected
installation and native transport tests passed. New-head CI and review
remain required.
- The under-15-second hosted response target remains unmet. This PR adds
diagnostics and does not claim a hosted latency fix.

## Risks

- Skill spans and Honeycomb export retain the operator endpoint gate.
OpenCode phase collection requires a separate explicit diagnostic flag.
Without an endpoint, its closed measurements stay in the instance run
log.
- Raw OpenCode OTLP can contain prompts and authorization attributes.
The new sink rejects unauthenticated requests and discards all
attributes before any measurement reaches PRP or the operator collector.
Request, event and per-phase limits bound memory and journal growth.
- Collection does not wait for a provider flush. Late or oversized
exports can be absent; these measurements are not a complete profiling
guarantee.
- The benchmark's inventory contents and transport delay are explicit
fixtures. They do not reproduce server contention or prove hosted
response time.
- The one durable diagnostic batch remains the local evidence. Its child
span export does not add per-phase run-log rows.
- No database migration, authorization policy, model selection or
inference transport changes. The Rust Runner and OpenCode proxy must be
shipped together for the new opt-in diagnostic.

## Model Used

OpenAI GPT-6 through Codex, with repository inspection, shell execution,
browser tools, and Honeycomb queries. The session does not expose a
verifiable backend deployment ID or context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Paperclip <paperclip@paperclip.ing>
2026-10-27 14:53:32 -05:00
DottaandPaperclip db70c5acd9 fix(runner): retain startup Stop and exhaust reconnect recovery (#17812)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators must be able to stop a remote runner while it starts.
> - Remote artifact staging can finish after the transport's bounded
cleanup wait.
> - The launcher discarded an early Stop request and could dispatch
after staging.
> - A separate path missed the runner's plain-text reconnect expiry
receipt.
> - This change retains startup cancellation and ends an exhausted
reconnect incident.
> - Public package imports and a source-bound profile keep the
regressions buildable and admission checks intact.

## Linked Issues or Issue Description

Related work: Refs #16835, Refs #16843, Refs #16855.

**What happened?**

The HTTP Stop route returned 200 and recorded a cancelled run. After
bounded bootstrap cleanup, releasing artifact staging still dispatched
one launch RPC. A separate reconnect test accepted a replacement after
the runner reported that its grace period had expired.

The first PR head also failed CI. The HTTP regression imported Runner
source across the server TypeScript boundary. Its event receipt mock
read a field that is not present on both event forms. The changed
transport also invalidated the pinned Copilot source identity.

**Expected behavior**

A cancelled launch must remain cancelled after staging. An exhausted
reconnect receipt must end that incident. Regression tests must use
public package contracts. The source identity must cover the changed
transport without replacing historical profile bytes.

**Steps to reproduce**

1. Hold the remote launcher's artifact staging promise.
2. Call the board Stop route and let bootstrap cleanup reach its
preparation deadline.
3. Release staging and count launch RPCs.
4. For reconnect expiry, end an owned runner with its coded or
plain-text expiry message.
5. Run the server typecheck and the Copilot profile identity check.

## What Changed

- Retain cancellation through staging, trace publication and an
in-flight launch RPC.
- Apply a deferred signal through the existing identity checks when the
launch identity arrives.
- Preserve an earlier KILL request when a later TERM request arrives.
- Recognize both coded and plain-text reconnect expiry receipts.
- Test the real board Stop route and heartbeat cancellation with
PostgreSQL. Use public Runner exports and handle both event receipt
forms.
- Generate source-bound Copilot profile v65 after integrating current
master. Preserve exact published v62, v63 and v64 fixtures, retain the
earlier v63 reconnect candidate as historical evidence, and reject
historical profiles for a current launch.
- Document process evidence, retained uncertainty and the limits of
cleanup and continuation evidence.

## Verification

- At current integration head
`2b96ee3adcb3be642c538436113e1159d92f843d`, launcher and HTTP Stop
regressions: 21 passed. This includes the existing process-generation
and exact-exit safety cases on the integrated base. The HTTP case
includes bootstrap expiry; it is not isolated Stop-only settlement
proof.
- At current integration head, reconnect expiry regressions: 2 passed,
for coded and plain-text receipts.
- At current integration head
`2b96ee3adcb3be642c538436113e1159d92f843d`, the Copilot installation and
identity suite passed all 63 tests and the canonical generator check
passed. Before regeneration, the merged-tree admission test failed with
a transport source hash mismatch and the generator reported a stale
identity. Published v62, v63 and v64 bytes remain unchanged; the prior
reconnect candidate is preserved separately. The v62 fixture SHA-256
remains
`faa4d1b35267b54e134a8e0c84586fe1196d8fad5525cb53aa195aae53ca6e83`.
- Current integration head passed all 86 focused tests, the full
recursive repository typecheck and the root repository build. The normal
server typecheck also passed, including its full Runner release rebuild.
- Historical full recursive repository typecheck and the root repository
build passed at `187bb85b4fa1fbd2ffaec992650a1c8557df9ebe`. Server
typecheck also passed through the normal package script and a direct
full server TypeScript check. The prerequisite full Runner release build
passed.
- The historical HTTP baseline returned 200 and dispatched one late
launch RPC. The repair returned 200 and dispatched zero in the bounded
fixture.
- Earlier failures remain part of the evidence: the first head failed
TypeScript package boundaries and source identity. One local HTTP run
failed before migrations; it passed after the disposable test database
received normal migrations. Earlier sandbox-wide checks ran out of
memory or lacked Cargo. Those runs did not pass.
- Historical head `187bb85b4fa1fbd2ffaec992650a1c8557df9ebe` received
Greptile 5/5 with no actionable findings and all hosted gates passed in
run `40412261957`: 53 successful check runs, four expected skips and a
successful legacy Snyk status. Those results predate the master
integration and do not establish current-head readiness.
- Current integration head `2b96ee3adcb3be642c538436113e1159d92f843d`
includes master `bd382eee536f4ada680072b1cc19100163c3d04a`. All
current-head hosted gates passed in run `40512885858`: 53 successful
check runs, four expected skips and a successful legacy Snyk status,
with zero pending or failed checks. Build passed at 13:42:36 UTC and the
final `ci / verify` aggregate (job `122224566238`) passed at 13:43:00
UTC on 2026-10-27. Greptile reviewed exact head
`2b96ee3adcb3be642c538436113e1159d92f843d` at 5/5 (updated 2026-10-27
13:36:41 UTC), with no actionable findings and no open inline threads.
The hosted partitions passed full-suite verification, including browser
and release gates. The wider qualification limits below remain in force.
- Local setup on current master initially failed frozen install with
`ERR_PNPM_LOCKFILE_CONFIG_MISMATCH` because `patchedDependencies`
differs from the lockfile. Pinned pnpm 9.15.4 hydrated dependencies with
`--no-frozen-lockfile --ignore-scripts`; its generated lockfile change
was restored. This PR changes no lockfile or workflow.
- Reproduce the Stop tests from `server`: `pnpm exec vitest run
src/services/native-runtime/native-session-executor.test.ts -t 'remote
runner process supervision|HTTP Stop during remote runner staging'`. The
test accepts a guarded disposable `_test` database through
`PAPERCLIP_TEST_DATABASE_URL`, or starts its normal embedded database.
- Reproduce reconnect tests from `packages/paperclip-runner`: `pnpm exec
vitest run src/live/runnerd-codex-transport.test.ts -t 'does not restart
an exhausted reconnect'`. Build the normal test runner first.
- Reproduce profile checks from `packages/paperclip-runner`: `node
scripts/copilot-profile-identity.mjs --check` and `pnpm exec vitest run
src/drivers/acpx/copilot-installation.test.ts`.

## Risks

- The wider qualification is incomplete. Verified-stopped replacement
and concurrent recovery plus Stop each entered two physical provider
processes. Both fail the original requirement of at most one physical
provider entry. Passing fixture assertions do not make all incident
scenarios accepted.
- HTTP concurrent recovery, shared provider-attempt accounting,
server-admitted restored continuation, live-provider behavior and
product cleanup settlement remain unrun or unproved.
- Accepting a deferred signal is not proof that a dispatched process
stopped. The existing monitor remains authoritative.
- The HTTP test uses the real route, heartbeat cancellation and
PostgreSQL state. Execution lease and event ports, plus the launch RPC,
are controlled fixtures. Bootstrap expiry participates in this case.
- The local incident matrix uses an installed runner binary and a
scripted provider. It does not qualify a live provider. Local fixture
teardown does not certify product cleanup settlement.
- This change does not authorize historical turn replay. It does not
change ownership, pause, approval or provider-attempt gates.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose the exact
serving model ID or context-window size. The agent used reasoning,
repository inspection, shell execution and connected GitHub tools.

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

**Subsystem affected**

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

**Problem or motivation**

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

**Proposed solution**

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

**Roadmap alignment**

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

## What Changed

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

## Verification

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

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

## Thinking Path

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

## Linked Issues or Issue Description

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

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

## What Changed

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

## Verification

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

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

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-26 21:39:04 +00:00
DottaandPaperclip 125ddcabe5 perf(runner): keep event journal writes off the HTTP thread (#17745)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

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

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

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 09:01:24 -05:00
Nicky Leach 2cd6eb27c7 fix(runner): record the plugin-prepared working directory (#17243) 2026-10-22 20:42:26 -07:00
Nicky LeachandPaperclip 0081863463 Fix isolated ACPX admission for assigned PRP tools (#17149)
## Thinking Path

- Paperclip uses Runner to execute agent tasks under Core's selected
policy.
- The ACPX sidecar can receive assigned MCP tools in its PRP catalog.
- Isolated admission still requires a separate native MCP endpoint for
those assignments.
- This check rejects a valid PRP route before the provider can start.
- This PR identifies the sidecar's PRP transport at the runtime-host
boundary.
- The benefit is that assigned tools work with the existing isolated
permission policy.

## Linked Issues or Issue Description

**What happened?**

An isolated Claude task with an assigned MCP binding fails with
`assigned native MCP launch binding is unavailable` when Core delivers
its tools through PRP.

**Expected behavior**

The sidecar must accept its authenticated PRP tool bridge as the
assigned-tool route. Callers that use the native gateway must still
supply its complete binding.

**Steps to reproduce**

1. Open an isolated Claude sidecar session with `deny-all` permissions
and a read-only policy.
2. Supply an assigned MCP binding in the runtime context and its tools
in the PRP catalog.
3. Omit native gateway environment variables. Admission fails before
provider startup.

**Paperclip version or commit**

Reproduced against `92cfd701c39bb1ea394a796023481a21decb2532`.

**Deployment mode**

Runner with an ACPX sidecar and controller-owned tool delivery. Related
contract work: #16978. The search found no existing PR or issue for this
failure.

## What Changed

- Let runtime-host callers select PRP delivery when they supply the
semantic tool bridge.
- Select that route in the sidecar. Keep native gateway validation and
direct callers' default behavior.
- Preserve exact controller operation names in PRP mode, including the
compact assigned-MCP catalog. Keep existing aliases for other bridge
callers.
- Preserve the selected permission and read-only policies.
- Add one process-level sidecar regression and one host admission
regression. The host test calls the real authenticated MCP bridge.
- Document the route and refresh the generated Copilot source hashes.
The provider and profile versions stay the same.

## Verification

- Passed 11 focused tests after the rebase across the runtime host,
sidecar, tool bridge, and Copilot identity tests. They cover both
compact catalog operations, restricted and approve-all policies, legacy
aliases, missing and invalid gateway bindings, and the existing direct
gateway path.
- The process-level test crosses the real sidecar dispatcher and stops
at workspace validation before provider startup. The host test uses real
ownership sockets and MCP HTTP, with a fake provider port.
- The generated identity tests match the current source hashes. The
historical fixture stays unchanged.
- The standard review passed on the rebased commit. [Apex passed the
required 5/5
threshold](https://github.com/paperclipai/paperclip/runs/119513362214)
on `e63a223`, with 11 files reviewed and no findings.
- Rebased onto master `734c265`. The conflicts affected generated source
identities and their test expectations. All reviewed behavior files
remain byte-for-byte unchanged. The user authorized retaining the Apex
result for this rebase. [CI passed on
`3facef5`](https://github.com/paperclipai/paperclip/actions/runs/39685163239).
The final PR checks contain 56 passes and four expected skips. The
branch is current with master, has no conflicts, and has no unresolved
review comments.
- `node packages/paperclip-runner/scripts/copilot-profile-identity.mjs
--check` passed.
- Initial local runs exposed missing test dependencies and sandbox
denial of loopback sockets. After the scoped dependency install and
socket permission, the selected tests passed.
- Broad typecheck, build, and test verification runs in GitHub CI, as
requested. No live provider or model request was made.

## Risks

- PRP callers must supply the assigned tools in the controller-owned
catalog. The existing bridge still enforces its closed catalog and
authentication.
- An explicit PRP selection without a semantic bridge still fails.
Invalid native gateway bindings still fail.
- No database, protocol-frame, provider-version, or credential-storage
change is required.

## Model Used

OpenAI GPT-6 through Codex, with source inspection, editing, and command
execution. The exact served model ID and context-window size are not
exposed in this session.

## Checklist

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

> - Paperclip manages AI agents and their work.
> - Users choose a harness during agent setup.
> - Claude, Codex, and OpenCode already receive their qualified Runner
default.
> - Pi has a qualified native integration but new Pi agents still use
the direct adapter.
> - This change gives new Pi agents the native default on supported
targets.
> - Saved agents keep their runner and compatible settings. Legacy
remains available in Advanced.

## Linked Issues or Issue Description

Refs #17120, #14921, #14922, #14923, #14924, and #14956. Related generic
default work: #15422. This PR is the separate Pi follow-up to the merged
OpenCode change.

**Current behavior**

Choosing Pi for a new agent saves the direct Pi adapter. The native Pi
integration remains behind the generic experimental flag.

**Proposed behavior**

Default new Pi agents to ACPX Pi on macOS ARM64/x64 and GNU/Linux x64
with supported glibc. Keep unsupported targets and explicit Legacy
selections on the direct adapter. Require an explicit provider/model
before test or hire. Permit model-free inactive setup drafts.

**Reason and benefit**

Users choose Pi once and receive its qualified runner. Saved agents
retain their identity and settings. Conversions reject unsupported
legacy thinking and launch settings instead of dropping them.

## What Changed

- Add Pi to the shared platform/default contract and server creation
selection.
- Admit native Pi without the generic experimental flag.
- Preserve provider models, credentials, workspace settings, exact
thinking, and saved native policies.
- Add Pi runner controls, branding, setup resume, onboarding, built-in
configuration, and import handling.
- Add managed Pi OpenRouter routing and matching native provider API-key
accounts. Keep subscription and custom gateway exclusions. Clear
alternate credentials and reject custom Pi provider overrides.
- Keep Pi draft models empty instead of applying Claude's default model.
- Verify setup against the pinned Pi runtime. For native Pi on the
official OpenRouter route, reverify the API key live without requiring a
global Legacy Pi CLI.
- Match Pi’s bounded controller close window to its native snapshot
cleanup and lifetime verification, preserving explicit caller deadlines
and the mandatory drain/suspension proof.
- Bind Pi sidecars to the package that owns the pinned native assets,
including source and vendored server layouts. Other providers retain
their existing package authority.
- Keep protocol-owned finish/block tools out of the ACPX forwarded
catalog. The trusted bridge installs these tools itself; the complete
Rust authorization catalog and terminal receipt ledger remain intact.
This fixes actual Pi session startup and applies to other ACPX
consumers.
- Advance Copilot’s shared-source attestation to v58 because it pins the
shared files touched by Pi. Preserve immutable v57 bytes and historical
decoding; Pi’s own release identity is unchanged.
- Add regression coverage and update the paired maps and developer
documentation.

## Verification

- Passed: full repository typecheck and full production build on final
head 656d304783, including the generated attestation repair.
- Passed: focused shared/server/UI suites covering default selection,
platform fallback, conversion preservation, inactive drafts, managed
account compatibility, credential isolation, OpenRouter routing/model
IDs, exact thinking controls, and saved-account selection. Relevant
batches include 375 server/conversion tests, 267 account/routing tests,
and 110 UI setup/account tests.
- Passed: 179 attestation, historical-profile, qualified-profile, and
native-execution contract tests after CI identified stale Copilot source
hashes. The identity generator check passes; the only delta after the
passing Pi browser run is this Copilot attestation/history repair.
- Passed: 145 managed-account tests, including actual service
preparation and API-key adoption/rejection for native Pi without the
Legacy CLI; 6 pinned-installation probe tests.
- Red then green: an actual task failed session.open because its
54-operation catalog included the bridge-owned terminal tools. The
regression with those tools failed before the filter; all 399 Rust
library tests pass after it. The full product retry exposed an
additional package-authority mismatch. Four authority tests failed
before that repair; 11 authority checks and 14 installation/asset checks
pass afterward. Direct real Pi session initialization with the corrected
package root and catalog succeeds. No model prompt was sent by that
diagnostic.
- Red then green: real Pi posted Hello from Pi but its controller closed
before native cleanup could finish. The cleanup-budget test failed with
the old default and passes with the bounded Pi window. All 46 selected
suspension, drain, and package-authority tests pass after building their
native fixture.
- Passed: token gates, paired map checks, Rust formatting, and git diff
--check.
- Passed real browser acceptance on macOS ARM64, generic native runner
flag disabled, source a433748a12 (Pi code unchanged afterward): the UI
selects Paperclip Runner by default, retains Pi and the selected
model/account, and verifies the pinned runtime plus live OpenRouter key.
A fresh UI-created task, assigned to the UI-created native Pi agent,
posted exactly `Hello from Pi` and reached Done without retry or
restart. The native run and workspace finalization succeeded; the
response and Done persisted after Reload.
- Evidence: 8 preserved browser attempts, including the final passing
18-step journey with all screenshots. Prior failures remain recorded.
The earlier failed checkpoint run recovered on server restart; that
recovery is separate from the fresh final task’s clean success.
- Preserved browser failures: missing account control/inherited Claude
draft model; incompatible managed-account/model-prefix handling; generic
npm probe for Pi; Legacy CLI hello check; duplicate terminal tools and
wrong provider-package authority at actual native session.open; a real
Hello from Pi comment followed by premature checkpoint cleanup timeout.
Each failure has retained screenshots/logs and a corresponding focused
repair. The fresh final task proves these repairs end to end.
- The exact Runner Vitest shard was also run locally after the
attestation fix: the stale-hash failure is gone; 1,833 tests passed, 10
skipped, and two Codex retained-control settlement scenarios failed with
`native_cleanup_maintenance_unproven` during terminal ACK/suspension
replay. Both scenarios passed in an isolated rerun (2/2), and the same
19-test file passed in the preceding Linux CI run. The precise
full-shard timing cause is not established. These Codex scenarios are
outside the changed Pi paths; the original local failures are retained;
no complete local Runner-shard pass is claimed. The corresponding Runner
shard now passes on the final head in hosted Linux CI. All 60 final-head
check runs are now terminal and clean (55 successful, 1 neutral, 4
skipped), and the legacy Snyk status is successful.
- Local full repository tests were attempted but not completed:
provisioning briefly confused a workspace symlink, then a later run was
stopped before browser-driven repairs. No full local-suite pass is
claimed. Final-head hosted CI is green and fresh Greptile review is 5/5
with all review threads resolved; earlier jobs canceled by runner
shutdown are not counted as a pass.

## Risks

- Pi cleanup has a finite 45-second default window, accounting for the
native 30-second snapshot cleanup and 5-second lifetime fence. Other
providers and explicit caller deadlines retain their prior behavior.
- Pi requires explicit operator setup with `paperclipai runtime setup
pi` on the execution host. This PR does not add automatic downloads.
- Linux ARM64, Windows, musl, and unqualified targets retain Legacy.
- Legacy thinking levels minimal, medium, and xhigh cannot be translated
exactly. Native max thinking, warm lifecycle, or restricted permissions
cannot be dropped during a return to Legacy.
- Copilot’s bound profile advances to v58 with exact current launch
admission; v57 remains decodable for recovery. No historical identity is
rewritten.
- Existing agents and immutable run descriptors are not migrated. Cloud
Pi availability is unchanged.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-21 17:10:00 -05:00
DottaandPaperclip 0a5f1546ee feat(cases): add reusable prompt workflows (#17114)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Cases keep facts, documents, and one primary task across agent
handoffs.
> - Each case currently needs its own procedure text.
> - Agents need to reuse procedures and move cases between them without
replacing the task.
> - This change adds company workflow definitions with a name and
Markdown prompt.
> - Existing handoff and document transactions preserve authority,
revisions, and recovery.
> - Cases remain behind `experimental.enableCases`.

## Linked Issues or Issue Description

Refs #16959. Related proposal: #3951 uses task graphs and a visual
editor. This change extends existing Cases with prompt definitions and
keeps its current handoff model.

**Problem or motivation**

Agents cannot share a reusable procedure across cases or inspect a
case's movement between procedures.

**Proposed solution**

Add name-and-prompt workflow definitions. Adopt a prompt into the
primary task's revisioned workflow document through a handoff. Keep
phases as free text.

**Alternatives considered**

Defer graphs, workflow versions, run entities, role schemas, authoring
screens, and Spec Kit integration.

**Roadmap alignment**

This extends the existing Cases experiment and same-task review flow. It
adds no work queue or new execution engine. The maintainer approved this
scope in the implementation plan.

## What Changed

- Add company-scoped definition storage, shared request schemas, REST
routes, and four optional Cases tools.
- Accept a workflow ID at kickoff. Agent handoffs can adopt, refresh,
preserve, or detach a workflow.
- Capture prompt text and the document base revision at acceptance.
Apply workflow, phase, and document revision together after outgoing
execution settles.
- Hold conflicting document edits for recovery. Preserve cancellation,
replay, and restart behavior.
- Show current workflow names and captured transition names/phases in
Work, history, and Audit.
- Update instructions, API/tool contracts, capability maps, and the
isolated workflow journey.
- Pin bounded workflow prompt reads to a content fingerprint;
continuation conflicts on edits and can restart safely.
- Remove experimental Cases/workflow/Mermaid guidance from the always-on
native prompt. Extract runtime-context prompt strings into a
CODEOWNERS-protected constants file while preserving the public imports.
- Refresh Copilot’s pinned source identity to v57, including the
extracted prompt file and retaining historical identities.

## Verification

Local checks: repository `pnpm -r typecheck` and `pnpm build` pass on
the prompt-extraction tree (`88222d45d8`). Full repository coverage
previously completed through the supported isolated shard groups (1,082
general server suites, 161 serialized suites, and all three workspace
groups). The earlier default serial run was interrupted and remains
incomplete. The first sharded run retained the failures described below;
targeted corrections and separate limited-concurrency reruns pass. All
CI jobs, security checks, and the 5/5 Greptile review passed on
`fc1bd79c28`. Fresh CI and review are pending for the prompt extraction
in `88222d45d8`. Focused verification passes: real-database handoff
recovery and reuse; 2,002 native-tool/API contract checks; 144 Runner
catalog/discovery checks; 27 Runner context/coverage checks; 37
case/Audit UI checks; and Product E2E oracle calibration. Token gates,
migration safety/numbering, module boundaries, capability maps, and
generated tool/Storybook catalogs pass. The final route/context
corrections pass 49 API/native-tool tests, 90 real-database handoff
tests, and server typecheck; 142 Copilot installation/sidecar tests pass
with the refreshed identity.

Greptile’s first review found that successive prompt pages could mix
definitions after an edit. The fix returns a content fingerprint,
requires it for continuation, and rejects edits with 409. Strict
live/catalog schemas pass (171 Runner checks). The 2,005 API/OpenAPI
tests pass; the initial native regression caught compression’s weak ETag
prefix, and all 23 native integration tests pass after handling it. The
regression covers same-length edits and a four-byte restart window. No
stored version fields or entities were added.

The prompt extraction passes all 462 checks across six focused suites,
including persisted-context recovery and provider transport. The first
local transport attempt lacked the required debug Runner binaries (102
failures, retained); after building the normal prerequisites, all 283
tests in that suite pass without source or assertion changes. Existing
saved snapshots retain their recorded prompt text, and new executions
use core-only prompt v7. The extracted prompt source is now covered by
both CODEOWNERS and Copilot’s source fingerprint.

Live-provider evidence is separate from those simulated checks: the
isolated API-key campaign `reusable-workflows-api-final-2026-10-21`
passed with local code matching `a1d73b4652`. Four actual Codex API runs
read the adopted task documents, moved one case A → B → A on the same
task, completed normally, and passed all nine durable checks. Browser
assertions verified the current workflow/phase, historical names/phases,
five handoff records including terminal completion, and the completed
original task. Cleanup passed. The local report remains under
`tests/runner-e2e/results/reusable-workflows-api-final-2026-10-21/`; no
credentials or screenshots are committed.

CI initially caught an omitted route-inventory entry and a stale pinned
instruction-source hash; both are corrected and separately verified.
Local serialized coverage also recorded an unrelated environment-route
socket disconnect and activity-route timeout; their separate 11-test and
17-test suites passed without code or timeout changes. An unchanged
chunked-webhook check also passed its separate four-test rerun. The
initial adapter/database workspace groups hit time and resource limits
under default worker counts; complete reruns with `VITEST_MAX_WORKERS=2`
pass, including all 55 database files and 211 tests. The UI/CLI groups
passed 837 files and 9,442 tests in the original run. Original failures
remain retained and are not regraded.

Earlier failed live campaigns remain unchanged: subscription HTTP 429
before agent execution; an obsolete exact-four-row oracle that rejected
the valid terminal fifth row; and a chat-marker expectation that did not
account for the existing explicit-comment presentation policy. The final
fixture requires terminal completion and places the marker in its
authoritative comment. Positive/negative oracle tests and the fresh live
campaign pass.

## Risks

- The additive migration adds a table and nullable case/handoff fields.
Existing rows keep null workflow metadata; no assignments are inferred.
- Adoption can wait on an intervening task-document edit. Recovery must
cancel the old intent and accept a new one after readback.
- Shared definition edits affect future adoptions. Existing case copies
keep their revisions.
- The feature remains experimental. This PR does not merge or deploy the
change.
- Live acceptance covers native Codex before the prompt extraction; this
cleanup has contract/transport verification rather than a new
live-provider campaign. The refreshed Copilot identity has static
compatibility evidence, not new live-provider qualification.

## Model Used

OpenAI Codex, configured model ID `gpt-6-astra`, xhigh reasoning. Used
terminal execution, file editing, and tool calls. The active
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
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-21 15:00:12 -05:00
eece07a747 fix: repair the complete projectless repository setup chain (#17088)
## Thinking Path

> - Paperclip lets people manage agents that do useful work.
> - A projectless task can prepare an authorized repository in its
retained workspace.
> - Setup must hand work to a later run without user supervision.
> - Real task attempts exposed gaps across admission, completion, and
queue dispatch.
> - A successful provider exit did not prove that the requested result
was delivered.
> - This PR repairs the existing lifecycle and checks the complete
repository journey.

## Linked Issues or Issue Description

Refs #17047. This PR includes the preserved repairs from #17049, #17052,
and #17082.

**What happened?**

A projectless native task could stop after requesting a repository. It
could also continue through a timer or generic recovery path and lose
its saved conversation lineage. The latest real Codex and Claude
attempts delivered correct files, but the native continuation had been
folded into the finishing predecessor. Both attempts remain failed
measurements.

**Expected behavior**

Prepare the authorized repository, retain the original context, and
dispatch one saved continuation after its predecessor finishes. Deliver
the verified result in the originating conversation. Stop, current
access, approval, and real blocker rules remain authoritative.

**Steps to reproduce**

Run the explicit automatic-repository suite for native Codex or Claude.
Inspect the downloaded result, original context artifact, both committed
run records, and continuation receipts. The suite uses one attempt and
does not widen the default paid selection.

## What Changed

- Resolve the retained local-board identity through current company
membership and workspace authority.
- Prepare required source dependencies before the isolated server
imports native tool authority.
- Explain the saved repository continuation in production completion
tools. Correct only the exact pending-checkout blocker backed by a live
receipt. Reject an unfinished response wait without a real response
source.
- Preserve the persisted task-session workspace source and its explicit
absence of root repository context. Permit Git's exact no-repository
result only for a validated plain task directory. Keep other Git errors
and linked metadata strict.
- Revalidate server-resolved same-agent continuation values against
current ownership and the saved kind, summary, and key. Carry this shape
through the internal bridge schema. Keep provider-facing schemas
restrictive.
- Preserve terminal result authority after a correlated successful
controller response. Controller rejection creates no result authority.
Bind the shared guidance and transport source in Copilot v55 and
preserve historical identities.
- Admit native status wakes with the existing no-coalescing contract.
The existing deferred queue retains a distinct future dispatch instead
of retagging the finishing run.
- Recover deferred conversation lineage through the actual admitted
dispatch. Accept a null outbox run binding only with matching decision,
effect, dispatch actor, idempotency, task, company, agent, and requester
evidence. Reject a conflicting nonnull binding.
- Independently grade retained random context, actual checkout bytes and
HEAD, accessible output, distinct continuation receipts, and admission
order.

## Verification

- Real database and Git regressions fail before their repairs. Prior
focused cohorts cover local-board authority, optional repository waits,
plain task directories, and first/reused workspace provenance.
- The new valid decision/effect-backed assembled-heartbeat regression
reproduces coalescing into its active predecessor before the queue
repair. With the repair, it dispatches one successor after the
predecessor finishes. Duplicate sweeps create no extra run.
- The deferred-outbox conversation regression fails before its repair.
The repaired test also rejects a conflicting predecessor binding.
- The current queue, continuation, publication, cancellation,
stale-admission, and domain cohort passes 344 checks across 11 suites.
Server and Product E2E typechecks pass. The strengthened
automatic-repository oracle passes 34 calibration checks.
- Three omitted/null/resolved forms pass through the compiled Rust
runner and controlled provider. The prior shared bridge cohort passes
492 TypeScript checks and 399 Rust core checks. Runner source identity,
TypeScript, Rust formatting, and locked Rust typechecks pass.
- Six real local development cells passed ordinary repository,
conversion, and necessary-question journeys. Independent artifacts and
rendered question/result evidence agree. They do not qualify staging or
Slack.
- Both latest automatic-repository attempts delivered correct files but
failed the strict continuation check. They remain failures. A fresh
replay of this queue repair is pending.
- On the combined candidate `380047f4b923807a8c4f7ef6016e4fe130ab4a3a`,
`pnpm -r typecheck` and `pnpm build` pass. Product E2E support passes
3,525 checks with two existing skips, plus 128 source checks. The
complete local `pnpm test:run` is running and is not yet a pass.
- The first replay selection failed catalog validation due to an
operator profile-ID error. A second selection used the wrong
default-model suite and was cancelled before any provider job existed.
Both setup attempts remain recorded. The corrected campaign selects the
recorded GPT-6.1 and Opus 5.5 models plus the local Stop/resume journey.
- Exact-head CI, review, and deployment acceptance remain pending.
GitHub reports delayed PR updates and webhook delivery; the current head
and checks have now propagated. No earlier-head green badge establishes
acceptance of this commit.

## Risks

This changes several boundaries of repository setup. Full product and
deployment acceptance remain required. The queue uses the existing
deferred admission and delivery contracts. Batch deduplication remains
in place. The provenance repair requires the actual bound dispatch and
does not grant publication authority. Current authorization is still
checked at publication. No accepted provider result is rewritten, and
completed provider work is not rerun to repair persistence or delivery.

## Model Used

OpenAI Codex, GPT-6 family, with repository tools and code execution.
The runtime does not expose its exact deployment ID or context-window
size. Those values are not 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Paperclip <paperclip@paperclip.ing>
2026-10-21 11:21:55 -05:00
DottaandPaperclip dff63551fe fix: resume unfinished work after repository preparation (#17047)
## Thinking Path

> - Paperclip manages agents that perform work for a company.
> - Task repositories are prepared at normal run admission.
> - A running native task can stage a repository while its work remains
unfinished.
> - The controller did not offer that saved setup as a continuation.
> - The agent could add a timer or wait for a user restart.
> - This change uses the existing same-agent continuation and status
ledger.
> - The accepted explanation and proven conversation remain available
after setup.

## Linked Issues or Issue Description

Refs #17045. That prerequisite has merged. This PR targets master.

**What happened?**

A projectless native task can request a repository for the next
admission. An unfinished task has no server-selected repository
continuation. An explicit same-agent continuation also loses chat
provenance.

**Expected behavior**

An unfinished standard task can yield and resume through the existing
admission queue. Its explanation and final result retain the authorized
conversation. A task that only stages a repository can complete without
another run.

**Steps to reproduce**

1. Start a native standard task in a task directory.
2. Request an authorized repository through prepare_repository.
3. Yield with unfinished work and no explicit continuation.
4. Observe that the former driver rejects the yield, although the
pending repository is saved.

## What Changed

- Offer a saved same-agent continuation for the current task's pending
repository.
- Accept that current server continuation in the shared provider driver.
- Resolve chat provenance through applied status decisions, delivered
effects, and admitted wakes.
- Preserve accepted setup explanations without repeating an owned
question card.
- Document optional reproduction details and configured repository
discovery.
- Extend database regressions and workspace access maps.
- Preserve Copilot profile v52 and bind the shared continuation source
in v53. Include the active identity in the QA image fingerprint.

## Verification

- Five focused server suites: 100 checks pass.
- Shared continuation driver: 12 checks pass.
- Server typecheck passes.
- Map contract and whitespace checks pass.
- Existing API and driver assertions fail on the former implementation.
- Real dispatcher and queue cohort: 43 checks pass. The original
reply-loss regression fails before the dispatch receipt fix.
- Continuation driver and installation identity cohort: 62 checks pass.
- Regenerated capability inventory and contract checks pass.
- Final response precedence cohort: 109 checks pass. The stale-comment
case fails on the former implementation.
- All required CI checks, build, and both source reviews pass on
b9c8677635.
- Live provider journeys and deployed acceptance remain pending. No live
qualification is claimed.

## Risks

A pending repository now offers a next admission when unfinished
standard work yields. Incorrect eligibility could create unwanted work.
The lookup requires the current workspace and task. Explicit completion
does not use it. Existing Stop, admission, approval, and transport
authorization remain authoritative. No schema or public task-status
change is included. The shared continuation change requires a new
Copilot source identity. This PR preserves v52 history and does not
claim fresh Copilot live qualification.

## Model Used

OpenAI Codex, GPT-6 family, with repository tools and code execution.
The runtime does not expose its exact deployment ID or context-window
size. Those values are not 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>
2026-10-21 07:17:50 -05:00
Nicky LeachandPaperclip e5351b240a Verify native Runner setup through plugin tasks (#17029)
## Thinking Path

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

## Linked Issues or Issue Description

**Subsystem affected**

Runner, plugin SDK, and agent environment tests.

**Problem or motivation**

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

**Proposed solution**

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

**Alternatives considered**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 18:13:09 -07:00
Nicky LeachandPaperclip 2a5a323e57 Add execution-owned Runner launch preparation (#16997)
## Thinking Path

> - Paperclip manages work for AI agents.
> - Runner can execute in a different environment from Core.
> - Core owns provider selection, policy, and resource assignments.
> - The execution environment must prepare its own files and paths.
> - A shared contract must keep these responsibilities separate.
> - This PR adds that contract to the Runner execution driver.

## Linked Issues or Issue Description

**Problem or motivation**
Runner transport prepares provider files on the controller before
launch. An execution owner cannot prepare those files in its own
environment through the existing driver.

**Proposed solution**
Add `prepareLaunch` to the execution driver. Supply versioned Core
requirements. Accept a configuration ID, requirements digest, and
ordinary provider descriptor. Validate Core policy and assignments
before launch. Keep existing provider session checks.

**Alternatives considered**
Provider-specific ownership flags would spread the boundary across
backends. Shell preparation would expose process details in the plugin
API.

Refs #16993, #16977. Both prerequisites are merged. This PR now targets
master. Native plugin integration and execution-host preparation follow
separately.

PR #16978 contains an earlier, unmerged prototype. Its
`persistentAgentHome` mode and skill path-map call will be replaced by
this preparation contract before activation. This PR preserves current
master callers of the skill helper.

## What Changed

- Add the optional preparation callback and an explicit Runner artifact
identity.
- Keep the built-in preparation path as the default.
- Validate provider policy and resource assignment identity. Preserve
instruction text when resource locations change.
- Persist the attachment seed after an authority epoch rotation, so a
later controller restart can recover the same run.
- Preserve explicit context removal on a new run. Only an omitted
context can reuse the saved context. Remove its registered instruction
framing when context is removed.
- Save exact requirements and configurations in a private file outside
Runner commands. Retain the active record across failed attachments. Use
current grants for new runs. Keep incompatible session changes rejected.
- Join delayed preparation during startup and warm attachment cleanup.
Retain an unsettled checkpoint after a timeout. Prevent work after
cancellation.
- Use the supplied Runner artifact for interrupted handoff recovery.
Restore the exact target configuration at each handoff crash boundary.
Check the Runner state when the final ACK may be lost.
- Bind the changed shared sources to Copilot profile v51. Preserve the
v50 receipt and current integrity checks.

## Verification

- Workspace typecheck passed.
- All 487 affected Runner transport, control-plane, preparation store,
builder, policy, and profile tests passed on commit `eaf8ae8d1`.
- Workspace build and typecheck passed again on commit
`eaf8ae8d12c7ef2d22d226e4b3f05fdbf79ef4cb`.
- Both warm attachment cleanup regressions fail before the fix. They
pass after the fix. The tests cover delayed preparation, timeout
retention, and concurrent attachment rejection.
- The routed handoff regression fails with a missing controller binary
before the fix. It passes after the fix. The execution owner launches
the real fixture Runner.
- The 200,000-byte instruction regression fails before the fix and
passes after it. Four prepared handoff crash cases verify exact request
and configuration recovery. The store tests verify private file mode,
conflicting records, corrupt data, and active-run retention.
- A real Runner with a controlled fake provider verifies execution-host
paths, exact recovery, warm reuse, incompatible profile rejection, and
cancellation. It does not contact an external provider.
- The regression found undefined settings in strict PRP command hashing.
Requirements now contain only JSON values. The warm transition test
passes without changing PRP validation.
- The broader root suite on the prerequisite finished with 22,420
passing tests, seven failed tests in unchanged Git and diagnostic code,
and two suite setup errors because Cargo was absent from its PATH. This
PR does not claim a passing full root suite.
- The CI Build job passed compilation and production runtime boot, then
its runner received a shutdown signal during the clean public install
check. Other jobs reported lost communication with their self-hosted
runners. The failed jobs passed on retry on the same commit; successful
jobs kept their results.
- The current Superagent security scan is inconclusive because its
pinned merge-base checkout failed or timed out. GitHub rejected the
check rerun request through the available API. This is not a passing
security scan.
- Standard Greptile and Greptile Apex each returned 5/5 on `eaf8ae8d1`.
All review threads are resolved. CI passed on attempt 2. Current checks
have 55 successes, four optional skips, and the inconclusive security
scan described above. The branch is ready, mergeable, and current with
master.
- No live provider qualification or deployment was run.

## Risks

- A preparation owner must store configurations and keep retries bound
to the same task and requirements.
- Copilot source binding requires a new profile identity. This PR does
not claim fresh live qualification.
- The callback is an SDK extension. This PR does not connect it to a
plugin task process owner or add a Launcher endpoint.

## Model Used

- OpenAI Codex, GPT-6. Reasoning and repository tools. The exact serving
model identifier and context size are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 14:24:13 -07:00
Nicky LeachandPaperclip 05f7079ecb Extract Runner provider launch preparation (#16977)
## Thinking Path

> - Paperclip manages work for AI agents.
> - Runner starts providers in local and remote environments.
> - Core selects the provider and task policy.
> - The execution environment supplies paths and installed files.
> - The transport currently combines these inputs in one large method.
> - This PR extracts provider descriptor construction before a separate
plugin preparation change.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Runner provider launch preparation.

**Current behavior**
The PRP transport constructs each provider descriptor inside startup.
This couples provider configuration to transport lifecycle code.

**Proposed behavior**
The transport calls one built-in descriptor builder. The builder takes
Core provider requirements and execution-environment locations as
separate inputs. File staging, provider validation logic, and session
rules keep their current behavior. The required Copilot source-identity
update changes profile admission metadata.

**Reason and benefit**
This gives launch preparation a separate unit of code. A later PR can
add plugin-owned preparation without adding ownership flags to each
provider backend.

Refs #15406, #16486. This replaces the earlier installed-home
implementation in this PR. #16978 remains a draft.

## What Changed

- Extract provider descriptor construction and its existing permission
helpers.
- Keep helper exports at their previous import path.
- Add focused tests for selection, permissions, locations, and managed
profile rejection.
- Update the Copilot source identity. Bind the extracted file and retain
the v49 history. The source attestation requires v50 after this move.
This changes the admitted profile identity even though no execution
behavior changes are intended.
- Document the boundary and its current limits.

## Verification

- 338 focused builder, transport, Codex security, and Copilot identity
tests passed on the rebased head.
- `pnpm -r typecheck` passed. `pnpm build` passed.
- The full root `pnpm test:run` on the pre-rebase head is still in
progress. It has reported five failures in unchanged server tests. One
isolated failure rejects the word `private` from this checkout's
`/private/tmp` stack path. The full root suite is not reported as
passing.
- All 56 CI checks passed on the rebased head. Four optional checks were
skipped. The branch is mergeable. Workspace typecheck and build passed
on this head.
- Standard Greptile and Apex each scored commit
`47f631883d8f417f6a818500ebe4e77e22cc70b8` 5/5. The rebase onto master
changed only Copilot identity metadata, history handling, and related
tests. `git range-diff` confirms that the launch-preparation
implementation is unchanged. The existing Apex result remains the review
evidence; it did not review the new commit hash.
- No live provider calls or Cloud deployment were run.

## Risks

- A moved field could change provider startup. Existing transport tests
and the new boundary tests check the projection.
- Copilot source binding requires a new identity after the move.
Existing artifacts and retained sessions must match the new admitted
profile. This PR does not claim fresh live qualification.
- This PR does not enable plugin-owned preparation. File materialization
remains in the existing SDK path.

## Model Used

- OpenAI Codex, GPT-6. Reasoning and repository tools. The exact serving
model identifier and context size are not exposed in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 11:20:49 -07:00
DottaandPaperclip 505e1a5582 feat(cases): add persistent workflows with same-task agent handoffs (#16959)
## Thinking Path

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

## Linked Issues or Issue Description

**Problem or motivation**

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

**Proposed solution**

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

**Alternatives considered**

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

**Roadmap alignment**

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

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

## What Changed

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

## Verification

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

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

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

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

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

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

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

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

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

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

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

Preserved CI failures and retries:

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


## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 12:46:14 -05:00
DottaandPaperclip df80616d98 Preserve Copilot historical runtime attestations (#15703)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Runner recovery must distinguish old profile identities from the
current launch identity.
> - The long integration produced historical attestations that must
remain inspectable after consolidation.
> - The release must preserve saved-token access and task lifecycle
guarantees.
> - This pull request will retain the historical Copilot profile records
without granting old profiles launch access.
> - The benefit is a reviewable part of the Copilot production release.

## Linked Issues or Issue Description

Refs #15701. Supersedes the provenance work in #15561. Base: #15701.
Next: #15705.

## What Changed

- Retain historical Copilot profile attestations as separate immutable
records.
- Preserve the mainline and candidate histories when version numbers
overlap.
- Keep exact current-profile launch checks in the runtime PR.

## Verification

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

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

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

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

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

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

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

## Risks

Historical records are evidence only. They must not be treated as
current qualification or as permission to launch an old provider
profile.

## Model Used

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

## Checklist

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

---------

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

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

## Linked Issues or Issue Description

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

## What Changed

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

## Verification

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

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

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 06:31:47 -05:00
DottaandPaperclip ac9459bae3 feat: configure company agent observability (#16874)
## Thinking Path

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

## Linked Issues or Issue Description

**Subsystem affected**

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

**Problem or motivation**

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

**Proposed solution**

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

**Alternatives considered**

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

**Roadmap alignment**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 15:36:04 -05:00
DottaandPaperclip 06d4fe3121 perf(runner): preload essential Claude task tools (#16885)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Runner exposes assigned tools to Claude through an authenticated
MCP bridge.
> - Claude can defer these tools and search for them before a simple
task can finish.
> - Title and terminal tools are common requirements for a task turn.
> - This pull request marks those three tools for immediate loading by
Claude.
> - The remaining tools keep the SDK deferral policy and the existing
access checks.

## Linked Issues or Issue Description

Refs #15993, #15994, #15997.

**What existing behavior does this improve?**
Claude Runner tool discovery during task execution.

**Current behavior**
Claude can use ToolSearch to discover the mandatory title and terminal
tools before it answers a simple task.

**Proposed behavior**
Expose `set_task_title`, `paperclip_finish`, and `paperclip_block` in
the first Claude request through per-tool `anthropic/alwaysLoad`
metadata. Keep other tools deferred under the SDK policy.

**Reason and benefit**
Remove an avoidable tool discovery step without changing the model,
effort, or authorization. Repeated product measurements will check the
latency benefit.

## What Changed

- Add closed metadata for the three essential tools only in Claude
runtime hosts.
- Keep incoming metadata discarded and private tools hidden. Keep other
providers unchanged.
- Test real bridge catalogs and provider routing. Check the pinned
Claude SDK request against a loopback fixture with no paid calls.
- Advance the pending Copilot source binding because it attests the
shared bridge file. Preserve historical profile readers and
qualification limits.

## Verification

- Focused bridge, admission, profile, and effort controls: 185 passed,
one skipped. Three provider-routing cases pass.
- Runner TypeScript compilation passes.
- The production SDK fixture loads exactly three essential tools with
the change and zero in the controlled baseline. The document tool stays
deferred.
- Six real API-key tasks used Opus 5.5 / High in alternating order A B B
A A B. Median first assistant receipt was 22.021 s baseline vs 17.060 s
candidate (22.5% lower). Median total was 24.119 s vs 19.150 s (20.6%
lower). ToolSearch was 3/3 baseline vs 0/3 candidate. All six tasks
saved a title and accepted finish. A separate candidate follow-up
resumed the same provider session and finished without ToolSearch.
- Median startup was 4.786 s baseline vs 5.381 s candidate. This change
does not improve startup. Three samples per version give directional
evidence only.
- Estimated cost for the six tasks was $0.850900800. Candidate total was
$0.450341800 vs baseline $0.400559000; the first candidate wrote a new
cache prefix. These rate-card estimates are not invoices.
- The benchmark used source `5aed3c6a083cf8e6246815455abde3b29ecbbbac`.
Rebuilding both bundles at master-reconciled head
`d2da07259048c0a2bebd210c35cc0ebb3ff42c67` produced identical SHA-256
values. Baseline bundle SHA-256:
`10a92c373bba4fb630bf4fefeab953d850a77cf8258bc2e94711410a73a78ecd`.
Candidate:
`40348fc67a3b1ae5cc1f27f933f369981d31bcdf5d1bdc7b1797968ddfe53938`.
Baseline differs only by compiling the Claude preload selector as false.
Fresh task sessions avoid checkpoint changes.
- Full local runtime-host runs exposed credential lease collisions in
existing cases. A later complete host run passed 67 cases and timed out
in an existing admission-abort case; that case passes in isolation. All
failures are retained. Focused controls pass. Complete Runner suites,
repository typecheck, tests, browser checks, and build pass in cloud CI
on this head.

## Risks

- These three tool schemas add input to Claude requests. Measurements
must include token usage and cost.
- Copilot source identity changes because it includes the bridge source
hash. It remains pending qualification. Its catalog and executable
closure do not change.
- The test fixture proves request shape. It does not prove real-provider
latency or platform package qualification.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 14:29:22 -05:00
DottaandPaperclip 95672307f4 feat(runner): carry acknowledged Claude effort through native resume (#15994)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The native runner must carry each supported agent setting.
> - Claude effort must reach its ACP session before a prompt and after
resume.
> - Installed Claude setup must find the owning server package without a
qualification override.
> - This PR adds those shared contracts and preserves historical
readers.
> - The Claude default change can then use the same runner path.

## Linked Issues or Issue Description

Refs #15683. This prerequisite follows the actual Codex squash
`adb69e8f09852c772d9901ae270e5b2d66e39c77`. Consumers: #15993 and
#15997. Related scope: #15422, #13978 and #15224.

## What Changed

- Add native-input v9 for Claude effort. Preserve v1–v8 readers,
including v7 explicit home modes, v8 Muse, Dot and Grok Bot.
- Preserve prepared task input and constraints through the newer
contracts, including completion-only continuation without wrapping
compact model input again.
- Carry effort through daemon/sidecar admission; require provider
acknowledgment before prompting and after resume.
- Find installed server package authority through the verified canonical
layout. Retain package-integrity, digest, architecture and no-follow
checks.
- Return Claude startup cancellation promptly while retaining unfinished
settings writes and the lifetime lease through cleanup. Preserve merged
Codex close/cleanup behavior.
- Retain both independently authored historical Pi profile-24
declarations. Combined master/Claude source attestations use Pi profile
27; pending Copilot remains profile 22. This does not expand either
provider's qualification boundary.

- Avoid a spare verified executable snapshot when Claude effort control
reuses its initialized provider. Preserve cold-control snapshot renewal
and acknowledged effort.

## Verification

- Reconciled with master `9179d8dcc3e908c217fde4f63c9d08ccf8132eeb`,
retaining its task-loading, progress, skill-retention, permission and
OpenRouter changes.
- Final focused protocol/provider checks passed 155 tests (one skipped),
the updated Pi attestation check passed 18 (one skipped), and 91
evaluation/catalog checks passed. Generated TypeScript/Rust profile
checks and Rust formatting pass. The integrated consumer's
TypeScript-only runtime build also passes.
- Earlier branch checks passed 369 protocol tests (one skipped), 72
catalog checks and TypeScript checks/build; their source identities
remain historical. No Rust compilation or Docker build is needed locally
for this proof.
- Current-head cloud CI is green. All three stack PRs have fresh
Greptile 5/5 reviews and zero unresolved review threads. Required
typecheck, test and build gates ran in cloud CI; Docker work stayed
remote. Earlier failed checks remain in their original runs.
- [Earlier four-target package
qualification](https://github.com/paperclipai/paperclip/actions/runs/39267321383)
passed on source `04e0202ca81387b17cbe7fd094a8338648356fe9`; it is not
relabeled as proof for the final merge. Existing failures and
unknown-cost holds remain preserved.
- Current-head cloud CI is green. All three stack PRs have fresh
Greptile 5/5 reviews and zero unresolved review threads. Required
typecheck, test and build gates ran in cloud CI; Docker work stayed
remote. Earlier failed checks remain in their original runs.

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

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

## Risks

- Explicit Claude effort needs a daemon and sidecar that support input
v9. Historical readers stay available; downstream builders and
permission-pin transport checks must also use v9.
- Source-bound profile changes may require reopening older Pi/Copilot
sessions. Copilot remains pending and executable package closures remain
unchanged.
- This prerequisite changes shared runtime behavior; Claude default
selection remains in #15993/#15997. No database migration or Codex
default change is introduced.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-19 13:31:09 -05:00
DottaandPaperclip 3858d2341d fix(recovery): default saved-monitor waits and keep task recovery quiet (#16686)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - A task must keep a durable path to its next action.
> - A provider can save a task monitor, then fail to yield because it
omits internal continuation fields.
> - An interrupted provider-pack check can then be reported as permanent
artifact incompatibility.
> - The task asks its user to certify recovered workspace files, even
though this is an operator responsibility.
> - This pull request derives the saved monitor continuation, bounds
verification retries, and removes that task form.
> - Normal recovery stays quiet. Unresolved holds retain inspection and
the existing safety checks.

## Linked Issues or Issue Description

**What happened?**

A yielded completion without `continuation` is rejected even after the
provider saves an eligible monitor on the task. Repeated attempts cannot
finish. Remote verification also treats timeouts and missing exit status
as artifact incompatibility. The task recovery notice exposes raw
diagnostics and asks the task user to certify infrastructure files.

**Expected behavior**

Use current persisted task state to fill routine continuation fields.
Retry interrupted verification reads within a fixed bound. Keep normal
recovery in the working state. Show a compact notice only when work
cannot safely continue.

**Steps to reproduce**

1. Save an eligible monitor on the active task.
2. Call `paperclip_finish` with `reportedWorkDisposition: "yielded"` and
omit `continuation`.
3. Return a timed-out remote provider-pack command with empty stderr
during recovery. Inspect the resulting task notice.

**Paperclip version or commit**

Source baseline: `aaeff418cf` (master integrated with its current task
visibility and saved-source reconstruction rules).

Related changes: #15824, #16104, #16451, #16493, #16690. This fix
complements saved-result recovery and verified pack reuse. It does not
replace their workspace ownership checks.

## What Changed

- Allow omitted or null continuation at the provider input boundary.
Read current authorized task context and fill a monitor continuation
only for the bound run and an eligible saved monitor. Keep accepted
results strict. Apply this to Codex, OpenCode, both direct and
production-sidecar ACPX paths, and external drivers. Reserve the
semantic call identity during the saved-context read and reject
cancellation or a changed run/turn.
- Bind the shared completion change and continuation helper in a new
Copilot v21 source declaration. Preserve v20 history and its decoder
support. Qualification stays pending.
- Expose the eligible continuation in task context. Completion admission
still checks persisted monitor state. No schedule is created or renewed
by the default.
- Retry read-only provider verification at most twice per command. Hold
exhausted reads with a distinct verification-unavailable cause.
Reattachment cannot renew the read budget through an unchanged
provider-attempt counter. Keep completed verification failures and wrong
versions incompatible.
- Remove the task file-certification form. Hide the notice only for a
matching durable recovery path without an unknown-action replay hold.
Keep missed retries, unsafe outcomes, and unresolved file holds visible.
- Add production-component stories for automatic recovery, blocked and
expired holds, reader access, persisted repair decisions, source
reconstruction, queued continuation, and mobile. Preserve master’s
guarded saved-source reconstruction choice after confirmed source
destruction. Update the execution contract and access maps.

## Verification

- Completion, helper, Codex, OpenCode, ACPX, and profile regressions
pass. After the sidecar review fix, 271 tests across the production
sidecar and three provider suites pass, plus 72 helper/profile tests.
The real sidecar MCP bridge tests cover saved-monitor acceptance,
no-monitor refusal, cancellation, duplicate call identity, and
raw-versus-forwarded semantic receipt hashes. The OpenCode tests also
cover eligible-monitor acceptance and refusal without one.
- The fresh full native executor suite passes all 743 tests. Four
profile, installation-integrity, and ACPX driver suites pass all 168
tests. The earlier CI fingerprint failure required a new immutable
source declaration; its follow-up Docker failure required the matching
context allowlist entry. Both fixes are verified locally. Targeted
server monitor, tool authority, and provider verification suites pass.
The probe tests include a real timed-out subprocess, an unrelated
responsive timer, transport errors, and completed integrity rejections.
- All 90 tests in the merged task notice, reconstruction choice,
recovery display, and lineage suites pass. They cover reader access,
live/missed/mismatched recovery, unknown outcomes, saved messages, retry
refusal, and removal of the file form. Both review findings have
failing-baseline/passing-treatment regressions: identical polling across
retry expiry, and a failed refresh after cached running activity.
- Browser walkthrough passed for automatic recovery, unresolved details,
a 390px mobile story, and the merged saved-source reconstruction and
queued states. The reconstruction control starts disabled and normal
automatic recovery shows only Working. The stories use production
components and fixture API data. They do not prove live cloud recovery.
- Token gates, map checks, and Storybook catalog generation pass. The
exact Docker context integrity command passes locally after adding the
new build declaration to its allowlist.
- Workspace typecheck and build pass on the final source, including the
versioned identity update. The final server and UI guards pass their
focused tests, typechecks, builds, and token gates. The final standalone
Storybook builds. The saved-monitor default retains master’s stricter
child-task visibility filter. Re-review caught an additional
production-sidecar validator before forwarding; the fix now defaults at
that boundary and has passing regression controls. After preserving
master’s new reconstruction capability, 68 targeted reconstruction,
tool-authority, and provider-verification server tests pass. The
current-master integration at `2a80050a0d` has a fresh 5/5 review with
zero unresolved threads. Its complete CI matrix, including Runner tests,
is the merge acceptance record.
- On the final master integration, local typecheck, build, and all 90
recovery UI tests pass. A concurrent runner run hit five 5-second
sidecar startup timeouts; an isolated sidecar run passed 86 tests and
timed out in the unrelated unsupported-bootstrap case. Those local
deadline failures remain recorded; the canonical CI Runner lanes use
their normal deadlines and pass. The unsharded local full-suite attempt
did not complete. It spanned source edits; the fresh native executor run
above passes. An unrelated workspace fixture timed out once and then
failed to reserve 32 contiguous ports on this host. Its unchanged-base
control and CI server suite pass. Full-suite acceptance uses the fresh
latest-head CI matrix; this PR does not claim a passing unsharded local
run.

## Risks

The default applies only to an eligible persisted monitor. An explicit
invalid continuation still fails validation. The added read occurs only
when a yielded report omits its continuation. Admission rechecks current
state after that read.

An interrupted verification command can add one extra 30-second probe.
Completed rejections stay closed. These probes do not change the pack,
launch provider work, or replay external tools. Two inconclusive reads
hold the original run. They do not schedule another reattachment with an
unchanged provider-attempt counter.

This PR’s pending Copilot v21 declaration binds the changed shared
contract, resolver, direct driver, and production sidecar sources. The
previous v20 declaration is immutable and remains decodable, but launch
requires the new exact identity. Qualification remains pending.

Task users lose the file-certification form. Board-authorized
source-only repair remains available through the resolution API with the
original evidence and stop-receipt requirements. This branch does not
deploy or recover historical held runs.

> This is a bug fix and UI polish within existing recovery behavior.
ROADMAP.md was checked.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, xhigh reasoning, with tool use 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 (changed-area suites; the
full local run limitation is recorded above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-18 21:43:15 -05:00
Dotta cfa9dce295 refactor(runner): remove unreferenced Paperclip Runner test fixtures (#16543)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Paperclip Runner package keeps fake agent servers and versioned
profile identity declarations under `test/fixtures/` for its test
suites.
> - Five of those fixture files have no reference anywhere in the
repository: no test, script, generator, workflow step, or document loads
or spawns them.
> - Dead fixtures add maintenance cost and make the referenced sibling
fixtures harder to trust.
> - This pull request deletes only those five unreferenced fixture files
and adds an audit receipt with the reference evidence.
> - The benefit is a smaller test-fixture surface with zero loss of
executed coverage.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The test-suite hygiene of the Paperclip Runner package. The repository
keeps unused test-support files that no suite loads. This slows audits
and makes the referenced fixtures harder to trust.

**Subsystem affected**

`packages/paperclip-runner` test fixtures.

**Current behavior**

Five files under `packages/paperclip-runner/test/fixtures/` have zero
references anywhere in the repository:

- `fake-native-resume-codex-app-server.mjs` (277 LOC): an old fake codex
app-server for resume testing. Resume coverage now runs through
`fake-final-burst-codex-app-server.mjs` (used by
`server/src/services/native-runtime/native-session-resume.test.ts:287`)
and `fake-durable-codex-app-server.mjs` (used by
`packages/paperclip-runner/src/live/live-session.test.ts:2192`).
- `copilot-profile-v{3,4,5,6}-identity.json` (64 LOC total): orphaned
profile identity declarations. Copilot profile tests,
`native-backend-factory.test.ts`, and
`scripts/generate-acpx-profiles.mjs` reference only v7 through v19 by
literal path. No dynamic `copilot-profile-v${...}` path exists in the
repository (the only template-literal fixture path is
`test-fixtures/pi-acp/profile-v${version}-identity.json`).

**Proposed behavior**

Delete only the five unreferenced fixture files. Keep every referenced
fixture. Keep all registered test cases unchanged.

**Reason and benefit**

Smaller test-fixture surface: 341 test/support lines removed with zero
loss of executed coverage. The audit receipt
`doc/plans/2026-10-16-runner-dead-fixture-test-audit.md` records the
per-file reference evidence.

**Breaking changes**

None. No production code, no registered test case, and no test selection
path changes.

**Additional context**

A repository-wide `git grep` for each removed filename stem returns zero
external references across all tracked file types. The
`hashFiles('packages/paperclip-runner/test/fixtures/**')` occurrences in
the workflows are Rust cache-key inputs, not execution selectors;
deleting files only changes that cache hash.

## What Changed

- Deleted
`packages/paperclip-runner/test/fixtures/fake-native-resume-codex-app-server.mjs`.
- Deleted
`packages/paperclip-runner/test/fixtures/copilot-profile-v{3,4,5,6}-identity.json`.
- Added the audit receipt
`doc/plans/2026-10-16-runner-dead-fixture-test-audit.md` with per-file
reference evidence.
- 341 test/support lines removed. Zero production, documentation, or
registered test-case changes.

## Verification

- Repo-wide `git grep -i` for each removed filename stem
(`fake-native-resume`, `native-resume-codex`, `copilot-profile-v3` …
`copilot-profile-v6`) across all tracked file types returns zero
external references.
- Selection audit: `packages/paperclip-runner/vitest.config.ts` includes
only `src/**`, `devtools/**`, `examples/**`, and two named
`scripts/*.test.mjs`; the server project selects `server/src/**` and
`server/scripts/**`; the `test:typescript:prep` `node --test` list names
no fixture. No workflow executes anything under `test/fixtures/` — the
`pr-trusted.yml`/`release-verify.yml`
`hashFiles('packages/paperclip-runner/test/fixtures/**')` occurrences
are Rust cache-key inputs, not execution selectors.
- Rust tests use their own `fake-codex-app-server` binary in
`runner/crates/runner-core`, not these `.mjs` fixtures.
- Searched open and merged PRs for each filename: zero overlap (`gh
search prs`).
- Repo-wide `pnpm -r typecheck`, `pnpm test:run`, and `pnpm build` were
not run this session: the removed files are unreferenced, absent from
every vitest/node-test include pattern, and excluded from all tsconfigs,
so no compiled or executed path changes. No runtime CI savings are
claimed.
- All Paperclip CI gates green on head `ce24ab3` (verified 2026-10-16
~09:00Z): every `ci /` shard (General tests, e2e shards, serialized
server suites, Verify Paperclip Runner rust/vitest/static, Build,
Typecheck + Release Registry, policy, Docker context integrity, Canary
Dry Run, gate), `review`, `Superagent Security Scan`, `Socket Security`
PR alerts + project report, and `Contributor trust` all pass; the only
skipped jobs are the Storybook deploy/visual-regression jobs, which are
not required for this change. Greptile Review: 5/5 confidence, "Low
impact", no actionable issues, last reviewed commit `ce24ab3`.

## Risks

Low risk. No executed coverage or selection path changes. The only side
effect is a one-time change to the `hashFiles` Rust cache key that lists
`test/fixtures/**`, which simply invalidates that cache on the next CI
run.

## Model Used

Zhipu `z-ai/glm-5.3` (GLM), served through OpenRouter, running as the
Paperclip Test Gardener agent. Context window size unavailable to the
agent. Capabilities used: shell tooling, git, GitHub CLI search, and
file inspection; no image or code execution capabilities were used.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] 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-17 21:18:11 -05:00
DottaandPaperclip 2cc7992369 Share the external Runner lifecycle and add strict Muse contracts (#16444)
Add the external Runner foundation with distinct Dot/Grok V6, canonical home-mode V7 and Muse V8 contracts.

Keep generated schemas and profiles synchronized. Bound default question-answer command IDs in a disjoint namespace while preserving existing IDs and durable replay. Preserve canonical migration history and add normally generated, replay-safe Muse schema milestones with literal preview-history fixtures.

Refs #16444.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-16 13:46:50 -05:00
Nicky LeachandPaperclip ec3eb1968b feat(runner): expose credential updates through PRP (#16463)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Runner uses PRP to send harness events to the host.
> - A harness can replace its stored OAuth tokens during a run.
> - The host has no PRP signal that tells it to read the updated
credential.
> - This pull request adds a durable credential update event and
observers for supported stores.
> - The host can react before it acknowledges the event. Token values
stay outside PRP.

## Linked Issues or Issue Description

**Subsystem affected**

`packages/paperclip-runner`: native provider execution, PRP schemas, and
host event delivery.

**Problem or motivation**

A Paperclip host that consumes PRP needs to react when a harness changes
its refresh-token credential. Existing credential copy-back paths do not
provide a common event during a warm session.

**Proposed solution**

Add `auth.credentials.updated` as a P0 runner event. Include only the
provider, binding ID, revision, and detection method. Observe native
Codex and Codex/Grok ACPX credential files. Retain each pending event
across runner restart until the durable outbox accepts it. Raw PRP
consumers opt in with `observeCredentials: true` before session open.
The bundled transport opts in for fresh sessions.

**Alternatives considered**

`harness.diagnostic` would mix a runner observation with harness
diagnostics. Sending token values through PRP would expose credentials
to event logs. Both approaches are unnecessary.

**Roadmap alignment**

I checked `ROADMAP.md`. This change extends the existing Runner protocol
and does not duplicate a planned core feature.

**Additional context**

Refs: #11094, #14056, #12696. These describe credential copy-back and
staging work. This PR adds the notification contract. It does not
replace those private credential channels or claim to fix their full
scope.

## What Changed

- Add strict credential update payload validation to PRP v1, v2, and v3.
Regenerate validators, the manifest, and the event catalog.
- Watch supported credential directories with `notify`. Add a periodic
read as a fallback and check at terminal and close boundaries.
- Persist a private baseline and pending event together. Notify on
account identity changes and retain the new baseline for later
refreshes. Ignore incomplete files, unsafe files, and metadata changes.
- Forward the event through the host transport. Test commit-before-ACK
delivery and replay.
- Commit pending runner observations before suspend and shutdown
commands complete. Preserve the provider event backlog.
- Create the private ACPX runtime directory before configuring
observation. Cover fresh session startup with observation enabled.
- Fence asynchronous PRP commits to the current authenticated connection
and run authority. Ignore replaced callbacks while preserving the
maintenance drain of admitted work.
- Deliver observations found during final provider cleanup before
clearing terminal recovery state. Retain the outbox and recovery state
when the host ACK is lost.
- Advance the pending Copilot candidate profile to v19 for the changed
shared PRP source hashes. Preserve its v18 history and pending
qualification status. Include the current fixture in the Docker build
context.
- Commit credential updates through an awaited host callback before PRP
ACK, including during idle and close. Persist them in a separate run-log
source namespace with company, agent, session, and runner checks.
- Preserve public event metadata through server redaction. Register the
event in task run details.
- Document opt-in behavior, supported stores, event semantics, and the
local run-log path.

## Verification

- All 45 durable runner control tests and 24 native executor integration
tests pass.
- Ten Rust credential observer tests pass. They cover atomic
replacement, polling, recovery, account-only changes and later refreshes
for Codex and Grok, unsafe files, fresh runtime creation, and the Grok
close handoff. Account identity stays private.
- The full Runner TypeScript suite passes: 3,565 tests in 221 files. An
additional 12 tests are skipped by the suite.
- All 214 focused tests pass for the contract, Codex event routing,
catalog, and durable host delivery.
- All 13 Node protocol contract tests pass.
- The exact Docker context integrity command passes: `docker buildx
build --file .github/docker-context-checks.Dockerfile .`.
- Rust formatting and generated protocol checks pass.
- `pnpm -r typecheck` and `pnpm build` pass. The full local `pnpm
test:run` was attempted with CI-compatible `init.defaultBranch=master`,
then stopped after a reproducible failure outside this change:
`git-workspace-expiration.test.ts` expects one re-expired workspace but
gets zero. The same case fails in isolation on this macOS checkout. Full
repository validation is provided by CI; the focused Runner and host
tests pass locally.
- All 253 native transport and restart tests pass against the final
release binary.
- All 3 durable recovery tests and 139 candidate profile and native
admission tests pass.
- All 41 host redaction and task protocol surface tests pass. `pnpm
check:token-gates` passes.
- All 467 CI policy tests pass, including the 15 CI profiling tests. The
upstream secret-reference test fix is retained from master. No workflow
changes are included.

- The Apex host-delivery fix passes 381 targeted Runner tests, six host
database tests, repository typecheck, and the production build. The
Runner tests cover commit-before-ACK, retry after a rejected host
commit, warm attachment, and close after the turn queue ends.
- Prior head `2f125cfcb` passed CI, standard Greptile 5/5, and Apex 5/5.
One CI shard was interrupted by GitHub runner shutdown; its single rerun
passed. Both Apex findings are addressed: idle/cleanup host delivery and
late callback reconnect fencing. Current head `5db78f082` passes CI (56
successful statuses and four optional skips) and standard Greptile 5/5.
Apex review of the account-change update is 5/5 on this exact head, with
no actionable issues.
- All 121 durable control-plane and credential callback tests pass,
including account-only change delivery, subsequent refresh on the new
account during close, host commit retry, late success/failure races,
forward cursor delivery on a replacement connection, and the existing
maintenance retirement contract. All 27 native provider and durable
recovery integration tests pass after the account-change update.

## Risks

- File changes signal a stored credential update. They do not prove that
an OAuth refresh succeeded. Changes between reads can be combined.
- Unix Codex and Codex/Grok ACPX stores are supported. Other harnesses
and credentials held only in memory need their own integration.
- Hosts must update their event schemas before opting in. Older hosts
omit the flag and receive no new event. Older runners ignore the flag.
- The host must use its existing private credential channel and account
checks to read or copy the token. Account switches trigger notification
but do not authorize accepting the new account. The event grants no
credential access.
- Tests use synthetic credentials. No live OAuth refresh has been
forced.

## Model Used

OpenAI Codex, exact model ID `gpt-6.1-sol`, with high reasoning effort,
repository inspection, tool use, and code execution. The session does
not expose its 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-15 14:49:00 -07:00
DottaandPaperclip 8843887c24 fix(runner): preserve managed GitHub access in OpenCode (#16488)
## Thinking Path

> - Paperclip manages AI agents and their authorized connections.
> - Native OpenCode agents use managed Git and GitHub launchers for
shell work.
> - Each operation must obtain credentials from the active run's broker.
> - Two OpenCode environment filters dropped that broker binding before
the shell started.
> - The shell therefore ran anonymously even when connector tools had
authorized access.
> - This pull request preserves the explicit broker environment through
both filters.
> - The benefit is working GitHub shell access with current identity and
revocation checks.

## Linked Issues or Issue Description

**What happened?**

Native OpenCode shell commands reported `GitHub capability_missing`
despite an authorized GitHub connection. Both runner startup and
provider startup dropped the controller's broker settings. Connector MCP
calls used a separate path and could still succeed.

**Expected behavior**

A managed shell operation obtains credentials for the current run. A
later operation uses the new identity after rotation and loses access
after revocation. Ambient host credentials do not supply authority.

**Steps to reproduce**

1. Start the native GitHub broker with an active run binding.
2. Pass its environment through native OpenCode startup.
3. Run `gh api user` from the provider shell.
4. Observe anonymous access before this fix.

**Paperclip version or commit**

Reproduced on master `6943904bad` before this change.

**Deployment mode**

Native Paperclip Runner with OpenCode, including remote execution.

Related: #16401 fixes the separate oversized OpenCode SSE failure and is
already merged. The same live-driver regression was verified locally
against its exact pre-fix source and current source. This PR does not
duplicate that fix. Searches found no open PR for this native broker
propagation defect; #15309 concerns the legacy OpenCode adapter.

## What Changed

- Use the existing GitHub credential environment projection at both
OpenCode launch boundaries.
- Preserve explicit controller authority while excluding an ambient host
broker.
- Exercise the real launcher and broker from an OpenCode child process,
directly and through runner projection.
- Check operation-time identity rotation, revocation, and exclusion of
controller API credentials and persistent GitHub tokens.
- Document the managed OpenCode shell contract.

## Verification

- Red: both new `native-github-access.test.ts` cases returned
`anonymous` instead of `fixture-a` before production changes.
- Green: both cases pass after the fix, including `fixture-a` to
`fixture-b` rotation and anonymous operation after revocation.
- Full native GitHub broker suite: 18 tests pass.
- OpenCode, provider-event, and configured-environment suites: 141 tests
pass across eight files.
- Separate SSE red/green verification: the existing live-driver
regression times out on `fd057f6ac4^` and passes with merged #16401. The
full OpenCode group also passes after restoration.
- Full repository build and typecheck pass locally. All CI jobs pass for
`23d734293f6a5c6d6128cae0c8773661816daf9a`. Final GitHub rollup: 55
successful checks/statuses, two skipped checks, and one neutral check;
none pending or failing. Greptile gave that commit 5/5 with no findings
or unresolved threads.
- Paperclip Review spent over 23 minutes preparing its runtime without a
provider assessment. Its run was cancelled for recovery and ended
neutral (review execution did not complete). This neutral result is not
a code assessment. No check policy or branch protection was changed.
- The full local Vitest attempt first hit embedded PostgreSQL startup
failures. Running the unchanged `initdb --version` and `postgres
--version` independently showed missing native library symlinks. The
dependency had been installed with scripts disabled. Running its bundled
`hydrate-symlinks.js` restored startup; all 15 affected native-session
cases and all 112 AI connection tests then passed without application
code changes. The original full-suite attempt was stopped after the
setup failure and its log is retained. A complete local suite pass is
not claimed.
- The broker and executable are local fixtures. No live GitHub account,
credential change, or test PR is required by these regressions.

## Risks

The change affects credential delivery into OpenCode processes. It
reuses the existing bounded GitHub projection and accepts broker
authority only from explicit input. Each shell operation still uses the
normal broker, scope, identity, and revocation rules. Unrelated
controller secrets remain excluded. There are no database or
permission-policy changes.

## Model Used

OpenAI `gpt-6.1-sol`, through Codex, with xhigh reasoning and repository
tools/code execution. The session does not report its context-window
size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run the focused regression and affected suites locally and
they pass; the full local attempt and setup failure are disclosed 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 (Paperclip Review is
neutral/incomplete, as disclosed above)
- [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-15 16:15:38 -05:00
DottaandPaperclip b8ffeb973a feat(runner): add experimental Grok Bot agent participation (#16219)
## Thinking Path

> - Paperclip manages AI agents that perform work for a company.
> - The shared Runner owns task admission, authority, receipts and
finalization.
> - An existing Grok Bot needs to receive assignments and return results
through that Runner.
> - The Bot also needs governed access when it starts work from its own
conversation.
> - This PR adds agent-purpose MCP access and routine webhook dispatch.
> - It reuses the external-agent Rust Runner and keeps Grok capabilities
explicit.
> - The provider stays experimental until the real-client managed
journeys pass.

## Linked Issues or Issue Description

**Agent or provider**
Grok Bot, distinct from the Grok Build coding runtime in #13882.

**Why this adapter is useful**
Users can assign work to an existing Bot, receive progress, questions,
documents and files in Paperclip, and let the Bot initiate work under
its agent permissions.

**How the agent is invoked**
A webhook-only routine delivers bounded references. Dedicated
named-agent OAuth and MCP provide inbound calls. Setup follows [Grok
routines](https://cursor.com/help/grok-bot/routines) and [custom
plugins](https://cursor.com/help/grok-bot/connect-plugins). The current
desktop app needs its Bot-generated Webhook URL navigation link when
routine-row clicks fail.

The GitHub search found related Grok Build runtime work, but no existing
Grok Bot agent provider. This extends the roadmap’s existing agent,
Runner, governance and artifact foundations.

## What Changed

- Add default-off Grok Bot participation through the shared real Rust
external backend, preserving native provider identity guarantees and
distinguishing session closure from remote termination.
- Bind agent OAuth to company, agent, client, gateway and authorizer;
recheck permissions and task-bound execution authority without
manufacturing a native identity.
- Persist routine configuration, dispatch intents, authenticated
acknowledgement and recovery holds. Store URL/key together in encrypted
secret storage, use guarded public egress, and never automatically
replay ambiguous HTTP delivery.
- Reuse native tools, durable waiting, completion assessment and review.
Add task-bound file grants through existing artifact storage; suppress
proactive echo dispatch and synchronous result wake loops.
- Enforce the current native deliverable work-mode policy at file-ticket
issuance and use. Add operator retries for confirmed rejected wakes,
with retained receipts, stable retry intent and current-authority
checks. Recovery locks bindings before routine rows. Thread Stop
resolves the selected run and its agent.
- Cancel queued and preparing Stop targets before assignment creation,
restore saved setup after a failed request and successful retry, and
publish the Grok provider descriptor schema. Advance the versioned
Copilot source declaration for the shared schema change; its
qualification remains pending.
- Filter task summaries with the shared privacy policy, preserve
feedback admission when wake delivery is blocked, reconcile settled
delivery receipts without restoring work authority, and bind every Stop
control to its displayed run. Recovery records distinguish dispatch
uncertainty from a revoked session.
- Add resumable guided setup, credential replacement, consent,
management, observed work status and stop/recovery controls, plus an
interactive Storybook journey using the production task thread, question
form and report card. Grok’s own apps remain available; Paperclip
workspace and third-party tools are deferred.

## Verification

- Five focused protocol, authorization, person MCP and Runner files: 192
tests pass. The Grok assigned-work case executes the actual Rust Runner,
saves a document, uploads/deduplicates a file and reaches ordinary
finalization.
- Proactive intake/deduplication and renewed-session recovery pass.
These use scripted clients and synthetic storage; they are not
real-provider acceptance.
- Repository typecheck, production build, token gates, map checks and
Storybook build/catalog checks pass. The local full-suite campaign was
stopped after macOS shared-memory exhaustion repeatedly prevented
embedded PostgreSQL startup. No local aggregate pass is claimed. The
first clean-worker CI run identified avatar fixture/configuration, flag
defaults, feature-card ordering and OpenAPI route-coverage gaps; all
four focused regressions pass after correction. Those regressions pass.
The latest clean-worker CI run also found a Copilot source-hash
declaration mismatch after the shared descriptor update; the corrected
declaration passes all 28 integrity tests. The next review corrections
pass 144 rendered UI tests, 21 OpenAPI tests and 82 Runner
contract/integrity/history tests. The latest database fixtures were
blocked at startup by host shared-memory exhaustion; clean-worker CI
must execute their new regressions. Full current-head CI now passes: 54
successful checks and four intentional skips. The database regression
uses the PostgreSQL driver result shape; file-policy, rejected-feedback
and lock-order cases pass on clean workers. Current-head Greptile is 5/5
with no unresolved findings.
- Rendered setup steps and outbound-only verification were walked
through in Storybook. Simulation cannot enable Done without an
authenticated-reply state.
- Actual client OAuth, continued access, reconnect and one routine wake
with an exact chat acknowledgement were observed separately. This
candidate’s live authenticated challenge, assigned/proactive workflows,
Linux managed artifact, restart and cleanup are not yet qualified. The
provider stays disabled by default.
- The separate Cloud ingress change forwards only exact task-bound
upload/download paths and preserves host identity and header stripping.
- Current Cloud policy reserves Test for pre-merge app/harness
experiments; Staging accepts only master-derived revisions. Real-client
qualification needs a supported, authorized deployment target and
remains outstanding.

## Risks

One append-only migration adds routine/dispatch state and extends shared
bindings and file tickets. The unshipped migrations were regenerated
after upstream consumed their original numbers. Rolling back code
retains the durable rows; revoke grants and inspect unknown remote
activity before resuming dispatch. Grok cannot confirm remote
termination, stream its complete transcript or report spending. Plugins
are account-wide and do not isolate credentials between Bots.
Real-client managed acceptance remains required before enabling the
experimental provider.

## Model Used

OpenAI Codex based on GPT-6, with reasoning, code execution and
browser/native UI tools. The exact deployment model ID and
context-window size are not exposed by this runtime.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 20:57:42 -05:00
DottaandPaperclip d6e6d1c78a Stream OpenCode immediately, scope reasoning to turns, and deduplicate instructions (#15708)
## Thinking Path

> - Paperclip helps people manage AI agents and observe their work.
> - The native runner carries provider output into the task transcript.
> - OpenCode sends incremental text in `message.part.delta` events.
> - The driver ignored those events and waited for a full part snapshot.
Accepted chats also waited after lifecycle verification was complete.
> - This pull request forwards each valid chunk as it arrives and
removes unnecessary isolated startup work.
> - Valid chunks reach Paperclip sooner without changing completion or
permission rules. The matched browser experiment below does not
establish a reliable end-to-end latency improvement.

## Linked Issues or Issue Description

**What happened?**

The native OpenCode driver withheld text until OpenCode sent a full
snapshot. A local delayed-provider probe with the pinned OpenCode
1.18.34 runtime showed a 1,496 ms gap between the first native text
delta and the first Paperclip text delta (1,510 ms from provider text).

**Expected behavior**

Forward valid assistant text and reasoning deltas immediately. Preserve
repeated identical tokens, message roles, turn ownership, and final
response selection.

**Steps to reproduce**

Send an empty text part, then text deltas, and withhold the final full
snapshot. The new fixture requires the consumer to acknowledge its first
text delta before releasing the snapshot. The previous driver cannot
pass this handshake.

**Paperclip version or commit**

Baseline: `011e5669bad61c435a4745fb10812bef70376841`. The patch is
rebased onto current master.

**Deployment mode**

Local native OpenCode 1.18.34 on macOS arm64. Live diagnostics use
`openrouter/deepseek/deepseek-v4-flash-0731`. These are narrow
diagnostics, not full Product E2E qualification.

## What Changed

- Keep the macOS verified OpenCode launch pathname until child exit,
with guarded reuse and cleanup on failed launches. This fixes a
reproduced asynchronous executable-lifetime failure.
- Dispatch accepted queued chats immediately after lifecycle readiness
commits, through normal scheduler admission. Preserve ready state if
dispatch fails.
- Validate native OpenCode model access with the real hello probe
without a redundant catalog scan. Keep legacy adapter discovery
unchanged and isolate unspecified native probe directories.
- Map incremental text and reasoning to the existing canonical event
path, using observed part and message identities.
- Keep additive chunks without IDs distinct. Preserve ID-based event
deduplication.
- Clear current streaming part metadata when a new turn starts. Reject
mismatched session/message identities and unknown parts or fields.
- Disable automatic updates, remote model refreshes, and default plugins
in each isolated OpenCode process. Keep assigned MCP tools and default
model reasoning intact.
- Retain the latest cumulative text/reasoning part while its message
role is unknown, including completion metadata after more than 100
chunks.
- Expose `startTurn({ message, reasoningMode: "disabled" })` for one
OpenCode/OpenRouter turn. Carry the selection in the durable command
through Rust and the proxy. An omitted/default option restores provider
defaults on the next turn, including warm and recovered sessions. There
is no environment-level setting or automatic selection policy.
- Group optional Rust turn inputs in `CodexTurnOptions` and dispatch
through `start_turn_with_options`; retain `start_turn` for defaults.
Future turn settings can be added without another feature-specific
method.
- Expose a native-session capability for per-turn reasoning and reject
explicit unsupported selections before dispatch, including direct ACPX
and Codex backends. Runnerd checks the durable selected model as well as
the provider.
- Remove duplicate agent instructions from the shared OpenCode proxy
task envelope for all users. Send one system copy on every turn,
including prepared and resumed turns, because OpenCode reads the latest
user message’s system field. Preserve task constraints and completion
contracts.
- Document startup and streaming behavior. Add regression coverage for
role ordering, repeated chunks, final snapshot deduplication, and stale
turns.

## Verification

### Lower-load browser retry — 2026-10-10

**All 8/8 trials succeeded. In this batch, median Send → first visible
reply fell from 30.586 s to 12.476 s (59.2% lower).** Four fresh-agent
trials per variant, phase order before/after/after/before with two
trials per phase. Every adjacent-phase pair favored the candidate,
although one difference was only 0.301 s. This is evidence for the
readiness/probe changes on this host, not a production percentile or a
guarantee across providers.

| Phase/trial | Variant | Send → reply (s) | Observed ready → run (s) |
Session open → turn start (s) | Model requests |
|---|---|---:|---:|---:|---:|
| 0/0 | before | 45.042 | 25.337 | 3.629 | 2 |
| 0/1 | before | 13.689 | 0.000 | 2.443 | 2 |
| 1/0 | after | 14.696 | 0.000 | 2.526 | 1 |
| 1/1 | after | 13.389 | 0.000 | 2.470 | 2 |
| 2/0 | after | 10.871 | 0.000 | 2.706 | 2 |
| 2/1 | after | 11.564 | 0.004 | 2.443 | 2 |
| 3/0 | before | 41.582 | 21.518 | 2.376 | 2 |
| 3/1 | before | 19.589 | 9.753 | 2.707 | 1 |

Observed ready-to-run median: **15.636 s → 0 s**; zero means execution
began by the first ready observation, not literally zero latency.
Polling interval is nominally 250 ms plus HTTP time.
Session-open-to-turn-start includes controller handling, not just child
startup. All eight ran within the existing startup timeouts; no timeout
or reasoning policy was changed. Host load at fixture creation stayed
**5.47–8.73 on 18 CPUs**, versus 68.9–100.8 in the prior campaign. No
builds/tests ran concurrently with measurement.

Same merged source **b0a0158729a7913882a0e756fe7e27228d72bf53**, release
runner, rebuilt static UI, OpenCode **1.18.34**, model
**openrouter/deepseek/deepseek-v4-flash-0731**, provider-default
reasoning, and empty isolated workspaces in both variants. Only the
readiness worker and explicit-model verification source were toggled;
the launch-lifetime fix and all proxy streaming changes were held
constant. Thus this does not separately measure the original streaming
changes. One browser per phase, two fresh companies/agents/chats per
phase. Measurement begins at capture-phase Send click and ends on
visible Hi text plus two animation frames. Status/thinking is excluded;
emoji can arrive just after the first text. Successful screenshots
inspected. Each variant had three two-request turns using
`paperclip_finish` and one one-request turn; no status lookup was
observed. Reported usage includes settlement after the first visible
reply.

Runner SHA-256
`57f658c220eecd2370ffd3333cd7e5d06d16bb2798af0cf43c84e01c8207c1c3`;
proxy
`bcc02fda2bf35b38a116cd880841aa6c534f6e0b497a96d97369a1e06dcc72ac`;
rebuilt UI tree
`eee238f2eda628c4e8c3660707986da4f8dd9100c814e26938fce3756df2eae4`
(sorted relative path, NUL, binary per-file SHA-256). Worker/probe
variant source hashes are unchanged from the preserved comparison below.
Measured turn cost **$0.00612574**, plus verification probes not
included in that figure. All eight attempts retained; all source/proxy
files restored and test supervisors exited.

Current commit validation: **53 successful CI checks, 4 skipped, zero
failing; Greptile 5/5 on b0a0158729 with no actionable findings.** The
previous 20 targeted post-merge tests passed. No source edit was made
for this rerun. Earlier failed and inconclusive cohorts below remain
historical evidence and are not pooled with this batch.


### Master update and failure diagnosis — 2026-10-09

Merged `origin/master` at `417db14e7d` into this branch without
conflicts; pushed merge commit
`b0a0158729a7913882a0e756fe7e27228d72bf53`. The incoming changes do not
alter OpenCode process startup or its timeout budgets. Historical
measurements below remain attributed to their original commits.

The four last-campaign failures never issued `turn.start`, so these were
**cold-session admission failures, not model replies failing**. Two
retained `session.open` commands eventually completed after controller
timeout/cleanup had begun. The other two ended with the inner
`thread/start` response timeout, and their diagnostics recorded OpenCode
startup retries. Startup event timestamps are buffered publication times
and must not be interpreted as exact process-spawn times.

On the merged source, two credential-free startup-only checks used the
real pinned OpenCode 1.18.34, empty temporary workspaces, a placeholder
key, and **no model turns**:

- Existing pinned executable: spawn at 1.083 s; failed health
attempt/retry at 11.311 s and 21.914 s; third process healthy at 32.210
s; session opened at **35.168 s**.
- Verified private executable path: snapshot preparation took **0.497
s**; process spawned at 1.588 s; healthy at 9.967 s; session opened at
**11.120 s**.

These are sequential diagnostic samples, not evidence that one
executable path is faster. Host load was **56.5–64.5 on 18 logical
CPUs**. The local health wait permits 10 s per attempt and the driver
retries up to three times; the outer controller's cold admission budget
is 30 s, and the Rust facade also waits 30 s for a response. Thus
retries plus setup/session creation can outlast the caller's budget. The
isolated 35.168 s success demonstrates that a session can eventually
open yet fail the app's admission deadline. Heavy load aggravates the
timing; its exact contribution is not isolated. No timeout was increased
and no new model-latency claim is made.

Merge validation: **20/20 targeted lifecycle-policy and heartbeat
run-completion tests passed**, including temporary PostgreSQL cases. The
first sandbox invocation skipped database cases; the authorized local-DB
rerun executed all 20. The package-manager launcher could not verify its
version via the unreachable registry, so validation used the
already-installed Vitest binary. Full CI/review subsequently passed on
this merge commit; see the October 10 retry above. Older results below
apply to their named commits.


### Follow-up: reproduced macOS launch failure — 2026-10-09

The retry exposed a startup bug rather than only host-load noise. The
macOS proxy deleted the private verified executable path immediately
after asynchronous spawn. A credential-free test of the actual pinned
OpenCode `--version` reproduced a fast SIGKILL and a 15-second timeout
in three immediate-cleanup attempts; three deferred-cleanup controls
succeeded. The timeout was killed by the diagnostic's own deadline. This
experiment does not establish the OS-internal reason for the fast
SIGKILL.

Commit `c30451e0ebf3f74e9ef70d37bbe4d9fe7fb56359` retains the private
launch path until child exit, cleans failed spawns, and waits for forced
shutdown before reuse. Source descriptor authentication, ownership,
mode, inode checks, and the prohibition on ambient executable fallback
remain. Overlapping reuse fails closed. The existing synchronous shell
test was changed to exercise the actual asynchronous boundary.

**Verification:** 59 focused proxy/driver tests passed; runner
TypeScript check passed. All six subsequent real OpenCode version
launches succeeded without timeout (4.11, 4.33, 5.73, 6.91, 4.95, 6.70
seconds). The native Rust binary is unchanged from the retry; no model
calls were made by these diagnostics.

Retained interrupted retry: before 42.56/18.69 seconds; after one
180-second timeout (`provider_process_exited` / health SIGKILL) and one
37.33-second success. The latter overlapped the credential-free
diagnostic and is not a clean matched timing. The next phase was stopped
before Send to diagnose the reproduced bug. Reported measured-turn cost:
$0.0016874, verification probes additional. These attempts are not
pooled with other campaigns.

<!-- launch-fixed-proof:start -->
**Completed retry, stopped by the declared failure rule after 6 of 8
planned trials. No reliable end-to-end speedup demonstrated.** At commit
`c30451e0ebf3f74e9ef70d37bbe4d9fe7fb56359`, the launch fix above was
held constant in both variants; only the readiness handoff and
explicit-model verification path changed. Planned phase order:
before/after/after/before, two fresh agents/chats per phase, one new
browser per phase. The second after phase had two consecutive failures,
so the final before phase was not run.

| Phase/trial | Variant | Send → first visible reply | Observed ready →
run | Outcome |
|---|---|---|---|---|
| 0/0 | before | No reply within 180 s | 2.777 s | session.open timeout
|
| 0/1 | before | 47.654 s | 9.383 s | Succeeded |
| 1/0 | after | 50.051 s | 0.087 s | Succeeded |
| 1/1 | after | No reply within 180 s | 0.151 s | session.open timeout |
| 2/0 | after | No reply within 180 s | 3.337 s | session.open timeout |
| 2/1 | after | No reply within 180 s | 1.434 s | session.open timeout |

Both successful screenshots show “Hi 👋”. Timing starts at the browser's
capture-phase Send click and ends at the first visible answer text plus
two animation frames; the first fragment can be “Hi” before the emoji
arrives. Thinking/status text is not counted. All four failures were
`runner_local_connect_failed: PRP command session.open timed out`
(`native_session_interrupted`), before a reply; none reported the
earlier health-stage SIGKILL. They are retained, not discarded as
outliers. One success per variant does not support a speedup estimate or
median comparison. Observed ready-to-run median was **6.080 s before
(n=2) vs 0.793 s after (n=4)**; this is sampled every nominal 250 ms
plus HTTP latency and is a lower bound, not precise tracing. Host load
at fixture creation ranged **68.9–100.8 on 18 logical CPUs**, a
substantial confound that worsened over the campaign. No local
build/test was run concurrently with this campaign.

Provenance: pinned OpenCode **1.18.34**, model
**openrouter/deepseek/deepseek-v4-flash-0731**, default reasoning in
both variants, empty synthetic workspaces and isolated probe homes.
Release runner SHA-256
`57f658c220eecd2370ffd3333cd7e5d06d16bb2798af0cf43c84e01c8207c1c3`;
current proxy SHA-256
`bcc02fda2bf35b38a116cd880841aa6c534f6e0b497a96d97369a1e06dcc72ac`;
built UI tree SHA-256
`7f0c2b7f586cb753408351574b2239e22311944add99af4f6f3562cd6d47bbcb`. This
holds the rebuilt runner and static UI constant. Provider-reported
measured turn cost **$0.00120649**; verification probes are additional.
Including the earlier interrupted retry, this follow-up reports
**$0.00289389** in measured turn usage; missing usage is not assumed
free. Prior cohorts remain separate below.

Validation on `c30451e0e`: **59 focused tests passed**, runner
TypeScript check passed, **6/6 real credential-free pinned OpenCode
launches passed**, fresh Greptile **5/5 with zero unresolved threads**.
CI: **51 success, 4 skipped, 1 failed**. The failed native compilation
job never reached compilation: Docker's auth endpoint timed out during
Buildx setup, then failed the same way on one retry
([job](https://github.com/paperclipai/paperclip/actions/runs/37994181674/job/114039737503)).
Full local checks were not rerun while measuring. The PR remains draft:
the launch defect is reproduced and fixed, but cold session startup
still exceeds the controller's admission budget on this host. Raising
that budget would not establish a faster first response.
<!-- launch-fixed-proof:end -->

### Readiness investigation and live rerun — 2026-10-09

**Measured queue fix; no reliable end-to-end speedup claim. Keep this PR
in draft.** Accepted chats could wait for the periodic queue sweep after
verification had already committed `ready`. The lifecycle worker now
dispatches through the existing scheduler immediately after that commit.
The normal company, pause, budget, concurrency, and task-ownership
checks still apply. Dispatch failure preserves readiness and leaves
recovery to the queue sweep.

Native OpenCode verification also avoids enumerating the full model
catalog before running its real hello request. Identifier validation
remains. Authentication failures, unavailable models, and timeouts still
prevent readiness. An unspecified local probe directory uses an empty
temporary directory.

**Queue-only experiment:** four before and four after attempts, in
before/after/after/before server phases, two fresh agents per phase.
Median observed ready-to-start delay fell from **19.429 s to 0.058 s**.
State polling was nominally 250 ms plus HTTP time, so the latter means
within observation resolution; it is not a precise 58 ms latency claim.
After timings were 100.20, 65.29, 63.78, and 76.97 seconds. Before had
one 59.65-second success and three 120-second response timeouts (one
provider health SIGKILL, one late success, one still running after
settlement and canceled). These censored results do not support a
success-only median speedup comparison. Focused tests overlapped the
last baseline phase, which further limits total-time interpretation.
Reported measured-turn cost: $0.0055383; verification probes and
incomplete/canceled usage are additional.

**Final matched experiment:** built static UI in both variants to avoid
pre-Send Vite compilation; current proxy, release runner, selected
model, default reasoning, and explicitly isolated empty probe
cwd/HOME/XDG held constant. Both worker handoff and model-probe changes
vary. Fresh browser/company/agent/chat per attempt. ABBA order, two
attempts per variant, 180-second response limit declared before the
batch, four-turn bound. Same Send-to-rendered-Hi metric as the earlier
experiment.

| Order | Variant | Send → visible Hi | Created → execution | Observed
ready → execution | Outcome |
| --- | --- | ---: | ---: | ---: | --- |
| 1 | Before | 62.66 s | 23.467 s | 2.830 s | Succeeded |
| 2 | After | >180 s | 14.200 s | Within polling resolution | Provider
health SIGKILL |
| 3 | After | >180 s | 13.877 s | Within polling resolution | Provider
initialization timeout |
| 4 | Before | >180 s | 144.256 s | 14.067 s | Still running after
settlement; canceled |

Only one of four attempts produced a timed reply. **There is no valid
overall speedup estimate from this batch.** The dispatch delay is
removed, but provider startup failures and heavy shared-host load
remain. A recorded host sample was load 93.55 on 18 logical CPUs. This
is a confound, not proof that every failure was caused by host load.
Provider-reported measured-turn cost was $0.00032752, with no reported
usage for the other three attempts; verification probes are additional.

Retained earlier setup attempts: one shared-memory startup failure
before model calls, and a separate development-UI batch with a
60.06-second baseline followed by a navigation timeout before Send.
These attempts are retained separately, not counted as successful
response timings. No live attempts were silently dropped.

Provenance: source base `53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f`,
measured patch committed as `40b54eafb`, then rebased as
`c590770dcc2bb1debce14037935a7031e5c3c1ac`. **These live timings predate
the rebase.** Source and binary hashes are retained below. The inner
harness label `after` selects the identical current proxy in every
attempt; the outer campaign handoff label is the actual before/after
variant. Owned benchmark processes stopped and original proxy restored.

<!-- readiness-check-status:start -->
Post-rebase validation at `c590770dcc2bb1debce14037935a7031e5c3c1ac`:

- Full local `pnpm -r typecheck`: **passed**, including the native
release build (1,098.6 seconds on the loaded host).
- Focused lifecycle and adapter tests: **26 passed**. The 14 database
integration tests did not run locally because their hard-coded 20-second
database setup hook timed out. A retry with a CLI timeout override
encountered the same explicit hook limit. The earlier pre-rebase focused
batch passed 77 tests; these results are not substituted for post-rebase
execution.
- Local `pnpm test:run` was started, then stopped to avoid duplicating
CI on the saturated host. Local `pnpm build` was not run separately.
**Current-head CI passed Typecheck + Release Registry, Build, all
general and serialized test groups, Rust checks, both runner Vitest
groups, and all eight browser E2E shards.** The last general shard
passed 1,179 tests (72 files).
- Fresh [Greptile
review](https://github.com/paperclipai/paperclip/pull/15708#issuecomment-6085742217):
**5/5**, reviewed this exact head, no actionable defect.
- Final CI rollup: **49 success, 4 skipped, 4 failure**. The failures
are [Compile isolated native
Runner](https://github.com/paperclipai/paperclip/actions/runs/37990274515/job/114024329242),
[Docker context
integrity](https://github.com/paperclipai/paperclip/actions/runs/37990274623/job/114024196511),
[Canary Dry
Run](https://github.com/paperclipai/paperclip/actions/runs/37990274623/job/114024196424),
and the dependent `ci / verify` aggregate. All three root failures are
Docker Hub HTTP 429 / unauthenticated pull-rate limits while fetching
Node base images. The native-image job was retried once and hit the same
limit. No source compiler/test failure was reported by those gates. CI
maintainers need authenticated pulls or to rerun after the registry
limit clears.
- Owned benchmark servers stopped. Local validation commands completed
or were stopped. The PR remains a draft: user-visible speed/reliability
is not qualified, and the Docker-dependent CI gates are not green.
<!-- readiness-check-status:end -->

<details><summary>Sanitized readiness evidence with all attempts and
source hashes</summary>

```json
{"campaign":{"order":["before","after","after","before"],"trialsPerPhase":1,"maxMeasuredTurns":4,"maxCampaignUsd":1,"sourceHead":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","reasoning":"provider default, no override","proxySha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","purpose":"Final matched comparison of both optimizations; distinct from earlier queue-only campaign.","responseTimeoutMs":180000,"timeoutRationale":"Declared before this final campaign because earlier unchanged baselines sometimes exceeded 120 seconds; earlier timeouts remain retained.","ui":{"mode":"built static UI","treeSha256":"7f0c2b7f586cb753408351574b2239e22311944add99af4f6f3562cd6d47bbcb"},"priorCampaign":"combined-proof stopped after a development-UI navigation timeout before Send; no failed attempts erased."},"complete":true,"statistics":{"before":{"attempted":2,"successfulMeasurements":1,"medianTtfrMs":62657.2000002861,"rangeTtfrMs":[62657.2000002861,62657.2000002861],"medianObservedReadyToRunMs":8448.5,"medianRunStartToVisibleMs":37290.199951171875},"after":{"attempted":2,"successfulMeasurements":0,"medianTtfrMs":null,"rangeTtfrMs":null,"medianObservedReadyToRunMs":0.0,"medianRunStartToVisibleMs":null}},"measuredTurnCostUsd":0.00032752,"costCoverage":"Provider-reported measured chat turns only; harness verification probes are additional and not included.","readinessMetricLimit":"First observed ready state sampled every 250 ms plus HTTP duration; clamped to zero if execution started before the observation. This is a lower bound on ready-to-start delay, not a precise sub-millisecond metric.","results":[{"phase":0,"trial":0,"handoff":"before","ttfrMs":62657.2000002861,"answer":"Hi","statuses":["succeeded"],"error":null,"runErrorCode":null,"providerHealthKilled":false,"queueMs":23467.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":26390.0,"observedReadyToRunMs":2830.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":37290.199951171875,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00032752,"costUsdExact":"0.000327520","inputTokens":26864,"outputTokens":46,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":1,"trial":0,"handoff":"after","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":"provider_process_exited","providerHealthKilled":true,"queueMs":14200.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":24028.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":0,"handoff":"after","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":"provider_initialize_timeout","providerHealthKilled":false,"queueMs":13877.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":18107.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":3,"trial":0,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["running"],"error":"TimeoutError: page.waitForFunction: Timeout 180000ms exceeded.","runErrorCode":null,"providerHealthKilled":false,"queueMs":144256.0,"queuedBeforeObservedReady":true,"observedVerificationMsAfterFixture":136901.0,"observedReadyToRunMs":14067.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"}],"hostLoadSample":{"at":"2026-10-09T20:48:40.031Z","parallelism":18,"load":[93.546875,82.68017578125,75.9091796875]},"measuredChangesCommit":"40b54eafb","postRebaseCommit":"c590770dcc2bb1debce14037935a7031e5c3c1ac","postRebaseLimit":"Live benchmark predates the rebase. No post-rebase live result is claimed.","variantSourceHashes":{"before":{"server/src/modules/agent-lifecycle/application/worker.ts":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326","packages/adapters/opencode-local/src/server/test.ts":"4c10bacb55f2c7589e7b5c79d74781206ae075db8955f5b998065d6db3c0335a","server/src/adapters/registry.ts":"4a858763f69947d5745c7b8cb251a62fa404bc9683ade0ffb76282ed12761394"},"after":{"server/src/modules/agent-lifecycle/application/worker.ts":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7","packages/adapters/opencode-local/src/server/test.ts":"cd2ea3d51c3f1b4fb42261be701fb7f6b85704ad8e641e6db73d7c58e47364d3","server/src/adapters/registry.ts":"4a858763f69947d5745c7b8cb251a62fa404bc9683ade0ffb76282ed12761394"}},"model":"openrouter/deepseek/deepseek-v4-flash-0731","prompt":"Reply with Hi and an emoji and nothing else.","runnerBinary":{"profile":"release","sha256":"6134c17debda14a76da69ac9631a2d10dad482ebd58dbc9a4e4480ed652211c4"},"probeIsolation":"Explicit empty cwd and HOME/XDG folders under the synthetic fixture workspace in BOTH variants. No server checkout or ambient provider home is used for the hello request.","comparisonLabelNote":"Inner run.mts variant after selects the identical current proxy in every trial; outer campaign readinessHandoff controls before/after source changes."}
```

Queue-only campaign:

```json
{"campaign":{"order":["before","after","after","before"],"trialsPerPhase":2,"maxMeasuredTurns":8,"maxCampaignUsd":1,"sourceHead":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","reasoning":"provider default, no override","proxySha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04"},"complete":true,"statistics":{"before":{"attempted":4,"successfulMeasurements":1,"medianTtfrMs":59654.5,"rangeTtfrMs":[59654.5,59654.5],"medianObservedReadyToRunMs":19429.0,"medianRunStartToVisibleMs":8843.5},"after":{"attempted":4,"successfulMeasurements":4,"medianTtfrMs":71128.7000002861,"rangeTtfrMs":[63778.90000009537,100195.59999990463],"medianObservedReadyToRunMs":58.0,"medianRunStartToVisibleMs":26542.849975585938}},"measuredTurnCostUsd":0.0055383,"costCoverage":"Provider-reported measured chat turns only; harness verification probes are additional and not included.","readinessMetricLimit":"First observed ready state sampled every 250 ms plus HTTP duration; clamped to zero if execution started before the observation. This is a lower bound on ready-to-start delay, not a precise sub-millisecond metric.","results":[{"phase":0,"trial":0,"handoff":"before","ttfrMs":59654.5,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":50590.0,"observedReadyToRunMs":25709.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":8843.5,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00087852,"costUsdExact":"0.000878520","inputTokens":25644,"outputTokens":264,"cachedInputTokens":28416,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":0,"trial":1,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["failed"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":41651.0,"observedReadyToRunMs":14656.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":1,"trial":0,"handoff":"after","ttfrMs":100195.59999990463,"answer":"Hi 🙂","statuses":["succeeded"],"error":null,"queueMs":65893.0,"observedReadyToRunMs":116.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":33243.60009765625,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00075782,"costUsdExact":"0.000757820","inputTokens":27014,"outputTokens":175,"cachedInputTokens":26368,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":1,"trial":1,"handoff":"after","ttfrMs":65288.60000038147,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":43511.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":21227.60009765625,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00085326,"costUsdExact":"0.000853260","inputTokens":25166,"outputTokens":250,"cachedInputTokens":28160,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":0,"handoff":"after","ttfrMs":63778.90000009537,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":39218.0,"observedReadyToRunMs":0,"readyAndStartedInSameSample":true,"runStartToVisibleMs":23479.89990234375,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000839,"costUsdExact":"0.000839000","inputTokens":27068,"outputTokens":238,"cachedInputTokens":26368,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":2,"trial":1,"handoff":"after","ttfrMs":76968.80000019073,"answer":"Hi 👋","statuses":["succeeded"],"error":null,"queueMs":46257.0,"observedReadyToRunMs":185.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":29605.800048828125,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030582,"costUsdExact":"0.000305820","inputTokens":24694,"outputTokens":32,"cachedInputTokens":1792,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"ceffb90a6bc97ffaaf8ec7d0267c7bfa7738d321aaf2a618b5efb9b114bc88e7"},{"phase":3,"trial":0,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["succeeded"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":100979.0,"observedReadyToRunMs":3872.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00190388,"costUsdExact":"0.001903880","inputTokens":25524,"outputTokens":852,"cachedInputTokens":55808,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"},{"phase":3,"trial":1,"handoff":"before","ttfrMs":null,"answer":null,"statuses":["running"],"error":"TimeoutError: page.waitForFunction: Timeout 120000ms exceeded.","queueMs":129391.0,"observedReadyToRunMs":24202.0,"readyAndStartedInSameSample":false,"runStartToVisibleMs":null,"usage":[{}],"workerSha256":"02adc7e1162fb60439869cec62b75d8fb22fec71155f80535c8e00211cde8326"}]}
```
</details>

### Matched live browser latency evidence — 2026-10-09

**Conclusion: the overall first-response speedup is not established.**
Twelve successful real browser runs produced a lower after median, but
the updated path won only 3 of 6 adjacent pairs. Median paired
improvement was -0.17 seconds (effectively tied). Do not treat the
deterministic streaming-forwarding improvement as proof that this PR
fixes end-to-end first-response latency.

- **Actual path:** local Paperclip browser → real server/database →
current optimized Rust runner → pinned OpenCode 1.18.34 → OpenRouter
`deepseek/deepseek-v4-flash-0731`. Default reasoning in both variants;
no disabled-reasoning override.
- **Prompt:** `Reply with Hi and an emoji and nothing else.` Fresh
company, agent, chat, and per-turn native provider process for each
trial; same QA fixture instructions and selected model.
- **Comparison:** current product/runner at
`53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f` held constant. The baseline
substitutes the exact `opencode-app-server-proxy.ts`,
`opencode-proxy-task-envelope.ts`, and `opencode-server-driver.ts`
contents from pre-PR `41fec8c8921f9fb19c13fe11e2c9b71bf1017317`. This
isolates those changed modules; it is not an entire old-checkout
comparison.
- **Metric:** browser capture-phase Send click to a rendered `Hi`
markdown answer plus two animation frames, with a screenshot of the
answer. Thinking, tool labels, and status indicators do not count. This
is a DOM/render measurement, not instrumented compositor pixel timing.
- **Order/bound:** predeclared `before, after, after, before` repeated
three times; six trials per variant; 120-second response timeout; $1
campaign guard. All 12 measured trials returned `Hi` and an emoji and
finished successfully; none omitted.
- **Result:** before median **48.08 s** (37.42–66.40); after median
**42.50 s** (27.68–63.32). The 11.6% lower median alone is not
persuasive evidence of a reliable improvement given the mixed paired
results and broad overlap.
- **Remaining delay:** retained queue timestamps for 10/12 trials show
**9.76–41.65 seconds from run creation to execution start**. This is
before the OpenCode path changed here. Its cause is not established by
this benchmark. The final two queue reads were unavailable after
automatic server shutdown; all twelve primary browser timings were
retained.
- **Cost:** $0.010517369 provider-reported across the 12 measured turns;
$0.011371499 including the successful setup pilot. This is separate from
the older diagnostics listed below.
- **Retained setup attempts:** two failures before Send (composer
locator and transpiler helper); one baseline startup failure before any
observed model request (`SIGKILL` while probing OpenCode health); one
successful current-code pilot whose selector missed the visible reply.
These are retained separately, not silently included/excluded as valid
timings. The measured batch used the corrected selector and the same
release binary for both variants.
- **Limits:** local development server and headless Chromium on macOS
arm64, small sample, variable queue timing/provider routing/cache. This
does not qualify production/cloud performance or isolate the
contributions of each changed module. Server, browser, and owned runs
were stopped; original proxy build artifact restored; no product source
files changed for this experiment.

| Pair | Before: Send → visible Hi | After: Send → visible Hi | Faster
variant |
| --- | ---: | ---: | --- |
| 1 | 66.40 s | 27.68 s | After |
| 2 | 37.42 s | 28.00 s | After |
| 3 | 39.75 s | 55.22 s | Before |
| 4 | 47.32 s | 63.32 s | Before |
| 5 | 48.85 s | 29.79 s | After |
| 6 | 51.31 s | 61.07 s | Before |

<details>
<summary>Sanitized measurement records, source/binary hashes, usage, and
retained attempt classification</summary>

```json
{"manifest":{"candidate":"53580f8fbd40b963f3fb7ba5172ff3ede2e9ef1f","baseline":"41fec8c8921f9fb19c13fe11e2c9b71bf1017317","comparison":"Same current product and runner; replace the three OpenCode proxy/driver source modules with exact pre-PR contents for baseline. Reasoning uses defaults in both.","model":"openrouter/deepseek/deepseek-v4-flash-0731","prompt":"Reply with Hi and an emoji and nothing else.","samplesPerVariant":6,"order":["before","after","after","before","before","after","after","before","before","after","after","before"],"maxTurnMs":120000,"maxCostUsd":1,"variants":{"before":{"sources":{"src/cli/opencode-app-server-proxy.ts":"e9b46c937d7ce3b51dc44181a2a3ad82befda9ebe184adf80c0a6b30da140fd6","src/cli/opencode-proxy-task-envelope.ts":"fc23f8a515c2c4d1551f6b95e5b38e6254849dec23f7396e76b646e170a6e006","src/drivers/opencode/opencode-server-driver.ts":"99de415e8fc3bb5fb6f8d7512d751c4c37d2aa77a18b0546b9fb232f1a6fb6c5"},"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b"},"after":{"sources":{"src/cli/opencode-app-server-proxy.ts":"fa800e9bccce02f05f1af83e225d3b5a1300d0a7d4c35ac548f400d6c0a83f79","src/cli/opencode-proxy-task-envelope.ts":"5c387614fc9832322686326b8482eb00d88699d491b05cf59cadcd94a41194ea","src/drivers/opencode/opencode-server-driver.ts":"a944f3bf7f1bf897daec3a5dc2aa34ee9d1a2133efcb3cf150b002095a0ec586"},"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04"}},"runnerBinary":{"profile":"release","sha256":"6134c17debda14a76da69ac9631a2d10dad482ebd58dbc9a4e4480ed652211c4"},"metric":"Browser Send capture-phase click to visible Hi answer, sampled on animation frames, plus two paint opportunities. Excludes reasoning/tool/status text.","setupAttempts":["setup-failure-1","setup-failure-2","startup-failure-3","pilot-selector-failure"]},"summary":{"before":{"attempts":6,"measured":6,"medianMs":48083.050000190735,"minMs":37420.5,"maxMs":66397.69999980927,"totalCostUsd":0.004945229,"toolCalls":[4,1,0,0,0,1]},"after":{"attempts":6,"measured":6,"medianMs":42504.049999952316,"minMs":27680.099999904633,"maxMs":63320.90000009537,"totalCostUsd":0.00557214,"toolCalls":[0,1,0,4,0,1]},"medianReductionPercent":11.602841334350234,"medianPairedImprovementMs":-168.59999990463257,"reportedCampaignCostUsdIncludingPilot":0.011371498999999998},"pairs":[{"indices":[0,1],"beforeMs":66397.69999980927,"afterMs":27680.099999904633,"improvementMs":38717.59999990463},{"indices":[2,3],"beforeMs":37420.5,"afterMs":27997,"improvementMs":9423.5},{"indices":[4,5],"beforeMs":39751.60000038147,"afterMs":55217.199999809265,"improvementMs":-15465.599999427795},{"indices":[6,7],"beforeMs":47318.90000009537,"afterMs":63320.90000009537,"improvementMs":-16002.0},{"indices":[8,9],"beforeMs":48847.2000002861,"afterMs":29790.900000095367,"improvementMs":19056.300000190735},{"indices":[10,11],"beforeMs":51311.7000002861,"afterMs":61072.40000009537,"improvementMs":-9760.699999809265}],"trials":[{"index":0,"variant":"before","startedAt":"2026-10-09T19:15:23.172Z","measurementError":null,"ttfrMs":66397.69999980927,"domMs":66390.59999990463,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.002612595,"costUsdExact":"0.002612595","inputTokens":55962,"outputTokens":1344,"cachedInputTokens":83456,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_get_task_context","paperclip_comment_on_task","paperclip_finish","paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":4,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:15:58.194Z","turn.submitted":"2026-10-09T19:15:58.311Z","turn.started":"2026-10-09T19:15:59.063Z","firstTextDelta":"2026-10-09T19:16:36.039Z","turn.completed":"2026-10-09T19:16:36.118Z"},"completedRunDurationsMs":[42915.0]},{"index":1,"variant":"after","startedAt":"2026-10-09T19:16:36.598Z","measurementError":null,"ttfrMs":27680.099999904633,"domMs":27636.599999904633,"answer":"Hi","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030429,"costUsdExact":"0.000304290","inputTokens":26845,"outputTokens":28,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":3,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:17:00.717Z","turn.submitted":"2026-10-09T19:17:00.841Z","turn.started":"2026-10-09T19:17:01.508Z","firstTextDelta":"2026-10-09T19:17:05.934Z","turn.completed":"2026-10-09T19:17:06.205Z"},"completedRunDurationsMs":[14435.0]},{"index":2,"variant":"after","startedAt":"2026-10-09T19:17:08.762Z","measurementError":null,"ttfrMs":27997,"domMs":27984.599999904633,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00101016,"costUsdExact":"0.001010160","inputTokens":27544,"outputTokens":366,"cachedInputTokens":26624,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:17:26.192Z","turn.submitted":"2026-10-09T19:17:26.305Z","turn.started":"2026-10-09T19:17:26.936Z","firstTextDelta":"2026-10-09T19:17:40.688Z","turn.completed":"2026-10-09T19:17:40.826Z"},"completedRunDurationsMs":[17763.0]},{"index":3,"variant":"before","startedAt":"2026-10-09T19:17:41.376Z","measurementError":null,"ttfrMs":37420.5,"domMs":37364.40000009537,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000693018,"costUsdExact":"0.000693018","inputTokens":24236,"outputTokens":282,"cachedInputTokens":27648,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:18:12.381Z","turn.submitted":"2026-10-09T19:18:12.616Z","turn.started":"2026-10-09T19:18:13.441Z","firstTextDelta":"2026-10-09T19:18:21.746Z","turn.completed":"2026-10-09T19:18:22.262Z"},"completedRunDurationsMs":[29216.0]},{"index":4,"variant":"before","startedAt":"2026-10-09T19:18:23.000Z","measurementError":null,"ttfrMs":39751.60000038147,"domMs":39705.7000002861,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000265747,"costUsdExact":"0.000265747","inputTokens":26123,"outputTokens":77,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:19:01.000Z","turn.submitted":"2026-10-09T19:19:01.163Z","turn.started":"2026-10-09T19:19:01.893Z","firstTextDelta":"2026-10-09T19:19:07.169Z","turn.completed":"2026-10-09T19:19:07.384Z"},"completedRunDurationsMs":[15843.0]},{"index":5,"variant":"after","startedAt":"2026-10-09T19:19:10.050Z","measurementError":null,"ttfrMs":55217.199999809265,"domMs":55204.89999961853,"answer":"Hi 🙂","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00030421,"costUsdExact":"0.000304210","inputTokens":4294,"outputTokens":28,"cachedInputTokens":22543,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:19:59.877Z","turn.submitted":"2026-10-09T19:19:59.990Z","turn.started":"2026-10-09T19:20:00.713Z","firstTextDelta":"2026-10-09T19:20:07.290Z","turn.completed":"2026-10-09T19:20:07.658Z"},"completedRunDurationsMs":[15104.0]},{"index":6,"variant":"after","startedAt":"2026-10-09T19:20:09.550Z","measurementError":null,"ttfrMs":63320.90000009537,"domMs":63313.09999990463,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00260723,"costUsdExact":"0.002607230","inputTokens":137971,"outputTokens":951,"cachedInputTokens":1024,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_comment_on_task","paperclip_get_task_context","paperclip_comment_on_task","paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":4,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:20:59.730Z","turn.submitted":"2026-10-09T19:20:59.859Z","turn.started":"2026-10-09T19:21:00.501Z","firstTextDelta":"2026-10-09T19:21:19.416Z","turn.completed":"2026-10-09T19:21:19.608Z"},"completedRunDurationsMs":[26519.0]},{"index":7,"variant":"before","startedAt":"2026-10-09T19:21:20.519Z","measurementError":null,"ttfrMs":47318.90000009537,"domMs":47246.800000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000257965,"costUsdExact":"0.000257965","inputTokens":4700,"outputTokens":71,"cachedInputTokens":21407,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:22:03.924Z","turn.submitted":"2026-10-09T19:22:04.439Z","turn.started":"2026-10-09T19:22:04.772Z","firstTextDelta":"2026-10-09T19:22:09.915Z","turn.completed":"2026-10-09T19:22:10.343Z"},"completedRunDurationsMs":[16702.0]},{"index":8,"variant":"before","startedAt":"2026-10-09T19:22:11.124Z","measurementError":null,"ttfrMs":48847.2000002861,"domMs":48802.59999990463,"answer":"Hi 🎉","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.000327654,"costUsdExact":"0.000327654","inputTokens":44796,"outputTokens":32,"cachedInputTokens":0,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:22:57.182Z","turn.submitted":"2026-10-09T19:22:57.281Z","turn.started":"2026-10-09T19:22:57.988Z","firstTextDelta":"2026-10-09T19:23:02.915Z","turn.completed":"2026-10-09T19:23:03.035Z"},"completedRunDurationsMs":[9541.0]},{"index":9,"variant":"after","startedAt":"2026-10-09T19:23:03.579Z","measurementError":null,"ttfrMs":29790.900000095367,"domMs":29748.800000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00034054,"costUsdExact":"0.000340540","inputTokens":24710,"outputTokens":59,"cachedInputTokens":1792,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":[],"eventCounts":{"turn.started":1,"item.delta":2,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:23:28.840Z","turn.submitted":"2026-10-09T19:23:28.954Z","turn.started":"2026-10-09T19:23:29.666Z","firstTextDelta":"2026-10-09T19:23:35.306Z","turn.completed":"2026-10-09T19:23:35.531Z"},"completedRunDurationsMs":[12732.0]},{"index":10,"variant":"after","startedAt":"2026-10-09T19:23:37.247Z","measurementError":null,"ttfrMs":61072.40000009537,"domMs":61061.300000190735,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00100571,"costUsdExact":"0.001005710","inputTokens":25307,"outputTokens":368,"cachedInputTokens":28160,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6691475ed55f10179ec6ee0023a1f6462982f763848da7cd5b1d0baf38633b04","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:24:33.721Z","turn.submitted":"2026-10-09T19:24:33.832Z","turn.started":"2026-10-09T19:24:34.601Z","firstTextDelta":"2026-10-09T19:24:43.135Z","turn.completed":"2026-10-09T19:24:43.278Z"},"completedRunDurationsMs":[17387.0]},{"index":11,"variant":"before","startedAt":"2026-10-09T19:24:44.710Z","measurementError":null,"ttfrMs":51311.7000002861,"domMs":51300.5,"answer":"Hi 👋","runCount":1,"statuses":["succeeded"],"usage":[{"model":"openrouter/deepseek/deepseek-v4-flash-0731","costUsd":0.00078825,"costUsdExact":"0.000788250","inputTokens":24316,"outputTokens":356,"cachedInputTokens":27648,"cacheWriteTokens":0,"usageSource":"per_run","costStatus":"reported"}],"bundleSha256":"6dd8726e72545341f6772e54ec5aeb6264dec74db67290df44930d87135efb6b","toolCalls":["paperclip_finish"],"eventCounts":{"turn.started":1,"tool.execution.started":1,"item.delta":1,"turn.completed":1},"eventTimes":{"session.started":"2026-10-09T19:25:31.347Z","turn.submitted":"2026-10-09T19:25:31.463Z","turn.started":"2026-10-09T19:25:32.208Z","firstTextDelta":"2026-10-09T19:25:39.405Z","turn.completed":"2026-10-09T19:25:39.563Z"},"completedRunDurationsMs":[15446.0]}],"additionalAttempts":[{"attempt":"setup-1","stage":"before_send","result":"non-editable composer locator","modelRequestObserved":false},{"attempt":"setup-2","stage":"before_send","result":"transpiler helper absent in browser","modelRequestObserved":false},{"attempt":"startup-pilot-before","runnerProfile":"debug","result":"no visible reply within 120s; OpenCode health startup SIGKILL; retained infrastructure failure","modelRequestObserved":false},{"attempt":"selector-pilot-after","runnerProfile":"debug","result":"Hi reply succeeded; browser selector missed it; no valid TTFR","providerReportedCostUsd":0.00085413}],"queueTimingCoverage":{"measuredTrials":10,"totalTrials":12,"records":[{"index":0,"runs":[{"createdAt":"2026-10-09T19:15:28.998Z","startedAt":"2026-10-09T19:15:53.558Z","queuedMs":24560.0}]},{"index":1,"runs":[{"createdAt":"2026-10-09T19:16:38.520Z","startedAt":"2026-10-09T19:16:54.157Z","queuedMs":15637.0}]},{"index":2,"runs":[{"createdAt":"2026-10-09T19:17:10.587Z","startedAt":"2026-10-09T19:17:23.561Z","queuedMs":12974.0}]},{"index":3,"runs":[{"createdAt":"2026-10-09T19:17:43.807Z","startedAt":"2026-10-09T19:17:53.564Z","queuedMs":9757.0}]},{"index":4,"runs":[{"createdAt":"2026-10-09T19:18:28.113Z","startedAt":"2026-10-09T19:18:54.011Z","queuedMs":25898.0}]},{"index":5,"runs":[{"createdAt":"2026-10-09T19:19:12.343Z","startedAt":"2026-10-09T19:19:53.993Z","queuedMs":41650.0}]},{"index":6,"runs":[{"createdAt":"2026-10-09T19:20:14.258Z","startedAt":"2026-10-09T19:20:53.866Z","queuedMs":39608.0}]},{"index":7,"runs":[{"createdAt":"2026-10-09T19:21:23.019Z","startedAt":"2026-10-09T19:21:54.298Z","queuedMs":31279.0}]},{"index":8,"runs":[{"createdAt":"2026-10-09T19:22:14.671Z","startedAt":"2026-10-09T19:22:53.933Z","queuedMs":39262.0}]},{"index":9,"runs":[{"createdAt":"2026-10-09T19:23:06.155Z","startedAt":"2026-10-09T19:23:23.941Z","queuedMs":17786.0}]}],"limitation":"The server shut down before a final API read; queue timing is retained for the first ten trials only."},"conclusion":"No reliable end-to-end speedup established. The after median is lower, but only three of six adjacent matched pairs were faster; median paired improvement is approximately zero. The deterministic streaming-forwarding fix remains separately supported.","limitations":["Local dev server and headless Chromium on macOS arm64; six fresh chats per variant; not a production/cloud latency guarantee.","Current product and current release runner held constant; only three OpenCode modules replaced by their exact pre-PR contents for baseline.","Default model reasoning unchanged; no no-reasoning override or decision policy.","Upstream routing/cache and queue time vary; trials run serially in predeclared counterbalanced ABBA order.","Render proxy: capture-phase Send click to visible nonempty Hi markdown, then two animation frames; screenshot verifies the rendered answer. This is not instrumented compositor pixel timing.","Two setup-only failures, one startup failure, and one invalid-measurement successful pilot are retained separately, not silently treated as successful timings."],"reproducibility":{"harnessSha256":"f93996b306c7d31c19bfcb9cc197653f867944ffb900d81a23a34f831e17c0c5","variantBuilderSha256":"4e88a7bbdc0de5d72601194ebe3b96d9c6f6eda5a33d8e0f00cf2d5d14db34c2","analyzerSha256":"2d129177a1b8033f768aad3c82dc8fff70ba0ba76e7270b2d8612ee760d4aaf4"}}
```

</details>

- Latest options-struct refactor: 33 provider tests and 86 backend tests
passed. Four port-dependent fixtures initially failed inside the sandbox
and passed with loopback access. Latest check snapshot: 51 successes, 4
skips, and 2 failures (`ci / e2e` and `ci / e2e shard (5/8)`). This
latency experiment does not make the PR merge-ready.

- Focused TypeScript suites passed: OpenCode driver, per-turn reasoning,
prepared-context recovery, proxy envelope, live sessions, Codex context
control, and native instruction measurements. The real runnerd/proxy
integration test confirms disabled followed by default in the same
session. A stale staged binary initially hid the new parameter;
rebuilding the release runner resolved it.
- Capability-guard regression suites passed all 53 tests; the real
runner/proxy boundary still accepts the per-turn selection. Both
OpenRouter and non-OpenRouter real runner/proxy cases passed, along with
62 existing OpenCode fixture tests. Runner TypeScript build passed after
the final correction.
- Affected Rust modules passed: 33 provider tests and 86 durable backend
tests. Malformed or unsupported reasoning selections do not dispatch a
provider turn or poison admission state.
- Pinned OpenCode 1.18.34 with a local OpenRouter-compatible fixture
sent three successive provider requests with reasoning omitted,
`enabled: false`, then omitted. Each request contained one copy of the
agent instructions. No paid provider call was needed.
- The reconstructed first-turn task envelope shrank from 4,356 to 460
characters. This is a payload-size measurement, not a claimed token or
latency reduction. Existing stored conversation history is not
rewritten.
- Prior head `8c07fe2e70267a7c8a3118f1071eca73ecdc6c8a`: all 53 checks
passed, with four intentional skips. Greptile is 5/5 with no open
findings. One bounded retry cleared first-test timeouts, a legacy
signoff lease failure, and CI runner shutdowns. The timed-out suites
also passed locally (14 auth-signal tests, 40 device-login tests, and
the runner resume case).
- Known reported diagnostic usage totals about $0.0029. Two prematurely
closed baseline warm-turn attempts are excluded from latency comparisons
and their usage is not fully captured; background provider usage is also
not fully accounted. No further paid runs are active.
- `pnpm -r typecheck`: passed. Runner TypeScript typechecks and build
also passed after the review correction.
- `pnpm test:run`: attempted and stopped after a reproducible failure in
the untouched Codex recovery test `archives a damaged prior epoch before
completing guarded same-task replacement with real runnerd`
(`server/src/services/native-runtime/native-session-resume.test.ts:1072`).
It returns `needs_review` / failed instead of done / succeeded,
including when rerun alone. The broad local suite is not green. The two
initial collection failures disappeared after building; their isolated
rerun passed all 1,565 tests.
- `pnpm build`: passed.
- Pinned real OpenCode plus a delayed local provider: first native delta
to Paperclip delta fell from 1,496 ms to less than 1 ms at millisecond
measurement resolution. This isolates forwarding delay, not
network/model inference.
- Two live driver samples after the patch reached first text in
2.28–2.62 seconds including session startup. Baseline first responses
took 12.37–13.43 seconds. Small unmatched samples had different
reasoning/cache outcomes, so these are observations, not an attributed
speedup ratio.
- Full compiled runnerd protocol diagnostic: completed with `Hi 👋`;
first assistant delta at 9.19 seconds and cleanup complete at 9.44
seconds. The seeded mock-control-plane harness used 27,512 input tokens
across two provider requests, split into 13,521 and 13,991. The extra
`answer_status_question` call posted `Hi 👋` to the mock task in 12 ms,
then caused another model request. A reconstruction contains 25 tools
(35.3k JSON characters), 12.8k system characters, and a 4.4k task
envelope; 3.9k instruction characters appear in both system and task
context. Provider-reported cost was $0.00073976; the pricing-table
estimate was $0.00395332. This is one integration diagnostic, not a
production latency claim.
- A separate full-runner sample with existing lazy tool discovery also
completed, but took 14.64 seconds through cleanup and called
`paperclip_finish`. Its usage ledger recorded 12,888 input and 11,776
cached-input tokens, with $0.00096344 provider-reported cost. This did
not establish a latency improvement, so the default tool exposure was
not changed.
- Four direct OpenRouter requests separately measured default reasoning
at 2.45/3.90 seconds to first text and disabled reasoning at 0.66/0.53
seconds. Default reasoning remains unchanged; disabling it requires the
explicit per-turn option.

## Risks

- Immediate readiness dispatch changes scheduling timing. It uses
existing admission checks and preserves the periodic sweep as recovery.
- Native model verification relies on the real request rather than
catalog enumeration. The final live batch had provider startup failures;
overall speed and reliability are not qualified.
- Incremental chunks without IDs cannot safely be deduplicated by
content. Repeated identical chunks are valid. Known-ID duplicates remain
suppressed.
- OpenCode uses its bundled model catalog plus the explicit
selected-model entry. New remote catalog metadata will not refresh
during isolated startup.
- Default provider plugins are disabled. This runner supplies
credentials and assigned MCP tools through its own controlled
configuration.
- Disabled reasoning is supported only on the OpenCode/OpenRouter path
and requires a compatible model. It applies to one turn and is not an
automatic latency policy.
- The matched live browser sample is small and does not establish a
reliable end-to-end improvement. It includes local queueing/startup and
browser rendering, but does not qualify production or remote sandbox
latency.

## Model Used

OpenAI GPT-6 (Codex). Tool use, code editing, and command execution were
used. The session does not expose a more specific model ID or
context-window size. Live diagnostic target: DeepSeek
`deepseek/deepseek-v4-flash-0731` through OpenRouter and OpenCode
1.18.34.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-10 07:15:41 -05:00
DottaandPaperclip 57e977be72 feat: integrate Pi 1.0 into the experimental Runner (#14921)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The experimental Runner owns provider processes and durable
sessions.
> - Pi needs working task execution and human controls.
> - The five-PR stack must preserve changes already on master.
> - Each layer now carries the complete integrated source for a safe
sequential fallback.
> - This PR belongs to native GitHub stack #15602, ending at #14956.

## Linked Issues or Issue Description

Refs #14436, #14631, #14743 and #14956.

Ship Pi 1.0 through the experimental Paperclip Runner. The five PRs are
#14921, #14922, #14923, #14924 and #14956. The user authorized the
complete merge after checks pass. Existing `pi_local` execution is
unchanged. Accounting and wider provider/platform qualification remain
deferred.

## What Changed

- Recover missing final replies after workspace finalization changes
owners, using accepted-turn evidence without rerunning work or granting
external-chat publication.
- Preserve the admitted Pi instruction root across warm runs, while
retaining changed-root rejection.
- Give Pi a bounded 15-second default shutdown grace so stop, drain
acknowledgement and durable suspension can complete. Explicit deadlines
and other providers retain their existing behavior.
- Integrate the Pi 1.0 runtime and master contracts.
- Use Pi profile 22. Preserve explicit caller-selected models and exact
native thinking levels. Keep Pi's wrapper, helper, extension and
question/control behavior unchanged from the qualified profile-19
runtime.
- Preserve master's Dot lifecycle and consent fields, configured task
environment, status guards and current Codex/Claude dependency versions.
Cursor stays qualified. Copilot stays pending; profile 17 binds the
changed shared protocol validation sources.
- Exclude general AWS IAM credentials from Pi static/custom provider
bindings and selected task projections; preserve the provider-scoped
Bedrock bearer key. Profile 21 is retained as historical provenance.
Rust and cloud install probes use the current declaration.
- Patch bundled brace-expansion 5.0.9 to the exact official 5.0.12
payload. Pin the patch and complete runtime closures. Include the patch
in normal installed setup tooling. Keep the upstream Pi shrinkwrap as
provenance and permit only this exact security correction.
- Include current attestation files in the Docker build context. Keep
the repository lockfile unchanged from master. CI and private image
builds resolve manifest changes before their frozen installation.

## Verification

- Full local `pnpm -r typecheck` passes, including Runner Rust, server
and UI. Focused integration checks pass: 194 Runner
admission/environment tests, 63 profile/credential tests with one
expected skip, 152 Dot/UI configuration tests, and Pi transcript/notice
tests.
- Full local `pnpm build` passes on the final source.
- Fresh final-source checks pass: all 698 Rust workspace tests (32
binaries), 156 credential/profile/controller tests with one expected
skip, Runner TypeScript typecheck, and 20 package/setup/sandbox tests.
- The profile-21 Pi materializer passes on the native host with the
official pinned Node 24.21.0 and its npm. It verifies all 150 locked
packages, the patched dependency and the exact closure. Setup/package
bundle tests and UI token gates pass.
- The old hashes were reproduced for all three supported targets before
calculating the patched graph. New closure hashes are darwin-arm64
`282022db10150c6632b3444df421342e7d534bdf5d5fb1097a2e79d0625a2bcf`,
darwin-x64
`64e251e19009f755c0b04f73ce2138246faab71a961b0f13d75ebfcc34bef12e`, and
linux-x64
`713b1fdff42fb56a1518bdc084f181d70bee8ebadc3e4b1d76321ed9108c8410`.
Independent native platform execution is separate from graph identity
reproduction.
- Historical cloud qualification remains unchanged: all seven core cases
pass on shipping source `10dc43c9ec65d88c2f782d62afb296d09494f215`,
harness `1a4408a48cfb5a1f094a311141c257c92cd7a893`, image
`sha256:5b3a775b383591bda1b0c1889e509acc70ce7f37c53f09733c81d59037f02280`,
and accepted Sonnet 4.6/low fixture. All 215 canonical files and all
seven cleanup checks pass independent verification. These are profile-19
results and are not relabeled as fresh profile-22 runs.
- Current Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.
[The readiness
plan](https://github.com/paperclipai/paperclip/blob/codex/pi-production-readiness/doc/plans/2026-10-02-pi-production-readiness.md)
preserves campaign and failed-attempt provenance.
- Merge only after every PR's current-head CI and fresh review pass.
Linux CI covers the full suites, build and browser tests. The local
embedded Postgres API-authority suite cannot start on this macOS/Node 26
host, so Linux CI must confirm that suite.

### Fresh profile-22 core qualification — 2026-10-08

All seven accepted core cases pass canonically on Pi profile 22, with
`openrouter/anthropic/claude-sonnet-4.6` and native-confirmed low
thinking. This model is a fixture; production accepts the caller's
explicit Pi provider/model.

Runtime/install source: `3241a992f2a7703e59e97ed0fd3e5d6405de4401`.
Frozen accepted harness: `1a4408a48cfb5a1f094a311141c257c92cd7a893`.
Immutable cloud image:
`ghcr.io/paperclipai/paperclip-daytona-runner@sha256:506f22db7edd78f37c0c40bec1cc084af1850455026dbf467194bfbb8fcef141`.
Pi digest:
`sha256:e92078bee3c23bec4100aa589013a44613d054cd686826534025d8019e9f39a9`.

[Hosted Linux image and clean-install
verification](https://github.com/paperclipai/paperclip/actions/runs/37868328023)
passes, including all 20 source-bound archives, normal CLI/Pi setup,
companion import and the production pack reader. This exact installation
source includes the latest master integration and the corrected Pi warm
instruction-root fence. Full local typecheck/build and current-head
hosted CI verify the final stack. All 13 focused real-root regressions
pass. The full local executor suite passed 662 tests; 15 database tests
could not start the Mac embedded PostgreSQL service. Hosted Linux CI
passes the full required verification and E2E checks. These fresh
results keep their own source identity; profile-19 results remain
historical.

| Core path | Canonical campaign | Retained archive SHA-256 |
| --- | --- | --- |
| File edit, validation, download and Done |
`pi-core22-replyfix-0-1791511228` | 23 files;
`a473e8603a3dd4737863291f8d3d1e392391f0b16d433c3e0e0e9d8baf7a97b0` |
| Pending question and controller restart |
`pi-core22-replyfix-1-1791511376` | 33 files;
`6b829c4eb74e1f32a89c692a4ae7130dbfc1c6d3cf13915effe2103d9e242c8e` |
| Three-turn session/process/workspace continuity |
`pi-core22-replyfix-2-1791511587` | 23 files;
`7a87021f8f9a3fdd3c58bb4467f8d82c635e3ea4795d6e75f144d9aa14818df8` |
| Four typed questions and browser reconnects |
`pi-core22-replyfix-3-1791511881` | 42 files;
`9e31755252be1f4f9cb0626c984c142d4d1ae5f5bee3a7af08444db8d12c280a` |
| Plan approval and completion | `pi-core22-replyfix-4-1791512031` | 22
files;
`a0383ce1aab38e7b5a25ce0e9dd3bebea5c037ebd96ae6b29dae19015da2ae2c` |
| Same-turn steering and permission denial |
`pi-core22-replyfix-5-1791512261` | 39 files;
`c929b8c7070f0b66aedc17e65ca46e6beab1e363926ac9f7e2a75fb250f05949` |
| Stop during pending permission | `pi-core22-replyfix-6-1791512390` |
33 files;
`7f0a58ae0f4d5bfc76149435f4e322537089c5bd16e7ffe9b5ad71f10a621a07` |

All 215 canonical files (28714587 bytes) are independently
hash-verified. All seven cleanup grades pass, with no owned runtime
process or temporary root after each case. Automatic retries are zero.
The owned cloud host stopped normally after retention. The prior
profile-22 warm attempt remains failed and separately retained: archive
SHA-256
`1e54eba5ec72b50cee1534b23d1d1d4f21a090006b8a64501ba70db972abfde5`. Its
original canonical classification is preserved. Diagnosis reproduced a
product bug comparing an agent-files root against an unset
checkpoint-only field. The fix stores the admitted physical root
separately from the adopted per-run collection capability. The real-root
regression fails before the fix and passes afterward, including
rejection of a changed physical root. Fixture, grader, model and all
seven accepted case IDs are unchanged; this fresh campaign tests
final-reply publication after file registration first. The intermediate
restart attempt also remains failed and retained: archive SHA-256
`5dcaefdf1d17cf4cd54fd4cf810f45e736667392339b8ce7caf08bb4e225277f`. Its
original canonical classification is preserved. Pi resumed, wrote the
verified answer and completed its task; exact runner suspension was
proven, but idle stop consumed about 5.2s and left under 3s for the
drain acknowledgement. The Pi-only default shutdown grace is now 15s,
preserving a full 5s drain round trip and a finite suspension reserve.
Explicit caller deadlines, other provider defaults, literal drain
receipts and exact suspension identity checks remain unchanged. The
timing regression fails before this correction and passes afterward; all
18 focused settlement tests and Runner typecheck pass. The final-source
file attempt is also preserved as failed (`candidate_failure`), archive
SHA-256
`db6767b6773ea618997927ac77bdb005a5ac81492c7b9c0ffbc900449f829bc9`.
Native edit, validation, exact downloadable artifact and Done/succeeded
all passed, and the exact final reply was durably recorded. A workspace
recovery owner completed before the live heartbeat reached presentation,
leaving that reply absent from task chat. Recovery now materializes only
a completed final reply from the accepted turn of an ordinary internal
Done task, preserving issue/run/contract binding, suppression,
external-chat authorization and same-run deduplication. The database
regression covers the generated file-preparation receipt, suppression,
unapproved external continuation and replay. Server typecheck and all 49
response-selection tests pass; hosted Linux verifies the database
regression because embedded PostgreSQL cannot start on this Mac.

The delayed-final-answer database regression passes on [the final
root-source Linux server
shard](https://github.com/paperclipai/paperclip/actions/runs/37868262553/job/113628594152),
alongside 1,108 passing tests. The first root Runner shard had one
unchanged durable-resume test exceed its 5-second timeout; the identical
top-source shard and the isolated exact test passed. One rerun of that
failed job and its required aggregate passed without source or test
changes. The original failed job log and the single-rerun receipt remain
retained.

### October 9 merge verification

Current merge head: `5a8fe63512a7166aaef5cf50065a25008aa8b44b`. All
current-head checks pass, including `ci / verify` and `ci / e2e`;
exact-head Greptile review is 5/5 with no unresolved threads. Current
master conflicts are resolved. The user authorized the maintainer
override of the code-owner review gate after these checks. The seven
retained live core cases remain bound to source
`3241a992f2a7703e59e97ed0fd3e5d6405de4401` and its recorded cloud image.

## Risks

- The security correction changes the dependency closure and profile
identity. Old sessions must reopen on the new profile. Exact identities
and credential bindings fail closed.
- The runner remains experimental and requires explicit selection.
Legacy Pi Local is unchanged. Caller model IDs pass through; the E2E
model is a fixture.
- Accounting and the broad platform/provider matrix remain deferred.
This merge does not publish a release or deploy a service.

## Model Used

OpenAI GPT-6 through Codex assisted with reasoning, repository
inspection, editing and tool use. The exact serving ID and context
window are not exposed in this session. Final live qualification uses Pi
1.0.0 with `openrouter/anthropic/claude-sonnet-4.6` and native-confirmed
low thinking.

## 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-09 08:56:41 -05:00