Commit Graph
7726 Commits
Author SHA1 Message Date
Dotta d4e8906dc3 test(evals): verify rendered references inside saved task comments 2026-10-27 16:10:58 -05:00
DottaandPaperclip 77295faebc fix(server): recover approved tool actions from committed changes (#17454)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

## What Changed

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

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

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

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

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

## Verification

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


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

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 16:10:44 -05:00
Dotta d6f00a8136 test(evals): use genuine human origin for disabled chat probe 2026-10-27 16:10:07 -05:00
Dotta 945674fffe test(evals): retain ordinary catalog chat screenshots privately 2026-10-27 16:06:44 -05:00
Dotta 43aeb5c141 test(evals): accept concealed expired-session reads with full sign-in proof 2026-10-27 16:00:38 -05:00
Dotta 872988beb1 test(evals): reconcile runtime descriptors before campaign admission 2026-10-27 16:00:03 -05:00
DottaandPaperclip 35820cf398 fix(evals): qualify Runner model receipts with separate operating reconciliation (#17929)
## Thinking Path

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

## Linked Issues or Issue Description

Refs #17928, #17889.

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

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 15:41:07 -05:00
Dotta 50d9ecad91 test(evals): distinguish capability-view advice from target selection 2026-10-27 15:35:02 -05:00
Dotta ba87644fcf test(evals): preserve public effective assignment authority for hire denial 2026-10-27 15:29:20 -05:00
Dotta b41ccbe890 test(evals): reject incompatible target recommendations 2026-10-27 15:28:51 -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>
canary/v2026.1027.0-canary.9
2026-10-27 15:28:42 -05:00
DottaandPaperclip d108aeeaaf fix(server): schedule pending tool-review expiry from committed changes (#17453)
## Thinking Path

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

## Linked Issues or Issue Description

**What happened?**

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

**What did you expect?**

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

**Steps to reproduce**

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

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

## What Changed

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

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

## Verification

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 15:26:19 -05:00
Dotta acfd0340db test(evals): separate advertised target capability from SSH health 2026-10-27 15:25:13 -05:00
DottaandPaperclip bf3ef12f3a fix(evals): qualify model spend separately from operating costs (#17928)
## Thinking Path

> - Paperclip manages agent work and its budgets.
> - Product E2E campaigns must explain each model request and attempt.
> - The current completion gate also requires complete operating-cost
evidence.
> - Long-lived observability and storage charges can block a campaign
after its model receipts are complete.
> - An operator can now choose model-request readiness in a retained
allowance.
> - The report keeps full accounting, operating holds and model
readiness separate.

## Linked Issues or Issue Description

Refs #17889, #17523, #17452.

**What happened?**
A hosted campaign could pass both product cases and retain complete
model receipts, yet fail readiness because operating charges were
unresolved.

**Expected behavior**
An explicit model-readiness policy permits complete model receipts to
qualify a run. Unknown operating charges stay visible and reserved.
Missing model receipts and budget violations still block qualification.

**Steps to reproduce**
Use a campaign with four unresolved operating reservations and one
completed model request. The regression checks readiness before and
after the final model receipt, then checks an operating overrun. The
default policy retains the original full-accounting gate.

## What Changed

- Add the explicit `accountingReadiness: "model_requests"` allowance
policy. Bind it into operating-bound configuration when present.
- Derive a model subtotal and receipt-coverage projection from the
retained journal. Show it beside full accounting and retained holds.
- Use the selected readiness policy in scheduled finalization. Keep
product, cleanup, feedback, trace and budget checks.
- Refresh two existing eval prerequisites found by the full unit suite:
the active Copilot image identity and the model-account catalog mapping.
- Document the policy and its limit: it does not certify a
full-lifecycle operating-cost ceiling.

## Verification

- Regression failed on the old implementation with `Invalid operating
overhead fields` and passed after the change.
- Focused accounting/operations/finalization checks: 54 tests passed
before the final policy assertions.
- Existing image/catalog failures reproduced, then their 12 checks
passed after the metadata repairs.
- Product E2E unit suite: 4,360 passed and 2 skipped, plus 137 Node
checks. Product E2E and workspace typechecks and workspace build passed.
- Review regressions: 35 focused accounting/finalization checks passed
on 4aeb8bd65c, including the optional-policy hash and the scheduled
consumer.
- Full local server tests encountered embedded PostgreSQL bootstrap
failures; retained output is not a passing full-suite claim. Hosted CI
remains required.
- Final head 4aeb8bd65c: all 57 check runs pass or are skipped, the
legacy security status passes, both reviews are 5/5 and no review
threads remain open.
- No paid campaign or schedule activation is claimed by this PR.

## Risks

The opt-in policy permits readiness while operating costs remain
unreconciled. The report retains full-accounting status and all holds.
The gateway still reserves requests inside the same total allowance.
This is an admission limit, not a vendor invoice guarantee. The omitted
policy keeps existing behavior. Old journals remain unchanged.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 15:10:26 -05:00
DottaandPaperclip 1c72e2d74e test(evals): retain genuine setup health pass evidence
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 15:08:29 -05:00
DottaandPaperclip 5398275d2a fix(server): schedule gateway credential expiry from committed changes (#17450)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

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

## What Changed

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

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

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

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

## Verification

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

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

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

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

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

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

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

## Linked Issues or Issue Description

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

**What happened?**

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

**Expected behavior**

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

**Steps to reproduce**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Paperclip <paperclip@paperclip.ing>
2026-10-27 14:53:32 -05:00
DottaandPaperclip 623f1dc289 fix(server): schedule secret-proposal expiry from committed changes (#17446)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents can propose secrets and bindings for approval.
> - Pending proposals already contain their expiry and encrypted value.
> - The server scans for expired proposals on every maintenance tick,
even when none exist.
> - Committed proposal changes and saved expiry times provide the
required triggers.
> - This PR uses those triggers and preserves scrubbing, approval
checks, and recovery.
> - Empty and completed proposal history no longer causes recurring
expiry queries.

## Linked Issues or Issue Description

Refs #17443. This is the second PR in the sleep migration stack and
targets its branch.

**What problem does this solve?**
The periodic proposal scan contacts PostgreSQL when no proposal needs
maintenance. That obstructs idle database behavior across tenant
instances.

**What is the proposed solution?**
Use transaction-aware notifications for creation and resolution.
Reconstruct the earliest pending expiry at startup. Run cleanup at that
deadline, or retry while reconciliation remains unfinished.

**Why is this useful?**
It removes an idle scan while retaining security checks and physical
ciphertext cleanup. No queue table or migration is required.

## What Changed

- Added intent notifications before secret/binding creation, approval,
terminal transitions, and linked interaction resolution. The existing
outer transaction owns settlement.
- Kept expiry selection, ciphertext scrubbing, dependent rejection, and
authorization in the secret-proposal service.
- Registered a startup and deadline worker in place of the aggregate
maintenance sweep. Empty/terminal states disarm; overdue batches and
failures retain retries.
- Reused shared scoped deadline dispatch for secret expiry. The service
owns company-filtered SQL and expiry policy. Custom-image expiry
continues to use `registerDeadlineWork`.
- Added real PostgreSQL producer, outer-transaction, concurrent-write,
expiry, restart, interaction resolution, and drain/resume tests. Updated
startup wiring fixtures and documented the supported writer/lifecycle
contract.

## Verification

- Landing reconciliation at `c10eb1bcf752b058713e05d3345e5cf38dd3fa72`:
160 tests pass across the complete secret-proposal, scoped deadline,
company batch, coordinator, startup, custom-image service and
custom-image worker suites; no cases skipped in the accepted runs.
Server typecheck passes. This integrates master after #17443 landed;
fresh remote CI and Ponytail review are required before merge.

Current head: `5bbe17ad9ebc4573b08ed1a9323644ef9608ca09`. This remains a
single-duty PR stacked on #17443.

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

## Risks

- Notifications cover supported writers sharing the database signal
owner. Independent SQL writers and other process roots require a
separate ingress contract; startup recovery alone is not live replica
support.
- The shared coordinator and scoped worker also serve later stack
duties. Their defaults remain intact; existing voice, chat, native, and
startup consumers are included in integrated verification.
- Startup now checks overdue proposals immediately. During drain,
physical cleanup waits; approval still rejects expired proposals
synchronously.
- Each due company pass remains bounded to 100 rows. Failed scopes back
off from 30 seconds to five minutes; healthy overdue work keeps
draining. Self-generated write hints coalesce and do not erase a failed
sweep's backoff.
- Heartbeat-disabled behavior and Cloud sleep-safety gates remain
unchanged. This does not establish deployed suspension or external wake
coverage. Tool review and gateway token cleanup remain separate slices.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1027.0-canary.8
2026-10-27 14:36:28 -05:00
DottaandPaperclip 5982246771 fix(server): schedule custom-image setup expiry from committed changes (#17443)
## Thinking Path

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

## Linked Issues or Issue Description

**What happened?**

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

**What did you expect?**

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

**Steps to reproduce**

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

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

## What Changed

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

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

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

## Verification

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

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

## Risks

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

## Model Used

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

## Checklist

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

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 14:17:01 -05:00
Dotta 2f68f4ff3c fix(evals): display existing campaign summary inline 2026-10-27 13:35:34 -05:00
DottaandPaperclip b3c77ff304 test(evals): check remote OpenRouter key before setup hello
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 13:35:33 -05:00
DottaandPaperclip 5b54009a03 test(evals): retain frozen chat scope across merged capability maps
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 13:11:41 -05:00
DottaandPaperclip e0b2fec56f Merge pinned master 50b932a142 into preserved chat campaign candidate
Preserve existing campaign measurements and initial ordinals; incorporate already-merged production behavior only. No live qualification claimed.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 13:07:03 -05:00
DottaandPaperclip 78de49f09d test(evals): use ordinary embedded Postgres on AWS chat
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 12:44:48 -05:00
DottaandPaperclip 50b932a142 fix(server): require approval before onboarding task creation (#17914)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/78/changes/paperclip/78
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip manages agent work and human decisions.
> - Onboarding asks the first agent to propose a task before it starts
work.
> - The first-task skill requires human acceptance before task creation.
> - The native tool could create and schedule that task without
acceptance.
> - REST task creation had the same gap.
> - This change checks saved acceptance in the shared creation
transaction.
> - Valid approvals and ordinary delegation keep their existing
behavior.

## Linked Issues or Issue Description

**What happened?**

An agent could create a task from the canonical onboarding first task
before the user accepted its proposal. A real journey caught this after
the agent read the first-task skill. A local database regression
reproduces the missing check in the native tool and both REST creation
endpoints.

**Expected behavior**

New task creation must wait for saved human acceptance of the latest
ordinary proposal. A different parent or a standalone task must not
bypass that check.

**Steps to reproduce**

1. Bind an authenticated agent run to a server-created onboarding first
task.
2. Leave its proposal unaccepted.
3. Call native `create_task`, `POST /api/companies/:companyId/issues`,
or `POST /api/issues/:issueId/children`.
4. Before this fix, creation succeeds. After this fix, it is denied
before a child or wake is committed.

**Paperclip version or commit**

Reproduced on `3be54534c24fc279533ff421e62a77ad15b72954` before the fix.

## What Changed

- Add a shared check for new task creation from an authenticated
onboarding run.
- Read the latest ordinary confirmation across both confirmation kinds
under the source task lock.
- Require a human card decision or validated conversational acceptance.
Require the current revision for a saved plan.
- Preserve ordinary delegation, committed replay, and dispatch recovery.
- Add database regressions and update execution and onboarding map
documentation.

## Verification

- Real PostgreSQL regression before the fix: 17 failures and four
passing approval/delegation controls. No skips.
- Exact published source: 102 tests passed across admission,
conversational confirmation, and project tools, including all 25
admission regressions. Real Linux PostgreSQL, no skips.
- `pnpm build` and `pnpm -r typecheck` passed locally.
- Map checks and `git diff --check` passed.
- `pnpm test:run` was attempted locally. Existing suites failed because
the host exhausted PostgreSQL semaphore sets. The remaining owned test
process was stopped; its failed log is preserved. No unrelated database
was stopped. Current-head Linux CI passed, including build, typecheck,
and browser E2E. The first CI attempt lost runners; its evidence is
preserved, and interrupted jobs passed one CI rerun.
- The live Cloud attempt remains failed. Local tests do not qualify
Cloud onboarding, artifact delivery, or native tracing. No deployment or
model retry is part of this change.

## Risks

A stricter creation check could reject a valid approval. Tests cover
direct, conversational, checkbox, dismissed-card, and clock-skew cases.
The check applies only to new tasks from the canonical onboarding run.
It does not change existing task updates, execution policy, or wake
recovery.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 12:30:50 -05:00
Dotta e68d1a8044 fix(evals): preserve retained model in discovered suite profiles 2026-10-27 12:28:24 -05:00
DottaandPaperclip 8eb98eb527 test(e2e): retain sanitized setup health failure detail
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 12:27:50 -05:00
DottaandPaperclip 6e781e0ab2 fix(connections): preserve removed grants when saving installs (#17906)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Connections give agents access to external tools through access
profiles.
> - Operators can remove a broad app profile and keep a limited profile.
> - Saving a connection's agent list restored the broad profile to
existing installation targets.
> - Those restored grants could permit write tools that the limited
profile omitted.
> - This pull request grants the app profile only to new installation
targets.
> - The benefit is stable permission choices when an operator edits an
installation list.

## Linked Issues or Issue Description

**What happened?**

`PUT /api/tool-connections/{connectionId}/installs` attached the app
profile to every target in the submitted list. An existing target
received the profile again if an operator had removed it. Adding an
agent, removing another agent, or saving the same list could therefore
restore broad tool permissions. The activity log recorded each restored
binding as `tool_connection.install_access_extended`.

**Expected behavior**

Targets that remain installed keep their saved profile assignments. A
removed app-profile assignment stays removed. New installation targets
receive the current app-profile defaults. Removing an installation still
removes its install-derived binding.

**Steps to reproduce**

1. Install a connection with read and write tools on two agents.
2. Give one agent a read-only profile and remove its broad app-profile
assignment.
3. Save the installation list, add an agent, or remove the other agent.
4. Check the first agent's permission to use the write tool.

Before this change, the write tool becomes allowed again. After this
change, it stays denied.

Related: #17422 adds an agent-edit permission check to direct profile
bind and unbind operations. This PR preserves removed assignments during
installation-list updates. The duplicate search found no open PR for
this defect.

## What Changed

- Attach app-profile bindings only for new installation targets.
- Preserve removed grants for existing agent and company installations.
- Keep legacy connection-wide include cleanup on every non-empty
installation save, including saves with no added targets.
- Add six PostgreSQL regressions. All six use the real install HTTP
route with a local operator fixture.
- Check effective read/write decisions, saved assignments, new-agent
defaults, uninstall cleanup, legacy-rule cleanup, and access-extension
audit records.
- Document the behavior in the connector runbook and both access maps.

## Verification

- Red: all four new regressions fail before the fix. The policy returns
`allow_profile` where the tests require `deny_default`.
- Review regression: the two legacy-rule cases fail before the review
correction. The original four cases still pass.
- Green after review: all six regressions and five existing
profile-precedence tests pass after the correction.
- Command: `pnpm exec vitest run
server/src/__tests__/tool-connection-installs.test.ts
server/src/services/tool-profile-binding-precedence.test.ts`.
- The local regression used `PAPERCLIP_TOOL_ACCESS_TEST_DATABASE_URL`
with a separate, fully migrated PostgreSQL 17 test database. Embedded
PostgreSQL could not start because the host had reached its semaphore
limit. Skipped tests were not counted as a regression pass.
- `pnpm -r typecheck` and `pnpm build` passed for the initial fix.
Server `tsc --noEmit` also passes after the review correction.
- `node scripts/check-maps.mjs`, `node
scripts/check-module-boundaries.mjs`, and `git diff --check` pass.
- `pnpm test:run` was started, then stopped after 16 tests in the
native-session suite failed during embedded PostgreSQL startup. A
focused rerun of its `collect` case confirmed the database startup
error. Direct `initdb` output reported `could not create semaphores: No
space left on device`. The full local suite is incomplete. All six new
regressions executed against the separate test database and passed.
- [Initial-fix
CI](https://github.com/paperclipai/paperclip/actions/runs/40541191695)
passed at `23253ee332b90f142e48df3f553aeaaa7f6fa298`. Greptile gave that
commit 5/5. Ponytail found the legacy cleanup gap; this revision
restores that cleanup and adds both regression cases.
- [Current-commit
CI](https://github.com/paperclipai/paperclip/actions/runs/40547366181)
passes for `729c487cf2ffaae261a820de0cf9a033a0365fd4`, including type
checks, build, test shards, and both `ci / verify` and `ci / e2e`
aggregate checks.
- The first CI attempt hit a 30-second module-import timeout in the
unchanged `issue-agent-mutation-ownership-routes.test.ts` suite. All 179
tests passed locally. One [job
retry](https://github.com/paperclipai/paperclip/actions/runs/40547366181/job/122349226221)
passed without a code change. The cause of the import slowdown was not
established. The failed attempt remains recorded in CI history.
- Greptile and Ponytail both give the current commit 5/5 with no
actionable findings. Ponytail confirms the legacy cleanup finding is
fixed. The review thread is resolved, and the PR has no merge conflicts.
Ponytail's advisory check has a neutral conclusion with a 5/5
assessment.

## Risks

- New installations retain the current app-profile defaults. Removing
and then reinstalling a target is a new installation.
- A repeated installation save no longer restores a missing profile
assignment. Operators must use an explicit profile assignment when they
want to restore that grant.
- Existing unwanted grants still require a separate access review and
repair. This PR does not change stored grants, reconnect identity
behavior, or the default access model.
- No database migration or API schema change is required.

## Model Used

- OpenAI GPT-6 in Codex, with reasoning, repository tools, and code
execution. The session does not expose the exact routed 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 12:25:01 -05:00
Dotta 93d635a806 fix(evals): link existing campaign summary when present 2026-10-27 12:24:44 -05:00
Dotta 3605d08784 docs(evals): preserve remote timings and incomplete journey scope 2026-10-27 12:22:25 -05:00
Dotta 36dc8027e9 fix(evals): bind role clarification and reject current skill denial 2026-10-27 12:21:30 -05:00
Dotta ba0da21ddc fix(evals): ground blocked journey oracles in public state 2026-10-27 12:21:30 -05:00
Dotta 17551f7c04 fix(evals): implement access invitation checkpoints and membership baselines 2026-10-27 12:21:30 -05:00
DottaandPaperclip f6ba9afab0 perf(server): narrow explicit continuation run reads (#17896)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Recovery must prove that old execution stopped before it admits new
user input.
> - Explicit continuation reads the source run before and after it takes
the run lock.
> - Both reads transfer the saved prompt and the full Runner profile.
> - The preflight needs only identity, comment, adapter, and workspace
receipt fields.
> - This pull request narrows those reads and keeps the complete locked
profile for session proofs.
> - The benefit is less database transfer with the same admission and
recovery rules.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Explicit native continuation admission after a failed or stopped run.

**Current behavior**

The preflight and locked reread select complete heartbeat run rows.
Large saved contexts and execution profiles cross the database
connection twice.

**Proposed behavior**

Read only required scalar fields and typed context keys. Read only
historical adapter identity and workspace sync receipts before the lock.
Keep the complete Runner profile in the locked reread. Keep lock order,
company scope, text lookup of historical run IDs, stop proofs, queued
input, and replay rules.

**Reason and benefit**

A synthetic PostgreSQL 17 fixture removes 74.9% of the two queries'
DataRow bytes. This result is local query evidence. It is not a claim
about deployed latency or monthly transfer.

**Breaking changes**

None intended. No schema, API, migration, workflow, or dispatch contract
changes.

**Additional context**

Related: #17491 narrows the separate execution blocker read path. This
PR covers explicit continuation admission. The PR has no dependency on
the other byte reduction PRs.

## What Changed

- Select required continuation fields and typed context keys instead of
complete run rows.
- Read a small historical adapter/workspace profile during preflight.
Preserve the full locked profile for exact suspended-session and
quarantined-cleanup proofs.
- Narrow four helper input types to their actual field requirements.
Their runtime behavior is unchanged.
- Add real PostgreSQL admission comparison coverage and a reproducible
baseline/treatment benchmark.
- Document the query boundary and benchmark command.

## Verification

- Baseline: `663fe667d66d3863d0919a8724f1d99500feef0b`.
- Disposable PostgreSQL 17.11. One source run has a 192 KiB
incompressible context and two 96 KiB profile payloads.
- Command: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-continuation-run-reads.ts
--baseline-ref=663fe667d66d3863d0919a8724f1d99500feef0b`. Set
`PAPERCLIP_CONTINUATION_BENCHMARK_DATABASE_URL` to a disposable database
ending in `_test` to use an external server.
- The harness captures SQL generated by both real service versions.
Baseline imports use current helpers; only their TypeScript input types
changed in this PR. Their runtime behavior stays fixed.
- Preflight DataRow bytes: 394,067 to 466 (99.88% less). Locked reread:
394,067 to 197,168 (49.97% less). Combined: 788,134 to 197,634 (74.92%
less).
- Byte counts cover exact PostgreSQL text-format DataRow frames. They
exclude RowDescription, command metadata, TLS, TCP, and other queries in
the service.
- Seven measured samples per query follow two warmups. The order
alternates. Final-head median preflight time: 6.53 to 2.28 ms (ranges
5.34–7.41 and 1.84–4.46 ms). Median locked read: 8.06 to 5.26 ms (ranges
5.94–13.84 and 4.61–6.81 ms). These are warm local SQL measurements
under shared machine load. The deterministic byte counts are the
acceptance criterion; these noisy timings do not establish a deployed
latency gain.
- The harness compares the admitted continuation, blocked reasons, every
retained scalar column, kept JSON, and the full locked profile. It fails
unless the fixture removes more than half of the two reads' DataRow
bytes. It records SQL, parameters, revision identity, samples, and
EXPLAIN plans.
- All 291 continuation tests pass together on the final head with no
skips in a clean isolated PostgreSQL 17 database. This includes all
seven new projection comparisons and six malformed/missing JSON cases.
- Edited server TypeScript check passes: `node
node_modules/typescript/bin/tsc --noEmit -p server/tsconfig.json`.
- `pnpm -r typecheck` and `pnpm build` pass on the final head. The
normal server build verifies the complete pinned Copilot closure. Local
full `pnpm test:run` is not claimed: host embedded PostgreSQL startup
limits prevent that gate. The isolated PostgreSQL regressions pass; the
full exact-head test matrix runs in CI. The targeted exact-head test
retry passes all 4,086 tests in 98 files. All CI verification checks and
the dependent aggregate are complete and successful on head
`47c1b5f7d17a58310f7a3ebd494fdcaa814777c2`. Greptile completed cleanly
on head `47c1b5f7d17a58310f7a3ebd494fdcaa814777c2`: 5/5, no findings,
and no unresolved review threads.
- Local setup evidence: embedded initdb could not load its ICU data
library. Tests therefore use a dedicated PostgreSQL 17 container. A run
against reused test fixtures produced stale sweep failures; a new clean
database passed all 285 cases. The first comparison mock replaced an
unrelated aliased query; it was narrowed to the two admission reads
before the clean pass.

- The first [server test shard
6/12](https://github.com/paperclipai/paperclip/actions/runs/40529210562/job/122277218565)
failed one existing workspace-recovery case: a third export stayed
`scheduled` at its 20-second poll deadline; 4,085 other tests passed.
The exact case passes on the pinned baseline and final head with the
same PostgreSQL 17 fixture. Temporary spies recorded zero calls to both
changed admission functions in either replay. Other touched helpers have
type-only changes. This supports one timing-flake retry; the exact
scheduler delay remains unproven. The single [targeted shard
retry](https://github.com/paperclipai/paperclip/actions/runs/40529210562/job/122285744135)
passes all 4,086 tests in 98 files. The exact case completes in 17.25
seconds. The dependent aggregate is complete and successful. No timeout
or unrelated runtime code was changed.

- The separate Paperclip Review check ended `NEUTRAL` without a final
report. The completed source review is the exact-head Greptile 5/5
result above.

## Risks

- A future admission check may need an additional saved context key.
Keep the projection and helper contracts in sync with that consumer.
- Exact suspended-session and quarantined-cleanup proofs still require
the complete Runner profile. This PR retains it under the lock rather
than weakening those checks.
- JSON values retain their types and missing keys stay absent.
Malformed-context comparisons preserve the existing controller hold.
- These measurements use synthetic local data. Deployed transfer savings
require a fresh capture after rollout. Nothing was deployed.

## Model Used

OpenAI GPT-6 through Codex. The exact runtime model ID and context
window are not exposed by this session. The work used repository tools,
code execution, and real PostgreSQL validation.

## 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 12:05:51 -05:00
DottaandPaperclip 6e5b9794d6 perf(github): avoid duplicate webhook body reads (#17894)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub webhooks enter a durable action queue before the worker
processes them.
> - A worker must check retry eligibility and win an atomic claim before
it replays a delivery.
> - The current eligibility read returns the complete webhook body, and
the successful claim returns it again.
> - This pull request reads small eligibility fields first and returns
the body only to the successful claimant.
> - The worker keeps its retry, ownership, runtime, credential, and
recovery checks.
> - The benefit is less database transfer without removing durable
replay data.

## Linked Issues or Issue Description

Refs: #17666, #15981. Those changes own the existing recovery scheduler
and ingress module. This PR changes the result projections and
validation order within that module. It has no dependency on another
open PR. A public issue and PR search found no duplicate change.

**What existing behavior does this improve?**

The durable GitHub webhook worker reads action eligibility and replays
claimed deliveries.

**Current behavior**

The first read returns all action columns and the complete webhook body.
A successful claim returns them again. An active claim or future retry
also downloads a body that this worker cannot process.

**Proposed behavior**

Read only ID, status, result, and update time for eligibility. Return
ID, endpoint ID, and payload from the successful atomic claim. Validate
that claimed payload before replay.

**Reason and benefit**

A synthetic 131,105-byte webhook body produces about 263 KB of response
values before this change. The changed service returns about 132 KB for
successful processing and fewer than 150 bytes for skipped work. This
removes duplicate body transfer.

**Breaking changes**

There is no public API or schema change. Malformed active or delayed
rows now remain under their current claim or retry deadline. The
eligible claimant validates and fails them later. A worker that does not
own the claim can no longer clear their payload.

## What Changed

- Use a small projection for initial action eligibility.
- Return the replay body only from a successful claim. Keep the existing
status, stale-time, and previous-attempt guards.
- Validate the row returned by the claim. Fence invalid-payload
settlement by kind, processing status, and the claimed attempt.
- Add 19 real PostgreSQL regressions for complete replay bodies, skipped
work, retries, stale-claim recovery, contention, corrupt bodies, claim
loss, replacement bodies, and payload retention.
- Wait for the saved chat authentication link in one existing async UI
test. Keep its exact destination and all other assertions. This repairs
a second independent CI test failure without changing product UI.
- Accept the two precise invalid-repository diagnostics from Git 2.55
and 2.56 in one existing test. This repairs an independent CI
compatibility failure. It changes no Git expiration service behavior.
- Add a reproducible benchmark that loads the real baseline service from
an explicit commit. It captures generated SQL and parameters, query
plans, response-value estimates, timings, and complete valid-work
behavior comparisons.

## Verification

- Baseline: `663fe667d66d3863d0919a8724f1d99500feef0b`.
- PostgreSQL 17.11, Node 24.22.1. The fixture uses synthetic random body
content. No hosted database or provider was changed.
- `pnpm exec vitest run
server/src/services/chat-channels/github/webhook-ingress.test.ts`: 19
passed with a dedicated disposable PostgreSQL database.
- Existing assembled GitHub tests: recovery from pre-ingress failure,
scheduler retry and restart, exact terminal redelivery, runtime
pause/resume, recovery tombstones, and credential rotation passed.
- `node scripts/check-module-boundaries.mjs` and `git diff --check`:
passed.
- Benchmark: `node --import ./server/node_modules/tsx/dist/loader.mjs
scripts/benchmark-github-webhook-ingress.ts
--baseline-ref=663fe667d66d3863d0919a8724f1d99500feef0b`. The default
uses disposable embedded PostgreSQL. `PAPERCLIP_TEST_DATABASE_URL` can
select a dedicated migrated test database with a name that ends in
`_test`.
- Ten timed samples after two warmups, with alternating
baseline/treatment order. The main acceptance criterion is response
size, rather than a timing threshold. The 0.51 ratio bound is
deterministic for this fixed synthetic fixture; it is not a promise for
arbitrary webhook bodies or result metadata sizes. Focused tests measure
the body transfer reduction directly. Actual wire savings require
post-rollout measurement.

| Scenario | Baseline response-value bytes | Changed response-value
bytes |
| --- | ---: | ---: |
| Received | 263,276 | 131,547 |
| Due retry | 263,342 | 131,613 |
| Stale processing | 263,291 | 131,563 |
| Future retry | 131,692 | 136 |
| Active processing | 131,642 | 86 |
| Processed | 131,659 | 103 |

The benchmark compares response status/body, all stable durable action
fields, and the replay body, signature, delivery ID, and provider
routing. All six valid scenarios match. It excludes generated row IDs
and timestamps. The final measurement records treatment commit
`f1ad8ce838700237b56f895cc61a9c6ed0850cd6`, an empty initial worktree
status, and the SHA-256 of the actual source. It ran from the server
directory to verify that Git paths resolve from the repository root.
Local timing ranges overlap and vary with host load. An earlier loaded
repeat had a due-retry median of 19.61 ms before and 22.58 ms after, so
no consistent latency gain is claimed. The byte reduction is the
verified result. Response-value estimates exclude PostgreSQL
protocol/TLS overhead and JSONB whitespace. These are local
measurements, not a claim about deployed latency or a monthly bill.

`pnpm -r typecheck` and `pnpm build` passed on production-change commit
`6f4f36bff525494dadda30b49ea6a9a33976e1ab`. Greptile completed with 5/5
and no review threads on that commit. Commit
`2abf9b1e50c568b632e7568398a5826a6122e456` changes only the Git test
matcher. Commit `f1ad8ce838700237b56f895cc61a9c6ed0850cd6` fixes
benchmark provenance after automated review. Commit
`ee2a96dad549c72da3132d2b93fd11eb1c45bc31` repairs an existing async UI
test. Final commit `994d398d12be65f595b305d1c2f8a61b9d587ff9` extends
real PostgreSQL contention coverage after review. Full CI completed
successfully on that final head: [workflow run
40537698349](https://github.com/paperclipai/paperclip/actions/runs/40537698349).
All 55 successful checks, one neutral review, and two optional skipped
checks are terminal; none are pending or failing. Fresh Greptile and
Paperclip reviews are both 5/5, with zero unresolved review threads. The
production source SHA-256 remains
`402f9c66cd030c9ded9f39a3bc72d26c56627752c0950b102adcab15c4512df3`, so
the production proof is unchanged. The full local `pnpm test:run` was
not completed because this host exhausted embedded PostgreSQL semaphore
resources; the focused real PostgreSQL tests used a private disposable
container. Current-head remote CI passed the full suite. A direct server
typecheck before runner preparation reported missing runner build
outputs; supported preparation and the full typecheck then passed. The
first complete build found a partial local Copilot closure from the
dependency cache. The complete pinned closure was restored and verified,
then the complete build passed. The first local test run also found a
fixture teardown order error; the teardown was corrected, then all 17
tests passed. Frozen dependency installation failed on the existing
master patch metadata. Independent cached dependency directories were
cloned, their workspace links were checked, and no dependency manifest
or lockfile was changed.

The first CI server4 shard failed one existing Git expiration test: Git
2.56 reported `gitfile does not point to a valid repository`, while the
test expected the Git 2.55 phrase `not a git repository`. The service
returned the correct `inspection_failed` result and preserved the
workspace. Separate test-only commit
`2abf9b1e50c568b632e7568398a5826a9c6ed0850cd6` accepts either precise
diagnostic. The affected assembled test passed locally with real
PostgreSQL 17.11 and Git 2.55; the captured CI diagnostic also matches,
and unrelated permission errors do not. This was a compatibility
failure, not a transient failure or an unchanged rerun.

Paperclip Review found that the benchmark recorded its own scratch
directory as an uncommitted change. The final benchmark-only repair
captures repository status before scratch creation, runs Git commands
from the repository root, records the source hash before measurement,
and rejects source edits during measurement. A full benchmark run from
the server directory then reported clean provenance and passed all six
byte/behavior comparisons. The review thread was marked addressed after
this proof.

The next full CI run found a separate unchanged UI test failure in
`ConnectionIntentInteractionBody.test.tsx`: the saved authentication
link was still absent after one fixed flush. The same failure reproduced
locally: one failed and 50 passed. Separate test-only commit
`ee2a96dad549c72da3132d2b93fd11eb1c45bc31` uses the existing bounded
`waitForAssertion` helper around the identical destination assertion.
The whole file then passed all 51 tests, and UI token gates passed. The
no-extra-setup and no-automatic-completion assertions remain. No UI
runtime or timeout changed.

Paperclip Review also asked for parallel claims from stale-processing
and due-failed rows. The contention test now covers those states and
received rows. Each case holds the claims until all 12 workers have read
the same eligible attempt, then uses real PostgreSQL to assert one
replay and exactly one attempt increment. The whole focused suite passed
all 19 tests. This coverage change does not modify production code or
the measured queries. The review thread was marked addressed after this
proof.

## Risks

- Payload validation now follows claim commit. If the process stops
there, the existing stale-claim recovery path retains the body and
retries it. Tests cover fresh and stale processing rows.
- A malformed future retry now fails when due instead of being cleared
by an unrelated early worker. The claimed-attempt guard prevents invalid
settlement from overwriting a later claim. Terminal invalid-payload
settlement intentionally retains the baseline result shape (`code` and
`retryable: false`, without `attempts`). Changing that result contract
is outside this byte reduction; the non-retryable row cannot become due
again.
- Existing runtime-generation, credential, recovery-source,
replay-barrier, redaction, and retry checks remain in place. Existing
assembled tests cover these boundaries.
- There is no migration, startup job, dependency change, or deployment
in this PR.

## Model Used

- OpenAI GPT-6 through Codex. The exact runtime model ID and context
window are not exposed by this environment. Capabilities used: source
analysis, code editing, shell tools, PostgreSQL experiments, and
automated tests.

## 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 (The
public contract is unchanged; benchmark usage and evidence are
documented above.)
- [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 12:05:30 -05:00
DottaandPaperclip 7a0c9c23cf perf(github): reduce inherited review-wait transfer (#17893)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review tasks can retain a passive wait after a review is
published.
> - The wait check reads current requester, task, agent, repository, and
publication bindings.
> - It also transfers the complete assessment for one commit comparison.
> - Large review summaries and findings add repeated database transfer.
> - This pull request selects only the typed reviewed commit value.
> - The wait keeps its existing checks and transfers less data.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The inherited GitHub review-wait check in the server.

**Current behavior**

The joined query selects the complete assessment JSON. The caller uses
only `assessment.reviewedCommit`.

**Proposed behavior**

Select `assessment->'reviewedCommit'`. Keep its JSON type and the strict
comparison with the head SHA. Keep all joins, filters, ordering, and
publication checks.

**Reason and benefit**

The synthetic PostgreSQL 17 fixture reduces one result DataRow from
6,874 bytes to 423 bytes (93.85%). This measurement excludes response
metadata, TLS, and TCP. It does not predict a monthly bill or deployed
savings.

**Breaking changes**

None. No public API, stored data, schema, or execution policy changes.

**Additional context**

Related work: #17562 narrowed a different external-review candidate
query. This PR changes the inherited published-review lookup. The
duplicate search found no matching open change.

## What Changed

- Select the commit as JSON, rather than text, to preserve strict
comparison for legacy numeric, object, array, missing, and null values.
- Add real PostgreSQL regressions for narrow responses, unchanged stored
assessments, revocation, tenant and agent bindings, and a newer queued
head.
- Add a synthetic benchmark that captures the real baseline and
treatment SQL, compares outputs, and measures raw DataRow bytes.
- Document the read contract and benchmark command.

## Verification

- Baseline: `663fe667d66d3863d0919a8724f1d99500feef0b`.
- `vitest run server/src/__tests__/github-review-wait.test.ts`: 14 tests
passed on disposable PostgreSQL 17.11.
- Restoring the baseline query makes the response-size regression fail:
8,823 column-value bytes exceed the 1,000-byte bound. Restoring
treatment passes.
- Benchmark: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-github-review-wait.ts
--baseline-ref=663fe667d66d3863d0919a8724f1d99500feef0b`.
- The benchmark compares every unchanged SQL column and full service
output. It also compares 15 JSON cases and live connection revocation.
- Two warmups and seven alternating samples had overlapping latency
ranges. No latency improvement is claimed.
- `pnpm -r typecheck` and `pnpm build` passed locally.
- Twenty existing published-review consumer regressions passed on
PostgreSQL 17.11. These cover continued review, a newer head,
publication state, and a connection-disable race at final commit.
- Final-head focused tests passed again after the benchmark-only review
fix.
- Final benchmark treatment: `d94410a6e6bb83e727afdf09cff450a91a89edd6`,
with an empty source diff. DataRow bytes remained 6,874 to 423. Warm
medians were 3.11 ms before and 3.43 ms after, with overlapping ranges.
This proves byte reduction, not a latency improvement.
- A provenance check with one staged and one unstaged source edit
confirmed that the benchmark records both from the documented server
working directory. Those temporary edits were removed.
- All final-head CI checks passed for
`d94410a6e6bb83e727afdf09cff450a91a89edd6`. Greptile scored this exact
commit 5/5. There are zero unresolved review threads or recommendations.
The independent Paperclip review also scored this commit 5/5.
- The first local embedded PostgreSQL attempt failed before assertions
because the host exhausted System V semaphores. A direct `initdb`
reproduced `could not create semaphores: No space left on device`. The
passing focused proof used an owned disposable Docker PostgreSQL 17
container. `pnpm test:run` was not completed locally because of that
host limit. The full final-head CI suite passed.
- The final CI aggregate briefly reported `in_progress` after all of its
steps and the workflow had completed successfully. One rerun of only
that aggregate produced a terminal success. The test matrix was not
rerun.
- The initial frozen install hit the existing upstream patch/lock
configuration mismatch. A cached non-frozen local install succeeded. The
generated lock change is excluded from this PR.

## Risks

The selected commit must retain its JSON type. Using `->>` could turn
numeric `1` into text and accept a malformed assessment against head
`1`. The regression covers this case. The complete assessment remains
available for actual review and publication. Existing fresh authority
checks remain in place. No migration is required.

## Model Used

OpenAI GPT-6, accessed through Codex. The exact runtime model ID and
context-window size were not exposed in this session. Used repository
inspection, code execution, and PostgreSQL validation.

## 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 12:05:01 -05:00
DottaandPaperclip 139d83b777 test(evals): add explicit zero-work chat setup health
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 11:48:17 -05:00
DottaandPaperclip e10d068130 test(evals): retain closed same-call readiness diagnostics
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-27 11:48:17 -05:00
Dotta 92c2cdaa5b docs(evals): link published historical and remote setup reports 2026-10-27 11:48:17 -05:00
DottaandPaperclip 8548173fc9 feat(evals): connect hosted Runner costs and traces (#17889)
## Thinking Path

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

## Linked Issues or Issue Description

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

**Current behavior**

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

**Proposed behavior**

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

**Reason and benefit**

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

OpenAI Codex, GPT-6-based coding agent with tool use and code execution.
The host does not expose an exact deployment model ID or context-window
size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 11:38:16 -05:00
DottaandPaperclip 585b4e6af8 fix(chat): preserve deferred Retry source batches (#17883)
## Thinking Path

> - Paperclip manages agent work through tasks and governed execution.
> - Connected conversations retain the source and authority for each
request.
> - Task Retry pins the full saved GitHub input batch before it waits
for cleanup.
> - Resuming that wait could append an independent board queue after
authorization.
> - Dispatch then rejected the changed batch before the provider
started.
> - This pull request keeps the authorized batch intact and restores
certified undelivered input from historical failed attempts.
> - Each board message retains a separate turn and its own admission
checks.

## Linked Issues or Issue Description

**What happened?**
A deferred GitHub task Retry could consume a separate board message
while promoting its saved receipt. The new run then failed with
`chat_failed_run_retry_not_authorized`. A second Retry could also fail
because the historical run retained the mixed batch.

**Expected behavior**
Retry must preserve the source batch it authorized. Separate board input
must keep its own execution path. Historical input may be restored only
when durable evidence proves that the rejected attempt never started a
provider.

**Steps to reproduce**
1. Retain ten authorized GitHub requests behind a failed native turn.
2. Start task Retry while the predecessor still lacks its exact
termination receipt.
3. Save an independent board message.
4. Complete cleanup and resume the same Retry receipt.
5. Observe the mixed batch rejected during dispatch. Retry that failed
attempt to reproduce the second refusal.

Refs #17725 for the existing saved-input Retry contract. This change
repairs the later queue merge and its retained failed state. Related
#17878 covers snapshot continuation and later turns in recovered
directories; its workspace repair can be reviewed independently.

## What Changed

- Keep deferred chat Retry promotion scoped to its exact receipt.
Ordinary board Retry coalescing retains its existing behavior.
- Let a new explicit task Retry restore a historical mixed batch only
after strict never-started, source, ownership, allocation, board-comment
and prior-delivery checks.
- Preserve failed-run history and original budget-skipped receipts.
Record restored queue ownership in activity.
- Add production queue and HTTP-route regressions. Update the execution
contract and verification maps.

## Verification

- Before the repair, the deferred ten-input batch failed before identity
initialization. The same regression now reaches the real initializer
with the exact GitHub batch. The independent board message then reaches
its own initializer in a separate turn.
- Before historical recovery, ordinary task Retry refused the persisted
mixed failed batch. The repair passes that case without changing the
failed run. HTTP duplicate requests retain one Retry owner. An
additional compatibility probe restored the old queue candidate
predicate and removed all historical mixed-state fixture writes: the
real producer created the exact batch and the complete historical HTTP
recovery case passed (1/1). The fixed-source historical fixture now uses
the production serializers.
- The affected Retry group passes 86 cases on commit
`325c00158df5569f5b42731cda4ecc4584909d99`, including already-coalesced
external receipts. Refusals cover edited sources, active controllers,
unresolved allocations, changed receipts, foreign external receipt
ownership and prior delivery of either board or GitHub input, including
immutable budget-skipped receipts.
- Full workspace `pnpm -r typecheck` and `pnpm build` pass with these
source changes. Map, module-boundary and diff checks pass.
- Full local `pnpm test:run` was started. The host cannot create
additional PostgreSQL semaphores; database-dependent suites fail or skip
at startup. The affected database group runs against a separate migrated
PostgreSQL 17.10 test database with Node 24.22.0 on macOS arm64.
- The regression deliberately stops after the real identity initializer
to avoid provider allocation. It proves HTTP, queue, source
authorization, identity and separate continuation behavior. It does not
claim a live model result, GitHub publication, deployment or recovery of
the original hosted task.
- Current head `325c00158df5569f5b42731cda4ecc4584909d99`: all checks
are terminal with no failures or pending checks; required `ci / verify`
and `ci / e2e` pass. Conditional Storybook checks are skipped. Greptile
and Paperclip each reviewed this exact commit at 5/5. Both earlier
review threads are resolved. Paperclip retains one optional robustness
suggestion for batch ordering; the verified historical producer order
remains a strict recovery contract.

## Risks

Restoring input could repeat work if the prior turn had executed. The
existing strict bootstrap proof rejects provider output, native state,
process or controller evidence, and allocations. Restoration also checks
current external authority, unchanged board revisions and other run
history. An uncertain executor remains held. No migration, provider
fallback or relaxation of dispatch validation is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository inspection,
code editing and test execution. The exact runtime model ID and
context-window size are not exposed in this session. A separately shared
regression supplied independent reproduction 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 (affected database
regressions; full local suite has the host 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
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1027.0-canary.7
2026-10-27 11:34:18 -05:00
DottaandPaperclip 3be54534c2 perf(server): decode workspace run context keys once (#17898)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Managed Git workspaces retain task and run obligations until cleanup
is safe.
> - Activity, expiration, retention and rehome share a run association
query.
> - That query repeatedly extracted three keys from wide historical JSON
contexts.
> - This pull request decodes those keys together and projects the six
fields its consumers use.
> - Native bindings, cleanup vetoes, lifecycle locks and fresh deletion
checks stay in place.
> - The benefit is less database work while preserving the same cleanup
decisions.

## Linked Issues or Issue Description

**What happened?**

Workspace activity and eligibility queries repeatedly decompress large
run contexts. An OR predicate extracts issue, task and workspace
compatibility keys separately. The run scope also materializes columns
its lifecycle consumers do not read.

**Expected behavior**

Read the same relevant runs and preserve all deletion and rehome vetoes
with less repeated JSON work. Keep existing native, historical and
pointer bindings independent.

**Steps to reproduce**

Run the synthetic PostgreSQL comparison below against baseline
`db70c5acd92f50fa37fb4f0dea3da0e7685089a2`. Repeat the small, large-tree
and combined controls documented in the PR.

Related work: #17464 preserves workspace descendants. #17877
reconstructs native workspace obligations. This change preserves both
contracts and adds no scheduling change.

## What Changed

- Decode the three legacy context keys together with `jsonb_to_record`.
A strict root-object guard preserves scalar, array and null behavior.
Independent native and pointer bindings still match.
- Materialize the full textual tree-ID set once. This avoids inflated
recursive estimates triggering JIT compilation for the correlated
decoder.
- Project the six run lifecycle columns used by activity, expiration,
orphan retention and rehome.
- Add binding, lease, malformed-shape and fresh-read regression cases.
Add a reproducible four-control benchmark and detailed evidence
documentation.

## Verification

- Full repository typecheck passed on the integrated final source.
- Six relevant suites passed all 209 tests against real PostgreSQL,
including the 20 new binding/shape cases, 25 eligibility cases, full Git
expiration/restoration, task-directory retention and configuration, and
isolated repository rehome. These cover conflicting bindings, company
isolation, duplicate admission, pending cleanup, controller leases,
non-object contexts and newly active consumers.
- PostgreSQL 17.11 comparisons use two warmups and five alternating
samples per variant. Each sample runs eight sequential workspace
queries. Every complete caller result and six-column relevant-run
multiset matches.
- Stress fixture: 4,813 runs and about 332 MB of run storage, with
unique wide contexts. Last-activity median: 1,071.54 to 743.45 ms per
eight workspaces, 1.44 times faster. Closed eligibility: 814.29 to
713.86 ms, 1.14 times faster. Idle eligibility: 721.46 to 481.69 ms,
1.50 times faster.
- Small-history control improves 1.23–1.36 times. The 250-descendant
stress control improves 1.24–1.30 times. Combined
small-history/large-tree activity and idle checks improve 1.19–1.22
times. Combined closed eligibility is neutral: 61.11 to 62.82 ms per
eight, about 0.21 ms extra per workspace.
- Stress last-activity ranges do not overlap: 920.27–1,111.22 ms before
and 689.14–880.40 ms after. Closed-eligibility ranges overlap; its
smaller median gain is directional.
- Last-activity buffer accesses fall from 113,202 to 38,081. Eligibility
run width falls from about 1,414 to 57 planner bytes. All final plans
retain one history scan with no JIT.
- Reproduce: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-workspace-activity.ts
--baseline-ref=db70c5acd92f50fa37fb4f0dea3da0e7685089a2
--docker-postgres=17 --reject-new-jit
--output-dir=/tmp/workspace-activity-stress`.
- Repeat with `--small`, `--descendants=250`, and both flags, using
distinct output directories. Each run creates and removes its own
synthetic database.
- Full CI passed on `bc4edd700f983e22f093d0a01e2f4c795075b982`: 54
successful checks, one neutral review and two expected Storybook skips,
plus successful Snyk status. Greptile is 5/5 on this exact head. There
are zero unresolved threads and the merge state is clean. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/40530494291).

- Full repository typecheck and build passed on the integrated final
source. The local full test command was stopped after native PostgreSQL
initialization failed repeatedly, producing 16 failures and skipped
database suites. It is incomplete, not a pass. Focused real-database
suites used disposable Docker PostgreSQL. Current-head CI passed all
full gates separately.

## Risks

- Cleanup safety depends on complete run association. Tests compare
every retained run field and exercise downstream vetoes, not only row
counts.
- PostgreSQL plan estimates matter. Rejected per-key index probes were
up to 56 times slower on a small-history/large-tree control. An ANY
variant also regressed. The final shape passes all four controls under
default JIT settings.
- The final combined eligibility control is neutral. Synthetic SQL
timings do not establish deployed latency, provider behavior or actual
compute sleep.
- Review suggested a CASE/jsonb_typeof root guard as an optional
alternative. The strict JSONPath guard is retained because its scalar,
nested-array and independent-native behavior passes real PostgreSQL
tests and all four measured controls. No correctness defect was
identified. A replacement needs its own comparative measurements.
- Future consumers that need another run column must extend this
explicit projection.
- No migration, index, startup job, polling change or deployment is
included.

## Model Used

OpenAI Codex, configured model `gpt-6.1-sol` with xhigh reasoning, tool
use and code execution. Independent blast-radius review also used
`gpt-6-astra` and `gpt-6.1-sol`. The runtime context window was not
exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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 11:23:09 -05:00
DottaandPaperclip 475f7df2e7 perf(server): prefilter chat milestone run candidates (#17892)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat publications connect a run to its authorized originating
conversation.
> - The milestone selector evaluates detailed lineage and final-answer
predicates.
> - A local plan evaluated these predicates across many unrelated run
and conversation pairs.
> - This pull request materializes recent runs that already match an
active or waiting conversation.
> - The existing query still makes each publication decision.
> - The benefit is less JSON work when most run history is unrelated to
active chat.

## Linked Issues or Issue Description

**What happened?**

The milestone candidate query repeatedly reads large run context values
for unrelated conversations. A synthetic baseline discarded 60,962 run
and conversation pairs through the complex join filter.

**Expected behavior**

Apply the existing same-company conversation binding before expensive
lineage checks. Preserve every candidate column, order, publication
decision and continuation rule.

**Steps to reproduce**

Run the two synthetic PostgreSQL comparisons below against baseline
`db70c5acd92f50fa37fb4f0dea3da0e7685089a2`. They capture complete SQL
from the actual service implementations.

Related work: #17606 changes chat lifecycle scheduling. #15802 deferred
milestone cadence. This SQL-only change leaves scheduling, startup
reconciliation and recovery intact. It has no dependency on those PRs.

## What Changed

- Materialize recent runs with an active or waiting same-company
conversation, using the unchanged native and legacy binding expression.
- Retain every outer lineage, continuation, final-response, privacy,
cursor, ordering and idempotency check.
- Add a real PostgreSQL historical-binding regression and
selective/dense performance controls.
- Document the measured gain and the dense-history tradeoff.

## Verification

- Dedicated binding, publication reconciliation and app coordination
suites passed all 27 tests across three files with real PostgreSQL where
required.
- The selective fixture has 2,615 runs, 55 conversation issues and about
192 KiB of pseudorandom context padding per run. Five alternating
measured samples follow two warmups on PostgreSQL 17.11.
- Final-harness selective milestone median: 1,495.85 ms before, 130.96
ms after, 11.42 times faster. Ranges: 1,483–1,716 ms and 125.59–135.85
ms. All 60 complete ordered rows match, including 15 explicit
historical-binding cases.
- Dense control: 736.71 ms before, 809.08 ms after, with overlapping
ranges. All 200 complete ordered rows match. This is inconclusive
performance evidence with possible materialization overhead.
- The unchanged native progress control is neutral in both fixtures. It
returns 41 equal complete ordered rows.
- The added large-window control has 12,215 runs, including 12,000
recent native history rows. A caller limit of one produces the real
service page size of 25. First-page medians 762.65 to 800.63 ms overlap
and are inconclusive. The 90% cursor improves 234.84 to 54.36 ms; the
99.99% tail improves 352.10 to 12.88 ms; the finished cursor improves
340.00 to 58.58 ms. Complete ordered results match: 25, 25, seven and
zero rows. Same-run later-conversation rows remain present.
- Large-window CTE materialization itself takes about 4.6–10 ms with
zero temp spill. This does not establish a materialization regression or
justify a larger production query rewrite.
- Reproduce the added window control with `--cursor-window` and a
distinct report path.
- Reproduce selective: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-chat-milestones.ts
--baseline-ref=db70c5acd92f50fa37fb4f0dea3da0e7685089a2
--docker-postgres=17 --report=/tmp/chat-milestones.json`.
- Add `--dense-chat` and a distinct report path for the dense control.
The harness applies normal migrations to a disposable container and uses
no hosted database.
- The existing real-service test at
`server/src/__tests__/chat-channels.integration.test.ts:34584` calls
enqueue with limit=1 four times, crosses 30 resolver-rejected
candidates, expects admissions [1,1,1,0], and asserts the exact three
publication keys plus internal-run exclusion. It passed and supplies the
full composition/publication-set proof requested in review.
- Assembled chat integration passed 37 selected tests. Together with the
27 focused tests, 64 checks passed. The selector covers bounded
draining, exact continuations, private summaries, final-answer
precedence, lifecycle idempotency and native progress races.
- Final head `1b3a6f50c9e7ec712dcbaf82c7fc3df141ec3f28`: [full CI
passed](https://github.com/paperclipai/paperclip/actions/runs/40534934737),
with 55 successful checks, two skipped and one neutral. Greptile is 5/5
on this head; zero unresolved review threads. Paperclip Review is 4/5,
neutral, explicitly with no must-fix correctness or security defect. Its
remaining payload-memory/dense-overhead caution is retained here as a
measured residual tradeoff; an identity-only projection needs production
evidence and separate comparison.

- After the Drizzle metadata correction, both generated service queries
and every parameter remain byte-identical to the selective and dense
measured versions. The real PostgreSQL binding regression passed again.
- Full repository typecheck and build passed on the integrated final
source. The local full test command was stopped after native PostgreSQL
initialization failed repeatedly, producing 16 failures and skipped
database suites. It is incomplete, not a pass. Focused real-database
suites used disposable Docker PostgreSQL. Current-head CI runs the full
gates separately.

## Risks

- A materialized source can add overhead when most recent runs match
active conversations. The dense control does not establish a gain.
- Historical JSON comparisons retain string and whitespace semantics.
Test fixtures disable the normalization trigger only while inserting
retained historical shapes in disposable databases.
- Synthetic SQL measurements exclude provider delivery and do not
establish deployed latency, actual compute sleep or fleet-wide cost
reduction.
- No schema migration, index, startup job, polling change or deployment
is included.

## Model Used

OpenAI Codex, configured model `gpt-6.1-sol` with xhigh reasoning, tool
use and code execution. Independent blast-radius review also used
`gpt-6-astra` and `gpt-6.1-sol`. The runtime context window was not
exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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 11:22:25 -05:00
DottaandPaperclip a26d217e94 fix(server): coalesce Cloud membership synchronization writes (#17890)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Cloud requests synchronize a human user's profile and company
membership.
> - Concurrent requests repeated the same writes before the debounce
could record success.
> - Upserts also updated unchanged rows and caused avoidable tuple work.
> - This pull request shares identical pending writes and guards
unchanged updates.
> - Each request still reads current authority. Bounded profile lookup
also reaches older memberships.
> - The benefit is less database work during request bursts with the
same actor results.

## Linked Issues or Issue Description

**What happened?**

A burst of 20 trusted Cloud requests issued 20 membership upserts and 40
profile plus membership tuple updates for one unchanged user. The
completed-write debounce did not share in-flight work.

**Expected behavior**

Identical in-flight requests share persistence work. Distinct contexts
retain their order. Failures remain retryable. Each request resolves its
own current company and role authority.

**Steps to reproduce**

Run the synthetic PostgreSQL comparison below at baseline
`db70c5acd92f50fa37fb4f0dea3da0e7685089a2`. The harness imports the real
resolvers and counts actual writes with database triggers.

Related work: #17663 covers adjacent Cloud authorization and projection
behavior. This change preserves fresh imported memberships,
owner-elevation settings and stale administrator removal.

## What Changed

- Serialize synchronization per database client and user. Share only the
last identical queued context. Preserve A/B/A transitions and retry
after partial failure.
- Guard user and membership updates with null-safe value comparisons.
Retain default-grant repair when `RETURNING` is empty.
- Keep authority reads outside the write debounce.
- Resolve exact principal IDs through the existing index, then use at
most one company-scoped alias query. This prevents both the old 200-row
profile cutoff and repeated membership-page scans. Exact IDs take
precedence over namesake aliases.
- Add concurrency tests, PostgreSQL tests, a reproducible benchmark and
behavior documentation.
- Accept both Git 2.55 and 2.56 diagnostic messages in an existing
workspace safety assertion, after full CI exposed that portability
failure. No expiration behavior changes.

## Verification

- Five focused suites passed, 63 tests total. These include Cloud actor
concurrency, transient database retry, company provisioning, real
PostgreSQL synchronization and the user profile route.
- The auth-to-profile regression returned 404 before the lookup repair
and 200 after it. The final fixture has 601 memberships and tests raw
and normalized non-UUID IDs, missing slugs, alias ordering and exact-ID
priority. A counterfactual with the old paging repair performs four
membership queries for a missing slug; the final code performs two, each
returning at most one row. Cross-company access returns 403 before
lookup.
- Local PostgreSQL 17.11 benchmark uses two warmup pairs and five
alternating measured pairs. Each pair starts a fresh debounce scope. All
20 complete actor results match on every sample.
- Burst median: 51.07 ms before, 25.71 ms after. Ranges: 47.21–63.25 ms
and 24.17–29.32 ms. Membership statements: 20 to one. Tuple updates: 40
to zero.
- Reproduce: `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-cloud-membership-sync.ts
--baseline-ref=db70c5acd92f50fa37fb4f0dea3da0e7685089a2
--docker-postgres=17`.
- Real PostgreSQL tests compare all four alias fields with the route's
own JavaScript canonical slug output across 76 fixtures. Exhaustive
Unicode lowercase inspection validates the special SQL mappings.
- A real SQL_ASCII database reproduces the previous en-dash alias 404.
The final whole-character replacements precede ASCII-only translation.
Four alias fields and ten multibyte edge cases pass, including rejection
of a false euro-to-k alias. The disposable database is migrated
normally, then removed.
- Server TypeScript passed with no diagnostics.
- PostgreSQL tests used the normal migrations with a temporary Docker
startup override because this host's native PostgreSQL semaphore
allocation is exhausted. No tracked test infrastructure changed.
- The first full CI run had an unrelated CLI company-import/export
health-start timeout. Review also identified repeated profile scans;
this follow-up repairs that finding. A later run passed 3,882 tests in
server shard 4/12 and failed one existing assertion because Git 2.56
changed its error wording for a missing gitfile target. The safety
behavior still refused expiration and preserved the workspace. The
assertion now accepts both valid messages; the actual Git/PostgreSQL
regression passes locally. Final head
`3a644e600ab0ae7315f9828b1ea9dffdef407e4a` passed [full
CI](https://github.com/paperclipai/paperclip/actions/runs/40537153522),
including the previously failing shard. There are 55 successful
checks/statuses, two skipped and one neutral. Fresh Greptile and
Paperclip reviews are both 5/5 on this exact head, with zero unresolved
threads. GitHub reports mergeable and CLEAN.

- Full repository typecheck and build passed on the integrated final
source. The local full test command was stopped after native PostgreSQL
initialization failed repeatedly, producing 16 failures and skipped
database suites. It is incomplete, not a pass. Focused real-database
suites used disposable Docker PostgreSQL. Current-head CI runs the full
gates separately.

## Risks

- Coalescing is local to one process and database client. Other replicas
can still take conflict locks.
- `updated_at` now records actual profile and membership changes. Access
lists sorted by it can show a different order. Profile resolution no
longer depends on the first 200 entries. Exact principal IDs take
precedence over namesake aliases. The single alias fallback still scans
company candidates; no constant-CPU claim is made.
- Default role grants retain their existing additive semantics. This
change does not define a new demotion policy.
- Local synthetic service timings exclude HTTP and network latency. No
hosted deployment or production speedup is claimed.
- No migration, startup job, polling change or deployment is included.

## Model Used

OpenAI Codex, configured model `gpt-6.1-sol` with xhigh reasoning, tool
use and code execution. Independent blast-radius review also used
`gpt-6-astra` and `gpt-6.1-sol`. The runtime context window was not
exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (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 11:21:44 -05:00
DottaandPaperclip 2f3516f6fd fix(github): authenticate external contributor lookups (#17902)
## Thinking Path

> - Paperclip manages AI agents and their access to external services.
> - A GitHub bot connection can add external contributors by username.
> - The lookup sent an anonymous request even when the bot had an App
installation.
> - Anonymous requests share the server IP quota and can fail for a
valid username.
> - This pull request uses the selected bot installation for the lookup.
> - It also gives users clear errors without exposing credentials or
provider response text.

## Linked Issues or Issue Description

**What happened?**

The Access tab could reject a valid external contributor username with a
generic GitHub error. The lookup did not use the connected bot's
identity.

**Expected behavior**

The lookup uses the selected bot's active App installation. It returns
the numeric user identity or a clear account, rate limit, or
installation error.

**Steps to reproduce**

1. Configure a GitHub review bot and open its Access tab.
2. Exhaust the server IP's anonymous GitHub quota.
3. Look up a valid external contributor username.
4. Observe the generic rejection even though the bot has an
installation.

The original provider HTTP status was not retained. Source inspection
proves the anonymous request. The historical cause remains unconfirmed.

**Paperclip version or commit**

The defect is present at `eda2a03bfe5213ffef2fbbdefdf572be775f1e14`.

**Deployment mode**

Server deployment with an active GitHub App bot connection.

## What Changed

- Pass the endpoint ID from the existing authorized lookup route.
- Issue a short-lived installation token with metadata read permission.
- Reject inactive connections and invalid installation IDs without an
anonymous fallback.
- Distinguish missing accounts, rate limits, and installation access
failures.
- Add 25 lookup tests and update the connector guide and both access
maps.

The GitHub management service owns the provider behavior. The shared
route only passes its authorized endpoint ID. The request body and
response shape stay the same.

## Verification

- Passed: [full
CI](https://github.com/paperclipai/paperclip/actions/runs/40535979115)
on `38d1ebcebb08553f159b3b81ee1bb31d1fbbba8e`, including typecheck,
build, server and workspace tests, Runner checks, serialized suites,
eight E2E shards, and the final verification gate.
- Passed: Greptile 5/5 for the same head, with no open review threads.
- Passed: 25 lookup regression tests on the final test fixtures.
- Passed: 91 tests across five GitHub service suites before the
fixture-only change.
- Passed: `node scripts/check-maps.mjs` and `git diff --check`.
- The tests exercise actual GitHub request construction with provider
response fixtures. They assert the installation identity, metadata-only
token request, request count, and sanitized error details.
- `pnpm build` and `pnpm -r typecheck` could not complete because this
environment has no Cargo executable.
- Two standalone server TypeScript attempts were killed. The second ran
after the full suite was stopped, with a 5120 MiB Node heap limit. The 8
GiB container recorded two OOM kills. Neither attempt produced a
typecheck verdict.
- `pnpm test:run` was started, then interrupted after resource
exhaustion. Its first server phase did not produce a final verdict.
These local attempts remain incomplete. Full CI later passed for the
same head. A live authenticated bot lookup remains unverified.
- The initial frozen install stopped on an existing patch configuration
mismatch. Installation then succeeded with lockfile writes disabled. No
dependency or lockfile changes are included.
- GitHub documents installation-token support for [Get a
user](https://docs.github.com/en/rest/users/users#get-a-user) without
extra user permissions.

## Risks

- The lookup now requires an active bot connection and a saved
installation ID.
- GitHub rate limits can still occur. The error keeps the retry metadata
and tells the user to retry.
- No database migration or permission-policy change is included.
- This PR does not prove that a deployment contains the fix.

## Model Used

OpenAI Codex, GPT-6 family, with code editing, tool use, and test
execution. The recovered implementation was assisted by `gpt-6.1-sol`.
This session does not expose its exact model ID or context window limit.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (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 11:19:14 -05:00
DottaandPaperclip ac22b1b1f9 fix: preserve recovered input and task directory continuity (#17878)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/60/changes/paperclip/60
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip lets people manage AI agents and their work.
> - Recovery must preserve files and the authority of each human
request.
> - Some failed native runs preserve a snapshot without completing
native copyback.
> - The saved input could remain blocked after recovery settled.
> - A later turn could also treat the new task directory as a Git base
because it inherited the agent default.
> - This change continues the same authorized input once and keeps its
saved directory usable on later turns and Retry after a pre-provider
preparation failure.

## Linked Issues or Issue Description

Refs #14905. Related: #17724 covers cleanup handoff after native
copyback. This change covers snapshot-only preservation and later turns
in its directory. #17814 covers a separate same-run checkpoint restore
defect. The open legacy-adapter change in #13291 does not cover this
native saved-input path.

## What Changed

- Forward the trusted deferred inbound request to native continuation
admission. Verify the exact unconsumed receipt and its source, actor,
company, agent, and task.
- Let historical holds for the same failed run use its settled recovery
strategy. Keep each controller and termination check.
- Keep the old native sync proof unchanged. Attach recovered files
through the verified snapshot path in a fresh attempt.
- Recognize only the current same-task, active local directory in the
canonical task or attempt namespace. Keep it on later turns instead of
applying inherited Git defaults.
- Keep the current healthy directory when canonical Retry follows the
exact pre-allocation Git-base failure. Require the committed source
link, strict server-produced failure events, no execution evidence or
unfinished owner, and the current canonical binding. Recognize the known
configuration warning without accepting arbitrary or provider-origin
warnings.
- Keep owned-directory readiness separate from repository-free strategy
selection. A repaired real Git checkout with explicit
task/project/assignee Git policy uses normal Git validation and
preparation. Preserve explicit fresh, new sources, immutable native
bindings, and locked path/binding checks.
- Add real PostgreSQL and filesystem regressions for admission, file
preservation, and the complete later-turn heartbeat policy chain.

## Verification

- Real PostgreSQL callback/queue regressions are RED on unchanged
production and GREEN with this repair: one successor from the same
authenticated saved request, with filesystem snapshot preservation. The
24-case source/Retry matrix passes and retains termination, allocation,
generation and revocation negatives.
- Actual browser use exposed both later-turn Git-base failure and
canonical Retry selecting an empty sibling. The real heartbeat
selection/configuration/preparation/Retry regressions reproduce each.
All 81 workspace-preparation cases passed before the final repaired-Git
edge; all 17 final affected phase-chain/safety cases pass, including
that new case. Its finalized oracle checks effective Git policy, an
actual Git checkout and saved-file bytes. Known preparation warnings
pass; unknown/provider warnings and execution contradictions do not
certify reuse.
- Full workspace typecheck, full build with matching `5342bd52da` stamp,
maps and diff checks pass. Runtime commit `5342bd52da` passed CI with 53
successful checks and 2 conditional Storybook skips, and Greptile 5/5
with zero unresolved threads. The follow-up `9096fe8f62` removes only
the feature/access map additions as requested; runtime and test files
are byte-identical. Map structural and diff checks pass. Greptile
reviewed this exact final commit at 5/5 with no unresolved threads. All
test and build jobs passed. The final required `ci / verify` and `ci /
e2e` aggregate gates are queued without runners; one bounded gate-only
requeue retained every successful job. GitHub auto-merge is enabled and
waits for those gates.
- Normal UI acceptance on exact final source with actual OpenCode,
configured DeepSeek model and Daytona passes both turns: snapshot
continuation writes a useful review/report; reload and a second ordinary
message retain the same workspace and logical native/provider session.
All six files remain byte-identical, the report's computed SHA and
unpredictable marker are confirmed, the concrete result is actual 250
versus correct 350, native finalization/copyback commit, and normal
lease cleanup succeeds. A separate normal UI canonical Retry on
preceding `9ac1d29147` preserves the current directory/report/marker and
writes a continuity note; the final Git-policy split leaves that
exercised non-Git path unchanged.
- Boundaries: local app/server source with real remote native execution;
seeded historical failure/stop receipts and actual stored snapshot, not
a replay of the original staging allocation or external review
publication. Prior local verification rewrote installed dependency
metadata; its generated lock diff was retained and reverted. Final
launch/end source and dependency metadata hashes match; no installed
dependency byte-identity claim beyond that observed freeze.
- Required full local suite was attempted but remains incomplete:
embedded PostgreSQL bootstrap failures prevented assertions in several
suites, so only its owned test tree was stopped. A prior
workspace-recovery test timed out and the following seed collided with
an active hold; both unchanged tests passed in isolation. Runtime-head
`5342bd52da` hosted CI passed the full gate; the documentation-only
follow-up waits for the aggregate jobs noted above. Its [first Rust
attempt](https://github.com/paperclipai/paperclip/actions/runs/40528918372/job/122276159874)
failed an unchanged ACPX shutdown cleanup assertion; the preceding
same-Rust head passed. [One bounded Rust-only
retry](https://github.com/paperclipai/paperclip/actions/runs/40528918372/job/122281990961)
passed. No test assertion or production guard was weakened.

## Risks

- Incorrect input authority could repeat work. The existing owner
reauthorizes the same durable source; admission verifies its receipt
under the task lock.
- Directory recognition could select unrelated files. It requires the
current scoped binding and canonical namespace, then preparation
rechecks the stored binding and path under the source lock. Missing or
symlinked retained roots are not recreated.
- Snapshot preservation does not certify native copyback or old external
outcomes. The old run and its unknown outcomes stay unchanged.
Unconfirmed controllers or termination remain blocked.
- There is no schema migration or new public API.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — targeted suites; the full
local attempt limitation and final CI proof are documented above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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 16:02:43 +00:00
DottaandPaperclip eda2a03bfe fix(ui): keep responder avatars visible through comment acknowledgement (#17885)
## Thinking Path

> - Paperclip gives people a shared place to manage and talk with
agents.
> - Task chat and Agent Chat show the responding agent as soon as a
person sends a message.
> - Comment storage and run discovery finish in separate requests.
> - Both chat surfaces removed the startup identity when comment storage
finished.
> - A slow run lookup therefore made the avatar disappear and appear
again.
> - This pull request keeps startup feedback until the run appears or a
newer execution outcome ends admission.
> - The agent stays visible while the response starts.

## Linked Issues or Issue Description

**What happened?**

The responding agent's avatar appeared after Send, disappeared when the
human comment was saved, and appeared again when the run loaded.
Existing conversations made the flash easy to see.

**Expected behavior**

Keep the agent identity visible across comment storage, queued
admission, and runtime startup. Clear temporary startup feedback on
failure, backoff, task completion, or a completed run.

**Steps to reproduce**

1. Open an existing agent conversation.
2. Send another message.
3. Let the comment POST finish before the task and live-run reads
finish.
4. Observe the responder identity disappear during that gap.

**Paperclip version**

Source baseline: `db70c5acd92f50fa37fb4f0dea3da0e7685089a2`.

**Deployment mode**

Local trusted mode with an isolated database. The browser test used the
real app, APIs, and native runner with a deterministic Codex provider.
It held read responses to expose the acknowledgement gap. It did not
call a live model provider.

Related: #4485 addressed human-comment alignment during session loading.
This change addresses agent-response startup.

## What Changed

- Share submission-to-run state between the task and classic chat
surfaces.
- Keep the identity mounted after comment acknowledgement. End startup
on a visible run or a newer admission outcome.
- Keep old execution projections and older loaded history from
acknowledging a new response. Retain slow-start refresh and
uncertain-save handling.
- Extend the startup tests through the missing acknowledgement interval
on desktop and mobile. Add existing-thread, paused-agent,
fast-completion, and clock-skew cases for both surfaces.
- Match completed runs to the saved comment and its server time. Use the
shared status rules and server-reported reporting-chain health for known
agent blockers and confirmed task pauses. Keep submitted feedback
visible through pause-state read errors. No browser/server clock
comparison is used.
- Clarify the identity continuity rule in `DESIGN.md`.

## Verification

- Red: the actual Send tests fail against the original components in
eight cases.
- Green: both chat suites pass, 420 tests total. Extra red/green cases
cover paused or ineligible agents, missing/terminated managers,
reporting cycles, browser clocks five minutes ahead or behind, and
pause-state read failures.
- Chromium on an existing conversation: the original avatar appeared at
58 ms and disappeared at 326 ms. On final commit `f9602e3e48`, the
avatar appeared at 68 ms and stayed visible through the same held-read
interval. Frame sampling found no disappearance after it appeared.
- Native fixture turns succeeded and stored their final provider
replies. Repeated the existing-thread turn and normal navigation/reload
on final commit `f9602e3e48`: both runs succeeded, both replies were
stored, and the conversation returned to its waiting state.
- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, and the
final UI typecheck passed.
- `pnpm test:run` was attempted. The host exhausted PostgreSQL
semaphores. The supported external test database let some suites run,
but other suites still attempted embedded clusters and failed or skipped
setup. The run was stopped after repeated setup failures.
- The broader UI run passed 9,251 tests and failed one existing
connection-authentication test. The same test fails on an untouched copy
of the base commit. This PR does not change that component or test.
Full-suite CI remains the complete-suite check.

- Final-head CI attempt 1 lost seven workers to shutdown or lost
communication and hit one timing assertion in an unchanged scheduler
test. Retried only failed jobs once on the same commit; the scheduler
test and interrupted jobs recovered. All retried jobs and both aggregate
gates passed. Final CI is green on
`f9602e3e48c75580935465eb0b4713fc7a4bcc56`.

## Risks

Low scope: this changes client startup feedback only. There are no API,
data, auth, or token changes. If run discovery is slow, the existing
slow-start message remains visible until current execution evidence
arrives. Completed runs are matched to the submitted comment by
consumption identity or server timestamps, so loading old history and
browser clock differences cannot end its feedback incorrectly.

## Model Used

OpenAI Codex, GPT-6 family. This session does not expose the exact
deployment ID or context-window limit. It used reasoning, code editing,
command execution, and Chromium automation.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (420 relevant chat tests;
the full-suite setup limit 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-27 10:25:56 -05:00
Dotta 0dd8e41800 Bind new remote intents to user-authorized AWS fleet fallback 2026-10-27 10:24:23 -05:00
Dotta 3084702f49 test(evals): allow authorized AWS fleet allocation fallback 2026-10-27 10:23:57 -05:00
DottaandPaperclip e71a23c01c fix(ui): animate late task sidebar loading (#17880)
<!-- entire-trail-link-start -->
https://entire.com/gh/paperclipai/-/trails/61/changes/paperclip/61
<!-- entire-trail-link-end -->

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task pages load the conversation and related sidebar data
separately.
> - The sidebar host did not exist until its content arrived.
> - Its first appearance skipped the width transition and moved the
thread at once.
> - This pull request keeps an empty host at zero width until content is
available.
> - The sidebar and thread now move together, with immediate changes for
reduced motion.

## Linked Issues or Issue Description

**What happened?**
A cold task load showed a wide skeleton. The right sidebar then appeared
at full width and shifted the thread at once.

**Expected behavior**
The sidebar should enter smoothly. The task thread should move with it.
Unknown or hidden sidebars should take no space.

**Steps to reproduce**
1. Open a populated task in a fresh browser context.
2. Delay the task metadata response.
3. Watch the skeleton and thread as the right sidebar becomes available.

Related work: [task cold-open
reads](https://github.com/paperclipai/paperclip/pull/17756).

## What Changed

- Keep the shared sidebar host mounted at zero width while its content
is unknown. Make hidden hosts inert and hide them from assistive
technology.
- Use shared motion tokens for width and opacity. Disable motion for
reduced-motion preferences and keep pointer resizing immediate.
- Clamp late content to the current viewport without overwriting the
saved width. Keep the motion catalog aligned with the reveal tokens.
- Clip the panel body during reveal. Keep the resize handle inside the
viewport during the first frame.
- Clear empty panes immediately when content is removed. Release
maximized geometry on that render. Remove the unused width/opacity
token.
- Add four replayable Storybook scenarios using the production skeleton
and panel components. Add browser checks for both arrival orders, absent
and hidden sidebars, reduced motion, resizing, and maximize/restore.
- Document the shared sidebar loading behavior in DESIGN.md.
- Load the comment-route test modules in suite setup. This prevents a
slow module load from timing out the first test and affecting the next
test. This test-only change fixes a reproducible CI failure; route
behavior and assertions stay the same.

## Verification

- 201 focused task-detail, properties-panel, and motion-catalog tests
passed. New host-continuity regressions failed against the original
component in both task interfaces.
- Eight focused Storybook browser checks passed without retries after
the review fix. They measure intermediate widths and matching thread
widths, check overflow, exercise resize and maximize controls, and
confirm immediate removal of docked and maximized content.
- The first removal checks sampled before replay cleanup committed.
Sampling now starts after the host becomes inert. All three removal
checks fail against the prior commit. Restoring the source during that
comparison left a stale Storybook module in the preview. After a preview
restart, all eight cases passed without retries on the fixed source.
- Verified a real populated local task in a fresh browser context with
delayed real API responses. Recorded a screencast for visual review. The
captured reveal had 20 intermediate widths, no horizontal overflow, and
no browser errors.
- Repository typecheck, full build, Storybook build, token gates, map
checks, and 30 catalog/map tests passed. Full typecheck, full build,
focused UI tests, and UI typecheck were repeated after the upstream
rebase.
- Full `pnpm test:run` was attempted and stopped after repeated embedded
PostgreSQL initialization failures. The host has exhausted its semaphore
pool. The local app test used a disposable container database instead.
- Replay `tasks-sidebar-loading--sidebar-during-skeleton` in Storybook.
Run the focused browser suite with `STORYBOOK_TEST_BASE_URL` set to that
Storybook server.

- CI serialized shard 6/9 failed when the first comment-route test hit
its 15-second timeout. Its work then affected the next test's mock
count. Both failures reproduced locally on Node 24. After moving module
loading to suite setup, all 103 tests and server typecheck passed with
the same test timeout. A first local attempt could not bind the
Supertest listener inside the sandbox; it was repeated with local
network access.

## Risks

- The shared host also serves other properties panels. Hidden
preferences, default widths, pointer resizing, maximize/restore, and
both task interfaces have focused coverage.
- Width animation can reflow text while the panel enters. Reduced motion
removes the transition. Navigation removes empty panes immediately.
- Visual approval is complete. The full CI suite must pass before merge.
No schema or API contracts change.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, code execution, and
browser tools. The exact deployed 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-27 10:10:45 -05:00