Commit Graph
5155 Commits
Author SHA1 Message Date
DottaandPaperclip 33d24e48ad fix(skills): simplify source rows, errors, and actions (#16310)
## Thinking Path

> - Paperclip manages agent skills from GitHub repositories.
> - Skills → Sources shows saved repositories and their sync status.
> - A saved source gained a second repository row when other projects
used the same repository and branch.
> - That row repeated the GitHub icon and branch, and it exposed project
names that did not help with source management.
> - The page also repeated the Installed navigation link and showed
refresh errors as separate lines of text.
> - Connection management also appeared under each source, where it
competed with source-specific actions.
> - This pull request shows each saved source once, groups error
details, and moves connection management into the menu beside Import
from GitHub.
> - The result is a clearer source list that keeps import and recovery
actions available.

## Linked Issues or Issue Description

**What happened?**

When a saved source shared its repository and branch with other
projects, Skills → Sources displayed a second GitHub header and the
names of those projects. The page also displayed an extra Installed
skills link and repeated Manage GitHub connection under source rows. A
failed refresh placed its timestamp and error on separate lines.

**Expected behavior**

Show one row for each saved source. Keep project names out of that row.
Keep the additional import action available in More. Put connection
management in the page actions menu beside Import from GitHub. Present
refresh errors as one readable notice with the time and review action.

**Steps to reproduce**

1. Open Skills → Sources in a company with one saved GitHub source and
another project that uses the same repository and branch.
2. Observe the repeated repository row and project names.
3. Open the Storybook journey `Existing source, more projects` to
inspect the same state. Open `Retained skills and retry` to inspect a
failed refresh.

**Paperclip version or commit**

The issue is present on base commit `739f9e40a4`.

**Deployment mode**

Built from source. The issue was also observed in a staging workspace.

## What Changed

- Remove project names, the duplicate repository row, and the redundant
Installed skills link from saved source rows.
- Put imports for additional projects in the source More menu. Show
brief import progress in the source metadata.
- Group source errors, attempt time, and the review link in a compact
notice. Add a Storybook journey and browser coverage for the
shared-repository state.
- Add a page actions menu beside Import from GitHub. Put Manage GitHub
connection there and remove the repeated inline links. Cover the menu
and keyboard focus in the Storybook browser suite.

## Verification

- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, `node
scripts/check-maps.mjs`, and `node scripts/storybook-catalog.mjs
--check` passed locally. The Skills sources unit suite passed 22 tests.
- All 18 repository-skills Storybook browser tests passed, including the
shared-source import, connection menu, mobile, and failed-refresh
journeys.
- A local full `pnpm test:run` was stopped after a server runner-API
test timed out. An isolated diagnostic identified macOS embedded
PostgreSQL shared-memory exhaustion. The PR passed all 55 CI checks,
including server test shards and end-to-end tests.
- Open the Storybook journeys `Existing source, more projects`,
`Automatically imported skills`, and `Retained skills and retry` to
inspect the compact source row, page actions menu, and grouped error
notice.

## Risks

Low risk. The visible import action for projects that share a saved
source moves to More. Connection management moves to a page menu and
opens the Apps catalog. People must open those menus to find the
actions. The import API and access checks do not change.

> I checked `ROADMAP.md`. This source-list correction does not duplicate
planned core work.

## Model Used

OpenAI Codex, GPT-6 family. The task runtime did not expose an exact
serving model ID or context-window size. The model used tool calls, code
edits, and browser verification.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 12:52:18 -05:00
Devin FoleyandPaperclip 5b29b9062e fix(server): compact finished task worktrees and shorten the reaper cooldown (#16304)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Each task can run in its own isolated Git worktree, and each
worktree installs its own dependencies
> - The terminal-workspace reaper removes a worktree only when the task
tree is finished, the delivery is merged, the files are clean, and a
7-day cooldown has passed
> - A recurring task that runs every hour keeps a week of worktrees, and
each worktree holds gigabytes of `node_modules`. A finished task with no
merged pull request, or with leftover agent files, keeps its worktree
forever
> - On a busy instance this fills the disk in days, and a larger volume
only delays the next failure
> - This pull request adds compaction: one hour after a task tree
finishes, the reaper removes regenerable directories from the worktree
and keeps the workspace, the branch, and all source changes
> - The benefit is that finished tasks stop holding gigabytes of disk,
and no work is lost because a resumed task regenerates the files when
its workspace is provisioned again

## Linked Issues or Issue Description

Refs #2022 (retention for workspace cleanup). Related: #11936 and #14608
add external reclaim scripts (a scheduled tool and a disk-guard step).
This pull request does the reclaim inside the server's
terminal-workspace reaper instead. That way it uses the reaper's
lifecycle lock, issue-tree checks, and live-run checks, and needs no
extra scheduler.

**What existing behavior does this improve?**
Disk retention of execution workspaces after their tasks finish.

**Current behavior**
A finished task keeps its full worktree, including installed
dependencies and build output, for at least 7 days. If the delivery is
not merged, or the worktree has uncommitted or untracked files, the
reaper never removes it. On one instance, an hourly recurring task
created about 22 worktrees per day at about 3 GB each (about 2.8 GB of
that was `node_modules`). Together with finished tasks that had no
merged pull request, they filled a 100 GB volume in about two days.

**Proposed behavior**
One hour after a task tree becomes terminal, the reaper removes
regenerable directories (installed dependencies, build output, tool
caches) from the worktree. It keeps the worktree, the branch, the
commits, and every tracked, untracked, or other ignored file. When the
task resumes, the existing reuse path runs the provision step, which
reinstalls the dependencies. Clean, merged worktrees are archived after
1 day instead of 7.

**Reason and benefit**
Most of a finished worktree's size is regenerable. Compaction removes
that part without the risk of deleting work, so it can apply to
workspaces that the reaper must keep (no merged pull request, leftover
files). The shorter cooldown limits the cost of the source checkouts
that stay.

**Breaking changes**
None. The default archive cooldown changes from 7 days to 1 day.
`PAPERCLIP_WORKSPACE_REAPER_COOLDOWN_DAYS` still overrides it.
`PAPERCLIP_WORKSPACE_COMPACTION_ENABLED=false` turns compaction off.

## What Changed

- New `server/src/services/workspace-compaction.ts`:
- Finds directories with a regenerable name (`node_modules`, `dist`,
`build`, `coverage`, `storybook-static`, `target`, `.cache`, `.next`,
`.nuxt`, `.parcel-cache`, `.svelte-kit`, `.turbo`, `.vite`).
- Keeps only the directories that the repository's own `.gitignore`
files ignore and that hold no tracked file. A negated pattern
(`!build/`), a global excludes file, and `.git/info/exclude` do not
count. Each candidate is checked per path, so dependencies below an
ignored parent (`vendor/tool/node_modules`) are found.
- Searches inside a regenerable-named directory that does not qualify
(for example a tracked `build/`), so its ignored dependencies still go.
- Never enters `.git` or `.paperclip` (the worktree instance data), and
never follows a symlink.
- Each Git read has a 60-second deadline and stops when the sweep is
aborted.
- Moves the directories into `.paperclip-compaction-trash` beside the
worktree with a same-filesystem rename, and can restore them.
- `sweepTerminalWorkspaces` compacts each terminal workspace once per
terminal cycle, after the compaction delay and before the archive
cooldown check:
- Only isolated linked Git worktrees qualify. A shared workspace, a
project's main checkout, or a row whose `.git` is a directory is never
compacted.
- The move runs inside a transaction that holds the workspace lifecycle
lock. The guard checks a fresh row and the same lifecycle generation. It
also checks that the issue tree is terminal, that no queued or running
run works on the tree or the workspace (by checkout or execution run, or
by run context), and that no runtime service runs from the workspace.
- The guard runs before the move and again after it. If the second check
fails (for example, the task reopened or a run started), the directories
move back. Otherwise the trash is deleted.
- The worker wakes at the compaction deadline, not only at the archive
deadline.
- Stale trash from an interrupted compaction or a failed delete is
purged by later sweeps. The sweep checks each worktree parent at most
every 30 minutes, whether or not anything is left to compact.
- New counters `compacted` and `compactionFailed` in the sweep result.
The activity log gets an `execution_workspace.regenerable_files_removed`
entry with the removed paths.
- Config: new `PAPERCLIP_WORKSPACE_COMPACTION_DELAY_HOURS` (default `1`)
and `PAPERCLIP_WORKSPACE_COMPACTION_ENABLED`. The default for
`PAPERCLIP_WORKSPACE_REAPER_COOLDOWN_DAYS` changes from `7` to `1`. Both
new keys are added to the run-failure diagnostics allowlists.
- Docs: `doc/DEVELOPING.md` documents the new variables and has a new
"Terminal workspace compaction" section. `doc/SPEC-implementation.md`
describes compaction.
- `execution-workspaces.ts` was already above 1,000 lines. The
file-system logic is in the new module. Only the guarded orchestration,
which uses the existing lifecycle lock and run predicates, is in the
service.

## Verification

- `pnpm exec vitest run src/__tests__/workspace-compaction.test.ts
src/__tests__/execution-workspace-compaction.test.ts` (in `server/`): 27
passed. `workspace-reaper-cooldown-config.test.ts`: passed.
- Unit tests: directory selection (ignored, untracked, regenerable name
only, `.env` and local data kept, tracked `coverage` kept, `.paperclip`
skipped, symlinks not followed), nested candidates under a source
`build/` and under an ignored `vendor/`, a negated `!build/` kept,
global and `info/exclude` rules ignored, glob characters in names,
abort, main checkout vs linked worktree, move and restore, restore that
keeps a recreated directory, and stale-trash purge.
  - Embedded Postgres tests:
- A no-PR, unmerged, dirty workspace is compacted. HEAD, the branch ref,
`git status --porcelain --untracked-files=all`, untracked notes, `.env`,
local data, and `.paperclip` data stay the same, and the row stays
active.
    - A delivered workspace inside the cooldown is compacted.
    - The delay is respected, and the worker wakes at the delay.
- An active checkout run, a queued run found through its context, an
unfinished child issue, and a running runtime service all block
compaction.
- The task reopens during the move: the files are restored and
unchanged.
    - A run starts during the move: the files are restored.
    - A shared workspace and a main checkout are never compacted.
- Compaction runs once per terminal cycle and again after a later cycle.
    - Disabled compaction does nothing.
- End to end: `realizeExecutionWorkspace` creates a worktree, the sweep
compacts it, and a second `realizeExecutionWorkspace` reuses the same
worktree. The provision command regenerates `node_modules`, and the
untracked notes and the unmerged commit are still present.
- Leftover trash is purged when the workspace has nothing left to
compact.
- Mutation checks: when the post-move guard is disabled, both race tests
fail. Without the negation fix or the repository-only source fix, their
tests fail.
- `pnpm exec vitest run` for `execution-workspaces-service.test.ts`,
`terminal-workspace-work.test.ts`, `execution-workspace-reopen.test.ts`,
`server-startup-feedback-export.test.ts`, and
`workspace-runtime.test.ts`: 335 passed. Two `workspace-runtime.test.ts`
cases fail locally with and without this change (`does not diagnose a
missing remote branch as a rejected credential`, `rejects explicit main
on a master-only remote ...`). They also fail on unmodified `master` on
the same machine, so the cause is the local Git environment.
- `pnpm typecheck` in `server/`: passed. `pnpm check:module-boundaries`:
passed.

## Risks

- A repository can keep something that is not regenerable in an ignored
`dist`, `build`, `target`, or `.cache` directory. Compaction removes it.
The fixed name list, the ignore check, and the tracked-file check limit
this. `PAPERCLIP_WORKSPACE_COMPACTION_ENABLED=false` turns compaction
off.
- A repository without a provision command does not get dependencies
back automatically. This is the same state as a new worktree for that
repository, where the agent already installs them.
- A resumed task pays for a dependency install again. This happens only
for tasks that finished more than an hour earlier.
- The shorter default cooldown removes clean, merged worktrees after 1
day instead of 7. An operator who wants the old hold can set
`PAPERCLIP_WORKSPACE_REAPER_COOLDOWN_DAYS=7`.
- Self-hosted instances get the same behavior. There is no schema
change.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), 1M context, through Claude Code
with tool use (shell, file edits, test runs). A separate Claude agent
read the reaper code during the diagnosis.

## 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
- [ ] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.11
2026-10-14 09:49:04 -07:00
DottaandPaperclip adb69e8f09 feat: default new Codex agents to Paperclip Runner on Linux and macOS (#15683)
## Thinking Path

> - Paperclip is the open source control plane for agent companies.
> - People choose a harness when creating an agent.
> - The server should resolve that harness to a qualified runner.
> - Codex is the first harness in the staged default rollout.
> - Saved agents must retain their execution choices.
> - New Codex agents therefore use Paperclip Runner on qualified
macOS/Linux targets, with an explicit Legacy override.

## Linked Issues or Issue Description

Refs #16028, #15555, #15673, #15422, #15631, #15926, #15932, #16149.

The runtime/install prerequisite and release repair are merged. This
slice owns Codex creation, setup, configuration and preservation. Other
harness defaults remain unchanged. It adds no database migration;
incoming master migrations, required maps and regression coverage are
retained.

## What Changed

- Resolve `runner: auto | paperclip | legacy` at the common creation
boundary across onboarding, API/CLI, hires, built-ins, plugins and
imports. Freeze pending hires and export resolved execution choices.
- Preserve existing runners on upgrades, unrelated edits and import
updates, including compatible accounts, workspace settings, Codex effort
and intentional clears.
- Use the underlying harness picker and branding; put the runner
override in Advanced. Use the shared dropdown and update
production-component stories and creation contracts.
- Support qualified Apple Silicon, Intel Mac, Linux x64 and Linux ARM64.
Linux requires GNU libc 2.39+. Disabled, external, unsupported and
unqualified combinations retain their applicable Legacy execution.
- Test the selected runtime/account/model/environment. Ordinary Connect
probes eligible immutable managed targets and refreshes scoped
discovery. Creation/discovery do not provision. Auth, dependency,
incompatible-setting and cleanup failures remain actionable without
changing runners.
- Keep setup probes read-only, preserve local/SSH isolation and resolve
packaged assets before staging credentials. Bound cleanup reads by the
remaining absolute deadline; physically close every owned ingress socket
before endpoint release. Unconfirmed cleanup retains recovery state.
- Preserve validated completed-onboarding callbacks through startup
recovery. First file-producing work belongs to the child task and uses
the existing dependency/block handoff and task-scoped registration.
- Reuse existing E2E fixtures, artifact checks, reporting and controls.
Keep Docker/Cargo/native compilation remote. Paperclip tarballs contain
no Codex payloads; official optional npm platform dependencies remain.

## Verification

Current tested head: `1c03a8815672d82c264a9b08d4ea1984e8fae107`.
**Merge-ready: required CI, fresh review, package qualification, Mac
core acceptance and Test task/follow-up acceptance pass.** The existing
attachment and native-continuity oracles independently verify both Test
downloads, run attribution and unchanged native/provider/workspace
identities. The maintainer authorized a code-owner-review exception for
this PR only. The first Test setup failure and normal Board
completion-review friction are retained below. Actual post-merge
packages and private Cloud distribution remain separate qualification
gates.

- [Current
CI](https://github.com/paperclipai/paperclip/actions/runs/38564241625):
all 48 ordinary jobs and required verify/E2E pass. Attempt 1 retained
six simultaneous host-shutdown cancellations. One failed-only retry
passes those six lanes and two aggregates, preserving 40 successes.
Actual integration checkout `53104c1` combines this head with master
`c80`; it is not relabeled as the branch tree. Fresh exact-head Greptile
5/5, 30 resolved threads, no actionable findings.
- [Exact-source package
qualification](https://github.com/paperclipai/paperclip/actions/runs/38565287239):
nine applicable jobs pass, nine conditional jobs skip. Four remote
native producers; Linux x64 clean install; Intel Mac, Apple Silicon and
Linux ARM64 native startup/physical cleanup controls. All 18
tarballs/four daemon source/hash/manifest bindings and 343 migrations
through 0344 verify. No Codex payload is packed. These hosted tarballs
are not a published npm canary.
- Normal Apple Silicon installation and credential-free native
startup/cleanup pass using the packaged daemon, with no source build or
provider turn. Fresh installed DB initialization passes. Upgrade
651a→1c03 preserves all three complete execution configs, accounts, ten
recorded run profiles, paused budgets, active incidents, cost summaries
and two historical unpriced events. Historical recovery state is
retained.
- Cleanup regressions: four delayed-read baseline failures become 15
passing deadline/authority controls. No-acknowledgement and prior-error
socket ownership regressions become 12 passing controls. Direct
runtime/server types, maps: 35 areas / 176 IDs, diff checks and
independent reviews pass. Permission/auth/reconnect policy and the
10-second setup budget remain intact.
- Existing source coverage includes creation/selection/imports, pending
approvals, recovery, account/lifecycle handling, mounted forms,
dropdowns and E2E support. Full typechecks/tests/build/token and
applicable Storybook checks pass in the recorded current CI; no
duplicate suite or weakened grader.
- Literal 9546 live Mac proof: ordinary Auto Codex onboarding, useful
document, real completed-child callback/reply, seven successful native
runs, manual follow-up and independently downloaded1,101-byte child
file. Existing Legacy title edit/reload preserves execution; two real
Legacy runs produce independently checked15/34-byte files. These remain
historical source records.
- Current literal 1c03 Mac core acceptance passes independent checks:
ordinary Auto native Codex onboarding without runner override; only
timeout 180 seconds/concurrency 1 saved; six successful native runs and
six serialized turns (maximum overlap 1); both same-task continuity
checks and five mechanical callback checks; actual rendered parent reply
and exact child downloads. The useful handoff advances from revision 1
to 2. Both files are 48 bytes, SHA-256
`8b742bd4e8123a7c078f0a8d9f3449fbfa8a320d7d90be641a2818db3c53d92c` and
`f42db9774fa06e804ab7d596fc8b922a2b638921c418b87d0111151d290a6afe`;
exactly one byte changes and old history remains. The agent is paused
with zero active runs/errors. Both artifact work products have
`isPrimary=false`, and descriptive titles fail a stricter title-helper
assumption; these retained results are scoped editorial follow-up, not
new merge gates. Six source-bound screenshots are uploaded and verified
in the private primary QA report.
- [Literal 9546 managed
proof](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-38485488621-1/index.html):
original 19 assertions and completed judge pass, four native turns,
child-bound240-byte file and session/workspace continuity. Checkout
reports a verified generated target-lock mutation; full final porcelain
was not retained. Signed execution-image identity remains separate from
Core source.
- Actual 651a Test deployment succeeds on one owned/pinned target. One
ordinary Auto API-key Connect then fails native cleanup before hire.
Controller turn/drain/suspend completion and service-recorded
environment cleanup are observed; they do not certify physical deletion
or native authority retirement. Failure/recovery/unknown holds are
retained. No Legacy switch or unchanged paid retry. The two source
repairs above require actual treatment.
- [Current immutable Core
preview](https://github.com/paperclipai/paperclip/actions/runs/38570365725)
and matching DB/shared artifacts pass. One owned, pinned Test target
serves exact `1c03`; identical migration history correctly skips the
migrator. Ordinary Auto Codex Connect succeeds and hires native; saved
native selection and QA bounds survive reload. The initial child
preparation attempt fails before provider work, with actual stdout
identifying `renewal_deadline`; its trigger remains unknown and the
failure is retained. Normal Board **Try again** and **Resume** recover
the child to Done, producing a browser-verified 44-byte file, SHA-256
`0a8458b1efcc2d7a0d815689458c4caab039a46c7c7a3e5805de6bc8b1a96ecc`. The
actual parent callback reports the completed child document/file. The
existing validator requires a parent-owned attachment, so recovery
enters normal Review; after byte checking, normal **Approve completion**
reaches parent Done. No forced status or duplicate parent file is used.
The validator is unchanged from integrated and current master.
Autonomous initial callback-to-Done is not proven. The same-child
follow-up completes document revision 2 and publishes a second
independently downloaded 44-byte file, SHA-256
`22022257300fae762784632d08d3bbe0bab61e2ce81f91864a14dcd7aa464591`; only
the revision digit changes. The unchanged existing native-continuity and
attachment oracles pass. All ten recorded runs are terminal: nine native
successes and the retained pre-provider setup failure. The QA agent is
paused with zero active runs. The pre-existing parent evidence scope
mismatch is a separate follow-up, with ordinary completion review
exercised rather than a forced status or relaxed validation. This
unsigned Core preview remains distinct from post-merge private Cloud
composition.

## Risks

- Saved agents are not migrated. Explicit runner changes use normal
configuration/session rules; historical runs retain their recorded
execution.
- Native readiness depends on verified assets and server-owned target
qualification. A Legacy probe, HTTP200 or successful account save cannot
prove native readiness.
- Recovery exceptions remain restricted to validated
completed-onboarding reports; process-loss, ownership and terminal-state
safeguards remain active. Unexecuted live journeys stay open.
- Linux ARM paid tasks, Windows, Alpine and 32-bit ARM remain deferred.
Cold Cargo cache misses are recorded; no warm-cache speedup is claimed.
- Historical invoices/physical cleanup remain unconfirmed and held.
After merge, exact published npm canary, signed standard image/migrator,
private composition and serving/live acceptance still require
qualification. Production deployment/default promotion is not
authorized.

## Model Used

OpenAI Codex, GPT-6 family, with reasoning, tools, code execution and
parallel agents. Exact serving snapshot and context-window size are not
exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used with available version and
capability details
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have linked public issues or PRs above
- [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 the stated focused tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation
- [x] I have considered and documented risks
- [x] All Paperclip CI gates are green on the current candidate
- [x] Greptile is 5/5 with no open findings on the current candidate
- [x] I will address all reviewer comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 11:33:02 -05:00
DottaandPaperclip 739f9e40a4 docs(skills): add slow-query diagnosis and fix skill (#16303)
## Thinking Path

> - Paperclip helps people manage agents that work across tasks and
services.
> - Slow pages and background work can come from expensive or repeated
database queries.
> - The query often starts in the Paperclip app while its evidence lives
in Paperclip Cloud, Neon, and application logs.
> - A useful fix must reproduce the slow SQL locally and preserve its
complete results and user behavior.
> - The procedure also needs to measure any exceptional migration on a
database of realistic size.
> - This pull request gives contributors a repeatable skill for that
work and for carrying the fix through PR checks.
> - The benefit is a clear, measured handoff with fewer query
regressions and fewer risky migration proposals.

## Linked Issues or Issue Description

**Issue type**

Missing documentation.

**Where is the issue?**

`.agents/skills/` has no shared procedure for diagnosing and fixing slow
Paperclip queries across Cloud and Neon.

**What's wrong?**

A contributor must reconstruct the path from a slow workspace to its
database, capture the service's actual SQL, reproduce it locally,
compare complete results, and track the PR through review and CI. That
makes it easy to mistake cumulative statistics for a recent request
trace or a faster but changed result for a valid fix.

**Suggested fix**

Add a project skill that covers discovery, baseline and treatment
benchmarks, regression checks, migration constraints, and PR
follow-through.

Related work: #16278, #16286, and #16291 supplied the query cases and
local benchmark lessons. No existing slow-query skill PR or issue
appeared in the duplicate search.

## What Changed

- Add `fix-slow-queries` with a bounded workflow from Cloud discovery to
a reviewed PR.
- Add references for locating the right Neon database and for measuring
full service SQL against complete output comparisons on disposable
PostgreSQL.
- Require a serious reason for migrations, prohibit boot-time migration
workarounds, and require production-size timing and escalation for slow
migrations.

## Verification

- Run the skill-creator `quick_validate.py` against
`.agents/skills/fix-slow-queries`: passed.
- Run `pnpm --filter @paperclipai/skills-catalog test`: 5 files, 20
tests passed, including the repo-wide skill-description budget check.
- Check all five local Markdown links, metadata length, final newlines,
and whitespace: passed.
- Run `git diff --check`: passed.
- Review the documented procedure against the cases in #16278, #16286,
and #16291: baseline helper isolation, large JSON, older deep links, and
latest-commit PR checks are covered.
- This change adds instructions only. It changes no database schema or
runtime behavior.

## Risks

- Provider menus and private Cloud file locations may change. The skill
requires contributors to verify the current stack mapping and owning
repository before using them.
- Synthetic benchmarks do not establish deployed latency. The skill
requires a fresh deployed measurement when rollout is authorized.

## Model Used

OpenAI GPT-6 via Codex, with tool use and code execution. The served
model variant and context window were not exposed to this task.

## 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.1014.0-canary.10
2026-10-14 11:03:16 -05:00
DottaandPaperclip 21ee5c9c85 feat(sentry): add opt-in run failure reporting with saved run references (#16300)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agent runs retain execution results and output in the instance.
> - Operators can report run failures to Sentry for investigation.
> - A backend Sentry DSN currently enables those reports with no
separate choice.
> - A repair bot also needs the exact instance, company, agent, and
saved run.
> - This pull request adds an explicit reporting mode and authenticated
run references.
> - The benefit is that operators can investigate every failure on
selected deployments while keeping other deployments quiet.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Optional server reporting of terminal agent run failures to Sentry.

**Current behavior**

A backend DSN enables run failure reports. Known account, quota, and
connection failures are excluded. Reports omit company and agent
references. Runs without a task are skipped. Tool-name collision errors
omit the conflicting bindings.

**Proposed behavior**

Set `PAPERCLIP_SENTRY_RUN_FAILURES=unexpected` to retain the existing
filters. Set it to `all` to report every failed or timed-out run,
including known setup and quota failures. The default is `off`. Expected
stops stay excluded. Each report supplies identifiers and API paths that
a bot can use with its own authorized Paperclip connection.

**Reason and benefit**

Operators can enable broad failure reporting on one staging deployment.
A bot can fetch the saved run, events, and logs instead of relying on a
short error label or copying complete transcripts into Sentry.

**Breaking changes**

A backend DSN alone no longer enables run failure reports. Existing
operators must set `PAPERCLIP_SENTRY_RUN_FAILURES=unexpected` to retain
the previous policy. Ordinary server exception capture remains enabled
by the DSN. Failure grouping gains the phase and original cause code
when available.

Refs #16281, #16297, #16298. These cover related tool discovery and
failure diagnostics. This change retains their existing boundaries and
does not depend on their open changes.

## What Changed

- Add `off`, `unexpected`, and `all` modes. Missing and invalid values
keep reporting off before diagnostic reads.
- Keep the Sentry backend DSN and audited optional SDK requirements.
- Include company, agent, run, and optional task identifiers. Include
versioned paths for the saved run, events, log, and task. Add absolute
run URLs only for a valid public HTTP(S) origin.
- Report company runs without a task. Prefer the first-class issue
binding when selecting the task reference.
- Select saved native provider/model settings, timestamps, and original
failure codes. Preserve gateway reason codes through redacted exception
projection.
- Group by error code, adapter, and available phase/cause. Keep run IDs
and error text out of grouping.
- Include the tool names and connection bindings in collision errors
without copying tool schemas or provider metadata.
- Document configuration, upgrade behavior, bot access, redaction,
retention, and best-effort delivery.

## Verification

- All 56 checks passed for `cccb47a721eaa1cc36e63278fc177b9101477541`.
Two unrelated Storybook jobs were skipped by their path filters. No
checks remain pending.
- Complete [Paperclip CI
run](https://github.com/paperclipai/paperclip/actions/runs/38591422284):
passed. This covers general and serialized tests, Runner checks, browser
E2E shards, typecheck, build, release-registry checks, canary dry run,
and Docker checks.
- Greptile reviewed that exact head: 5/5, with no unresolved threads or
actionable findings. Superagent, Socket, and Snyk checks passed.
- Local focused reporting, diagnostics, collision, and real SDK contract
tests: 410 passed across five suites. This includes the external-wake
filter in both reporting modes.
- The audited `@sentry/node@10.71.0` tests use an in-memory transport.
No events were sent to Sentry.
- `pnpm -r typecheck` and `pnpm build`: passed locally after the final
rebase.
- `node scripts/check-module-boundaries.mjs` and `git diff --check`:
passed.
- The full local `pnpm test:run` command was stopped to avoid
duplicating the complete CI shards. It did not finish locally. The full
suite passed in CI.

## Risks

- The new default disables existing run failure exports until the
operator selects a mode. The upgrade setting is documented.
- `all` can increase event volume and include known user-action
failures. Secret redaction and diagnostic limits still apply.
- Reporting remains asynchronous and best effort. This PR adds no
durable delivery queue and does not install a bot or Sentry alert rule.
- API references grant no authority. Existing company, private-task, and
run-output checks still apply. Complete transcripts stay in Paperclip.
- This changes optional Sentry error reporting. It changes neither
first-party Telemetry nor OpenTelemetry span exports. It adds no
database migration.

## Model Used

- OpenAI GPT-6 through Codex, with reasoning, shell, file editing, and
test execution. The exact backend deployment ID and context window are
not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:56:40 -05:00
DottaandPaperclip 09a2f0b7b0 refactor(server): isolate provider message admission and runtime policies (#16289)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn external messages into shared task workflows.
> - The main service still contains some provider decisions.
> - These decisions belong with the existing channel modules.
> - This pull request isolates provider message-admission and runtime
policies.
> - Shared authorization, persistence, and runtime ownership keep their
current order.

## Linked Issues or Issue Description

Refs: #16235. Stack part 3/3. Base: `master`. #16276 and #16283 are
merged.

**What existing behavior does this improve?**

Provider ownership and readability in the chat channel service.

**Current behavior**

The entry point combines shared workflows with provider decisions.

**Proposed behavior**

Provider modules own their decisions. Shared modules own product state
and authorization.

**Reason and benefit**

Maintainers can find provider behavior in its channel folder.

**Breaking changes**

None intended. Public service methods and durable data shapes stay
compatible.

## What Changed

- Move Discord SDK admission and its barrier to the Discord message
module.
- Move Photon live-message eviction and startup recovery policy to its
runtime callbacks module.
- Move Slack mention eligibility and Teams setup-channel eligibility to
their message modules.
- Keep Photon deferred ingress and Speko conversation policy with their
provider modules.
- Keep ordered SDK message batching in a shared runtime module with a
live per-message ingress callback.
- Keep receiver leases, cache lifetime, startup failure cleanup,
authorization locks, and transaction ownership shared.
- Reduce `chat-channels.ts` from 3,570 to 3,548 lines.

## Verification

- The same 46 runtime/admission integration cases and all 18 Photon
channel cases passed before and after in the owned Linux container.
- The existing first-channel Teams orphan-admission case passed before
and after moving its eligibility predicate.
- The same 94 SDK adapter and lifecycle-normalization tests passed
locally.
- Server typecheck and module-boundary checks passed.
- Token comparison confirms ordered SDK batching and every processor
argument, plus Photon invalidation and its live runtime lookup.
- The shared factory creates no cache or worker. It reads the ingress
policy for each message and awaits processing in order.
- The extraction rebased without conflicts onto master after #16276 and
#16283 merged. Git range-diff reports the same patch. Final head
`7b63b569e2a0dbcc959310f565f77f367fa64aa0` has the same patch by
range-diff. The 94 SDK/lifecycle tests, server typecheck, and boundary
check passed on the final head. All CI gates pass on that exact head.
Greptile reviewed it at 5/5 with no inline findings or unresolved review
threads.
- One Runner CI test failed its original short timing window. The
unchanged test passed earlier-head CI and local reproduction. The single
failed-job retry passed.
- Cumulative `pnpm -r typecheck` and `pnpm build` passed. All 1,321
channel integration cases passed. The normal UI, CLI, database, adapter,
plugin, and serialized API test selections ran.
- The first Linux `pnpm test:run` returned 1. Original-source runs
reproduced the local failures. Container-only repairs supplied missing
tools, process reaping, and sufficient Node heap. The existing
mocked-fetch CLI telemetry fixture passed with the image opt-out flag
overridden only for that fixture.
- One local venue limitation remains: adapter-utils T24 fails unchanged
on both original and final source in the Linux container. Its entire
56-case suite passes before and after on the host. All other failed or
aborted suites passed in repaired reruns. No test assertion or timeout
changed.
- These fixtures prove application integration. They do not prove live
provider execution.

## Risks

- A captured option value or changed callback order could affect
deferred ingress or stale-runtime handling.
- The ingress callback and runtime getter remain live. Core maps and
receiver lease operations keep one owner.
- No schema migration or public API change is included.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:50:34 -05:00
DottaandPaperclip 7df55f3dcc refactor(server): isolate provider webhook lifecycle decisions (#16283)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn external messages into shared task workflows.
> - The main service still contains some provider decisions.
> - These decisions belong with the existing channel modules.
> - This pull request moves webhook recovery and payload-scope decisions
to their provider modules.
> - Shared authorization, persistence, and runtime ownership keep their
current order.

## Linked Issues or Issue Description

Refs: #16235. Stack part 2/3. Base: `master`. #16276 is merged.

**What existing behavior does this improve?**

Provider ownership and readability in the chat channel service.

**Current behavior**

The entry point combines shared workflows with provider decisions.

**Proposed behavior**

Provider modules own their decisions. Shared modules own product state
and authorization.

**Reason and benefit**

Maintainers can find provider behavior in its channel folder.

**Breaking changes**

None intended. Public service methods and durable data shapes stay
compatible.

## What Changed

- Move GitHub revoked-installation recovery classification to
`github/webhook-scope.ts`.
- Move Teams payload-scope validation to its message module.
- Record normalized GitHub, Telegram, and Teams lifecycle events through
one shared durable call.
- Keep Slack callback ordering and persistence failures outside parser
catches.
- Reduce `chat-channels.ts` from 3,598 to 3,570 lines.

## Verification

- The same 86 selected webhook/lifecycle integration cases passed before
and after in an owned Linux container.
- The same 17 selected Telegram edit and Teams edit/delete/restore cases
passed before and after in that container.
- The same 94 SDK adapter and lifecycle-normalization tests passed
locally before and after.
- Server typecheck and module-boundary checks passed.
- Token comparison confirms the shared recording payload and runtime
fence, plus the Teams scope and parser inputs.
- The host database baseline failed before assertions because System V
shared-memory IDs were exhausted. No other PostgreSQL server or host
setting was changed. Database verification used an isolated container
under its unprivileged user.
- The extraction rebased without conflicts after #16276 merged. Git
range-diff reports the same patch. The 94 SDK/lifecycle tests and server
typecheck passed on this base. All CI gates pass on rebased head
`d835d7c3815c168226fa646aec6370b6a8ac94c1`. Greptile reviewed that exact
head at 5/5, with no inline findings or unresolved review threads.
- Cumulative `pnpm -r typecheck` and `pnpm build` passed. All 1,321
channel integration cases passed. The normal UI, CLI, database, adapter,
plugin, and serialized API test selections ran.
- The first Linux `pnpm test:run` returned 1. Original-source runs
reproduced the local failures. Container-only repairs supplied missing
tools, process reaping, and sufficient Node heap. The existing
mocked-fetch CLI telemetry fixture passed with the image opt-out flag
overridden only for that fixture.
- One local venue limitation remains: adapter-utils T24 fails unchanged
on both original and final source in the Linux container. Its entire
56-case suite passes before and after on the host. All other failed or
aborted suites passed in repaired reruns. No test assertion or timeout
changed.
- These fixtures exercise application state and the service entry point.
They do not prove live provider execution.

## Risks

- A scope or ordering error could record an event for the wrong provider
context.
- The selected parser returns normalized data. The shared service keeps
durable recording and runtime fencing.
- No database migration or API change is included.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:38:12 -05:00
DottaandPaperclip 74ba530b9e fix(workspaces): keep cleanup Git scans fresh and dedupe page reads (#16302)
## Thinking Path

> - Paperclip manages execution workspaces for agent tasks.
> - It must preserve work when it closes a workspace.
> - The terminal-workspace worker checks Git before it decides whether a
workspace can close.
> - A request for fresh Git status could join a scan that started before
a file changed.
> - Several records for one directory can also repeat the same Git work
in a bounded page.
> - The worker already reads the task tree before Git, then reads it
again for delivery assessment.
> - This pull request fixes the fresh-read boundary and removes those
repeated reads.

## Linked Issues or Issue Description

- Refs #14759 and #14423 for the background Git scan load.
- Refs #16282 for the merged event-driven terminal-workspace worker.
- Refs #13619 for the original community investigation and tests. Thanks
to @fayonation for identifying the shared-directory and in-flight scan
cases. This implementation starts from current master and adapts those
ideas to the new worker.

## What Changed

- Give correctness-sensitive Git status requests their own scheduler
scan. They skip completed cache entries and older scans in progress.
- Share compatible Git readiness results across workspace records in one
bounded worker page. The key includes company, path, branch, base ref,
and runtime ownership. Each record keeps its own task and delivery
assessment.
- Reuse the task tree already read by the worker during delivery
assessment.
- Add regression tests for a file created during an older scan,
compatible scan sharing, and company and branch separation. Update
developer and workspace map documentation.

## Verification

- `pnpm exec vitest run
server/src/services/workspace-git-operation-scheduler.test.ts
server/src/__tests__/execution-workspaces-service.test.ts` — 92 tests
passed.
- `pnpm -r typecheck` — passed with the repository's pnpm 9.15.4.
- `node scripts/check-maps.mjs` — passed.
- `pnpm build` — passed.
- The full local `pnpm test:run` was interrupted when its original
worktree disappeared. All PR test shards passed in GitHub CI.
- Latest commit `e7622127c7d978a9a90857112675834725965d72`: 53
successful PR checks, 2 expected skips, and no failures. Greptile
reviewed this commit at 5/5 with no open findings.

## Risks

- A shared page inspection can become stale if the directory changes
before the next record is assessed. The final cleanup still starts a
separate Git scan and checks current task, ownership, and lifecycle
state under the existing guards.
- The new scan key changes request coalescing for correctness-sensitive
callers. They still use the scheduler's concurrency and queue limits.
There is no database migration or API change.

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

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:36:41 -05:00
bcfc03bc94 fix(sentry): keep provider-rejected Grok wakes out of run failure reports (#16297)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Paperclip Runner can run an external Grok bot. Paperclip offers
the bot an assignment and sends a webhook wake. The bot must accept the
assignment in 10 minutes.
> - When the Grok endpoint rejects every wake with HTTP 4xx, the bot
never sees the work. The offer expires and the run fails with `Dot
assignment acceptance or execution authority expired.`
> - Paperclip already records each wake in `grok_bot_dispatches` with
its HTTP status. The operator sees the rejection and can retry it. Thus
Paperclip operates correctly in this case.
> - But `reportRunFailure` sends this run to Sentry as an unexplained
backend error. This makes noise and hides real defects.
> - This pull request skips the Sentry report only when durable receipts
prove that the Grok endpoint rejected every wake.
> - The benefit is a cleaner Sentry signal. Local defects, uncertain
delivery, and accepted work stay visible.

## Linked Issues or Issue Description

Sentry issue `PAPERCLIP-BACKEND-3M` (staging, 1 event).

**What happened?**
A Grok bot run on staging failed after 10 minutes in the `preparing`
stage. Sentry got the error `Dot assignment acceptance or execution
authority expired.` with the code `native_provider_terminal_failed`. The
stored receipts show two `mailbox_updated` wakes for the assignment. The
Grok endpoint rejected both wakes with HTTP 400: the first wake and one
operator retry. The assignment was never accepted. Wakes with the same
shape got HTTP 200 before and after this run.

**Expected behavior**
The run fails, and the operator sees the rejected delivery. Sentry does
not get a backend error for a proven external rejection.

**Steps to reproduce**
1. Connect a Grok bot agent and verify its routine.
2. Make the Grok endpoint return HTTP 400 for work wakes.
3. Assign a task to the agent and wait 10 minutes.
4. See that the run fails and that a Sentry event is sent.

**Paperclip version or commit**
`f69c6a8` (master).

## What Changed

- `server/src/services/run-failure-report.ts`: Add
`isRejectedExternalBotWake`. It returns true only when all of these
conditions are true:
- The run failed in native mode with `native_provider_terminal_failed`.
- The finalization `failureDetail.originalFailureCode` is
`dot_assignment_expired`.
- The run has exactly one Dot assignment, and that assignment was never
accepted.
- The assignment has at least one `mailbox_updated` wake, and each wake
has the status `rejected` with an HTTP 4xx status.
- `captureTerminalRunFailure` skips the Sentry capture when the check is
true. If the receipt check itself fails, it logs a warning and the
failure stays reportable. The run status, the task, and the operator
recovery do not change.
- `packages/db`: Add the index `grok_dispatch_assignment_kind_idx` on
`grok_bot_dispatches (assignment_id, kind)` (migration `0346`). The
receipt lookup and the dispatcher's per-assignment checks use this
index.
- `server/src/services/__tests__/run-failure-report.test.ts`: Add one
test for the skipped case. Add nine tests for cases that must stay
reportable: no wake, a local rejection with no HTTP status, a delivered
wake, uncertain delivery, accepted work, a different provider failure
code, no finalization, more than one offer, and a receipt read that
fails.

## Verification

- `pnpm --dir server exec vitest run
src/services/__tests__/run-failure-report.test.ts`: 208 tests pass.
- I removed the new catch and ran the tests again. The
receipt-read-failure test failed.
- `pnpm --filter @paperclipai/db run check:migrations` and
`src/migration-snapshot-drift.test.ts` pass.
- I removed the source change and ran the new tests again. The
skipped-case test failed and the six reportable cases passed. This shows
that the test proves the change.
- I did not run the full `pnpm -r typecheck` locally. The server
`typecheck` script needs `cargo` to build the Runner binary, and the
sandbox stopped `tsc` with SIGKILL. CI runs the full typecheck.

## Risks

- Low risk. The change only removes one Sentry report. It does not
change run state, recovery, or what users see.
- The check uses durable receipts, not message text. A wake with no HTTP
status (local validation or credential failure) stays reportable, so a
Paperclip defect cannot hide behind this rule.
- For failed native runs with `native_provider_terminal_failed`, the
check adds up to three indexed reads. Other runs do no extra reads.
- Migration `0346` builds one index in a transaction.
`grok_bot_dispatches` was created in `0344` and is small, so the build
lock is short. The table is not on the migration gate's large-table
list.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic. Agentic tool use with
shell, code search, 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

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

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:32:48 -07:00
14f961b698 fix(runner): report Runner disconnect age when a Dot bridge exits (#16296)
DurablePrpControlPlane records when the last authenticated Runner connection closes and exposes runnerDisconnectedForMs(). RunnerdDotDriver appends disconnectedMs=<n|none> to dot_runner_process_exited_recovery_required errors. Diagnostic only; authority, classification and recovery are unchanged.

Co-authored-by: Devin Foley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:26:32 -07:00
DottaandPaperclip f16c0ad5c8 refactor(server): isolate chat conversation and control policies (#16276)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn external messages into shared task workflows.
> - The main service still contains some provider decisions.
> - These decisions belong with the existing channel modules.
> - This pull request separates conversation binding and Telegram
control policy.
> - Shared authorization, persistence, and runtime ownership keep their
current order.

## Linked Issues or Issue Description

Refs: #16235. Stack part 1/3. Base: `master`.

**What existing behavior does this improve?**

Provider ownership and readability in the chat channel service.

**Current behavior**

The entry point combines shared workflows with provider decisions.

**Proposed behavior**

Provider modules own their decisions. Shared modules own product state
and authorization.

**Reason and benefit**

Maintainers can find provider behavior in its channel folder.

**Breaking changes**

None intended. Public service methods and durable data shapes stay
compatible.

## What Changed

- Keep shared conversation lookup and completion in
`inbound/conversation-binding.ts`.
- Move Photon binding-completion policy to its messages module.
- Move Telegram command classification, forum behavior, and chronology
exemptions to its commands module.
- Keep the original conversation generation separate from the retained
task binding.
- Reduce `chat-channels.ts` from 3,649 to 3,598 lines.

## Verification

- The same 62 selected Telegram/Teams integration cases passed before
and after extraction.
- All 18 Photon channel integration cases passed before and after
extraction in separate test processes.
- The initial combined baseline command had a Photon database-startup
hook timeout. No Photon assertion ran in that invocation. The unchanged
Photon suite then passed in isolation with its existing timeouts.
- Server typecheck and the module-boundary check passed.
- A token comparison confirms the moved lookup, completion, and
generation logic, after normalizing the explicit policy callbacks.
- All current-head CI checks passed. Greptile reviewed this exact head
at 5/5 with no findings.
- Cumulative `pnpm -r typecheck` and `pnpm build` passed. All 1,321
channel integration cases passed. The normal UI, CLI, database, adapter,
plugin, and serialized API test selections ran.
- The first Linux `pnpm test:run` returned 1. Original-source runs
reproduced the local failures. Container-only repairs supplied missing
tools, process reaping, and sufficient Node heap. The existing
mocked-fetch CLI telemetry fixture passed with the image opt-out flag
overridden only for that fixture.
- One local venue limitation remains: adapter-utils T24 fails unchanged
on both original and final source in the Linux container. Its entire
56-case suite passes before and after on the host. All other failed or
aborted suites passed in repaired reruns. No test assertion or timeout
changed.
- These fixtures exercise the assembled service and persisted state.
They do not prove live third-party execution.

## Risks

- Changing query order or losing the original generation could bind a
message to the wrong task.
- The workflow retains the original lookup result and all existing query
and write conditions.
- No schema migration or API change is included.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:21:48 -05:00
DottaandPaperclip bd64eb27b0 perf(recovery): use indexed execution identity lookups (#16291)
## Thinking Path

> - Paperclip manages AI agents and their execution.
> - Recovery must keep old execution ownership visible before new work
starts.
> - Ownership reads filter large run contexts through a combined text
expression.
> - Recovery and status delivery also cast indexed UUID columns to text.
> - These reads can scan history before finding the requested execution.
> - This pull request preserves identity and ownership rules while using
existing indexes.
> - The benefit is less database work during recovery and task polling.

## Linked Issues or Issue Description

Refs #14406. Related community report: #15275. This is an independent
implementation. It does not use that pull request's code or commits. It
covers the reported execution joins and the additional ownership query
hotspot.

**What happened?**

Accumulated staging query statistics showed 11,782 ownership reads at 51
ms each. A paired recovery-action read averaged 22 ms. Both queried
large run JSON. Text casts also prevented indexed UUID lookups in
recovery and status delivery.

**What did you expect to happen?**

Recovery must find the same execution evidence through existing indexes.
Malformed identifiers must match nothing without a cast error. Native
issue bindings must retain precedence. Missing termination evidence must
continue to block new work.

**Steps to reproduce**

Run the disposable benchmark below. It loads the original service
modules from the baseline revision. It compares their exact ownership,
blocker action and status-delivery SQL with the current modules on 1,400
synthetic runs, 350 historical recovery actions and 192 KiB contexts.

## What Changed

- Convert saved text to UUID only after checking its canonical lowercase
form.
- Keep indexed run and task UUID columns unchanged in execution joins.
- Split native and legacy issue predicates so existing indexes can
filter ownership candidates.
- Preserve company scope, native precedence, process and lease holds,
recovery eligibility and delivery receipts.
- Add real PostgreSQL identity and ownership regressions, a reproducible
benchmark and database documentation.

## Verification

- Local service SQL benchmark: ownership 78.30 ms to 1.14 ms, with the
same two complete rows. Blocker action read 76.94 ms to 22.55 ms, with
the same complete row. These are synthetic SQL timings, excluding
process probes, provider calls and HTTP.
- Status delivery returned the same 100 rows. Timing was neutral on the
small-task fixture: 7.85 ms before and 8.30 ms after. No speedup is
claimed for that case.
- 231 local tests passed across six server suites. They cover malformed
identifiers, canonical spelling, company scope, native precedence,
retained processes, workspace restore, native replacement, conversations
and delivery.
- `pnpm -r typecheck` and `pnpm build` passed.
- `git diff --check` passed.
- All current-head CI and security checks passed, including the full
general and serialized suites, browser shards, Runner verification and
build. Greptile reviewed the exact commit at 5/5 with no actionable
findings.
- The older full local sweep in the companion worktree was stopped after
final-commit complete CI passed. It is not claimed as a completed local
pass. The 231 focused tests above passed locally on this branch.

```sh
pnpm --filter @paperclipai/server exec vitest run src/services/conversation-continuation.test.ts src/services/legacy-execution-recovery.test.ts src/__tests__/legacy-workspace-restore-recovery.test.ts src/__tests__/chat-completion-delivery.test.ts src/__tests__/agent-conversations.test.ts src/services/native-runtime/native-safe-replacement.test.ts
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-recovery-queries.ts --baseline-ref=1e731520bb
```

## Risks

- PostgreSQL accepts more UUID spellings than the old text joins. The
explicit guard preserves the old lowercase spelling requirement.
- Query plans depend on the data distribution. Small task sets can show
neutral status-delivery timing. The benchmark is not a production
latency claim.
- Recovery ownership checks remain conservative. Process, lease,
workspace and no-replay rules are unchanged.
- No migration, new index, cache, cleanup change or lock removal is
included.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.9
2026-10-14 10:14:58 -05:00
DottaandPaperclip ebeac833a6 perf(runs): bound history and reduce repeated context reads (#16286)
## Thinking Path

> - Paperclip helps operators manage AI agents and inspect their work.
> - Run history supplies recent execution records to the board and API
clients.
> - The list repeats eight reads of a large stored JSON context.
> - A caller can also omit the limit and read the complete history.
> - This pull request expands context fields once and bounds every list
read.
> - The benefit is lower database cost and bounded redaction work.

## Linked Issues or Issue Description

Refs #958. Related community reports: #13962 and #10631. This is an
independent implementation. It does not use their commits or code. It
covers the history bounds reported in both. Process memory monitoring
from #10631 is outside this change.

**What happened?**

The run-history query repeatedly extracts fields from large context
JSON. Requests without a limit also load every historical run before
authorization and redaction. Accumulated staging query statistics showed
271 ms for summary history and another 58 ms for its redaction lookup.

**What did you expect to happen?**

Normal reads must use a bounded recent history. Context projection must
preserve the existing values and privacy behavior with less repeated
database work.

**Steps to reproduce**

Run the disposable benchmark below against the baseline revision. It
creates 1,400 synthetic runs with 192 KiB contexts. It compares the
exact service SQL and every returned column for both summary and full
history.

## What Changed

- Expand context fields with one lateral record projection. Preserve
non-object legacy contexts and the first-class issue binding.
- Enforce a 200-row default and a 1,000-row maximum in the route and
service.
- Apply the default in the shared UI client, including both agent detail
implementations.
- Preserve response arrays, authorization, result projection and secret
redaction.
- Fetch older linked runs by ID in both agent pages. Check company and
agent scope, navigation races and visible retry errors.
- Update OpenAPI, data-path documentation and capability maps.
- Add real PostgreSQL and HTTP regressions plus a reproducible
benchmark.

## Verification

- Local benchmark: summary history 37.72 ms to 19.34 ms; full history
37.84 ms to 19.01 ms. All 200 complete positional rows match in each
comparison. These are synthetic local SQL timings, excluding HTTP and
redaction.
- History, route, privacy and redaction suites: 160 server tests passed
across six files. Twenty-two UI API, selection, run-panel and
log-visibility tests passed. Both agent-page variants render an older
linked run with an empty history page on desktop and mobile.
- `pnpm -r typecheck` and `pnpm build` passed.
- Map validation and `git diff --check` passed.
- All current-head CI and security checks passed, including the full
general and serialized suites, browser shards, Runner verification and
build. Greptile reviewed the exact commit at 5/5 with no remaining
findings.
- The full local sweep began before the final compatibility fixes. It
was stopped after the final commits passed complete CI. The focused
local suites listed above passed on the final code. Before interruption,
the broader local sweep passed 31,743 tests across the general server,
UI and several package groups, with no reported failures. The full local
command is not claimed as a completed pass.

```sh
pnpm --filter @paperclipai/server exec vitest run src/services/heartbeat/run-state.test.ts src/__tests__/heartbeat-list.test.ts src/__tests__/agent-live-run-routes.test.ts src/__tests__/run-secret-redaction.test.ts src/__tests__/heartbeat-run-privacy-routes.test.ts
pnpm --filter @paperclipai/ui exec vitest run src/api/heartbeats.test.ts
pnpm --filter @paperclipai/server exec tsx ../scripts/benchmark-run-history.ts --baseline-ref=1e731520bb
```

## Risks

- Clients that relied on an unbounded array now receive 200 rows by
default. Explicit limits allow up to 1,000. This change does not add
pagination.
- Legacy context conversion must stay identical. Real database
regressions cover null, array, scalar, nested values and native issue
precedence.
- No schema migration or persistent cache is introduced. Redaction and
access checks remain active.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 10:14:41 -05:00
03fcd3c1fb fix(native-runtime): report which close barrier failed (#16298)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native agent runs use the Paperclip runner. When a run ends, the
controller closes the session. Close must prove that the runner durably
suspended before the controller releases its checkpoint.
> - If close cannot prove this, the run fails with
`provider_transport_failed: runner did not durably suspend before
checkpoint`.
> - The runner knows which barrier was not proven. It writes that
settlement only to the instance run log.
> - The Sentry report for the failed run has no settlement evidence.
Operators cannot tell a stuck suspend command from an undrained
provider, an unreadable provider state, or unsettled tool results.
> - This pull request sends that settlement to the run failure report as
closed labels and counts.
> - The benefit is that the next occurrence shows which barrier failed,
so the root cause can be fixed instead of guessed.

## Linked Issues or Issue Description

No public issue exists. This describes the bug.

**What happened?**

Hosted staging native Codex runs failed with `provider_transport_failed:
runner did not durably suspend before checkpoint`. This happened on two
runs, on 2026-09-30 and 2026-10-14. The second run used a release from
2026-10-14. The Sentry events contain only the error code, run phase,
driver kind, and duration. They contain no stack and no settlement data.
The native executor calls `reportRunFailure(db, run)` without the caught
error, and the runner settlement is never read.

**Expected behavior**

A failed close report should tell an operator which barrier was not
proven: runner suspension, provider drain, provider state, or semantic
tool settlement. It must not expose tool identities, digests, provider
turn IDs, or unredacted error text.

**Steps to reproduce**

1. Run a native Codex session whose close cannot prove durable runner
suspension. For example, the runner suspend command does not complete
before the close deadline.
2. Observe the Sentry run failure event. Before this change,
`run_execution` has no close settlement fields.

## What Changed

- `collectRunFailureDiagnostics` accepts a new `nativeCloseFailure`
option. It reads only a `native_session_close_unrecoverable` error,
directly or up to four `cause` levels deep.
- It adds closed labels and counts to `run_execution`:
`closeRunnerSuspended`, `closeProviderDrained`,
`closeSuspendCommandStatus`, `closeRunnerLifecycle`,
`closeRunnerIdentityMatches`, `closeProviderState`,
`closeProviderPendingEventCount`, `closeProviderTurnActive`,
`closeSemanticResultPersistenceFailed`, `closeSemanticToolsPending`,
`closeSemanticToolDeliveriesOpen`, and `closeSemanticResultFailures`.
- Values outside the known vocabularies are dropped. Getters that throw
are contained.
- The native session executor passes the caught error as
`nativeCloseFailure` when it reports a terminal run failure. It does not
pass the error as `error`, because the raw error text and stack bypass
the executor's identity redaction.
- `doc/observability.md` documents the new fields and the privacy
boundary.

## Verification

- `cd server && npx vitest run
src/services/__tests__/run-failure-diagnostics.test.ts
src/__tests__/run-failure-sentry.test.ts`: 130 tests pass.
- New tests check the full label set, a wrapped cause, null suspension
and provider states, unrelated error codes, hostile and unknown values,
and a missing settlement. They also check that no tool identity, digest,
turn ID, or error text leaves the module.
- Negative control: with the reader disabled, the new main test fails.
- A scoped `tsc` run on `run-failure-diagnostics.ts`, its test, and
`run-failure-report.ts` passes. The full server `tsc` and `pnpm build`
were not run locally. The sandbox has a 4 GiB memory limit and no
`cargo` for the runner binary. CI runs the full checks.

## Risks

- Low risk. The change only adds Sentry context fields for one error
code. Close, quarantine, retry, and recovery behavior do not change.
- Sentry grouping does not change. The fingerprint stays `[errorCode,
agentAdapter]`, and no exception chain is added.
- The data path is Observability (Sentry error reporting, gated by the
operator DSN). It does not change Telemetry. The fields contain only
booleans, fixed labels, and counts. The DSN gate is unchanged.
- These fields are observations. They do not prove a root cause by
themselves.

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

## Model Used

- Anthropic Claude Opus 5.5 (`claude-opus-5-5`), run through Claude Code
as an agent with tool use (shell, file edits, test execution, Sentry and
GitHub connectors). Context window and reasoning mode are not exposed in
this session.

## Checklist

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

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

Co-authored-by: Devin Foley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 07:57:21 -07:00
DottaandPaperclip df4ee06e2f feat(skills): select and validate tracked GitHub branches (#16288)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Skills can track a branch in an authorized GitHub repository.
> - Sources previously offered only a default-branch repair action.
> - People need to select a listed branch or enter a branch that GitHub
has not listed.
> - The server must validate the selected ref with the caller's
authorized connection.
> - This pull request connects the approved branch picker to production
APIs.
> - Installed skills remain usable while the source changes its tracked
ref.

## Linked Issues or Issue Description

**Subsystem affected**

Skills UI, shared API contracts, GitHub source services, and agent API
discovery.

**Problem or motivation**

The default-branch repair action does not let people choose another
branch. The settings service also validates the old ref when a caller
supplies a new ref other than HEAD. A missing tracked branch can prevent
connection repair even when the selected account has repository access.

**Proposed solution**

Load a bounded branch list with the authorized connection. Mark the
default branch. Search listed branches or accept a typed ref. Validate
the selected ref before saving. Keep the chosen value after a load
error, invalid ref, or concurrent update. Save the selected connection
and branch together during connection repair.

**Alternatives considered**

A default-branch button does not support a named branch. A text field
alone does not help people find the repository default or available
branches.

**Roadmap alignment**

This improves the existing Skills source manager. It does not add a new
skill import system.

**Additional context**

Refs #16066 and #16256. This is the production implementation of the
approved branch-selection Storybook journeys.

## What Changed

- Add an authorized branch-list endpoint and shared response/query
types. Register it in agent API discovery.
- Validate the requested ref, including the returned commit SHA.
Preserve source leases, revision checks, project ownership, skill
identities, selections, and installed versions.
- Add the searchable branch picker to Sources and connection repair.
Allow typed refs during branch discovery and after discovery fails.
- Keep save errors in the dialog. Retain the selected branch through a
concurrent source update.
- Use the production components and API client in Storybook. Add
keyboard, touch, loading, retry, invalid-ref, connection-repair, and
concurrent-update browser journeys.
- Update product documentation and the feature/access maps.

## Verification

- Red/green: two new database regressions fail against the previous
service and pass against the implementation.
- Linux database/service suite: 85 tests passed. This includes source
visibility, human/agent authorization, selected connections, immutable
versions, and invalid refs.
- Rebased branch and review fixes: 94 focused UI, route,
branch-validation, and fixture tests passed. Two conflict-message
regressions and the stale-retry fixture regression fail before the fix
and pass after it.
- Storybook build passed. All 26 focused browser journeys passed.
- Repository typecheck and build passed. Final UI typecheck passed after
the review fixes.
- The full local Vitest run was interrupted when the checkout and its
dependencies disappeared. It reported missing working-directory/Postgres
files and worker startup errors. Its two timed-out tests pass after the
checkout was restored. The complete CI suite passed on the final head,
`cf5d4c8f0a`: [CI
run](https://github.com/paperclipai/paperclip/actions/runs/38571068332).
One unchanged workspace timestamp test required a single rerun. Its
release-minus-one-millisecond value can equal the original confirmation
time. The rerun passed.
- Live acceptance passed on implementation head `5dd935bf14` in an
isolated macOS arm64 instance with Node 24.21.0 and an authorized
private GitHub repository. The UI loaded the actual default branch,
saved branch and selected connection together, and preserved the
installed skill/version IDs after reload. An invalid typed ref retained
the draft and showed the provider error. A valid typed HEAD ref then
saved successfully. The owned runtime and database were stopped after
the test. Focused unit, Linux database, and browser suites passed again
after the error-handling review fixes.
- Greptile reviewed final head `cf5d4c8f0a` at 5/5. Both review threads
are resolved; the fresh review has no remaining findings.
- Token gates and map/catalog checks passed.
- Review entry points: `Skills / Project repository skills / 03 Branch
selection components` and `04 Branch selection journeys`. Run `pnpm
storybook` to inspect them.
- Browser command: `pnpm exec playwright test --config
tests/storybook-visual/playwright.config.ts
tests/storybook-visual/skill-source-branch-selection.spec.ts
tests/storybook-visual/project-repository-skills.spec.ts`.
- Manual check: open an independent GitHub source, choose a new branch,
select the default or type a ref, save, and reload. Try an invalid ref
and confirm the selection remains in the dialog. For a project-bound
source, change its ref in project settings.

## Risks

- GitHub discovery is bounded to 100 listed branches. The default branch
is always included. Typed refs remain available.
- A source can change while the dialog is open. The API rejects a stale
revision and the UI keeps the draft for retry.
- A ref change schedules the existing refresh pipeline. Installed
versions remain available until a successful refresh imports new
content.
- No database migration or credential storage change is required.
Existing HEAD requests remain supported.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 09:55:43 -05:00
DottaandPaperclip d4892d4761 fix(observability): sample native runs independently of triggers (#16285)
Start native background run traces under the operator's root sampling policy and link them to valid trigger contexts. Preserve child parenting and silent unconfigured tracing.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-14 09:49:08 -05:00
DottaandPaperclip f69c6a8a35 fix(github): retry and recover review publication (#16284)
## Thinking Path

> - Paperclip manages agent work and its published results.
> - GitHub review bots publish task-bound assessments through governed
tools.
> - A review can survive a caller timeout because its publication intent
is durable.
> - A transient provider failure still returned a failed receipt before
recovery.
> - Gateway replay could return an empty cached result, and publication
retries had no dedicated scheduler deadline.
> - This pull request adds bounded retries, receipt recovery, and an
independent durable worker.
> - A temporary GitHub failure can recover without another review or
duplicate publication.

## Linked Issues or Issue Description

Refs #16275. That change increased the GitHub tool deadline. This change
repairs retry and recovery behavior.

**What happened?**

A one-off GitHub HTTP 503 or 429 left the caller with a failed
publication receipt. The saved retry did not have its own scheduler
worker. An identical gateway call after a timeout could return an empty
cached result instead of the saved publication receipt.

**Expected behavior**

Temporary failures should retry under current authority. Pending work
should resume at its saved deadline after restart. Exact retries should
return the current receipt. Lost responses must not create duplicate
comments, findings, or checks.

**Steps to reproduce**

1. Admit an advisory PR review request and begin its assessment.
2. Return HTTP 503 or 429 for the first summary-comment PATCH, then let
GitHub succeed.
3. Submit the assessment through the run-scoped tool gateway.
4. On master, the result says publication failed. With this change, the
same call returns the processed receipt and neutral check.
5. For receipt recovery, use a shorter caller deadline and repeat the
exact call after publication finishes.

**Paperclip version or commit**

Reproduced on master at `6cb6ac3b8e40cb90d734ba115a2f22f850ff9477`.

## What Changed

- Classify transient transport, server, and rate-limit failures. Honor
Retry-After and primary reset deadlines. Stop retries for permanent
permission and validation errors.
- Retry safe reads and installation-token issuance within a bounded call
window. Retry publication writes through the existing outbox and
provider receipt checks.
- Wait for up to three publication attempts within a 45-second retry
window. Keep the durable eight-failure cap and enforce saved deadlines
on explicit retries.
- Register an independent GitHub publication worker with
transaction-owned wake notifications, startup recovery, and per-PR lease
deadlines.
- Recover exact comment, progress, and assessment gateway calls from
their stored publication. Require the same company, agent, task, run,
connection, tool, arguments, and current policy. Clear stale timeout
errors after recovery. Approved exact retries read the current receipt
through the existing signed replay path; the worker retains the verified
approval for deferred writes and still rejects revocation.
- Add regression coverage and update the connector guide and
feature/access maps.

## Verification

- Red: both one-off HTTP 503 and 429 regressions failed on master with a
failed publication receipt.
- Green: the same tests passed after the change.
- GitHub review workflows: 133 covered against isolated PostgreSQL 18.
The final combined run passed 132 and hit one fifteen-second timeout
under concurrent build load. All three variants of that workflow passed
in isolation. The earlier combined run passed all 131 workflows before
the two approval regressions were added.
- Retry policy and delivery coordinator tests: 35 passed.
- Additional focused checks passed for the actual eight-failure cap,
exact-argument conflicts, policy revocation, and timeout receipt
recovery. The approved deferred-publication and revocation regressions
failed before the review repair and passed after it, with one approval
request preserved.
- `pnpm -r typecheck`: passed. `pnpm build`: passed. `node
scripts/check-maps.mjs`: passed.
- The broad local `pnpm test:run` path remains blocked by the host's
exhausted PostgreSQL shared-memory slots. The changed database-backed
workflows use an isolated Docker database instead. All Paperclip CI jobs
passed at a6d81b67cb, including the required verify and E2E gates.
Greptile is 5/5 at the same head, with the approval-recovery finding
resolved. The external Superagent Security Scan also passed.
- Live acceptance passed on a dedicated single-repository local test App
and native Paperclip Runner. A test-only preload returned one HTTP 503
before the final summary PATCH. One submit_review call completed in
17.305 seconds; the bot published its 3/5 advisory review and neutral
check, then automatically finished the task. [Published
review](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/pull/9#issuecomment-6168809007),
[neutral
check](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/runs/115863564014).
This live test ran at de6862072c; approval-specific recovery is covered
by the later regressions. The preload is excluded from the repository
and removed from the running local instance.

## Risks

Retries make additional bounded provider requests. A provider write with
a lost response is recovered through its existing App-owned identity
before another write is permitted. The worker rechecks authority and the
PR head; revocation and superseded work stop publication. Calls can
still exceed their deadline, and repeated failures eventually exhaust
the retry cap. A pending publication is not a completed task. The agent
still owns task completion after receiving a confirmed receipt. No
schema migration is needed.

## Model Used

OpenAI Codex (GPT-6 family), with code inspection, editing, and test
execution. The exact deployment model ID and context window are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 08:40:32 -05:00
DottaandPaperclip 7c016c049b perf(workspaces): wake terminal cleanup from committed changes (#16282)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use execution workspaces to retain their files and Git
branches.
> - A reaper closes eligible workspaces after their task tree is
terminal.
> - The reaper scanned every heartbeat tick and read Git before cheap
eligibility checks.
> - Permanent scans also query idle databases when no cleanup work
exists.
> - This pull request wakes cleanup after transaction settlement and
restores bounded work at startup.
> - The benefit is fewer scans while fresh cleanup guards continue to
protect retained work.

## Linked Issues or Issue Description

Related work: Refs #13619, Refs #11753. Those PRs bound scans or back
off unchanged candidates. This PR uses the transaction work coordinator
to remove the permanent reaper tick. It overlaps their early
terminal-state filtering but does not change their runtime restart
behavior or introduce a second Git scheduler cache.

**What existing behavior does this improve?**

Terminal workspace cleanup and Git inspection for workspace detail
reads.

**Subsystem affected**

Server orchestration, execution workspaces, and idle sleep admission.

**Current behavior**

The heartbeat tick scans workspace candidates every thirty seconds. It
runs Git before rejecting nonterminal trees, cooldowns, and active runs.
Display inspections expire after five seconds.

**Proposed behavior**

Recover workspace rows in bounded startup pages. Wake after relevant
issue, workspace, and pull-request work-product transactions settle.
Schedule the terminal tree cooldown or a five-minute eligibility retry.
Back off unchanged candidates across unrelated wakes, and invalidate
their backoff after relevant committed changes. Park empty and
nonterminal-only lanes. Reuse display inspections for thirty seconds.
Read fresh Git before destructive cleanup.

**Reason and benefit**

Avoid recurring database and Git work when no cleanup is possible.
Retain transaction admission holds, restart recovery, and fresh deletion
checks. Retention eligibility can wait for the next host wake; active
and failed recovery work still blocks sleep.

**Breaking changes**

No schema or API shape changes. Display Git state can lag by thirty
seconds. Cleanup eligibility retries can take five minutes.

## What Changed

- Add a terminal-workspace worker to the existing transaction work
coordinator and scheduler.
- Signal relevant writes before mutation on the owning transaction.
Outer transaction settlement wakes cleanup.
- Derive cooldown deadlines from the full company-scoped terminal task
tree. Continue bounded recovery pages without a permanent sweep.
- Bound unchanged candidate inspections to five minutes, retain at most
256 entries, and invalidate affected entries with scoped transaction
hints. Repeated wakes preserve the earliest inspection deadline.
- Collect deadlines from task trees already read by bounded pages.
Restore the cursor after a failed page and rescan commits received
during a rotation.
- Check terminal state, cooldown, and active runs before Git. Preserve
lifecycle locks, generation fences, and fresh final checks.
- Keep failed or incomplete recovery visible to idle admission. Preserve
the passive retention exception.
- Extend the bounded display cache to thirty seconds and document the
scheduling and wake limits.

## Verification

- Focused workspace, coordinator, cache, and local sleep suites: 111
tests passed with real local PostgreSQL and Git worktrees where
applicable.
- Final worker, display cache, and local sleep suites: 28 tests passed.
- The regressions prove three ineligible workspaces invoke zero Git
scans, cached clean display state cannot remove new untracked files, and
real producer notifications wait for outer transaction settlement.
- `pnpm -r typecheck` and `pnpm build` passed locally. Map and
module-boundary checks passed.
- Work-product and sleep-safety suites: 221 tests passed. Reopen and
issue-tree control suites: 46 tests passed. Final backoff, workspace,
worker, and work-product suites: 87 tests passed.
- Final workspace and worker suites: 81 tests passed. Deadline selection
performs zero database reads. A failed full page retries its unread
terminal workspace before recovery can park.
- Full CI coverage passed on head `2c397970f7`: general tests,
serialized server suites, runner verification, E2E shards, typecheck,
build, and the final verification gate. The duplicate serial local `pnpm
test:run` was stopped after full CI coverage passed; it is not reported
as a completed local pass.
- Greptile: 5/5 with both findings resolved. The security scan also
passed. No failing or pending PR checks remain.

## Risks

- Display state can be stale for thirty seconds. Destructive guards
bypass the display cache.
- Undelivered or otherwise ineligible terminal work retries after five
minutes instead of each heartbeat tick.
- Transaction signals cover the owning `createDb` scope. Direct SQL and
independent server processes require startup recovery.
- Local cooldown timers are maintenance hints. They do not establish an
external wake alarm or whole-instance sleep safety. Existing blockers
remain in force; failed bounded recovery keeps the host awake.

## Model Used

OpenAI GPT-6, model ID `gpt-6`, through Codex. Reasoning, repository
inspection, shell execution, and browser tools assisted the 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>
canary/v2026.1014.0-canary.8
2026-10-14 08:28:45 -05:00
DottaandPaperclip 1e731520bb fix(mcp): deduplicate discovered tool descriptors (#16281)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents receive governed app tools through the MCP gateway.
> - GitHub review tasks can contain a PR discussion and inline finding
threads.
> - Discovery repeated each tool for every conversation linked to the
task.
> - Native tool registration treated these repeated descriptors as a
fatal collision.
> - This pull request lists GitHub tools once and deduplicates identical
descriptors across providers.
> - Agents can continue work while conflicting definitions and normal
tool permissions remain enforced.

## Linked Issues or Issue Description

**What happened?**

A follow-up run on a GitHub review task failed with
`assigned_mcp_tool_name_collision` before the provider started. The task
had a main conversation and an inline finding thread. Discovery returned
the same seven tools twice. Repeated descriptors from other providers
could cause the same failure.

**Expected behavior**

Discovery exposes each identical tool once. Separate connection names
remain separate tools. Conflicting definitions remain an error. Every
call still passes the gateway's policy, approval, revocation, and audit
checks.

**Steps to reproduce**

1. Run a GitHub review and publish an inline finding.
2. Send a follow-up request on the same PR task.
3. Inspect the task-bound bot catalog and the next native startup.
4. Separately, return two identical descriptors from an assigned app or
plugin catalog.

Related: #13717 added the GitHub review workflow.

## What Changed

- Use a distinct GitHub discovery query across conversations that share
an endpoint and task. Keep both thread mappings.
- Deduplicate identical gateway descriptors by their full gateway name
across providers. Use this rule for MCP listings, plugin listings,
assigned-tool startup, and fresh assigned-tool discovery.
- Reject conflicting descriptors with `tool_name_collision`. Keep the
projected-name collision guard.
- Cover GitHub inline-thread discovery, repeated plugin/app tools,
direct and on-demand catalogs, revocation, conflicting bindings, and
separate connection names.
- Update the execution contract, GitHub documentation, and agent access
map.

## Verification

- Regression baseline: six new assertions failed on the original
implementation. GitHub returned fourteen entries, plugin discovery
repeated a tool, and native startup failed on repeated app tools.
- Focused verification passed: 272 GitHub cases, all 29 assigned-tool
cases, and all 88 gateway acceptance cases.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- `node scripts/check-maps.mjs` passed.
- Current-head CI passed: 55 checks passed, two inapplicable checks
skipped. Greptile scored the current head 5/5 with no unresolved
threads.
- Full local `pnpm test:run` encountered a 15-second timeout in the
existing bearer-auth throttling test, before tool discovery. That test
passed in the separate 88-case gateway run and on one isolated rerun.
The duplicate broad local run was then stopped; the complete
current-head CI matrix passed.

## Risks

- Deduplication keeps the first identical descriptor and preserves
listing order. Same-name descriptors with different definitions fail
with HTTP 409 rather than selecting an ambiguous binding.
- The GitHub query changes result cardinality. It retains the existing
task/company/agent filters and leaves conversation rows intact.
- No schema migration or credential change. Live staging recovery
requires deployment and a new authorized run.

## Model Used

OpenAI Codex, based on GPT-6, with code inspection, editing, browser
investigation, and test execution. The exact serving model ID and
context window are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 07:39:54 -05:00
DottaandPaperclip e9b6c4d44c perf: remove history scans from task and chat queries (#16278)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Task reads and external chat notices must remain responsive as run
history grows.
> - The chat notice sweep casts indexed UUID columns to text.
> - Run redaction and task provenance filter large JSON contexts with
expressions that lack matching indexes.
> - These queries scan history and read large stored contexts on common
requests.
> - This pull request adapts two existing fixes to current master and
adds the missing provenance index.
> - The benefit is less database work with the same query results and
access rules.

## Linked Issues or Issue Description

Refs #15927. This change adapts that chat sweep fix to the extracted
inbound notice module and retains the contributor credit.

Refs #12499. This change adds that missing nested-context index through
a current, concurrent migration. It retains the contributor credit.

This combined change replaces those older layouts for the measured query
paths. It also covers task creation provenance, which those pull
requests do not address.

**What happened?**

The chat notice sweep scans wakeup history. Issue redaction scans run
contexts because only one branch of its JSON condition has an index. The
task creation-source filter also scans contexts because its native and
legacy ID expression lacks an index.

**Expected behavior**

The queries use indexed lookups and return the same rows. Company
access, task origin precedence, secret redaction, and chat notice
ordering remain the same.

**Steps to reproduce**

Run `pnpm --filter @paperclipai/server exec tsx
../scripts/benchmark-slow-queries.ts --baseline-ref=f8af817f8d`. The
benchmark creates disposable PostgreSQL data and compares the old query
with the current query on the same fixture.

## What Changed

- Compare chat UUID columns directly with safely parsed payload IDs.
Reject malformed and noncanonical IDs without a cast failure.
- Add the nested `paperclipIssue.id` run-context index and the exact
native/legacy task-provenance expression index.
- Build both indexes concurrently. Register the migration for top-level
execution and invalid-index retry repair.
- Extend chat payload and migration regression coverage.
- Add a repeatable synthetic SQL benchmark and document its scope and
command.
- Keep the five newest schema snapshots.

## Verification

- Focused local checks: 76 selected tests passed in five files. These
cover FIFO notices, malformed IDs, conversation state, redaction,
provenance, and company boundaries.
- Disposable PostgreSQL 18.1 fixture: 335 tasks, 1,400 runs, 13,000
wakeups, 377 actions, and 192 KiB synthetic contexts.
- Five warm samples per query, after two warmups. Every returned SQL
column matched before and after, compared as positional tuples so
duplicate unnamed projections are retained.

| Query | Before, median | After, median | Improvement |
| --- | ---: | ---: | ---: |
| Chat notice candidates | 26.21 ms | 6.43 ms | 4.1× |
| Task creation-source list | 159.69 ms | 6.51 ms | 24.5× |
| Issue redaction contexts | 131.88 ms | 0.34 ms | 389.1× |

The run-history context projection returned the same 200 rows and kept
the same index plan and buffer counts. Its timings were noisy (37.30 ms
before and 56.78 ms after in the last run; 34.25 ms and 34.14 ms in the
previous run). No improvement is claimed for this control. Its repeated
JSON projection remains a separate optimization opportunity.

The populated plans use the wakeup primary key, the provenance
expression index, and a BitmapOr over both redaction indexes. These are
local SQL measurements. They do not prove an equivalent change in hosted
API latency.

- `pnpm -r typecheck` and `pnpm build` passed locally.
- The full local `pnpm test:run` was started and then interrupted (exit
130) when the Mac reached its PostgreSQL shared-memory limit. It did not
complete and is not reported as passed. The final SQL benchmark passed
after its disposable database resources were released. The full general
and serialized test suites passed in CI.
- All CI checks for final head
`193acca6abaa992acad12f4b631bd31dd3234641` passed, including full Vitest
coverage, E2E checks, typecheck, build, migration order, and lifecycle
boundaries.
- Greptile reviewed that exact head at 5/5 with no actionable comments.


## Risks

- Both indexes add storage and write cost. Initial builds read stored
run contexts and can take time on large histories.
- Concurrent index builds avoid holding a write-blocking table lock for
the whole build. The existing migration retry path removes invalid
partial indexes before retrying.
- The chat parser accepts only canonical lowercase UUID text. This
preserves the prior text comparison, including rejection of uppercase
and malformed values.
- Staging has not been migrated or deployed. Local PostgreSQL and
synthetic data do not reproduce hosted load or network latency.

## Model Used

- OpenAI Codex, based on GPT-6. The exact serving model ID and context
window were not exposed in this session. Used reasoning, repository
tools, browser inspection, and local code execution. The adapted fixes
retain their original contributor credits.

## 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.1014.0-canary.7
2026-10-14 07:37:51 -05:00
DottaandPaperclip 5498e8ba64 docs(skills): add maintenance bot setup workflow (#16279)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents, skills, and routines support recurring repository
maintenance.
> - Setting up that work requires choices about the instance, agent,
credentials, repository, and trigger.
> - A repeatable setup procedure must preserve those choices and verify
saved configuration.
> - This pull request adds a skill that configures maintenance bots for
any selected maintenance task.
> - Each run creates useful PRs and revises them until required checks
pass.

## Linked Issues or Issue Description

Refs #16211 for the test-audit skill that can serve as one maintenance
task.

**Issue type**

Missing documentation.

**Where is the issue?**

The repository skill library lacks a procedure for setting up a code
maintenance agent and routine.

**What's wrong?**

Users must compose agent selection, skill delivery, scheduling,
workspace access, and PR follow-up themselves. The setup must also work
through the browser when API access fails.

**Suggested fix**

Add a standalone setup skill with API guidance and reusable
maintenance-run instructions. Support existing agents and new hires.
Support scheduled, webhook, and manual triggers.

## What Changed

- Add `setup-code-maintenance-bot` with instance and agent selection.
- Document harness, provider, AI account, repository, skill, and trigger
choices.
- Add API setup guidance, browser fallback, paused setup, and
saved-field verification.
- Add a generic run template with work limits, duplicate-PR checks, and
PR revision until current-head checks pass.
- Keep private run-to-PR mappings on Paperclip execution issues. Publish
internal references only when the target repository permits them.
- Add skill UI metadata.

## Verification

- Skill frontmatter validator passed.
- Relative links, JSON examples, UI metadata, and whitespace checks
passed.
- Compared API shapes and authorization rules with Paperclip source.
- No live agent or routine was created. No maintenance trial was run.
- Local application typecheck, Vitest, and build were not run for this
Markdown/YAML-only change.
- Repository CI and automated review will run on this PR.

## Risks

Low code risk. The change adds instructions and metadata only. API
details can differ by deployment. The skill requires discovery from the
selected instance and verification of saved settings before activation.
Browser setup must preserve the same permissions and approval rules.
Live setup remains untested.

## Model Used

OpenAI Codex, based on GPT-6, with repository inspection, tool use, and
file editing. The exact deployment model ID and context-window size are
not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 07:37:00 -05:00
DottaandPaperclip c80d93e14e fix(observability): time execution configuration steps (#16236)
Record optional execution-configuration timings before provider dispatch, with success, failure, sampling, cleanup, and silent-unconfigured controls.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-14 07:21:56 -05:00
DottaandPaperclip 6cb6ac3b8e fix(github): allow review publication to finish before tool timeout (#16275)
## Thinking Path

> - Paperclip manages agent work and its published results.
> - GitHub review bots publish task-scoped assessments through the tool
gateway.
> - A submission saves its assessment and publication intent before it
waits for GitHub.
> - The gateway's ten-second default can expire while those provider
requests continue.
> - GitHub can then show a completed review while the agent receives a
timeout and blocks its task.
> - This pull request gives GitHub bot tools the existing sixty-second
maximum by default.
> - The caller can receive the confirmed publication result without
manual task repair for ordinary slower responses.

## Linked Issues or Issue Description

**What happened?**

A GitHub bot's `submit_review` call returned `504 tool_timeout`. Its
saved assessment continued to publish a summary and completed check
after the caller stopped waiting. The agent treated publication as
unconfirmed and blocked the task.

**Expected behavior**

A valid GitHub response that takes longer than ten seconds should return
its confirmed publication receipt within the gateway's supported
deadline.

**Steps to reproduce**

1. Configure a report-only GitHub review bot and admit a PR review
request.
2. Delay the summary-comment PATCH response by eleven seconds.
3. Submit a complete assessment through a real run-scoped tool gateway.
4. Before this fix, the caller gets a timeout while the durable action
publishes one summary and a neutral check.
5. With this fix, the caller gets `completed`, `processed`, and the
assessment score. Retrying does not add another comment.

**Paperclip version or commit**

Reproduced from master at `2c17d3ca52a7840f280f1dd87975a2ad77de3b35`.

Related changes: Refs #16259 and #16263. Those changes repaired
connection recovery. This change addresses the subsequent submission
deadline.

## What Changed

- Use a sixty-second default for `paperclip_github_chat` tools in run
execution and board tool tests.
- Preserve explicit shorter deadlines and the existing maximum.
- Add PostgreSQL-backed regressions through the real gateway for delayed
publication, explicit deadlines, neutral checks, and duplicate
prevention.
- Document the deadline and the durable publication behavior.

## Verification

- Red: the eleven-second publication regression failed with
`ToolGatewayHttpError(504, tool_timeout)` after the summary and neutral
check were published.
- Green: the same regression passed after the repair.
- GitHub review workflow suite: 122 tests passed.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- `pnpm test:run`: running; results will be recorded before handoff.
- Live local verification is running against a dedicated test App on
[the disposable test
PR](https://github.com/paperclipai/paperclip-permissions-smoke-20260926-pap57-fee7428e/pull/9).
A test-only preload delays one real GitHub PATCH response by eleven
seconds. It is not part of this change.

## Risks

GitHub bot calls can occupy their execution slot for up to sixty seconds
by default. Calls that exceed that limit can still time out. Durable
publication may continue after any caller timeout, so a timeout alone is
not proof of a failed write. This change does not add automatic task
reconciliation for arbitrarily slow or unavailable providers. No schema
or credential changes are required.

## Model Used

OpenAI Codex (GPT-6), with code inspection, editing, test execution, and
browser verification. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-14 06:52:33 -05:00
DottaandPaperclip f8af817f8d fix(ui): make external agent pairing codes copyable (#16274)
## Thinking Path

> - Paperclip manages AI agents and their work.
> - External agents connect through the shared MCP agent gateway.
> - Grok setup gives the operator a one-use code for the authorization
page.
> - The password field hides the code but does not provide a working
copy action.
> - The pending approval button names Dot before the agent preview
loads.
> - This pull request adds explicit code copying and a neutral approval
label.
> - The operator can review the fixed agent without sending credentials
to chat.

## Linked Issues or Issue Description

Refs: #16219, #15581, #15414.

**What happened?**

The Grok setup code is in a read-only password field. Ordinary browser
copying does not copy that field. The shared authorization page says
“Connect Dot with pairing code” before it knows the invited provider.
These defects blocked a watched Grok desktop setup before approval.

**Expected behavior**

An operator can copy the one-use code with a visible control. The code
stays hidden and outside the Bot prompt. The authorization page shows
the registered client and the fixed company, agent, permissions, and
authorizing person before approval.

**Steps to reproduce**

1. Choose New agent, Invite an external agent, and Grok Bot.
2. Save the Bot identity and open Connect access.
3. Try to copy the masked code into the Bot's browser authorization
page.
4. Inspect the pending approval action before a valid preview loads.

**Paperclip version or commit**

The fix starts from master commit
2c17d3ca52.

**Deployment mode**

Cloud. The same UI serves self-hosted instances.

## What Changed

- Add Copy code beside the masked Grok pairing field. Reuse CopyText and
the shared clipboard fallback, failure feedback, and retry.
- Associate the pairing label with its input for keyboard and
screen-reader access.
- Use Allow agent connection before and after the fixed-agent preview.
Keep approval disabled until that preview loads. Align Dot's generated
setup prompt and guide with that action.
- Add tests for copy failure and retry, a Grok invitation using the
Cursor client identity, and unchanged person and Dot connection paths.
- Add a waiting-for-authorization Storybook state and record the live
qualification blocker in the existing plan.

## Verification

- Focused Grok, Dot, and person-connection UI tests: 33 passed.
- Repository build: passed.
- Token gates: passed.
- Storybook catalog: passed; structure only.
- Watched Storybook preview: native browser input copied the full
synthetic code while the field stayed masked and Continue stayed
disabled. This is fixture evidence, not live OAuth or Runner
qualification.
- Repository typecheck and Storybook build: passed. UI typecheck and
production build passed again after the review fix.
- Current-head CI: 55 successes, two intentional skips, one neutral
result, no unfinished or failed gates. Greptile: 5/5, with the review
finding fixed and resolved. Head:
1b95218c91.
- The additional local aggregate test run is still running. No local
aggregate pass is claimed. The required full server, workspace, Runner,
browser, and release checks passed in CI for the current head.
- After deployment, resume the saved Grok setup, use Copy code, check
the fixed agent preview, and finish the real authenticated round trip.

## Risks

Copying temporarily places the one-use code on the clipboard. Its
existing expiry and one-use checks remain. The authorization endpoint,
grant scopes, fixed identity, and disabled-state checks do not change.
No persistent secret enters the prompt. Live provider and managed Runner
qualification remain incomplete.

## Model Used

OpenAI GPT-6 through Codex. Used tool calls, code execution, and browser
inspection. The exact serving model suffix and context limit are not
exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.6
2026-10-14 06:36:47 -05:00
DottaandPaperclip 2c17d3ca52 fix(github): recover webhook verification in attention state (#16263)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review bots require signed webhook delivery before
activation.
> - Cloud can deduplicate an old ping after a connection repair.
> - A fresh event could verify active connections, but an
attention-state connection discarded it before authentication.
> - This pull request allows signed delivery verification while the
connection needs attention.
> - It discards ordinary work until the manager completes the existing
reconnect and activation checks.

## Linked Issues or Issue Description

Refs #16259. Related: #16138 addresses the separate classification of
local authorization failures.

**What happened?**

Live verification of #16259 found that a GitHub App already marked as
needing attention remained stuck waiting for a signed ping. The Cloud
relay had already delivered that ping. New signed events were discarded
by the attention-state ingress gate before they could verify delivery.

**Expected behavior**

A fresh valid event from the bound installation verifies delivery. It
does not activate the connection, change repository access, or start
work. The manager can then complete the normal reconnect flow.

**Steps to reproduce**

1. Put an existing App connection into attention state with webhook
verification cleared after repair.
2. Deliver a fresh signed comment event for its bound installation.
3. Continue setup. Before this fix, webhook verification remains missing
and reconnect cannot proceed.

## What Changed

- Use a content-free verification path for signed ordinary GitHub events
while the connection needs attention.
- Allow a fresh signed event from the same installation to verify
webhook delivery.
- Verify delivery even from disabled or unavailable repositories.
Discard the event before content storage, resource reconciliation, or
runtime creation.
- Keep newly verified connections in the provider-setup step. Later
installation events cannot activate them before reconnect. Preserve
normal installation recovery for existing qualified connections.
- Extend recovery regressions to cover attention state, foreign
installations, invalid signatures, missing installation IDs, unchanged
resources, no wakeups, and successful reconnect after verification.
- Document the recovery behavior.

## Verification

- The targeted regression reproduced the attention-state failure before
the change.
- All ten recovery cases pass after the change. The tests cover disabled
and unavailable repositories, content-free verification, and
installation events after verification.
- Server typecheck passed.
- All 260 GitHub integration tests passed after the review fixes. Final
server typecheck also passed.
- `pnpm -r typecheck` and `pnpm build` passed.
- The full local suite is running. One unrelated workspace-runtime
conflict-reference test failed and then passed on its isolated rerun.
Final totals and CI/review outcomes will be updated before merge.
- Live verification will use the existing advisory review bot after
deployment.

## Risks

- Attention-state ordinary events authenticate under the current
credential lease without creating a durable content record. They return
before resource reconciliation or runtime creation.
- Verification is still bound to the current credential lease, runtime
generation, valid signature, and installation ID. It does not activate
the bot or replace normal setup checks.
- Paused, revoked, archived, and unconfigured connections retain their
existing ingress rules. No schema changes or permission expansion.

## Model Used

OpenAI Codex (GPT-6), with code inspection, editing, test execution, and
browser verification. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [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>
nightly/v2026.1014.0-nightly.0 canary/v2026.1014.0-canary.5
2026-10-14 05:23:42 +00:00
DottaandPaperclip c36281d639 fix(skills): repair missing branches and show grouped import progress (#16256)
## Thinking Path

> - Paperclip lets people manage AI agents and their reusable skills.
> - GitHub skill sources must keep their installed content usable during updates.
> - A source can track a branch that no longer exists.
> - The UI treats that GitHub error as a connection problem, so saving a valid account does not resolve it.
> - Project workspaces also show the same repository several times, and long imports give little feedback.
> - This pull request adds explicit branch repair, groups repository imports, and shows import progress.
> - People can repair the actual problem and see when their import is working.

## Linked Issues or Issue Description

Refs #16066 and #14713. This fixes the Sources experience introduced by those changes. Related adapter-source PRs #14340 and #14341 cover runtime mounting, not this source-management flow. No overlapping source-management fix was found.

**What happened?**

An installed source tracked `main` while its GitHub repository used `master`. GitHub returned HTTP 422. The UI showed a general read error and asked for a new connection after a valid account was saved. The project repository list repeated the same repository/ref for each project. Import had no spinner or explanation of queued work.

**Expected behavior**

Identify an unavailable branch and offer an explicit repair. Retain the selected connection and installed versions. Show one repository/ref row with its projects. Give immediate feedback and show the queued and active import states.

**Steps to reproduce**

1. Install a source with an immutable commit and a saved tracked branch that does not exist.
2. Refresh it, or try to save a valid GitHub connection.
3. Add the same repository/ref to two legacy project workspaces and open Sources.
4. Import that repository and observe the row until installation completes.

## What Changed

- Distinguish a missing GitHub revision from access denial and temporary read errors.
- Validate both repository identity and the tracked revision when saving a connection.
- Offer Use default branch on independent sources and in connection repair. Keep `HEAD` as the default-branch alias after refresh. Preserve skill IDs, versions and selections.
- Keep active project refs under project configuration. Reject source-level changes that would alter their tracking. Recheck the ref under the source lock when project attachment races with branch repair.
- Group matching repository/ref workspaces. Adopt eligible workspaces and skip pending workspaces. Keep remaining project links inside the existing source card. Allow remaining imports while another workspace is pending.
- Show a spinner, busy state and queued/importing text. Keep the saved authorized account selected in connection repair.
- Update shared contracts, feature/access maps, database notes and production-component Storybook journeys.

## Verification

- Red/green: three local regressions failed on the original code: missing-ref classification, duplicate repository rows, and branch repair instead of another connection prompt. The changed UI/reader tests pass after the fixes.
- Live local app with a real authorized GitHub credential: reproduced HTTP 422 for the unavailable branch; used the UI to restore default-branch tracking; confirmed the same connection, skill ID and single immutable version remained.
- Live local grouped Paperclip import: one source, two project associations and 52 installed skills. Sources survived reload. No staging data was changed.
- All 16 project repository Storybook browser journeys pass on the final head, including keyboard focus recovery after branch repair. These include branch repair, grouped imports, connection selection, recovery, removal and responsive layouts.
- Repository typecheck, production build, Storybook build, token gates and 28 map/catalog tests passed. Final UI typecheck and build also passed after grouping remaining project links.
- Linux qualification: all 94 focused source, project import, GitHub reader and UI tests pass with supported Node 24. No database tests were skipped. Both review findings failed before their fixes and pass after them.
- The full local `pnpm test:run` attempt was stopped after macOS database suites exhausted the host shared-memory limit. The complete Linux CI matrix is the full-suite gate. The complete Linux CI matrix passes for head `f886e3ac073ec1c6f051fd6429496234f5143694`.
- Greptile rates head `f886e3ac073ec1c6f051fd6429496234f5143694` 5/5. Both findings are fixed and all review threads are resolved.
- Storybook: `skills-project-repository-skills-02-journeys--missing-branch` and `--duplicate-projects`.

## Risks

- Default-branch repair changes the tracked branch only after an explicit user action. Existing execution version pins stay intact.
- A selected connection now needs access to the tracked revision, not only repository metadata.
- Grouping is by repository and ref. Project access and provenance remain separate and are checked by the existing services.
- Legacy source errors contain safe text. The repair-action classifier maps known errors and treats other failures as retryable. No credentials or provider response bodies are returned.
- No schema migration, workflow change, lockfile change or staging deployment.

## Model Used

OpenAI Codex, GPT-6 family. The exact serving model identifier and context-window size are not exposed in this session. Tool-assisted implementation, code execution and browser 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>
canary/v2026.1014.0-canary.4
2026-10-13 22:27:11 -05:00
DottaandPaperclip a8b652b085 fix(github): preserve review delivery through reconnect (#16259)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - GitHub review bots turn authorized repository events into agent
tasks and publish the result on the pull request.
> - Cloud Apps send callbacks through a relay, but the direct callback
recovery worker reported that URL as broken.
> - Reconnecting the same App then prevented a new authorized
publication from updating its existing working comment.
> - Report-only runs could also produce an action-required check when no
complete assessment was available.
> - This pull request preserves comment identity across reconnects,
verifies fresh signed delivery after repair, and keeps report-only
results neutral.
> - Users can receive the review without changing repository access or
making an advisory bot block their pull request.

## Linked Issues or Issue Description

**What happened?**

A review could be saved in Paperclip while GitHub kept showing “Working
on this…”. A same-App reconnect changed the runtime generation and the
existing response receipt then failed with “GitHub response binding
changed”. Cloud callback recovery also compared the relay URL with a
direct tenant URL. An incomplete or failed report-only run could produce
an action-required check.

**Expected behavior**

A fresh authorized attempt updates the same App-owned comment after
reconnect. Stale attempts and revoked people remain denied. Cloud relay
delivery does not produce a direct-callback mismatch. Report-only checks
remain neutral and explain incomplete work honestly.

**Steps to reproduce**

1. Accept a GitHub request and publish its working comment.
2. Reconnect the same App before the agent publishes its result.
3. Submit the result and inspect the working comment and check.
4. Separately, let a report-only run end without an assessment and
inspect its check conclusion.

Related: #16138 addresses the separate classification of local
authorization errors as provider credential failures. This change fixes
the response binding and report-only paths themselves.

## What Changed

- Bind durable response comments to the App and agent. Keep per-attempt
runtime generation checks and provider comment ownership checks,
including legacy receipts.
- Exclude Cloud-managed Apps from the direct webhook recovery scan and
its stale callback-mismatch warning. The Cloud inbox owns relay retries.
- Let a fresh authenticated event from the bound installation verify
webhook delivery after repair. Keep signature, runtime epoch,
installation, and credential lease checks.
- Keep report-only assessment and terminal-run checks neutral. Preserve
incomplete/error text and gated-review behavior.
- Add integration regressions for reconnect races, legacy comments,
failed runs, Cloud recovery, and foreign or forged webhook traffic.
Update connector documentation.
- Correct the assigned-tool search guidance to name the actual input
fields (`offset` and `schemaOffset`) and show valid arguments. The
failed automatic review had an input-schema rejection before tool
execution; this clarifies recovery without expanding tool access.

## Verification

- `pnpm -r typecheck` passed.
- GitHub policy and integration suite: 291 tests passed (`vitest run
server/src/services/chat-github-review-policy.test.ts
server/src/__tests__/chat-channels.integration.test.ts -t
'GitHub|github'`).
- The report-only policy regression failed before the fix and passed
after it.
- `pnpm build` passed.
- Assigned tool discovery: 24 tests passed. Its guidance now maps
returned pagination offsets to the correct input fields and tells the
model to omit unused optional fields.
- Full `pnpm test:run` is running. It encountered a 15-second timeout in
the unrelated authenticated Workspace calendar-write test. That test
passed on one isolated rerun.
- After the review-requested module extraction, server typecheck and
both direct/Cloud recovery activity integration checks passed.
- All 55 non-skipped CI checks passed for
`32e690279d847e44a6946b6c7cfb110fb11aff79`. Greptile scored that commit
5/5 with no unresolved findings. Live staging publication verification
follows deployment.

## Risks

- A durable response can now survive a same-App reconnect. Fresh
authorization, runtime generation checks for each publication attempt,
App ownership, and the publication lease still fence writes.
- Report-only failures intentionally become neutral. The check still
reports the failure; it does not claim a complete assessment.
- Cloud-managed callbacks rely on their existing durable relay inbox.
The direct callback recovery worker remains unchanged for direct
installations.
- No schema migration or permission expansion.

## Model Used

OpenAI Codex (GPT-6), with code inspection, editing, test execution, and
browser verification. The exact deployment model ID and context window
are not exposed in this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 22:24:41 -05:00
DottaandPaperclip 40ecacff4c fix(voice): accept authenticated Cloud callers (#16254)
## Thinking Path

> - Paperclip manages agent work through company-scoped tasks.
> - Speko voice connections bind a caller to that work.
> - Private voice routes must recognize an authenticated human caller.
> - Cloud sign-in uses a trusted Cloud actor, rather than a local
session actor.
> - The voice caller check rejected that existing authentication type.
> - This pull request accepts authenticated Cloud callers and retains
the current access checks.
> - Cloud users can load call history and start private voice sessions.

## Linked Issues or Issue Description

Refs #15727, #15728, #15729.

**What happened?**

A signed-in Cloud user sees “Sign in to start a private voice
conversation” when the Speko connection loads call activity. The same
check prevents the user from starting a private voice session.

**Expected behavior**

The trusted Cloud user identity should have the same voice caller access
as a local authenticated session. The current company and user identity
checks must still apply.

**Steps to reproduce**

1. Sign in to a Cloud workspace with experimental chat connectors
enabled.
2. Connect a Speko persona to an existing agent.
3. Open its call activity, or start a browser voice session.
4. Observe the sign-in rejection despite the authenticated workspace
session.

**Paperclip version or commit**

Reproduced on the voice route in master at b8ffeb973a.

**Deployment mode**

Paperclip Cloud with trusted tenant authentication.

## What Changed

- Accept `cloud_tenant` and `session` actors with a user ID as private
voice callers.
- Use current company membership for Cloud owners, including owners with
temporary administrator access. Retain local administrator authority,
company isolation, and credential-source restrictions.
- Add route regressions for call history, session creation,
administrator authority, missing identities, company boundaries, and
rejected caller types.
- Add Cloud authentication qualification steps to the Speko runbook.

## Verification

- Before the fix: 2 Cloud regressions failed; 9 boundary and local-user
tests passed.
- After the fix: all 100 voice caller and real-database persistence
regressions passed. The Cloud-owner route test covers history, session
creation, persisted caller authority, and membership revocation.
- Repository typecheck and build passed with the repository’s pinned
dependencies.
- All current-head CI gates passed. Greptile reviewed f84fee2605 at 5/5
with no remaining findings. The repaired local full repository test run
is still in progress. The first local full-suite attempt failed on
missing native database library aliases; those aliases were repaired
only in the isolated test dependency. No skipped run is counted as
database proof.
- On Cloud, verify that signed-in call activity loads and private
session creation reaches media setup. Real conversation and spoken
playback acceptance remain separate.

## Risks

The change accepts an existing trusted Cloud actor type. Authentication
still runs in the current middleware. Raw Cloud headers, board API keys,
MCP OAuth, Cloud control credentials, and agent callers cannot establish
private voice caller authority. No migration, UI change, credential,
transcript, or lockfile is included.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.3
2026-10-13 21:39:56 -05:00
DottaandPaperclip 75189b8762 refactor(server): isolate channel runtime admission and maintenance (#16235)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn provider messages into shared task workflows.
> - The main service still implements provider details beside common
authorization and persistence.
> - These details belong in the existing channel folders.
> - This pull request moves Discord runtime command capture and root
receipts, Speko runtime and authority, and GitHub maintenance scheduling
behind explicit typed functions.
> - The service keeps its shared workflow and selects the provider
implementation directly.

## Linked Issues or Issue Description

Refs: #16192. Stack part 5/5. Depends on #16233. Base: `master` (parent
PR merged).

**What existing behavior does this improve?**

The ownership and readability of provider behavior in the chat channel
service.

**Current behavior**

The service implements Discord runtime command capture and root
receipts, Speko runtime and authority, and GitHub maintenance scheduling
inline.

**Proposed behavior**

Channel modules own these details. The core calls their typed functions.
Runtime and database effects retain their current order.

**Reason and benefit**

Maintainers can find channel behavior in its channel folder without
following a generic provider framework.

**Breaking changes**

None intended. Public service entry points and durable data shapes stay
compatible.

## What Changed

- Extract Discord runtime command capture and root receipts, Speko
runtime and authority, and GitHub maintenance scheduling into the
existing channel folders.
- Keep shared company scope, authorization, and transaction ownership in
their current workflow.
- Reduce `chat-channels.ts` from 3715 to 3649 lines.

## Verification

- The same 167 selected chat-runtime cases and 87 voice ownership cases
passed before and after extraction. Full workspace typecheck and build
passed. Token parity checks passed for six moved control-flow blocks.
- Server typecheck passed.
- `node scripts/check-module-boundaries.mjs` passed.
- Full workspace typecheck and build passed on the cumulative stack. All
current-head CI gates passed. Greptile completed at 5/5 with no
findings.
- The full local `pnpm test:run` command exited with three database
fixture-startup hook timeouts. It reported 19,529 passing tests and 250
skipped tests. No assertion failed. Its later test groups did not run
because the driver stops on the first failing group.
- The timed-out files were `environment-custom-images-service.test.ts`,
`generic-mcp-connection.test.ts`, and
`modules/wake-queue/adapters/postgres.test.ts`. All 166 tests in these
files passed in isolation on both baseline `edcfcaf3f6` and stack head
`faaca26d46`, with existing timeouts and assertions. The tests and
database-startup helper are unchanged.
- Provider fixtures prove application integration. They do not prove
live third-party execution.

## Risks

- Incorrect inputs or changed await order could affect provider handling
and recovery.
- Existing integration tests exercise the assembled service before and
after extraction.
- No database migration or API change is included.

## Model Used

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

## Checklist


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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 21:39:08 -05:00
DottaandPaperclip c1994056f9 refactor(server): isolate channel registration and setup services (#16233)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn provider messages into shared task workflows.
> - The main service still implements provider details beside common
authorization and persistence.
> - These details belong in the existing channel folders.
> - This pull request moves Slack registration, account linking,
test-message setup, GitHub setup progress, and Telegram webhook URL
restrictions behind explicit typed functions.
> - The service keeps its shared workflow and selects the provider
implementation directly.

## Linked Issues or Issue Description

Refs: #16192. Stack part 4/5. Depends on #16232. Base: `master` (parent
PR merged).

**What existing behavior does this improve?**

The ownership and readability of provider behavior in the chat channel
service.

**Current behavior**

The service implements Slack registration, account linking, test-message
setup, GitHub setup progress, and Telegram webhook URL restrictions
inline.

**Proposed behavior**

Channel modules own these details. The core calls their typed functions.
Runtime and database effects retain their current order.

**Reason and benefit**

Maintainers can find channel behavior in its channel folder without
following a generic provider framework.

**Breaking changes**

None intended. Public service entry points and durable data shapes stay
compatible.

## What Changed

- Extract Slack registration, account linking, test-message setup,
GitHub setup progress, and Telegram webhook URL restrictions into the
existing channel folders.
- Keep shared company scope, authorization, and transaction ownership in
their current workflow.
- Reduce `chat-channels.ts` from 3813 to 3715 lines.

## Verification

- The same 97 selected setup integration cases passed before and after
extraction. The cases cover Slack installer linking and welcome
eligibility, GitHub registration, and Telegram webhook restrictions.
- Server typecheck passed.
- `node scripts/check-module-boundaries.mjs` passed.
- Full workspace typecheck and build passed on the cumulative stack. All
current-head CI gates passed. Greptile completed at 5/5 with no
findings.
- The full local `pnpm test:run` command exited with three database
fixture-startup hook timeouts. It reported 19,529 passing tests and 250
skipped tests. No assertion failed. Its later test groups did not run
because the driver stops on the first failing group.
- The timed-out files were `environment-custom-images-service.test.ts`,
`generic-mcp-connection.test.ts`, and
`modules/wake-queue/adapters/postgres.test.ts`. All 166 tests in these
files passed in isolation on both baseline `edcfcaf3f6` and stack head
`faaca26d46`, with existing timeouts and assertions. The tests and
database-startup helper are unchanged.
- Provider fixtures prove application integration. They do not prove
live third-party execution.

## Risks

- Incorrect inputs or changed await order could affect provider handling
and recovery.
- Existing integration tests exercise the assembled service before and
after extraction.
- No database migration or API change is included.

## Model Used

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

## Checklist


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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 21:28:16 -05:00
DottaandPaperclip 875943ac83 refactor(server): isolate provider webhook lifecycle processing (#16232)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn provider messages into shared task workflows.
> - The main service still implements provider details beside common
authorization and persistence.
> - These details belong in the existing channel folders.
> - This pull request moves GitHub webhook runtime deadlines and Slack
lifecycle processing behind explicit typed functions.
> - The service keeps its shared workflow and selects the provider
implementation directly.

## Linked Issues or Issue Description

Refs: #16192. Stack part 3/5. Depends on #16231. Base: `master` (parent
PR merged).

**What existing behavior does this improve?**

The ownership and readability of provider behavior in the chat channel
service.

**Current behavior**

The service implements GitHub webhook runtime deadlines and Slack
lifecycle processing inline.

**Proposed behavior**

Channel modules own these details. The core calls their typed functions.
Runtime and database effects retain their current order.

**Reason and benefit**

Maintainers can find channel behavior in its channel folder without
following a generic provider framework.

**Breaking changes**

None intended. Public service entry points and durable data shapes stay
compatible.

## What Changed

- Extract GitHub webhook runtime deadlines and Slack lifecycle
processing into the existing channel folders.
- Keep shared company scope, authorization, and transaction ownership in
their current workflow.
- Reduce `chat-channels.ts` from 3906 to 3813 lines.

## Verification

- The same 61 selected webhook/lifecycle integration cases passed before
and after extraction. They cover cold GitHub runtime startup, signed
ingress, installation recovery, Slack lifecycle effects, and
Telegram/Teams edits.
- Server typecheck passed.
- `node scripts/check-module-boundaries.mjs` passed.
- Full workspace typecheck and build passed on the cumulative stack. All
current-head CI gates passed. Greptile completed at 5/5 with no
findings.
- The full local `pnpm test:run` command exited with three database
fixture-startup hook timeouts. It reported 19,529 passing tests and 250
skipped tests. No assertion failed. Its later test groups did not run
because the driver stops on the first failing group.
- The timed-out files were `environment-custom-images-service.test.ts`,
`generic-mcp-connection.test.ts`, and
`modules/wake-queue/adapters/postgres.test.ts`. All 166 tests in these
files passed in isolation on both baseline `edcfcaf3f6` and stack head
`faaca26d46`, with existing timeouts and assertions. The tests and
database-startup helper are unchanged.
- Provider fixtures prove application integration. They do not prove
live third-party execution.

## Risks

- Incorrect inputs or changed await order could affect provider handling
and recovery.
- Existing integration tests exercise the assembled service before and
after extraction.
- No database migration or API change is included.

## Model Used

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

## Checklist


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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 21:03:46 -05:00
DottaandPaperclip b8ffeb973a feat(runner): add experimental Grok Bot agent participation (#16219)
## Thinking Path

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

## Linked Issues or Issue Description

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

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

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

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

## What Changed

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

## Verification

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

## Risks

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

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 20:57:42 -05:00
DottaandPaperclip f6608f382f refactor(server): isolate GitHub task preparation and review containment (#16231)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn provider messages into shared task workflows.
> - The main service still implements provider details beside common
authorization and persistence.
> - These details belong in the existing channel folders.
> - This pull request moves GitHub task prompts, review provenance, and
shared guest containment behind explicit typed functions.
> - The service keeps its shared workflow and selects the provider
implementation directly.

## Linked Issues or Issue Description

Refs: #16192. Stack part 2/5. Depends on #16230. Base:
`codex/chat-channel-inbound-policies`.

**What existing behavior does this improve?**

The ownership and readability of provider behavior in the chat channel
service.

**Current behavior**

The service implements GitHub task prompts, review provenance, and
shared guest containment inline.

**Proposed behavior**

Channel modules own these details. The core calls their typed functions.
Runtime and database effects retain their current order.

**Reason and benefit**

Maintainers can find channel behavior in its channel folder without
following a generic provider framework.

**Breaking changes**

None intended. Public service entry points and durable data shapes stay
compatible.

## What Changed

- Extract GitHub task prompts, review provenance, and shared guest
containment into the existing channel folders.
- Keep shared company scope, authorization, and transaction ownership in
their current workflow.
- Reduce `chat-channels.ts` from 3970 to 3906 lines.

## Verification

- The same 130 selected GitHub and low-trust integration cases passed
before and after extraction. Existing transactions still own
containment, authority receipts, and review rows.
- Server typecheck passed.
- `node scripts/check-module-boundaries.mjs` passed.
- Full workspace typecheck and build passed on the cumulative stack. All
current-head CI gates passed. Greptile completed at 5/5 with no
findings.
- The full local `pnpm test:run` command exited with three database
fixture-startup hook timeouts. It reported 19,529 passing tests and 250
skipped tests. No assertion failed. Its later test groups did not run
because the driver stops on the first failing group.
- The timed-out files were `environment-custom-images-service.test.ts`,
`generic-mcp-connection.test.ts`, and
`modules/wake-queue/adapters/postgres.test.ts`. All 166 tests in these
files passed in isolation on both baseline `edcfcaf3f6` and stack head
`faaca26d46`, with existing timeouts and assertions. The tests and
database-startup helper are unchanged.
- Provider fixtures prove application integration. They do not prove
live third-party execution.

## Risks

- Incorrect inputs or changed await order could affect provider handling
and recovery.
- Existing integration tests exercise the assembled service before and
after extraction.
- No database migration or API change is included.

## Model Used

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

## Checklist


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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 20:54:18 -05:00
DottaandPaperclip 3e8e1efb84 refactor(server): isolate inbound channel message policies (#16230)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - Chat channels turn provider messages into shared task workflows.
> - The main service still implements provider details beside common
authorization and persistence.
> - These details belong in the existing channel folders.
> - This pull request moves inbound message filtering, command
rendering, reply metadata, and setup-reply settlement behind explicit
typed functions.
> - The service keeps its shared workflow and selects the provider
implementation directly.

## Linked Issues or Issue Description

Refs: #16192. Stack part 1/5. Base: `master`.

**What existing behavior does this improve?**

The ownership and readability of provider behavior in the chat channel
service.

**Current behavior**

The service implements inbound message filtering, command rendering,
reply metadata, and setup-reply settlement inline.

**Proposed behavior**

Channel modules own these details. The core calls their typed functions.
Runtime and database effects retain their current order.

**Reason and benefit**

Maintainers can find channel behavior in its channel folder without
following a generic provider framework.

**Breaking changes**

None intended. Public service entry points and durable data shapes stay
compatible.

## What Changed

- Extract inbound message filtering, command rendering, reply metadata,
and setup-reply settlement into the existing channel folders.
- Keep shared company scope, authorization, and transaction ownership in
their current workflow.
- Reduce `chat-channels.ts` from 4082 to 3970 lines.

## Verification

- The same 14 selected chat/Photon integration cases passed before and
after extraction, including Telegram forum controls, guidance retries,
Teams setup replies, and Photon conversation reuse.
- Server typecheck passed.
- `node scripts/check-module-boundaries.mjs` passed.
- Full workspace typecheck and build passed on the cumulative stack. All
current-head CI gates passed. Greptile completed at 5/5 with no
findings.
- The full local `pnpm test:run` command exited with three database
fixture-startup hook timeouts. It reported 19,529 passing tests and 250
skipped tests. No assertion failed. Its later test groups did not run
because the driver stops on the first failing group.
- The timed-out files were `environment-custom-images-service.test.ts`,
`generic-mcp-connection.test.ts`, and
`modules/wake-queue/adapters/postgres.test.ts`. All 166 tests in these
files passed in isolation on both baseline `edcfcaf3f6` and stack head
`faaca26d46`, with existing timeouts and assertions. The tests and
database-startup helper are unchanged.
- Provider fixtures prove application integration. They do not prove
live third-party execution.

## Risks

- Incorrect inputs or changed await order could affect provider handling
and recovery.
- Existing integration tests exercise the assembled service before and
after extraction.
- No database migration or API change is included.

## Model Used

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

## Checklist


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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.2
2026-10-13 20:44:29 -05:00
DottaandPaperclip 450d93d49d fix(auth): deduplicate run history permission checks (#16242)
Share matching run-history permission checks within one list operation while preserving current authorization, redaction, and fresh checks on subsequent requests.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 20:37:48 -05:00
DottaandPaperclip 9fb42df8e5 perf(workspaces): bound parallel snapshot reads (#16239)
Bound workspace snapshot file reads in batches while preserving snapshot contents, ordering, confinement, and failure settlement.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 20:37:37 -05:00
Devin FoleyandPaperclip 5ea3f905cf fix: preserve workspace finalization during watchdog recovery (#16247)
Keep task completion separate from runtime and workspace settlement. Permit verified board file-only repair of successful legacy retained-source runs without authorizing replay.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 18:35:27 -07:00
9cc979116e fix(server): stop reporting queries that outlive the database shutdown (#16243)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The server reports unexpected route errors to Sentry through the
shared error handler.
> - An orderly shutdown drains the HTTP listener, and then it ends the
database pool.
> - `server.close()` completes when the sockets close. A route handler
whose client disconnected, or whose socket the drain timeout closed, can
still run.
> - The next query of that handler fails with postgres.js
`CONNECTION_ENDED`, because this process ended the pool. The error
handler reports this as a 500 crash.
> - This pull request marks the pool as closing just before it ends. The
error handler then skips the error sinks for that one error code during
shutdown.
> - Public MCP calls run in their own internal Express app, so the flag
is also shared with that app.
> - The benefit is that a normal restart does not create false Sentry
crash reports. Real errors are still reported.

## Linked Issues or Issue Description

No public GitHub issue exists. This is the bug description.

**What happened?**

A staging server restarted. During the restart, `GET
/api/companies/:companyId/heartbeat-runs` failed in the per-row run
privacy check (`canActorReadHeartbeatRun`). The error was `Failed query:
select "id" from "issues" ...`. Its cause was `write CONNECTION_ENDED
<host>:5432`. postgres.js raises this code only for a query that starts
after the process called `sql.end()`. The error handler sent the error
to Sentry as a crash.

**Expected behavior**

A query that runs after the shutdown ends the pool is an expected part
of the shutdown. The server must not report it as a crash. If the
response is still open, the server answers `503`. The server must
continue to report all other errors.

**Steps to reproduce**

1. Start the server, and send a slow request (for example, a large
heartbeat run list).
2. Close the client connection, or let the 5 second drain timeout close
it, while the handler still runs.
3. Send SIGTERM. The shutdown drains HTTP and ends the pool.
4. The handler's next query fails with `CONNECTION_ENDED`. Before this
change, the error goes to Sentry.

## What Changed

- `server/src/database-retry.ts`: Add `isEndedDbPoolError`. It finds the
postgres.js `CONNECTION_ENDED` code anywhere in the error `cause` chain.
`isTransientDbConnectionError` now uses the same chain walk. Its
behavior does not change.
- `server/src/index.ts`: The orderly shutdown sets
`app.locals.paperclipDatabaseClosing = true` immediately before it ends
the database pools.
- `server/src/middleware/error-handler.ts`: When the flag is set and the
error is `CONNECTION_ENDED`, the handler answers `503 { error: "Server
is shutting down" }`, or it ends the response if the headers are already
sent. It does not call Sentry or crash telemetry. This follows the
existing client-abort (`ECONNRESET`) case.
- `server/src/services/public-mcp/capabilities.ts` and
`server/src/app.ts`: `createMcpApiDispatch` takes the main app's locals.
Each per-call dispatch app reads `paperclipDatabaseClosing` through a
live getter, so a public MCP call that outlives the pool is handled the
same way (Greptile review finding).
- `server/src/__tests__/error-handler.test.ts`: Add tests for the 503
path, the headers-sent path, `CONNECTION_ENDED` outside shutdown (still
reported), and `CONNECTION_CLOSED` during shutdown (still reported).
- `server/src/__tests__/public-mcp-dispatch-shutdown.test.ts`: Send an
ended-pool error through the real MCP dispatch, both during shutdown
(503, not reported) and outside shutdown (reported).

## Verification

- `cd server && vitest run
src/__tests__/public-mcp-dispatch-shutdown.test.ts
src/__tests__/error-handler.test.ts
src/__tests__/cloud-tenant-transient-db-retry.test.ts`: 25 tests pass.
- With only the error-handler change reverted, the two new error-handler
shutdown tests fail. With only the dispatch change reverted, the MCP
shutdown test fails. The negative-control tests pass in both cases.
- I could not run the full `pnpm -r typecheck`, `pnpm test:run`, and
`pnpm build` locally, or `public-mcp.test.ts`, which needs built
workspace packages. The sandbox has a 4 GB memory limit. CI runs the
full gates.

## Risks

- Low risk. The skip applies only to `CONNECTION_ENDED`, and only after
the shutdown starts to end the pools. postgres.js raises that code only
for a pool that this process ended. Network and database failures
(`CONNECTION_CLOSED`, `CONNECTION_DESTROYED`, and others) are still
reported.
- `CONNECTION_ENDED` outside shutdown (for example, a dedicated client
used after it ended) is still reported as a crash.
- The MCP dispatch app gets only the shutdown flag from the main app's
locals. It does not get any other locals.
- No schema, API contract, or UI change.

## Model Used

Anthropic Claude Opus 5.5 (`claude-opus-5-5`) in Claude Code, with tool
use (repository inspection, shell, test execution) and the Sentry and
GitHub connectors.

## 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

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

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 18:26:03 -07:00
f987f95d6a fix(cli): guard service install against a missing managed shim (#13985)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The `paperclipai` CLI can run Paperclip as a background service
(launchd on macOS, a systemd user unit on Linux), and that service
definition always launches the managed-install shim
> - #12148 made onboarding create the managed install first
(`ensureServiceShim()`), or refuse with a repair path, when the shim
does not exist
> - The standalone `paperclipai service install` command never got that
guard: it calls `manager.install()` directly, reports `installed: true`,
and leaves the supervisor crash-looping on a missing binary (for example
after a global npm install)
> - This pull request runs the same onboarding guard in `service
install` before any service definition is written
> - The benefit is that `service install` either produces a service that
can start, or fails with the same repair instructions onboarding gives,
and never reports success for a service that cannot run

## Linked Issues or Issue Description

- Fixes: #13841
- Refs #12148 (the onboarding-path fix this extends), #11755 and #11620
(related global-npm / service issues, not addressed here)

## What Changed

- `cli/src/onboard-service.ts`: moved the existing onboarding shim
guard, unchanged, into an exported `ensureServiceShim()` so both entry
points share it. It takes an optional `installIfMissing` flag that
defaults to `true`, so onboarding behaves exactly as before. When only
the shim is missing (a managed install is recorded and its current
payload is still present), the guard now runs the installer's existing
`smokePayload()` check (the payload must run and report its recorded
version), then rewrites the shim in place with the existing
`writeManagedShim()` instead of reinstalling. A payload that fails the
check gets no new shim; the command stops with the repair hint. The
recorded version and update channel stay unchanged, with no download and
no payload pruning. Otherwise the existing onboarding fallback
(reinstall the recorded git revision, or install this CLI's release
version) is unchanged.
- `cli/src/commands/service.ts`: `service install` now calls
`ensureServiceShim()` after the service manager is resolved and before
`manager.install()`. If the shim cannot be made available, the command
throws `Background service not installed: <reason>. Run \`paperclipai
install\`, then \`paperclipai service install\`.` (exit code 1) and
writes no service definition.
- With `--json`, the command only checks for the shim and does not start
a managed install. `installCommand()` prints progress to stdout, which
would corrupt the machine-readable result. JSON callers get a clean
non-zero exit with the repair hint; interactive callers get the same
behavior as onboarding (create the managed install, then the service).
The JSON output shape and all existing flags are unchanged.
- Docs: no change needed. `doc/INSTALLING.md` already says the service
uses the managed-install shim; this makes the command enforce that.
- Tests: a new command-level test (`service-install-command.test.ts`)
and one `ensureServiceShim` case in `onboard-service.test.ts`.

## Verification

- `pnpm exec vitest run
cli/src/__tests__/service-install-command.test.ts` on unmodified
`master` (efce9356): 3/3 tests fail (the guard is never called, and the
missing-shim command resolves instead of rejecting). With this change:
pass.
- `pnpm exec vitest run
cli/src/__tests__/service-install-command.test.ts
cli/src/__tests__/onboard-service.test.ts
cli/src/__tests__/service-health-check.test.ts`: 36/36 pass.
- The tests cover: the guard runs before `manager.install` (call order);
`--no-start-now` / `--no-start-on-login` are still forwarded;
`installed: true` JSON is printed only on success; a failed guard
rejects with the repair message, never calls `manager.install`, and
prints nothing; `--json` uses check-only mode; check-only mode never
calls `installCommand`; with a managed payload present, the repair
smoke-tests the payload, then restores the shim in place without calling
the installer, and rechecks the executable; a payload that fails the
smoke test gets no shim and no reinstall.
- `pnpm --filter paperclipai typecheck` and `pnpm --filter paperclipai
build`: pass.
- Repo-wide `pnpm -r typecheck` and `pnpm build` stop at the unchanged
`paperclip-runner` package because `cargo` is not installed locally.
They fail the same way on unmodified `master`, so CI is the authority
there.
- `pnpm test:run` locally: 32 server failures. 30 reproduce on
unmodified `master` (AI-connection/auth and worktree-provisioning
cases). The other 2 pass when run alone on both `master` and this
branch. None are in `cli/`.
- Manual check for reviewers: with no `~/.local/bin/paperclipai`,
`paperclipai service install --json` now exits 1 with the repair hint
and writes no LaunchAgent/unit. Without `--json`, it creates the managed
install first, then the service.

## Risks

- Low risk. Behavior changes only when the managed shim is missing,
which is exactly the case that used to produce a crash-looping service.
- Behavior shift: in that case, `service install --json` now fails
instead of reporting a service that cannot start. Scripts that relied on
the old false success will see exit code 1 and the repair instructions.
- Onboarding is unchanged. The guard body moved into a named function,
and onboarding calls it with the same defaults.

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

## Model Used

- Implementation and tests: OpenAI Codex, model `gpt-6-astra` (agentic
coding with tool use and code execution; context window not reported by
the runtime).
- Plan critique before implementation: OpenAI `gpt-5.6-sol` at high
reasoning effort (read-only).
- Coordination, scoping and PR description: Anthropic Claude Opus 5.5
(`claude-opus-5-5`, 1M context, tool use).
- Independent code review of the exact head: Anthropic `claude-sonnet-5`
at medium effort (read-only), no findings.
- A human contributor directed the work and owns the 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

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

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
canary/v2026.1014.0-canary.1
2026-10-13 17:20:36 -07:00
Devin FoleyandPaperclip b7f41ee51d perf(ci): warm the public-install npm cache during pnpm build (#16204)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Each pull request runs the Trusted PR CI. The `ci / Build` lane is
the longest check, or close to the longest, in each green run.
> - On 2026-10-13, `ci / Build` took 415-446s in runs 38426120144,
38432086560 and 38423713537. Of that, the public-install verifier took
226-241s.
> - In the verifier, the consumer `npm install` took 119-129s. It
downloads the full public registry graph into an empty npm cache.
> - Source manifests set that graph. Thus CI can download it before
`pnpm build` makes any tarball.
> - This pull request fills the npm cache in the background while the
Rust restore, Evalbook and `pnpm build` run. Then the verifier reads
that cache.
> - The benefit is a shorter `ci / Build` lane. The verifier keeps all
its checks.

## Linked Issues or Issue Description

Refs #15213, #15849, #15868, #15888 (earlier changes that made this
verifier faster).

**Enhancement description**
The `ci / Build` lane runs the public-install verifier after `pnpm
build`. The verifier starts with an empty npm cache. Its consumer
install then downloads the full public registry graph: 119-129s of a
226-241s step.

**Proposed change**
Download the same registry graph into an npm cache in the background,
during the earlier part of the lane. Give that cache to the verifier.

**Why it helps**
The download moves off the critical path of the lane. A local test of
the same 628-package install took 51s with a cold cache and 21s with a
warm cache.

## What Changed

- Add `scripts/public-install-closure.mjs`. It holds the one definition
of the public package closure: `@paperclipai/server`, `paperclipai`, and
each public workspace package that they reach through `workspace:`
specs. It also gives the registry dependencies of that closure.
- Add `scripts/warm-public-install-npm-cache.mjs`. It installs those
registry dependencies into a temporary consumer, with scripts disabled,
to fill `PAPERCLIP_PUBLIC_INSTALL_NPM_CACHE`. Then it removes the
temporary consumer.
- `scripts/verify-grok-npm-install.mjs` now gets its closure from the
shared module. When `PAPERCLIP_PUBLIC_INSTALL_NPM_CACHE` is set, it uses
that directory as the consumer npm cache. When the variable is not set,
it uses a new empty cache, as before. `docker-runner-check.yml` and
`release-smoke.yml` do not change.
- `pr-trusted.yml` (Build job): a new step starts the warm-up in the
background after `Install dependencies`. The verify step waits for the
warm-up for a maximum of 180s and then gives the cache to the verifier.
If the warm-up fails, the step writes a notice and the verifier
continues as before.
- Add `scripts/__tests__/public-install-closure.test.mjs` and add it to
`test:release-registry`. Update the closure assertions in
`grok-public-install-sandbox.test.mjs`.

## Verification

- `node --test scripts/__tests__/public-install-closure.test.mjs`: 4/4
pass.
- `node --test scripts/__tests__/grok-public-install-sandbox.test.mjs`:
24/24 pass.
- `node --test scripts/__tests__/run-vitest-stable-shard.test.mjs
scripts/__tests__/e2e-shard.test.mjs
scripts/__tests__/runner-release-crate-cache.test.mjs`: all pass.
- `release-verify-workflow.test.mjs`: the two "publisher lockfile" tests
fail in my sandbox on clean master too, because they need pnpm. Two
canary git-fixture tests timed out once under load. They pass when they
run alone.
- I ran the warm-up against current master: 62 direct dependencies, 628
packages, 51s cold. The same install with the warm cache took 21s.
- Important: `pr.yml` calls `pr-trusted.yml@master`. Thus the CI of this
pull request runs the refactored verifier on its default path (empty
cache), but not the new warm-up steps. The warm-up steps start after
merge. To measure them, compare the `consumer_install_ms` value in the
`paperclip.public-npm-install.timing.v1` line of a Build job before and
after merge.

- Final review: all latest-head CI checks pass (54 successes, one
neutral result, two intentional skips). Fresh Apex is 5/5 on
`64d091b8b0c5359fa3dc0edb1fd7ef9d24294477` with no unresolved findings.
The two relevant local script suites pass all 28 tests. Current master
combines cleanly.

## Risks

- Low risk. The verifier result does not change. npm checks each cached
tarball against the integrity of its own resolution, and the consumer
directory and lock start empty.
- npm can use a cached registry packument that is a maximum of about 5
minutes old (registry `max-age`). This has the same effect as starting
the verifier a few minutes earlier.
- The warm-up runs at the same time as `pnpm build`. It uses network,
disk and some CPU. In the measured runs, `pnpm build` took 76-96s.
- If the warm-up is slow or fails, the verify step waits a maximum of
180s and then continues with what is in the cache.
- The verifier receipt still reports `cleanNpmInstall: true`. The
consumer install is clean. Only the download cache is shared.

## Expected time savings

- `ci / Build`: an estimated 65-85s less, from 415-446s to about
340-370s. The consumer install goes from 119-129s to about 40-55s, from
the local cold/warm ratio.
- Full PR time: after this change, `ci / Build` is no longer the longest
lane. The longest lanes become `General tests (server N/12)` and `Verify
Paperclip Runner (vitest 1/2)` at about 405-496s. Thus the full PR time
decreases only when Build is the critical path. That is approximately
0-30s in the runs above.

## Model Used

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

OpenAI GPT-6 (`gpt-6`) through Codex assisted the final repository
review and targeted script validation. This session does not expose an
exact 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

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1014.0-canary.0
2026-10-13 17:18:44 -07:00
e0f30a4c71 feat(apps): collapse provider connections behind an "N connections" toggle (#16097)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Apps page shows one card for each provider. Each card lists the
connections for that provider.
> - Some providers have many connections. For example, a team can have
five OpenAI accounts.
> - Each connection uses a full row. Thus, the page becomes long and
cluttered.
> - This pull request puts the connection list behind a "N connections"
row with a chevron. The user clicks the row to show or hide the list.
> - The benefit is a shorter Apps page. Connections that need action
stay visible.

## Linked Issues or Issue Description

**Subsystem affected**
UI: the Apps page (`ui/src/pages/apps/Browse.tsx`), the `ConnectorCard`
component.

**Problem or motivation**
A provider card shows every connection as a full row. When a provider
has many accounts, the card is very tall. The page is hard to scan.

**Proposed solution**
When a card has two or more connections, show a "N connections" row with
a chevron below the card header. A click on the row opens or closes the
list. The list is closed when all connections are healthy. The list is
open when a connection needs attention or setup. The row also shows the
count, for example "· 1 needs attention". The list is open while a
search is active. A card with one connection does not show the row.

**Alternatives considered**
- Always show the list. This is the current behavior, and it causes the
clutter.
- Show the toggle for one connection too. This adds a click and gives no
benefit.
- Always close the list. This can hide an account that needs
reconnection, so we did not use it.

## What Changed

- `ConnectorCard` counts native connections, gateway-managed accounts
(Composio, Arcade, Executor), and chat or bot endpoints.
- When the count is two or more, the card wraps the list in the existing
`Collapsible` component. The trigger row shows the count and a chevron
that turns when the list opens.
- The list opens by default when one or more connections need attention
or setup. The trigger row shows how many need attention.
- The `Browse` page sends `defaultExpanded` and the current trimmed
search query while a search is active. A new search opens the list
again, even after the user closed it.
- The upstream account state logic moved into the `upstreamAccountState`
helper. The list render and the attention count use the same helper. The
behavior did not change.
- The attention count and Finish setup action share one predicate. A
verifying endpoint stays visible until setup is complete. Four
regression cases cover provider setup, identity linking, missing setup
metadata, and completed setup.
- New tests in `Browse.test.tsx` cover: open and close with the toggle,
search opens the list, one connection stays inline, and the list opens
when an account needs attention.
- New review story:
`ui/storybook/stories/connection-setup/apps-connection-count-toggle.stories.tsx`
("Apps, channels, and extensions / Connection setup / Connection count
toggle"). It includes production component fixtures for collapsed,
expanded, needs-attention, search-match, single-connection,
page-overview, and unfinished-chat-setup states. The original six story
IDs are retained; the unfinished chat setup fixture adds one ID.

## Verification

- `pnpm exec vitest run ui/src/pages/apps/Browse.test.tsx`: all 84 tests
pass. The new test closes an active search result, changes the query,
then returns to the first query. It fails before the search-reset fix
and passes after it.
- `node scripts/storybook-catalog.mjs --check`: passes (265 story files,
2,520 stories). Story annotations describe the production components,
fixture boundary, and covered capabilities.
- `pnpm check:token-gates`: passes.
- Full repository typecheck and build passed after the master merge. The
final UI typecheck passes after the setup fix. Final full build and
Storybook build pass on `d4c923d3ce0`. The built index retains all six
prior story IDs and adds the unfinished-chat-setup ID. Chromium checks
pass for all seven states, including the setup action and toggle
behavior. All 54 successful CI checks pass on this head, with two
intentional skips, including all general and serialized test shards,
E2E, typecheck, and build. The fresh Apex review is 5/5 on this head
with no unresolved findings. The separate, unsharded local `pnpm
test:run` invocation has not completed; complete suite verification
comes from CI.
- The stories use local account fixtures and stub navigation. They do
not prove a live provider connection or persistence.

## Risks

- Low risk. The change is UI only, with no API or data change.
- Behavior change: users must click to see the connections on a healthy
card with two or more connections. Cards with a problem stay open, so a
broken connection is not hidden.

## Model Used

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

OpenAI GPT-6 (`gpt-6`) through Codex assisted conflict resolution,
regression tests, and repository verification. This session does not
expose an exact 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

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

---------

Co-authored-by: Devin Foley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 14:57:48 -07:00
ba4fac585d feat(agents): show who created an agent in shared companies (#16055)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - A company in Paperclip can have more than one human member, and each
member can create agents
> - The app does not record which person created an agent
> - When two or more people share a company, members cannot see who
added an agent or who to ask about it
> - This pull request records the creator of each agent and shows the
creator on the agent Overview tab
> - The benefit is clear ownership of agents in shared companies, with
no change for single-user companies

## Linked Issues or Issue Description

No public issue exists. This description follows `feature_request.yml`.

**Subsystem affected**

Agents: the agent data model, the agent create path on the server, and
the agent Overview tab in the board UI.

**Problem or motivation**

Paperclip does not record which human user created an agent. When more
than one human user works in a company, the agent page does not tell
members who created the agent.

**Proposed solution**

Record the user ID of the creator when a human creates an agent. Show
"Created by <name>" on the Identity card of the agent Overview tab. Show
this row only when the company has two or more human members. Do not
count the synthetic local Board principal as a human member. Do not show
the local Board as a creator.

**Alternatives considered**

Count human users across the full instance. We did not do this. An
instance-wide count tells a member of one company that other companies
have users. The creator is always a member of the agent's company, so
the company count is sufficient.

**Roadmap alignment**

`ROADMAP.md` has no item for agent ownership. This change is small and
additive.

## What Changed

- Add the nullable column `agents.created_by_user_id`
(`packages/db/src/schema/agents.ts`, migration `0343_new_mentor.sql`).
- Set the column in the single agent insert path
(`server/src/modules/agent-lifecycle/adapters/records.ts`). The value
comes from the authenticated user actor. The server ignores a creator
value in the request body. Agents that agents or the system create keep
`null`.
- Backfill existing agents in the migration. The backfill uses the
earliest `agent.created` or `agent.hire_created` activity row that a
user actor wrote in the same company.
- Add `createdByUserId` to the shared `Agent` type
(`packages/shared/src/types/agent.ts`).
- Add `ui/src/lib/agent-creator.ts`. It decides if the UI shows the
creator row and it resolves the creator name. If the creator left the
company, the row shows "Former member".
- Add the "Created by" row to the Identity card in
`ui/src/pages/AgentDetail.tsx`. If the company user directory request
fails, the row shows "Could not load creator". The row does not
disappear silently.
- Add the Storybook story `Pages/Agent Detail → Shared Company Shows
Creator`.
- Document the column in `doc/SPEC-implementation.md` §7.2.

## Verification

- `pnpm --filter @paperclipai/db typecheck` passes. This includes the
migration numbering and migration safety checks.
- `pnpm --filter @paperclipai/shared typecheck` passes.
- `ui`: `tsc --noEmit` passes.
- `server`: `vitest run
src/modules/agent-lifecycle/__tests__/lifecycle.test.ts` passes (49/49).
Two new tests:
- The server records the creator from the actor and ignores a creator
value in the request body.
- The backfill takes the earliest user activity row. It skips agent
actors and rows from other companies.
- `server`: `vitest run src/__tests__/built-in-agents.test.ts` passes
(40/40). A new test checks that a built-in agent enabled by a human
records that human, and that automatic provisioning stays unattributed.
The gated (pending-approval) provisioning test also asserts the creator.
`src/__tests__/built-in-agent-routes.test.ts` also passes.
- `ui`: `vitest run src/lib/agent-creator.test.ts
src/pages/AgentOverview.test.tsx` passes (10/10). The tests cover these
cases: the row shows with two or more humans, the row stays hidden with
one human plus the Board, the UI never shows the Board as the creator,
the row shows an error when the directory request fails, and the row
stays hidden (no error) for agents with no creator or the Board as
creator. The last case fails without the fix.
- The current Storybook catalog uses source annotations and generated
indexes. `node scripts/storybook-catalog.mjs --check` passes (264 story
files, 2,514 stories). The merge keeps the authored catalog deletion
from master.
- `pnpm check:token-gates` is clean.
- Screenshots from the Storybook story (fake data: two human members,
Alice Admin and Bob Builder, plus the local Board). The red "Could not
load public key" text is a Storybook artifact: the story has no fixture
for the public key request. The existing `Dashboard` story shows the
same text.

  **Two or more human members: the Identity card shows "Created by".**

![Identity card with the Created by
row](https://raw.githubusercontent.com/paperclipai/paperclip/9b62bd2ea6cf984ce6745f08cc45f44ddf00fb51/pr-16055/identity-created-by.png)

  **One human member plus the local Board: the row stays hidden.**

![Identity card without the Created by
row](https://raw.githubusercontent.com/paperclipai/paperclip/9b62bd2ea6cf984ce6745f08cc45f44ddf00fb51/pr-16055/identity-single-human.png)

Full Overview tab:
[overview-created-by.png](https://raw.githubusercontent.com/paperclipai/paperclip/9b62bd2ea6cf984ce6745f08cc45f44ddf00fb51/pr-16055/overview-created-by.png).
The images are on the separate branch `pr-assets/agent-created-by`. They
are not in this PR and do not go to `master`.
- Manual check: open Storybook at `Pages/Agent Detail → Shared Company
Shows Creator`. The Identity card shows "Created by Alice Admin". The
`Dashboard` story has one human, so it does not show the row.
- Final focused verification on
`5a02350cf16050a3cf3cb3f8dc061fe61758c60d`: all 99 tests pass across the
two UI suites, built-in-agent suite, and lifecycle suite. The backfill
test applies the complete migration twice. The migration uses `ADD
COLUMN IF NOT EXISTS` and preserves the company-scoped backfill.
Migration numbering and token checks pass.
- Full repository typecheck, build, and Storybook build pass. The
generated creator story ID is present. A Chromium check renders the
production agent page fixture and verifies the creator row and Alice
Admin name. Map checks and their 21 tests pass. A fresh Apex review is
5/5 on the current head with no unresolved findings. All 54 successful
CI checks pass on this head, with two intentional skips, including all
general and serialized test shards, E2E, typecheck, and build. The
workspaces-b job passed after rerunning a runner shutdown; no source
change was needed. The separate, unsharded local `pnpm test:run`
invocation has not completed; complete suite verification comes from CI.

## Risks

- Migration: the migration adds one nullable column and runs one
`UPDATE` on `agents` with a correlated subquery on `activity_log`. On an
instance with a very large activity log, the backfill can take some
time. The migration does not lock other tables and does not delete data.
- Backfill accuracy: agents with no user-authored create activity row
keep `null`. The UI then does not show a creator. This is the same as
the current behavior.
- Privacy: the row shows only names from the company user directory, and
only to users who can already see that directory.
- Low risk for single-user companies: the UI does not change for them.

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

## Model Used

- Provider: Anthropic, Claude Opus 5.5 (model ID `claude-opus-5-5`), run
as a coding agent through Claude Code with tool use (shell, file edit,
and test execution), standard context window.

OpenAI GPT-6 (`gpt-6`) through Codex assisted conflict resolution,
regression tests, and repository verification. This session does not
expose an exact 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

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

---------

Co-authored-by: Amy (Opus) <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-10-13 14:57:41 -07:00
DottaandPaperclip 2238831ecd test(voice): qualify Speko task conversations and Storybook surfaces (#15729)
Third PR: depends on #15728 and #15727. The user has reviewed and
authorized merging this experimental feature stack.

## Thinking Path

> - Paperclip manages agent work through tasks and governed connections.
> - Chat connections already bind external conversations to those tasks.
> - Speko handles voice and telephony, while the selected Paperclip
agent does the work.
> - A call needs durable session authority, ordered follow-ups, and safe
result delivery.
> - This PR adds repeatable qualification for the Speko voice task
integration.
> - This PR depends on #15728, which depends on #15727. Speko stays
experimental.

## Linked Issues or Issue Description

**Problem or motivation**

Phone and browser voice conversations cannot use the chat connection
task lifecycle. A separate voice runtime is needed to preserve task
authority, retries, and reply history.

**Proposed solution**

Add company-scoped voice sessions, signed callbacks, durable replies,
inbound intake, and an agent-facing outbound-call tool. Reuse existing
tasks, queues, secrets, and publications.

**Roadmap alignment**

This extends the experimental chat connector entry points under Agent
Chat and Connected Apps. The project owner requested this feature.

Refs #11418 for the original provider catalog proposal. This
implementation uses the newer chat connection infrastructure rather than
an MCP catalog-only integration. Refs #15721 for remote OpenCode
startup.

## What Changed

- Add a real Paperclip server/database E2E fixture that stubs only
external Speko transport and the execution provider.
- Add authenticated multi-user and cross-company qualification journeys.
- Add Storybook interaction, accessibility, responsive, and visual-suite
integration.
- Add an E01–E16 runbook, component-to-story inventory, and current
redacted qualification report.
- Keep historical private call traces out of the PR. Provider proof
tools are opt-in.

## Verification

- All 21 standalone proof tests and browser client/server syntax checks
pass. They cover signatures, redaction, cleanup retry, final audio
saves, bounded report transport and late server write ordering. No live
calls were placed.
- All 27 focused UI/controller regressions, UI typecheck, token gates,
and 28 map/catalog structural tests pass. The shared connection cache
test covers pause/resume invalidation during the 30-second fresh period.
- Storybook builds 157 Speko production-component stories. The complete
prior 156-story set passed all 624 checks on UI source 249cbc616a. After
the final cache repair, all 152 affected page/launcher checks passed
across both themes, 390/1200 widths and reduced motion. Real microphone
access and external provider requests are blocked.
- Hosted Storybook origin isolation and representative narrow-screen
stories pass. Provider requests remain blocked.
- Source annotations follow the current generated-catalog contract. No
generated catalog or lockfile is included. Three inherited
GitHub-heading tests passed after master reconciliation.
- Commit 905bc5da5d has 55 passing checks,
including required verify/E2E gates, and a fresh Greptile 5/5 review
with zero unresolved findings. Local fixture success does not establish
provider or spoken-playback acceptance.
- The separate integrated browser run passed two journeys and failed
browser answer retrieval. Real browser/telephone playback and timing
acceptance remain outstanding. See the dated qualification report and
E01–E16 runbook. Speko stays experimental.

## Risks

- Voice sessions add migrations and provider-dependent lifecycle
behavior. Migrations preserve existing chat and AI transports.
- Callback origins must be reachable HTTPS. Provider keys and signing
secrets remain vaulted.
- Unverified callers receive task-scoped low-trust authority. Caller ID
does not grant private task access.
- Outbound telephony incurs provider charges. Provider acceptance is not
proof that the caller heard an answer.
- Keep the feature behind the existing experimental chat setting until
the real browser, inbound, outbound, and delayed-result acceptance
matrix passes.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 16:54:41 -05:00
a64969b288 fix(server): attribute legacy runs stopped by controller lease loss (#16084)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The heartbeat runner executes legacy agent runs. A controller lease
watchdog keeps durable ownership of each legacy run.
> - When the watchdog loses the lease, it aborts the adapter. The abort
reason was a plain `Error`, and nothing recorded why the run stopped.
> - Completion then saved the cancellation as source `unknown`. Sentry
got an unexpected cancel that it could not tell apart from other
unrecorded stops.
> - We saw this on a sandboxed Grok run. The system cancelled it after
about 22 minutes with `cancellationSource: unknown`. Workspace copy-back
then failed. Every `cancelRun` path records a stop request, so an
unrecorded stop this late points to the lease watchdog.
> - This pull request records a lease loss as its own cancellation
source, with a closed cause label.
> - The benefit is that the next event shows whether the lease loss
caused the stop, and which renewal failure caused it. That is the
missing fact to fix the root cause.

## Linked Issues or Issue Description

Refs #15790
Refs #15920

**What happened?**
A legacy sandbox run was stopped by the system while it was working. The
run record and the Sentry diagnostics show `cancellationSource:
unknown`, with no initiator. The controller lease watchdog aborts the
adapter with a plain `Error("Legacy controller lease lost")`. Completion
does not read the abort reason, so it records the stop as `unknown`.

**Expected behavior**
When the host stops its own adapter because it lost the controller
lease, the run records that cause. Diagnostics name the cause with a
closed label. A stop that a user or the control plane requested earlier
keeps its recorded source.

**Steps to reproduce**
1. Start a legacy run that has a controller lease.
2. Make lease renewal fail: the renewal query errors, the update matches
no row, or the lease deadline passes.
3. Let the adapter return its cancelled result.
4. Read `resultJson.cancellation` on the run. Before this change,
`source` is `unknown`.

**Agent adapter(s) involved**
Not adapter-specific (core bug). We saw it with `grok_local` in a
sandbox.

**Additional context**
This change adds diagnostics. It does not prevent the lease loss. #15920
retries a transient copy-back failure. It does not help here, because
the stopped sandbox rejects every retry.

## What Changed

- `legacy-controller-lease.ts`: The watchdog aborts with a new
`LegacyControllerLeaseLostError`. The error carries a closed cause:
`renewal_rejected`, `renewal_deadline`, or `renewal_error`.
- `run-cancellation.ts`: Add the `controller_lease` cancellation source.
Add `controllerLeaseLossCancellation()` and
`readControllerLeaseLossCause()`. The reader accepts only the
server-written reason text.
- `heartbeat/run-completion.ts`: When the outcome is `cancelled` and the
abort reason is a lease loss, record a `controller_lease` cancellation
(`expected: false`). This covers both an adapter that returns a
cancelled result (`completeRun`) and one that throws after the abort,
for example through `signal.throwIfAborted()` (`failRun`). A stop
request recorded earlier still takes precedence.
- `run-failure-diagnostics.ts`: Add `controllerLeaseLossCause` to the
execution diagnostics. Only the closed label goes to Sentry, never the
reason text.
- `heartbeat/run-state.ts`: preserve `controller_lease` in the bounded
SQL projection when saved results exceed 64 KB. A database regression
verifies the default run-detail read.
- `canContinueCancelledRun` stays unchanged. It does not accept
`controller_lease`, so a lease loss does not authorize automatic
continuation.
- `doc/run-log-events.md`: Document the new source and cause labels.
- Tests: unit tests for the cause on each watchdog path, completion
tests that record the source when the adapter returns and when it throws
the abort reason (both fail without the change), tests that a recorded
stop request takes precedence, and a test that the Sentry report
contains the closed label and not the reason text.

## Verification

- `cd server && npx vitest run src/services/run-cancellation.test.ts
src/services/legacy-controller-lease.test.ts
src/services/__tests__/run-failure-report.test.ts
src/services/heartbeat/run-completion.test.ts`: 238 passed, including
the embedded Postgres suites.
- I reverted only `run-completion.ts` and ran the new completion test.
It failed with `source: "unknown"`. With the change, it records
`controller_lease`.
- I removed only the `failRun` attribution and ran the new thrown-error
test. It failed without the `controller_lease` record, and passes with
it.
- Final full repository `pnpm -r typecheck` and `pnpm build` pass.

- Final local regression verification: all 247 tests pass across
run-state, cancellation, watchdog, failure reporting, and completion
suites. The large-result test fails before the SQL allowlist change. All
latest-head CI checks pass (54 successes and two intentional skips).
Fresh Apex is 5/5 on `708856c568d07d7b446a4a4af2edc6d9eec7d155` with no
unresolved findings.

## Risks

- Low risk. The change adds a new source value to server-owned JSON. Old
rows keep their values. The readers accept the new value, and no UI code
switches on this field.
- A lease-loss cancel stays `expected: false`, so it is still reported
as unexpected, as before. Now it has a more specific source.
- The Sentry payload gets one new closed label
(`controllerLeaseLossCause`). It does not include reason text or IDs.

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

## Model Used

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

OpenAI GPT-6 (`gpt-6`) through Codex added the large-result regression
and SQL projection fix, with shell, file-edit, and test tools. The exact
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

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

---------

Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 14:50:40 -07:00
DottaandPaperclip edcfcaf3f6 fix(ui): leave hidden task source defaults to the server (#16220)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The task dialog sends project and workspace choices to the control
plane.
> - Hidden workspace controls must leave automatic source choices to the
server.
> - The dialog still sent its computed source pointer while those
controls were hidden.
> - This bypassed the implicit default branch added in #16095 and saved
an untyped source choice.
> - This pull request omits that automatic pointer and preserves
explicit launch context.
> - The benefit is that fresh tasks can use the server's safe isolated
default source path.

## Linked Issues or Issue Description

Refs #16095. A search found no open duplicate for the hidden-selector
payload bug.

**What happened?**

A fresh task created through the board with a project and hidden
isolation controls failed setup with “Task workspace access is no longer
available.” The dialog sent `projectWorkspaceId` even though the user
had not selected a source. The saved task had no workspace-selection
provenance. No provider turn started.

**Expected behavior**

Omit automatic or restored draft source pointers when the selector is
hidden. Let the server select and record the project default. Preserve
explicit source and execution-workspace context supplied by a launch
action.

**Steps to reproduce**

Hide `workspaces.isolation` through the existing operator setting. Use a
project with a default Git source and isolated workspace policy. Create
a fresh task from the board. Inspect the creation payload: the hidden
automatic source must be omitted. The server must then apply its
existing default source contract. A restricted shared source must remain
protected.

**Paperclip version or commit**

Observed on Core `c7f4b74111d16f0b57112fa6d0b6a59c2d63bfe8`, which
includes #16095.

**Deployment mode**

Authenticated staging Cloud instance with a configured remote runner
provider and operator-hidden workspace controls.

## What Changed

- Omit the automatic `projectWorkspaceId` while isolation controls are
hidden.
- Keep explicit same-project launch source context, including reused
workspaces and subtasks.
- Add a fresh-default payload regression and strengthen stale-draft and
explicit-context controls.
- Keep server authorization, trust checks, source fallback rules,
visible selectors, and stored old tasks unchanged.

## Verification

- Before the repair, the hidden fresh/default and restored-source
regressions failed: 2 failed, 3 passed, 79 other cases filtered.
- Final rebased source: `pnpm exec vitest run --project @paperclipai/ui
ui/src/components/NewIssueDialog.test.tsx
ui/src/lib/project-workspace-defaults.test.ts` passed all 87 cases.
- `pnpm --filter @paperclipai/ui typecheck` passed.
- `pnpm --filter @paperclipai/ui build` passed.
- `pnpm check:token-gates` passed.
- Initial UI typecheck failed because this new checkout had not built
the plugin SDK. Building that dependency and repeating the unchanged
check passed. The failed attempt remains separate from the source
regression.
- Full repository typecheck, full repository tests, and full repository
build have not been run locally for this two-file UI patch. Complete
latest-head CI passed with 55 successful checks and two intentional
skips. This includes the full repository typecheck, build,
general/serialized tests and all eight browser shards. Fresh Apex is 5/5
on `f992823480311691469c6797d5cdff26d76899a2`, with no unresolved
findings or recommendations.
- No live recovery pass is claimed. The deployed baseline failed before
provider startup. A fresh same-project task must pass after this patch
is deployed. Existing tasks with untyped source pointers need a separate
authorized recovery path.
- The old Storybook maps were reviewed at the baseline, then master
removed them. The rebase preserves that removal. The final Storybook
structural check covers 262 files and 2,485 story IDs. No new Storybook
browser, play, render, or visual proof is claimed.

## Risks

- Hidden restored draft source choices are intentionally ignored.
Explicit same-project launch defaults remain in the request and have
controls for normal tasks and subtasks.
- Visible workspace choices retain their existing behavior.
- This patch fixes one creation path. It does not recover old tasks,
relax private source restrictions, or establish a performance fix for
slow historical runs.
- No data model, endpoint, permission, runner, or Observability changes.

## Model Used

OpenAI GPT-6 through Codex, with code and browser tools. The exact
served model identifier and context-window size are not exposed in this
session.

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 14:26:56 -07:00
DottaandPaperclip 22d05644f4 feat(ui): add Speko voice setup, task calls, and Storybook coverage (#15728)
Runtime #15727 is merged. This PR adds the UI. Qualification follows in
#15729.

## Thinking Path

> - Paperclip manages agent work through tasks and governed connections.
> - Chat connections already bind external conversations to those tasks.
> - Speko handles voice and telephony, while the selected Paperclip
agent does the work.
> - A call needs durable session authority, ordered follow-ups, and safe
result delivery.
> - This PR adds the Speko setup and call controls to the existing Apps
and task UI.
> - This PR depends on #15727. The qualification suite follows
separately. Speko stays experimental.

## Linked Issues or Issue Description

**Problem or motivation**

Phone and browser voice conversations cannot use the chat connection
task lifecycle. A separate voice runtime is needed to preserve task
authority, retries, and reply history.

**Proposed solution**

Add company-scoped voice sessions, signed callbacks, durable replies,
inbound intake, and an agent-facing outbound-call tool. Reuse existing
tasks, queues, secrets, and publications.

**Roadmap alignment**

This extends the experimental chat connector entry points under Agent
Chat and Connected Apps. The project owner requested this feature.

Refs #11418 for the original provider catalog proposal. This
implementation uses the newer chat connection infrastructure rather than
an MCP catalog-only integration. Refs #15721 for remote OpenCode
startup.

## What Changed

- Add the Speko Apps catalog entry, provider artwork, and browser SDK.
- Reuse existing agents in setup. Keep the optional Company Phone Agent
in the catalog, with connection instructions available to any assigned
agent.
- Add task voice controls, transcripts, phone callbacks, inbound-line
settings, and call Activity entries.
- Surface retryable connection and incoming-task inventory failures,
preserve active call controls and cached tasks, restore keyboard focus
after recovery, and bound notification polling so a stuck request cannot
hide later results.
- Put Save & exit and Connect Speko in the credential step’s shared
footer.
- Add deterministic production-component Storybook fixtures for setup,
lifecycle, failures, permissions, and phone surfaces.
- Include voice components in the design guide. Stories never request a
real microphone or place calls.

## Verification

- All 27 focused UI/controller regressions, UI typecheck, token gates,
and 28 map/catalog structural tests pass. The shared connection cache
test covers pause/resume invalidation during the 30-second fresh period.
- Storybook builds 157 Speko production-component stories. The complete
prior 156-story set passed all 624 checks on UI source 249cbc616a. After
the final cache repair, all 152 affected page/launcher checks passed
across both themes, 390/1200 widths and reduced motion. Real microphone
access and external provider requests are blocked.
- Source annotations follow the current generated-catalog contract. No
generated catalog or lockfile is included. Three inherited
GitHub-heading tests passed after master reconciliation.
- Latest-head CI and Greptile review must pass before merge. Local
fixture success does not establish provider or spoken-playback
acceptance.
- The separate integrated browser run passed two journeys and failed
browser answer retrieval. Real browser/telephone playback and timing
acceptance remain outstanding. See the dated qualification report and
E01–E16 runbook. Speko stays experimental.

## Risks

- Voice sessions add migrations and provider-dependent lifecycle
behavior. Migrations preserve existing chat and AI transports.
- Callback origins must be reachable HTTPS. Provider keys and signing
secrets remain vaulted.
- Unverified callers receive task-scoped low-trust authority. Caller ID
does not grant private task access.
- Outbound telephony incurs provider charges. Provider acceptance is not
proof that the caller heard an answer.
- Keep the feature behind the existing experimental chat setting until
the real browser, inbound, outbound, and delayed-result acceptance
matrix passes.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 16:26:38 -05:00
Harjoth KharaandClaude Opus 5 be3e614d61 fix(workspace-runtime): keep the real readiness failure when the deadline-clamped probe aborts (#11575)
## Thinking Path

> - Paperclip manages AI agents and the services they use for work.
> - An agent can wait for a workspace service to become ready.
> - Each readiness probe has a time limit.
> - A final probe can expire and hide an earlier HTTP failure.
> - This pull request keeps that observed failure in the reported error.
> - Operators can then see why the service was not ready.

## Linked Issues or Issue Description

Refs #11525. Related: #11494.

**What happened?**

A deadline-limited final readiness probe replaced an observed HTTP 503
with an abort message.

**Expected behavior**

Keep an earlier service failure when only the readiness deadline aborts
the last probe. Report normal connection failures and probe timeouts as
before.

**Steps to reproduce**

Return HTTP 503 from the first probe. Leave one millisecond in the
readiness budget. Abort the last probe. The reported error must still
contain HTTP 503.

## What Changed

- Track whether a readiness probe observed a service failure.
- Preserve that observation when the final probe expires at the
readiness deadline.
- Add a deterministic regression with an injected clock.
- Keep probe scheduling, request count and timeout limits unchanged.

## Verification

- Author verification: the readiness suite passed all nine tests; server
typecheck passed. The regression failed before the fix and passed after
it.
- The later task review recorded 172 passing workspace tests and seven
additional readiness checks. Historical author baseline failures are not
claimed as passing local runs.
- Latest head `936a374a08d0e74d87d588ba034f674388e8d508`: CI passed with
54 successful checks and two intentional skips. Fresh Apex review is 5/5
with no unresolved findings or recommendations.
- A test merge with current master is clean.

## Risks

- Error text changes when a service first fails and then hangs. The
earlier observed failure is retained.
- A hang without a prior service failure still reports the abort.
- No data model, API or permission change.

## Model Used

Anthropic Claude Opus 5 (`claude-opus-5`) authored the fix through
Claude Code with reasoning, file editing and test tools. OpenAI GPT-5.6
assisted the original diagnosis. OpenAI GPT-6 (`gpt-6`) through Codex
assisted this final review and PR preparation with repository and
terminal tools. This session does not expose an exact 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: Claude Opus 5 <noreply@anthropic.com>
canary/v2026.1013.0-canary.16
2026-10-13 14:25:09 -07:00
DottaandPaperclip 473c80d13f Automatically import and update project repository skills (#16066)
Automatically import skills from new GitHub project repositories and update enabled sources in the background. Preserve project-derived access, saved selections, immutable execution versions and explicit pins; add legacy adoption, refresh and connection repair in Sources.

Include durable scheduling and bounded work credits, production Storybook journeys, real GitHub-to-routine acceptance receipts and final-head CI/security/Greptile qualification.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 16:11:43 -05:00
Devin FoleyandPaperclip de335b42d4 Expose signed routine wake deadlines during idle sleep checks
Expose signed routine wake deadlines during idle sleep checks

Report the earliest eligible routine deadline to an authenticated host scheduler, while preserving local execution, owned sleep leases and conservative blocking for unsupported work.

Verified with focused tests, typecheck, build, all required CI checks and Apex 5/5.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-13 14:09:16 -07:00
DottaandPaperclip 7eea9d8214 fix(github): use bot names in review summaries (#16212)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - A GitHub bot can send a pull request to an agent and publish its
review.
> - Each bot has its own GitHub App identity, but every summary
currently starts with "Paperclip Review".
> - A generic heading makes it harder to identify reviewers when several
bots review the same pull request.
> - This pull request uses the bot display name in review summary
headings.
> - Users can identify each reviewer while required checks keep their
existing name.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

The heading of a GitHub bot's published pull request review summary.

**Current behavior**

Every summary uses "Paperclip Review", regardless of the bot's name. The
check also uses "Paperclip Review" and must keep that name for existing
branch rules.

**Proposed behavior**

Complete and incomplete review summary headings use the GitHub bot
display name. The heading falls back to the bot login, then the assigned
agent name, when old connections have no display name. Separate GitHub
Apps keep independent checks with the same name.

**Reason and benefit**

Readers can identify each bot's review. A regression test confirms that
publishing a review does not update a check owned by another App or
endpoint.

**Breaking changes**

The summary heading changes. Consumers that parse the old heading must
accept bot names. No API, prompt configuration, database schema, or
check name changes are included.

No duplicate PR was found in the GitHub bot title search. ROADMAP.md
does not contain a duplicate of this change.

## What Changed

- Use the bot display name in complete and incomplete review headings.
- Escape Markdown in names and fall back to the bot login or agent name.
- Verify the heading through the publication workflow and keep check
updates scoped to the App and endpoint.
- Document bot-named summaries and independent checks. Update both
access maps.

## Verification

- Focused policy, heading, and existing UI tests: 67 passed.
- Database-backed regression cases: 2 passed, including bot-name
publication and independent checks.
- Map checks, token gates, and git diff --check passed.
- Typecheck and build passed on the final rebased branch. The final
focused run passed 44 tests; the two database-backed regression cases
also passed in a separate run. All final-head CI checks passed,
including full test suites, build, typecheck, E2E, and security scans.
Greptile reviewed the final commit at 5/5 with no actionable findings.
No review threads remain unresolved.

## Risks

- Consumers that parse the old summary heading must accept bot names.
- The GitHub check remains Paperclip Review. Multiple-bot check
isolation was tested with provider fixtures; a live two-bot GitHub test
was not run for this change.

## Model Used

OpenAI GPT-6 through Codex. The exact backend model ID and context
window are not exposed in this session. Used reasoning, repository
tools, 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
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-13 15:33:05 -05:00