Commit Graph
6184 Commits
Author SHA1 Message Date
DottaandPaperclip bf7f77d8cd fix: avoid response recovery self-contention (#18715)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The server must present accepted agent responses as comments under
current chat authority.
> - The recovery worker can check four tasks at the same time.
> - Different tasks can share a chat endpoint or external principal.
Their authorization transactions then compete for endpoint or identity
locks.
> - A failed transaction leaves the accepted response pending and
repeats its source queries on a later retry.
> - This pull request groups checks that share a task, endpoint or
principal before dispatch. It keeps every transactional authority check
and lock.
> - The benefit is less failed recovery work and prompt, exactly-once
presentation of valid accepted responses.

## Linked Issues or Issue Description

Refs #17714 for a separate publication-commit lock-order fix. Refs
#18686 for separate run-list JSON work. Neither changes this recovery
admission path.

**What happened?**

A response-presentation worker reported `could not obtain lock on row in
relation "chat_endpoints"`. Four real PostgreSQL recovery fixtures
reproduced three such failures in one pass with no external ingress. The
worker grouped by task, while authorization locks shared endpoints and
principals. Review also exposed two valid Slack endpoints in one
workspace that share one principal and compete for its try-advisory
lock.

**Expected behavior**

Recovery checks that share an endpoint or principal should retain task
order without competing with one another. Unrelated endpoints should
make progress. The server must still reject stale authority and retry
legitimate external contention.

**Steps to reproduce**

Run the shared-endpoint regression or the portable comparison helper
linked below. The fixture creates four accepted historical responses for
distinct tasks and principals on one actual endpoint.

## What Changed

- Read optional endpoint and principal scheduling hints through a
company-scoped join to the canonical wake action. The join does not
change eligibility or grant authority.
- Extend existing bounded check groups to merge intersecting resource
keys. Preserve task order, transitive conflicts, independent-group
progress, shutdown, drain and pending scopes.
- Add real PostgreSQL controls for shared endpoints, a principal shared
across two endpoints, an observed blocked transaction with independent
endpoint progress, external locks, exact selected output, and endpoint
revocation despite a forged hint.
- Add a portable helper that materializes the pinned baseline with `git
show`, runs the existing real fixture, retains results, and restores
temporary files.

## Verification

- Final principal-extension head
`57047441b28765ed1cf49b8924efc69f5c03dcb4`: 34 focused scheduler/chat
controls passed on Node 24.22.2 / pnpm 9.15.4. Independent exact-head
source review is green. Full local `pnpm -r typecheck` and `pnpm build`
pass on this head. Fresh Greptile and Paperclip reviews are both 5/5
with no findings. All 59 final-head contexts are complete: 55 success, 3
skipped, and the neutral Paperclip review at 5/5. There are no failures
or pending checks.
- Earlier endpoint-only head `eea437e7edbe7eb41eb880d4d8fd6d99a9c247da`:
full local typecheck/build and all remote CI passed. The redundant local
full suite was interrupted for this review fix after 956 passing chat
cases; it is not a full local pass.
- Final shared-principal counts-only comparison completed the same two
exact responses: product calls 165 → 147, rows 114 → 100, outer
contention failures 1 → 0. SQL query errors stayed zero; advisory-lock
refusal is not a failed SQL query.
- The earlier endpoint-only study completed five alternating pairs / ten
measured runs: median calls 443 → 293, rows 314 → 200, query errors 6 →
0 for four exact responses. Its instrumented shared-host CPU data
predates the principal extension and is not a final-head or hosted CPU
claim. Retry clocks were accelerated; wall time is not hosted latency.
- [Raw samples, final principal work counts, portable commands and
failure
accounting](https://github.com/paperclipai/paperclip/blob/57047441b28765ed1cf49b8924efc69f5c03dcb4/doc/performance/2026-11-03-response-presentation-contention.md).
- Initial server4 CI reported three provider calls instead of two in the
unchanged Anthropic identity fixture. The exact local case passed; the
full 88-case file passed with observations showing the two expected
identity-route calls. The third CI call's origin remains unknown. One
bounded rerun of the failed job and its dependent CI aggregate passed.
No assertion or source change was made for that failure.
- The causal benchmark baseline worker/query is
`82c033ed127d07862e6765aa4b69a3cf339bde81`. The PR base is `36df8933f0`.
They are not claims about the currently serving revision.

## Risks

- Connected resource groups can reduce parallelism when tasks link
several endpoints. This preserves the existing task ordering contract.
- Missing or stale endpoint/principal hints retain current transactional
checks. Other workers and ingress can still cause legitimate NOWAIT
retries.
- There is no schema, API, permission or provider-transport change.
Endpoint revocation and company isolation remain enforced by their
existing owners.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`), with tool use and code execution,
produced and reviewed this change. The runtime does not expose the
context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-03 06:04:25 -06:00
DottaandPaperclip 76ee5d0886 fix(evals): preserve singleton reports and pin reviewed chat repairs (#18749)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The chat eval lane runs selected cases from one immutable candidate.
> - The finalizer must authenticate every original projection and
publication.
> - The pinned artifact action places one matched artifact at the
download root.
> - The finalizer expects named child directories, so a valid one-case
run fails before final coverage verification.
> - This PR supports both valid layouts and binds one reviewed repair
candidate.
> - The lane keeps exact selection, source, digest and publication
checks.

## Linked Issues or Issue Description

Refs: #18740, #18736, #18742, #18734, #18717.

This PR is a proposed replacement for the source pin in #18740. That PR
remains open. The evaluated candidate contains all five repairs from
that prior cut and five further reviewed repair conditions. The product
PRs remain unmerged. Merge authority for this replacement is pending;
this PR does not dispatch a run.

A completed one-case run has a verified original PASS and a verified
publication. Its final aggregate fails because the pinned artifact
action flattens a single matched artifact. The same path assumption also
affects the later publication verifier. The final checks must still run;
the repair must preserve their identity and digest checks.

## What Changed

- Bind the finite candidate `ab2019e976076ec0eb60b026844f3d9211cb0208`
through the manifest and exact descriptor snapshot.
- Retain the original 244 case identities and the explicit cumulative
definition overrides. Keep the historical definition source separate
from the current candidate.
- Add the reviewed source dependencies for real hire-review readiness
and the strict later-human-intent review overlay from unmerged #18742.
Preserve all original clocks, queries and model settings. Keep the
earlier Studio144 accounting change explicit.
- Document one current target and identify the prior Source5 cut as
unmeasured.
- Preserve named singleton download destinations for both bundles and
publications. Authenticate every bundle before gathering its safe
projection. Reject mixed, foreign, missing and symbolic-link layouts.
Accept only the producer's exact closed once-marker schema. Do not
export or upload results again.

## Verification

- Candidate controls: 217 pure checks in 13 files; 242 real factory
declarations with zero fixture callbacks; 42 admission controls;
unchanged 506-input SDK registry; focused actual database-row type
check.
- Combined trusted pin and layout controls: 124 Node checks in seven
real files, plus source-byte closure for all 244 singleton evidence
policies. The unchanged parent reproduces both layout failures. Actual
producer-marker, multi-case and malformed-layout controls pass.
- The two actual PostgreSQL route regressions on core #18742 head
`61996a96dd09e90a5788e8711a94fc5ae631f425` ran and passed. That core PR
remains unmerged. This is not chat-case acceptance.
- The independent layout logic peer and the whole final eight-path PR
source peer passed. Current-head CI completed with 48 successful jobs
and one skip. Both required checks passed. All 60 exact-head checks
completed: 55 success, two neutral and three skipped. The separate
Windows Rust check passed. Greptile and Paperclip Review both scored
5/5, with no unresolved threads.
- The optional raw-order note is [disposed with source
evidence](https://github.com/paperclipai/paperclip/pull/18749#issuecomment-6598680442).
The admitted selector writes canonical order before hashing. A changed
raw order fails closed before copying. The checked code remains
unchanged.
- Full local candidate typecheck and build are not claimed. Installed
workspace dependency gaps prevent that full local check. The existing
remote source and build preflight must pass before a native query.
- No new model run or TestOps upload was used to prepare this PR. Prior
attempts and grades stay unchanged.

## Risks

A permissive layout repair could hide missing or foreign publications.
Exact selected names, singleton counts, source identities, hashes and
final readback checks must remain enforced. The layout helper must
reject symbolic links and mixed shapes.

The active default-branch ruleset requires CODEOWNERS review for the
workflow. Normal merge is currently blocked on that review. This PR does
not enable auto-merge, change branch rules or dispatch an eval.

The candidate contains explicit unmerged product overlays. It is not a
core release or a full-catalog qualification. The other five SDK cases
remain held. SDK115 completion remains unknown. Provider quota failures
are not fixed by the skill observer change. No credentials, caps, runner
permissions or workflow admission references are added.

## Model Used

OpenAI `gpt-6.1-sol`, with code execution, tool use and independent
agent source review. The host does not expose the exact context window.
No model eval was run to prepare this PR.

## 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 links)
- [x] My branch name describes the change and contains no internal
ticket id
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.8
2026-11-03 06:03:25 -06:00
DottaandPaperclip 7b8aa60b6d test(e2e): add repository continuation journey (#18729)
## Thinking Path

> - Paperclip keeps agent work in project workspaces.
> - A later user request must continue from the saved repository state.
> - A successful reply alone cannot prove file or Git history
preservation.
> - The repository journey in #18652 passed against QA staging with
independent byte and commit checks.
> - Its separate completion journey remains unpassed and must stay open.
> - This PR delivers only repository continuation and reuses the merged
shared support from #18728.

## Linked Issues or Issue Description

Refs: #18652. Builds on merged #18728. This is the repository-only
delivery from #18652. The original completion implementation and all
failed attempts remain on that open PR.

## What Changed

- Add `repository-continuation` with the exact measured source fixture,
two native turns, and eight required checks.
- Start from measured source `ac4efb7c6f4782ea806661683c656fd2b4cc3189`.
Keep the repository flow and Git/byte oracle unchanged. Clarify the two
file-content instructions to require the word first or verified followed
by exactly one LF newline; retain the exact expected bytes and the
original random-reference contract.
- Document the two-turn proof boundary: final saved hidden Git metadata
is not independently read. Keep all eight success assertions.
- Use the original-deadline and routine failure-reporting repairs from
merged #18728. Integrate its actual master squash
`e5713d95c6d9a258882649789ea5eb071cc17dc0` through one normal merge.
- Use a fixed public read-only repository commit. Verify downloaded Git
objects, parent commits, changed paths, saved workspace identity, and
exact source bytes across both turns. Reopen the registered outputs
through the browser.
- Keep the shared artifact reader behavior unchanged and narrow its type
to the API capabilities it uses.
- Add only this case to the catalog, feature association, dispatcher,
source hash, types, run/check contract, strict catalog expectation, and
journey documentation.

## Verification

- Current head `86808b7ec17e1727bd55a3fd46bc7e0409ca0e31` passed fresh
[QA staging run
41589522430](https://github.com/paperclipai/paperclip-cloud/actions/runs/41589522430)
and its [full
report](https://pages.paperclip.ing/evals-qa-smoke-41589522430-1/). All
eight checks and five phases passed. Both native turns succeeded and
committed in the same workspace. The independent same-buffer Git audit
verified that the second commit has the first commit as its parent. The
saved original files and browser downloads matched their expected bytes.
This does not add a final hidden `.git`/HEAD assertion.
- The fresh run used OpenCode with
`openrouter/deepseek/deepseek-v4.1-flash-1017` on QA staging/Daytona. It
used Core `09162fe893b464dd2ccdafd14bd3ef1611202a86`, Cloud
`cloud-41570439002-1`, and environment configuration version 9. Actual
checkouts matched public source
`86808b7ec17e1727bd55a3fd46bc7e0409ca0e31`, adapter
`7367cf6fd0ee1cf52c2651a8a6671e087728a9c1`, and protected workflow
bootstrap `a9ad6877de62fe3f65aacadc8a9dfba7d90729cf`. The bootstrap
matched the accepted 117-file QA contract.
- Normal cleanup completed. The original manifest is complete, evidence
cleanup is complete, no operations remain active, and the owned agent is
terminal. The coordinator verified ACTIVE TestOps case 685 / result 3695
and closed [launch 1921](https://paperclip.testops.cloud/launch/1921).
This records normal cleanup closure; no separate physical provider-stop
acknowledgement was collected.
- Measured source `ac4efb7c6f4782ea806661683c656fd2b4cc3189` passed [QA
staging run
41573331189](https://pages.paperclip.ing/evals-qa-smoke-41573331189-1/)
against Core `09162fe893b464dd2ccdafd14bd3ef1611202a86`. TestOps launch
1723 / result 3501 maps to case 685. All eight checks and five phases
passed. The two run bindings, independent saved-byte/Git audit, and
completed cleanup were verified.
- Initial extraction `54103639850d08d4d125ebe0493d8d3d49b58211`
preserved the measured case files. The current head also clarifies the
two LF instructions, documents the final Git-metadata limit, and
inherits the reviewed helper repairs. This changed the fixture
conditions. The current head now has its own live pass, listed below.
The original ac4 result remains a pass under its original conditions; it
was not used to qualify this head.
- The emitted-prompt control failed on the old quoted backslash+n
instructions, while 14 sibling controls passed. All 47 focused
repository/artifact controls then passed after the two-sentence repair.
Local: 891 related support tests, runner E2E typecheck, recursive
typecheck, build, maps, token gates, and `git diff --check` passed. The
inherited routine source has 62 causal read/cleanup controls and 26
unchanged real component controls.
- The initial repository head's normal full CI run 41578686494 passed.
Its 4/5 review and all original findings remain recorded. The later
stacked head `037b979477161881a4877230500e6f3de8faea5c` also passed full
CI run 41581342503 and a fresh 5/5 review. Current integration head
`86808b7ec17e1727bd55a3fd46bc7e0409ca0e31` passed normal full [CI run
41584981651](https://github.com/paperclipai/paperclip/actions/runs/41584981651),
attempt 1. Its fresh exact-head Greptile review is 5/5, with zero
unresolved threads and no open findings. The broad local suite was not
repeated. The earlier full local run recorded in #18643 had four
failures and did not reach 164 serialized groups; this PR does not claim
an all-local pass.
- Earlier repository failures remain recorded: provider-pack transfer
timed out in one attempt; a later attempt could not read saved workspace
files. The later pass does not regrade those failures. The product
repairs are separate from this unchanged case delivery.
- The fixed actual #18728 squash is now integrated. The PR targets
master. Its aggregate diff has exactly 14 repository-only paths, each
identical to `037b979477161881a4877230500e6f3de8faea5c`; all other
master changes are preserved. No later master head was chased. The
current CI, review, and fresh staging qualification all passed for this
integration head.

## Risks

- Git bundles and workspace bytes are private evidence. Public reports
retain closed checks; the fixture never pushes to the public source
repository.
- The second committed output must retain the first commit as its
parent, the same workspace binding, and original saved file bytes. Final
hidden `.git`/HEAD after the second save is not independently exposed by
the supported remote workspace API; this test does not claim third-turn
Git metadata durability.
- Only JSON metadata observations retry transient transport failures.
Binary attachment and browser downloads remain single attempts.
Transport failures and digest mismatches remain visible failures.
- The existing artifact reader is shared. Its runtime code is unchanged
and its regression coverage remains included.
- Daily source pins and plan selection stay with the coordinator. This
PR does not register or bypass the unpassed completion case.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
deployment ID and context window are not exposed by this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.7 nightly/v2026.1103.0-nightly.0
2026-11-03 00:46:13 -06:00
Dotta 2aeceb963d fix(evals): pin reviewed Source4 chat repair candidate (#18736)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The chat catalog checks real user journeys through a fixed
candidate.
> - The current candidate retains several known fixture and observer
defects.
> - A new source must bind each repaired declaration before paid work
starts.
> - This pull request pins the reviewed Source4 candidate and its exact
descriptor snapshot.
> - The next measurements can test those repairs without changing old
results or relaxing private evidence guards.

## Linked Issues or Issue Description

Refs #18726. Related core changes remain separate and unmerged: #18717
and #18734.

**What happened?**

The active lane still uses Source3. It cannot test the accepted primary,
app review, CLI, timeline, plan review, hire fixture and SDK input
repairs. Old results must remain historical.

**Expected behavior**

The trusted lane must bind the new immutable candidate, all 244 case
identities, exact current declarations and private source hashes. It
must retain the original definition provenance and explain changed
conditions.

**Steps to reproduce**

1. Compare the current manifest with candidate
`51ef450754370c8a8f2cbe4bd18e1536bbc93966`.
2. Check each of its 242 declarations against the checked descriptor
snapshot.
3. Run the focused manifest, contract and reconciliation controls. Run
the selected real cases only after normal source delivery and a fresh
execution guard.

## What Changed

- Pin candidate `51ef450754370c8a8f2cbe4bd18e1536bbc93966` and its exact
descriptor snapshot. Keep all 244 identities and aliases.
- Record cumulative original-to-current field overrides. Keep the
original `de094` definition provenance and case limits. Studio144
retains its earlier explicit 2..3 accounting revision.
- Record the reviewed SDK expected build-lock correction and the
candidate-only full proposal disclosure from unmerged #18734. Keep
compiler/parser/Zod identities, privacy guards and the other SDK holds.
- Update the static owning controls and identify current versus
historical sources in the lane guide. Runtime JavaScript, declarations,
workflow permissions and private transfer code are unchanged in this PR.

## Verification

- 47 focused Node controls passed: contract, manifest and idempotent
reconciliation.
- Candidate controls: 293 pure tests across 16 files passed. All 242
actual factory declarations and 42 admission controls passed without
fixture callbacks.
- The final candidate SDK registry check matched all 506 inputs. The
actual Git launcher, checked snapshot, three private protocol files and
all 244 singleton evidence policies matched.
- The candidate product disclosure is byte-identical to the reviewed
#18734 file. Its token gate passed. The separate core change retains 115
React controls.
- Independent full PR and integration source review passed before
publication.
- Full local workspace typecheck, application build and model execution
were not run for this pin. The existing workspace dependency limitations
remain recorded. Latest-head CI `41586212647` passed on attempt 1: 48
passed and 1 skipped. Both required checks passed. Greptile reviewed the
exact head at 5/5 with no open threads.

## Risks

- These are new candidate measurements. A source-qualified repair does
not prove a user journey passed.
- SDK115 must first pass real admission with its original
300-second/one-native limit. The other five SDK cases and plugin558
canary certificates remain held.
- The CLI parser rejects unresolved placeholders and foreign values. It
executes the actual returned commands without substitutions. The old
failed command remains failed.
- The core guidance and review-card PRs remain unmerged. This pin
changes neither core merge authority nor the previous full-catalog
acceptance gate.
- A running Source3 launch remains pinned to its immutable controller
and candidate. The next model wave must wait for terminal accounting and
cleanup guards.

## Model Used

OpenAI `gpt-6.1-sol`, with code execution, tool use and independent
agent source review. The host does not expose the exact context window.
No model eval was run to prepare this PR.

## Checklist

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

> - Paperclip is the open source app people use to manage AI agents for
work
> - The native Runner supervises the harness and tool processes for each
run
> - A launcher can start Runner with a negative `oom_score_adj`, and
Linux children inherit that value
> - Then a large tool process has the same protection as Runner
> - If that protection is -1000, the kernel cannot kill the process, and
a VM with no other candidate panics
> - The correct protection for Runner is different in each environment,
so one static value is not correct
> - This pull request adds an optional `--oom-score-adj` launch flag.
With the flag, Runner also sets supervised processes to 0 when Runner
has a negative score
> - The benefit is that the launcher controls Runner protection, and the
kernel can kill the large process and let Runner report the failure

## Linked Issues or Issue Description

Related: #14509 and #16844. These pull requests change scores for the
server and for sandbox tool commands. This pull request changes the
native Runner.

**What happened?**

A native Runner on a VM inherited `oom_score_adj` -1000 from the VM init
process. A typecheck under Runner used most of the VM memory. The kernel
could not select any process and panicked with "System is deadlocked on
memory". The VM restarted, and the run failed with a transport error.

**Expected behavior**

The kernel can kill the large tool process. Runner continues and reports
the result.

**Steps to reproduce**

Start Runner with a negative score. Start a supervised process. Read
`/proc/<pid>/oom_score_adj` for the supervised process. The value is the
same as the Runner value. After this change, the value is 0 when the
launcher gives the flag.

**Deployment mode**

Native Runner on Linux, when the launcher gives Runner a negative score.

## What Changed

- Add the optional `--oom-score-adj <-1000..=1000>` flag to
`paperclip-runnerd`. Runner has no default value.
- Stop Runner startup when the value is not valid. When the kernel
refuses a valid value, or the platform is not Linux, write a diagnostic
and continue, because Runner is then only less protected than the
launcher asked for.
- When the launcher gives the flag and the Runner score is negative, set
each supervised process and verified stdio MCP server to 0 after spawn.
- Without the flag, Runner does not change any score. Children inherit
the Runner score, as they do now.
- Add unit and integration tests.

## Verification

Tests ran in `rust:1-bookworm` (rustc 1.99.1) on Linux arm64 with
`CAP_SYS_RESOURCE`:

- `cargo fmt --check -p paperclip-runner-core`
- `cargo test -p paperclip-runner-core --no-fail-fast`, before the flag
gate commit: all targets pass except `codex_provider` and `stdio_mcp`.
- `provider_receives_the_isolated_codex_auth_home` and its subprocess
helper fail in this container. They fail in the same way on clean
`master`.
-
`receipt_limit_polls_an_authoritative_terminal_with_unacknowledged_events`
and `cancellation_waiting_behind_output_is_handled_before_new_dispatch`
failed once in the full run. They pass when they run alone, on this
branch and on clean `master`. I think that they are sensitive to load,
but I did not prove this. CI is the check for these tests.
- `--test oom_score` and `--test oom_score_without_flag` pass with and
without `CAP_SYS_RESOURCE`. It covers the real Runner binary, flags that
are not valid, a Runner that cannot apply a negative score, and a
supervised child of a Runner with a negative score. The tests for
children of a Runner with a negative score skip themselves without
`CAP_SYS_RESOURCE`. The unit test covers the same reset logic without
that capability.

I also ran the debug Runner binary through the agent computer `enter`
command in a container, as UID 1000, with a floor of -500:

- Runner stayed alive at -500.
- The `oom_score` integration test passed in the same setup. Its
supervised child had the score 0.

After the flag gate commit, I ran the library `oom_score` tests, `--test
oom_score`, `--test oom_score_without_flag`, and `--test
process_supervisor` again. CI runs the complete suite.

I did not run this on a real VM.

## Risks

- A fork in the short time after exec and before the write keeps the
Runner score. The kernel can still kill that process unless the score is
-1000.
- The write to the child can fail. Runner ignores this failure, because
the child has no more protection than Runner.
- A launcher without the necessary privilege gets a Runner at the
inherited score. Runner writes a diagnostic to standard error, and the
run continues. A launcher that discards standard error does not see the
diagnostic.
- A launcher that does not give the flag has no change, also when Runner
starts with a negative score. On Linux, each spawn has one more atomic
read and no system call. A `oom_score_without_flag` test binary checks
this.
- A new Runner under a launcher that does not give the flag and gives
Runner -1000 keeps its children at -1000. Update that launcher to give
the flag.

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with
tool use and code execution.

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 22:02:45 -08:00
DottaandPaperclip e5713d95c6 test(e2e): add scheduled routine journey (#18728)
## Thinking Path

> - Paperclip manages agent work through tasks, projects, and routines.
> - Daily QA must exercise the staging app through normal browser and
API surfaces.
> - A schedule must create real work and retain its result and history.
> - Pausing that schedule must prevent the next invocation.
> - The routine journey in #18652 passed in QA, while its separate
completion journey has not passed.
> - This PR delivers the routine test independently and preserves its
measured flow and assertions.

## Linked Issues or Issue Description

Refs: #18652. This is the routine-only delivery from that PR. The
original completion implementation and its failed attempts remain on
#18652.

## What Changed

- Add the target-independent `routine-scheduled-run` journey with one
native run and seven required checks.
- Start from the measured routine source
`ac4efb7c6f4782ea806661683c656fd2b4cc3189`. Keep its request, seven
success assertions, one native-run limit, and 65-second pause check.
- Bound each observed GET by the original remaining journey deadline.
Preserve the normal API timeout for other callers. Keep the original
routine error if final trigger disabling also fails, save a closed
secondary receipt, and fail an otherwise successful journey when
disabling fails.
- Narrow the shared output-reader type to its one-argument GET
capability without changing its runtime code.
- Register only this case in the catalog, types, feature associations,
dispatcher, and definition hash. Keep the strict catalog expectation in
sync.
- Retain the real Routines component controls and the existing
project-flow coverage for the shared browser helper.
- Document resource cleanup and the 65-second pause observation.
Preserve the current routine map content.

## Verification

- The original source passed [QA staging run
41567574185](https://pages.paperclip.ing/evals-qa-smoke-41567574185-1/).
TestOps launch 1657 / result 3431 maps to case 718. All seven checks and
five phases passed. One scheduler-bound native run, saved output
attribution, the full pause window, and cleanup were verified.
- Current source `8f62137f130f59fd3e39276e3d60185ddff24517` passed
[fresh QA staging run
41582706162](https://pages.paperclip.ing/evals-qa-smoke-41582706162-1/)
against Core `09162fe893b464dd2ccdafd14bd3ef1611202a86`. TestOps launch
1855. All seven checks, five phases, and all three workflow jobs passed.
The run used one scheduler-bound native turn and observed 65.352 seconds
after pause and completion. Canonical evidence collection and normal
cleanup completed, with no active operations and the owned agent
terminal.
- This fresh pass covers the reviewed deadline and failure-reporting
changes in the current source. The earlier ac4 pass and the
byte-preserving b940 extraction remain historical records under their
original conditions; neither failed attempts nor prior source conditions
are regraded.
- Causal controls: six assertions failed on the old behavior, then all
62 focused controls passed after the repair. Local: 834 related support
tests, 41 shared chat/output-reader tests, and 26 unchanged real
component controls passed. Runner E2E typecheck, recursive typecheck,
build, maps, token gates, and `git diff --check` passed. The temporary
output-reader type mismatch exposed by typecheck was corrected by
narrowing the capability type.
- The first restricted build/typecheck invocations failed because local
tsx IPC was denied. A restricted support run also lacked the report CLI
output. The same source passed with normal owned local IPC allowed; the
original logs remain retained.
- The original head's hosted e2e shard 2/8 failed at the unchanged
mobile preference frame-count test: expected more than five frames,
observed five. The cause is unknown. Its original log remains retained;
it is not labeled a proven flake. No CI rerun was requested.
- Current-head full CI run 41580423918, attempt 1, passed. The fresh
review is 5/5 with zero unresolved threads. The broad local suite was
not repeated. The earlier full local run recorded in #18643 had four
failures and did not reach 164 serialized groups; this PR does not claim
an all-local pass.
- Prior failed routine attempts remain recorded. They exposed composer
focus, collapsed schedule controls, pending browser events, and Markdown
serialization problems. The measured later pass does not regrade those
attempts.

## Risks

- The shared browser-event helper also serves task creation and project
creation. Its regression tests and existing consumers remain included.
- The staging pass qualifies the captured source and configuration. The
coordinator retains source merging, daily pinning, and plan selection.
- The repository test and the unpassed completion test are not
registered by this PR.

## Model Used

OpenAI GPT-6 through Codex, with tool use and code execution. The exact
deployment ID and context window are not exposed by this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have 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 issue/PR references)

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.5
2026-11-02 23:25:56 -06:00
DottaandPaperclip 4461905b92 fix(evals): bind repair launcher and Source3 candidate contracts (#18726)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The private chat catalog tests real user requests through TestOps
and AWS.
> - Each test must bind its immutable candidate and private evidence
owner before it receives model credentials.
> - The previous source pin changed the candidate launcher but kept the
old launcher digest in the full-catalog evidence policy.
> - The private guard rejected the 23-case launch before any original
test or model-key step began.
> - This pull request binds the full-catalog launcher to its reviewed
candidate and selects the next reviewed repair source.
> - The result is an explicit source contract for new measurements, with
the old grades and privacy gates preserved.

## Linked Issues or Issue Description

Refs #18721. Related: #18710 and #18717. The core guidance PR #18717
remains unmerged. A duplicate search found no open PR for this launcher
binding defect.

**What happened?**

The full-catalog evidence policy used the legacy pilot launcher digest
after the candidate launcher changed. All first eight case jobs failed
the private binding step. Their original Execute and model-key steps
were skipped. The operator cancelled the remaining jobs once. This was
an operational failure, not a feature result.

**Expected behavior**

Every singleton policy must use the launcher digest from the same
reviewed manifest as the immutable full-catalog target. A final source
check must compare the digest and private protocol files with the exact
Git target before submission.

**Steps to reproduce**

Compare the old evidencePolicy digest with launch.ts from target
36dff2e. The old owning regression fails. The corrected full-lane policy
emits the digest of launch.ts from target 43c44ccc. The legacy pilot
digest remains unchanged.

## What Changed

- Pin the full catalog to candidate
`43c44ccc823a8c972b247fa7159281887e6f5255` and its exact launcher
digest. Keep the strict private prepare guard and pilot digest
unchanged.
- Bind the actual 242-row candidate descriptor snapshot and the explicit
changed definition fields. Preserve all 244 case IDs, aliases and
original definition provenance.
- Select the reviewed source repairs for skill import guidance,
immutable skill versions, app review navigation, authorized app testing,
adapter prerequisites, the isolated announcement fixture and bounded
diagnostics. These are new candidate measurements.
- Record the one native-accounting change: Studio144 has a 2..3 envelope
and requires three genuine settled source-bound turns. Its query, model,
human count and 540-second case limit stay fixed. All other native
bounds and all original case clocks stay fixed.
- Keep the SDK scanner, compiler/parser identities and canary
certificates unchanged. The public SDK source-input registry is
synchronized; this does not certify the runtime or release held SDK
cases.
- Update the current-target documentation and preserve dated source
history.

## Verification

- The old full-catalog policy fails the new regression with the stale
launcher digest. The corrected policy passes for all 244 singleton
declarations.
- Current CI tests hash the checked exact candidate launcher source
bytes and bind their target and Git blob OID. The previous test accepted
an advanced target with a stale launcher; the corrected test rejects
that mutation. The candidate remains unchanged.
- 62 focused Node controls pass across the manifest, API adapter,
reconciliation and trusted contract owners.
- The source-bound final-GO helper reads the exact Git target launcher
and all three private protocol files. It verifies every singleton policy
against those bytes. All 244 pass.
- The unchanged actual private prepare command passes with the exact
candidate bytes. Mutated launcher bytes, a missing launcher and a
wrong-target policy fail before outputs. No service or provider
credentials are passed in these controls.
- Candidate verification: 294 pure controls, eight Git/FS updater
controls, actual 242 factory declarations with zero fixture callbacks,
and 42 admission/legacy controls pass. SDK registry check reports no
change on the final candidate.
- Prior head6bda80f passed PR CI41577494646 on attempt1:48 jobs passed
and1 intentionally skipped. Both required checks and Greptile5/5 passed.
Two late review findings then required declaration synchronization and
removal of an unused exported helper. Final head09719566 then passed PR
CI41579310890 on attempt1:48 jobs passed and1 intentionally skipped.
Both required checks and exact-head Greptile5/5 pass. The whole ten-file
diff received independent review after both late findings were fixed.
- One actual TypeScript declaration consumer reproduces
missing-export/property errors on the prior declarations and passes
after synchronization (installed TypeScript6.0.3; isolated consumer
only). The finalGO keeps direct exact-source comparisons; no unused
guard export remains.
- Local full graph typecheck/build and native browser/model execution
were not run for this trusted metadata change. Workspace dependency
output prevents a clean local full typecheck claim. Latest-head CI is
required. No new feature PASS is claimed from these controls.

## Risks

- This advances a private evaluation candidate. It does not merge the
candidate's core guidance changes to master. Existing result history and
the catalog qualification gate remain unchanged.
- The new Studio144 accounting and app492 context/outcome are explicit
changed conditions. They must not be credited as passes under the
original definitions.
- SDK input synchronization preserves all scanner guards. Runtime canary
certificates still need real qualification; the other five SDK cases
remain held.
- The isolated announcement fixture contains one public synthetic JSON
object. Production announcement feeds and the global index are
unchanged.
- The cancelled 23-case launch must be reported as operational BROKEN
rows with unknown original grades. It must not be retried under the
unchanged source.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) assisted with source integration,
code, tests and review. The model used tool execution and repository
inspection. The host did not report the context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 22:54:16 -06:00
Dotta fea6163811 test(evals): pin synchronized chat repair declarations and definitions (#18721)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The chat catalog runs a fixed candidate through the trusted TestOps
lane.
> - The first repair source exposed fixture, observation and
evidence-readiness defects.
> - Changed declarations also need matching static runtime descriptors.
> - This pull request pins one corrected candidate and records each
changed definition.
> - New measurements keep their source and original outcomes separate
from past results.

## Linked Issues or Issue Description

Refs: #18710, #18693, #18680, #18647.

**What happened?**

The first repair candidate left five static descriptors out of sync with
its actual declarations. The real no-callback admission check rejects
them. A five-case attempt was cancelled before any case or model step.
The earlier pin note overstated remote coverage: importing the catalog
did not load every actual factory.

**Expected behavior**

Every repaired declaration must pass the real factory admission check
before a new batch. The trusted pin must record exact source and
definition changes. Existing case identities, prior measurements and the
full-catalog pass gate must remain intact.

**Steps to reproduce**

Run `node --import ./cli/node_modules/tsx/dist/loader.mjs
tests/runner-e2e/chat-catalog-consistency.ts` on the old candidate. It
rejects five declarations. The corrected candidate admits all 242
declarations without invoking a fixture. The existing legacy-cell
scoring and selection controls also pass.

## What Changed

- Pin candidate `36dff2eab3dfb6de6efb4fd2ce6c1a58f8a5f383`. Its
[candidate-only
delta](https://github.com/paperclipai/paperclip/compare/9ab0f951a5b5990c266ef4456610e0a0775aa334...36dff2eab3dfb6de6efb4fd2ce6c1a58f8a5f383)
remains separate from master application code.
- Record the real descriptor digest and all 19 declaration-field changes
across 18 cases. Check them against the exact candidate static
descriptor snapshot, including setup policies. The runtime loader still
rejects drift.
- Keep original definition values and record 19 manifest-field changes
across 15 cases. These include the clarified Fast response request,
reviewed goal/skill navigation outcomes, and scoped oracle/source
ownership changes.
- Keep unchanged all 244 ordered identities, model, case clocks,
native-run bounds, private evidence rules, workflows and reporting
authority. The original ledger and historical results are unchanged.
- Require actual factory admission and legacy controls before each
repair-batch GO. SDK audit capture remains private diagnosis only; it
does not waive scanner rejection or qualify the other SDK cases.

## Verification

- Candidate focused controls: 561 passed across 32 pure test files.
- Real lazy factory admission: 242 declarations passed, with zero
fixture callbacks. The prior source failed 18 declarations before
descriptor sync. The two-file admission and legacy scoring suite passed
all 42 controls.
- Trusted manifest, reconciliation and adapter controls: 38 passed.
Contract and dispatch controls: 23 passed.
- Independent source reviews cover the repair slices, descriptor sync
and this metadata pin.
- `git diff --check` passed.
- No local app, DB, native or model run was started for this metadata
PR. Full harness typecheck/build is not qualified: existing workspace
dependency errors remain outside these pure checks. The established
credential-free remote Runner build is still required before paid
queries. It does not typecheck the full harness graph.
- Initial head 90d4ecf passed first-attempt CI (48 passed, 1 skipped)
and Greptile 5/5. A later review found stale current-target prose and an
unchecked setup-policy provenance assertion. The corrected head adds the
exact candidate descriptor snapshot, computes its digest, and compares
every declared field. A wrong-policy mutant accepted by the parent is
now rejected, as is a stale digest. Correct metadata controls pass all
38 cases. Latest-head CI41572232196 passed48 jobs with1 skip after one
approved failed-only recovery. The first attempt failed one browser
cleanup cancellation with PostgreSQL row-lock timeout; the lock holder
remains unknown. No server or timeout change was made. All46 successful
executions kept their original full step and execution timestamps. Only
the failed browser shard and dependent e2e summary reran. Both required
checks passed, current-head Greptile is5/5 and all review threads are
resolved. An optional review may remain queued; no claim is made that
all optional checks finished. No corrected-candidate feature pass is
claimed.

## Risks

The candidate changes selected setup, observation and oracle conditions.
Each new result must retain its exact source and declared changes; it
cannot replace an old failed result. The Fast response request and
goal/skill outcome changes are explicit new definitions. Static TestOps
prose may still show the original definition until a separate supported
metadata reconciliation. SDK scanner findings remain unknown until the
private audit is captured; the scanner and evidence bounds remain
enforced.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) with reasoning, source editing and
tool use. The exact context window is not exposed by this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either linked existing issues or described the issue in-PR
following the issue template
- [x] I have not referenced internal or instance-local Paperclip issues
or links
- [x] My branch name describes the change and contains no internal
Paperclip ticket id
- [x] I have run focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All required 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
canary/v2026.1103.0-canary.4
2026-11-02 21:55:33 -06:00
DottaandPaperclip 1e3ab690b0 fix(routines): prevent recursive Sentry run repairs (#18714)
Validate Sentry failed-run alerts before routine dispatch. Reject repair-generated provenance and private sources. Deduplicate source runs through stable primary-key receipts, including setup retries and suppressed deliveries.

Verified with 166 focused tests, server typecheck and build, generated-reference checks, passing required CI, and Greptile 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-02 21:37:11 -06:00
Dotta f8b35b3318 fix(ui): retain Slack conversation handoff after setup (#18722)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Slack setup connects a person with an agent in Slack.
> - Welcome delivery can complete setup before the person chooses Open
Slack.
> - Success and saved settings then offer no link to the conversation.
> - This pull request retains Open Slack in both views.
> - The benefit is that people can use the connected bot without finding
its URL elsewhere.

## Linked Issues or Issue Description

Refs: #18707. This is the next problem found during its deployed user
walkthrough.

**What happened?**

Managed setup completed after welcome delivery. The Open Slack link
disappeared. Success offered Done, and saved settings offered only Slack
app configuration. The bot could answer, but the handoff to its
conversation was lost.

**Expected behavior**

A person can open the connected bot from Success and from the saved
connection.

**Steps to reproduce**

1. Complete managed Slack setup with welcome delivery.
2. Wait for automatic Success before choosing Open Slack.
3. Choose Done and open the saved connection. No conversation link is
available.

## What Changed

- Retain Open Slack on Success while keeping the centered Done action.
- Add Open Slack to completed Slack connection pages. Keep app
configuration separate.
- Use a saved DM only when its linked owner matches the current
signed-in account. Other managers and unknown identities use the
provider-link or Slack fallback.
- Update the existing component regressions, three Storybook cases,
setup guidance and feature recipe.

The Slack UI owns the shared URL helper. This change adds no API or
permission contract and leaves unfinished setup on its existing path.

## Verification

- Focused Slack component and prompt suites: 40 passed. All related chat
UI suites: 269 passed across 19 files. The settings regression switches
from the installer to a second user and then to a signed-out state.
- Repository typecheck and production build: passed.
- Token gates, map structure and Storybook catalog checks: passed. The
map/catalog Node suite passed all 30 tests; these are structural checks.
- Storybook managed and own-app Success play assertions passed. The
managed mobile view retained readable Open Slack and Done controls after
scrolling. Saved settings play assertions passed after a fresh page
load. Fixtures simulate Slack; no live provider actions were sent from
Storybook.
- The first local typecheck rejected an unsupported Storybook assertion
option. It passed after using an exact-name regular expression. The
settings story first hit a stale Vite dynamic-import cache; a normal
reload fetched the current module and all settings play assertions
passed. Restarting the owned review server later emitted Storybook
manager state timeouts; all three production-page play cases passed
again on the corrected head.
- The preceding deployed fix produced real Slack DM and thread replies.
This follow-up still needs deployed acceptance through its visible Open
Slack link.
- Greptile first found that a second manager could receive the
installer's DM link. The correction checks the linked owner against the
resolved account and falls back while identity is unknown. The two
threads have replies and are resolved. Greptile reviewed corrected head
94a6946719 at 5/5 with no new findings.
The optional Paperclip agent check ended neutral without a complete
assessment; one fresh review was requested. No fresh secondary
assessment was available at merge.
- [All required CI suites
passed](https://github.com/paperclipai/paperclip/actions/runs/41571276944)
on corrected head 94a6946719. Full local
Vitest was not repeated for this UI-only follow-up.

## Risks

- Low risk. This adds navigation to existing Slack destinations.
- Old connections without a known DM use their provider link or Slack.
- No schema, credential, scope, identity-link or transport changes. The
UI consumes the existing shared account identity query.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository editing, browser
use and command execution. The runtime does not expose a more precise
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
2026-11-02 21:33:59 -06:00
DottaandPaperclip 09162fe893 refactor(runner): clarify native task assignment guidance (#18704)
## Thinking Path

> - Paperclip lets people assign work to AI agents.
> - Native task creation can start the assigned agent as soon as the
task is ready.
> - The default assignee is the agent that creates the task.
> - An agent can omit the requested teammate, create work for itself,
and reassign it too late.
> - The server already supports setting the requested agent and project
during creation.
> - This pull request makes those fields and the early-start risk clear
in both tool catalogs and the delegated-task example.
> - The benefit is clearer guidance for the existing delegation
contract.

## Linked Issues or Issue Description

Related: #13281.

**What happened?**

An observed delegation attempt called `create_task` with only a title
and retry key. The task used the documented current-agent default and
started work before a later reassignment. The server honored its
contract. The original failed QA result remains failed.

**Expected behavior**

When a user names an existing teammate and project, the agent should put
their exact IDs in `assigneeActorId` and `projectId` during task
creation. The requested worker can then start with the correct task
ownership and project.

**Steps to reproduce**

1. Ask an agent to create work for a named existing teammate in a named
project.
2. Create a ready task with only its title and retry key.
3. Observe that the creating agent is assigned and can start before a
later reassignment.

This is a guidance mitigation for agent tool misuse. It does not change
the default or enforce model compliance. A fresh deployed qualification
is still required.

## What Changed

- Explain initial teammate and project selection in the canonical
`create_task` description and its two field descriptions.
- Add a representative delegated-task call with an explicit agent,
project, and saved plan.
- Synchronize the same three descriptions in the sibling semantic-action
catalog. Keep its schema constraints intact.
- Keep the global execution prompt byte-for-byte equal to the base.
Revision `paperclip-execution.v8` already directs the agent to create
delegated work with the teammate ID.
- Refresh the generated catalogs, seeded catalog identity, and protocol
manifest.
- Make the collaboration contract test use the declared scenario
example, as the general contract test already does. Retain separate
live-example validation and strict scenario input checks.

## Verification

- All 79 existing native controls passed across `chat-project-tools`,
`paperclip-runner-tool-authority`, `task-creation-backlog`, and
`tool-receipt-recovery`. These cover alternate-agent readback,
current-agent defaults, backlog holds, company boundaries, and dispatch
recovery after commit.
- All 108 protocol-action, semantic-catalog, catalog-doc,
runtime-context, and collaboration checks passed. All 11 contract
fingerprint checks passed.
- The original CI collaboration-test failure reproduced locally before
correction: the test sent live-only fields to the older scenario schema.
After selecting the declared scenario example, all 13 collaboration
cases passed. Malformed titles, undeclared project fields, and arbitrary
unknown fields still reject. No schema or live example was changed for
this correction.
- Generator checks passed for semantic contracts, the semantic-action
catalog, operation groups, and protocol coverage.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` passed.
- A structural comparison confirms that types, required fields, lengths,
modes, permissions, outputs, and defaults are unchanged on both catalog
surfaces.
- No new text-matching tests were added. These local checks passed again
after the global prompt was restored. Fresh exact-head Greptile and
Paperclip reviews are both 5/5 with no actionable findings.
[Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41565349812)
completed successfully on `2e5f93e122191e17b316a7780a74ff404fc468f3`
(attempt 2), with all 49 workflow jobs successful.
- Current-head CI first failed only the unchanged native-process
retention case at its original five-second limit. The shard passed 2,130
other tests and skipped eight. One unchanged local Node 24 control
passed. The original test and retention dependency blobs match the base.
The exact timeout cause remains unknown. No source, assertion, or time
limit changed. One authorized recheck of only that runner shard and its
normal final gate passed. The recheck passed 2,131 tests and skipped
eight. The other 47 successful job results were carried forward with
their original start and finish times.
- The prior head `42207172dd4bc376dab880dbccb2c698acccf6c4` passed all
49 CI jobs and fresh 5/5 reviews. Its first CI attempt lost one server
runner to a reported shutdown. One authorized retry of only that lost
shard and its normal gate passed with unchanged assertions and time
limits. The original failure and recovery remain recorded.
- A normal merge of that prior head was rejected by the base policy
because the global prompt required a code-owner review. This revision
drops that optional global change. No policy override or bypass was
used.
- The new catalogs have semantic catalog digest
`sha256:5af904b7fc088509b98dde41611c042ff3c22c881e252190817978de0d1b733a`.
The authorized `create_task` operation digest is
`sha256:f5dad10c7969680d91514603966705ac09ceaa3f2cff21fd6c199e2de0d7a63d`.
- A new run can report admitted prompt revision v8 and its digest. The
ordinary run-profile tool fingerprint does not hash these descriptions.
Source/Core and matching provider-pack identity prove deployed code, not
model delivery or compliance. A fresh campaign with new agents is still
required.
- No model run or deployed acceptance was performed for this source
change. The original failed qualification remains failed. This
tool-guidance change is a mitigation hypothesis.

## Risks

The longer tool descriptions change the catalog identity. A model can
still omit a requested field. The global prompt remains v8. Existing
assignment, authorization, wake, replay, and session behavior stays
intact. A new campaign is required because a stored provider session can
retain old tool declarations. A native-process retention test has a
recurring five-second timeout on unchanged code. One unchanged local
Node 24 control passed. This does not prove CI reliability or explain
the timeout. No timeout or assertion was changed.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.3
2026-11-02 20:46:07 -06:00
DottaandPaperclip e5e22148e4 test(evals): pin the reviewed chat catalog fixture repairs (#18710)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The chat catalog uses a trusted TestOps workflow and an immutable
candidate source.
> - The retained first pass found fixture failures before real feature
work could start.
> - Candidate repairs must use the same source checks as the original
lane.
> - This pull request advances only the fixed catalog target and its
source note.
> - New AWS measurements keep the original case queries, limits, graders
and reporting path.

## Linked Issues or Issue Description

Refs: #18542, #18647, #18680, #18693.

**What happened?**

The full-catalog lane remains pinned to the original candidate. A repair
candidate cannot run through the trusted TestOps selection without a
reviewed pin change.

**Expected behavior**

TestOps must select the reviewed immutable repair source. It must keep
the existing case identities, model, clocks, private evidence controls
and original grading.

**Steps to reproduce**

Inspect the full-catalog target in the manifest. The trusted contract
uses that exact commit for selection, source checks, build and export.

## What Changed

- Advance the immutable full-catalog target to
[`9ab0f951a5b5990c266ef4456610e0a0775aa334`](https://github.com/paperclipai/paperclip/commit/9ab0f951a5b5990c266ef4456610e0a0775aa334).
[Candidate-only
delta](https://github.com/paperclipai/paperclip/compare/3b66c3c144360ddf32714a0742fd774b8ceafb16...9ab0f951a5b5990c266ef4456610e0a0775aa334).
- Preserve all original queries and limits. Record company observer
source ownership and the secret-entry v2 oracle as explicit metadata
overrides against the original definition source.
- Explain SDK staging, scoped human membership, original-clock
observation and exact controller-secret baseline conditions. Preserve
the original failed measurements.
- Leave the application and held core fixes off master. This change does
not copy the candidate app or catalog implementation to master.

## Verification

- Candidate integration: 167 focused pure tests passed for SDK custody,
membership, feature and privacy controls.
- Trusted target consumers: 46 manifest, full-catalog adapter and
dispatch contract tests passed.
- The candidate has no diff to the original YAML queries or descriptor
bytes.
- `git diff --check` passed.
- Local full typecheck, application build, DB and model execution were
not run for this two-file pin change. Worker typecheck attempts hit
existing missing workspace dependencies and are not recorded as passes.
The trusted AWS source check and build must pass before any native
query. It imports the real candidate catalog and checks every descriptor
before provider access. It does not typecheck all harness TypeScript
files.
- Initial CI41563164012 passed48 jobs with1 skip. A later review
requested the exact target assertion; the valid-SHA mutant is now
rejected. Corrected-head CI41564795118 passed48 jobs with1 skip
on2226f093. Both required checks passed. Greptile and the follow-up
source review are5/5 with no unresolved threads. No new candidate case
result is claimed here.

## Risks

A new fixture condition can change a measured outcome. Each result
records the actual candidate and trusted workflow revision. Original
failed measurements remain unchanged. The model, case bounds,
independent feature requirements, private custody, reporting identities
and automatic retry count remain fixed. This pin applies to future
full-catalog runs, so operators must not infer that every catalog case
has been qualified. The inherited source-ref label is not source
authority; the exact checked commit is authoritative.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) with reasoning, source editing and
tool use. The exact context window is not exposed by this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 20:28:06 -06:00
DottaandPaperclip 36df8933f0 fix(slack): resolve manager grants during bot setup (#18707)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Slack chat connections let people start and continue work with an
agent.
> - Managed setup reuses a personal Slack workspace authorization to
create and install the bot.
> - The provisioning route passed that Slack grant ID to the generic
tool-grant lookup.
> - A valid workspace therefore failed with a 404 before provisioning
started.
> - This pull request selects the existing Slack grant resolver for
provisioning and validates the request-body ID.
> - The benefit is that saved Slack setup can continue while company and
personal ownership checks remain enforced.

## Linked Issues or Issue Description

Refs: #15679, which introduced managed Slack setup.

**What happened?**

Continuing a saved managed Slack draft returned `Connection management
resource not found`. The workspace list and endpoint read both
succeeded. The provisioning POST returned 404.

**Expected behavior**

Continue should use the selected personal Slack manager grant and create
or resume the bot once.

**Steps to reproduce**

1. Authorize a Slack workspace for managed bot setup.
2. Create or resume a managed Slack chat connection.
3. Select the saved workspace and choose Continue.

## What Changed

- Select the Slack manager-grant resolver for the managed provisioning
route.
- Accept a validated grant ID from the route parameter or request body.
Enforce the current user's ownership for both board and agent requests.
- Run the existing duplicate-install regression through the HTTP route.
Add HTTP rejection cases for missing, malformed, foreign-company and
other-user grants.
- Document the grant boundary and update the matching feature and
agent-access maps.

The shared authorization guard owns resource resolution and company
checks. Its existing Slack resolver previously handled only the
revocation route parameter. This change extends that resolver to the
provisioning body's grant ID. Generic tool-grant resolution and
deployments without managed Slack keep their existing path.

## Verification

- Before the fix, the HTTP installation regression failed with the same
404 as the browser walkthrough.
- `pnpm exec vitest run
server/src/__tests__/chat-channels.integration.test.ts -t 'managed
Slack'` — 31 passed. Uses real PostgreSQL, production routes and
provider fixtures. The board actor is a fixture; this does not qualify
live Slack or agent authentication.
- `node scripts/check-maps.mjs` and `git diff --check` — passed.
- `pnpm -r typecheck` and `pnpm build` — passed. Full local Vitest is
running. [All CI gates
passed](https://github.com/paperclipai/paperclip/actions/runs/41561466277)
for commit c04b426e60. Greptile and
Paperclip reviews are 5/5 with no required changes. Deployed Slack
acceptance remains pending.

## Risks

- Low risk. The guard must select the correct grant registry. Tests
cover valid ownership, duplicate requests and rejected IDs.
- Board requests now receive the ownership denial in the guard. The
Slack service already required the same owner.
- No schema, credential format, provider scope or runtime transport
changes.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, repository editing, browser
use and command execution. The runtime does not expose a more precise
model ID or context-window size.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.2
2026-11-02 19:55:29 -06:00
Nicky LeachandPaperclip 6d72243d8a fix(runtime): recover task creation after a lost acquire reply (#18692)
## Thinking Path

> - Paperclip manages agent execution and the resources that execution
owns.
> - A retained environment task can need a replacement before the next
turn.
> - Core records the creation attempt before it asks the provider to
acquire it.
> - A lost reply can leave that journal without the resource ID needed
for cleanup.
> - This change lets an opted-in provider recover the identity from that
recorded attempt.
> - Core still requires the existing exact-task termination proof before
it releases ownership.

## Linked Issues or Issue Description

Refs #18405 and #18658. This is the separate lost-reply follow-up from
their recovery audit.

**Draft status:** Both prior review findings are fixed in
`a66520c8d4e06e0eec6ccb5446190ace0ca3003f`. Fresh standard Greptile is
5/5 with no unresolved threads. Current-head CI is green (53 successful
checks/statuses including Snyk, three expected skips). Apex completed
5/5 on this exact head at 2026-11-03T00:54:59Z (request 6592407130),
with no unresolved threads. The review cycle is complete; the PR remains
draft for human merge review.

**What happened?**

If a replacement task's acquire reply is never received, the creation
journal can reach manual reconciliation without a resource ID. Startup
cleanup cannot complete, and ordinary Stop cannot release the run owner.

**Expected behavior**

When the selected provider supports creation inspection, Core should
retain enough binding information to inspect the recorded attempt and
continue verified cleanup. An inspected identity must not count as
termination proof.

**Steps to reproduce**

1. Use a retained task whose provider supports creation inspection.
2. Lose the replacement acquire reply before Core records its resource
ID.
3. Restart cleanup and inspect the existing creation journal.
4. Confirm that the exact task is stopped and its termination receipt is
saved before cancellation releases the owner.

**Paperclip version or commit**

Current head `a66520c8d4e06e0eec6ccb5446190ace0ca3003f`, based on master
`3a7bb4dac62dbd7a34a55deb665c55df310bdf64`. Tested with isolated
PostgreSQL fixtures.

**Deployment mode**

Local source tests with controlled provider responses. No deployment or
live model request.

## What Changed

- Save the selected inspection capability and prior opaque binding in
the existing creation journal. Acquire through that same worker so a
worker replacement cannot change the recorded contract.
- Make failed opted-in creations due through the existing cleanup
notification and saved retry deadline.
- Add optional SDK observation field `creationLease`. Use it only to
recover the requested creation's identity and binding, then follow the
existing Stop, status, completion and receipt checks.
- Keep old entries and providers without the recorded opt-in under their
existing reconciliation policy.
- Add actual PostgreSQL recovery, cancellation and worker-replacement
regressions. Document the provider contract.

## Verification

- Current correction: 53 distinct targeted cases pass (20 real-worker
IPC, 12 task-recovery PostgreSQL and 21 generic-sandbox cases), with
server typechecking. The IPC selection was rerun after the final
late-observation ordering refinement; the other tested sources were
unchanged.
- An assembled live-child IPC and PostgreSQL case proves cleanup and
cancellation release the owner despite the original worker never
replying and remaining alive. Accepted host work, unrelated acquisitions
and late observations remain accounted for. Removing the recovery
handoff and restoring the old drain snapshot produce distinct assertion
failures.
- The unsupported-host control skips all 12 PostgreSQL cases without
setup; removing the guard fails the controlled setup. These tests do not
constitute live VM/provider qualification.
- Initial head `5db6882` passed an exact reference-tree comparison
against master plus the reviewed follow-up patch, 97 targeted cases and
server typechecking. Those checks predate the final inspection
correction.
- Previous head `59f87fa` passed 32 targeted cases (11 task-recovery and
21 generic-sandbox cases) and server typechecking. Both `pending` and
`needs_reconciliation` observations without `creationLease` preserve
ownership and get a future retry deadline. Restoring the previous guard
makes both new cases fail.
- The reproduced failure was a wrong generic cleanup shape that could
resolve its journal while leaving the owner held—not a demonstrated
false ownership release. The correction reuses the existing
missing-identity guard before the generic decoder and leaves generic
sandbox behavior unchanged.
- Earlier affected selection: 72 cases passed on the original follow-up
base. This overlaps the final selection and is not an additional count
of unique final-head tests.
- Two isolated negative controls restore the missing task inspection and
redirected-worker behaviors. Both fail at the expected recovery and
dispatch assertions without changing production source files.
- The PostgreSQL cases verify one cleanup lease, both late-result
orders, recovery after the old journal deadline, ordinary legacy
behavior, retained ownership on missing or mismatched identity, and
cancellation acknowledgement after exact termination proof.
- The tests use actual database and run-control services with controlled
worker callbacks. They do not prove live IPC or production recovery
timing.
- A compatible provider is needed for the new recovery path. No normal
successful-startup database or network call is added. No ordinary TTFT
improvement is claimed; the repair removes an indefinite ownership hold
for supported lost replies. No full local CI suite was run; GitHub runs
the full regression gates.

## Risks

The provider must recover the identity for the recorded creation
operation and preserve its selected binding. `creationLease` does not
authorize a new turn or prove that a process stopped. Older journal
entries do not infer a new identity after an upgrade. Unavailable
original machine bindings or credentials retain the existing uncertainty
behavior; this change does not repair machine or credential loss. No
schema migration, deployment or ROM qualification is included.

## Model Used

OpenAI Codex, GPT-6 family. Exact model ID and context window are not
exposed in this session. Tool-assisted implementation, targeted tests
and independent subagent review.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 17:45:07 -08:00
DottaandPaperclip 40ea7a9b89 fix(heartbeat): wait for inherited remote workspace writers (#18691)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - A child task can inherit its parent's remote workspace.
> - The remote workspace permits one writer until that writer saves its
files.
> - Reservation reports an active writer as a generic setup failure.
> - The existing shared workspace wait does not cover inherited isolated
workspaces or a race at reservation.
> - This pull request sends verified active writer contention through
the existing scheduled retry path.
> - The child keeps a live execution path while unfinished files remain
protected.

## Linked Issues or Issue Description

**What happened?**

A native sandbox task inherited an isolated remote workspace from its
running parent. Setup failed with `The workspace still has an unfinished
writer or save operation.` The child became blocked before provider
execution and had no scheduled continuation after the parent saved.

**Expected behavior**

The child waits for the active writer through the existing workspace
retry path. It keeps its workspace binding. A stale writer or a stopped
writer with unfinished saves still requires reconciliation.

**Steps to reproduce**

1. Start a native sandbox task with remote workspace storage.
2. Create a child that inherits its isolated workspace or operator
branch while the parent is still writing.
3. Start the child. On the old code, atomic reservation raises a generic
setup failure.

**Paperclip version or commit**

Observed on `410b0e27015495ab8951768b5b0b94727de33785`. Regression
reproduced on source based on
`554a770c6f8e48e327e19f5208b575a5ec5bce30`.

**Deployment mode**

Authenticated managed server, external PostgreSQL, native Codex with a
Daytona sandbox. The failed attempt stopped before runtime selection or
provider startup.

Related: #18611 permits inherited remote bindings. #16371 adds waits for
reused shared execution workspaces. This repair handles active writer
contention at atomic remote reservation. #17156 proposes a separate
change to task workspace inheritance.

## What Changed

- Return a typed conflict with the exact active writer from the remote
reservation owner. Keep company, binding, access, and writer checks in
that transaction.
- Translate a recent running writer into the existing heartbeat
workspace wait. Keep stale, unknown, stopped, dirty, and uncertain save
fences. The writer task lookup uses its primary key.
- Preserve the admitted assignee role across preparation so reassignment
cannot turn an old owner into a guest retry.
- Add PostgreSQL regressions for isolated workspaces, operator branches,
native writer identity, unchanged saved authority, admission after save,
durable retry, Stop, and reassignment before contention reaches the wait
handler.
- Update the development guide and workspace verification recipes.

## Verification

- Red: both inherited isolated/operator preparation cases fail on the
old code. They receive `HttpError(remote_workspace_writer_pending)`
instead of a workspace wait. No provider or allocation starts.
- Green: those same cases pass after the repair. The assembled public
heartbeat cases also pass: one scheduled retry owns the task lock, no
sandbox lease is created, the original writer and saved authority remain
unchanged, and Stop prevents retry promotion.
- Ownership race red/green: changing the assignee during preparation
produced `wasIssueAssignee: false` before the review fix. The same
regression now preserves its original role. A real transaction fault
boundary also reassigns the task after reservation rejects it and before
the wait handler runs; promotion cancels that retry with
`issue_reassigned`.
- Test isolation: an initial combined placement cached the synthetic S3
run-log backend and failed twelve later preparation cases. The assembled
native tests now have their own process. The ordered reproduction and
all four complete affected suites pass after that change: 171 tests,
zero skipped.
- Four additional saved-file lifecycle cases pass against disposable
Docker PostgreSQL 17 with independent filesystem execution and local
object storage. They restore inherited shared, isolated, and
operator-branch files on a new allocation and retain the second-writer
fence. The other 42 cases in that file were outside the selection.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` pass on the final source.
- The earlier `pnpm test:run` passed all six chat shards: 1,828 tests.
Its remaining general-server phase was interrupted after final-head CI
passed. That local command began before the review fix and is not a
complete local full-suite pass.
- Final head `096235d8fc80033f92d8de1fcfa9835795ba0456`: 54 successful
checks/statuses, three skipped checks, and two neutral checks. None is
pending or failed. All build, typecheck, general/serialized tests,
Runner checks, and eight browser E2E shards pass in
[CI](https://github.com/paperclipai/paperclip/actions/runs/41544310900).
The PR is mergeable with no conflicts.
- Greptile is 5/5 on that exact head. Its ownership finding is resolved
and no review thread remains open. Paperclip Review also reports 5/5
with no findings; its check conclusion is neutral. Its earlier
status-conflict recovery completed through the ordinary review request
path.
- Local environment: macOS arm64, Node 26.4.0, pnpm 9.15.4, isolated
native PostgreSQL and the disposable PostgreSQL 17 lifecycle fixture.
The acquisition boundary is controlled in the focused preparation cases.
No live Codex/Daytona replay is claimed: the local environment and test
configuration lack the required test credentials.
- No deployment, merge, or original task recovery is claimed.

## Risks

- Incorrect contention classification could retry a stopped or
unverified writer. Only a running writer with a same-company task and
recent activity enters the wait path. Stale and terminal dirty cases
retain the conflict.
- Retries must not start another executor or release unsaved files.
Reservation remains atomic. The tests check unchanged writer authority,
no allocation before release, one durable retry, retained binding, Stop,
and reassignment before the conflict is caught.
- No API schema, database migration, provider configuration, model,
credential, trust, or approval changes.

## Model Used

- OpenAI `gpt-6.1-sol` through Codex. The context window size is not
exposed in this session. Used reasoning, tool use, code execution, and
browser diagnostics. No sub-agents were used.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 19:26:59 -06:00
DottaandPaperclip ca3f99449e fix(testops): report retained catalog results with explicit gaps (#18693)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Product E2E reports preserve the original evaluation and its
evidence.
> - The catalog report joins one safe projection for each selected case.
> - One unavailable projection currently blocks every retained sibling
result.
> - A reporting gap must not become a fabricated evaluation result.
> - This PR adds an explicit offline retained-reporting mode to the
existing aggregate owner.
> - It preserves authentic grades and reports unavailable originals as
separate operational gaps.

## Linked Issues or Issue Description

**What happened?**

A completed 196-case catalog run produced 153 safe projections. The
strict aggregate rejected the incomplete set, so no outcomes reached
TestOps. One additional retained original can be recovered through the
unchanged strict reader. The expected retained archive keys for the
remaining 42 are absent.

**Expected behavior**

Publish authentic retained outcomes. Mark unavailable original evidence
as a reporting gap with an UNKNOWN original grade. Keep exact
selected-case coverage and all original evidence checks.

**Steps to reproduce**

1. Prepare two valid singleton projections for a three-case selection.
2. Supply a terminal, source-bound custody disposition for the third
case.
3. Observe that the existing aggregate rejects the incomplete projection
set.

Refs: #18647, #18676, #18680. This PR changes evaluation infrastructure
only. It does not merge product fixes or change the candidate
application.

## What Changed

- Add an explicit `retained-reporting` mode to the existing catalog
aggregate CLI.
- Validate each authentic singleton with the unchanged strict reader,
merger and Allure exporter.
- Require an exact, disjoint partition of authentic originals and
explicitly recorded missing retained archives.
- Emit separate BROKEN reporting-gap records. Their original status,
native-run count, checks and cleanup are null. They contain no
fabricated execution time or test steps.
- Freeze one Allure payload and a file-hash manifest. Keep recovery
executor identity separate from original measurement identity.
- Document the operator data-preparation and once-only publication
procedure.

## Verification

- Meaningful parent RED: the existing aggregate rejects the valid
partial original set with `Incomplete projection set`.
- Pure Vitest: 30 tests pass, including four new recovery controls and
26 unchanged strict exporter controls.
- Existing API and streaming Node controls pass alongside the new
partition controls.
- Negative controls reject foreign origin, duplicate or unexplained
membership, active upstream jobs, corrupt authentic data, foreign
archive keys, injected private text and a supplied gap PASS.
- Actual retained data validates as 154 authentic originals: 29 passed
and 125 failed. Seven failed originals also have failed cleanup. There
are 42 separate UNKNOWN reporting gaps. This is not a new model run or
regrade.
- `git diff --check` passes.
- Local runner noEmit encountered stale workspace package output/type
errors. No changed-file type errors remain. The current-head AWS/GHA
typecheck, build and test gates pass. Full app/database/provider setup
was not run locally under the user's execution constraint.
- CI run 41547666905 is successful at head
b20ee216f1: 48 successful jobs and 1
allowed skip. One unchanged server fixture failed before its test body
with PostgreSQL23505 on its short company prefix. One failed-only
recovery passed. All 46 prior successful executions were carried forward
with identical execution/step timestamps. The original failure is
retained; its conflicting row identity was not captured. No server code
or timeout changed.
- Greptile is 5/5 on the exact current head. All known review threads
are resolved. The nonrequired Paperclip Review check is queued; it is
not a required CI gate.

## Risks

The disposition is an operator data record, not an authentication
mechanism. The operator must authenticate the original selection,
terminal job state and exact-key custody observations before using it. A
missing retained archive does not establish that an evaluation passed or
failed. Upstream producer byte/privacy limits remain unchanged. The
command does not upload, dispatch agents, acquire credentials or grant
privileges. An ambiguous later upload must be reconciled with GET
requests, without another export or blind resend.

## Model Used

OpenAI GPT-6.1 (`gpt-6.1-sol`), with reasoning, repository tools and
code execution. The host does not expose a context-window value. No
model or provider evaluation was run for this change.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 19:26:11 -06:00
DottaandPaperclip 8145b01e2d feat(ui): add New task above Chat in Coordinator sidebar (#18703)
Add a visible New task button above Chat. Open the existing task form in expanded and collapsed sidebar states. Update the Storybook fixture and navigation map. Add tests for action order and dialog dispatch.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-02 19:14:20 -06:00
DottaandPaperclip 5955dd4eb4 fix(files): preserve saved reads during allocation cleanup (#18701)
## Thinking Path

> - Paperclip saves remote agent work in committed workspace snapshots.
> - Files can read that save after the writer finishes.
> - Compute cleanup can clear the recorded location while a saved
preview loads.
> - The current fence treats that physical cleanup as a change to the
saved bytes.
> - Permit only that one-way location removal for an already verified
saved copy.
> - Keep all logical-authority checks and live-read fences.

## Linked Issues or Issue Description

Refs: #18677. This fixes the remaining in-flight cleanup race after
saved reads began preferring the current committed version.

A Files preview can return `422 workspace_changed` when allocation
cleanup clears the location during archive loading. The epoch, committed
snapshot, source, clean state, and absent writer can all remain
unchanged. The extracted copy remains valid.

An original QA denial recorded this error eight milliseconds after
location cleanup. Its later successful read does not regrade the failed
attempt. The original audit does not reconstruct the full earlier
authority record. A controlled production-composed regression isolates
the same cleanup transition.

## What Changed

- Allow the recorded location to become null during a verified saved
read while every other parsed authority field stays identical.
- Remember observed removal so a reintroduced or foreign location still
rejects the read.
- Keep live reads, dirty state, active writers, changed epochs,
snapshots, and sources fenced.
- Add a real `createApp` content-route regression with PostgreSQL,
encrypted archive storage, and private-copy cleanup.
- Add negative controls for logical changes, foreign and reintroduced
locations, and live location removal.
- Update developer guidance and the workspace feature/access maps.

## Verification

- Red: the production `createApp` route returned exactly `422
workspace_changed` when normal archive loading overlapped location
removal.
- Green: all 108 Files route and authorization tests passed. The preview
returns the saved bytes, and its private extraction is removed.
- All 46 opt-in workspace lifecycle tests passed on one owned local
PostgreSQL database with local filesystem transport. The database and
server were cleaned up.
- `pnpm -r typecheck`, `pnpm build`, `node scripts/check-maps.mjs`, and
`git diff --check` passed.
- [Current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41550908692)
completed successfully on `45517b474b6866de2de6c618b7ff2193c93038ac`
(attempt 2). All PR gates are clean: 55 successes, 3 skips, and 1
neutral review result. The full suite ran in CI; it was not duplicated
as a long local full-suite invocation.
- [Original CI
failure](https://github.com/paperclipai/paperclip/actions/runs/41550908692/job/125638034035)
is retained: an unchanged mobile frame-sampling check collected 5 frames
where more than 5 are required; all sampled geometry was identical. The
exact unchanged local Chrome case passed, then one failed-job-only retry
passed on the same source. No assertion or time budget changed.
- Fresh exact-head Greptile review is 5/5 with no findings, inline
comments, or unresolved threads. The separate Paperclip static review is
also 5/5 with no actionable findings.
- No deployed acceptance is claimed by these local tests. The original
failed QA attempt remains failed.

## Risks

This permits one specific transition for an immutable saved copy: the
original recorded location can disappear. The company/workspace query,
epoch, snapshot, source, dirty state, writer, and
location-reintroduction checks remain. A live read still rejects
physical location changes. The change does not release compute, change
snapshot admission, or alter extraction limits. No schema or API-shape
change is required.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1103.0-canary.1
2026-11-02 18:33:49 -06:00
DottaandPaperclip 16643a6e03 fix(runner): recover pending Stop cleanup after controller restart (#18682)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The server owns execution, Stop delivery, and usage settlement.
> - A Stop can remain pending when the controller restarts.
> - Recovery must reach the existing session without starting more paid
work.
> - Startup and budget fences currently block that cleanup, and
interrupted runs leave the restart selection.
> - This pull request gives exact audited Stop cleanup a shared
authority check and records its real acknowledgement.
> - The benefit is safe cleanup while usage debt remains honest.

## Linked Issues or Issue Description

**What happened?**

A pending native run-only Stop can retain an unfinished execution owner
after controller loss. Its startup cancellation fence prevents recovery
admission. If teardown marks the run interrupted and clears its task
lock, restart selection also omits it. A recovered session can receive
cancellation without the durable acknowledgement that the normal Stop
request would save.

**Expected behavior**

Recover only the existing remote session for the audited pending Stop.
Keep fresh provider work blocked, including during budget pause. Keep
incomplete usage pending until a real complete receipt arrives.

**Steps to reproduce**

1. Start a native run with a held reservation and an authenticated
remote checkpoint.
2. Persist a run-only Stop and its startup and execution cancellation
fences before acknowledgement.
3. Lose the controller. Leave the coordinator unfinished, mark the run
interrupted, and clear its task lock.
4. Attempt restart recovery and observe the missing claim or
cancellation admission rejection.

Related work: #14733 binds caller Stop requests. #18658 handles plugin
startup cleanup obligations. #18035 proposes broader accounting changes.
This change repairs existing-session Stop recovery and preserves current
accounting guards.

## What Changed

- Add one shared check for the exact run, company, issue, pending Stop,
intent audit, live recovery lease, generation, and remote reattachment
disposition.
- Include eligible interrupted Stop owners in restart selection. Keep
generic interruptions and another task execution owner fenced.
- Reuse only the original held reservation for cleanup. Keep budget
pause effective for fresh, bootstrap, dead-runner, and unproven recovery
work.
- Apply the same cleanup authority at heartbeat runtime selection and
native entry. Skip attachment staging and warm-owner retirement only for
that exact cleanup. Revalidate at session publication and fail closed if
the proof changed.
- Send the existing Stop through the audited cancellation producer
before turn submission. Close the coordinator only after
acknowledgement, including system-owned run-only Stops.
- Give verified cleanup a transport purpose that retains pending
semantic inputs without replay, dispatch, or a semantic reply. Add an
explicit Core retain-only intake mode; preserve authenticated identity,
schema, digest, sequence and replay checks. Ordinary execution still
requires its dispatcher.
- Add PostgreSQL, native protocol, and startup-fence regressions. Update
the execution contract and recovery maps.

## Verification

- The combined Stop regression fails on unchanged production at the
cancellation reservation guard. Interrupted restart selection also fails
before the repair while its running sibling passes.
- An assembled `heartbeatService.recoverNativeRunsAfterRestart`
regression exposes the earlier runtime-selection fence with the rest of
the repair present. The fixed path reaches selector/claim, runtime
selection, original held-budget reuse during pause, dispatch, real
native protocol, audited cancellation, and heartbeat settlement. It
starts no provider turn, acquires no new sandbox, and does not reclaim
the task lock.
- Fail-if-called attachment staging and turn boundaries remain
untouched. A retained warm-owner regression prevents retirement.
Invalidation at session publication fails closed. Actual backend/driver
constructor tests verify cleanup-purpose forwarding, absent default
options, and denial under foreign ownership.
- Missing usage retains accounting debt and the hold. A later complete
receipt records one 25-cent charge and settles that same hold.
Concurrent duplicate cleanup is denied. Both user-owned and system-owned
Stops pass.
- Real transport tests: 9 pass on Node 24.22.1. They preserve ordinary
saved-tool and completion recovery, prove the authority-denial race
before cancellation, and qualify cleanup with pending
ordinary/completion inputs and either handler ordering.
- Real authenticated Core intake: 11 pass. Callback-present and
callback-absent retain-only cases persist and acknowledge unanswered
input without dispatch, recovery or result. Default missing-dispatcher
rejection and digest-integrity/suspension guards remain effective.
Omitting the callback alone first failed by disconnecting; the explicit
retain-only mode fixes that defect.
- Repository `pnpm -r typecheck`, the server/runner-vendor build, map
checks, and module boundary checks passed locally before integrating the
latest retained-startup change. That integration passes 11 native
startup/cleanup compatibility cases and 3 assembled recovery/accounting
cases. The final broad affected-suite attempt was stopped without a
verdict; it is incomplete. Full repository tests and build are delegated
to current-head GitHub CI.
- Review exposed an additional real-process close failure with
unanswered input. The corrected path requires a fresh exact
provider-stop receipt confirming exit, followed by durable event drain
and exact runner suspension. All 11 focused transport cases pass,
including missing/false exit-proof negatives and ordinary recovery
siblings. Runner TypeScript and map validation pass after this
correction.
- The assembled test controls provider, workspace-transfer and GitHub
bootstrap I/O. It does not qualify hosted credentials, physical provider
termination, workspace preservation, or historical receipt recovery.
Local socket-permission setup failures are separate from semantic
regression results. No hosted replay has run on this repair.

- CI exposed an ordinary factory-call compatibility regression and an
obsolete authority-read test fixture. The repair preserves
single-argument ordinary calls and updates the race fixture without
changing its Stop assertions. The complete native executor suite now
passes all 1,049 tests; the ordinary factory boundary and all five
Stop-accounting cases pass. A separate local environment-default case
twice exceeded its five-second wait while other work ran; its prior-head
CI case passed. The same unchanged case passed an isolated diagnostic
without changing its assertion or timeout; the precise contention source
remains unproven.

- The final fixture edit initially used the wrong overloaded promise
type. CI rejected it; the annotation-only correction passes the exact
`pnpm run typecheck:build-gaps` entry point locally, including server
service tests and remaining workspaces. No runtime assertion changed.

- Final exact head `007fd4d04a2d6338c6dc073e97ab470a277fc3d0`: required
`ci / verify` and `ci / e2e`, build, typecheck and test groups pass.
Greptile is 5/5 with both findings resolved. Three expected checks are
skipped; the optional native check is neutral, while its final
current-head comment gives 5/5 from source inspection without a checkout
or test execution. The first server-shard attempt lost its self-hosted
runner connection; one scoped rerun passed. Its original annotation and
unavailable-log evidence are retained.

## Risks

- This changes execution authority. Cleanup requires an audited, exactly
bound pending Stop, an unfinished coordinator, a live remote
reattachment claim, and the original held reservation. It never
authorizes a replacement provider turn.
- Missing checkpoint, original held reservation, termination, or usage
evidence can keep cleanup or accounting pending. The repair does not
manufacture acknowledgement, replies, receipts, or zero cost.
- Retain-only intake is an internal trusted constructor option. It
changes no agent tool permission. Ordinary callback requirements and
semantic dispatch remain unchanged.
- No schema, public API, provider profile, or deployment setting changes
are required.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, Extra High reasoning, with source
inspection, code execution, and regression testing. The context-window
capacity is not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 18:22:40 -06:00
DottaandPaperclip 82c033ed12 test(e2e): cover uploaded input and personal inbox triage (#18643)
## Thinking Path

> - Paperclip lets people assign work to agents and manage their tasks.
> - Product E2E journeys verify the saved outcome through the browser
and normal APIs.
> - Uploaded input and personal inbox actions need repeatable coverage.
> - An agent answer must match the input file, and an inbox action must
retain its saved state.
> - This change adds two journeys with independent evidence checks.
> - A blocked fixture action must use the normal human-owned unblock
contract.
> - Registration stays separate from deployed qualification and daily
admission.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Product E2E coverage for file attachments, saved task documents, and
personal inbox read and archive actions.

**Current behavior**

The journey catalog lacks an uploaded-input calculation and a persisted
personal inbox triage path. A successful agent run alone cannot prove
either outcome.

**Proposed behavior**

Upload a generated CSV through the task composer. Require an exact saved
answer and unchanged input bytes. Read and archive one owned task
through the inbox, reload each state, and verify that a new Blocked
event brings it back without agent work.

## What Changed

- Add a file-input journey with a random reference held only in the
uploaded CSV.
- Check exact result values, document authorship, native run binding,
original input bytes, and persistence after reload.
- Add a browser inbox journey with an independently authenticated human
author, saved read and archive state, unchanged work status, and
activity resurfacing checks.
- Reject wrong, missing, duplicate, and foreign evidence in assertion
controls.
- Register both cases and document their scope and privacy rules.
- Supply a current-human unblock owner and action for the archived-task
fixture. Test that exact payload through the production route and retain
the bare-blocked422 negative control.
- Include the fixture constructor in the source definition hash and both
new cases in the exact catalog assertion.
- Reject collected inbox receipts with unexpected runs, providers,
models, or native/legacy execution modes.

## Verification

- The frozen source is `cdb6659fb4e4b67e9321bc3fd963cf11e9b8b2f3`. It
includes one fixed master integration at
`fd0d61b8e329efc89ff541dc2cac44e7c7a37f78`. The single map conflict
retains both coverage paragraphs.
- The production HTTP route rejects the original bare blocked payload
with422 and accepts the exact human-owned fixture payload with200.
Neither control wakes an agent. The full related route file passes
all200 tests.
- The frozen current head passes recursive workspace typecheck, runner
typecheck, full build, map checks, and diff checks. Its full related
journey/catalog suite passes723 tests, the production route suite
passes200, and the separate Node support suite passes347. The retained
contract file passes all38 tests. Fresh Greptile review is 5/5 on the
frozen current head. Current-head hosted CI passes after one authorized
failed-jobs-only recheck. The original Runner close test failed; the
unchanged, properly cargo-prepared focused local control passed in2.99s,
and the hosted recheck then passed. The cause remains unknown; no Runner
code, test timing, or assertion changed. The original hosted diagnostic
and the initial invalid local invocation without required fake binaries
remain recorded. The ordinary local full-test run is in progress.
- The unrestricted local runner support run on the fixed-master
integration is not green:5993 tests passed,12 failed,3 skipped. The
unchanged failures cover onboarding cleanup expectations, Pi metadata,
workflow-security expectations, and an expired test allowance. An
untouched743 baseline reproduces the same non-PG failures; their
source/test blobs also match pre-feature40b807. This change does not
extend an allowance or alter paid admission. The
original5983-pass/15-failure run remains recorded. Restoring the local
Postgres package's own library aliases resolved its two startup
failures. The feature-related catalog omission is corrected.
- The uploaded-file case passed its first complete deployed QA attempt:
one configured native run, all six independent checks, original
evidence, complete cleanup, and no active operations.
- The first inbox attempt stopped at the agent comment execution-context
guard. That guard stays intact. The fixture uses an approved,
independently authenticated QA human.
- The next original inbox attempt verified protected-secret retrieval,
human attribution, and session closure, then failed its unread
prerequisite. The product unread defect was repaired in #18670.
- The fresh deployed inbox attempt passed external-human activity, saved
read state, archive persistence, and unchanged task status after the
product rollout. It then stopped at the fixture's bare blocked PATCH
before any resurfacing assertion. The response status was discarded;422
is an explicit contract inference independently reproduced through the
production route. That failed attempt remains retained. A fresh full
inbox qualification on the current frozen head now passes all six checks
and all five phases; the normal human comment receipt, closed human
session, zero agent work, complete cleanup, and absence of active
operations are verified in the original evidence. Daily admission
remains a separate coordinator action.
- The retained-result review gap failed a negative receipt control
before the repair. All38 retained journey contract tests now pass. The
two old unread advisory threads are resolved only after the fresh full
deployed inbox pass.
- Original failures remain recorded, including the earlier unchanged
environment-runtime assertion and unchanged runner/occupied-port startup
failures. Closed operation codes and failure screenshots retain the
failing step without raw browser errors. Actual retry qualification
remains separate from source tests.

## Risks

The target must supply the declared external-human fixture. Inbox
control selectors may differ across deployed UI revisions. File
processing depends on the configured native agent. Exact saved-state and
source checks must remain required when those dependencies fail. The
change adds test journeys and does not change production behavior or
schemas.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and browser
tools. The runtime does not expose a more specific model identifier 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 (relevant suites; broader
baseline failures are listed 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-11-02 18:12:16 -06:00
DottaandPaperclip 4814d1ab69 fix(ui): show composer images as rounded thumbnails (#18689)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - People use the new-task and thread composers to send text and files.
> - Images currently enter the text editor or appear with other files.
> - Large images interrupt text entry and make the two composers
inconsistent.
> - This pull request puts image previews above the text in both
composers.
> - People can check and remove images while they continue to edit the
text.

## Linked Issues or Issue Description

Refs: #13206. Related shared-composer work: #15091.

**What existing behavior does this improve?**

Image selection, paste, and drop in the new-task and thread composers.

**Current behavior**

Thread images enter the editor at the text cursor. New-task images can
appear inline or with file attachments. Images do not have one preview
size.

**Proposed behavior**

Show images above the text as 80 by 80 previews with rounded corners.
Use the existing spacing and radius tokens. Keep file attachments in
their current row. Add image references when the thread message is sent.

**Reason and benefit**

People can review images without moving or deleting message text. One
shared image row keeps both composers consistent.

**Breaking changes**

New image uploads stay outside the editor until send. Old inline-image
drafts remain readable. No server API or database changes are required.

## What Changed

- Add `ComposerImageAttachments` for local previews, removal, upload
status, and retry.
- Let `TaskChatComposer` own the image row and all image input paths.
Keep attachment IDs in the existing send flow.
- Let `NewIssueDialog` stage images and upload retained files after task
creation. Save file bytes in browser IndexedDB by account and company.
Restore them after reload. Clear them after creation. Show storage
errors. Merge saved file changes in one IndexedDB transaction. Delete
only the files removed by that draft. This keeps files saved by other
open tabs.
- Keep rich editing for old image Markdown. Use the same MIME and
filename checks for image previews in both composers.
- Save optional MIME data with thread draft attachments. Existing draft
records remain valid.
- Add desktop and mobile Storybook examples. Update the task feature map
and component tests.

## Verification

- `pnpm exec playwright test --config tests/e2e/playwright.config.ts
tests/e2e/board-attachment-receipts.spec.ts`: all 14 Chromium tests pass
against the real local Board, API, storage, and disposable database. The
suite proves image recovery in two open tabs after saves and task
creation, new-task image recovery after reload, byte-for-byte upload
content, cleanup after creation, rich editing of old image drafts,
upload receipt recovery, and removal during pending uploads.
- The first local browser attempt could not start because Chromium was
absent. Chromium was installed. A later run passed 12 tests but the new
legacy-draft fixture restored an empty body. That fixture wrote storage
while an empty composer was mounted. It now seeds before React startup
and uses a real uploaded image. The complete 13-test rerun passes. Early
component runs also exposed the new restore timing. Submit and file
controls now wait for restoration. The test helper now waits for React
effects.

- 316 focused tests pass across `TaskChatComposer`, `NewIssueDialog`,
`MarkdownEditor`, `composer-draft`, and `useStagedIssueFiles`. The tests
cover explicit file removal, file recovery, account and company changes,
storage failures, MIME-empty images, upload retries, and removal.
- The two-tab browser test failed on the previous commit: the second
save erased the first image. The fix merges files in one read/write
transaction and records explicit removals. The first fixed run reached
the final create step but had no text request after the other tab
cleared the shared text draft. The test now enters a fresh request
before that step. The full 14-test rerun passes.
- `pnpm check:token-gates`, `node scripts/check-maps.mjs`, `node
scripts/storybook-catalog.mjs`, and `git diff --check` pass.
- `pnpm --filter @paperclipai/ui typecheck` and `pnpm --filter
@paperclipai/ui build` pass after building the local plugin SDK
dependency. Repository typecheck and build stop because this workspace
has no `cargo`. Full CI must pass before merge. The first CI run passed
typecheck, build, and all unit-test shards. Its browser failure expected
the old inline upload label. The assertion now uses the thumbnail upload
status.
- The prior browser review used the production components with simulated
upload and submit calls. Desktop, mobile, and dark-theme captures were
accepted before this PR. Browser checks confirmed equal-size rounded
previews above the editor, no inline image nodes, no horizontal
overflow, and removal that preserves text. These checks do not prove
live backend persistence.
- Earlier repository typecheck and build attempts also stopped without
`cargo`. An earlier full test run was killed with a recorded
out-of-memory event during a server integration shard. It had no
full-suite verdict. One document-recovery test timed out during that
concurrent run. Its isolated rerun and later complete focused runs
passed; the initial timeout cause was not established.
- An initial catalog command in this workspace ran before dependency
installation finished. It could not load Storybook. The command passed
after installation. The first UI typecheck could not find plugin SDK
declarations while that package was still building. The UI typecheck
passed after `pnpm --filter @paperclipai/plugin-sdk build`.

To inspect the layout, open `composer-new-task--images`,
`composer-new-task--mobile-images`, `composer-add-menu--images`, and
`composer-add-menu--mobile-images` in Storybook. Select images with
different aspect ratios. Check removal, mixed files, failed upload and
retry, and draft restoration.

- Greptile reports 5/5 for commit
`9b9e93beeed80371f667ad2e1a9573e82332c05c`. There are no open review
threads.
[CI](https://github.com/paperclipai/paperclip/actions/runs/41544180330)
passed on this commit. All 58 checks finished: 54 passed, one review is
neutral, and three optional checks were skipped. The legacy Snyk status
passed. Paperclip also reports 5/5. No review threads are open.

## Risks

- Open tabs share the account and company draft. Atomic file writes keep
changes from other tabs. A reload can restore those saved files.

- Attachment state now controls when image references enter a thread
message. Tests cover pending uploads, failures, retry, removed images,
and retained upload IDs.
- New-task images use the existing staged-file upload flow after task
creation. A failed upload follows that flow's existing error behavior.
Browser storage can be unavailable or full. The composer keeps the files
in memory and shows a recovery message.
- Legacy inline-image drafts retain their original text. No migration is
required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, tool use, and shell
execution. The exact runtime snapshot ID and context-window size are not
exposed in this session. The earlier implementation's model snapshot is
not recorded in the handoff.

## 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 available in this session)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub references)
- [x] My remote branch name describes the change and contains no
internal Paperclip ticket ID
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 23:35:32 +00:00
sentry[bot] 18abf7c905 fix(db): tolerate unparseable connection URLs during teardown (#18684)
closeRegisteredClients now uses hostPortKeyOrNull and returns early for URLs that new URL() rejects, matching createDb, which never registers clients under such URLs.

Fixes PAPERCLIP-BACKEND-5C
Fixes #18685
2026-11-02 15:33:36 -08:00
Nicky Leach 3a7bb4dac6 perf(runner): activate shared retained startup context (#18405) 2026-11-02 15:12:57 -08:00
DottaandPaperclip 58308a3e63 perf(apps): scope sidebar review counts to one connection (#18688)
## Thinking Path

> - Paperclip helps people manage AI agents and their governed app
access.
> - The Apps sidebar displays a Review badge for one connection.
> - It polls the full company attention service every 30 seconds to get
two counts.
> - That service also loads every profile, rule and active catalog
entry.
> - This pull request adds an authorized connection read for only those
counts.
> - The same badge now avoids unrelated profile evaluation and database
result decoding.

## Linked Issues or Issue Description

**Current behavior**

The contextual sidebar polls company-wide attention. It needs only one
connection's signed pending action count and whether any catalog entries
are quarantined.

**Proposed behavior**

Both sidebar variants poll a connection-scoped count endpoint with
existing connection read authority. The full attention API stays
unchanged.

**Reason and benefit**

The retained 200-profile fixture performs seven service queries and
returns 80,115 rows for this badge. The new reader performs one query
and returns one row. This reduces local service CPU and avoids
unnecessary decoded profile/rule data. Related merged evaluator fixes
are already in the baseline: Refs #18673, Refs #18681. A search found no
existing PR for this scoped count reader. ROADMAP.md contains no
duplicate planned work.

## What Changed

- Add the narrow shared DTO, typed client, guarded REST/OpenAPI route
and catalog-owned reader.
- Count independent aggregates with both company boundaries and exact
signed-argument semantics. Keep archived counts at zero.
- Update both contextual sidebar variants. Keep the exact badge, 30
second interval and existing attention-prefix invalidation.
- Add PostgreSQL differential tests, authenticated HTTP tests, sidebar
tests, a repeatable benchmark and access documentation.

## Verification

- Baseline: `3f8ebfff8aa9febd0733c6f65b07485dcadfd0e2`, including both
merged evaluator fixes. Service treatment: `0827f7d0b3`; route/fixture
refinement: `230c42ee15`; final local existence gate: `390a218254`.
- Passed: focused PostgreSQL differential test; assembled HTTP test with
board session and agent JWT; 14 sidebar component tests; token gates;
map checks; diff check.
- Fixture: 200 profiles, 76,000 rules, 1,900 active tools, 695 removed
references, 12 agents, a sibling connection and 2,000 unrelated
historical invocations. Complete normalized two-count results are equal
on both paths.
- Quiet local measurement: seven alternating warm pairs after two warmup
pairs, Node 24.22.2, macOS, real disposable PostgreSQL. Legacy/new
service CPU median: 213.891/1.680 ms; ranges:
209.329–228.552/0.515–6.137 ms. Wall median: 156.867/1.248 ms; ranges:
151.739–162.289/1.115–1.386 ms. Queries: 7/1. Returned rows: 80,115/1.
- Run `cd server && node --expose-gc --import
./node_modules/tsx/dist/loader.mjs
scripts/benchmark-connection-review-counts.ts`. See
`doc/connection-review-counts.md` for scope and failure history.
Byte-volume accounting runs outside timing; no HTTP payload reduction is
claimed.
- Initial raw scalar SQL failed with ambiguous columns. Typed subqueries
fixed it and passed real PostgreSQL equality. Initial fixture agents
lacked permissions and correctly received 403. The final fixture grants
explicit authority and tests revocation. An initial benchmark included
byte serialization in timing; the reported run excludes it.
- Passed required local `pnpm -r typecheck` and `pnpm build`. The
initial sandbox typecheck could not open the tsx IPC socket; the
escalated rerun passed. Full monolithic `pnpm test:run` was not run
locally: repeating a 15–25 minute suite serially across both performance
PRs adds no distinct evidence. Broad suite acceptance uses final-head
CI, which runs the same general/serialized test partitions and the
native Runner lane. Final-head CI is in progress.
- Passed built-static Chromium journey on an owned local-trusted server
and disposable PostgreSQL: Review 3 appears, only scoped counts are
requested by this sidebar, resolving requests/clearing quarantines then
reloading removes the badge, and archived counts are zero. The first ad
hoc launcher omitted required decision-service options and failed at
startup; using the normal no-op wake callback fixed that harness.
- Greptile identified an invalid resolved-request fixture label.
Corrected `denied` to the declared `rejected`, then reran the real
PostgreSQL differential test. The count SQL and non-pending exclusion
are unchanged.
- The first final-head CI failed the static cross-tenant
existence-oracle guard because the new explicit resource company
assertion had no nearby `hasCompanyAccess` gate. Existing management
admission already rejects foreign resources with 404. The route now also
follows the standard local two-step gate. The unchanged guard plus
authenticated HTTP negative cases passed (3 tests). No allowlist or test
was weakened.
- These local service measurements do not prove hosted performance. No
deployment is included.

## Risks

Low risk. New read admission reuses existing current-authority checks.
The old attention API is unchanged. Counts still require database work
over relevant pending/catalog rows. No cache, schema migration or
telemetry is added. Roll back this PR if the badge differs or scoped
reads deny previously permitted users.

## Model Used

OpenAI `gpt-6.1-sol` (Sol 6.1), with reasoning, tool use and code
execution. The host does not expose the configured 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>
2026-11-02 17:12:22 -06:00
commitperclip[bot] fd0d61b8e3 fix: Compare native finaliser lease expiry at millisecond precision when releasing an expired owner (#17214)
> [!NOTE]
> Opened by Prospector's automated issue-fix pipeline. A maintainer
reviews and decides; nothing here merges on its own.

## Thinking Path

- Issue #16715 reports a defect in paperclipai/paperclip.
- Root cause, as the fixing agent read it: Lease renewal writes
'lease_expires_at' from the database clock ('now() + interval'), so the
stored value has microseconds. 'agentExecutionsHaveStopped' reads that
value into a millisecond JS 'Date' and then releases the row with an
exact 'eq' on it. The update never matches, so the stop check returns
false on every tick and the agent stays in 'pausing'.
- This pull request: Compare native finaliser lease expiry at
millisecond precision when releasing an expired owner

## What Changed

- `server/src/services/agent-execution-stop.ts`: The release update now
truncates the stored lease expiry to milliseconds before comparing it
with the value it read, using the same 'date_trunc('milliseconds', ...)
= ...::timestamptz' pattern as 'chat-channels/activity.ts'. The other
guards stay the same: owner, generation, phase and the null result. This
was the only exact-match comparison on a lease expiry in 'server/src'.

## Verification

- Reproducing test(s), added in this PR:
`server/src/modules/agent-lifecycle/__tests__/lifecycle.test.ts`
- They fail on the base commit and pass with the fix, each twice in a
fresh sandbox.
- 3 independent attempts wrote 3 reproductions; this fix passes every
one of them.
- The repository's compile command passes with the fix applied.
- The full test suite passes except for the 10 file(s) that already fail
on the base commit.

## Risks

- Written by an automated pipeline, not a person: review it as you would
an outside contribution.
- Risk tier of the touched paths: 2.
- The scope reviewer found it also changes, beyond the report:
agentExecutionsHaveStopped for an expired finaliser row whose
lease_expires_at is already millisecond-precise (written from a JS Date)
- The scope reviewer found it also changes, beyond the report: Finaliser
row whose lease was renewed or taken over between the select and the
update
- The scope reviewer found it also changes, beyond the report: Rows with
null leaseExpiresAt

## Model Used

- codex:gpt-6.1-sol, opus, sonnet (Anthropic Claude, via Claude Code;
OpenAI, via the Codex CLI), writing and checking the change in an
isolated sandbox.
- opus (Anthropic Claude, via Claude Code), reviewing it independently.

## Linked Issues

Fixes #16715

Other pull requests that name #16715:
- #17204 (open): fix(heartbeat): stop loading full run rows and stale
pids when pausing an agent
- #16745 (open): fix(agent-lifecycle): release an expired native
finalizer lease at millisecond precision

## Checklist

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

<!-- prospector:issue-fix v1 issue=16715 base=c7ea5c0216b8
report=1a4e13ecd7c6cdb6 -->

Co-authored-by: commitperclip[bot] <284812584+commitperclip[bot]@users.noreply.github.com>
2026-11-02 15:01:52 -08:00
DottaandPaperclip 554a770c6f perf(apps): scope connection profile configuration reads (#18687)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Apps Permissions page reads saved access profiles for one
connection.
> - The page fetched every company profile, rule, and binding.
> - It used only the app profile and eligible task-granted profiles for
that connection.
> - This pull request adds a saved configuration read owned by the
profile service.
> - The route keeps current connection and per-profile management
checks.
> - The benefit is fewer database rows, less Node work, and a smaller
response for the same displayed configuration.

## Linked Issues or Issue Description

**Subsystem affected**

Server profile configuration reads and the Apps Permissions and Review
data caller.

**Problem or motivation**

One connection page loaded and serialized unrelated company profiles. In
the local fixture, this produced a 32.35 MB response with 76,001 rule
rows.

**Proposed solution**

Select the displayed connection's app profile and exact eligible
connection-intent profiles before loading their entries and bindings.
Return an explicit configuration DTO with complete selected arrays. Keep
summary and pending-review work on the existing full API.

**Alternatives considered**

Filtering the full response in the browser retains the database and Node
cost. Truncating the full API would break other clients. Filtering
entries to the connection would lose selectors and bindings needed by
saves.

**Roadmap alignment**

This improves the existing governed Apps capability. It does not add a
new access policy. Related merged work: #18673 and #18681. Related
harness cleanup: #18683. Public PR searches found no duplicate
connection configuration projection.

## What Changed

- Add `ToolProfileConfiguration` and `GET
/api/tool-connections/{connectionId}/profile-configuration`.
- Select `app:<connectionId>` at any status and exact active, correctly
bound `connection_intent` profiles. Run the existing per-profile
visibility filter before configuration queries.
- Preserve complete ordered entries and bindings. Keep all save
behavior, empty-binding install fallback, and the existing full profile
API.
- Switch AppDetail and AgentConnectionAccess to the configuration DTO.
Use a distinct cache key below the existing profiles prefix so mutation
and reconnect invalidations still refresh it.
- Add real PostgreSQL differential and authenticated HTTP tests, UI
caller coverage, a reproducible benchmark, and access-map documentation.

## Verification

Baseline: `3f8ebfff8aa9febd0733c6f65b07485dcadfd0e2`, after both #18673
and #18681. Final head: `b40c1ed7c0833d403e20ee8a5ff9d09f1bad6d22`.
Current implementation and reproduction details are in [the performance
note](https://github.com/paperclipai/paperclip/blob/b40c1ed7c0833d403e20ee8a5ff9d09f1bad6d22/doc/performance/2026-11-02-connection-profile-configuration.md).

- AppDetail: 79 tests passed. Existing access/action saves, install
fallback, grant removal, errors, and refresh cases use the new caller.
- Real PostgreSQL differential: passed. Full ordered selected
configuration equals the old full-list selection. Cases cover extra
bindings, sibling selectors, wrong source/key/status/binding, null and
non-string agent metadata, fresh mutations, empty app bindings,
visibility filtering, and company scope.
- Production HTTP authentication: API key and run JWT cases passed.
Hidden personal accounts omit spanning profiles. Private connection
reads fail. Restored ownership restores visibility. Revoked management
grants deny fresh calls. Final UID canonicalization and foreign-company
404 assertions passed on the current head.
- Map structural check, token gate, and `git diff --check`: passed.
- Required local `pnpm -r typecheck` and `pnpm build`: passed on the
current head. `pnpm test:run` was started once. Its first chat shard
passed (337 tests, 151.87 seconds); the second shard was intentionally
interrupted after the complete final-head CI suite passed. This partial
local attempt is not a full local test pass. The same stable-runner
general and serialized partitions and Runner lanes passed in [final-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41538805231),
including aggregate `ci / verify`. No local assertion failures were
observed before interruption.
- Final-head focused acceptance: four files, 85 tests passed. Full token
gates, maps, and module boundaries passed.
- Actual browser acceptance passed on the current checkout with isolated
real PostgreSQL and a local trusted board. An action saved as Off
persisted after reload. Both app agent bindings stayed intact. Removing
an agent-only task grant persisted after reload. Requests used only the
narrow profile endpoint. No browser exceptions occurred. No responses
were mocked. No provider calls or hosted changes were made. The helper
stopped the owned runtime and database after the check.
- Final exact-head checks: 54 success, one clean neutral Paperclip
Review, three skipped, zero pending or failures. Legacy Snyk status:
success. No inline review comments.
- Greptile reviewed exact head
`b40c1ed7c0833d403e20ee8a5ff9d09f1bad6d22`: 5/5, no findings, completed
successful check.

Five alternating unprofiled pairs ran with real PostgreSQL on
macOS/arm64, Node v24.22.2, and forced GC. The fixture has 210 profiles
(200 heavy profiles plus ten eligibility cases), 76,001 rules, 1,900
active tools, 695 removed tools, and 12 agents. The selected
configuration has two profiles and 1,391 rules. Each pair asserts
complete ordered selected DTO equality.

| Measurement | Full list | Configuration read |
| --- | --- | --- |
| Service wall ms, median [min, max] | 200.927 [193.319, 213.390] |
6.414 [5.508, 6.973] |
| Node CPU ms, median [min, max] | 262.751 [246.727, 271.573] | 27.525
[22.576, 29.308] |
| Select queries / returned rows | 7 / 78,139 | 3 / 1,397 |
| Actual response JSON bytes | 32,353,534 | 592,233 |
| Serialization wall ms, median [min, max] | 90.714 [88.715, 99.304] |
1.644 [1.637, 1.745] |
| Serialization CPU ms, median [min, max] | 90.644 [88.569, 96.778] |
1.654 [1.637, 1.807] |

Reproduce: `node --expose-gc --import
./server/node_modules/tsx/dist/loader.mjs
server/scripts/benchmark-connection-profile-configuration.ts 5`.

The benchmark measures the service and actual response JSON separately.
It excludes HTTP and authorization work through an identity visibility
callback. Node CPU does not include PostgreSQL CPU. No hosted or
foreground-under-load improvement is claimed.

Preserved failures: offline install lacked a locked tarball; frozen
online install passed. Sandbox localhost and tsx IPC restrictions
blocked initial DB/typecheck attempts; permitted retries use the same
checks. The first HTTP suite needed the unbuilt plugin SDK; its owning
build helper fixed setup. Shared typecheck caught a missing barrel
export, now fixed. A broad typecheck inherited the host's unpinned
nested pnpm executable; the owned stalled process was stopped and
restarted with pinned pnpm 9. The complete current-head CI suite and
aggregate verify passed. The separate Paperclip agent review published
5/5 with no findings at this head and completed with a clean neutral
conclusion. An added foreign-company assertion expected 403; the
existing guard correctly returned 404. Only the test expectation
changed. The first real browser attempt saved and reloaded the action
correctly, but grant deletion returned 422: the stress fixture had a
company binding, which makes that profile the company default. The UI
showed the existing deletion error. The second browser seed used the
production agent-only intent shape and passed removal and reload. This
does not change the stress fixture or product deletion gates. Initial
external browser script attempts also needed an ESM extension and the
correct dependency path. Logs, first-failure screenshots, traces, and
result files are retained in the local evidence directory.

## Risks

- SQL selection must stay aligned with connection-intent eligibility.
Differential fixtures cover the exact current predicate.
- A selected connection can still have many rules. This change preserves
all selected configuration.
- Per-profile authorization still reads current selected resources and
can add work. Connection visibility does not bypass that check.
- No migration, default-allow, effective-access, policy-review,
provider, or deployment behavior changes. The old endpoint remains
available. Rollback restores the old AppDetail caller and removes the
additive endpoint.

## Model Used

OpenAI Codex, `gpt-6.1-sol`, with code execution and repository tools.
The host does not expose the context-window size.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 16:55:56 -06:00
DottaandPaperclip 00fea0da52 refactor(perf): reuse database test setup for profile benchmark (#18683)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tool profiles govern the tools that agents can use.
> - Profile listing and app attention shared nested selector scans that
consumed the server CPU.
> - #18681 and #18673 replaced those scans with indexes for each
computation.
> - Their performance benchmarks need consistent setup and reproducible
per-service measurements.
> - This pull request uses the shared helper entry point and retains the
exact measurement harness and results.
> - Reviewers can inspect both the CPU savings and the limits of the
evidence.

## Linked Issues or Issue Description

Refs #18681 and #18673.

**What existing behavior does this improve?**

The consistency of benchmark setup and the reproducibility of evidence
for the two merged CPU fixes.

**Current behavior**

The profile-review benchmark imports the database starter directly. The
matching benchmark uses the shared server test-helper entry point. On
the current base, that helper re-exports the database starter, which
already supports `PAPERCLIP_TEST_POSTGRES_ADMIN_URL`. The previous
committed benchmark measures both services together; the per-service
measurements and separate HTTP/Inspector runs lacked a committed
harness.

**Proposed behavior**

Use the same test-helper entry point in both benchmarks. Retain the
compile, per-service timing, Inspector, and HTTP-probe programs with
their exact commands and raw samples. Preserve the existing embedded and
admin-server database behavior.

**Reason and benefit**

A shared entry point keeps benchmark setup consistent. The committed
harness lets reviewers reproduce and compare each real owning service
before and after the merged fixes. The failure-path checks verify that
result-write errors still release the database and probe resources.

**Breaking changes**

None. This change affects benchmark setup and documentation.

## What Changed

- Import the database starter from the repository test helper in
`benchmark-profile-review-projection.ts`.
- Record separate CPU and elapsed measurements for profile listing and
app attention.
- Retain the actual compile, per-service measurement, Inspector capture,
and separate-process HTTP probe harness.
- Always tear down the test database, HTTP server, and probe even when
result writing fails.
- Retain all timing and responsiveness samples as sanitized JSON.
- State the runtime, fixture, source revisions, and limits of the local
comparison.

## Verification

- 24 focused tests passed across selector matching, pending projection,
review-service freshness, and effective assignments.
- Four selected real database-backed service/route tests passed for
summaries, review changes, auto-allow behavior, and company isolation.
The other 494 tests in that file were not selected.
- Injected an `EISDIR` result-write failure into both profiling programs
on an owned local admin server. Each child exited with the expected
error and removed its disposable database. The responsiveness child also
terminated its probe/server handles.
- The changed benchmark completed with a configured local PostgreSQL
admin URL. Its full responses matched the baseline, and query/row counts
matched.
- The exact documented compile, benchmark, and responsiveness commands
completed from the committed harness at
`ca458baddc6461fb6c888984246e329e2bb4bdfe`. The JSON records that build
revision and the four owner source hashes.
- Five alternating samples per service and implementation used Node
24.22.2 with compiled ES modules. No runtime TypeScript loader ran in
those measurements.
- Median process CPU from the committed harness: profile listing 3,164
ms to 385 ms; app attention 2,466 ms to 221 ms. Both versions returned
identical ordered results and made seven queries per service.
- Separate Inspector profiles confirmed that the repeated scope and
summary scans were removed. Three separate-process HTTP probe trials per
service showed less event-loop blocking. These are local synthetic
service results, not hosted page-load acceptance.
- Initial local setup failed on missing embedded PostgreSQL library
aliases and an unbuilt plugin SDK. Restoring local aliases and building
the SDK resolved those setup failures. The original failed setup logs
were retained; the 28 selected tests then passed.
- The merged summary fix CI run
[41535304968](https://github.com/paperclipai/paperclip/actions/runs/41535304968)
hit two 15-second timeouts in the unchanged attention-retention history
cases. The server shard passed unchanged on one failed-jobs-only retry.
Original and retry logs are retained. The compared runs used different
runners and synthetic merge trees, so the original timeout cause is not
established. No timeout or assertion was changed.
- Full repository typecheck, test matrix, and build passed in CI on
final head `2f484ed4284f3fa632d8e73d9be084827d1c987e`: 54 successful
check runs, three expected skips, one non-blocking Paperclip review, and
a successful Snyk status. No failures or pending checks remain. Those
broad commands were not rerun locally for this benchmark-tooling
follow-up; the 28 selected local regressions and the actual
profiling/failure-path programs ran locally.
- Fresh Greptile is 5/5 on that exact head. Both review P2 threads are
resolved. The Paperclip review's current-base documentation note is
corrected in this description; its optional tooling suggestions remain
outside this bounded change.

## Risks

- The test helper creates a unique disposable database on the configured
admin server and removes it afterward. The operator must use a database
server where those test operations are appropriate.
- Synthetic data and shared-host activity affect absolute timings. The
measurements do not establish a production latency percentage or
capacity limit.
- Production behavior is covered by the two linked merged fixes. This
follow-up changes only benchmark setup and documentation.

## Model Used

OpenAI GPT-6 through Codex, with code execution and repository tools.
The exact runtime model revision and context window were not exposed in
this session. The original linked performance fixes record their own
model details.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 16:50:58 -06:00
DottaandPaperclip 3f8ebfff8a fix(evals): pass named environment secrets to case workflows (#18680)
## Thinking Path

> - Paperclip lets people manage AI agents and inspect their work.
> - The chat catalog sends each original Product E2E result to TestOps.
> - Each case uses a reusable workflow with separate protected job
environments.
> - The caller passed literal empty strings for three secret names.
> - A live worker received an empty model key although its environment
had that secret.
> - GitHub requires matching named secret references at the caller
boundary.
> - This PR uses those references and keeps the closed credential
boundaries.

## Linked Issues or Issue Description

Refs #18647, #18666, #18676.

**What happened?**

The first two workers in a live streaming check failed before a
qualified native case. Their model-key environment values were empty.
Name-only metadata confirmed that the key exists in the intended
protected environment. Both closed diagnostics recorded zero runs, zero
checks and no original result carrier. The remaining case was cancelled
before its original execution. These records are setup failures, not
feature or model grades.

**Expected behavior**

Each caller passes only the three declared secret names through matching
expressions. Each called job uses its own protected environment and only
its existing credential consumers. GitHub documents this requirement
even when the secret exists only in that environment: [Reuse
workflows](https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows).

**Steps to reproduce**

Run the new `paidWorker` consumer control against the parent helper. It
rejects the supported named-reference caller. The deployed literal-empty
caller also has the retained live empty-key witness.

## What Changed

- Replace six literal empty values in the two case callers with exact
matching secret references.
- Keep the host-contract resolver closed to those three names and
expressions.
- Reject blank, extra, mismatched and inherited credentials in focused
consumer and workflow controls. Keep the existing lane and authorization
controls.
- Keep the called workflow, protected environments and
credential-consuming steps unchanged. No secret was read, copied,
rotated or added during this repair.

## Verification

- Parent consumer control: RED with `Workflow caller boundary mismatch`
for the named-reference contract.
- `node --test
tests/runner-e2e/chat-completion-testops-contract.test.mjs
tests/runner-e2e/chat-catalog-testops-streaming.test.mjs`: 36 controls
pass.
- Review found an existing streaming-test mutation that became a no-op
after the caller contract changed. Its actual `Missing expected
exception` failure is retained. The mutation now uses a blank value, and
its description names the current contract. All production posts are
unchanged by this test correction.
- The focused `Runner eval workflows pin actions and gate paid live
execution` security control passes.
- Four JavaScript syntax checks, actionlint for caller and callee, and
`git diff --check` pass.
- An independent source peer checked the four original frozen posts and
unchanged callee. The two-line dependent-test correction has a separate
peer review.
- Local checks use synthetic values, source files and mocked boundaries.
No local app, database, native build or provider ran.
- Corrected-head GitHub CI passes with 48 successful jobs and one
skipped. Both required aggregates, typecheck, build and browser checks
pass. This head needed no CI recovery.
- Live nonempty resolution and incremental TestOps publication still
need qualification after delivery.

## Risks

- The previous assumption that literal empty placeholders would resolve
environment secrets was wrong in the observed run. This change follows
the current primary contract. Local controls do not prove GitHub runtime
resolution.
- The three names stay explicit. There is no `secrets: inherit`, new
secret, environment change or permission expansion. The model worker,
private reader and TestOps uploader keep their existing separate
consumers.
- The immutable evaluation source, cases, original grades, run limits,
deadlines and zero-retry policy do not change. Earlier setup failures
remain recorded. The existing large batch is not changed or replayed.
- Streaming publication and final backend coverage remain unqualified
until a real small run proves them.

## Model Used

OpenAI `gpt-6.1-sol`, with tool use and code execution. The session does
not expose a context-window size. The independent source peer uses the
same model family.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1102.0-canary.7
2026-11-02 16:25:55 -06:00
DottaandPaperclip d0ffa179b4 perf(tools): index profile selectors per resolution (#18673)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - Core resolves tool profiles before it prepares runtime MCP
assignments.
> - A selected profile can contain a rule for each individual tool.
> - The resolver and profile summary scan these rules for each catalog
row.
> - This repeats millions of exact comparisons for a large selected
profile.
> - This pull request indexes each selector kind once per computation.
> - The benefit is less server CPU with the same current access
decisions and result contract.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Effective tool assignment and profile summary computation for large
selected profiles.

**Current behavior**

Each catalog row scans the profile's includes and excludes. The work
grows with catalog size times rule count. The runtime assignment path
also computes a profile summary with the same scans.

**Proposed behavior**

Build five selector sets for each include or exclude group. Match
catalog rows with exact set membership. Retain all current database
reads and the full result contract.

**Reason and benefit**

Reduce repeated JavaScript comparisons. On the synthetic PostgreSQL
fixture below, median process CPU per resolution falls from 50.068 ms to
10.129 ms. This is independent of
[#18371](https://github.com/paperclipai/paperclip/pull/18371), which
removes unused administrative results and narrows instruction
descriptors. This PR retains those results and does not include that
change.

## What Changed

- Index application, connection, catalog-entry, tool-name, and risk
selectors in the profile owner.
- Use indexed matching in effective access resolution and profile
summaries.
- Add a differential test against the original single-rule matcher.
Cover null applications, exact special-character names, unknown
selectors, and empty rule groups.
- Add a PostgreSQL regression for per-profile exclusion precedence, the
union of multiple effective profiles, and current rule removal.
- Add a real PostgreSQL resolver benchmark and document reproduction and
limits.

## Verification

Baseline: `410b0e27015495ab8951768b5b0b94727de33785`. Treatment:
`895ee2eec15cf4cdedee4c257fcdddb2a7000a1b`. Node 24.22.2 on macOS arm64.
Source modules run with `tsx`; these are local service measurements, not
production-build or hosted acceptance.

The real owning resolver ran against disposable PostgreSQL with 1,890
active catalog tools, 1,575 individual include/exclude rules, one
deny-by-default effective profile, and 12 agents. The installation
dependency returns an empty list because the fixture has no installed
connections. There are no provider calls. Full returned assignments,
profile summaries, rules, bindings, and names are identical to baseline.

After two warmups per version, seven alternating samples ran ten
resolutions each. Other workers paused CPU measurements and builds.
Unrelated host work was not controlled.

| Per resolution | Baseline median (range) | Change median (range) |
| --- | --- | --- |
| Process CPU | 50.068 ms (46.380–58.880) | 10.129 ms (8.089–11.072) |
| Elapsed time | 50.362 ms (44.799–106.408) | 8.853 ms (7.719–18.590) |
| Queries | 6 | 6 |
| Returned database rows | 3,480 | 3,480 |

Median process CPU falls 79.8%; median elapsed time falls 82.4%. The
long baseline elapsed sample had no matching process CPU increase. Query
and row counts do not decrease. Small or broadly allowed profiles can
save less. This does not establish whole-run latency or hosted
performance.

Reproduce with `server/scripts/benchmark-tool-profile-matching.ts`;
baseline module preparation is in `doc/mcp-discovery-performance.md`.

Passed on the treatment source:

```sh
node node_modules/vitest/vitest.mjs run server/src/__tests__/tool-profile-matching.test.ts server/src/__tests__/tool-effective-assignments.test.ts server/src/services/native-runtime/runtime-context.test.ts server/src/__tests__/heartbeat-runtime-mcp-servers.test.ts
```

All 45 tests in four suites passed. `git diff --check` passed. The first
PostgreSQL test attempt failed at setup because the sandbox blocked its
loopback listener (`EPERM`); the authorized unsandboxed retry passed. No
behavior failure was discarded.

At measured head `895ee2eec15cf4cdedee4c257fcdddb2a7000a1b`, CI
typecheck, build, canary, Runner checks, and all eight browser shards
passed. Server general shard 8/12 failed an unchanged
background-quietness assertion in `heartbeat-run-dispatch-work.test.ts`:
expected 235 select calls, observed 236 after advancing fake timers. Its
cause remains unverified; no baseline reproduction was run.

That head also failed the module-boundary policy because the benchmark
inserted synthetic agents outside the test fixture tree. Follow-up head
`e20165b6eb` moves the fixture body byte-for-byte into
`server/src/__tests__/helpers/tool-profile-matching-fixture.ts`,
following the existing listing benchmark pattern. The production matcher
and benchmark measurement loop are unchanged. `node
scripts/check-module-boundaries.mjs`, a Node 24/tsx fixture import
check, and `git diff --check` pass. The benchmark was not rerun for this
extraction. New-head CI and review are pending. Greptile gave the
measured head 5/5 with no actionable issues. No deployment or live
runtime mutation was performed.

## Risks

Exact equality must remain identical to the original matcher, especially
for null application selectors and exclusions. The differential and
PostgreSQL tests cover these cases. Sets add linear temporary memory in
rule count. They live only for the current computation. Current
company-scoped state reads, profile precedence, revocation, and runtime
assignment digest checks remain in place. Revert this commit to roll
back.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) with source inspection, code
execution, tests, and local PostgreSQL benchmarking. The context window
size is not available 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-11-02 16:13:18 -06:00
Nicky LeachandPaperclip a9b18e1cbe fix(runner): preserve cleanup ownership across startup failures (#18658)
## Thinking Path

> - Paperclip controls which run owns an agent task.
> - A plugin can continue accepted work after Core stops waiting.
> - A late task-creation reply can therefore arrive after startup
cancellation.
> - Core must keep that work owned until its resource identity and
cleanup outcome are known.
> - This PR supplies the cleanup and recovery support before shared
startup is enabled.
> - The dependent activation PR can then reuse transport data within a
bounded startup context.

## Linked Issues or Issue Description

Refs #18405. This is the independently mergeable prerequisite for that
stacked activation PR.

**What existing behavior does this improve?**

Cleanup of explicitly recorded startup work that outlives its caller.

**Current behavior**

Caller timeout, worker exit, or failed cleanup-intent persistence can
leave work without a complete recovery path.

**Proposed behavior**

Retain the cleanup obligation, use existing Stop and recovery queues,
and release ownership only after the exact task and accepted work have
stopped. Ordinary calls keep their existing startup payloads and
budgets. This PR does not create startup contexts or advertise transport
reuse.

**Reason and benefit**

Separate the failure-handling contract from activation so each can be
reviewed on its own. This support PR has **no standalone TTFT speedup**.

## What Changed

- Add the startup cleanup marker, exact ownership checks, verified
completion, and acknowledgement helpers.
- Connect recorded cleanup obligations to existing Stop, deadline
reconciliation, restart recovery, and retry scheduling.
- Retain typed cleanup responsibility when a database write fails. Keep
the nonterminal run from being treated as ordinary completed cleanup.
- Observe late acquisition results and save resource identities before
retiring them. Retain real host writes and received results across
worker exit or persistence failure.
- Queue abandoned replacement tasks through the existing creation
journal and cleanup machinery. Require the replacement's own Stop proof.
- Accept an explicit startup context in the internal bridge for lifetime
tracking. Automatic context creation, marker production, capability
advertisement, transport capture, and executor activation belong to
#18405.
- Add PostgreSQL and worker IPC regressions, including legacy payload
assertions.

## Verification

Initial split source `8fb482d8be9e70101b0cfdd0830f41cf5b8e3cf4` had tree
`95508bd1859e991670cad8afd4de8d2167009ac5`. **190 distinct targeted
tests pass**, along with server typechecking. The selected checks cover
real PostgreSQL cleanup/ownership, worker IPC, the bridge and creation
journal, ordinary/distributed Stop, restart and deadline recovery,
idle-sleep behavior, and the unchanged legacy warm-task suite.
Independent recovery and worker reviews found no blocking issue.

The first correction, `b6342d42042601b376da38dc8e1dba9ca80e9539`, fixes
the replacement cleanup finding with the existing startup-cleanup
marker, scoped to contextual abandoned task creations. The replacement
was never prepared, so preparation-stop proof is not required. No
dispatch is fabricated and no normal-startup query is added. The actual
queue/sweep/driver/receipt/cancellation regression fails before the fix
and passes after it: void, running or foreign-task status retains
ownership; exact-task stopped status permits completion even when
Release returns void. **64 affected targeted cases and server
typechecking pass**. Independent review found no blocker.

Current source is `f53af72af76f263096c3c2e788506e6faef9474f`. It fixes
both recovery findings from the prior head's Apex 3/5: orphan recovery
now preserves pending or completed-but-not-cancelled cleanup through its
existing final-write fence, and exact late identities can reach verified
cleanup after reconciliation or restart. The regression selection went
from four failing assertions to six passing cases. Affected selections
cover 217 distinct cases; the exact final six-case regression and server
typecheck pass. Independent reviewers found no blocker in either fix.
Current-head standard review is 5/5 and all CI checks pass (54
successes, three expected skips, plus Snyk). Apex also completed at
**5/5** on this exact head, with zero unresolved threads. The requested
independent availability audit is complete on this head. It found an
activation-dependent operability gap: an acquisition response that is
never received can leave an unknown creation identity with no supported
task inspection/reconciliation path, while cleanup keeps the run owner
reserved. This does not occur in ordinary lower-only calls. The contract
and recovery policy need follow-up before activation; the external
review scores do not resolve that availability tradeoff.

The split preserves the accepted implementation at `21db7b3851` after
its clean merge with frozen master
`946735d03a55c1fb4cc5434d6bf1d87742daa9df`. The initial dependent
activation PR restored exact aggregate tree
`f68c6895f87c7b93ae03e6324d955d2659a99dce`. Both subsequent cleanup
corrections are integrated into upper head
`27978f294a02da3992585c7f4daa73cd8fcf99f8`; its current aggregate tree
is `a0b66c33f5e22745f034f45d24d213f5c210cf16`. Lower-only payload tests
cover the absence of capability advertisement and transport projection.

Only targeted local tests and typechecking are used. Full regression
coverage runs in GitHub CI. No deployment or ROM qualification is part
of this change.

The lower audit covered connected worker, creation-journal, Stop,
restart, deadline and orphan-recovery paths. A new isolated
real-PostgreSQL characterization reproduced the unknown-ID hold through
actual recovery, cleanup verification and run-control cancellation. It
models a lost acquisition response; it is not a live provider or
complete IPC test. No source edits were made by the audit. The
upper/composition audit remains required after its review cycle.

## Risks

- Recording a replacement result now commits with the existing cleanup
notification. This conditional replacement path adds
transaction/notification responses; common retained startup is
unchanged.
- This adds cleanup and recovery state handling. A missing receipt or
permanently inaccessible old backend can keep ownership held
indefinitely. Temporary outages retry; an ordinary retry is not evidence
that a deleted or replaced backend stopped.
- A caller timeout does not undo work already accepted by a plugin.
Unknown resource creation remains unresolved until its identity/outcome
is established. Current task creation has no supported
inspect-by-operation or operator reconciliation API for a permanently
lost identity; repeated Stop alone cannot resolve it.
- The support code understands records produced by the dependent
activation PR. It does not enable the shared startup policy by itself.
- Existing legacy callers must retain their behavior; context-only
automatic replacement cleanup remains explicitly scoped.

## Model Used

OpenAI Codex, GPT-6 family. The exact model ID and context window are
not exposed in this session. Tool-assisted implementation, targeted
testing, and independent subagent review.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used, with available version and
capability details
- [x] I have checked ROADMAP.md and confirmed this is the requested
split of existing work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have described the issue with the required fields
- [x] I have not referenced internal issues or private links
- [x] My branch name describes the change and contains no internal
ticket ID
- [x] Targeted local tests pass on this source
- [x] I have added or updated relevant tests
- [x] I have updated relevant documentation
- [x] I have documented the risks
- [x] All current-head GitHub CI gates are green
- [x] Current-head standard Greptile and Apex are 5/5 with no unresolved
findings
- [x] I will address all review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 14:13:00 -08:00
DottaandPaperclip b4315943e8 fix(heartbeat): keep remote retry workspace strategy stable (#18660)
## Thinking Path

> - Paperclip preserves agent work across separate execution services.
> - A remote retry can create a new isolated Git workspace.
> - Later admissions compare its saved configuration with the current
policy.
> - Fresh preparation also creates a temporary controller-side strategy.
> - Remote preparation saved that temporary strategy in its fingerprint.
> - The next unchanged turn then reported a workspace strategy
replacement.
> - This change saves the admitted remote strategy so unchanged reuse
stays stable.

## Linked Issues or Issue Description

Related preparation work: #18543 and #17924. I searched open and merged
workspace/session repairs and public workspace-strategy issues. None
covers this fresh remote retry case.

**What happened?**

After Retry created an isolated remote Git workspace, each unchanged
follow-up reported `workspace_config_freshness` with `action: replace`
and `changedCategories: [strategy]`. It retained the same workspace. The
stored fingerprint contained `project_primary`, which was only a
temporary controller provisioning choice.

**Expected behavior**

Save the configured remote strategy. An unchanged follow-up must reuse
the same workspace without a false replacement report. A real strategy,
base-ref, mode or environment change must retain its replacement checks.

**Steps to reproduce**

1. Prepare a fresh isolated remote Git retry with a `git_worktree`
strategy.
2. Complete its runtime handoff.
3. Admit another turn with the same workspace policy.
4. Inspect the recorded workspace freshness decision.

**Paperclip version or commit**

Reproduced on `b9e94b85a69bf679818eeef9ecf4655554a89c6b`. The regression
also fails on the unchanged preparation code in the current base.

**Deployment mode**

Authenticated server with remote workspace authority and a sandbox
execution target.

## What Changed

- Keep the admitted strategy when a fresh workspace uses remote
authority.
- Retain the temporary controller strategy for existing host-side seed
preparation.
- Extend the PostgreSQL preparation test through a fresh admission and
its next ordinary admission. Assert the same workspace, current writer
and stable fingerprint, with no false drift operation.
- Cover a genuinely configured `project_primary` fresh remote Git retry
followed by a real strategy change, preserving its replacement decision
and stored fingerprint.
- Document the execution rule and the separate live verification recipe.

## Verification

- The final regression was run before and after the production change.
Before: the next admission recorded a strategy replacement. After:
unchanged reuse records no drift and retains the workspace and
fingerprint.
- All 312 targeted cases pass on
`48b3e548afa42e740871feae2763d88fd5a00431` across workspace preparation,
workspace/session policy and inherited session preparation. These
include actual strategy/base-ref changes and the rule that explicit
reuse must not hide real replacement-class drift.
- All eight remote preparation cases also pass with the compatibility
regression: a genuinely configured `project_primary` fresh Git retry
creates a `git_worktree` row, and its later real strategy change retains
the replacement decision and saved fingerprint.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Full recursive typecheck and `pnpm build` pass locally on this head.
- The [full current-head CI
matrix](https://github.com/paperclipai/paperclip/actions/runs/41524105868)
passes: typecheck/build, all general server, chat, workspace and
serialized test groups, plus Runner and E2E checks. The workflow and
`run-vitest-stable.mjs` partition the complete suite.
- The duplicate local `pnpm test:run` passed all 1,828 chat cases and
was intentionally stopped during general-server after the same complete
CI matrix passed. This is not recorded as a full local-suite pass.
- Greptile and Paperclip Review both assessed this head at 5/5 with no
new findings. Paperclip Review accepted the compatibility boundary after
the counterexample; its check conclusion is neutral. The addressed
review thread is resolved.
- The regression uses real PostgreSQL and preparation policy. Runtime
acquisition is controlled at its external boundary. The new fix has not
been deployed; live provider resumption remains unverified for this
patch.

## Risks

- Existing incorrect fingerprints are not rewritten. The same stored
shape can come from a genuinely configured `project_primary` remote Git
retry; a Git workspace row alone cannot prove the old admission policy.
Rewriting it would hide a real policy change. After preserving and
inspecting retained work, an explicitly admitted fresh recovery after
rollout establishes a correct new fingerprint. Ordinary reuse of the old
workspace does not migrate it. Normal recovery gates remain required.
- Real policy changes still use the current replacement guard. No
schema, credential or authority change is included.

## Model Used

OpenAI GPT-6 Codex with reasoning, repository editing, shell execution,
PostgreSQL tests and browser inspection. The host does not expose the
exact model variant 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-11-02 16:11:30 -06:00
DottaandPaperclip 482706e7dd perf(tools): index pending profile review scopes (#18681)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - The Apps UI lists tool profiles and shows new tools that need
review.
> - Both services project new-tool review for each profile.
> - The projection scans include rules and exact rules for each catalog
row.
> - This repeats millions of comparisons when many selected profiles
exist.
> - This pull request builds scope and selector indexes once per
projection.
> - The benefit is less server CPU with the same fresh review results.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

New-tool review projection in profile listings, profile review, and app
attention.

**Current behavior**

Each newer catalog row scans the profile's included scopes. Included
catalog entries require a map lookup for each scope comparison. Rows in
scope then scan all rules again to omit tools that were already
reviewed. Profile listing and app attention repeat this work for every
profile.

**Proposed behavior**

Index covered application and connection scopes once. Expand included
catalog entries to their existing connection and non-null application.
Index exact selectors across all rules once. Keep the ordered catalog
filter and returned metadata.

**Reason and benefit**

A recent main-thread profile identified this scope-matching path as a
large CPU consumer. The local reproduction below confirms multi-second
CPU work in the actual owning services. This PR removes the repeated
scans without caching authorization or changing database reads.

Related [#18673](https://github.com/paperclipai/paperclip/pull/18673)
indexes effective access and profile summaries. It leaves this
pending-review path unchanged. This PR targets the separate
pending-review mechanism and has no dependency on that PR. The selector
helper is identical so the owners can share it when both changes land.

## What Changed

- Build covered application and connection sets for included scopes.
- Build exact selector sets for all rules, including exclusions, to omit
already reviewed tools.
- Preserve null application selectors, missing catalog references,
review watermarks, status checks, output order, and names.
- Add differential tests against the former scope/matching evaluator.
- Add PostgreSQL checks through all three affected service methods,
including current catalog and rule changes.
- Add a reproducible PostgreSQL benchmark of complete profile-list and
app-attention results.

## Verification

Baseline: `1f8f2e195f4897cd1c237bdc068de95780ab0c3c`. Treatment:
`fd59c0183ce64c44696f79604516f4d51ca5662b`. Node 24.22.2 on macOS arm64.
The production projection file at this baseline is identical to the file
at `410b0e27015495ab8951768b5b0b94727de33785`.

The benchmark exercises the real
`createToolProfileService(...).listProfiles` and
`createToolAppAttention(...)` methods against disposable PostgreSQL. It
uses 200 selected profiles, 1,900 active tools, 76,000 rules, and 12
agents. Profiles alternate between 65 and 695 rules. Half reference 695
removed catalog entries; half select current tools. This tests both the
slow failed scope scans and the slow exact-rule scans. No provider calls
or hosted traffic are generated.

The complete ordered results from both services match baseline. After
one equality/warmup invocation per version, five samples alternate
implementation order. Forced GC runs before each measured pair of
service calls. Other workers paused owned builds and benchmarks;
unrelated host activity was not controlled.

| One profile listing plus one attention listing | Baseline median
(range) | Change median (range) |
| --- | --- | --- |
| Process CPU | 5,406.512 ms (5,221.533–5,648.262) | 1,770.116 ms
(1,596.232–2,045.617) |
| Elapsed time | 5,279.231 ms (4,932.419–5,537.105) | 1,532.414 ms
(1,499.199–1,610.428) |
| Queries | 14 | 14 |
| Returned database rows | 156,215 | 156,215 |

Median process CPU falls **67.3%** and median elapsed time falls
**71.0%**. Profile summaries retain their old nested matching in this
comparison, so the result isolates pending-review indexing. Query counts
and row counts do not decrease. This is local source/tsx service proof.
It does not establish hosted improvement, whole-run latency, or HTTP
tail latency.

Reproduce with `server/scripts/benchmark-profile-review-projection.ts`;
baseline-module setup is documented in
`doc/mcp-discovery-performance.md`.

Passed:

```sh
node node_modules/vitest/vitest.mjs run server/src/__tests__/tool-profile-pending-projection.test.ts server/src/__tests__/tool-profile-review-service.test.ts server/src/__tests__/tool-profile-entry-order.test.ts
node scripts/check-module-boundaries.mjs
```

All five tests in three suites passed. The differential tests cover all
selector kinds, include/exclude effects, null scope behavior, missing
references, review watermarks, and exact special-character names.
PostgreSQL checks preserve current pending counts after exclusions,
catalog removal, and review; another company remains separate. `git diff
--check` passes.

The first new integration assertion used `summary` instead of the
existing attention response's `totals` field. It failed before the
mutation checks. The test assertion was corrected; no production code
changed for that correction. The final run above passed.

Server typecheck was attempted but did not pass local setup. The
packaged command did not reach TypeScript because a global pnpm child
tried to fetch and verify the project's pnpm version through an
unavailable registry. A direct Node 24 TypeScript invocation then
reported missing built `@paperclipai/paperclip-runner` and related
package declarations, with cascading type errors in unchanged consumers.
No error points to the changed projection. The prerequisite build was
not expanded into a full workspace build. Full local unsharded tests and
build were not run; final-head CI must supply broad acceptance. No merge
or deployment was performed.

## Risks

Scope expansion must preserve existing semantics. An individual catalog
rule covers its connection and only a non-null application. An explicit
null application selector still matches null applications. Removed
references contribute no scope when absent from the supplied catalog.
The oracle and PostgreSQL tests cover these boundaries.

The indexes add linear temporary memory in rule count and live only for
one projection. Current company-scoped database reads and review
mutations remain in their owners. Exclusions remain explicitly reviewed;
they do not create new review items. Revert this commit to roll back.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) with source inspection, code
execution, tests, and local PostgreSQL benchmarking. The context window
size is not available 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-11-02 16:10:42 -06:00
DottaandPaperclip 2b374caba0 fix(recovery): preserve unfinished remote exports before Retry (#18678)
## Thinking Path

> - Paperclip manages agent work and preserves each task's saved files.
> - A completed native result can still need workspace export.
> - Remote workspaces now use a different saved descriptor from legacy
copyback.
> - The execution hold checked only the legacy descriptor.
> - Task Retry could admit another run before the original export
finished.
> - A later failure could then supersede the original recovery record.
> - This change keeps unfinished remote exports fenced and permits
explicit historical file recovery.
> - Recovery keeps human review and newer execution authority intact.

## Linked Issues or Issue Description

**What happened?**

A native run completed successfully, but its remote workspace export
failed. The recovery action used
`native_workspace_sync_out_retry_exhausted`. Task Retry created a second
task run while the original files still needed preservation. The newer
failure then superseded the original action. A board file-recovery
request could queue that cancelled record, but the worker excluded it
from discovery.

**Expected behavior**

Keep Retry behind the unfinished export. Save the exact source and
finalize the existing accepted result once. Preserve pending human
review. An explicit request for a superseded source must save its files
without applying an old result over newer work.

**Steps to reproduce**

1. Save an accepted successful native result with a prepared
`remoteWorkspace` descriptor.
2. Fail its final export and retain its exact sandbox lease.
3. Select Task Retry before preservation completes.
4. Observe another task run before the original workspace is saved.
5. Supersede the original action and request file recovery for its exact
source. Observe queued work that the worker does not select.

**Paperclip version**

Observed at `1f8f2e195f4897cd1c237bdc068de95780ab0c3c`. The regression
is present on current master before this patch.

**Deployment mode**

Authenticated hosted instance with native Paperclip Runner and remote
sandbox workspaces.

Related: #18403 introduced the remote workspace path. #18644 reduces
export scratch disk use. #17916 covers a separate legacy warm-copyback
policy case. This change repairs remote export admission and explicit
historical preservation.

## What Changed

- Include prepared remote descriptors in the existing native export
hold.
- Retain remote source identity in the blocker and continuation read
projections.
- Let the existing worker select a cancelled export-repair record only
after an explicit board file-recovery request. Keep the current action
and workspace binding unchanged.
- Add real PostgreSQL, HTTP, filesystem and Git regressions. Update
execution semantics and recovery maps.

## Verification

- Red before the admission fix: HTTP Retry creates two task runs instead
of one.
- Red before the historical-source fix: the explicit recovery stays
scheduled and saves no snapshot.
- All 588 focused tests pass across the workspace recovery, recovery
source, explicit continuation and native export retry suites. The three
new integration cases verify duplicate request identity, original result
finalization, restored bytes and Git HEAD, pending human review,
current-writer exclusion, and preservation without older-result
commitment over newer work.
- `pnpm -r typecheck`, `pnpm build`, map validation and `git diff
--check` pass.
- Full hosted CI passes on `c598718379fa939ec539e8e91a15a94d90321b59`,
including all server, workspace, serialized, Runner and browser lanes
([run](https://github.com/paperclipai/paperclip/actions/runs/41529739604)).
Greptile reviewed that commit at 5/5 with no findings; there are no
unresolved review threads. Paperclip Review also published a complete
5/5 assessment for that exact commit with zero findings. Its check
conclusion is advisory/neutral, titled `5/5`. The first attempt lacked a
structured assessment; one normal completion request recovered the saved
analysis and published the validated assessment.
- The local `pnpm test:run` passed all six chat partitions, then was
stopped during the general server group after equivalent full CI
completed. Its partial log is retained; it is not reported as a
completed local full-suite pass.
- The test provider boundary uses real temporary files and the
production archive path. It simulates provider resume/stop calls. The
deployed fix and original hosted task recovery remain unverified until
merge and rollout.
- The older local Node 24.11.0 runtime failed to load the installed tsx
worker. Node 26.4.0 passed the isolated worker check. Required
repository checks use an isolated Node 24.22.2 runtime. The earlier
failure logs remain recorded.

## Risks

- Recognizing another unfinished export can keep previously admitted
work waiting. This is intentional until persistence is verified.
- Explicit historical recovery can resume the exact stopped sandbox to
read files. It retains source, allocation, ownership, writer and
bounded-attempt checks. It starts no provider turn.
- A newer run still prevents commitment of an older accepted result.
This change does not infer that a cancelled run had no external effects.
- No schema, credential, deployment or fleet configuration changes.

## Model Used

OpenAI Codex, GPT-6 family. The runtime does not expose the exact model
ID or context-window size. Reasoning, repository inspection, tool use
and code execution assisted this change.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 16:03:09 -06:00
DottaandPaperclip 919ddbf46d fix(workspaces): read committed files before live allocations (#18677)
## Thinking Path

> - Paperclip keeps task files in managed workspaces.
> - A final remote save commits a durable snapshot and clears writer
authority.
> - The old allocation can remain recorded while its transport becomes
unavailable.
> - Files still tried that live allocation before the accepted saved
version.
> - This PR reads the validated save when authority is clean and no
writer owns it.
> - Dirty work and active writers still require the live allocation.

## Linked Issues or Issue Description

Related: #18403 introduced remote Files access. #18665 fixes a separate
completion-settlement issue and is included in the base.

**What happened?**

A file preview returned `422 workspace_unavailable` after a remote task
had saved its files. Its clean authority still had a live location. The
same original bytes were readable from the committed save after that
location cleared. The exact original live transport failure is unknown.

**Expected behavior**

Once the workspace is clean and has no writer, Files reads its exact
current committed save. A retained location must not make accepted files
depend on remote command execution.

**Steps to reproduce**

Create a real committed workspace archive. Keep its allocation active in
the recorded authority. Clear dirty state and writer authority. Make
live execution unavailable, then request the ordinary file preview
route. Before this fix it returns 422. After this fix it returns the
saved bytes without a provider command.

## What Changed

- Select the saved-file loader before consulting a live location when
authority is clean and has no writer.
- Keep exact company, workspace, snapshot, archive, and authority-change
checks.
- Keep the live path for dirty work and active writers. Never substitute
their older saved bytes.
- Cover browse, resolve, preview, download, rejection controls, and
saved-copy cleanup through real routes and storage.
- Document the selection rule and update its feature and access-map
recipes.

## Verification

- Red: the new ordinary-route regression expected HTTP 200 but received
422 against the old service.
- A separate compatibility control reproduced the optional-loader
regression. Valid live reads still work when the loader is absent;
no-location reads still fail, and a configured invalid save never falls
back to live bytes.
- Green: 98 ordinary file-route and authorization tests passed with real
PostgreSQL and archive storage.
- All 46 opt-in remote workspace lifecycle tests passed against one
owned local disposable PostgreSQL database. Its database, server, and
files were cleaned after the run. No live S3 or provider flags were
enabled.
- Full workspace typecheck passed after the optional-loader
compatibility repair. Full build passed locally before that narrow
repair. All normal CI checks pass on the current head, including build
and server suites. The separate Paperclip Review job and the full local
test suite remain in progress.
- Feature/access-map validation and `git diff --check` passed.
- A read-only staging check preserved and verified the original saved
bytes. It did not rerun the agent or qualify the failed journey. The
fixed active-location path has local regression evidence; deployed
acceptance is pending.

## Risks

A clean workspace now uses the existing bounded saved-archive loader
while a location remains recorded. Each Files request can retrieve and
extract that archive. Existing disk, size, concurrency, cancellation,
and cleanup bounds remain. A dirty workspace or current writer still
uses live files and fails closed when they are unavailable. This change
neither releases compute nor changes access permissions. It does not
identify the original provider RPC subreason.

## Model Used

OpenAI GPT-6 through Codex with reasoning, code execution, and browser
tools. The runtime does not expose a more specific model identifier 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
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 16:00:04 -06:00
DottaandPaperclip 5d40e75253 fix(evals): distinguish scheduled TestOps results from uploads (#18676)
## Thinking Path

> - Paperclip lets people manage AI agents and inspect their work.
> - The chat catalog reports each original Product E2E case to TestOps.
> - TestOps creates scheduled result rows before a case runs.
> - Those rows have identity fields but no status property.
> - The publisher currently mistakes any case row for an uploaded
outcome.
> - This PR distinguishes scheduled membership from an outcome after
strict identity checks.
> - Each case can upload once and wait for processing without changing
its grade.

## Linked Issues or Issue Description

Refs #18647, #18666.

**What happened?**

A real TestOps launch had all three scheduled result rows before any
model case started. Each row had the expected case, project, launch and
job-run identity. Its status property was absent. The publisher treated
the row as already uploaded, skipped its only POST and then rejected
readback.

**Expected behavior**

A fully bound scheduled row permits the first immutable case upload. It
does not count as an outcome. Readback waits within the existing bound
until the original status and exact attachments are ready.

**Steps to reproduce**

Run the new scheduled-row control against the parent API. It rejects
before sending the initial result. Fixing only that initial check still
rejects the first scheduled readback after one POST.

## What Changed

- Share the strict result-detail identity check between initial
inspection and readback.
- Recognize an absent status property as scheduled only after that
check. Present valid statuses, including unknown, stay readback-only.
Malformed statuses and foreign identities fail closed.
- Keep scheduled full-catalog readback unready within the same poll and
deadline bounds. Keep the final status, evidence and attachment checks
unchanged.
- Calibrate three planned rows, delayed and permanent processing,
unknown outcomes, wrong job/source and explicit-null status. Retain the
once-only upload and uncertain-response controls. Use the registered
legacy full-name alias in the fixtures.

## Verification

- The real-shape parent control fails with `result_mismatch` after the
first upload is suppressed.
- A controlled initial-only fix sends one POST and still fails on
scheduled readback. The final two-seam fix passes.
- All 77 focused controls pass: `node --test
tests/runner-e2e/chat-catalog-testops-streaming.test.mjs
tests/runner-e2e/chat-completion-testops-api.test.mjs
tests/runner-e2e/chat-full-catalog-testops-adapter.test.mjs`.
- Both changed files pass Node syntax checks. `git diff --check` passes.
- All local controls use synthetic data and mocked HTTP. No local app,
database, native build or provider runs.
- The affected live run was cancelled during build after metadata proved
no original case had started. Its build instance is terminated. No
original grade was changed or inferred.
- Latest-head GitHub CI is green: 48 successful jobs and one skipped.
Typecheck, build, browser and required aggregate checks passed.
- The first CI attempt failed a heartbeat scheduling test’s five-second
idle wait after its 51-admission assertion passed. Its six direct owners
were byte-identical to the prior passing CI. One same-head failed-job
recovery passed the server shard and required aggregate; all 46 earlier
successful jobs were carried unchanged. The original failure is
preserved, and its underlying cause remains unresolved. No heartbeat
source, fixture or timeout was changed.
- Live streaming qualification remains pending. No user command or
documentation contract changes.

## Risks

- The observed JSON distinction is status-property absence, not a
result-stage or UUID field. Those fields are not used.
- A scheduled row must match the current project, launch, case,
registered full name, job run and GitHub source URL. It never qualifies
as passed or complete.
- The same 12-poll and time limits remain. A permanent scheduled state
fails. A present outcome never causes another POST. An uncertain write
still uses GET-only reconciliation.
- Backend handling of uploaded scheduled rows still needs live
qualification. Duplicate, foreign and final-coverage guards remain; this
PR does not assume server deduplication.
- Earlier dispatch and cancelled setup records remain separate. The
first integration HTTP 500 cause is still unknown. No in-flight legacy
workflow is changed or rerun.

## Model Used

OpenAI `gpt-6.1-sol`, with tool use and code execution. The session does
not expose a context-window size. The independent source peer uses the
same model family.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 15:43:33 -06:00
DottaandPaperclip 0c48f5e727 test(runner): cover document guidance for file-only objectives (#18669)
## Thinking Path

> - Completion guidance can link a saved task document even when the
user requested only a file.
> - The validator loads document publication proof when the objective
requests a document or the completion report cites one.
> - The success tests added in #18661 all requested both a document and
a CSV.
> - Those tests therefore could not detect loss of the cited-document
branch.
> - This test requests only a CSV and resubmits the actual guidance link
with a registered file receipt.

## Linked Issues or Issue Description

Addresses the [coverage warning on
#18661](https://github.com/paperclipai/paperclip/pull/18661#discussion_r4447457009).

**What happened?** The earlier success cases exercised the
document-requested condition. The independently cited-document condition
lacked regression coverage.

**Expected behavior:** A file-only objective can cite a verified
saved-document guidance link alongside the required registered file.

**Steps to reproduce:** Publish a task document, register a CSV, request
only the CSV, obtain the saved-document href from completion guidance,
and submit both pieces of evidence. Removing only the cited-document
lookup must make this case fail.

**Paperclip version or commit:** Current master after #18661.

**Deployment mode:** Local source tests with real PostgreSQL and native
publication receipts; the remote CSV reader is controlled. No deployment
is part of this follow-up.

## What Changed

- Allow the existing registered-file test helper to accept a file-only
objective.
- Add one success case using real document publication, file
registration, and the server-generated guidance href.
- Keep production source and the existing negative cases unchanged.

## Verification

- All 27 native completion feedback tests pass on current production
code.
- The new case fails when only `|| citesTaskDocument` is temporarily
removed from publication lookup. The production file is restored exactly
afterward. This demonstrates a coverage gap; it does not establish a new
production defect.
- Server typecheck and `git diff --check` pass.
- Full repository CI passed, including both required E2E and verify
aggregate gates. Greptile scored the current head 5/5 with no unresolved
findings. The separate optional Paperclip review is queued and has
supplied no finding. The preceding production PR records its separate
local full-suite timeout and isolated passing retry; this follow-up uses
the focused local suite and full CI rather than repeating that long
local run.

## Risks

Low risk: only the existing test file and its fixture helper change. The
new case depends on real document/file publication contracts, including
the CSV receipt requirement.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning, code editing, shell
execution, and automated tests. The context-window size is not exposed
in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1102.0-canary.6
2026-11-02 15:33:46 -06:00
45e91f097c fix(inbox): requalify existing unread fix (#18670)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - The personal inbox must keep new comments unread until the person
reads or answers them.
> - A comment updates task recency, even when another person writes it.
> - The assignee unread query treats that task timestamp as a read
receipt.
> - [rudycelekli](https://github.com/rudycelekli) already repaired this
in #15085, including a reviewed deleted-comment safeguard.
> - That PR now has merge conflicts and checks from an older base. This
PR ports and requalifies the existing unread fix on current master.
> - The port adds real human-comment and API regressions. The original
contribution remains open and unchanged.

## Linked Issues or Issue Description

Fixes: #15079
Refs: #15085

This is an attributed maintainer port of #15085 at
`fe6a486c9ca21cd3a6ea0cef9764c372c53f4572`. The commit includes the
verified original contributor credit. This is not an independent claim
to the original repair.

## What Changed

- Port the stable creation-time fallback for a human assignee in SQL and
derived user context. Explicit reads and own replies still take
precedence.
- Port the reviewed safeguard that excludes deleted external comments.
Keep the historical touch from a deleted own reply.
- Exercise real comment writes, task recency updates, existing read
receipts, read/unread toggles, later assignment, company isolation, and
comment deletion through native PostgreSQL and ordinary API projections.

## Verification

- Native PostgreSQL regressions fail before the repair: real comment
writes leave the assignee falsely read, and later assignment hides
existing comments.
- A separate deletion regression fails before the reviewed safeguard: a
deleted external comment remains the latest external activity.
- The frozen head `0dadf85611cbfdc7a762cb82b03ed64519be5434` passes all
41 focused inbox, source-visibility, request, archive, and user-context
tests on native PostgreSQL. No tests were skipped.
- `pnpm -r typecheck` and `pnpm build` pass on that same frozen head
with Node 24 and pnpm 9.15.4. The current-head CI is green, including
all general and serialized test shards, build, typecheck, Runner checks,
and eight E2E shards. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/41525545915).
- The local full-test attempt was stopped before the one master rebase.
It is incomplete and is not a local full-suite pass. The full
current-head CI completed successfully.
- Fresh Greptile review is 5/5 on
`0dadf85611cbfdc7a762cb82b03ed64519be5434`, with no actionable findings
or open review threads.

## Risks

- Assigned tasks with older external comments can appear unread. A later
explicit read or own reply still clears them.
- This changes no schema, API fields, company membership rules, or query
joins.
- Legacy compact-response cache policy is unchanged. Immediate mutation
checks use the ordinary, rows, and index projections.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, repository inspection,
code editing, and command execution. This session does not expose a more
specific backend model identifier 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 (no
documentation change is needed to restore the existing unread contract)
- [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: Rudy Celekli <47457359+rudycelekli@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 15:26:28 -06:00
Huanyi Xie 3b24911c16 fix(hermes-gateway): preserve complete whitespace-sensitive delta frames (#15201)
## Thinking Path

> - Paperclip shows agent output in a live transcript.
> - Hermes Gateway emits structured events and raw message text to
stdout.
> - A raw chunk without a newline prefixes the next structured event.
> - The anchored transcript parser then loses later message deltas.
> - This pull request emits each delta once as a complete JSON event.
> - The transcript can read all streamed events again.

## Linked Issues or Issue Description

Fixes: #15132


Related PR #9909 removes the duplicate raw-delta log write. This PR also
fixes two separate fidelity defects that its diff leaves:
whitespace-only/leading/trailing delta text is trimmed by `nonEmpty`,
and large delta payloads are shortened by the event-log summarizer. The
final implementation preserves the exact delta in a JSON frame and the
assembled output, with whitespace, 9,000-character, and forged-prefix
regressions. The overlapping raw-log removal is required so the safe
frame is the only transcript copy.

## What Changed

- Remove the redundant raw stdout write; each delta is logged once as a
JSON event.
- Preserve whitespace and existing secret redaction; keep complete
message deltas beyond the diagnostic truncation limit.
- Exercise the persisted stdout through the real transcript parser, with
consecutive chunks, embedded newlines, a forged event prefix, and a
9,000-character delta.

## Verification

- The new regression finds only the first delta on the original code.
- All 87 Hermes adapter tests pass after the fix.
- Hermes adapter typecheck and build pass.
- git diff --check passes.
- All remote full-repository CI gates pass for the final head.

## Risks

Low risk. Message-delta logs contain one canonical redacted delta
payload. Other events keep their existing diagnostic limits. The
regression proves there are no duplicate stdout entries or fabricated
events.

## Model Used

OpenAI Codex, based on GPT-6, assisted with source review,
implementation and local test execution. The exact deployment model ID
and context-window size are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (targeted local checks and
full remote CI pass)
- [x] I have added or updated tests where applicable (Hermes regression
/ real Compose interpolation checks)
- [x] I have updated relevant documentation to reflect my changes
(Hermes has no configuration changes; Compose documentation is updated)
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
2026-11-02 15:07:44 -06:00
DottaandPaperclip b4a66027b7 fix(server): deliver chat completions after nested workspace saves (#18665)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent Chat returns completed worker tasks to the original
conversation.
> - Delivery must retain its wake receipt when execution gates refuse
admission.
> - A workspace save can contain a nested snapshot operation.
> - The old checks lost the receipt and treated that saved snapshot as
unfinished work.
> - This pull request preserves the receipt and recognizes a successful
owning save.
> - The benefit is that completed work can reach the chat through the
normal queue.

## Linked Issues or Issue Description

Refs #18652. Related: #17206 covers failed finalize recovery. This
repair handles a successful finalize with an enclosed snapshot and does
not change failed-save recovery policy.

**What happened?**

A delegated worker finished and saved its result. The original chat
received no update. The dependency gate compared operation start times.
A nested snapshot started after its enclosing finalize and therefore
left a permanent hold. The completion wake also lost its exact
idempotency receipt when the queue merged a refused wake into a generic
dependency wait. The outbox reported `Completion wake returned no run or
durable receipt`.

**Expected behavior**

A successful finalize covers a completed operation enclosed by that save
when company, workspace, issue, and run match. Completion wakes that
disable coalescing keep their own durable receipt even when admission
waits. Dependency, budget, Stop, and pause gates still apply.

**Steps to reproduce**

1. Hand a task from a chat to a worker and make the chat wait on that
task.
2. Finish a workspace finalize that starts before its nested snapshot
and ends after the successful snapshot.
3. Mark the worker Done and deliver its completion outbox entry.
4. On the parent revision, the dependency stays blocked and the
completion receipt is absent.

**Paperclip version or commit**

Reproduced against `53f480d1b3` with real disposable Postgres rows and
the normal queue/outbox services.

## What Changed

- Honor `allowRunCoalescing: false` when recording execution waits.
- Accept an enclosed successful operation only when the successful
finalize has the same company, workspace, issue, and run and covers its
whole recorded interval.
- Preserve the existing rule that a strictly later successful workspace
finalize clears earlier work.
- Add failure controls for foreign runs, unfinished snapshots, failed
saves, snapshots that finish too late, and later operations.
- Exercise the real outbox and queue together. Hold provider dispatch at
the existing drain boundary and verify server-recorded Done facts reach
the admitted turn.
- Document receipt identity and workspace-save coverage.

## Verification

- Before repair: the two causal regressions fail and five safety
controls pass. The missing exact receipt and empty wakeable-dependent
list match the observed failure.
- After repair: those seven cases pass without assertion changes.
- The full affected set passed 288 tests and failed one existing
scheduling test. Its unchanged Node24 baseline also failed. A
closed-phase probe showed the fake adapter finished successfully at
3.453 seconds, after the incidental 3-second poll. The test now joins
the existing execution promise and retains its status and dependency
assertions under the unchanged Vitest timeout. The synchronized full
dependency suite passes all 13 cases.
- `pnpm -r typecheck` and `pnpm build` pass on pinned Node24/pnpm9.
`pnpm test:run` is running. The combined real outbox/queue case passes.
Fresh Greptile is 5/5 on `d7cee24b7032c7fdf171bfd1246cd90d41db1cba`.
Exact-head normal CI and required `ci / verify` and `ci / e2e` pass.
- The original scheduling failures on Node26 and Node24, the
unchanged-source baseline failure, and the closed-phase probe are
retained in the validation record. No model, deadline, production
assertion, or paid attempt was retried to change the failure grade.
- Current-head CI attempt1 passed all product and workspace coverage but
failed the unchanged serialized retry-worker case at
`issue-scheduled-retry-routes.test.ts:606` (first batch not observed
before the poll deadline;410 other shard tests passed). The exact
unchanged case passes locally on Node24 with real Postgres. The one
failed-jobs-only retry passed on the same head; the original grade is
retained.
- The full local command completed all1828 chat integration tests. Its
general stage remains running and has retained failures in unchanged
`workspace-runtime.test.ts` (30-second local port-conflict fixture) and
`muse-control.test.ts` (current binding authentication fixture). These
are not counted as passing local full-suite evidence. Their current-head
hosted coverage passed.
- The separate advisory Paperclip Review app is paused and has no code
finding. Its in-progress state is preserved and is not counted as a
pass; it is not a required repository status check.
- The live Cloud completion journey remains failed and unqualified. It
must pass at the deployed fixed revision before daily-plan admission. No
QA oracle, model, budget, or run limit changes are included.

## Risks

- The workspace coverage query must not clear a save from another owner
or new work after finalization. The guard checks the full interval and
exact owner identity, with negative controls.
- Refused noncoalescible automatic wakes retain separate receipts.
Replaceable automatic signals still merge. No new polling or provider
retry path is added.
- No migration or API change. Deployment and live acceptance are
separate remaining gates.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 15:06:26 -06:00
DottaandPaperclip cd12432947 fix(runner): recognize verified task document evidence (#18661)
## Thinking Path

> - Paperclip manages AI agents and keeps their results attached to
tasks.
> - Native tools return links to saved task documents.
> - Completion feedback asks agents to include those links.
> - The file-delivery validator treated every such relative link as a
workspace path.
> - A valid document and CSV result could therefore fail completion when
it cited the supplied document link.
> - This change derives document links from the same verified
publication projection for guidance and validation.
> - Requested files still need their own verified delivery evidence.

## Linked Issues or Issue Description

**What happened?**
The native document tool and completion feedback produce a link such as
`/EX/issues/EX-1#document-output`. When a task also requests a
downloadable CSV, citing that link causes completion to reject it as a
workspace-only file. This occurs even when the document is published and
the file has a valid current-run delivery receipt.

**Expected behavior**
Accept a server-derived document link only when it names the current
company/task and a currently attached revision with a matching native
publication receipt. Keep the separate requested-file requirement and
all foreign, stale, missing, and workspace-file guards.

**Steps to reproduce**
1. Save a task document through the native `write_document` tool.
2. Publish a CSV through `register_deliverable`.
3. Ask completion feedback for the final-response guidance.
4. Cite its returned document link alongside the file receipt in the
next completion report.
5. The old validator rejects the valid document link as a workspace-only
file.

**Paperclip version or commit**
Current source checkout. The regression exercises the real native
document producer and completion validator.

**Deployment mode**
Local source verification on macOS arm64 with Node 24.22.1, pinned pnpm
9.15.4, locked dependencies, temporary PostgreSQL, and a controlled
remote file-reader boundary. No live provider or hosted deployment is
included.

## What Changed

- Derive the canonical document href in the existing
company/task/current-revision publication query.
- Use that same verified href in completion guidance and reference
validation.
- Keep file registration and hash/size receipt requirements separate
from document evidence.
- Cover evidence, artifact, and criterion references; foreign
companies/tasks; bogus keys; local paths; and lost current-revision
publication proof.
- Exercise actual native document writes and CSV registration, including
attachment download query and fragment links.
- Update the execution contract and the document feature/access maps.

## Verification

- Red before the production edit: native completion generated a real
saved-document link, then rejected the same link alongside a valid
published file. The failure was the workspace-only-file guard.
- Green: 210 tests across native completion feedback, explicit output
validation, and the existing native file-handoff suite pass. These use
real PostgreSQL and native tool receipts; the remote file reader is
controlled.
- A saved document link alone still fails the explicit CSV requirement.
A document whose current revision lacks its publication receipt is
rejected. Foreign task/company links, missing keys, malformed links, and
workspace paths remain rejected.
- Full workspace typecheck, server typecheck, and production build pass.
- `node scripts/check-maps.mjs`, `node
scripts/check-module-boundaries.mjs`, and `git diff --check` pass. Map
checks establish structure only.
- Full `pnpm test:run` is running separately. There is no full-suite
verdict yet. CI and review are pending.
- Hosted acceptance and any recovery of existing tasks remain separate
steps. This PR does not change final-response recovery or scheduling.

## Risks

- An overly broad URL exception could admit foreign or unpublished
output. The validator accepts only exact hrefs from the authenticated
publication projection.
- Document evidence could hide a missing requested file. A separate
regression keeps that delivery gate effective.
- The shared projection adds current task/company joins. Existing
document feedback and publication tests cover those consumers.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning, code editing, shell
execution, and automated tests. The context-window size is not exposed
in this session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 15:02:00 -06:00
DottaandPaperclip aa6c9c3f25 perf(storage): overlap streamed S3 multipart uploads (#18659)
## Thinking Path

> - Paperclip manages AI agents and preserves their work.
> - Large workspace and skill objects use the shared S3 multipart
uploader.
> - The uploader waits for each part acknowledgement before it sends the
next part.
> - Storage request latency therefore accumulates once per part.
> - This change overlaps up to four streamed part requests.
> - One source reader preserves byte order and backpressure.
> - Failure cancels and settles active requests before cleanup.

## Linked Issues or Issue Description

Related: #18082 added the shared streamed multipart uploader. #18644
fixes temporary disk use during workspace capture. It changes a separate
stage.

**What happened?**
The shared S3 multipart uploader sends large object parts in sequence.
The code waits for each `UploadPartCommand` before it consumes the next
part. A controlled HTTP test confirms that only one complete part
reaches the endpoint while its acknowledgement is held.

**Expected behavior**
Upload independent parts concurrently within a fixed limit. Preserve
exact bytes, ordered completion receipts, source backpressure,
cancellation, and full snapshot verification.

**Steps to reproduce**
1. Upload a large stream through the S3 multipart provider.
2. Hold each successful part acknowledgement at a disposable storage
endpoint.
3. Observe that the old uploader sends only one complete body until its
acknowledgement returns.
4. Repeat with this change. Four complete bodies can reach the endpoint
before the first acknowledgement.

**Paperclip version or commit**
Current source checkout. The affected uploader was introduced in #18082.

**Deployment mode**
Local source verification on macOS arm64 with Node 24.22.1, pinned pnpm
9.15.4, and locked dependencies. The HTTP tests use synthetic data and a
disposable loopback endpoint.

## What Changed

- Send up to four part requests at once through bounded streams.
- Keep one source reader and retain the existing adaptive part-size
policy.
- Store successful receipts by part number before completion.
- Cancel a stalled asynchronous source read without waiting for the
source to produce more bytes.
- Preserve the first error. Cancel sibling requests and settle them
before multipart abort.
- Cover exact bytes, out-of-order acknowledgements, backpressure, the
concurrency limit, source errors, cancellation, and the real S3 HTTP
client.
- Document the transfer bound. Snapshot encryption, publication, and
full object verification retain their existing behavior.

## Verification

- Failing before the change: the held-acknowledgement regression
expected four complete part bodies and received one. The same regression
now passes.
- All 15 focused multipart and storage-diagnostic tests pass. The real
AWS S3 SDK sends four exact 8 MiB bodies through a disposable HTTP
endpoint before any acknowledgement. Completion retains source order.
- Controlled transfer comparison: one synthetic 64 MiB stream, eight 8
MiB parts, real S3 SDK and loopback HTTP, each acknowledgement delayed
100 ms. Original: 904 ms, peak one request. Fixed: 247 ms, peak four.
Both transfers verified every part hash and completion order. This is
local boundary evidence, not a hosted latency claim.
- A second safety regression reproduced cancellation waiting
indefinitely on a stalled asynchronous source. Abort-aware reads now
settle within the existing bounded cleanup budget.
- All nine existing encrypted snapshot storage tests pass after
correcting missing library aliases in the local embedded-Postgres
dependency. The failed setup attempt had no test verdict.
- Full workspace typecheck and production build pass. The rebased server
typecheck also passes.
- The first full `pnpm test:run` attempt stopped during chat test
collection with `No test found ... in lines ...` before a suite verdict.
The chat test and line-selection scripts are unchanged from master. A
retry after local Postgres dependency setup passed its first chat
shards, then was stopped to avoid redundant host load after current-head
CI passed every type/build/general/serialized/runner group. The
unrelated narrow-banner E2E job failed its first attempt and passed one
bounded retry; all current-head GitHub CI jobs are now green. There is
no full local verdict. The separate Paperclip native review concluded
neutral after reporting that work was paused; it supplied no substantive
code review.
- Commands: `pnpm -r typecheck`, `pnpm build`, and `pnpm --filter
@paperclipai/server exec vitest run --configLoader runner
src/__tests__/storage-s3-multipart.test.ts
src/__tests__/storage-s3-failure-diagnostics.test.ts
src/services/remote-workspace-snapshot-storage.test.ts`.
- Deployment and an end-to-end hosted acceptance run remain separate
steps.

## Risks

- Four requests per upload increase concurrent storage traffic. Multiple
simultaneous uploads multiply that bound.
- Shared source consumption could reorder bytes. One producer and
exact-content tests protect that boundary.
- Failed siblings could outlive multipart cleanup. Cancellation and
settlement tests protect cleanup order.
- Capture and full read-back verification still take time. This change
only targets serial multipart latency.

## Model Used

OpenAI `gpt-6.1-sol` through Codex, with reasoning, code editing, shell
execution, and automated tests. The context-window size is not exposed
in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 15:01:34 -06:00
DottaandPaperclip 410b0e2701 fix(evals): accept refreshed catalog workflow URL (#18666)
## Thinking Path

> - Paperclip lets people manage AI agents and inspect their work.
> - The chat catalog reports original Product E2E grades to TestOps.
> - TestOps can refresh its job metadata from GitHub.
> - That operation returns a canonical master workflow-file URL.
> - The catalog guard currently rejects that exact URL before case
selection completes.
> - This PR accepts that fixed URL and keeps the existing source and
identity checks.
> - The catalog can use the refreshed job without changing its cases or
grades.

## Linked Issues or Issue Description

Refs #18542, #18647.

**What happened?**

A supported TestOps job refresh changed the catalog job URL to the
GitHub `blob/master/.github/workflows/chat-catalog-testops.yml` form.
The selection guard rejects it as `job_mismatch`.

**Expected behavior**

The guard accepts that exact parent workflow URL. It still rejects
another owner, branch or workflow.

**Steps to reproduce**

Run the new adapter regression against the parent commit. It fails in
`validatePilotSelection` before the job-run request.

## What Changed

- Add one exact canonical master URL to the full-catalog workflow URL
guard.
- Add a regression through the real selection validator with refreshed
job metadata. Keep negative checks for another owner, branch and the
called case workflow.

## Verification

- The new selection regression fails on the parent with `job_mismatch`
and passes with this change.
- All 73 focused controls pass: `node --test
tests/runner-e2e/chat-full-catalog-testops-adapter.test.mjs
tests/runner-e2e/chat-completion-testops-api.test.mjs
tests/runner-e2e/chat-catalog-testops-streaming.test.mjs`.
- Both changed files pass Node syntax checks. `git diff --check` passes.
- These controls use synthetic metadata and mocked HTTP. No local app,
database, native build or provider runs.
- Removing the one added predicate restores the parent API file exactly.
The branch, job, case, source, evidence and grade checks remain
unchanged. The pilot URL policy also stays unchanged.
- Current-head GitHub CI passes: 48 jobs pass and one is skipped,
including the required typecheck, test, build and final summaries. Live
streaming qualification remains pending. No documentation change is
needed for this internal URL compatibility fix.

## Risks

- The alias accepts only this repository, master branch and parent
workflow in the full-catalog lane. It grants no alternate source or
execution authority.
- An earlier TestOps dispatch failed with an integration HTTP 500 before
GitHub created a run. Its cause remains unknown. This patch addresses
the separate, reproduced metadata compatibility failure; it does not
claim to cause or cure that HTTP 500.
- Existing in-flight workflows keep their original source. This PR does
not patch, rerun or upload into them.

## Model Used

OpenAI `gpt-6.1-sol`, with tool use and code execution. The session does
not expose a context-window size. The independent source peer uses the
same model family.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 14:53:30 -06:00
Devin FoleyandPaperclip 49b3804830 fix(connections): load permissions and show AI account identity (#18653)
## Thinking Path

> - Paperclip manages AI agents and their access to saved connections.
> - The Permissions page loads account details and permitted agent
choices.
> - Company-wide AI accounts repeat retained installation checks for
every candidate agent.
> - This makes target checks grow with the square of the roster size.
> - The browser waits without a deadline, and connection names do not
identify the provider login.
> - This pull request batches direct AI checks and bounds loading with
recovery controls.
> - Account details load separately and show a provider email or an
explicit profile-permission limit.

## Linked Issues or Issue Description

**What happened?**

Opening a saved AI account can leave Permissions on “Loading AI
account…” for minutes. The account itself can be connected. The existing
capability batch excludes AI connections, so a company-wide install
repeats checks for every installed agent for every candidate. Saved
names and Paperclip ownership also do not establish which provider login
a credential uses.

**Expected behavior**

Direct AI accounts reuse retained-target checks within one descriptive
request. The page shows loaded account controls or a bounded failure
with Retry. Permissions shows the provider email and organization when
the selected credential permits profile access. An unavailable profile
must not block maintenance or disconnect a working inference credential.
Writes still authorize current permissions.

**Steps to reproduce**

1. Save an AI account in a company with several agents.
2. Install the account company-wide.
3. Open its Permissions page.
4. Delay the account-list or grants response to exercise the loading
failure.

The maintained benchmark reproduces database work with synthetic local
data. Refs #17945, which added batching for non-AI connections. Searches
found no open PR for this AI-account loading fix.

## What Changed

- Include direct AI accounts in the existing board capability batch.
Referenced pool members, delegated actors, complex selectors, and
mutation authorization keep their existing evaluator.
- Add opt-in per-caller GET deadlines to the API client. A timed-out
caller detaches the stuck coalesced request so Retry starts a fresh
fetch. Other callers retain their own cancellation and results.
- Apply a 15-second deadline to AI account lists and grants reads. The
permissions view retries transient failures once and reports other
failures immediately.
- Share the parent Permissions grants query with AI account details.
Keep loaded controls visible after a background error and offer Retry.
- Add a grant-scoped identity GET and OpenAPI contract. The service
checks current membership and credential audience before it reads the
selected credential. It projects only the provider email and
organization; provider IDs, tokens, and raw errors stay private.
- Show account details independently of maintenance controls. Anthropic
profile denial has an explicit message and preserves connected status.
Transient profile failures have a separate Retry action. Observations
are cached for five minutes under the company, connection, grant, and
grant revision.
- Extend real PostgreSQL and authenticated HTTP coverage,
client/component regressions, map guidance, and the existing benchmark's
AI mode.
- Address the Apex file-size finding by moving gallery identity lookup
into the existing app display helper module. `AppDetail.tsx` is 984
lines; lookup behavior is unchanged.

## Verification

Local source checkout on macOS, Node 25.6.1, pnpm 9.15.4, and disposable
PostgreSQL 18.1. Provider calls use fixtures. No hosted deployment or
provider qualification is claimed.

- Passed `pnpm -r typecheck` and `pnpm build`.
- Passed all 87 tests in `connection-management.integration.test.ts` and
all 33 tests in `connection-install-capabilities.test.ts`.
- Passed 196 AI connection, identity-provider, and OpenAPI tests:
`ai-connections.test.ts`, `ai-account-identity.test.ts`, and
`openapi-routes.test.ts`.
- Passed 107 focused UI/client tests: `client.test.ts`,
`ManagedAiConnectionDetails.test.tsx`,
`AiConnectionAccountDetails.test.tsx`, and `AppDetail.test.tsx`.
- After the Apex extraction, passed UI typecheck/build and 106 component
tests across `AppDetail.test.tsx`, `AppNotConnected.test.tsx`,
`ManagedAiConnectionDetails.test.tsx`, and
`AiConnectionAccountDetails.test.tsx`.
- The authenticated HTTP tests compare complete grants responses across
human roles, for tool and AI connections. They verify a real install
mutation succeeds before revocation and fails afterward.
- A company-wide personal AI fixture checks 20 targets instead of 400.
Pool-member permission loss still denies the complete pool description.
- UI states covered: shared cached grants, stuck account/grants fetches,
one automatic retry, terminal failure, manual recovery, authorization
failure, background failure with retained controls, and unmount
cancellation. Client tests also cover stalled response bodies and
independent coalesced callers.
- Identity coverage includes actual bearer-key/JWT reads, private-user
and cross-company denial before provider access, revoked credentials,
provider 401/403/429/500, and grant-change isolation. A real local HTTP
fixture stalls the response body, verifies the shared 15-second
deadline, and keeps unrelated HTTP requests responsive. The test
shortens the native deadline to 100 ms. Profile permission denial leaves
the saved account connected.
- Passed `pnpm check:token-gates`, `node scripts/check-maps.mjs`, `node
scripts/check-module-boundaries.mjs`, and `git diff --check`.
- The full local `pnpm test:run` started with the loading-only change.
All six chat shards passed. It recorded one failure in the unchanged
`heartbeat-retry-scheduling.test.ts` quota-rejection case. That exact
case passed a focused rerun on the final head. The initial failure cause
remains unconfirmed and its local log is retained; this is not a full
local-suite pass. The redundant local run was stopped with SIGINT after
final-head CI completed successfully.
- [Final-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41515556725)
passed on `ead8d276d4a2023614fff54b3e9a858f28c3178b`: typecheck, build,
all 12 server shards, all 3 chat shards, workspace suites, all 9
serialized suites, all 8 end-to-end shards, Runner checks, and the
aggregate verify gate. Security checks passed. Optional Storybook checks
were skipped by workflow policy. GitHub reports the branch mergeable
without conflicts.
- Apex reviewed head `ead8d276d4a2023614fff54b3e9a858f28c3178b` at 5/5,
confirmed the extraction resolves its earlier file-size finding, and has
no unresolved review threads.

The existing benchmark ran for the loading-only change now recorded in
commit `5f725b36fa52002545241a5a8b7a10602f0cc0ce`, with `--purpose=ai
--baseline-ref=026fd9e3452`. The identity follow-up leaves that batch
source unchanged. Two warmups and five alternating samples exercise each
of eight fixture shapes. Complete positional capabilities, reasons, and
operations match the baseline in every sample.

| AI fixture | SQL calls before → after | Target reads before → after |
| --- | ---: | ---: |
| 1 agent, company install | 9 → 9 | 1 → 1 |
| 32 agents, company install | 5,248 → 164 | 1,024 → 32 |
| 100 agents, company install | 50,400 → 504 | 10,000 → 100 |
| 100 agents, partial install | 13,175 → 503 | 2,575 → 100 |

These counts measure the real service over local PostgreSQL. They do not
predict hosted page latency. To reproduce the standalone benchmark, use
a checkout of commit `5f725b36fa52002545241a5a8b7a10602f0cc0ce` and run
the command below. Its isolation check intentionally rejects the later
identity follow-up's additional runtime changes.

```sh
node --import ./server/node_modules/tsx/dist/esm/index.mjs scripts/benchmark-connection-install-capabilities.ts --purpose=ai --baseline-ref=026fd9e3452
```

Run the final-head regression suites from the repository root:

```sh
cd server
pnpm exec vitest run src/__tests__/connection-management.integration.test.ts src/__tests__/connection-install-capabilities.test.ts src/__tests__/ai-connections.test.ts src/services/ai-account-identity.test.ts src/__tests__/openapi-routes.test.ts
cd ../ui
pnpm exec vitest run src/api/client.test.ts src/components/ai-connections/ManagedAiConnectionDetails.test.tsx src/components/ai-connections/AiConnectionAccountDetails.test.tsx src/pages/apps/AppDetail.test.tsx
```

## Risks

Descriptive permissions reuse retained facts within one request. A
concurrent change can leave a displayed choice stale; the next request
and every write still authorize fresh. Pools with referenced members
retain their existing cost.

The account and grants clients now bound each caller's wait. A browser
abort does not cancel an authorization read already admitted by the
server. The independent profile request uses a fixed Anthropic origin, a
bounded body, no redirects, and a 15-second deadline. Inference-only
credentials can return no email; that is reported without guessing from
a Paperclip owner or changing connection health. Profiles are fetched
only for the caller's authorized selected grant. No ambient CLI
identity, persistent identity cache, background polling, or
billing-identity change is added. Other API reads keep their existing
behavior. No migration is required. Staging has not been redeployed.

## Model Used

OpenAI `gpt-6.1-sol` through the Codex harness in T3 Code, with xhigh
reasoning, code editing, execution, and test tools. 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 and contains no internal
Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 12:29:03 -08:00
DottaandPaperclip 33fc7fcddc fix(db): clean up owned PostgreSQL test servers (#18627)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Database, server, and CLI tests use real PostgreSQL fixtures.
> - Each fixture must own its server until PostgreSQL has stopped.
> - The old teardown returned after five seconds even when its server
remained alive.
> - A startup failure could then mark the host unsupported and skip
database coverage.
> - This pull request waits for owned shutdown and makes supported-host
startup failures fail collection.
> - A shared-server command reduces process creation while keeping each
fixture's database isolated.

## Linked Issues or Issue Description

Refs: #7756 for related development-process ownership. That
development-server issue remains outside this test-fixture fix.
Related PR: #16799 collects macOS startup diagnostics. This PR changes
test shutdown and failure behavior.

**What happened?**

Repeated test runs can exhaust macOS PostgreSQL semaphore resources. The
fixture abandoned slow shutdown and swallowed stop errors. The support
probe converted ordinary startup failures into skipped integration
coverage.

**Expected behavior**

Tests must stop their PostgreSQL servers, retain files if stop fails,
and report resource exhaustion as a failure. Fixtures on a shared server
must not close another database's clients.

**Steps to reproduce**

Start a fixture whose PostgreSQL stop exceeds five seconds, or make a
supported-host startup fail with semaphore exhaustion. The former helper
returned from teardown or reported unsupported coverage. The new
regression tests exercise both paths without exhausting host resources.

**Paperclip version or commit**

Source checkout based on current master.

**Deployment mode**

Local source development and CI tests.

## What Changed

- Add explicit ownership for test PostgreSQL children. Wait for fast
shutdown, then request immediate PostgreSQL shutdown if needed. Keep
cleanup idempotent and fail when exit cannot be confirmed.
- Publish reusable templates only after clean shutdown. Do not publish a
crashed or immediately stopped cluster.
- Stop owned children on POSIX worker signals and process exit. Preserve
test directories when shutdown fails. Remove conflicting dependency exit
hooks.
- Retry port collisions only. Fail collection for resource exhaustion,
unavailable configured servers, and other startup failures on supported
platforms. Preserve skips for explicitly unsupported platforms.
- Move administrative-server support into the common fixture used by
database, server, and CLI tests. Close clients at database scope and
migrate cloned templates before use.
- Add a directly invoked shared-server runner to own one test server and
run suites against separate disposable databases. Preserve child exit
status and support an existing disposable server.
- Unify cancellation: stop and wait for the test process group before
PostgreSQL teardown. Add nested-process coverage, real worker-exit
coverage, shutdown regressions, shared-database isolation checks, and
setup documentation. Replace ignored heartbeat completion polls with the
existing execution drain before asserting persisted outcomes.
- Finish owned cluster-directory cleanup after signal-driven
cancellation. Preserve prepared templates across shared-fixture tests.
Remove stopped directories asynchronously, using native removal on POSIX
with a Node fallback.
- Align database and CLI fixture hook budgets with the existing
30-second server budget. This lets the ten-second shutdown protocol
finish and report errors. The idle-sleep suite uses the existing
90-second fixture budget for its unusually large final directory
cleanup.

## Verification

- The semaphore-exhaustion regression failed against the old helper
because it resolved to `supported: false` instead of rejecting.
- All 37 focused tests pass on the final runtime code (`e4de00ab40`).
They include real worker exit, SIGTERM, nested-process SIGINT/SIGTERM
cancellation with PostgreSQL available during child cleanup, failed
template shutdown, unsupported platforms, stale SQL templates, and
directory removal. A child exiting with status 7 makes the shared-server
runner return status 7 after cleanup.
- Full local `pnpm -r typecheck` and `pnpm build` pass on the final
runtime code (`e4de00ab40`). Subsequent changes only adjust server-test
lifecycle waits, the idle-sleep cleanup budget, and documentation; the
server typecheck also passes with those final tests.
- A fresh shared-server run on `90b65fd8ad` passed all 68 database files
and 297 tests. Earlier preparation runs had two ten-second teardown
timeouts and a stale-template failure; the final helper migrates cloned
templates and permits the full shutdown budget. These earlier failures
remain accounted for here.
- The local full repository attempt stopped on a Discord receiver-lease
test after 338 passing chat tests. That exact case passed in isolation.
This full-suite attempt is not a pass.
- On `90b65fd8ad`, [server shard
6](https://github.com/paperclipai/paperclip/actions/runs/41496495253/job/125452949369)
and its one unchanged retry reported two 15-second cached-input
heartbeat timeouts and a 30-second idle-sleep teardown timeout. All ten
cached-input cases then passed locally with their original deadlines. A
local parallel run of the full files reported eight behavioral/hook
failures and two suite teardown timeouts (281 tests passed).
- Serial idle-sleep runs passed all 225 test assertions but overran the
30-second final hook. Tracing measured client closure in 4 ms,
PostgreSQL exit after 5 seconds, and synchronous directory removal
taking another 35 seconds. Asynchronous Node removal and native removal
also exceeded that hook under the full workload. Cleanup now remains
asynchronous and awaited, and only this heavy suite's final hook uses
the existing 90-second fixture budget. No PostgreSQL shutdown deadline
or test assertion was weakened. The serial run then passed the complete
idle-sleep file, including all 225 tests and teardown. Its heartbeat
file passed 63/64 cases, exposing an ignored three-second completion
poll. After replacing that poll with an execution drain, another timer
case exposed the same pattern (63/64 passed). All remaining ignored
completion polls now await execution drain without changing test
deadlines. The complete heartbeat file then passed all 64 tests. The
intentional asserted lock-contention poll is unchanged. The final server
typecheck passes, and a process audit found no PostgreSQL server left by
the completed local runs.
- On final head `2cf316d3f571e4516890cba743ecffeb9703cce3`, the
previously failing server shard 6, database lane, full typecheck, and
build passed. The [first CI
attempt](https://github.com/paperclipai/paperclip/actions/runs/41506358136)
then lost self-hosted runners in the canary and serialized-server lanes,
with additional jobs cancelled. The server-2 lane had one 30-second
timeout in the unchanged workspace-recovery HTTP Retry test (2,282 other
tests passed). That exact test passed locally with its original deadline
(28.78 seconds including imports). One unchanged retry of only failed
and cancelled jobs completed successfully on the exact final commit
(workflow attempt 2). The workspace-recovery timeout case and every
interrupted lane passed; successful first-attempt jobs were retained.
The additional Paperclip Review check remains queued, waiting for its
assigned agent; it has no unresolved GitHub review threads. Greptile
completed review on this exact final head at 5/5, with zero unresolved
review threads. All four original review findings and their threads are
resolved; additional Windows shutdown, cancellation-directory, and
template-reuse findings are fixed.
- `pnpm check:module-boundaries` and `git diff --check` passed. Post-run
process checks found no PostgreSQL servers left by the completed
verification runs.

## Risks

- Immediate PostgreSQL shutdown can require crash recovery. This
fallback applies to disposable test clusters and runs only after fast
shutdown times out.
- No process can handle `SIGKILL` or machine power loss. Host resource
cleanup remains a separate backstop.
- Directory cleanup on cancellation applies to the shared-server
runner's own cluster. Directly terminated test workers stop their
PostgreSQL process but retain disposable files for inspection. The
process-exit guard cannot await file removal.
- The two-second `pg_ctl -W` deadline bounds signal dispatch. It is
separate from the five-second and thirty-second server-exit waits. A
control-command failure fails cleanup and retains its directory; it does
not report successful cleanup or force-delete live files.
- Shared fixtures require a disposable PostgreSQL server and a role that
can create databases. The directly invoked shared command is opt-in; the
existing `pnpm test` command remains available.
- These changes do not stop unrelated development servers or delete
host-wide IPC resources. Clean shutdown uses the owned `pg_ctl` binary
on every supported platform. Its real control path was tested on macOS.
A Windows host was not available for live verification; POSIX signal
tests skip on Windows.

## Model Used

- OpenAI Codex, based on GPT-6. The runtime does not expose the exact
serving variant or context-window size. The agent used reasoning, shell
execution, code editing, and GitHub tools.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 14:24:48 -06:00
DottaandPaperclip 53f480d1b3 fix(native): preserve warm continuity and deferred review replies (#18631)
## Thinking Path

> - Paperclip manages AI agents and their saved work.
> - Product E2E tests must check saved personal files across separate
turns.
> - The server records file collection in the durable `instruction_save`
run-log event.
> - The warm test read optional terminal result metadata instead and
rejected a recorded successful save.
> - This pull request reads the complete event stream for the current
run and uses its latest save receipt.
> - The prompt now specifies the exact nine bytes required by the
temporary-file transfer count.
> - Human review actions select the actual interaction card, which can
share its interaction ID with a navigation button.
> - A later real three-turn run exposed a missing reply after workspace
finalization moved to its durable recovery owner.
> - Reply recovery handled completed tasks but omitted ordinary tasks
that awaited review.
> - This pull request also publishes their recorded final reply once
while preserving the pending review.

## Linked Issues or Issue Description

**What happened?**

The [retained live continuity
attempt](https://github.com/paperclipai/paperclip/actions/runs/41477302876/job/125420001074)
saved the correct memory file and unchanged 8 MiB binary. Its durable
run log contained a successful `instruction_save` receipt. The oracle
read `resultJson.instructionSave`, which was absent, and failed before
turn two. The temporary file also had a trailing LF. Its prompt allowed
that result, while the byte-count check required nine bytes.

**Expected behavior**

The oracle must use the documented authoritative save event. A missing
receipt, a later failed save, incorrect transfer counts, or another
run's events must fail. The prompt must specify the bytes that its
independent check requires.

**Steps to reproduce**

1. Run `daytona-warm-continuity.runner-codex.daytona.warm-three-turn`
with the configured protected credentials and immutable image.
2. Complete a native turn whose terminal result has no `instructionSave`
field.
3. Compare the oracle output with the same run's successful
`instruction_save` event.

A subsequent [three-turn
attempt](https://github.com/paperclipai/paperclip/actions/runs/41495337334/job/125451304553)
passed every personal-file assertion and reused the same warm process.
Its first final reply was recorded as a completed agent-message event
but was absent from comments. The log shows
`native_workspace_finalization_busy`; the durable recovery path excluded
`needs_review` replies. The final message matcher correctly failed. This
failure remains recorded.

The observed application revision was
`aab87ce70744660a4a21c77278b0ede267c04720`. Related work: #14695 and
#18494. The retained failed result keeps its original grade and
definition.

## What Changed

- Read all run-event pages through the existing bounded collector.
- Require events to belong to the requested run and select the latest
`instruction_save` event.
- Retain strict byte counts and reject missing, failed, pending or
superseded receipts.
- Specify nine ASCII bytes and no trailing newline for the temporary
file.
- Scope human review actions to the interaction card and its exact
interaction ID.
- Advance the warm suite definition to version 5 and document its
evidence source.
- Recover recorded final replies for ordinary native tasks with an
accepted `needs_review` result and terminal state.
- Preserve pending reviews, existing reply selection,
company/turn/digest checks and external governed-response authorization.
- Update the task feature and agent access maps.

## Verification

- Real PostgreSQL regression: deferred review reply discovery failed
before the production repair (expected one candidate; found zero). The
final-message event and pending review were present.
- Recovery cases cover one publication, no repeated provider run,
unchanged review, and rejection of absent/wrong-turn final messages, bad
digest and suppressed comments.

- Red: seven new boundary regressions failed against the old receipt
lookup.
- Green: 169 focused oracle, event pagination and catalog checks passed.
Product E2E typecheck passed after rebuilding local package
declarations.
- Retained-evidence replay confirms that the new lookup finds the real
successful save event. The original attempt remains failed because its
temporary file included an LF.
- Recursive typecheck passed before the final recovery change; server
typecheck passed afterward. The recovery and control-plane suites passed
all 112 tests. Full build and map checks passed.
- The broad local test run reached one unrelated 30-second timeout in
`attention-retention-work.test.ts` (maintained-review/confirmation
batching). The same unchanged case then passed on one targeted retry
(39.9 seconds including module load). The original failure remains
retained. The broad run also reported one unchanged workspace-conflict
case, which passed on its targeted retry (14.85 seconds including module
load). Both original failures remain retained. The redundant broad local
run was stopped after current-head CI completed all required gates: 55
successful checks and 3 selection skips. No all-green local broad-run
claim is made.
- The separate artifact-transfer cell already passed on the recorded
application revision: independent source and delivered bytes matched at
407,485 bytes, with a completed task, succeeded native run and cleared
execution locks. This does not establish a three-turn continuity pass.

- [Real native three-turn
acceptance](https://github.com/paperclipai/paperclip/actions/runs/41499102994/job/125465795210)
**passed** at `3b207a42943e9eeb371d4f2d5623de72093eb6d5`, suite
definition 5. Turn one exercised `committed_task_response_recovered`.
All three completed final replies were persisted once and in order. All
three strict personal-file receipts passed. The unchanged 8 MiB binary
survived; later transfers copied only 36 and 54 bytes. The lease was
created, resumed, and resumed with the same runner PID/start time,
runner instance, native session and provider session. Final task was
`done`, all three runs succeeded, and checkout/execution locks were
null.
- The aggregate startup summary has no separate provider-process PID
proof. The raw run records independently prove the stable runner process
and provider session stated above. This single native cell does not
qualify the legacy cell or a full provider matrix.
- The passing campaign reused the signed immutable runner image. It
required no disk expansion. Earlier campaign image builds used the
recorded temporary 120 GiB mitigation; default 60 GiB build capacity
remains unqualified. All scoped completed probes were removed and
independently returned 404; org CPU/disk usage returned to zero. This
does not resolve unknown historical resources under a different
credential identity.
- Current-head Greptile is 5/5; review-thread pagination is complete
with zero threads. All 55 current-head checks are successful; 3
selection checks are skipped. The paid campaign, result enforcement and
report publication all completed successfully.

## Risks

- Publishing a reply must not approve the work. Recovery only copies the
accepted turn’s completed final message. It preserves the pending review
and does not start an executor.
- Conversation and external governed-response paths retain their
existing separate authorization.

The latest save event can record failure after an earlier success. The
oracle rejects that case. Event pagination, missing receipts and
cross-run evidence also fail closed. The exact temporary-file byte count
remains required. The review selector still requires the intended
interaction ID and enabled action on its actual card. The production
change is limited to ordinary internal-task reply recovery. It still
requires an accepted result, a matching successful terminal disposition,
the completed final message, and existing publication authority.

## Model Used

OpenAI Codex, based on GPT-6, with shell and code tools. The exact
deployment variant and context-window size are not exposed in this
session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1102.0-canary.5
2026-11-02 14:19:48 -06:00
DottaandPaperclip 0fd82e386e feat(evals): stream completed chat catalog results to TestOps (#18647)
## Thinking Path

> - Paperclip lets people manage AI agents and inspect their work.
> - The chat catalog uses real Product E2E cases and reports their
original grades to TestOps.
> - The current report matrix waits for every selected worker.
> - A large selection can hide completed results for hours.
> - Each case can use the existing private reader and safe exporter
after its own worker ends.
> - This PR gives each case a separate upload and readback job, then
verifies final coverage without another upload.
> - People can inspect completed cases while the rest of the selection
runs.

## Linked Issues or Issue Description

Refs #18542, #18625.

**What existing behavior does this improve?**

The existing chat catalog reports results to TestOps only after all
selected workers finish.

**Current behavior**

One slow case holds back the report and upload jobs for all other cases.

**Proposed behavior**

Each finished case gets its own protected reader, safe projection,
upload and backend verification. The final job checks the whole
selection through read-only requests. It does not upload results again.

**Reason and benefit**

A person can inspect a completed grade and its safe evidence receipts
while other cases run. This changes future runs. It does not change an
in-flight run.

## What Changed

- Add one same-commit reusable workflow with separate worker,
private-reader and TestOps-upload jobs. Each job uses only its own
protected environment. Callers pass empty named secret placeholders and
do not inherit secrets.
- Reuse the original exporter and grade checks. Freeze each case's three
Allure JSON files once. Allow known sibling results during per-case
readback. Keep final exact selection coverage.
- Submit each bundle at most once. Reconcile uncertain responses by
readback. Retain only closed publication, failure and upload-intent
receipts. A rerun attempt still fails the existing attempt-one admission
guard.
- Preserve failed original grades, failed cleanup and missing evidence.
No missing original can become a passing result.
- Keep external-input cases in the serial lane. Small native-only
selections allow two cases at once. Small mixed selections allow one
native and one external case. Larger selections retain eight native
cases and one external case.
- Add source, privacy and failure controls to the existing unit roster.
Document the reporting flow and runner-group admission requirement.
- Fix an existing corruption-test fixture that could write the same byte
back to a random IV. Read and flip one bit instead. Keep the storage
rejection and unpublished-plaintext assertions unchanged.

## Verification

- 152 focused Node controls pass across the shared client, API,
selection, CLI and streaming tests. The retained parent controls show
the missing multipart and partial-readback behavior, plus the small
external-selection error before its fix.
- The focused workflow security control passes. Actionlint passes for
both workflows. Changed JavaScript files pass syntax checks. Git diff
checks pass.
- Local controls use synthetic data and mocked HTTP. They make no
provider call and do not start an app, database or native build.
- Previous head `b51406df` passed PR CI (48 jobs pass and one is
skipped). The review-driven test-only successor `0c65cc21` then failed
one unchanged snapshot-storage corruption test, plus the final CI
summary. The latest head includes its narrow fixture repair. Its first
CI attempt separately hit runner shutdown/lost-communication failures,
two setup/timeouts and a heartbeat-cancel cleanup HTTP 500/lock timeout;
those observations are retained without claiming their underlying cause.
One same-head failed-and-cancelled-only recovery now passes at
`bf9c3e8f`: 48 jobs pass and one is skipped, including required `ci /
verify` and `ci / e2e`. All 31 already-passing jobs retained their
original execution records; all 15 recovered leaves and both dependent
summaries passed. The first attempt remains recorded; the recovery does
not establish the underlying causes of those failures. A small AWS run
after delivery must prove that one case and both attachments are visible
before another original case ends. That live proof is pending; local
controls do not prove vendor ingestion or environment-secret resolution.
- Retained earlier fixture-calibration failures remain recorded. The
final integrated Node control run is green. A deterministic Node
crypto/filesystem control also reproduces the no-op corruption mutation
with a valid IV byte equal to `X`, then passes after flipping that byte.
This control uses no app or database. The failing CI byte was not
captured, so the exact historical byte remains unknown.

## Risks

- The called workflow needs its exact master ref in the existing
selected-workflow runner group. No IAM role change is needed.
- Environment-only secrets must resolve in the called jobs. The caller
passes no actual model or reporting key. The small live proof must
confirm this behavior.
- TestOps does not document an idempotency key for this upload route. An
uncertain write is never resent automatically. If readback cannot verify
it, the workflow fails with retained closed receipts.
- The existing job run can already be marked finished by the selection
watch. The live proof must record its actual stage and prove subsequent
uploads are accepted. This PR does not reopen, stop or close that job
run.
- Backend ingestion does not prove that an already-open TestOps page
refreshes automatically.
- The corruption-test repair changes no production storage or
cryptography. New-head AWS CI must qualify the existing database-backed
owner test.
- Each case adds short protected reader and upload jobs. The app source,
original case clocks, graders, model, budgets, raw-evidence privacy
boundary and zero eval retries stay unchanged. The versioned stream
concurrency group serializes new streaming runs; an old immutable batch
run can continue in its original group.

## Model Used

OpenAI `gpt-6.1-sol`, with tool use and code execution. The session does
not expose a context-window size. Independent source peers used the same
model family.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 14:18:00 -06:00
DottaandPaperclip 946735d03a Persist task sorting in URLs and show newest routine tasks first
Save task sort choices in URLs across task views. Open routine tasks by creation time, newest first, with stable sorting before pagination.

Co-Authored-By: Paperclip <Paperclip-Paperclip@users.noreply.github.com>
2026-11-02 13:32:40 -06:00
DottaandPaperclip 1f8f2e195f perf(ui): reuse parent metadata when loading the inbox (#18645)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - The Mine inbox combines task rows with approval and failure items.
> - It waits for parent captions before it reveals the initial list.
> - It fetched rich diagnostics for every parent, including parents
already in the task index.
> - Parent captions only use fields that the index already provides.
> - This change reuses loaded parents and fetches missing parent
metadata through the index view.
> - Failure items keep their rich interruption data and the initial
reveal boundary stays in place.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The initial load of Mine and other inbox views that need parent task
captions.

**Subsystem affected**

`ui/` collection reads. The API contract and database schema stay the
same.

**Current behavior**

The inbox fetches all parent and failed-run task IDs with `view=rows`
after the primary task request. This adds active-run, blocker, review,
interruption and recovery work to the reveal path. The observed hosted
case fetched four parents. One was already in the 31-row task index. The
other three were completed parents. The serial context response took
1.0–2.9 seconds during the diagnostic reloads.

**Proposed behavior**

Reuse parents from the selected source index. Fetch missing parents with
`view=index`. Keep `view=rows` for every failed-run task, including
overlaps with parents or source rows. Keep both role-specific ID lists
in the query key. Drop old placeholder rows when the new index supplies
a parent.

**Reason and benefit**

This removes unnecessary diagnostic work from a required serial request.
Five alternating same-four-parent requests on the hosted app had index
times of 189, 162, 156, 128 and 169 ms, versus rich-row times of 282,
211, 329, 219 and 284 ms. All requests missed the response cache. All
consumed parent fields matched. This isolates the projection cost; it is
not a deployed UI speedup claim.

**Breaking changes**

None. Membership, ordering, nesting, archive state, authorization and
failure presentation retain their owners and contracts. Refs: #18323 and
#18492 for the prior collection and startup work. This change addresses
the remaining parent-context read.

## What Changed

- Partition missing parent metadata from failed-run context. Load the
two batches concurrently, with at most two batch requests in flight.
- Keep richer failure rows last in the context result. Filter
placeholders by company and current requested IDs. Track completed
failure reads, including missing tasks, so a parent placeholder cannot
reveal an unverified failure card. Keep existing verified cards mounted
through refresh.
- Cover delayed captions, reuse of indexed parents, refreshed parent
captions, failure overlaps, resolved failures and parent-to-failure
cache transitions.
- Add a real browser check for delayed parent metadata and stable
geometry through deferred diagnostics. Give the test its own disposable
company.
- Add a reusable local timing harness and update the collection
verification recipe.

## Verification

- Baseline source: `0710c5684243a663c09ff907011ab88838173a02`. Final
measured candidate: `c8c69b5af11966b4144707a3da21e840c73c6cca`.
Production UI assets were built from the same checkout and dependencies,
with only the Inbox module changed between variants.
- Targeted regression failed on the old implementation and passed after
the change. All 58 Inbox component tests pass, including existing
archive/undo and order checks.
- Full workspace typecheck passes. The final UI typecheck passes. Full
build passes. Token gates, map checks and diff whitespace checks pass.
- All 12 collection browser checks pass, including pagination and
reading-position restoration.
- The full CI workflow passes on
`c8c69b5af11966b4144707a3da21e840c73c6cca`, including all server, chat,
workspace, serialized, runner and E2E shards. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/41502803275).
Greptile reports 5/5 on this commit with no unresolved threads. The
separate Paperclip Review check is still queued. Its first attempt saved
a text result but did not complete the GitHub assessment. Normal retry
was rejected because that attempt already recorded a result. The
current-head review request is queued. The review service is now
unavailable, so this external gate remains open.
- The duplicate local `pnpm test:run` was interrupted after the
equivalent CI run passed. Its six chat shards passed 1,828 tests. The
general-server phase was stopped. This local full-suite run is
incomplete, not a passing result.
- Local synthetic fixture: four parents and 30 children, with three
completed parents archived. The fixture also has 30 archived child
records. No agent or provider calls ran. Mac arm64, Node 24.22.2,
Chromium, production assets, 1440×900, native CPU, loopback network,
fresh HTTP/query caches for each cold sample.
- Five alternating local pairs produced identical 31-row membership and
order and no browser errors:

| Journey | Baseline median (range), ms | Candidate median (range), ms |
Median paired saving, ms |
| --- | --- | --- | --- |
| Cold first usable Mine rows | 310 (252–435) | 258 (250–261) | 50 |
| Warm Recent → Mine | 60 (56–64) | 67 (61–71) | -7 |
| Task → Back to Mine | 42 (40–47) | 43 (40–45) | 0 |

The final cold result has a material control limitation. The median
primary-request start was 259 ms for baseline and 210 ms for candidate.
Much of the cold difference occurs before the changed request. The
parent response medians were 19.3 and 13.5 ms, with fewer parent IDs
requested. Do not attribute the full 52 ms difference between cold
medians to this fix. Four cold pairs were faster and one was 6 ms
slower. Warm Recent → Mine was about 7 ms slower at the median; Back was
unchanged. These runs establish no warm-navigation gain. The earlier
five-pair experiment showed the same startup confound and mixed
warm/Back results. All samples remain in the local evidence. A hosted
final-shape comparison timed out and was cancelled by closing its owned
browser tab; it supplies no result. The candidate has not been deployed.

Reproduce the contract and geometry check against an isolated production
UI with `pnpm exec playwright test --config
tests/perf/collections/playwright.config.ts parent-context.spec.ts`. Run
`tests/perf/collections/measure-mine-context.ts` against baseline and
candidate loopback production origins that share one disposable API, as
documented in `tests/perf/collections/README.md`. Preserve upstream
startup timings as controls. Required parent responses remain inside the
reveal boundary.

## Risks

- Explicit-ID `index` and `rows` requests use the same company,
visibility and actor filters. They do not use the inbox archive filter.
An archived parent is still returned by either projection. A deleted or
unreadable parent is absent in both. A second index request for a
failure-parent overlap would not restore missing caption data.
- A failed-run task must never reuse parent-only metadata. The query key
includes each projection role. Completed reads carry explicit failure-ID
coverage. The tests cover overlaps, pending role changes, late heartbeat
data, known absence, and transitions to empty views.
- Old parent context must not override a fresh indexed parent. The
current-ID placeholder filter and caption-refresh regression cover this
case.
- The hosted app still has unrelated server contention. This PR reduces
parent request work. It does not claim to fix all hosted loading delay.
Deployment acceptance should confirm the serving revision, compare
matched Mine reloads and inspect errors and row stability. Revert this
change if failure items or captions regress.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, browser
diagnostics and code execution. The exact runtime model identifier and
context-window size are not exposed by this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 13:29:04 -06:00
DottaandPaperclip 5a07c30c1a fix(workspaces): reduce temporary disk use during remote capture (#18644)
## Thinking Path

> - Paperclip manages AI agents and preserves their completed work.
> - Native remote finalization must save workspace files before it
releases the writer.
> - Portable capture copied the working tree and Git history, repacked
the history, and then wrote an archive.
> - These temporary copies can exhaust a small sandbox after normal
development work.
> - A completed provider turn then fails finalization and file
preservation repeats the same failure.
> - This change streams checked working files and keeps only an
independent Git copy in scratch.
> - The save still rejects changed sources and incomplete output.

## Linked Issues or Issue Description

Related: #18403 added portable remote workspace storage. #18172 handles
disk pressure in Daytona directory transfer. This failure occurs
earlier, while the portable archive helper creates its source archive.
That earlier repair does not cover this path.

**What happened?**
A completed native run failed workspace finalization three times. Its
file-preservation retries also failed. In a retained 10 GB Linux sandbox
with about 1.5 GB free, the deployed helper failed during `git repack -a
-d` with `Out of diskspace`. The working files used about 603 MB, and
Git used about 444 MiB.

**Expected behavior**
Capture a coherent workspace when free space can hold one full archive
plus an independent Git copy. Preserve working files, staged changes,
unpushed commits, and existing recovery gates.

**Steps to reproduce**
1. Use a disposable Linux sandbox with a Git repository and generated
working files.
2. Leave enough free space for an archive and a Git copy, but not a
second working tree and another repack.
3. Run the portable capture helper. The old helper fails while creating
temporary data.
4. Run the fixed helper against the same source and free-space limit.
Verify each archived file hash.

The small regression uses real file serialization and a controlled
filesystem capacity failure at archive creation. It failed with `ENOSPC`
before the production edit and passes afterward.

**Paperclip version or commit**
The observed staging server served
`42c64d4ec4b9b0898556fcdf6ba304c4285a7819`. The repair is based on
`a92f616cd0`.

**Deployment mode**
Hosted staging. Linux x64, Node 25.9.0, Daytona sandbox. Local tests use
a macOS source checkout.

## What Changed

- Stream working files from checked file handles. Keep only normalized
Git metadata in scratch.
- Remove the second repack after a mirror clone that already uses
`--dissociate` and `--no-hardlinks`.
- Check each streamed file's hash, size, mode, and filesystem identity.
Recheck the source inventory and Git state before returning a receipt.
- Remove incomplete archives after failure or cancellation. Keep
pre-existing archive files intact.
- Add space-limit, concurrent-change, cancellation, and existing-file
safety cases. Update execution semantics and workspace verification
recipes.

## Verification

- Red before the production change: the capacity regression failed with
`ENOSPC`. Green afterward: 54 archive and transport tests pass.
- The existing tests restore ordinary, linked, and borrowed Git
repositories after their sources disappear. They retain staged,
unstaged, and unpushed work. Credential and path guards also pass.
- Live comparison on the same retained sandbox: the deployed helper
failed after 19.4 seconds with Git disk exhaustion. The fixed helper
completed in 35.3 seconds. It produced a 1,081,872,803-byte archive with
24,111 entries. An independent reader checked every archived file hash
and the manifest digest. The source commit stayed unchanged. Diagnostic
scratch was removed.
- This live probe exercised the changed capture boundary. It did not
deploy a server, upload a production snapshot, finalize the failed run,
or replay its provider turn. Full task recovery still needs rollout and
the normal export recovery path.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- Current-head CI passes: [PR
workflow](https://github.com/paperclipai/paperclip/actions/runs/41499985180),
commit `d42700f7f4b0bef14a5969a44c2da0b2513e0ed2`. Greptile rates the
same head 5/5 with no actionable findings or unresolved threads.
- The independent Ponytail advisory also rates this exact head 5/5 with
no findings. Its structured check remains queued because the automatic
request was bound to the earlier head. A [fresh current-head review
request](https://github.com/paperclipai/paperclip/pull/18644#issuecomment-6585296011)
was accepted and queued. Its predecessor has a successful workspace
export but remains active in finalization, so the new review cannot
start yet. This review-service publication gate must complete before
claiming every check is green.
- `pnpm -r typecheck` and `pnpm build` pass. The final server-only
typecheck also passes after the test additions.
- Supported-runtime verification on Node 24.11.0: all 54
archive/transport tests and all 46 existing workspace lifecycle tests
pass. The lifecycle suite uses a disposable real Postgres database and
local filesystem transport with encrypted snapshot storage. It checks
save/restore after losing the original allocation, ownership, retention,
and file continuity. This is separate from the live Daytona capture
probe.
- The first extra lifecycle attempt could not start its local Postgres
binary because the installed Darwin package lacked library aliases.
Local dependency setup was repaired before the passing run. No
production or repository code changed for that setup.
- The full local `pnpm test:run` on the host default Node 26.4.0 stops
in chat-test collection with `No test found ... in lines ...`; it has no
suite verdict. A clean retry repeats the failure. The unchanged
`a92f616cd0` test wrapper reproduces it with the same installed
dependencies, after correcting an initial baseline setup that lacked
built package entries. This is a local test-runner limitation, not a
full local pass. Current-head CI remains the full-suite gate.
- One focused run timed out while deeply comparing 4 MB buffers under
concurrent build load. Complete SHA-256 comparisons retain the content
check without that assertion cost. The capacity case then passes in
under one second, and the final 54-test run passes. The disk allowance
and production code did not change.

## Risks

- Streaming reads the live source instead of a copied working tree. File
identity, content hashes, mode checks, the final inventory read, and Git
signatures must reject concurrent changes. Regression tests exercise
these checks.
- Capture still needs space for the full archive and normalized Git
metadata together. It cannot export from a completely full disk.
- Archive framing and restore validation stay compatible. The change has
no database migration or new execution authority.
- The incident remains unrecovered until the fixed server performs
normal workspace finalization. No deployment or merge is included in
this PR.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
editing, shell tools, browser diagnostics, and automated tests. The
exact serving variant and context-window size are not exposed in this
session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1102.0-canary.4
2026-11-02 13:22:23 -06:00
DottaandPaperclip 026fd9e345 fix(server): keep controller identity independent of Git probes (#18649)
Read the existing boot timestamp without synchronous Git diagnostics. Keep the voice-retention precision test clock fixed.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-11-02 13:11:41 -06:00