Commit Graph
6200 Commits
Author SHA1 Message Date
DottaandPaperclip 86b365f992 feat(auth): add independent agent configuration read permission (#18766)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents need to inspect configuration and instructions when they set
up teammates.
> - Configuration reads currently depend on configure or suggestion
grants.
> - Legacy standard agents did not receive those newer grants. Some
self-read routes also lose the target agent identity.
> - This pull request adds an independent read grant and applies only
that grant to eligible existing agents.
> - The benefit is that agents can inspect and verify configuration
without new write authority.

## Linked Issues or Issue Description

Refs #15283. Related earlier proposals: #8064 and #12050. Those
proposals target older authorization code; this change uses the current
configure/suggest model and adds a read-only rollout for existing
agents. Related bounded peer metadata proposal: #14160.

**What existing behavior does this improve?**

Agent configuration, configured skill, instruction, and revision reads
through the existing APIs and native instruction tools.

**Current behavior**

An agent needs `agents:configure` or `agents:suggest-changes` to inspect
a peer. Older standard agents can hire a teammate but cannot verify the
saved instructions. Configuration and revision routes also reject
self-reads because they authorize a company resource instead of the
target agent.

**Proposed behavior**

Add `agents:read` for redacted configuration and instruction reads. Keep
`agents:configure` as read/write and preserve suggestion-grant
compatibility. Standard new agents receive the read grant. A one-time
migration grants only reads to eligible existing standard agents.
Individual routes authorize the target agent and grant scope.

**Reason and benefit**

Read access can be granted without configuration changes, rollback, or
environment probes. Legacy agents can verify teammates without receiving
new write permissions.

## What Changed

- Add `agents:read` to the shared permission contract and standard-agent
defaults.
- Accept read, configure, or suggestion grants for configuration reads,
with target scope and the responsible-user ceiling.
- Fix target-aware self and scoped configuration, skill, and revision
reads.
- Add an audited data migration. Skip low-trust, built-in, inactive,
pending, terminated, setup, and scoped configuration/suggestion cases.
Preserve existing read scopes and later revocation.
- Update the specifications, default-permission documentation, and agent
access map.

## Verification

- Focused acceptance: 276 tests passed across seven suites on commit
`a37314df88`: authorization, real-key HTTP access, route authorization,
canonical instructions, default grants, migration replay, and lifecycle
configuration.
- The HTTP journey uses a real hashed agent API key and a disposable
PostgreSQL database. It verifies redaction, scoped reads, denied edits
and rollback, cross-company isolation, and both agent and
responsible-user revocation.
- New read-grant regressions failed before the authorization change. A
realistic paused/pausing/resuming migration fixture also failed before
the lifecycle filter correction and passed afterward. Setup-held paused
agents stay excluded.
- `pnpm -r typecheck` and `pnpm build` passed on the rebased branch; the
final lifecycle migration correction also passed the database package
typecheck and build. The latest commit changes only a test assertion.
- `pnpm --filter @paperclipai/db check:migrations`, `node
scripts/check-maps.mjs`, and `git diff --check` passed.
- Full current-head [CI
run](https://github.com/paperclipai/paperclip/actions/runs/41641531426)
passed: typecheck, build, all general and serialized test lanes, Runner
checks, all eight browser shards, canary dry run, policy, and aggregate
gates. The local full-suite attempt was stopped after exposing the
outdated cross-company 403 assertion; interrupted local full-suite
attempts are not counted as passes.

## Risks

The migration deliberately expands redacted configuration and
instruction visibility for eligible existing standard agents in the same
company. An absent older write grant does not deny the new read
capability. It adds no write grant. Scoped configure/suggestion grants
and all existing read-grant scopes stay intact. Administrators can
remove the independent read grant after the one-time rollout; ordinary
updates and startup do not restore it. Configure and suggestion grants
still imply reads within their own scopes. Cross-company
configuration/history reads now return 404 through the common
target-aware helper. No schema change or credential-value disclosure is
added.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-03 07:26:27 -06:00
DottaandPaperclip 44a9a043b8 fix(ui): make the full chat agent selector clickable (#18708)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Chat gives each person a standing conversation with an agent.
> - The Coordinator chat header shows an agent avatar, name, and caret.
> - Only the caret opened the agent picker. The avatar and name were
separate text.
> - This pull request puts all three parts in one button that opens the
existing picker.
> - The benefit is a larger click target with one keyboard focus stop.

## Linked Issues or Issue Description

**What happened?**

In Coordinator Chat, the caret opened the agent picker. The agent avatar
and name did not open it.

**Expected behavior**

The avatar, name, and caret must form one control. Each part must open
the same picker.

**Steps to reproduce**

1. Enable the personal Coordinator workspace and open an agent chat.
2. Click the agent avatar or name in the header.
3. Compare the result with a click on the caret.

## What Changed

- Put the avatar, name, and caret inside one button in
`CoordinatorAgentSwitcher`. Keep its current-page marker for screen
readers.
- Add an optional trigger to `AgentChatPicker`. The shared dialog
handles keyboard access and focus return.
- Add an optional breadcrumb control slot. The chat owns its button,
while the text label still sets the document title.
- Add regression cases for both header layouts on desktop and mobile.
Check all three click areas, Escape, focus return, and selection of
another agent.
- Add a Coordinator chat Storybook case with production components and
fixture API data. Update the feature recipe.

## Verification

- Passed 235 focused tests for `BreadcrumbBar`, `AgentChatPicker`,
`BreadcrumbContext`, and `IssueDetail`. The header cases also check the
current-page marker.
- Passed UI typecheck and UI production build.
- Passed token gates, map checks, and Storybook catalog checks. All 30
map and catalog regression tests passed.
- The new header cases failed before the change and passed after it.
- Full local typecheck could not finish because this workspace has no
`cargo` command.
- Full local build and the first UI typecheck attempt reached the 8 GB
workspace memory limit. The separate UI build and typecheck passed. The
full local test run was stopped to free memory for browser verification;
it has no complete verdict.
- Passed 18 browser checks in Chromium across desktop light, mobile
light, and desktop dark. Each case checks avatar/name/caret clicks,
Enter, Space, Escape/focus return, and selection of QAChecker. No page
render errors occurred.
- Captured six screenshots of the header and picker across these
viewports and themes. Review images remain outside the repository.
- Browser review first found stale fixture responses for recent
comments, decision receipts, chat handoffs, and ordinary-task email
state. Correct API response shapes removed those fixture render failures
before the successful review.

## Risks

- Low risk. The shared breadcrumb renderer has a new optional control
slot. Callers that omit it retain their existing rendering.
- Chat selection uses the existing picker and route. No database or API
contract changes are required.
- The Storybook API is simulated. It does not prove provider execution
or server persistence.

## Model Used

OpenAI Codex, GPT-6. The runtime did not expose the exact deployed model
ID or context window. The agent used code editing, terminal checks, and
browser automation.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` 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-03 07:20:20 -06:00
DottaandPaperclip a61cf38106 docs: keep the feature map focused on substantial features (#18767)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The feature map describes product capabilities and user journeys.
> - Small fixes and test changes have added long notes to that map.
> - These notes make substantial features harder to find.
> - This pull request removes those additions from the last week's
changes and sets a clear rule for future additions.
> - The benefit is a smaller map with stable capability IDs and accurate
entry points.

## Linked Issues or Issue Description

**Issue type**

Unclear or confusing documentation.

**Where is the issue?**

`maps/feature-map/`, the map maintenance instructions, and repository
rules.

**What's wrong?**

Between October 27 and November 3, 2026, 115 commits changed the feature
map. Many additions describe bug fixes, performance details, small UI
changes, or new tests. They do not introduce substantial product
features. The old synchronization instructions also encouraged a map
edit for every behavior change.

**Suggested fix**

Add a rule that requires a substantial new feature before expanding the
map. Remove minor-update notes. Keep genuine feature additions and
minimal corrections to existing instructions. The review covers master
through `b22ef22d56`; it does not revert application code. Conflict
resolution preserves later map changes from master outside that audit
snapshot.

Searched open GitHub PRs and issues for related feature-map work. No
duplicate cleanup was found. Substantial feature additions retained here
include Coordinator (#17983), the agent YAML editor (#18036), document
image galleries (#18157), remote workspace storage (#18403), native Kimi
(#18391), proactive chat messages (#18374), and the Sentry receiver
added in #18714.

## What Changed

- Add `rules/feature-map-scope.mdc` and register its `maps/**` scope
with Greptile.
- Align `AGENTS.md` and the shared map contract with that rule. Routine
fixes and test changes no longer require incidental map edits.
- Remove 755 net lines from 23 feature recipes. Preserve all 35 areas
and 192 capability IDs.
- Keep substantial features and the corrections needed for current
navigation, provider availability, and access boundaries.

Examples from the reviewed changes:

| Removed or shortened addition | Why it does not need a feature-map
expansion |
| --- | --- |
| Rounded composer image thumbnails (#18689) | Small UI change within
existing task creation. |
| Connection profile reads and review-count queries (#18687, #18688) |
Performance details within existing app permissions. |
| Warm-session, Retry, export-capacity, and tool-wait cases | Regression
details for existing execution and recovery. |
| New task-search, project-context, document-persistence, and routine
test journeys | Test additions for existing capabilities. The tests
remain in place. |
| New task button placement (#18703) | Another entry to an existing task
form. |
| Local browser verification notes | Run evidence belongs in the PR or
test report. |

## Verification

- `node scripts/check-maps.mjs` passes: 35 areas, 192 capability IDs,
valid references and contract fields.
- `node scripts/storybook-catalog.mjs` passes: 328 files and 3,068
stories. Generated indexes remain ignored.
- Compared capability keys and navigation metadata in every edited
recipe with the original source. All are unchanged.
- Checked rule frontmatter, Greptile registration, representative scope
matches, and `git diff --check`.
- `pnpm -r typecheck` and `pnpm build` pass on
`9a60eef8eb8da9bc7c3a02203c79bec12e8c8b6b`. The final
`a0801e8a939494ecde3739097a80258917428e94` commit only corrects two
lines in the plugin-panel recipe; map and catalog checks pass again.
- Greptile reviewed the final `a0801e8a939494ecde3739097a80258917428e94`
head at 5/5 with no findings. The earlier review found one inaccurate
phrase about unavailable plugin panels. The hook confirms that readiness
gates automatic opening, while declared panels remain selectable. The
final documentation commit corrects that phrase and the thread is
resolved. Paperclip's refreshed review is advisory and remains queued.
- The earlier CI run failed two assertions: [server
4/12](https://github.com/paperclipai/paperclip/actions/runs/41634761842/job/125914173960)
counted three Anthropic identity calls instead of two in
`connection-management.integration.test.ts`; [chat
1/3](https://github.com/paperclipai/paperclip/actions/runs/41634761842/job/125914174257)
observed zero publications instead of one in the same-principal
endpoint-settlement case. Both exact tests pass locally on the rebased
head. This PR changes neither their source nor their expectations. These
failed results remain historical evidence.
- Final-head CI passed server 4/12 and all other suites except the first
[chat 1/3
attempt](https://github.com/paperclipai/paperclip/actions/runs/41637834618/job/125925926131),
which repeated the same zero-publication assertion. The browser gate
passed. The single failed-job retry was accepted for this unchanged head
in [workflow attempt
2](https://github.com/paperclipai/paperclip/actions/runs/41637834618/attempts/2).
[Chat 1/3 passed on that
retry](https://github.com/paperclipai/paperclip/actions/runs/41637834618/job/125933199635),
and the aggregate verification gate passed. Both required gates, `ci /
verify` and `ci / e2e`, are green on
`a0801e8a939494ecde3739097a80258917428e94`. The one retry allowance is
consumed.
- The first full local `pnpm test:run` attempt was interrupted before
completion so master could be rebased without changing source under
running tests. It is not a passing test result. Full current-head CI
remains required.
- No application code, tests, schemas, or lockfiles changed.

## Risks

- Low runtime risk. This change only edits documentation and review
guidance.
- Detailed regression instructions become less visible in the feature
map. Their tests and technical documentation remain available.
- Some additions mix a new feature with a small fix. Those blocks retain
the feature and shorten the incidental detail.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass — map, catalog,
capability-ID, and rule-scope checks; full Vitest limits are stated
above
- [x] I have added or updated tests where applicable — no new runtime
tests apply to this documentation 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-03 07:16:37 -06:00
17e8bd7735 fix(runner): save native checkpoints when the sandbox disk is full (#18705)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Native runs on a remote sandbox save two things after each turn: the
provider checkpoint and the workspace export
> - An agent can fill the sandbox disk during its own work, for example
with a package install
> - The turn still finishes, but both saves need free sandbox disk, so
they fail and the task becomes blocked with no clear reason
> - This pull request makes the checkpoint work on a full disk and makes
a full disk visible in the export failure
> - The benefit is fewer stranded checkpoints, and an operator sees at
once why an export failed

## Linked Issues or Issue Description

Related: #18715 added the shared-principal response-recovery control
synchronized below. #18644 reduced the scratch disk that the workspace
capture uses. #18172 added the disk-free streaming fallback to the
Daytona directory sync-out. Both were deployed when this failure
occurred. Neither changes the checkpoint copy, and neither can help when
the disk has no free space.

**What happened?**

A native agent ran a package install for a large monorepo in a 10 GB
Daytona sandbox. `df` in the run showed `10G 10G 4.6M 100%`. The agent
committed its work and reported `done`. Then:

1. The provider checkpoint made a filtered copy of the provider
directory inside the sandbox (`tar -cf archive; tar -xf archive -C
snapshot`) to apply its exclusions. On the full disk, tar failed. The
run recorded `runner_remote_checkpoint_snapshot_failed` without the
reason, and the partial copy stayed on the disk.
2. Workspace finalization failed three times, and file preservation
failed six times. The capture builds its archive inside the sandbox, so
each attempt failed. Every failure was recorded as
`remote_workspace_operation_failed` / `export_interrupted`, so nothing
named the full disk.
3. The task went to `blocked`. The only copy of the commit was in the
retained sandbox.

**Expected behavior**

The checkpoint does not need free sandbox disk when the provider can
stream. A workspace export that cannot fit says that the sandbox disk is
full.

**Steps to reproduce**

1. Run a native agent with a provider whose checkpoint has exclusions
(for example ACPX) in a small remote sandbox.
2. In the turn, fill the sandbox disk (for example `pnpm install` of a
large repository, or `fallocate` of the free space) and finish the task.
3. The checkpoint fails with `runner_remote_checkpoint_snapshot_failed`,
and every workspace export attempt fails with a generic code.

**Paperclip version or commit**

Observed on `410b0e27015`. This change is based on `5955dd4eb4c`.

## What Changed

- Synchronize the shared-principal response-recovery regression with its
saved comments and empty final deadline. Cover an in-flight discovery
invalidation. Keep every authority lock, exact publication, error, and
no-retry assertion. This changes test synchronization only.

- `syncRemoteRunnerDirectoryOut`: when the in-sandbox checkpoint copy
fails with a full-disk tar diagnostic, remove the partial copy and pass
the exclusions to the provider sync-out (`exclude` on the directory
mapping). The Daytona sync-out streams the directory without sandbox
disk when it cannot write its archive. Other copy failures and timeouts
still throw `runner_remote_checkpoint_snapshot_failed`. They now also
remove the partial copy.
- `remote-workspace-transport.ts`: the helper install and the capture
scripts report `remote_workspace_sandbox_disk_full: ...` when Node
reports `ENOSPC` or `EDQUOT`, or a Git or tar child reports "No space
left on device". `command()` passes only that exact message through,
like the existing unfinished-Git-operation message.
- `native-workspace-finalizer.ts`: a remote save that fails with that
message adds it to the failed operation's stderr. The failure code, the
retry budget, and the recovery flow do not change.

## Verification

- Current-head infrastructure interruption: the [Build
job](https://github.com/paperclipai/paperclip/actions/runs/41637668555/job/125923826158)
completed the actual build and production bundle boot, then the runner
received a shutdown signal during the clean public Grok npm-install
check. GitHub marked that step cancelled. The exact host-stop cause was
not retained. One bounded rerun of only the failed Build and dependent
`ci / verify` jobs passed on the unchanged head. [Build attempt
2](https://github.com/paperclipai/paperclip/actions/runs/41637668555/job/125931400745)
completed successfully, including the clean Grok npm-install check. No
product code, assertion or workflow changed for this interruption.

- CI failure retained: commit `6c5937fcae` failed [chat shard
1/3](https://github.com/paperclipai/paperclip/actions/runs/41634638570/job/125913957217)
because the shared-principal fixture saw zero saved comments after
`worker.ready` and zero active work. The other chat child passed. The
exact case passed once locally and then 30 times on the same Node
24.22.2 version as CI; those passes alone do not explain the CI
interleaving.
- Controlled RED/GREEN: invalidate the real database discovery once
while its read is in flight. The worker correctly retains a future
reconstruction deadline, but the old initial-pass/active-count barrier
reproduces the same zero-versus-one comment assertion. Waiting for both
saved comments and final `active=0`/`nextWakeAt=null` passes. Six
real-PostgreSQL controls pass on final commit `a60e5629e8`, including
endpoint independence, source revocation, and external lock
failure/recovery. No sleep, timeout increase, weakened assertion, or
product scheduling/authorization change was added.
- A local server typecheck first lacked the checkout's built Runner
declarations. After the declared Runner TypeScript build, the server
typecheck passes on `a60e5629e8`. Final-head remote verification is
complete: 54 successful checks, 3 expected skips, no failures or pending
checks, and successful `ci / verify` and `ci / e2e` aggregates. Greptile
is 5/5 on this exact commit with no unresolved review threads.

- Merge preparation: rebased onto master `b22ef22d56` and kept both
test-import additions. Added the checkpoint fallback and
capacity-failure contract to `doc/execution-semantics.md`. On rebased
commit `6c5937fcae`, 47 focused checkpoint, transport, finalization and
retained warm-projection tests passed across three files. The name
filter skipped 1,040 unrelated cases. Map and whitespace checks passed.
The final-head CI and Greptile results are recorded above.

- `npx vitest run
server/src/services/native-runtime/native-session-executor.test.ts
server/src/services/native-runtime/native-workspace-finalizer.test.ts
server/src/services/remote-workspace-snapshot-archive.test.ts` passes
(1,152 tests).
- `npx vitest run server/src/services/remote-workspace-transport.test.ts
server/src/services/native-runtime/native-workspace-finalizer-failure.test.ts`
passes (30 tests).
- New tests:
- Checkpoint, with real files: a full-disk snapshot leaves a partial
copy. The provider then gets the exclusions, the session files are kept,
the package caches are left out, and the partial copy is removed.
- Checkpoint: a permission failure and a timeout still fail, remove the
partial copy, and do not call the sync-out.
- Transport: the real capture scripts run with an `ENOSPC` preload, for
the helper install and for the archive write. Both report the full-disk
message and leave no partial attempt. A message with extra text still
collapses to `remote_workspace_operation_failed`.
- Finalizer: the operation stderr names the full disk and keeps
`workspace_sync_out_failed`. Other failures keep the bare code.
- With the source change removed, the 3 checkpoint cases and the 2
transport ENOSPC cases fail.
- `npx tsc --noEmit -p server/tsconfig.json` is clean.
- Suites that refer to the changed error codes
(`explicit-native-continuation`, `native-recovery-notice-work`,
`native-run-finalizer-telemetry`, `native-workspace-export-retry`,
`remote-workspaces.integration`) pass. In `chat-channels.integration`, 2
cases fail locally on unmodified `master` too (a bundled skill path
outside the checkout, and a chat run timing assertion). They are not
related to this change.
- Manual recovery of the observed task: the retained sandbox was resumed
with free space, file preservation was requested again, and the saved
workspace contained the agent's commit.

## Risks

- The fallback runs only after the snapshot fails with a full-disk
diagnostic. The normal path does not change.
- Provider exclusions are not anchored to the directory root. In the
fallback, a nested entry that has an excluded name (for example a nested
`tmp` or `config.toml` in a Codex home) is also left out. The fallback
never copies more than the snapshot, so credentials stay out of the
checkpoint.
- The fallback depends on the provider honoring `exclude`, which the
sync protocol requires. The Daytona and Kubernetes providers honor it.
- A workspace export on a full disk still fails. This change only names
the cause. A full fix needs one of these: free-space reserve for the
export, removal of re-creatable caches before the export, or a capture
that streams its archive. Each of these changes behavior, so this pull
request does not include one.
- No migration.

## Model Used

- OpenAI Codex, GPT-6 family, assisted with merge preparation, conflict
resolution, documentation, test synchronization and verification. The
harness does not expose the exact serving model ID or context-window
size.

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, in Claude Code with
tool use (shell, file edits, test runs). It did the root-cause analysis
from run events, tool output, and sandbox inspection, wrote the code and
tests, and ran local verification.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: Dotta <bippadotta@protonmail.com>
2026-11-03 07:09:52 -06:00
DottaandPaperclip dc9f387edc fix(api): surface existing skill source import in discovery (#18757)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents discover supported API operations through the public OpenAPI
catalog.
> - Importing existing skill content must retain its source provenance.
> - A normal source-import query misses the applicable operation on its
first page because that operation has little search metadata.
> - This pull request describes the existing import operation and its
source boundaries.
> - The benefit is clearer discovery without changing search scoring or
import authority.

## Linked Issues or Issue Description

**What happened?**

`search_api` does not return `POST
/api/companies/{companyId}/skills/import` in the first ten results for
`import skill from source SKILL.md`. Source-management operations rank
ahead of the import operation. The import entry has only the summary
“Import a skill.”

**Expected behavior**

Ordinary source-import discovery should surface the existing operation.
Its documentation should explain that imported content retains
provenance and remains subject to company policy and source checks.

**Steps to reproduce**

Call `searchRunnerApi({ query: "import skill from source SKILL.md",
limit: 10 })`. Inspect the operation IDs on the first page. The new
regression sends this result through the real bounded MCP serializer.

Related: #18717 clarifies the separate `create_skill` tool. This change
covers the existing source-import HTTP operation. Neither PR is merged
by this work.

## What Changed

- Expand only the source-import OpenAPI summary and description.
Describe allowed local skill directories, supported remote sources,
retained provenance and existing access checks.
- Add a first-page discovery regression through the actual authenticated
MCP bridge and serializer. Keep non-import lookup, company/mode refusal
and denial forwarding controls.
- Update the feature and access maps with the test scope and its limits.

## Verification

- Parent regression: the controlled loopback MCP response lacked the
applicable import operation on the first page.
- Focused current checks: 2,060 tests pass in
`skill-import-discovery.test.ts` and the existing `runner-api.test.ts`
owner.
- `node scripts/check-maps.mjs` passes. This checks map structure only.
- The first head had one server test job cancelled after a runner
shutdown signal. The reason for the shutdown is unknown. The reviewed
successor removes only two test comments required by contribution rules;
its four focused controls pass. The remaining obsolete CI run was
cancelled after that successor was published. No same-head retry was
used.
- The new test is under `server/src/__tests__`, which the production
server typecheck excludes and the server Vitest suite includes.
- No local app, database, native agent or provider model was run. Normal
PR CI on `a4aaae8e320fb1d56cdbff9f376ec832a634a5da` passed with 48
successful jobs and one skipped job, including the required `ci /
verify` and `ci / e2e` checks. No completed agent-import journey or
reliability result is claimed.
- Greptile is 5/5 on the current head with no unresolved threads. The
optional Paperclip Review check remains queued. This is not merge
authorization.
- Keep this core PR open and unmerged. Do not enable auto-merge.

## Risks

The expanded metadata can change where this operation ranks for related
queries. Search weights, request schemas, HTTP routes, source parsing,
authorization and company skill policy are unchanged. The synthetic 403
control proves denial forwarding; it does not qualify the real policy or
source-import route. A live import still needs separate acceptance.

## Model Used

OpenAI `gpt-6.1-sol`, through Codex with reasoning, source review and
code execution tools. The exact context-window size is not exposed by
this environment. A separate agent reviewed the source and contract
before publication.

## 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.9
2026-11-03 06:29:13 -06:00
DottaandPaperclip ef5b98594f Explain the human primary-agent control in API discovery (#18747)
## Thinking Path

> - Paperclip lets a person manage a company of AI agents.
> - A primary agent is that person's company preference.
> - Only the person's board session can change it.
> - Native API discovery explains that restriction but omits the real
human control.
> - An agent can then suggest a Chat-picker setting that does not exist.
> - This change describes the existing profile crown and replacement
confirmation.
> - It adds no agent authority and no new tool.

## Linked Issues or Issue Description

**What happened?**

API discovery for the personal primary-agent preference explains
board-only access. It does not explain the supported profile control. A
retained native response gave a correct board API alternative but also
suggested a primary setting in the Chat picker. The picker only opens
conversations.

**Expected behavior**

The discovered operation should direct the person to the chosen agent's
profile, the crown control labeled Set as my primary, and the
replacement confirmation. It must keep the current person's board
authority and the agent denial.

**Steps to reproduce**

1. Search the native API for set primary agent.
2. Read the primary-agent operation's description.
3. Compare its guidance with the profile crown and the Chat picker.
4. The current description has no supported UI path.

**Paperclip version or commit**

Master `7b8aa60b6d` and the retained evaluated application have this
metadata gap. The profile control was checked in both sources. A scoped
open-PR search found no matching primary-discovery fix.

## What Changed

- Add general profile/crown/confirmation guidance to the existing GET
and PUT operation description.
- Clarify that the Chat picker does not change the preference.
- Keep all other OpenAPI bytes, authority, schemas and handlers
unchanged.
- Update the two existing capability maps.

## Verification

- The actual API search result passes through the existing authenticated
OpenCode MCP bridge and its bounded JSON serializer. The parent fails
because the delivered description has no profile control. The new result
retains the full guidance, board-only actor and original schema.
- The existing API client keeps its agent bearer/run identity and
propagates a mocked board403. This is client propagation proof, not a
new real-route claim.
- Initial selected controls:997PASS,1061 intentionally unselected. After
relocating the same test into the existing server `__tests__` directory,
both complete owning files pass:2058 controls. These are static/protocol
controls, not native journeys.
- The first normal CI head failed with TS6059 because the test imported
Runner source outside the server build root. The successor moves only
that test to the already-excluded test directory and adjusts four
relative imports. An independent source peer confirms identical test
bodies; `--listFilesOnly` confirms build-program exclusion. The failed
head is retained. Corrected-head CI41599277833 passed48 jobs/1skip on
attempt2 at08:17:23UTC. Attempt1 had46passing jobs but a server4
runner-shutdown cancellation; exactly that job and dependent verify were
rerun once on the unchanged head.
- Maps and diff checks pass. The initial loopback listen EPERM was a
setup failure; the controlled transport test then reached the actual
assertion RED.
- No Paperclip app, database, browser, model, external provider or real
credential ran locally. Full typecheck/build passed in corrected-head
normal PR CI. Fresh Greptile5/5 is tied to that exact head, with zero
unresolved threads.

## Risks

The added description can affect API search ranking. It changes guidance
only. It does not impersonate a person, change permissions or
automatically select an agent. Future model behavior remains
unqualified. The prior mixed failed journey is retained; its separate
versioned grading work is not part of this PR. Keep this core PR
unmerged.

## Model Used

OpenAI `gpt-6.1-sol` with reasoning, source inspection and tool use.
Context-window size was not exposed by the host.

## 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:28:57 -06:00
DottaandPaperclip a2a6129ed5 Allow a new human intent to request tool review after a decline (#18742)
## Thinking Path

> - Paperclip manages work for companies of AI agents.
> - App writes can require a human review for each invocation.
> - Decline and Always allow are separate controls.
> - The gateway currently reuses a declined action across later human
requests with the same arguments.
> - A new request can therefore receive the old decline instead of a new
review.
> - This change uses the saved run and human comment to distinguish a
new intent.
> - The new intent still follows the current policy and approval gates.

## Linked Issues or Issue Description

**What happened?**

After a person declines an Ask first app write, a later request from
that person for the same write receives `action_declined`. The gateway
matches company, task, agent, tool and arguments across runs. It does
not distinguish the later human request.

**Expected behavior**

A distinct later request from the same responsible person can open a new
Ask first review. It must not execute the write or reuse approval. A
retry of the declined intent, including its rejection continuation, must
remain declined.

**Steps to reproduce**

1. Ask an agent to perform an app write that requires approval.
2. Decline the proposed action.
3. Send a new request for the same action.
4. Observe that the gateway reuses the old rejection and creates no new
pending review.

**Paperclip version or commit**

The behavior is present on master `7b8aa60b6d` and in a retained native
journey. The focused parent control reproduces the matching error. No
related open fix was found in the scoped PR search.

## What Changed

- Only a rejected match can be released for a later human intent.
- Require the active run, company, task, agent and responsible person to
match the saved direct-human comment. Reject derived, deleted, untrusted
or system-authored input and invalid chronology.
- Preserve all other replay states, signed argument checks, current
policy, unresolved-effect guards, approval and execution owners.
- Document the distinction between decline and a standing policy change.

## Verification

- Actual matching-function control: parent fails; this change passes.
The control uses the unchanged owner body with synthetic database rows.
It does not claim real PostgreSQL or provider verification.
- 52 focused pure controls pass. These cover same-intent retries,
rejection continuations, foreign scope and actor, invalid authorship,
chronology and other action states.
- TypeScript 7.0.2 checks pass for the new helper and its owning tests.
- `node scripts/check-maps.mjs` and `git diff --check` pass.
- The existing gateway service suite has a new signed-action integration
test. It covers ordinary and reopened human requests. It requires the
old rejection plus one new pending request, a stable retry, and no
completed call. Each leaf prints one fixed success label after its
assertions so CI can distinguish execution from a platform skip. No
local PostgreSQL, app, model or provider execution was run. Current-head
normal CI41594912212 completed with48 successful jobs and1 expected
skip. Both real PostgreSQL leaves executed and emitted their
post-assertion markers; the owning job passed. Full typecheck/build
checks passed in CI.

## Risks

This adds one indexed run/comment read only after a rejected matching
action. Missing identity or ambiguous provenance keeps the old
rejection. Legacy and external comments without direct-human provenance
do not reset it. A new human intent is not consent to execute. This core
PR remains unmerged. Candidate native journey qualification is separate;
the original failed journey is retained.

## Model Used

OpenAI `gpt-6.1-sol` with reasoning, source inspection and tool use. The
host did 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
#123` / `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:28:36 -06:00
DottaandPaperclip 8bd45b5b30 fix(ui): expose redacted arguments in pending tool reviews (#18734)
## Thinking Path

> - Paperclip helps people manage AI agents and review their actions.
> - Ask first tool actions require a person to inspect the proposed
operation.
> - The task and Apps review surfaces share the pending tool-action
card.
> - That card shows a short preview but omits the available redacted
argument body.
> - A valid preview can omit important text, such as the date at the end
of a proposal.
> - This pull request adds optional argument inspection to the shared
card.
> - The person can inspect the proposed content before using the
existing decision controls.

## Linked Issues or Issue Description

Refs: #16540.

Related PRs: #16571 exposes reviewed arguments on formal board approvals
and scrolls the task review into view. #16716 routes tool actions to
their required formal board approvals. This change addresses the
separate shared pending tool-action card used by the task takeover and
linked Apps reviews. It does not close the other reported paths in
#16540.

## What Changed

- Add the existing Arguments and audit hash disclosure pattern to the
shared pending card.
- Show only the bounded argument summary already redacted by the server
and its audit hash. Show an unavailable message for missing, malformed,
or oversized fields.
- Keep the current approval, decline, and remembered-scope callbacks.
- Add a long-proposal story and update the tool-review feature recipe.
- Add React coverage for the real task review transition, the linked
Apps review, plain text rendering, invalid fields, and unchanged
decision calls.

## Verification

- The new task-review test failed on the parent because the disclosure
was absent. It opens Review request, inspects the proposal tail and
hash, then approves the same interaction.
- Oversized-whitespace controls fail on the previous guard ordering
because trimming runs before the length bound. The guard now checks
length first for both fields.
- Passed: 117 React tests across TaskChatInteractionCard,
IssueThreadInteractionCard, and ReviewQueueCard. The tests use the
repository UI config with the existing installed Vitest 5.0.3 dependency
tree.
- Passed: token gates, map checks, Storybook catalog checks, and git
diff checks.
- Local full UI typecheck did not pass. The linked dependency tree lacks
adapter and json-schema-to-ts declarations and has stale shared exports.
It reports no diagnostics in the changed files. This is not a successful
full typecheck.
- Full workspace build, browser, and provider checks were not run
locally. Current head 50600786f7 passed
all 48 normal CI jobs with one expected skip. Greptile and Paperclip
Review both report 5/5 at this head; all review threads are resolved. No
tool action or model call was run for this change.
- Inspect the new ToolActionLongProposal story. Open Arguments and audit
hash and read the final launch date. Inspection must not submit a
decision. Existing destructive, running, failed, declined, and expired
states keep their controls.

## Risks

- This changes the pending review presentation in tasks and linked Apps
reviews.
- The UI displays the existing server-redacted projection. It does not
request or reconstruct signed execution arguments. The existing server
schema caps the summary at 20,000 characters and the hash at 255
characters. The UI uses the same limits and escapes both as text.
- The server still owns redaction, scope checks, approval, and
execution. Inspection makes no API mutation. The current callbacks
retain the same request identity and permission scope.
- The PR will remain unmerged for separate review and candidate-source
integration.

## Model Used

OpenAI `gpt-6.1-sol` (Codex), with source inspection, code editing,
React tests, and Git/GitHub tools. 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-03 06:28:21 -06:00
DottaandPaperclip 07721e33f7 fix(runner): distinguish new skill authoring from source imports (#18717)
## Thinking Path

> - Paperclip lets people manage agents and shared company skills.
> - Agents can author new skills or add existing skills from approved
sources.
> - Source import and catalog install retain the source used by update,
audit and reset flows.
> - The create_skill tool described saving complete Markdown, without
explaining this choice.
> - An agent can therefore read an existing source and create an
unrelated managed copy.
> - This PR explains the distinction in the existing tool contract and
tests its actual model-facing projections.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The model-facing description of create_skill and the choice between
authoring and source import.

**Current behavior**

The tool says it saves a complete single-file skill. It does not
distinguish new authored content from adding an existing skill. The
Company Skills reference already directs external sources to import and
catalog skills to install.

**Proposed behavior**

The tool explains that it saves newly authored content. It directs
existing-source work to the existing import or install APIs through
search_api and call_api. It retains the existing assignment and retry
guidance.

**Reason and benefit**

A managed copy does not retain the original source locator. Clear
guidance helps an agent choose the source-aware operation without adding
a tool or changing permissions. This is a guidance repair. It does not
claim that the import backend failed.

## What Changed

- Clarify the canonical documentation, live descriptor and scenario
descriptor for create_skill.
- Test the actual discovered contract and provider projection, including
API claim and company-boundary negatives.
- Refresh generated descriptions and the seeded catalog digest and
manifest entry.

## Verification

- A focused regression fails on the parent because the actual discovered
contract lacks the authoring versus import distinction.
- Three focused pure suites pass: 48 tests. They include existing skill
creation, retry, schema and authorization controls.
- The source-owned serializers and protocol fixture validator
regenerated the inventories without an app or native build.
- Both generated inventories change only create_skill description.
Arguments, required claims, modes, idempotency and all other tools
remain byte-equivalent.
- Current head `bca441726a6cba80e6e7da0321db59e27183c5b8` passes
required `ci / verify` and `ci / e2e`; the full main CI run has 49
successful jobs. Windows, Docker, security and review checks also pass
or are intentionally skipped. Greptile and the final Paperclip review
are 5/5, with zero unresolved threads. This PR remains deliberately
unmerged for the separately reviewed evaluation candidate.

- Original head CI preserved: one unrelated UI clipboard-confirmation
assertion failed after the clipboard call passed; 47 other executions
succeeded and the final verify check failed as its dependent. The two UI
owners are unchanged from the base. Exact React scheduler/timer timing
is unknown. No unchanged-head retry was used before the necessary master
conflict sync.
- The conflict sync preserves incoming task-assignment guidance and
regenerates metadata. It is not a fix for the UI test failure. The
synchronized current head passes CI and review. No same-head recovery
was consumed.

## Risks

The description changes model context and the catalog digest. It may
affect tool choice, but actual same-request and same-model acceptance is
still pending. The change does not alter authorization, API behavior or
grading. Local checks did not run the app, database, native runner, full
graph typecheck or build. Intermediate test-fixture claim and placement
mistakes were corrected; the final focused run passes. Do not treat
these pure controls as a feature pass.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) through Codex, with reasoning, source
inspection and tool execution. The host does not report a 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; narrow
create_skill/import and skill-import-guidance searches found no
duplicate.
- [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:27:50 -06:00
a497bae83a test(e2e): verify Cloud workspace access isolation (#18655)
## Thinking Path

> - Paperclip keeps agent work inside company boundaries.
> - Cloud users switch workspaces through the tenant account menu.
> - A company-bound credential must work inside its permitted company.
> - A missing resource cannot prove an access denial.
> - This journey uses real controls in two registered test workspaces.
> - It checks reads and task creation in both directions and revokes
both keys.

## Linked Issues or Issue Description

Refs: #18728, #18729, #18652.

**What existing behavior does this improve?**

Product E2E coverage for Cloud workspace selection and company-bound
agent API access.

**Current behavior**

The journey catalog lacks a two-workspace boundary check with real
allowed and denied controls.

**Proposed behavior**

Use the visible Cloud menu to switch workspaces and return. Read a real
task and create one task in each credential's own company. Require real
foreign reads and the same task-creation operation to return 401 or 403
in both directions. Verify that no foreign task was created and that
protected content was not returned. Revoke both credentials and require
their earlier allowed reads to return 401.

## What Changed

- Add a browser journey and a narrow target-provider fixture contract.
- Require independent owner reads, exact agent authorship, zero-to-one
task creation, stable run history, no unexpected work and no foreign
creation.
- Validate observed workspace entry links against the exact registered
targets.
- Add wrong, missing, leaked, foreign and invalid-entry evidence
controls. Saved passes reject collected runs or nonempty model usage.
- Register all seven required checks, definition-hash inputs, feature
associations. The feature-map documents are unchanged, as requested.
- Base the final tree on verified repository master
`7b8aa60b6d79b6cd9e4d46ca1369515c33e2d5d4` plus only 15 access journey
and catalog files. Preserve all other master files and modes. The held
completion journey is outside this PR's diff.

## Verification

- 851 catalog, journey, completion-helper, artifact and browser-action
support tests passed across 40 files.
- E2E TypeScript, credential-free discovery, feature-map validation,
full workspace recursive typecheck, full build and `git diff --check`
passed.
- The broad local `pnpm test:run` attempt stopped in chat integration
shard 1 before any assertion. Embedded Postgres initialization exited
with code null. No chat tests or later unit shards ran. The startup
cause is unresolved, the failure is retained, and the command was not
retried. The database/chat/test-runner source is unchanged from the
fixed master snapshot. The separate hosted full CI result is recorded
below.
- The first local E2E typecheck read stale compiled plugin SDK
declarations after the merge. The SDK source already declared the field.
Rebuilding its declarations cleared the diagnostic without a source
edit.
- The complete tree comparison proves exactly 17 changed paths before
the documentation removal against the fixed master snapshot. Every other
master file and mode is preserved. All four access flow, contract and
test blobs match the previously passing source
`fab9a1fb2fefb41a7248e4fc1aa239d77455f5e2` byte for byte.
- The historical staging attempt on source
`fab9a1fb2fefb41a7248e4fc1aa239d77455f5e2`, the earlier Core42
deployment and the earlier adapter passed all seven checks: owner
resource controls, visible Cloud switch and return, scoped data, both
restricted-agent positive controls, cross-workspace read/task-creation
denials, credential revocation and no agent work. Both credentials were
revoked, owned credential agents had terminal receipts, and evidence
cleanup was complete. No agent or model work was recorded.
- The earlier attempt failed before journey checks while reading the
borrowed fixture agent's historical details. That failed result remains
preserved. The provider then supplied a separately owned primary
identity. The public history assertions remain unchanged.
- The strict root catalog expectation first failed because it omitted
the new access case. Adding only that expected entry made the test pass.
The ordered list and default-selection assertions remain unchanged.
- The first combined-head full CI run failed two unchanged
attention-retention tests at their original 15-second limits. The
catalog fix does not change those tests or their timing. The initial
failures are retained, their cause is unresolved, and that failed run
was not retried.
- Normal full CI passed on the new commit in [run
41595755161](https://github.com/paperclipai/paperclip/actions/runs/41595755161),
attempt 1: 48 successful jobs and one intended skip. The two unchanged
attention-retention cases passed at about 12 seconds; the earlier
timeout cause is still unknown. The fresh review on commit
`4c0ea682444738ad6fa17017a6afd25a49037559` is 5/5 with no open findings.
The fresh staging result is recorded below. This PR changes no daily
plan, private configuration, model or live workspace.


- Fresh staging qualification on commit
`4c0ea682444738ad6fa17017a6afd25a49037559` passed all seven checks and
all five phases. Both ordinary same-workspace task creations returned
201. Both cross-workspace task creations returned 401. Both credential
agents reached terminal state. Both keys were revoked, and both
revoked-key reads returned 401. The manifest records complete cleanup
and no active operations. No model or task run was recorded. All three
workflow jobs passed.
- The coordinator verified TestOps case 719 and result 3761 as passed,
then closed launch 1987. Its report shows model none and the current
qualification run. The automatic Slack report recorded one pass and zero
failures.
- The original normalized result was passed. The first evidence
collector left its own qualification false because its allowlist omitted
the standard `dashboard.html` artifact. The adapter already declared
that file, and the public launcher generated it. An exact-object read
matched the 118,791-byte object, ETag and SHA256 archive receipt. This
completed the three-artifact inventory. The original result, collector
proof and seal remain unchanged. No HTML was executed or rendered, and
no test was rerun or regraded.

| Fresh staging provenance | Verified value |
| --- | --- |
| Public commit | `4c0ea682444738ad6fa17017a6afd25a49037559` |
| Qualification workflow | `41597774599`, attempt 1 |
| Serving Core commit | `09162fe893b464dd2ccdafd14bd3ef1611202a86` |
| Target adapter commit | `7367cf6fd0ee1cf52c2651a8a6671e087728a9c1` |
| Actual workflow bootstrap commit |
`55351ffba2704a4e13c1ead3e50665acd51aef87` |
| Exact 117-file QA contract SHA256 |
`14d95c29059c82563ab0e1d65a01aa4ac6c4f60f77a236803cf06ad5d9e7d27b` |
| Provider-pack configuration version | `9` |

- At the user’s request, follow-up commit
`7e0dbc4bdba8a25ff6486648b0ca0d0db2616a4c` removes both feature-map
additions. The final diff contains 15 paths and no `maps/feature-map/`
changes. An entire-tree comparison against the QA-passed commit proves
these two Markdown files are the only changes; every executable file,
test, fixture, registration and file mode is unchanged. `node
scripts/check-maps.mjs` and `git diff --check` pass after the removal.
The live QA run above was not repeated for this documentation-only
change. Fresh current-head full CI passed in [run
41633385961](https://github.com/paperclipai/paperclip/actions/runs/41633385961),
attempt 1. The current-head Greptile review is 5/5 with zero unresolved
threads. The normal merge preserves every newer master file outside the
15 PR paths and keeps all 15 PR files byte-for-byte intact.

## Risks

The private target provider must register two exact test workspaces and
preserve their separate ownership and cleanup. The case verifies
company-bound agent credentials. It does not certify human membership
roles. It tests task creation because ordinary agent task edits require
a real execution context. No execution context is forged and no product
authorization guard changes.

The local broad unit run could not start embedded Postgres, so it does
not establish a full local unit pass. The earlier hosted
attention-retention timeouts also remain unexplained. Passing a later
run would not prove the source of those timeouts.

The four case files retain their historical passing bytes. The fresh
qualification verifies the executable test code retained in this PR
against the deployed staging stack. Daily admission remains a
coordinator action after the normal source merge. The case does not
cover future deployments without another run.

## 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>
Co-authored-by: Codex <noreply@openai.com>
2026-11-03 06:24:08 -06:00
DottaandPaperclip b22ef22d56 fix(runner): show provider failure details on tasks and runs (#18622)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native Runner starts providers and records their run outcomes.
> - Provider failures can contain useful details below a generic
protocol error.
> - Those details were lost at the sidecar, command receipt, and run
projection boundaries.
> - A blocked task therefore showed a generic failure even when the
provider gave a clear reason.
> - This pull request carries a bounded, sanitized provider failure
through those boundaries.
> - Operators can read the actual cause on the task and run pages.
Existing recovery policy still controls retries.

## Linked Issues or Issue Description

Refs #17543 for the related closed JSON-RPC classification work. Refs
#17272 for provider recovery in the legacy OpenCode adapter. This change
adds display evidence for native Runner providers and keeps recovery
policy separate.

**What happened?**

A native Claude session returned an HTTP 429 message below an ACP
`Internal error`. The task and run showed only a generic startup
failure. Operators had to inspect the provider response to learn that
the account was rate limited.

**Expected behavior**

The task and run show the sanitized provider message, provider name,
startup or turn phase, and available HTTP status. Unknown categories
keep the message. Display evidence does not grant a retry or replace a
recovery decision.

**Steps to reproduce**

1. Start a native Claude run whose account is rate limited during model
selection, or return a structured provider failure from a Codex or
OpenCode turn.
2. Let the run fail and open its task page.
3. Before this change, the page shows a generic failure. With this
change, the page shows the provider explanation. The run page shows the
same explanation after reload.

**Paperclip version or commit**

Source checkout based on `f8a888a072`.

## What Changed

- Add one JSON Schema for `ProviderFailure` and generate matching Runner
and shared TypeScript readers. Keep the Runner package independent of
the app workspace at runtime.
- Normalize known ACPX, Codex, and OpenCode error fields. Preserve
unknown messages. Redact known credential values and credential patterns
before applying the 4,000-character limit. Do not copy response bodies,
headers, stacks, or prompts.
- Carry startup failures through the sidecar, Rust Runner, durable
command receipts, and private transport error details. Keep provider
text out of generic transport error strings and Sentry failure messages.
- Keep turn failures in authenticated run events. Recover the same
evidence from persisted events during server finalization. Store the
cause in the company-scoped run result.
- Show one shared notice on failed tasks and run details. Keep existing
retry permissions, scheduled retry state, and resolved-task behavior.
- Reapply registered run-secret and current-user redaction to task
display data. Batch secret lookups for only the visible provider causes.
- Document the contract and update the capability maps. Add regressions
for nested Claude 429 errors, OpenAI quota and rate limits, OpenCode
errors, redaction, durable receipt replay, restart finalization, and UI
rendering.

## Verification

- `pnpm -r typecheck` passed. `pnpm build` passed. All GitHub Actions
build, test, package, and validation jobs passed on `d49c79ab4a`. The
security checks passed. Greptile gave this head 5/5 with no open review
threads. Paperclip Review remains pending. Its review worker exhausted
six workspace recovery attempts with export_interrupted. A fresh review
request was accepted and is waiting for that saved workspace. The
ordinary Retry action rejected reuse of the stopped request. This is an
external review-worker blocker; no check was overridden. The duplicate
local `pnpm test:run` was stopped after the CI test shards passed.
- Focused server settlement, provider evidence, and restart tests: 93
passed. Runner admission and normalization tests: 103 passed. Focused
Runner wire and terminal tests: 29 passed. The real Rust/sidecar command
receipt replay test passed.
- The new projection test failed before implementation because the task
had no provider cause. The startup producer regression also failed
before extraction moved ahead of the generic error-code replacement.
Both pass with this change.
- Live check: a rebuilt local sidecar received an actual Claude HTTP 429
during startup. The new cause kept the full provider message. A
synthetic task in an isolated local app then reached the same provider
error through the native Runner path. The dedicated run result, task
API, task banner, and run detail all showed the same message after
reload. The later reporting fix keeps run.error generic; a regression
proves the display cause still survives restart and stays out of Sentry
capture.
- The first isolated app attempt failed earlier in
`admission_credential`. An ordinary manual Retry reached the provider
and produced the 429 above. This PR does not claim to fix that separate
admission failure. An initial parallel local database test setup also
failed; the serial restart suite passed.
- Security review found that copying display text into run.error could
forward it to Sentry. A regression failed with that behavior. The fix
keeps the cause in its display field. All 38 settlement/restart tests
and the server typecheck pass.
- All 29 protocol contract tests pass, including bounds and extra-field
rejection. An earlier full Rust core run passed. The later full run hit
one 5-second receipt-limit timing assertion; its isolated rerun passed.
The full Linux and Windows Rust CI jobs passed on this head.
- Review regressions pass for explicit Codex driver identity, native
Rust startup and resume receipt propagation, oversized OpenCode/ACPX
errors, task read-time registered-secret redaction, and the standalone
source closure. The focused Runner run passed 103 tests;
projection/restart tests passed 16.
- Read-time redaction edge cases passed: a missing decryption key omits
only the unsafe optional explanation; expanded redacted messages remain
visible within the Unicode character limit. All 14 task projection tests
and server typecheck pass.
- The package Build check found an old Pi assertion against
Error.message. The probe now checks the exact closed classification in
the authenticated receipt and requires the new provider cause. Both
polling transport cases pass. A local credential-free Pi probe stopped
at admission_installation because this checkout lacks the Pi
distribution; the installed Linux package probe passed in CI on this
head.
- UI coverage includes startup and turn text, unknown categories,
literal rendering of provider text, read-only retry behavior, and
resolved-task suppression. Token gates and map checks passed.
- The live check covers Claude startup on macOS. Codex, OpenCode,
terminal failures, and restart paths have deterministic regression
coverage. The change is not deployed.

## Risks

- Provider messages are untrusted text. The boundary selects specific
fields, redacts credential patterns and known environment secret values,
bounds the message, and renders plain text. New provider-specific secret
formats may need added redaction patterns.
- Optional fields preserve compatibility with older producers and stored
runs. Old runs without the field keep their current fallback text. No
database migration is required.
- The cause stays in company-scoped run data. This change does not send
provider text to first-party Telemetry or add it to OpenTelemetry span
attributes.
- Normalized categories and retryability are display evidence. Existing
recovery classifiers, retry limits, ownership checks, and approval gates
keep their authority.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, repository tools, code
execution, and browser verification. The host does not expose the exact
serving 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 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-03 06:13:26 -06:00
DottaandPaperclip 718336eb04 fix(native): refresh prior warm controller projections (#18718)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native remote sessions keep their controller state in a database
checkpoint.
> - An admission can also leave a full local copy of a prior run's
state.
> - The prior owner can commit more state without changing its run ID.
> - Warm admission skipped a refresh when the local and saved run IDs
matched.
> - This pull request refreshes that prior-run copy when no retained
warm owner exists.
> - The next turn can use the committed state while existing ownership
checks remain effective.

## Linked Issues or Issue Description

**What happened?**

A prior warm run can complete after an earlier admission reads its
controller checkpoint. The local copy can still contain a pending
command or lack the final terminal event. A later admission sees the
same run ID and skips restoration. It can then hold work against that
old copy even though the database checkpoint has settled.

**Expected behavior**

Read the canonical prior-run checkpoint before reuse when no retained
in-memory owner exists. Keep current-run state with its controller. Keep
unresolved canonical work and invalid checkpoint bindings blocked.

**Steps to reproduce**

1. Create a full prior-run local projection while a command is pending.
2. Complete that command and record the terminal in the canonical
checkpoint under the same run ID.
3. Start an ordinary remote warm continuation without a retained
in-memory owner.
4. Before this change, the local command remains pending. With this
change, the completed command and terminal replace the stale copy.

**Paperclip version or commit**

Reproduced on master `36df8933f0` before changing production code.

Related work: #18018 restored per-turn checkpoints; #18343 added
controller replacement recovery; #18554 restored missing remote
suspension receipts. This change handles a full prior-run projection
whose run ID already matches the saved supervisor. It does not change
the settlement guard or MCP compatibility policy.

## What Changed

- Refresh a prior-run warm controller projection even when its run ID
has not changed.
- Keep current-run and retained warm owner authority on the existing
path.
- Add five executor cases for a settled source, a pending canonical
command, a current run, legacy file-backed state, and an invalid
checkpoint binding.
- Add an opt-in Linux continuity case with a stale full local projection
and two follow-up turns.
- Update execution documentation and the paired session verification
recipes.

## Verification

- RED before the production edit: the executor fixture retained
`pending` in its local command record when the canonical record was
`completed`.
- GREEN on the final commit: 48 focused tests passed across executor
restoration, retained warm owner rotation, per-turn restoration, and
remote settlement guards.
- `pnpm --filter @paperclipai/server typecheck` passed. The server
TypeScript check also passed after the integration fixture was added.
- `node scripts/check-maps.mjs` and `git diff --check` passed.
- The unit fixture uses the real durable controller serializer and the
real executor entry. It stops at current tool authority before
provider/backend creation. It proves restoration and guard behavior, not
full task acceptance.
- Actual protocol RED/GREEN: the same opt-in continuity fixture uses
real PostgreSQL, TLS, the current Linux Rust Runner, and a deterministic
fake Codex backend. With only the executor restored to its parent
revision, continuation fails with
`prior_owner_terminal_state_indeterminate` in the settlement guard after
one provider turn (20.16 seconds). The PR source completes all three
turns with one provider thread and final suspension (34.77 seconds).
Hard recovery permits one provider-process replacement; the healthy
final follow-up starts no additional process. Both runs use the same
Runner binary and owned container.
- The exact PR executor source was restored after the baseline
comparison, its Git blob was verified, and the worktree is clean. The
disposable local container was removed. This fixture proves the
controlled stale-projection recovery path; it does not establish a live
model or Daytona API result.
- Full current-head CI passes, including typecheck, build, general and
serialized tests, Rust/Runner checks, all eight E2E shards, and the `ci
/ e2e` and `ci / verify` aggregate gates. Greptile is 5/5 on the current
commit, with no unresolved review threads. No original task was retried
and no staging sandbox lifecycle was changed.

## Risks

- Admission without a retained owner performs one additional scoped
checkpoint read when a full prior-run projection already exists.
- The canonical checkpoint must still pass its company, task, session
and record validation. A pending canonical command stays held.
Current-run and retained owner state are not replaced.
- The regression proves a stale local projection defect. It does not
establish that a historical incident had those same local bytes.

## Model Used

OpenAI Codex, GPT-6 family. The harness does not expose the exact
serving model ID or context-window size. Capabilities: repository
inspection, code generation, tools, and test execution.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (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:12:22 -06:00
DottaandPaperclip db8a273562 fix(native): publish fresh retry sessions for later turns (#18713)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native tasks save a provider session for later comments and monitor
checks.
> - The goal projection also records the run that owns the session event
sequence.
> - A fresh retry uses a new native session, but the projection accepted
only the old session.
> - The accepted checkpoint then rejected session publication because
the goal source still named the old run.
> - This pull request lets the current task executor advance that source
after a terminal predecessor with no unfinished goal.
> - Later turns can then use the fresh retry's saved session.

## Linked Issues or Issue Description

Related: #12669, #18343. I searched open and closed PRs for source
epochs and native task-session publication. I found no duplicate repair.

**What happened?**

A successful fresh native retry could retain its predecessor's
task-session pointer. A later comment or monitor selected the old
provider session. The goal source transition required both runs to have
the same native session. The terminal checkpoint then saved a
`suppressed_newer` publication result.

**Expected behavior**

The current task executor can publish its accepted fresh session. A
later turn resumes that session. Delayed events cannot restore the old
source or revive a cleared goal.

**Steps to reproduce**

1. Complete a native turn and retain its task-session row.
2. Admit a fresh session on the same task without deleting the row.
3. Complete that turn, then send an ordinary follow-up.
4. Before this change, the saved pointer can still name the first
session.

**Paperclip version or commit**

Reproduced on source commit `36df8933f0` with a PostgreSQL regression
before the production change.

**Deployment mode**

Source checkout. The affected producer runs for local and remote native
sessions.

## What Changed

- Permit a different native session to advance the goal source only when
its run holds the task execution lock and assignee, and the task is in
progress.
- Keep the terminal predecessor, native runtime, runner identity, absent
or completed goal, source sequence, and conversation reset checks.
- Test accepted session publication, a fresh heartbeat followed by an
ordinary resumed turn, stale events, current-owner loss, and unfinished
or unreadable goals.
- Add an opt-in live Codex file-persistence check. Update execution
documentation and both recovery maps.

## Verification

- Red: the new PostgreSQL publication regression failed before the
producer change. The saved session, display ID and goal source still
named the predecessor.
- Green: 72 distinct tests passed across the final focused runs of
`runner-goals.test.ts`, `native-task-session-publication.test.ts`,
`native-session-resumption.test.ts`, and
`remote-warm-session-recovery.test.ts`.
- The assembled heartbeat test admits three turns, opens two provider
sessions, resumes the second session once, and stores three results. It
uses a deterministic provider backend.
- `node scripts/check-maps.mjs` and `git diff --check` passed.
- Real local Codex acceptance passed on macOS arm64 with `gpt-6.1-sol`
and explicit warm mode. Three heartbeat turns saved three exact file
lines. The fresh second turn published its new normalized and provider
session IDs. The ordinary third turn retained both IDs. The fixture
closed its warm owners and removed its private credential copy and
workspace. The production code was at `450e15e`; the final test-only
commit selects explicit warm mode and uses the existing owned-home
cleanup helper. The production change is identical in the final head.
- The earlier per-turn fixture preserved all three file steps and
selected the correct normalized session, but provider-thread reuse
failed. `run.attach` reported that the Codex provider had pending
events; the safe fallback used another provider thread. This remains a
separate failure. The first fixture cleanup also failed on immutable
instruction assets. The owned-home helper fixed cleanup, and the second
per-turn attempt exposed the provider identity assertion directly.
- Full current-head CI passes, including typecheck, build, general and
serialized tests, Rust/Runner checks, all eight E2E shards, and the `ci
/ e2e` and `ci / verify` aggregate gates. Greptile is 5/5 on the current
commit, with no unresolved review threads. Broad local workspace checks
were not duplicated; the focused regressions and actual provider
acceptance above were run locally. No merge, deployment, or recovery of
an original task is included.

## Risks

- Source epoch changes affect saved goal state. The fresh-session path
requires current task authority and refuses unfinished or unreadable
saved goals.
- The change starts no provider work and changes no prior-owner recovery
guard. Unknown external outcomes retain their reconciliation hold.
- A prior session remains held when it lacks the required authority or
state proof.
- Per-turn provider-thread reuse remains an open coverage gap described
above. This change does not alter that attachment guard.

## Model Used

OpenAI Codex, GPT-6 family. The exact model ID and context window are
unavailable in this session. The agent used code inspection, tools, and
executable tests.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` 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:12:00 -06:00
DottaandPaperclip 89e3c23062 fix(daytona): stream files when export copies cannot fit (#18712)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A native task must save its files before finalization can release
its writer.
> - Remote workspace capture can produce an archive that fits on the
sandbox disk.
> - Daytona then makes another copy before it downloads that archive.
> - The second copy can run out of space and leave completed work behind
a save hold.
> - This pull request uses the existing bounded stream when that copy
cannot fit.
> - The benefit is a saved archive without a second archive-sized
sandbox allocation.

## Linked Issues or Issue Description

Related: #18644 reduced capture scratch space. #18172 added the
disk-free directory export. #18705 preserves provider checkpoints on a
full disk and reports capture failures. This change handles the later
single-file download copy. It does not depend on #18705 and does not
replace its checkpoint fix.

**What happened?**

A native provider turn returned a successful result and captured its
workspace archive. The Daytona outbound file guard then failed with exit
43 and `No space left on device` while it copied the archive to a
reserved download file. Finalization and file-preservation retries could
not pass this boundary. The workspace kept its writer hold.

**Expected behavior**

Download an existing archive through a confined sandbox process when its
second copy cannot fit. Keep the source and all finalization holds until
the normal save commits.

**Steps to reproduce**

1. Capture a workspace archive in a Daytona sandbox.
2. Leave less free space than the archive needs for another copy.
3. Finalize the task. The outbound single-file guard fails before
download.

**Paperclip version or commit**

Reproduced against `6d72243d8a`. The incident used the native sandbox
runtime. This branch is based on current master.

**Deployment mode**

Cloud with native Paperclip Runner execution and remote workspace
storage.

## What Changed

- Remove partial outbound file copies after a failed snapshot command.
Only copy capacity failures select the stream path. Permission,
confinement, and transport errors still fail.
- Use the existing acknowledged terminal stream to read each file as the
sandbox user. Recheck canonical confinement and regular-file status. Use
a no-follow open. Keep the sandbox disk limit, host free-space reserve,
shared transfer deadline, and bounded teardown.
- Keep host files in private temporary files until the complete batch
has transfer receipts. Never pass a mutable live source to the
privileged download API.
- Add real-file and real-terminal regressions, a disposable Daytona
acceptance case, and workspace verification notes.

## Verification

- Red before repair: a real 5 MiB copy under a controlled file-size
limit failed with exit 43. The same test passes after repair and
compares every source and destination byte.
- The ten capacity cases pass. They cover producer failure after output,
source replacement, stream size limits, permission errors, timeout
teardown, cleanup, and a successful retry. A two-file case completes the
first stream and fails the second. Both old host files stay intact, both
source files survive, and retry saves both files. An isolated
early-publication mutation makes that test fail.
- The initial complete Daytona package suite passes: 537 tests passed, 8
skipped. After the test-only review follow-up, all 60 focused transfer,
stream, and diagnostic tests pass. The package typecheck also passes.
- Real Daytona acceptance passes: an owned Ubuntu 24.04 sandbox stops
and resumes, a copy to `/dev/full` reports ENOSPC, production export
saves the exact archive hash, and a second save after reconnect passes.
The test deletes only its disposable sandbox. This is provider-boundary
acceptance, not a UI journey.
- Assembled finalization acceptance passes with real Postgres and a live
Linux x86_64 Daytona sandbox. The production control-plane port accepts
one fixture result. The production workspace finalizer encounters the
failed copy, saves the files, and commits the task as `done`. A new
database client reads the committed result and exact file hash. The
workspace has no writer or running save, and there is still one run and
one result. No model turn runs. The target resolver is bound to the live
provider fixture. Object storage uses the production encryption and
local-disk service with an S3 admission label; this does not prove an S3
network transfer or a UI journey.
- The live tests used the fixed transfer source with SHA-256
`857b3d8c9ad75170707d95277c17c051ce4582fa79a9c38331d51d2800b36af5`. That
source is identical in this PR head.
- `pnpm -r typecheck` passes locally. The duplicate full local test run
passed all six chat shards before it was stopped during the server lane
in favor of completed current-head CI; a duplicate local build was
skipped. Full current-head CI passes, including typecheck, build,
general and serialized tests, Rust/Runner checks, all eight E2E shards,
and the `ci / e2e` and `ci / verify` aggregate gates.
- Greptile is 5/5 on the current commit with no unresolved review
threads.
- `node scripts/check-maps.mjs` and `git diff --check` pass. Map checks
prove structure only.

## Risks

- The fallback requires the Bash and GNU `dd`/`base64` tools already
required by the existing stream path.
- Terminal streaming is slower than the normal bulk download. It runs
only after a copy capacity failure.
- The workspace capture itself still needs sandbox space. This change
does not fix a full disk before an archive exists.
- The test injects a failed copy sink. It does not exhaust a shared host
disk. No original task was retried, and no deployment or merge is part
of this PR.
- No schema, API permission, writer ownership, or retry-budget change.

## 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>
2026-11-03 06:11:41 -06:00
DottaandPaperclip 1bc3ed6dd5 fix(opencode): keep native tool calls pending until Runner settlement (#18711)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native OpenCode sends semantic tool calls through the durable Runner
protocol.
> - The Runner retains a call until its result is known.
> - OpenCode and its HTTP bridge each stopped waiting after 30 seconds.
> - A slow response could leave a call pending after the provider had
moved on.
> - A later run then failed the pending-call guard during attachment.
> - This pull request keeps native calls under their Runner owner until
settlement or cancellation.
> - The benefit is one delivered result and a safe next run.

## Linked Issues or Issue Description

Related: #18343 applies the durable wait policy to native ACPX calls.
This change applies that policy to native OpenCode.

**What happened?**

An assigned tool call took more than 30 seconds. OpenCode reported an
MCP timeout while the Runner still retained the request. The source turn
could finish, but suspension failed. A later `run.attach` failed because
provider tool calls were still pending.

**Expected behavior**

The native proxy must wait for the authoritative result under the Runner
owner. Stop, bridge close, and lease expiry must still end the wait.
Unknown effects must still block attachment.

**Steps to reproduce**

1. Start a native OpenCode run with an assigned semantic tool.
2. Hold the controller's result for 31 seconds.
3. Observe the provider's MCP result and attach a later run to the
session.

**Paperclip version or commit**

Reproduced against `6d72243d8af0362d73fbcb5331fd42a384800d4e`. The
branch is based on `36df8933f0`.

## What Changed

- The native OpenCode proxy enables a driver capability for durable tool
requests.
- That capability removes the bridge's separate request timer and sets
OpenCode's fixed MCP client ceiling to one hour, consistent with the
native ACPX sidecar.
- Ordinary driver calls keep their 30-second deadline. Assigned external
MCP connections keep their existing budget.
- Cancellation, result replay, tool authorization, and the pending-call
attachment guard keep their existing contracts.
- The native regression holds a result for 31 seconds, then completes a
second run with the same Runner process and no pending provider calls.
- The deterministic provider fixture honors the emitted MCP budget and
retains the initial completion contract across ordinary follow-ups.
- Execution semantics and the session verification maps describe the
wait and its safety checks.

## Verification

- Red before production edits: the bridge aborted a durable request at
the ordinary 30-second boundary. The driver emitted `30000` instead of
the expected `3600000` client budget.
- The final combined bridge, driver, proxy, and native protocol run
passed: 95 tests in five files (71.17 seconds).
- The native delayed-result probe passed with the current Rust Runner
and current bundled proxy. It completed the later run with the same
Runner PID and an empty pending-call ledger.
- Actual provider check passed on macOS arm64 with
`opencode-ai@1.18.34`, the changed source, and a local deterministic
OpenAI-compatible model. One assigned write waited 31 seconds and saved
one file. Both turns completed. The second turn retained the saved tool
receipt. The write ran once across five model requests.
- Bridge safety cases cover result replay without another action,
ordinary timeout behavior, MCP cancellation, and teardown of an
unanswered durable request.
- Both runner TypeScript projects passed typecheck. The first attempt
lacked the eval-kernel build; it passed after building that declared
dependency.
- Map alignment, module boundaries, and `git diff --check` passed.
- The first native follow-up probe failed because its synthetic provider
forgot the initial completion-contract revision. This caused a repair
turn and another discovery call. The fixture now retains the contract,
and the same probe passed. The failure is retained here.
- Runtime acceptance used the implementation at `583d316ad4`. The later
clarification commit changes comments, documentation, and a test name
only. It does not change runtime behavior.
- Full current-head CI passes, including typecheck, build, general and
serialized tests, Rust/Runner checks, all eight E2E shards, and the `ci
/ e2e` and `ci / verify` aggregate gates. Greptile is 5/5 on this
commit, with no unresolved review threads. No deployment or retry of the
affected historical task was performed. The actual provider check used a
local model; it does not qualify a deployed Linux sandbox or a live
model service.

## Risks

- A native call can wait longer while its Runner owner remains valid.
Stop, teardown, and lease expiry still end the wait. The MCP client has
a separate fixed one-hour ceiling. Runner ownership can renew beyond
that ceiling. If the client deadline expires first, the operation
outcome remains unknown and the existing hold must still block replay
and run attachment.
- This prevents new premature timeouts. It does not classify or replay
an old request whose effect remains unknown.
- No schema, migration, credential, or permission change is required.

## Model Used

- OpenAI Codex, GPT-6 family. The harness does not expose the exact
model ID or context window. Capabilities used: code generation,
tool-assisted diagnosis, local execution, and test analysis.

## 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:11:24 -06:00
DottaandPaperclip dd02595390 fix(db): retain hosted census construction callers (#18725)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Operators use a bounded database census to find expensive read
paths.
> - The hosted server combines application code and capture wrappers in
generated files.
> - Generic HTTP owners suppressed caller capture. Generated paths also
failed the caller allowlist.
> - This PR retains trusted query construction locations without source
maps.
> - Operators can distinguish application query sites while exact
owners, privacy limits and capture bounds stay intact.

## Linked Issues or Issue Description

Refs #17522, #17564.

**What happened?**

A real map-free bundle with two application query sites produces one
callerless census group. This affects unowned queries and queries under
the generic `http.request` owner.

**Expected behavior**

The census should distinguish trusted query construction sites. It must
keep unknown calls unknown and preserve specific semantic owners without
stack capture.

**Steps to reproduce**

Run the committed bundle test and pinned comparison helper. The helper
bundles the actual capture module and real Drizzle, with a fake
postgres-js client. It does not assign a fake path to an isolated mock
caller.

**Paperclip version or commit**

Control: `09162fe893b464dd2ccdafd14bd3ef1611202a86`. The branch is
rebased onto `1e3ab690b072bbf6a1c1f1d0454ea49315b2074c`; neither
intervening commit changes this owner.

## What Changed

- Keep the exact generic HTTP owner and add bounded caller capture only
during the active census window.
- Exclude capture wrapper frames with a local V8 stack boundary. Keep
one static generated construction anchor for trusted root builders.
- Keep unscoped bundled driver and relational paths unknown. Their first
frame can belong to the ORM.
- Cover exact application lines, alternate parameters, prepared
builders, transactions, nested savepoints, privacy and inactive windows
in a real bundled scaffold.
- Add a portable pinned comparison helper and retained measurements.
Existing group, page, byte, expiry and output-rate caps remain in force.

## Verification

- PASS: 54 focused unit, real-bundle, existing runtime bundler and
real-PostgreSQL tests.
- PASS: database TypeScript check.
- PASS at final head `b270b92821`: full local `pnpm -r typecheck` and
`pnpm build`.
- The first local `pnpm test:run` was stopped after two chat partitions
passed (668 cases), because source changed during the run. This is
partial evidence only. The fresh final-head full local command passed
all six chat partitions (1,829 cases). Its general phase reported one
failure in the unchanged workspace port-conflict test. The exact case
then passed alone (1 pass, 178 skipped), and the unchanged full file
passed 179/179. The original failure did not reproduce; its cause is
unknown. The general phase was stopped after its remaining serial queue
was measured at roughly three hours. Cancellation did not print the
original assertion diff. The full command is failed/incomplete, not
passed. Remaining general files, workspace-project phases and 164
serialized files were not reached. Fresh final-head CI passes all
partitions.
- Final-head code CI passes. Greptile is 5/5 with its thread resolved.
Paperclip Review is delayed by an external review workspace recovery
failure; it has not completed on this head.
- Five serial alternating rounds per mode, 1,000 queries per sample, 40
retained samples, Node v24.22.2. Generic and unowned attribution rises
from 0/1,000 to 1,000/1,000 across two exact application anchors.
Specific owners stay stack-free.
- HTTP median wall cost is 10.528 → 15.169 µs/query; process CPU is
15.461 → 17.662 µs/query, with noisy overlapping ranges. This is census
overhead, not a product speedup.
- Review failure retained: the existing runtime bundler test first
failed because the public parser accepted arbitrary generated frames.
The fix restores default rejection and permits generated frames only
from the trusted builder boundary. The unchanged existing test now
passes.
- Full ranges, raw samples, proof boundaries and reproduction commands:
https://github.com/paperclipai/paperclip/blob/b270b92821ae47c456a1b61d78c1593c5348ede7/doc/performance/2026-11-03-db-capture-hosted-callers.md

## Risks

- Active generic HTTP census now captures stacks. More groups can reach
the existing 2,048-group cap sooner.
- Anchors identify construction sites in one exact generated build. They
do not identify later async consumers, TypeScript lines or CPU owners.
- Unscoped driver calls can remain unknown. This is intentional.
- The no-network local fixture excludes deployed Sentry/OTel stack
formatting and traffic effects. It does not establish exact hosted
overhead.
- Wrappers remain installed after expiry. Disabled, future and expired
windows do not capture stacks. No schema, authorization, provider, or
query behavior changes.

## Model Used

OpenAI GPT-6.1 Sol (`gpt-6.1-sol`) with reasoning, code execution and
repository tools. The host does not expose the context-window size.
Independent review 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
- [ ] 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-03 06:04:42 -06:00
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