Commit Graph
5357 Commits
Author SHA1 Message Date
842efe0181 fix(ui): stack project field save indicator below its label (#14765)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The web UI has a project detail page. A properties panel on that
page lets a user edit the project name, description, and other fields.
> - Each field shows a "Saving...", "Saved", or "Failed" indicator while
an edit is in progress.
> - The indicator was rendered next to the label text in a fixed 80px
label column. The "Description" label almost fills that column, so the
indicator spilled into the value column and covered the description
text.
> - A user cannot read the description while the indicator is visible.
This looks broken and it hides content.
> - This pull request stacks the indicator directly below the label
text, so it stays inside the label column.
> - The benefit is that the indicator never covers the field value, for
the description and for every other labelled field.

## Linked Issues or Issue Description

No public GitHub issue exists for this bug. The issue is described here.

**What happened?**

When a user edits a project description in the project properties panel,
the "Saving..." and "Saved" indicator appears next to the "Description"
label. The label column is 80px wide. The indicator does not fit, so it
overflows into the value column and overlaps the description text.

**Expected behavior**

The "Saving..." / "Saved" / "Failed" indicator must appear directly
below the "Description" label. It must not overlap the description text
or any other field value.

**Steps to reproduce**

1. Open a project in the Paperclip web UI.
2. Click the Description field in the properties panel and change the
text.
3. Click outside the field to save.
4. Look at the "Description" label while the "Saving..." and then
"Saved" indicator is visible. The indicator overlaps the description
text.

**Paperclip version or commit**

master at `5edf55d7350c7f08c9dd132c7e0f1421fa0bf2fb`.

**Deployment mode**

Local development (`pnpm dev`). The bug is in the UI layout, so it
applies to every deployment mode.

## What Changed

- `ui/src/components/ProjectProperties.tsx`: `FieldLabel` now renders
the label text and the `SaveIndicator` in a vertical flex column
(`flex-col`) instead of a horizontal row. The indicator sits directly
below the label and stays inside the 80px label column. This applies to
every labelled property row (Name, Description, Env, and so on), so no
label can overflow.
- `ui/src/components/ProjectProperties.save-indicator.test.tsx`: new
regression test. It asserts that the indicator is a stacked sibling
under the Description label for the `saving` and `saved` states, and
that no indicator renders for the `idle` state.

## Verification

- Run `pnpm --filter @paperclipai/ui exec vitest run
src/components/ProjectProperties` from the repo root. All
ProjectProperties tests pass, including the new save-indicator test.
- The new test fails against the previous inline layout (2 of 3 cases
fail) and passes with this change (3 of 3 cases pass).
- The existing `ProjectProperties.concurrency`,
`ProjectProperties.managed-sandbox`, and `ProjectDetail` tests pass (18
tests).
- `tsc -b` in `ui/` reports no errors in the changed files.
- Manual check: open a project, edit the description, and save. The
"Saving..." and "Saved" indicator now appears below the "Description"
label and does not cover the description text.

## Risks

- Low risk. The change is a single flex-direction swap on the label
wrapper in one component.
- Every labelled row in the project properties panel gets a slightly
taller label cell while an indicator is visible. This is intentional and
it matches the requested layout.
- No data, API, or migration changes.

## Model Used

- Claude Fable 5.1 (Anthropic), model id `claude-fable-5-1`, with
extended thinking and tool use, run through Claude Code inside a
Paperclip agent session. A human reviewed the change and the pull
request text.

## 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)
- [ ] 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: Bender (Fable) <bender@paperclip.local>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-30 18:34:41 -07:00
Devin FoleyandPaperclip 98d8a6ccac Stop replaying ambiguous database disconnects (#14773)
## Thinking Path

> - Paperclip stores agent work and control state in PostgreSQL.
> - Its database client must not repeat a mutation after an uncertain
result.
> - The global retry wrapper treated `write CONNECTION_CLOSED` as proof
that PostgreSQL never received a statement.
> - postgres.js also uses that message when the connection closes after
statement delivery.
> - This pull request removes that global replay and tests the actual
driver over a local wire connection.
> - Callers retain control of retries when they can prove the complete
operation is idempotent.

## Linked Issues or Issue Description

Follow-up to #13417. Preserve the transaction disconnect handling from
#13643 and the explicit actor synchronization retries introduced in
#12773. Searched open and closed issues and PRs for database retries,
disconnects, and `CONNECTION_CLOSED`. The open circuit-breaker proposal
#11142 addresses outage queue growth; it does not establish whether an
already-sent statement can be replayed.

**What happened?**
The database wrapper replayed an arbitrary statement up to three times
after `write CONNECTION_CLOSED`. The driver adds `write ` to
connection-close errors even after the peer receives the statement. A
local protocol peer receives the same submitted INSERT three times when
it drops each response. A committed write could therefore execute more
than once.

**Expected behavior**
An ambiguous statement result must fail without automatic replay. A
subsequent operation must be able to reconnect.

**Steps to reproduce**
Run the new wire regression against the parent commit. The six Simple
Query cases and the parameterized Drizzle case receive three executions
instead of one. The named prepared-client case was already safe and
stays covered. The peer reads the entire statement and then closes the
connection. This demonstrates repeated delivery with the real driver; it
does not claim that a historical incident duplicated a committed write.

**Paperclip version or commit**
Reproduced on source commit `018993140f` with the patched postgres.js
3.4.9 dependency.

**Deployment mode**
Built from source with a local PostgreSQL protocol peer. No live
provider or customer database is used.

## What Changed

- Pass the original postgres.js client to Drizzle and remove the global
statement replay wrapper.
- Add eight wire regressions: six Simple Query cases for INSERT,
side-effect-capable SELECT, and a data-changing CTE, plus parameterized
Drizzle and named prepared-client cases. The extended peer processes
Parse, Describe, Bind, and Execute, verifies bound parameters, and drops
the response only after Execute. Each case checks one delivery and
recovery on a fresh query.
- Document ambiguous outcomes and the retry compatibility tradeoff. Keep
explicit idempotent actor-sync retries and disconnected-transaction
handling unchanged.

## Verification

- Before the fix: the six Simple Query cases and the parameterized
Drizzle case failed with three executions instead of one. The named
prepared-client case was already safe. All eight wire cases pass on this
branch.
- Final focused client, pool teardown, configuration, and actor-sync
retry checks: 28 tests passed. `pnpm --filter @paperclipai/db typecheck`
also passed after the test-only follow-up.
- First implementation head, `pnpm exec vitest run --project
@paperclipai/db`: all 158 tests passed across 45 files, including real
PostgreSQL transaction/reserved-connection recovery. The local embedded
dependency's symlinks were hydrated before this run.
- `pnpm -r typecheck`: passed.
- `pnpm build`: passed.
- The complete local `pnpm test:run` did not finish; no complete local
suite pass is claimed. All CI test, typecheck, and build gates passed on
the first implementation head `11f8b22d90`. Final-head CI is pending
after the test-only follow-up.
- `git diff --check`: passed. Reviewed the diff for secrets, personal
data, generated output, and run artifacts.

## Risks

Some transient statement failures that the global wrapper previously
replayed now reach the caller. Operation owners must retry only when
they have an idempotency guarantee or a durable receipt that prevents
duplicate effects. A connection error is not proof that a write failed
to commit. There is no SQL-text retry heuristic, new suppression, schema
change, or migration. This change prevents unsafe replay; it does not
prevent network disconnects.

## Model Used

OpenAI Codex / GPT-6, with reasoning, repository inspection, code
execution, and local protocol tests. The exact backend model ID and
context-window size are not exposed in this session.

## Checklist

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


Final verification (September30): every final-head CI check passed at
`3004c5bda39c985c3557547ec45e33870ce5d010`. Greptile scored5/5 on this
head, all review threads are resolved, and the branch is mergeable.
Eight real-wire regressions cover simple, parameterized Drizzle, and
named prepared queries. Full local suite did not produce a completed
result; the complete CI matrix passed. This public PR remains open for
maintainer merge.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.1001.0-canary.0
2026-09-30 18:34:00 -07:00
DottaandPaperclip 8ffecf0fc1 fix(runner-e2e): admit explicit native active-stop candidates
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 20:11:36 -05:00
DottaandPaperclip 2ea54f2c3f fix(runner): bind transitive Copilot permission policy sources
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 20:11:36 -05:00
DottaandPaperclip eeb48425ee fix(runner): bind transitive Copilot permission policy sources
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 20:09:09 -05:00
DottaandPaperclip 66f61521a1 fix(runner-e2e): preserve negation in async bootstrap task
State each bootstrap prohibition separately so the production file-delivery classifier does not treat an isolated clause as a requested output. Keep immediate completion stress, private marker evidence and all settlement assertions unchanged; version the authored Copilot protection definition.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 20:03:36 -05:00
DottaandPaperclip fcf1866928 fix(runner): bind Copilot permission grants to visible targets
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:59:38 -05:00
DottaandPaperclip a9cec40001 test(cli): retain target Postgres fixture failure logs
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:59:19 -05:00
DottaandPaperclip fa8642d1eb test(runner): gate installed package staging regressions
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:59:19 -05:00
DottaandPaperclip 9661dd6473 fix(runner): stage installed dependency pack inputs
Preserve non-bundled package contents outside the pnpm tree before npm packs them. Keep bundled and root-package behavior and clean-consumer assertions unchanged.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:59:19 -05:00
DottaandPaperclip 3eeaf69a96 test(runner): capture warm attach evidence before epoch rotation
Observe the retired authority at its durable prepared commit rather than the later attach observer. Add a forced post-activation lost-ACK observer regression while preserving event, ACK, identity, process, and cleanup assertions.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:59:19 -05:00
DottaandPaperclip 03090216b7 fix(runner): bind Copilot permission grants to visible targets
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 19:54:27 -05:00
DottaandPaperclip c8f874311c fix(ui): hide Google connectors only on the Connections page (#14774)
## Thinking Path

> - Paperclip helps people manage AI agents for work.
> - The Connections page lists the apps and saved accounts that agents
can use.
> - Google Workspace verification is still pending.
> - Google entries must be temporarily hidden from this page without
removing their implementations.
> - This PR filters the final page rows, including saved Google
accounts, after the page resolves their provider.
> - Definitions, direct setup routes, OAuth profiles, credentials, and
runtime access stay intact.
> - Review instances can keep the prior UI by staying on their pinned
app release.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Temporary provider visibility on the Connections landing page.

**Current behavior**

The page can show Google Workspace catalog entries and saved accounts
while verification is pending.

**Proposed behavior**

Hide all nine Google Workspace rows on this page. Keep every other
connector and all Google integration code unchanged. Use an existing
release pin for review instances instead of a hostname exception in the
app.

**Reason and benefit**

Pause public discovery without disabling existing runtime tools or
removing the implementation needed for verification and later
re-enablement.

**Breaking changes**

Google accounts are no longer visible on this landing page. Direct setup
and management routes remain available. This is not an access-control
restriction.

Related completed work: #13551 used catalog-level visibility. This
change is deliberately limited to the landing page and also covers saved
account rows. #14740 reduced Google scopes; this change leaves those
scopes unchanged. No duplicate open PR or matching open issue was found.

## What Changed

- Derive the Google app slugs from the existing Workspace profile
registry.
- Filter the combined catalog and saved-account rows only inside
`Browse`.
- Cover all nine Google entries, active/draft/disabled accounts, legacy
connection metadata, mixed-provider rows, and independently identified
non-Google connectors in regression tests.
- Document the display-only hold, pinned review builds, and how to
restore visibility after approval.

## Verification

- Passed: `pnpm exec vitest run ui/src/pages/apps/Browse.test.tsx
ui/src/pages/apps/AppsConnect.test.tsx` (199 tests, including the latest
master changes).
- Passed: `pnpm check:token-gates`.
- Passed: `pnpm build`.
- Passed: `pnpm -r typecheck` and `pnpm build` after merging the latest
master. An earlier overlapping run hit a local runner codesign race;
sequential checks passed.
- Passed again after the final custom-provider fix: `pnpm --filter
@paperclipai/ui typecheck` and `pnpm --filter @paperclipai/ui build`.
- The full local `pnpm test:run` was started, then stopped after the
full remote CI suite passed to avoid continuing duplicate long-running
work on the developer machine. It is not claimed as a completed local
pass.
- All 54 latest-head CI checks passed. Two non-applicable Storybook jobs
were skipped. One serialized server job lost its self-hosted runner
connection; its single retry passed.
- Greptile: 5/5 on `aeda167bf4494feed6ee0de2585960511fb02918`, with no
unresolved review threads.
- Confirmed in the existing review instance that all nine Google entries
still appear after its current release was pinned. No new app release
was deployed to that instance.
- Reviewer steps: open Connections on this branch with Google catalog
entries and saved Google accounts. None should appear. Non-Google
connectors must remain. Direct Google setup routes must still load.

## Risks

- Existing Google accounts cannot be found on this page during the hold.
Their data and runtime access remain unchanged.
- This is a UI-only filter, not an authorization gate. Direct routes and
API access still work by design.
- Review instances must not receive this UI build until the hold is
removed. Their existing release pin excludes fleet app upgrades; an
explicit targeted upgrade must still be avoided.
- No migrations, backend changes, broker changes, or credential changes.

## Model Used

OpenAI Codex (GPT-5-based coding agent), with reasoning, tool use, code
execution, and browser inspection. 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>
canary/v2026.930.0-canary.17
2026-09-30 18:22:25 -05:00
d6fa1fd1ef feat(ui): streamline account menu profile access and add Invite shortcut (#14480)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Humans work in teams, so Paperclip has a multi-user system with
logins, profiles, and a company sidebar.
> - The account menu in the lower-left corner of the sidebar is the main
entry point for a user's own settings.
> - The account menu spent half of its rows on "View profile" and "Edit
profile". Users open these rows rarely.
> - The account menu had no fast path to invite a new member. The invite
flow is different on a self-hosted instance and on Paperclip Cloud.
> - This pull request removes the two profile rows, makes the header a
link to the profile, adds an "Edit profile" button on the profile page,
and adds an "Invite" row.
> - The benefit is a shorter account menu that keeps profile access and
gives users with the invite permission a one-click path to invite
people.

## Linked Issues or Issue Description

No public GitHub issue exists for this change. The description below
follows the enhancement template.

Refs #14060. That earlier pull request holds the first two commits and
the first Greptile review. It closed when the branch got a new name to
remove an internal ticket id. All Greptile findings from both reviews
are fixed in this branch.

**What existing behavior does this improve?**

The account menu in the sidebar (`SidebarAccountMenu` and its
`.production` variant) and the user profile page at `/u/:userSlug`.

**Subsystem affected**

ui/ — React + Vite board UI

**Current behavior**

The account menu shows the user's picture and name at the top. Below
them, the menu shows "View profile" and "Edit profile" rows, then the
other rows. The header is not a link. The menu has no row to invite
people. On a self-hosted instance, the user must open Company settings,
then Members, then the Invites tab. On Paperclip Cloud, the user must
open the Members page and use the Cloud People link there.

**Proposed behavior**

The account menu does not show "View profile" or "Edit profile". The
picture and name at the top of the menu are a link to the user's own
profile page. The profile page shows an "Edit profile" button when the
viewer looks at their own profile. The account menu shows an "Invite"
row with the same `UserPlus` icon as the company menu. On a self-hosted
instance, the row opens the Members page on the Invites tab, and shows
only to boards that hold the `users:invite` grant (company owners and
admins, instance admins, and local boards). On Paperclip Cloud, the row
opens the People settings for the current stack, and shows only to the
owner or admin of the stack, the same rule the Members page uses.

**Reason and benefit**

Users open their profile rarely, but the two rows took half of the menu.
Inviting people is a common task, but it needed three clicks and a
different path on Cloud. The new menu is shorter, keeps profile access
in one tap on the header, and gives one "Invite" entry point on both
hosting modes to the users who can invite.

**Breaking changes**

None. Routes, API responses, and settings keys do not change. The
profile page and the invite pages keep their current URLs.

## What Changed

- `SidebarAccountMenu.tsx` and `SidebarAccountMenu.production.tsx`:
remove the "View profile" and "Edit profile" rows. Make the picture and
name header a link to the user's profile. Add the "Invite" row after
"Settings" in the streamlined menu and first in the production menu.
- Header structure: `master` added a staging commit SHA link under the
email in the same header. The profile link is now a stretched overlay
behind the header content, so the SHA anchor sits beside the email and
the header has no nested anchors.
- `ui/src/lib/userProfileLinks.ts` (new): build the profile path from
the user id first. The profile endpoint treats the id as the one unique
slug, so two members with the same display name get different links.
Name and email are a fallback only when the session has no id.
- `ui/src/hooks/useCloudInviteUrl.ts` (new): read the Cloud stack
portfolio and return the People settings URL only when the current stack
role is owner or admin. This is the same rule as the Members page.
- `ui/src/hooks/useCompanyInviteAccess.ts` (new): read the current board
access snapshot and report whether the board may invite people to the
selected company on a self-hosted instance. Local boards and instance
admins pass. Other boards need an active owner or admin membership, the
roles that carry `users:invite`. This follows the same client-side gate
pattern as `ToolsAdminGate` and the run ledger. The server stays
authoritative.
- Invite row visibility: the row is hidden when the operator hides
`company.members` or `company.invites`, and until the health check
resolves. On self-hosted instances, the row is hidden until the board
access snapshot loads and when the board cannot invite. On Cloud, the
row is hidden when no People URL can be built. The in-app Invites tab is
never a fallback on Cloud, because it drives a different flow.
- `ui/src/pages/UserProfile.tsx`: add an "Edit profile" button that
links to `/company/settings/instance/profile`. The button shows only on
the viewer's own profile and follows the `instance.profile`
hidden-settings gate.
- Tests: extend `SidebarAccountMenu.test.tsx`; add
`userProfileLinks.test.ts`, `UserProfile.test.tsx`, and
`useCompanyInviteAccess.test.ts`.
- No documentation references the removed menu rows, so no docs change
is needed.

## Verification

Run the focused tests from the `ui/` directory:

```bash
pnpm vitest run src/components/SidebarAccountMenu.test.tsx src/hooks/useCompanyInviteAccess.test.ts src/lib/userProfileLinks.test.ts src/pages/UserProfile.test.tsx
```

- 52 tests pass in these four files. They cover the header link by user
id, the removed rows, the header overlay with no nested anchors, the
self-hosted invite target, the self-hosted permission gate (owner,
admin, instance admin, and local board see the row; an operator does
not, on both menu variants), the Cloud invite target with no
`target="_blank"`, the menu order, the hidden-settings gate on both
variants, the Cloud role gate (a plain member sees no row), the
no-fallback rule when Cloud stack metadata is missing, the staging
commit SHA link from `master`, and the own-profile-only "Edit profile"
button.
- `tsc -b` in `ui/` reports no errors in the changed files. The only
errors are pre-existing `@paperclipai/plugin-sdk/ui` resolution errors
in `PluginOrganizationSwitcher.tsx` from an unbuilt workspace package.

Manual steps:

1. Sign in and open the account menu in the lower-left corner. Confirm
the menu has no "View profile" or "Edit profile" rows.
2. Click your picture or name at the top of the menu. Confirm your
profile page opens and shows an "Edit profile" button.
3. Open another user's profile. Confirm the page shows no "Edit profile"
button.
4. On a self-hosted instance, as a company owner or admin, click
"Invite". Confirm the Members page opens on the Invites tab. As an
operator or viewer, confirm the menu shows no "Invite" row.
5. On Paperclip Cloud, as a stack owner or admin, click "Invite".
Confirm the Cloud People settings page opens in the same tab. As a plain
member, confirm the menu shows no "Invite" row.

## Risks

- Low risk. The change is limited to the UI and touches ten files.
- Users who know the "View profile" and "Edit profile" rows must learn
the new header link. The header has hover and focus styles to show that
it is a link.
- On self-hosted instances, the "Invite" row depends on the board access
snapshot from `/cli-auth/me`, which other gates in the UI already use. A
member with a custom `users:invite` grant but an operator or viewer role
does not see the row. That member can still use the Members page. The
row is a shortcut, not the only path.
- On Paperclip Cloud, the "Invite" row depends on the stack portfolio
query. When that query fails or the role is unknown, the menu hides the
row instead of sending the user to the wrong flow.
- Both menu variants change together, so a behavior difference between
them is not expected.

## Model Used

- Provider: Anthropic. Model: Claude Fable 5.1 (`claude-fable-5-1`).
- Run through Claude Code on the Claude Agent SDK inside a Paperclip
`claude_local` agent, with extended thinking and tool use (file edits,
shell, tests, GitHub API).
- The model wrote the code, the tests, and this description. A human
reviewed the pull request and requested the review fixes.

## 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: Bender (Fable) <bender@paperclip.local>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: devinfoley <139239+devinfoley@users.noreply.github.com>
2026-09-30 16:18:59 -07:00
DottaandPaperclip f7e36ba3e2 fix: isolate repository-free low-trust tasks in private directories (#14766)
## Thinking Path

> - Paperclip manages work by agents within company boundaries.
> - Email tasks can run under the low-trust review preset.
> - These tasks must use an isolated workspace and a sandbox.
> - The default workspace strategy assumed that the project had a Git
repository.
> - A project without a configured workspace failed before the agent
could start.
> - This change gives each such task a private directory and keeps the
sandbox requirement.

## Linked Issues or Issue Description

**What happened?**
An inbound email assigned to a low-trust agent failed with
`git_worktree_base_not_git_checkout` when its boundary project had no
configured workspace. Setup had accepted the project and sandbox.

**Expected behavior**
The agent can process email without a repository. Its workspace stays
isolated from other tasks and the shared agent home.

**Steps to reproduce**
1. Select a low-trust agent with an active sandbox and a project
boundary.
2. Leave the project without a configured workspace.
3. Receive an email through AgentMail.
4. Observe that startup fails before provider work starts.

**Paperclip version or commit**
Reproduced against `5edf55d73`.

**Deployment mode**
Hosted staging with sandbox execution.

Related: #13256 added email tasks. #13636 fixed default isolation for
projects without workspaces; the explicit isolation used by low-trust
tasks still needed this path.

## What Changed

- Select private task directories for low-trust sandbox tasks with no
configured workspace or explicit workspace strategy.
- Keep each directory scoped to its company and task. Retain files
across turns and reassignment and reject symlink paths and mismatched
workspace reuse.
- Preserve Git validation for configured workspaces and explicit
strategies, plus the existing authorization and remote gates for
referenced projects.
- Add a startup regression and directory isolation tests. Document the
supported repository-free path.

## Verification

- The startup regression failed before the fix with the same Git
validation error.
- 260 targeted email, workspace policy, heartbeat, referenced-project
and directory tests pass.
- Full `pnpm -r typecheck` and `pnpm build` pass on the latest commit.
- All CI checks, including the complete sharded test suite and canary
dry run, pass on `b4ccd9802b09b2e95499df72d48b4a3906b8c328`.
- The final commit also passes the same server shard locally: 60 files,
1,024 passed / 6 skipped tests. The earlier all-groups local run was
interrupted during follow-up edits; complete-suite verification comes
from CI on the final commit.
- Deployed the reviewed commit to staging and independently verified the
full serving SHA. Two real Codex runs in Daytona succeeded and finalized
the same private company/task workspace. The first wrote a 35-byte
marker; the second read the existing file without modifying it and
returned the independently verified SHA-256
`ce3bbeb44d07ca6822826d3a5945752a38d30b356d10829f3159a191e5aa92a6`.
- Live runtime caveat: Codex reported a nested `bwrap` loopback
permission error and used its configured escalated execution inside
Daytona. The outer Daytona sandbox remained active for both runs.
- The startup regression uses a real database, production trust checks,
workspace persistence, sandbox lease acquisition and realization, and a
fake provider. It checks reassignment and allows only an authorized
referenced project.
- The transfer regression runs production archive/sync-back/merge code
against distinct filesystem roots: create output in one sandbox, restore
it, then read and update it in a fresh sandbox. The provider I/O is
emulated; live staging verification is separate.

## Risks

- The new default applies only to low-trust sandbox tasks without
workspace configuration. Standard agents and explicit Git strategies
keep their existing behavior.
- Task directories retain work across turns and consume instance
storage. The change does not migrate or copy existing shared files.
- No database migration or credential changes are required.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, repository inspection, code
execution, and browser tools. The exact runtime model revision 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.930.0-canary.16
2026-09-30 18:06:07 -05:00
1d23cb6962 ci: pin a checkout-independent Rust cache path so PR lanes hit master's cache (#14394)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Paperclip ships a native Runner binary, written in Rust, and seven
CI lanes build it on every pull request
> - `Canary Dry Run` is the slowest check on every green PR run, and
most of its time is `cargo build --release` on third-party crates
> - Master saves a Rust dependency cache for these lanes, but every PR
lane logs `No cache found` and compiles every crate from zero
> - The cache key matches, but GitHub also compares a hash of the
absolute cache paths, and the master writer (RunsOn fleet,
`/home/runner/_work/...`) and the PR readers (GitHub-hosted,
`/home/runner/work/...`) hash different paths
> - This pull request gives both sides a checkout-independent workspace
path, so the hashes match and the PR lanes restore master's cache
> - The benefit is about 2.5 minutes less wall clock per PR run and
about 18 fewer runner-minutes per run

## Linked Issues or Issue Description

No public issue exists for this problem. The description below follows
the enhancement template.

Related prior PRs on the same cache: Refs #13194, Refs #13259, Refs
#13457, Refs #13459, Refs #13500, Refs #13586. None of them pins the
workspace path, so none of them fixes this miss.

**What existing behavior does this improve?**

The `Swatinem/rust-cache` restore step in the PR workflow lanes that
build the Runner: `Canary Dry Run`, `Build`, `Typecheck + Release
Registry`, and the four `Verify Paperclip Runner` lanes.

**Subsystem affected**

CI workflows under `.github/workflows/`, their guard tests under
`.github/scripts/tests/`, and `doc/RELEASE-AUTOMATION-SETUP.md`.

**Current behavior**

Every PR lane logs `No cache found` although master holds an entry with
the exact key. Run 36424309181 computed
`v0-rust-release-runner-v1-Linux-x64-c3a3ca66-a95b0328`, and master
holds a 678 MB entry with that key. GitHub matches a cache entry on the
key and on a version hash of the absolute paths in the cache. The master
writer runs on the RunsOn fleet, where the checkout is
`/home/runner/_work/paperclip/paperclip`. The PR readers run on
GitHub-hosted `ubuntu-latest`, where the checkout is
`/home/runner/work/paperclip/paperclip`. The stored version `5c40870d…`
is the sha256 of the `_work` paths plus `zstd-without-long|1.0`. The
`work` paths hash to `1656e9ee…`. The key can never match, so each lane
compiles every third-party crate again.

**Proposed behavior**

The writer and the readers pass the same checkout-independent path to
`rust-cache`. Both runner layouts then produce the same version hash,
and the PR lanes restore master's cache.

**Reason and benefit**

`Canary Dry Run` takes 533s on a green run. 251s of that is dependency
compilation that a warm cache removes. Seven lanes pay this cost in
every PR run.

**Breaking changes**

None. This change affects CI only.

## What Changed

- Add a `Pin the Runner Rust workspace path` step before `rust-cache` in
the master writer (`release-verify.yml`, typecheck and runner lanes) and
in all four PR readers (`pr-trusted.yml`). The step creates the symlink
`$HOME/paperclip-runner-rust` →
`$GITHUB_WORKSPACE/packages/paperclip-runner/runner` and passes that
path to `rust-cache` as `workspaces: <path> -> target`. `rust-cache`
resolves the input with `path.resolve`, which does not follow symlinks,
so both runner layouts now produce the same cache paths and the same
version hash. `$HOME` is `/home/runner` on both images, which is why the
`~/.cargo` paths already agreed.
- Bump the shared keys `release-runner-v1` → `release-runner-v2` and
`release-typecheck-v1` → `release-typecheck-v2`. The old, unreachable
entries are then visibly orphaned instead of sharing a key with the new
ones.
- Extend the guard tests `pr-runner-rust-cache`, `release-runner-cache`,
and `typecheck-rust-cache`. They now require the pin step in both
workflows with identical text, placed before the cache step, and they
reject a `workspaces:` value that resolves under the checkout. The
`pr-runner-rust-cache` test checks all four PR reader jobs and fails if
a `rust-cache` step appears in a PR job that is not in its reader list.
- Update `doc/RELEASE-AUTOMATION-SETUP.md` to name the
`release-runner-v2` key and to explain the pinned workspace path.

### Expected savings once merged

Measured from run 36424309181. "Removed" is the dependency-compile time
that a warm restore removes, minus about 18s to restore the 680 MB
entry. The fleet writer's own restore shows this cost.

| Lane | Today | Removed | Expected |
|---|---|---|---|
| Canary Dry Run | 533s | ~150s | ~380s |
| Typecheck + Release Registry | 462s | ~155s | ~305s |
| Verify Paperclip Runner (vitest 2/2) | 453s | ~245s | ~210s |
| Verify Paperclip Runner (rust) | 400s | ~175s | ~225s |
| Build | 348s | ~130s | ~220s |
| Verify Paperclip Runner (static checks) | 321s | ~170s | ~150s |
| Verify Paperclip Runner (vitest 1/2) | 346s | ~70s | ~275s |

- Wall clock per PR run: about 533s → about 385s. That is about 2.5
minutes faster to a green check set. `Canary Dry Run` stays the longest
check. The rest is the non-cargo work in `release.sh` (standalone
package builds ~30s, publish-payload preview ~73s).
- Runner time: about 18 runner-minutes saved per PR run across the seven
lanes.
- The first master push after merge compiles from zero once in the fleet
writer (about 4 extra minutes on that one run) and saves the v2 entry.
Later PRs hit it. When a PR changes `Cargo.lock`, the prefix restore key
still gives a partial hit, as before.

## Verification

- Run the guard tests for the three cache lanes:
`node --test .github/scripts/tests/pr-runner-rust-cache.test.mjs
.github/scripts/tests/release-runner-cache.test.mjs
.github/scripts/tests/typecheck-rust-cache.test.mjs`
  Result: 21 pass, 0 fail.
- Run the full guard suite: `node --test
'.github/scripts/tests/*.test.mjs'`. Result: 376 pass, 3 fail. The 3
failures are in `docker-canary-promotion.test.mjs`. They hit a sandbox
temp-file ENOENT and fail the same way on the unmodified branch.
- Run `node --test scripts/__tests__/release-verify-workflow.test.mjs`.
Result: 14 pass.
- Local archive test: create a tar from the `_work` layout through the
symlink (relative `../../../paperclip-runner-rust/target` entries, `tar
-P -C $GITHUB_WORKSPACE`, the same way `@actions/cache` does). Extract
it on the `work` layout. The files land in the real target directory and
the symlink stays intact.
- After merge, open any GitHub-hosted PR run and confirm that the seven
Rust lanes log `Restored from cache key ...release-runner-v2...` in
place of `No cache found`.

## Risks

- Low risk. The change touches CI workflows, their tests, and one doc
page. No product code changes.
- If the pin step fails, `rust-cache` reports a miss and the lane
compiles from zero, as it does today. The build does not break.
- Both runner layouts sit four levels under `/home/runner`, so the
relative `../../../` archive entries line up. The existing
`~/.cargo/registry` and `~/.cargo/git` cache paths already rely on this
property. A future runner image with a different `$HOME` depth would
miss the cache but would not fail the job.
- `rm -rf "$pinned"` acts on the symlink itself (no trailing slash),
never on the checkout behind it. It only matters on a reused runner.
- Squash-merge note: the branch carries commits by `Bender (Fable)`. Add
`Co-Authored-By: Bender (Fable) <bender-fable@paperclip.local>` to the
squash body to keep that authorship.

## Model Used

- Anthropic Claude Fable 5.1 (`claude-fable-5-1`), run through Claude
Code inside a Paperclip agent heartbeat. Extended thinking was on. Tool
use: shell, GitHub CLI, and the GitHub REST API for workflow logs, cache
listings, and PR operations.

## 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)
- [ ] My branch name describes the change and contains no internal
ticket id. The agent execution workspace fixed this branch name, so I
cannot rename it. Squash-merge drops the branch name.
- [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 Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Bender (Fable) <bender-fable@paperclip.local>
2026-09-30 16:04:23 -07:00
Devin FoleyandPaperclip 3bbb8d0f69 Add bounded AgentMail failure diagnostics (#14768)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - AgentMail connections create inboxes and handle email tasks.
> - A failed provider request currently records only its HTTP status.
> - The same 403 can mean a permission denial, a resource limit, or
another provider restriction.
> - This pull request records a fixed operation name and a documented,
allowlisted error code.
> - Operators can distinguish these failures without exposing provider
payloads or changing retry behavior.

## Linked Issues or Issue Description

**What happened?**

An AgentMail inbox creation failure reports only `AgentMail request
failed (403)`. The response body is deliberately excluded because it can
contain private mail or credentials. That also discards the provider
code needed to identify the cause.

**Expected behavior**

Keep the HTTP failure visible with a fixed operation name and a safe
provider code. Never copy arbitrary error text, resource identifiers,
suggested fixes, or URLs into diagnostics.

**Steps to reproduce**

1. Make an inbox creation request through `agentmailApi` with a fake
provider returning HTTP 403 and `code: "missing_permission"`.
2. Observe that the old error lacks the operation and provider code.
3. With this change, verify the error includes `operation=create_inbox,
code=missing_permission`, preserves status 403, and excludes all other
response fields.

Related work: #13256 introduced the AgentMail connection. The provider
documents stable codes in its [error
reference](https://docs.agentmail.to/errors).

## What Changed

- Add a fixed method/route-to-operation map and an allowlist of
documented provider codes.
- Read at most 8 KiB for diagnostics, with a one-second deadline. Cancel
unread bodies and preserve the HTTP error if reading or parsing fails.
- Keep the existing error prefix, status, retry delay, and failure
handling.
- Add regression coverage and document the diagnostic limits.

## Verification

- `pnpm exec vitest run server/src/__tests__/agentmail-api.test.ts` — 44
tests passed.
- `pnpm build` — passed.
- `pnpm -r typecheck` — passed before the review correction. Final `pnpm
--filter @paperclipai/server exec tsc --noEmit` also passed.
- Full local `pnpm test:run` did not finish successfully; three
company-skills-service failures were observed outside the changed
module. The final-head CI server suites passed. The remaining
workspaces-b CI retry covers an unrelated HTTP/2 port collision.
- The diff passed a scan for configured secrets, private deployment
references, and non-fixture email addresses.

## Risks

- A failed request can now wait up to one extra second while reading its
diagnostic code.
- New, missing, malformed, or oversized provider codes report `unknown`.
A future provider code needs an explicit allowlist update.
- This is a diagnostics change. It does not establish or repair the
cause of an existing provider denial.
- No schema, credential policy, or retry behavior changes.

## Model Used

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

## Checklist

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


Final verification (September 30): all final-head GitHub checks pass at
`20853e31abacf53a32f1a63467ee208a719bbf00`, including the targeted
workspaces-b rerun after the unrelated EADDRINUSE failure. Greptile
scored 5/5 on this head and no review threads remain unresolved. The
branch is mergeable. The local full-suite run did not yield a passing
completion; CI completed successfully across all suites. This public PR
remains open for maintainer merge.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.930.0-canary.15
2026-09-30 15:29:15 -07:00
DottaandPaperclip e2908fff5c fix: enforce terminal outcomes during recovered sandbox cleanup (#14767)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runners can keep a reusable sandbox warm after successful
turns.
> - Failed turns must stop their sandbox before a later retry resumes
it.
> - Workspace recovery can release a lease outside the executor's normal
teardown.
> - Successful file copy-back can then retain a sandbox even when its
run failed.
> - This pull request checks the durable run outcome at the shared
release boundary.
> - Ordinary teardown and recovery now apply the same retention rule.

## Linked Issues or Issue Description

**What happened?**

A real Daytona verification on `5edf55d73` produced a failed native
turn. The runner process exited, but workspace recovery retained the
sandbox without stopping it. The recovery callback used successful
workspace copy-back to select warm retention. It bypassed the
terminal-state check in normal heartbeat teardown.

**Expected behavior**

Keep a sandbox running only after a successful run. Failed, cancelled,
timed-out, and interrupted runs must convert requested warm retention to
stop-and-retain. Preserve the existing ownership hold before release.

**Steps to reproduce**

1. Persist a terminal failed native run whose workspace copy-back
succeeds.
2. Release its environment lease from the recovery path with a stored
`keep_running` disposition.
3. Observe that the provider receives `keep_running` on the base commit.
4. With this fix, the provider receives `stop_and_retain` and the lease
status follows the durable run outcome.

**Paperclip version or commit**

Base: `5edf55d7350c7f08c9dd132c7e0f1421fa0bf2fb`.

**Deployment mode**

Native runner with a reusable Daytona sandbox.

Related: #14747 retires unsuccessful warm runner sessions. This change
closes the separate recovery lease-release path. Related search found no
duplicate fix.

## What Changed

- Read the durable run status at the shared lease-release boundary.
- Apply the existing terminal-outcome retention rule before calling the
environment runtime.
- Use that same durable status for the lease-state mapping.
- Add five database-backed regressions for four unsuccessful outcomes
and successful warm retention.
- Document the recovery rule.

## Verification

- Before the fix: the four unsuccessful-outcome regressions fail; the
successful case passes.
- After the fix: 163 tests pass across the lease-release, native
lifecycle, and explicit continuation suites.
- Repository typecheck and build pass.
- `pnpm test:run` encountered the existing local
`native-session-resume.test.ts:1125` assertion failure; a focused rerun
reproduced the same failure. This was also recorded before this
follow-up with the unmodified base executor. The full command was
stopped after that confirmation, so later local groups were not
completed.
- All 56 latest-head checks are successful or intentionally skipped (54
passed, 2 skipped), including the complete CI test groups and browser
E2E suite. Greptile is 5/5 on `e7da3b3ad`, with no unresolved review
comments.
- Deployed exact PR head `e7da3b3adbf7a13642c0e56f5b0f0c4666adf358` to
the staging workspace and independently verified the serving commit. A
real failed native turn persisted `keep_running` and completed workspace
finalization, reproducing the recovery-path conditions; Paperclip
automatically issued stop-and-retain, and an independent Daytona read
confirmed `stopped`. No manual stop was used.
- Retried that failed run through the public API after correcting its
temporary API-key credential. The same stopped sandbox resumed
successfully. Three successful turns retained one live runner PID/start
time and the same native, runner, and provider sessions.
- Verified exact canonical note contents, deletion persistence, and an
unchanged 8 MiB binary after every turn. Subsequent checkpoints
copied/hashed only 58 and 87 bytes. After sandbox deletion, canonical
files still matched. Temporary secrets were removed and
agent/configuration policy restored.
- Live acceptance used temporary API-key authentication. The separate
managed-subscription authentication issue and browser Retry control were
not tested by this campaign.

## Risks

- Recovery callers can no longer use stale success status to retain a
failed run's sandbox.
- The existing native ownership hold still blocks release while
ownership is unresolved.
- Successful warm turns and explicit destroy dispositions keep their
existing behavior.
- No database migration, API contract, dependency, or UI change is
included.

## Model Used

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

## Checklist

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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 17:20:25 -05:00
DottaandPaperclip 33f2b3a159 fix: separate GitHub tools and code review bot connections (#14750)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The Connectors catalog lets people give agents tools or connect
agents to conversations.
> - GitHub put these two uses behind one card and an extra choice.
> - People should choose the connection they need from the catalog.
> - This pull request keeps GitHub for tools and adds GitHub Code Review
Bot as a separate card.
> - Each card opens its setup directly. Both use the existing connection
code.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

GitHub connector discovery and setup.

**Current behavior**

With chat connectors enabled, GitHub opens a menu that asks whether to
use tools or create a bot. Saved tools and bots share the same catalog
entry.

**Proposed behavior**

GitHub opens tool account access. GitHub Code Review Bot opens agent
selection. Saved bots and drafts appear under the bot card.
Chat-disabled instances show only GitHub tools.

**Reason and benefit**

The catalog names the two uses and removes an extra setup choice. The
bot keeps the existing GitHub provider, credentials, endpoint IDs, setup
steps, and runtime.

**Additional context**

Related work: https://github.com/paperclipai/paperclip/pull/12843 and
https://github.com/paperclipai/paperclip/pull/14594 established GitHub
account identity. This change preserves that tool flow. No duplicate
catalog split was found.

## What Changed

- Split the generated app definitions into GitHub tools and GitHub Code
Review Bot. Reuse the existing GitHub logo and channel method.
- Open bot setup directly, including old resume and reconnect links.
- Put existing bot endpoints and drafts under the bot card. Hide
duplicate internal chat applications.
- Keep pasted GitHub URLs mapped to the tool connection.
- Add seven Storybook states for the catalog, saved connections,
disabled chat, both setup paths, mobile, and light mode.
- Fix narrow-screen bot rows so the label cannot overlap status and
setup actions.
- Update catalog, route, browser, and API tests, plus the GitHub
connector guide.

## Verification

- [Hosted
Storybook](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex~2Fgithub-review-connection/?path=/story/connections-github-and-code-review-bot--catalog):
seven states built from this branch. The deployment passed its
public-file verification.
- All GitHub checks pass on `d13a2cd53561645bb2a15c6f8e75a61a936d6459`.
Two optional Storybook jobs skip under their normal trigger rules; the
manual Storybook deployment passes. The branch has no merge conflicts.
- Greptile: 5/5 on the current head, with no review comments or
unresolved threads.
- `pnpm -r typecheck`, `pnpm build`, `pnpm check:token-gates`, and `pnpm
build-storybook` passed. The final Storybook fixture also passed UI
typecheck and the hosted build.
- Targeted catalog, URL matching, routing, grouping, brand, and chat UI
contract tests passed.
- GitHub provider browser tests: 2 passed. These cover direct tool setup
and the bot setup and management lifecycle with provider responses
mocked.
- Embedded-browser test on an isolated local instance: opened both
cards, selected an agent, saved a bot draft, and resumed the same
endpoint under the bot card after a reload.
- Storybook Tool Setup and Bot Setup assertions pass in the published
preview. Chat Disabled assertions pass locally. Inspected mobile and
light mode, including the draft-row layout and official GitHub marks.
- Local full-suite limitation: `pnpm test:run` was not clean. A
cross-company route assertion failed in the aggregate run and passed in
isolation; a workspace-runtime test reached its 30-second hook timeout.
Some isolated database reruns skipped when the embedded-PostgreSQL
availability probe failed. The local aggregate was stopped after CI
completed. The corresponding full CI suites pass all 360 tool-access
tests and all 162 workspace-runtime tests.
- No live GitHub authorization or installation was performed. The
isolated instance correctly stopped at the cloud enrollment or public
HTTPS prerequisites.

## Risks

- Low scope: catalog presentation and routing change. There is no
database migration or provider credential change.
- Existing GitHub bot URLs now open bot setup directly. The tool route
remains `/apps/connect?source=github`.
- The bot remains behind the existing chat-connectors feature flag.
Existing endpoints retain `provider: github`.
- Channel applications are represented by endpoint rows. Regression
tests cover legacy bot applications, tools, active bots, and drafts
together.

## Model Used

OpenAI GPT-6 through Codex, with reasoning, code execution, and
embedded-browser tools. The exact deployed model ID, context window
size, and reasoning setting are not exposed to this session.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 17:15:02 -05:00
DottaandPaperclip 6ce62cac75 test(server): report routine telemetry mock failure state
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 17:07:28 -05:00
DottaandPaperclip 6c70800a66 fix(runner-e2e): reserve remote runtime readiness budget
Include lease revalidation and the readiness RPC in the existing setup reserve, so late lease admission cannot consume the observation window. Keep the authored outer deadline, single installation, armed baseline action gate, and teardown reserve unchanged.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 16:51:35 -05:00
DottaandPaperclip 018993140f feat: let agents name prompt-only tasks (#14761)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Users create tasks with a title and a description.
> - A required title adds work when the prompt already explains the
request.
> - An agent can name the task once it reads that request.
> - This pull request accepts prompt-only tasks and starts them with a
short prompt slice.
> - A scoped title tool lets the assigned agent replace that slice early
without changing execution state.
> - A live browser eval checks the real agent call, saved title, audit
entry, and preservation of user titles.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: task creation, shared contracts, database, server, runner
tools, and board UI.

**Problem or motivation**

Users must currently write a title before they can submit a detailed
task prompt. The agent has enough context to write a useful title
itself.

**Proposed solution**

Make the title optional when a description is present. Save the first
120 characters of the normalized prompt as a provisional title. Ask the
assigned agent to call `set_task_title` early. Use an atomic
provisional-title guard to preserve titles supplied or edited by users.
Keep explicit titles supported.

Related: #14543 and #14556 concern empty-title submission. This change
intentionally enables that submission when a prompt is present, instead
of requiring a title.

## What Changed

- Add the `titleNeedsGeneration` field with an idempotent migration.
Keep existing titles unchanged.
- Add `PUT /api/issues/:id/title` and the native and legacy
`set_task_title` tool. Enforce company access, active-run ownership,
shared, bounded retry receipts across native/HTTP calls, and
transactional audit logging. Refresh external-object links after commit,
with the same feature gate and plugin detectors as ordinary title edits.
- Add early naming guidance in Standard, Ask, and Plan task context.
Preserve the description, status, and assignment.
- Allow prompt-only root and child task creation, plus draft restoration
in the New Task dialog. Keep user titles supported.
- Add an opt-in Product E2E suite for prompt-only Standard and Ask
tasks, plus an explicit-title control. It checks actual provider calls
within the first five tools, persisted state, audit attribution, and the
reloaded UI.
- Preserve a closed vocabulary of API key maintenance phrases in
declared prose while rejecting opaque credential suffixes. Add one
bounded naming retry after wording is rejected, without treating the
rejected call as a saved title.
- Repair the native cleanup receipt check exposed during full
verification: accept matching input digests, retain legacy input checks,
and reject conflicting receipts.

## Verification

- Live Product E2E on `f43478473800e3a46b85c5ee79677efdb15108e7`: **3/3
passed** with native Codex `gpt-5.4-mini`, first attempts only,
automatic retries disabled. Standard and Ask each saved “Rotate expired
API key” on their first tool call, with matching persisted state and a
single same-run audit entry. The explicit-title control retained its
user title with zero title writes. All three verified the reloaded
browser UI.
- Campaign: `local-2026-09-30T21-30-11-021Z`. Earlier failed campaigns
are retained separately; they exposed credential-prose handling and
prompted the naming recovery fix. No failed result was regraded or
deleted.
- Reproduce with `pnpm test:e2e:runner -- --id
task-titles.runner-codex-mini.local.prompt-title-standard --id
task-titles.runner-codex-mini.local.prompt-title-ask --id
task-titles.runner-codex-mini.local.preserve-explicit-title
--max-automatic-retries 0` and an authorized provider key.
- Full `pnpm -r typecheck` and `pnpm build` passed on the latest commit.
The runner build used the configured external eval source tree.
- Product E2E unit suite: **61 files, 818 tests passed**; E2E typecheck
and UI token gates passed.
- Title API/native regressions cover prompt-only and explicit child
creation, user edits, ownership/company isolation, external reference
refresh, cross-surface retry replay, and the 64-key limit without
receipt eviction. All passed. Prompt-context coverage: **44 tests
passed**.
- Rust credential regressions: **35 tests passed**, including benign
maintenance qualifiers and opaque credential rejection in every declared
prose field. Catalog/report reconciliation: **28 tests passed**. Native
recovery: **560 tests passed**.
- Broad local `pnpm test:run`: **14,555 tests passed** in the general
server group; two suites failed to initialize embedded PostgreSQL and
the existing 40,000-file Git streaming stress test exceeded its
300-second macOS timeout. All three suites then passed in isolation (**5
tests passed**) without code or timeout changes. The original full local
command exited nonzero and is not being represented as a clean full run.
- Latest-head GitHub checks are green: **53 passed, 4 skipped, zero
failed or pending**, including all test shards and the canary packaging
dry run. Greptile reviewed the same commit at **5/5**, with zero
unresolved review threads.

## Risks

- The additive database field must reach the server and UI together. The
migration uses `IF NOT EXISTS` and defaults existing tasks to a final
title.
- Title generation depends on the assigned agent running. Tasks without
a run keep their provisional title.
- Live qualification covers the native Codex path in Standard and Ask
modes. API/legacy and Plan behavior have deterministic coverage.
- The credential-prose exception validates the entire suffix against a
closed maintenance vocabulary. Unknown suffixes, assignments, quoted
values, credential prefixes, and diagnostics retain strict checks.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, tool use, and code
execution. The exact deployment ID and context window are not exposed in
this session. The live eval uses the native Codex `gpt-5.4-mini`
profile.

## 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.930.0-canary.14
2026-09-30 16:48:24 -05:00
Dotta e3659ef004 docs(runner-e2e): describe remote runtime readiness evidence 2026-09-30 16:32:31 -05:00
DottaandPaperclip 11fdee5f65 fix(runner-e2e): wait for exact remote runtime before native fixture install
Observe the pinned run process and runtime inode within the original deadline before one observer install. Revalidate identity at installation and baseline, and retain only closed RPC phase/error diagnostics. Preserve action, ownership and cleanup gates.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 16:29:27 -05:00
Devin FoleyandPaperclip d6d67b00d3 Prevent background workspace scans from refreshing the Git index (#14666)
## Thinking Path

Paperclip runs background workspace scans alongside real Git writers.
`git status` can refresh the index as an optional side effect, taking a
lock that makes another operation fail. Disable optional locking in the
shared scan subprocess so background observation does not compete with
workspace updates.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Workspace Git scans used by changed-file browsing, cleanliness guards,
and sandbox snapshots.

**Current behavior**
The scan process inherits Git's default optional-lock behavior. Even a
clean `status` can rewrite stale stat-cache entries in the index and
contend with a concurrent writer.

**Proposed behavior**
Always set `GIT_OPTIONAL_LOCKS=0` for the shared scan subprocess while
preserving the selected environment and Git's required write locks.

**Reason and benefit**
Background reads stop creating avoidable index contention. Git documents
this behavior and recommends disabling optional locks for background
status: [background
refresh](https://git-scm.com/docs/git-status#_background_refresh).

**Breaking changes**
None to scan results or required write locking. Later scans may repeat
stat checks that would otherwise have been cached in the index.

Related scan implementation: #11572, #14253. This avoids one known
contention source; it does not identify every historical lock owner or
repair abandoned locks.

## What Changed

- Disable optional locking at the shared scan subprocess boundary,
including explicit caller environments.
- Test a clean status against a deliberately stale index and prove an
ordinary status would rewrite it.
- Test tracked/untracked results with an existing index lock,
preservation of that lock and working files, and continued rejection of
a mandatory-lock write.
- Document the scan behavior and performance tradeoff.

## Verification

- Focused stream, workspace-sync, and scheduler suites: 63 tests passed.
- Full `pnpm -r typecheck` and `pnpm build` passed locally. Final head
`effe6420c77bd18d36af6b093db3a564c04b8b38` passed all 53 CI checks,
including complete test coverage, typecheck, build, and browser/runner
gates; two unrelated checks intentionally skipped.
- Full local test attempts initially had missing embedded-Postgres
library symlinks; the dependency setup was repaired. Duplicate local
full-suite runs were stopped after full CI completed. This PR does not
claim a completed full local suite.
- Review regression: real Git honors the supplied `GIT_CONFIG_*` setting
and the input environment remains unchanged; all four direct subprocess
cases passed.
- Reviewed the diff for secrets, customer data, and internal references.

## Risks

Low risk. Disabling optional index refresh can repeat filesystem stat
work on later scans. Required locks remain enforced; no lock is removed,
no failed reset is retried, and workspace mutation guards are unchanged.
No schema changes.

## Model Used

OpenAI GPT-6 via Codex, with repository inspection, code execution, and
tests. Exact model build identifier is not exposed by this session.

## Checklist

- [x] Thinking path and model are specified
- [x] Checked ROADMAP.md; this is a maintenance correction, not planned
feature work
- [x] Searched for duplicate and related PRs
- [x] Described the issue using the enhancement template
- [x] No internal issue references, customer data, or private instance
links
- [x] Descriptive branch name
- [x] Focused regression tests pass
- [x] Added tests and updated documentation
- [x] Risks documented
- [x] Required validation and CI gates are green (full suite validated
in CI; local scope documented above)
- [x] Greptile is 5/5 with no unresolved findings
- [x] I will address review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 14:28:07 -07:00
Devin FoleyandPaperclip 0ea6b10967 Record ACP activity and workspace restore failure evidence (#14665)
## Thinking Path

Paperclip records terminal run failures for operators. A timeout's own
log and cleanup output update the run's last-output timestamp, so that
timestamp can make a long-silent provider look active. Snapshot runtime
activity before finalization and include the saved workspace restore
classification to make the next failure actionable without copying tool
payloads.

## Linked Issues or Issue Description

**What existing behavior does this improve?**
Terminal run diagnostics in the existing opt-in Sentry integration.

**Current behavior**
Reports cannot distinguish runtime events from finalization logging and
omit the already-persisted workspace restore code. A later successful
run also does not establish that earlier workspace files were restored.

**Proposed behavior**
Record runtime-event age/count and pending-tool inventory at
finalization, before status reads and cleanup. Forward only finite
counts, a completeness boolean, and known restore codes through the
existing reporter.

**Reason and benefit**
Operators can distinguish a silent turn with unfinished tools from
recent runtime activity and see restore failures without retrieving
private run output. Neither signal certifies productive work or
successful recovery.

**Breaking changes**
None. Error grouping, execution deadlines, cancellation, recovery
policy, and the Sentry opt-in remain unchanged.

Related diagnostic work: #14573, #14575, #14639.

## What Changed

- Snapshot ACP activity before success/failure finalization, including
thrown relay failures.
- Forward bounded numeric/boolean evidence and shared workspace restore
codes; exclude commands, tool IDs, paths, and arbitrary result data.
- Document limitations and test silence, empty streams, timeout, cleanup
delay, incomplete tool inventory, and privacy.

## Verification

- `pnpm -r typecheck` passed after the final implementation.
- Changed suites: 252 tests passed; all 29 database reporter tests
subsequently passed after restoring the embedded-Postgres package
library symlinks. The migration test also passed (30 database cases
total).
- `pnpm build` passed during implementation. Final head
`fe78dba6f592b1abccac7cdbf341bd2e0b0d30cb` passed all 53 CI checks,
including complete test coverage, typecheck, build, and browser/runner
gates; two unrelated checks intentionally skipped.
- Full local test attempts initially hit missing embedded-Postgres
library symlinks; the dependency setup was repaired and database tests
passed. Duplicate local full-suite runs were stopped after full CI
completed. This PR does not claim a completed full local suite.
- Review regression: completed, failed, and cancelled tools are excluded
from the pending count; focused activity/timeout tests and adapter-utils
typecheck passed.
- Reviewed the diff for secrets, customer data, and internal references.

## Risks

Low risk, diagnostic-only. The existing tool inventory is incomplete for
some runtime events, so the report carries its completeness flag. Event
age is measured at finalization and does not prove useful work or
identify the underlying provider failure. No schema changes or new
capture gate.

## Model Used

OpenAI GPT-6 via Codex, with repository inspection, code execution, and
tests. Exact model build identifier is not exposed by this session.

## Checklist

- [x] Thinking path and model are specified
- [x] Checked ROADMAP.md; this is a maintenance correction, not planned
feature work
- [x] Searched for duplicate and related PRs
- [x] Described the issue using the enhancement template
- [x] No internal issue references, customer data, or private instance
links
- [x] Descriptive branch name
- [x] Focused regression tests pass
- [x] Added tests and updated documentation
- [x] Risks documented
- [x] Required validation and CI gates are green (full suite validated
in CI; local scope documented above)
- [x] Greptile is 5/5 with no unresolved findings
- [x] I will address review comments before requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.930.0-canary.13
2026-09-30 14:27:53 -07:00
DottaandPaperclip 31201f4a96 docs(runner-e2e): correct trusted board caller identity
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 15:46:28 -05:00
DottaandPaperclip 880b84193b test(runner-e2e): bound remote Stop proof to process lifetime
Distinguish live snapshots from the automatic owned-process retirement seal. Preserve local four-phase observation and separately revalidate remote UI/API cancellation state without claiming later filesystem reads. Version the suite and calibrate stale/replayed/foreign/lost-descendant evidence.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 15:42:26 -05:00
DottaandPaperclip 5edf55d735 fix: retire failed warm sessions before sandbox stop (#14747)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Native runner sessions can stay warm between turns in a reusable
sandbox.
> - Heartbeat stops that sandbox when a turn fails or is cancelled.
> - The native executor treated every returned terminal result as a
successful warm release.
> - A failed session could therefore retain a transport for a stopped
sandbox.
> - This pull request retires unsuccessful sessions before heartbeat
stops their sandbox.
> - A retry can start without inheriting that stale transport.
Successful turns stay warm.

## Linked Issues or Issue Description

**What happened?**

A structured failed or cancelled terminal result did not throw. The host
kept its native session in the warm cache even though heartbeat stopped
the reusable sandbox. Later session retirement could use the stopped
provider transport and reject the retry.

**Expected behavior**

Retire the unsuccessful session and collect its managed files before
returning to heartbeat. Keep successful sessions warm.

**Steps to reproduce**

1. Run a native session with a warm lifecycle and a reusable sandbox.
2. Return a structured failed or cancelled result from the provider.
3. Stop the sandbox after the executor returns.
4. Retry with a changed native session identity.
5. Verify that the previous session was closed before step 3 and is not
closed again during retry.

**Paperclip version or commit**

Developed from `b54b2dc35`, the current `origin/master` at
implementation time.

**Deployment mode**

Native runner with a reusable Daytona sandbox. The same warm-session
release path also serves local providers.

Related work: #14735 added incremental managed-file checkpoints for warm
turns. #14734 preserves tool outcomes during shutdown. This change fixes
the host's handling of unsuccessful terminal results.

## What Changed

- Retain a warm session only when its terminal run state is `succeeded`.
- Use the existing failed-session retirement path for structured
failures and cancellations.
- Preserve the existing checkpoint-before-retirement path, including
when provider shutdown fails. Collect stopped files after successful
shutdown, including edits made during shutdown.
- Retire the warm owner if the checkpoint or its receipt callback
rejects, then propagate the initiating error.
- Add ten regression cases for failure and cancellation, with and
without managed files. They check cleanup order, cache removal, retry
with a new session identity, and edits preserved when close rejects.
- Document the lifecycle rule.

## Verification

- The failed and cancelled managed-file regressions fail on unpatched
master because the provider is not closed.
- All 516 native executor tests pass, including ten new regressions.
- `pnpm -r typecheck` and `pnpm build` pass. `pnpm test:run` finished
its general-server group with 14,537 passed, 75 skipped, and one
existing failure in `native-session-resume.test.ts`
(`retainedNativeCleanupJournalMatches`, line 1125). A separate run using
the unmodified `origin/master` executor fails the same assertion. The
command stops before later local groups; all equivalent CI groups pass
on this head.
- All 56 PR checks are successful or intentionally skipped. Greptile
reviewed this head at 5/5 with no remaining findings.
- A real Daytona public-API probe forced a Codex authentication failure,
waited for a confirmed sandbox stop, corrected the credential, and
retried successfully in the same resumed sandbox. It verified the agent
note in canonical storage and deleted the test sandbox.
- Pumpkin staging on this exact commit: forced a structured
authentication failure, confirmed sandbox stop, corrected the
credential, and retried successfully in that same sandbox. Three
successful turns kept the same live runner PID/start ticks, native
session, runner instance, and provider session. Canonical downloads
verified the note, all 8 MiB binary bytes, and deletion persistence.
Subsequent checkpoints hashed/copied only 52 and 78 bytes. After sandbox
deletion, canonical files still matched. Temporary secrets, agent
configuration, and test policy were cleaned up or restored.
- Unpatched live probes with both 5-second and 90-second retry delays
also succeeded. The unit regressions prove incorrect retention; the
original stopped-lease exception was not reproduced in those probes. The
staging recovery campaign used the public retry API after an explicit
reset of the disposable task’s already-deleted old sandbox/session. The
UI did not expose a Retry control on the inspected task or run detail
views.
- Temporary API-key authentication was used for the campaign. This
change does not repair the original managed-subscription authentication
401.

## Risks

- Failed and cancelled turns now close their provider sooner. Successful
warm-turn behavior is unchanged.
- Cleanup uses the existing failed-session path. Its existing handling
of cleanup errors is unchanged.
- No database migration, API contract change, or dependency change is
included.

## Model Used

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

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass (516 relevant executor
tests; the full local suite has the independently reproduced baseline
failure documented above)
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [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.930.0-canary.12
2026-09-30 15:36:06 -05:00
DottaandPaperclip fdfe9418c9 test(runner-e2e): require rendered cancelled Stop screenshot
Observe the task In Progress header and native Run cancelled marker with loaded history before treating an absent Deny button as unanswerable. Bound all waits by the existing attempt deadline.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 14:49:23 -05:00
DottaandPaperclip 3e04cf1461 test(runner-e2e): bind active Stop actor and terminal stream
Observe the isolated local-board session through the public API, retain it before Stop, and require its exact startup cancellation actor. Explicitly bind both closure and terminal envelopes to the observed turn, normalized session and source, including missing/null-turn negatives.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 14:46:45 -05:00
DottaandPaperclip 11bc74b68d test(runner-e2e): wait for rendered warm review screenshots
Wait for the exact turn reply and pending review card with enabled Continue work, In Review header and completed history loading before capturing intermediate warm screenshots. Reuse the existing turn deadline; preserve prior screenshots and result grades.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 14:45:22 -05:00
DottaandPaperclip a6a5417cd9 test(runner-e2e): qualify Stop at pending native permission
Add explicit Cursor and Copilot local/Daytona cells that retain an unanswered callback before a caller-correlated Stop, require cancelled provider settlement and stale-answer rejection, and independently verify no effects through owned retirement. Normal completion and provider death do not satisfy this active-work oracle.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 14:42:10 -05:00
DottaandPaperclip ad55d0a281 fix(connections): repair personal credentials and request write access (#14739)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents use Apps through a gateway that checks identity, company
access, and action policies.
> - Personal pasted credentials can point to company secrets. Setup can
show success while the gateway rejects every call.
> - Several OAuth methods also omit the scopes needed for their
supported write actions.
> - This pull request gives setup, health checks, and invocation the
same credential rules. Owners repair existing connections by
reconnecting.
> - New connections request reviewed permissions for their supported
actions. Read-only choices remain available under Advanced.
> - Agents can use the connections people give them, while existing
consent, identity boundaries, and action restrictions remain enforced.

## Linked Issues or Issue Description

Refs #14009 and #14008. This addresses the personal-credential defect.
The separate GitHub organization-identity selection defect is outside
this change.

Related work: #13942 fixed part of new personal-key setup. #14200
independently fixes legacy personal reconnect and protects managed-agent
profile credentials during removal. This PR covers that ownership
invariant across key and secret-URL setup, reconnect, health, discovery,
and invocation, and keeps owner reconnect as the repair path. #14059
tracks requested versus provider-asserted OAuth scopes; it remains
separate work. I searched open PRs and issues for Zapier, Airtable
scopes, connector writes, and personal credential failures.

**What happened?**

A Zapier secret URL saved through personal setup can become a company
secret referenced by a user grant. Health checks bypass the gateway's
ownership check, so the connection appears healthy but calls fail with
`grant_credential_invalid`. Custom-header paths can also receive a
duplicate `credentials.` prefix. Omitted OAuth scopes make write access
depend on provider defaults.

**Expected behavior**

Personal invocation credentials belong to the selected user. Setup,
health, and actual calls enforce the same rule. New connections request
documented permissions for supported read and write actions. Existing
tokens gain no permissions without provider consent.

**Steps to reproduce**

1. Connect Zapier or a generic secret URL with the personal identity.
2. Allow an agent to use the connection and complete setup.
3. Invoke a tool through a run-scoped gateway. The legacy layout fails
ownership validation despite successful setup.

**Paperclip version or commit**

The implementation started from
`44736c9c7c67b7b646ead9d51721db10f5b83835` and was rebased onto master
at `94e8dec56`.

**Deployment mode**

Built from source. Regression tests use isolated PostgreSQL fixtures and
controlled MCP transports.

## What Changed

- Share credential writing, ownership validation, and canonical paths
across initial setup, resume, reconnect, rotation, health, discovery,
and gateway calls. Keep OAuth client-registration secrets separate from
invocation credentials.
- Existing personal connections with company-scoped credentials require
owner reconnect with a fresh key or secret URL. Reconnect creates a
correctly owned value and updates the existing grant and declarations.
There is no automatic ownership backfill or new startup hook.
- Preserve PostgreSQL timestamp precision when reconnect checks whether
a grant changed. Previously, converting the timestamp to a JavaScript
Date could reject reconnect with a false concurrent-change error.
- Protect credentials used by other grants, connections, bindings,
managed-agent profiles, routine triggers, or secret proposals from
connection removal.
- Review all 117 tool methods, including 84 OAuth methods. Record
explicit scopes or documented provider-default exceptions with official
evidence. Add Airtable's seven scopes, Hugging Face repository/job
scopes, and other documented MCP permissions.
- Prefer available write-capable methods. Put explicit read-only choices
under Advanced. Explain pasted-key permissions and offer reconnect for
missing OAuth consent. Preserve existing grants, policies, Google
availability gates, and curated scope allowlists.
- Reconnect generic secret URLs and custom headers using their stored
credential fields. Refresh the catalog after setup, correct reconnect
feedback and error guidance, and let Cancel exit invalid setup while
Save & exit retains draft-saving behavior.
- Apply ownership checks to the new GitHub repository/skill connection
picker. Align the permission audit with the Google scope reductions
merged on master.
- Add run-scoped gateway, ownership, owner-reconnect, OAuth URL,
insufficient-scope, UI, and catalog-wide regression coverage. Update the
connector playbook and permission audit.

## Verification

Latest commit `97bc0b86e0eae0ec892e4ac44beff1a66164b20e` passes all
CI/status gates (55 completed check runs, no failures or pending checks)
and has a completed Greptile review at **5/5 with no outstanding
findings**. GitHub reports the PR as mergeable/CLEAN.

- **Embedded browser:** used the actual server and built UI from this
worktree, a fresh isolated database, and local HTTP MCP fixtures.
Completed personal bearer-key, secret-URL, and custom-header setup;
reproduced the legacy ownership failure; reconnected through the owner’s
form; and completed writes afterward. Read-back was verified for
bearer-key and secret-URL connections. Public organization-wide setup
appeared immediately in Browse without reload. Zapier URL
validation/Cancel and Google’s enrollment gate were also exercised.
- **Persistence and invocation:** verified user ownership, canonical
`credentials.authorization` / `remote.url` / `headers.X-Api-Key`
declarations, and unchanged connection/grant identity. The old company
secrets retain their ownership. Separate HTTP calls through an actual
run-scoped gateway session completed a write and read-back.
- **Backend coverage:** the final gateway suite passes all 82 cases,
including catalog Zapier and generic inline reconnect. It checks
company/user isolation, canonical declarations, same-endpoint URL
validation, fresh credentials, retained restrictions, and real gateway
read/write execution using fixture transport. A timestamp with
PostgreSQL microseconds covers the former false reconnect conflict.
- **Local checks:** 368 catalog, gateway, repository, and UI tests
passed before the final extra Zapier case; 49 GitHub skill access tests
also passed. All three Apps browser regressions pass, including
reconnect through the actual form and catalog visibility without reload.
Full `pnpm -r typecheck`, `pnpm build`, server typecheck after the final
patch, and token gates passed. Full tool-access service runs hit varying
15-second Google fixture timeouts; both affected cases and the updated
reconnect assertion pass in isolation (3 tests). The complete test
matrix passes in CI on this head.
- **Verification limits:** no live provider account was available for
Zapier/Airtable/OAuth consent or account-bound write proof. Public
metadata and local fixtures do not establish provider consent. The
original development database clone failed on a pre-existing missing
`tool_connections_transport_check` constraint; browser acceptance used a
fresh isolated database created by the normal CLI onboarding flow.

## Risks

- Existing broken personal connections stay unusable until their owner
reconnects. Health, discovery, and invocation return an actionable
ownership error; startup does not rewrite credential ownership.
- Scope changes affect new authorization requests. Providers may still
require resource selection, account roles, paid plans, or app
verification. Existing consent and action restrictions remain unchanged.
- Shared credentials are retained rather than reassigned or revoked.
Provider-default exceptions and unavailable live checks are documented
in `doc/connections/CONNECTOR-PERMISSION-AUDIT.md`.
- No new endpoint, database table, lockfile change, or CI workflow
change is included.

## Model Used

OpenAI Codex, based on GPT-6, with reasoning, code editing, shell
execution, web research, and browser tools. The exact deployment model
ID and context window were 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.930.0-canary.11
2026-09-30 14:32:34 -05:00
DottaandPaperclip cbd278dc03 fix(interactions): derive chat recipients and validate explicit users (#14742)
## Thinking Path

> - Paperclip helps people manage AI agents and their work.
> - Agents use saved questions to get human input and continue the same
task.
> - The standard question example recently told models to copy a user
ID.
> - A model can omit an identity prefix and create a question its
intended recipient cannot answer.
> - Agent Chat already knows the conversation owner, so the server can
supply that identity.
> - This pull request removes the blanket instruction and validates
explicit recipients before saving.
> - Ordinary questions stay simple, and explicit addressing remains
available for decisions that need a particular person.

## Linked Issues or Issue Description

Refs #14707, #14188. Related: #14238 handles legacy email recipients;
this change prevents invalid recipients in new cards and retains exact
ID matching.

**What happened?**

A model copied a Cloud user ID without its prefix into
`addresseeUserId`. Creation succeeded. The intended user's answer then
failed the exact recipient check.

**Expected behavior**

Ordinary chat questions use the saved conversation owner. A task may
optionally name a specific recipient. The API rejects an unknown or
unauthorized recipient before it creates a card.

**Steps to reproduce**

Create a chat question for a user whose ID is `paperclip-id:example`.
Supply `example` as the addressee. Before this change, creation accepts
the invalid recipient and the owner cannot answer. With this change,
creation returns 422. Omitting the field saves the full owner ID and
allows that owner to answer.

## What Changed

- Remove `addresseeUserId` from standard question examples and remove
the blanket requester-ID instruction.
- Derive the recipient of ordinary chat questions from the persisted
conversation owner. Reject conflicting explicit user IDs.
- Keep explicit task recipients optional. Validate supplied user IDs
with the existing board mutation policy, including company, viewer, and
Cloud restrictions.
- Preserve explicit agent routing, connector intents, confirmations,
exact recipient checks, idempotent retries, and no-login local-board
authority in local-trusted mode.
- Update the blocker grader to accept an omitted recipient and verify
the actual requester answered.
- Add database and HTTP tests for prefixed identities, denied
recipients, concurrent retries, saved answers, and response delivery.

## Verification

- Database interaction service suite: 90 tests passed, including
implicit local-board creation/answering and authenticated/Cloud denial.
- Interaction HTTP route suite: 84 tests passed.
- Affected interaction/native/connector/documentation suites: 231 tests
passed across six files after valid-user fixtures were updated.
- Resolver and interaction unit suites: 29 tests passed.
- Product E2E unit/calibration suite: 793 tests passed; Product E2E
typecheck and blocker catalog discovery passed.
- Generated API-reference and capability contract checks passed.
- `pnpm -r typecheck` and `pnpm build` passed.
- Full local `pnpm test:run` did not finish green: its initial
general-server pass had 14,416 passing assertions, one unrelated
native-resume assertion failure on macOS, and three teardowns from an
intermediate fixture cleanup fixed above. Separate broad local groups
also encountered timeout/live-port failures under host load. Local UI
(7,026), CLI (502), shared (817), and skills-catalog (20) tests passed;
the complete final-head CI matrix is the broad verification gate.
- After two CI cold-start readiness timeouts, a separate test-only
commit gives the first exposure lifecycle fixture the existing normal
30-second readiness budget. Its real HTTP, ordering, and cleanup
assertions remain intact; the targeted case and final Linux CI shard
passed. Production deadlines are unchanged.
- A separate OpenCode fixture failed twice on GitHub-hosted Ubuntu
because its cached Node executable was group-writable; the same case
passed on AWS runners. The fixture now qualifies its own Linux copy with
mode `0500` and the actual copy digest. Host files and production
security checks are unchanged. The focused macOS case passed; the new
Linux-copy branch also passed on the final AWS-hosted Linux runner
(1,125 passing Runner tests, 3 skipped). The final run was not on a
GitHub-hosted runner.
- Final-head [CI run
36762078176](https://github.com/paperclipai/paperclip/actions/runs/36762078176)
passed for `116b968b24fa0a8c5724a7bf96e73a8dda5f0425`: 54 successful
checks and two conditional Storybook skips, with no pending or failed
checks. The 27 general/serialized test jobs reported 28,635 passing
tests. Typecheck, build, Runner, browser E2E, and Canary gates passed.
Greptile reviewed that exact head at 5/5; both review threads are
resolved, with no open follow-ups.
- No live provider replay is claimed by this PR.

## Risks

- New explicitly addressed cards reject users who cannot mutate the
issue, including viewers, inactive members, and invalid IDs. Callers
that supplied invalid recipients must correct their request.
- Existing addressed cards are not rewritten. Existing authorization
checks remain strict.
- Chat inference applies only to questions without an agent addressee.
Connector intents and governed confirmations retain their own recipient
paths.
- No schema change or migration is required.

## Model Used

OpenAI Codex, GPT-6 (exact serving variant and context window are not
exposed in this environment). Used reasoning, tool use, code editing,
and test execution.

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 14:16:15 -05:00
Dotta e4bf459e31 fix(server): fence native retry cancellation through final commit
Recheck retry eligibility under the coordinator lock before creating a cancellation intent. Preserve later run and coordinator outcomes with a failed-only acknowledged-result CAS, while retaining same-intent recovery and NOWAIT conflict handling.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
(cherry picked from commit 29230e2000)
2026-09-30 13:54:30 -05:00
Dotta 45b977bca0 fix(server): admit correlated Stop for durable native retries
Check failed-run retry eligibility under the run and coordinator locks, fail closed on concurrent coordinator claims, and preserve same-caller recovery after the audited intent disables a retry. Keep terminal failures and foreign actors or intents rejected.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
(cherry picked from commit 79db1c2a6f)
2026-09-30 13:36:15 -05:00
DottaandPaperclip b54b2dc35c fix: preserve warm Codex turns with incremental managed file checkpoints (#14735)
## Thinking Path

> - Paperclip manages AI agents and keeps their instructions and files
durable.
> - Native Codex runners can keep a process alive between compatible
turns.
> - Managed file collection stopped that process after each turn, which
defeated warm reuse.
> - Agent folders can contain large images and other files, so full
copies on every turn are expensive.
> - This change keeps one managed directory for the live session and
saves only file changes after each turn.
> - Ownership, authorization, instruction changes, and process
retirement still control when reuse is safe.

## Linked Issues or Issue Description

Related: #13710 introduced native warm session reuse. This fixes managed
file collection that still forced those sessions to stop. No duplicate
open PR or issue was found.

**What happened?**

With managed instructions and warm native Codex enabled, consecutive
turns reused a Daytona sandbox but started a new runner process each
time. The managed directory collector required process termination
before saving files.

**Expected behavior**

Compatible turns keep the same process and managed `AGENT_HOME`. Each
completed turn saves added, changed, and deleted files before the next
turn starts. Unchanged large files do not transfer again.

**Steps to reproduce**

1. Use a native Codex agent with managed instructions and a reusable
Daytona environment.
2. Enable warm session reuse and run three turns on the same task.
3. Write a large binary on the first turn, edit a small note on each
turn, and delete a file on the second turn.
4. Compare process identity across turns and read the canonical files
through the public agent-files API.

**Paperclip version or commit**

Reproduced on `d30b03bd8c17604cdab1533eeeeb087aba30e8b1`.

**Deployment mode**

Local server with remote Daytona execution; cloud native runner uses the
same path.

## What Changed

- Retain the managed directory only for the verified owner of a live
native Codex session.
- Checkpoint each completed turn before releasing the session for reuse.
Retry unstable captures, then stop and collect when a warm checkpoint
cannot be validated.
- Compare metadata and cached hashes, stream only changed file payloads,
record deletions, and validate path, content, quota, and authorization
before saving.
- Rotate sessions when canonical files, loaded instructions,
credentials, or launch policy change. Fence stale collection and cleanup
callbacks from later owners.
- Keep cleanup and recovery aware of the current session owner. Recheck
canonical files under the writer lock at handoff, attach the successor
collector before fallible bookkeeping, and emit one final save receipt
on checkpoint fallback. Preserve storage warnings across unchanged
checkpoints.
- Add regression coverage and a three-turn Daytona test with independent
public API file checks, an unchanged 8 MiB binary, deletion checks, and
strict process identity checks.
- Document checkpoint consistency, lifecycle behavior, and local run-log
counters.
- Replace a timing assumption in the Daytona teardown test with explicit
transfer-arrival gates after CI exposed an unset release callback.

## Verification

- Full local `pnpm -r typecheck` and `pnpm build` passed. Server checks
were repeated after the final storage-warning fix.
- Runner E2E typecheck and 749 runner E2E unit tests passed.
- Focused file checkpoint, directory ownership, instruction collection,
native session, and merge tests passed. After review fixes, the
managed-directory and native-session suites passed 550 tests, including
intervening canonical edits, same-run fresh restore, failed handoff
collection, and one-call fallback collection. Server typecheck passed
again. The Daytona plugin suite passed 218 tests. The quota-warning
regression failed before the fix and passed afterward.
- Three real Daytona campaigns passed before the final handoff review
fixes. The latest kept PID 547 across all three turns. The first
checkpoint copied 8,388,635 bytes; the next two copied 36 and 54 bytes.
Public API reads verified the binary, note contents, and deletion after
every turn. Test cleanup deleted the sandbox.
- The final head was also deployed to an isolated cloud staging instance
and passed three UI-triggered native Codex turns with managed
instructions. All three retained the same process ID/start time, native
session, provider session, runner instance, and Daytona sandbox.
Checkpoints copied 8,388,643 bytes on turn 1, then only 52 and 78 bytes
on turns 2 and 3; those warm captures also hashed only 52 and 78 bytes.
Independent canonical API reads verified every byte of the unchanged 8
MiB binary and the exact note contents after every turn; the deleted
file returned 404 after turns 2 and 3. After restoring the original
lifecycle and agent-auth configuration, removing the temporary secret,
pausing the test agent, and deleting both test sandboxes, independent
canonical API reads still verified the entire binary, the final 78-byte
three-line note, and the deletion. The native runner flag remained
enabled and the final serving revision remained the PR head.
- Two earlier staging attempts are preserved as failures and are
excluded from the acceptance result: a saved ChatGPT login failed with a
provider routing 401, and its subsequent stopped-sandbox retry failed
before provider startup with a closed-lease admission error. The
successful campaign used a fresh sandbox and a temporary encrypted
API-key binding. The stopped-lease retry remains unexplained; this
campaign does not establish recovery of that failed sandbox.
- All [Paperclip CI
gates](https://github.com/paperclipai/paperclip/actions/runs/36750397355)
pass on `26ef2ef56a389259246809805c0b34a4747eb86b`, including full test
partitions, build, typecheck, runner verification, E2E shards, and the
Canary clean public-npm install. Greptile reviewed that exact head at
5/5 with no unresolved review threads or outstanding findings.
- Full local repository coverage used the existing CI partitions, but
the 40,000-file Git streaming stress test timed out and its local retry
was interrupted by macOS thermal emergency sleep; this is not a green
full local suite claim. The exact stress test passed on the final head
in [CI server shard
2/12](https://github.com/paperclipai/paperclip/actions/runs/36750397355/job/110008294290),
in 111.9 seconds.
- Repeat the live test with configured credentials and a Linux runner
artifact: `pnpm test:e2e:runner -- --id
daytona-warm-continuity.runner-codex.daytona.warm-three-turn`.

## Risks

- This is a file-level checkpoint, not an atomic snapshot of the whole
folder. Background writes after a capture are saved by the next
checkpoint or final stopped collection.
- Metadata scans still visit all paths. Modified files transfer in full;
unchanged files do not rehash or transfer.
- Incorrect ownership or reuse could collect the wrong directory. Run
ownership fences, current authorization, stable capture validation, and
stopped collection fallbacks are covered by tests.
- Warm reuse remains opt-in. No database migration or fleet default
changes.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
canary/v2026.930.0-canary.10
2026-09-30 13:33:37 -05:00
DottaandPaperclip d432dc7fa3 Add GitHub-synced skill sources (#14713)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Company skills supply instructions and files to those agents.
> - GitHub imports already exist, but users cannot manage repositories
as skill sources.
> - Repository refresh also needs caller-authorized access and complete
local packages.
> - This pull request adds Sources inside Skills and reuses GitHub
connections from Apps.
> - Installed snapshots let agents use skills without fetching GitHub
during a run.
> - Manual refresh preserves skill identity and leaves failed imports on
their last good version.

## Linked Issues or Issue Description

**Subsystem affected**

Cross-cutting: skills UI, server, database, shared contracts, and
runtime materialization.

**Problem or motivation**

Users keep skills in GitHub repositories. They need a clear way to
select, import, and refresh those skills. Existing imports do not expose
repository management or consistently preserve supporting files.

**Proposed solution**

Add company-scoped skill sources. Browse repositories from all
accessible GitHub connections, or paste a public repository or branch
URL. Select whole skill packages, inspect included files and reference
warnings, and install complete, immutable snapshots. Refresh each source
manually.

**Alternatives considered**

Project repository settings hide the workflow from Skills. A second
GitHub connector would duplicate credentials and grants. Upstream
editing and PR creation are separate work.

**Roadmap alignment**

This implements the Skills Manager direction in ROADMAP.md. The
maintainer requested this scope and reviewed the component and full-app
journey stories before implementation.

Related reports: Refs #10285, Refs #10949, Refs #13464. Related work:
#14356, #13656, #9268.

## What Changed

- Add source and entry records, an idempotent migration, company-scoped
APIs, and legacy GitHub import adoption.
- Reuse current caller grants and credential refresh. Combine and
deduplicate repository inventories across accessible connections. Pasted
public URLs also prefer the active user’s authorized connections. Tokens
stay in the Git child environment, never argv or disk.
- Fetch a shallow Git snapshot at one immutable commit. Scan the full
local tree, including hidden and nested folders. Read Git objects
without checkout or archive transformations and enforce nested package
boundaries.
- Bound Git downloads to 128 MiB and three minutes. Cancel active
process groups and remove incomplete downloads. Preserve cancellation
and deadlines while progress drains; close stalled HTTP progress streams
after 30 seconds. Reuse caller-scoped temporary snapshots for
preview/import after reauthorization.
- Index repository package boundaries once and cap expanded work at
1,000 packages, 10,000 files, and 100 MiB, including repeated copies of
shared blobs. Bound path depth and the shared path index. Discovery
keeps audited manifests without retaining all package bodies.
- Resolve moving branches before fetching so unchanged discovery reuses
caller-scoped snapshots. Limit active scans, scan frequency, and new
downloads per caller and company; quotas apply before metadata reads and
across connections, and cached scans do not consume the download quota.
- Store complete versions with script content, binary bytes, and
executable modes. Preserve these through copies, runtime caches, and
runner packaging.
- Stage downloads before publication. Use source leases, revision
checks, and transactional activity records. Keep installed versions
after failures, upstream deletion, deselection, and disconnect.
- Add the approved import flow, Sources page, selection tree,
provenance, read-only Studio behavior, and saved return from GitHub
setup.
- Add package manifests, commit-pinned file previews, and separate
runtime requirements and reference warnings. Supporting files are
included together; nested skills remain independently selectable.
Preview requests reauthorize the caller and re-audit package content.
- Show installed skills as compact links beneath each source. Repository
titles open GitHub. Keep Refresh, Select skills, and Disconnect source
in a three-dot menu. Source rows omit the branch, imported count, and
refresh timestamp; action alignment and repository titles work at narrow
widths.
- Stream discovery metadata over an opt-in NDJSON response. Show
measured Git download progress and real package/file counts, animate
newly checked skills, support cancellation, and require a complete scan
before selection. Keep the existing JSON API.
- Retain component stories and add a separate full-app journey story
group. Include fixed progress states and interactive scan,
large-repository, interruption, and saving stories.
- Update Skills documentation and product contracts. Suppress private
GitHub skill references in telemetry. Privacy review requested for the
telemetry changes.

## Verification

- Local repository typecheck, full build, token gates, and Storybook
build passed during this work. Focused transport, authorization,
scanner, persistence, route, and UI tests pass. The final UI refinement
passes all eight focused UI tests, UI typecheck/build, and token gates.
The scanner resource and repeated-discovery fixes pass 132 focused
scanner, transport, authorization, source-service, route, and rate-limit
tests, plus server typecheck/build. Full-suite verification comes from
CI; the older full local Vitest run was stopped after unrelated chat
failures and a font-test failure, all of which passed in fresh focused
runs. At commit `1098d5996`, all 54 active checks pass; two optional
Storybook jobs are skipped. CI covers repository typecheck, build, the
full test suites, browser shards, and the canary dry run. Greptile is
5/5 with no open findings; the security scan also passes.
- Adversarial scanner tests verify repeated-blob byte accounting with
and without declared sizes, package/file/path caps, one-time repository
indexing, metadata-only discovery audits, and nested package boundaries.
Additional tests cover branch movement, snapshot reuse, caller/company
quotas, isolation across connections, active-lease cleanup, quota
recovery, and rejection before any metadata API call.
- Real Git tests verify hidden paths, exact binary bytes, executable
modes, export-ignore preservation, symlink/submodule reporting, pinned
commits, caller-scoped cache reuse, cancellation, cleanup, and
credential isolation. Regression tests hold both download slots with
permanently blocked progress callbacks, verify timeout/cancellation
cleanup and retry, and exercise HTTP backpressure cancellation. Access
tests cover automatic public-URL connection selection and revoked
grants. Database tests verify company and grant audiences.
- Live isolated browser test: the public `anthropics/skills` scan now
completes and discovers all 20 skills without connecting an account.
Imported canvas-design with all 83 files, opened it from Sources, and
verified the installed binary-font preview/download control. Package
previews also expose the complete file inventory before import.
Cancelled an active Git download and retried successfully to all 20
discovered skills; the browser displayed measured download progress. The
current audits reject four other packages; eligible selections remain
importable.
- Browser checks verify the simplified source rows at desktop and narrow
widths, keyboard navigation into the actions menu, Refresh from the
menu, selection, and fixture disconnect with installed skills retained.
Storybook includes a menu-open checkpoint and a 320px layout.
- Storybook includes receiving/preparing download checkpoints and a
timed full-app import journey, plus cancellation, retry,
large-repository, and saving states. Streaming tests cover split UTF-8
frames, incomplete streams, late responses, cross-company requests, HTTP
errors, and JSON compatibility.
- Earlier live acceptance on this PR imported `stitch-skill` with
`DESIGN.md`, assigned it to an agent, disconnected its source, and ran a
successful Studio test that read both installed files. An editable copy
changed independently. Both Skills variants, mobile selection, and
return from GitHub setup were exercised.
- Private access, revoked credentials, OAuth success return,
binary/script preservation, concurrent refresh, transaction rollback,
version pins, and legacy adoption have automated coverage. A real
private-repository OAuth grant was not created during this test.

## Risks

- The migration groups recognizable legacy imports without provider
calls. Their first successful refresh completes the local package
snapshot.
- Reference checks are advisory. They cover Markdown links and explicit
relative resource paths, not arbitrary runtime dependency graphs.
Preview text is capped at 64 KiB; imported bytes remain complete.
- Git must be installed on the server. Shallow fetches still download
the branch snapshot, including files outside selected packages.
Downloads have size/time/concurrency limits. Temporary caches are
bounded and caller-scoped. GitHub API quota still applies to repository
metadata and the connection picker; content no longer uses per-file API
requests. Failed scans retain installed content.
- Sources depend on the current caller's GitHub access. A saved
connection does not grant access to another person's token.
- GitHub script support and immediate manual refresh are explicit
maintainer-approved requirements. The operator trusts the selected
repository and accepts upstream script and executable-mode changes on
refresh. Static audits are not a sandbox or a guarantee of safe code;
agents may later invoke installed helpers under their runtime
permissions. Import and refresh do not execute scripts, hooks, package
installation, or builds. Raw URL and skills.sh imports keep their prior
script restrictions.
- Source originals remain read-only. Refresh affects subsequent unpinned
runs; explicit pins and active runs retain their versions.
- The telemetry change removes source-managed GitHub identifiers from
skill-reference events. It introduces no event or field. Please review
the privacy boundary.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 13:32:58 -05:00
DottaandPaperclip 7141ab68a0 docs: improve README quickstart, harness logos, and links (#14744)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The README introduces supported harnesses, features, and setup.
> - Its logo table omits several supported harnesses.
> - Feature descriptions also need direct links to their user guides.
> - People interested in Paperclip Cloud need a clear waitlist link.
> - The Quickstart leads with a long installer script even though npx is
supported.
> - This pull request adds the logos, guide links, waitlist and careers
links, and a maintenance FAQ, and leads Quickstart with asking an agent
to install Paperclip, followed by the npx command for manual setup.

## Linked Issues or Issue Description

**Issue type**

Missing documentation coverage.

**Where is the issue?**

The README header, “Works with” table, feature cards, system
descriptions, Quickstart, deployment FAQ, and Contributing section.

**What's wrong?**

The icon table omits supported harnesses. Feature descriptions lack
direct links to the published guides, and the header has no Cloud
waitlist link. The README also lacks a careers link. Its Quickstart
leads with a multi-step shell installer instead of the supported npx
command.

**Suggested fix**

Use the brand assets already shipped with the UI. Arrange the table in
two rows. Add direct documentation links in context and a Cloud waitlist
callout below the embedded video and above the main heading. Link the
careers page near the bottom. Lead Quickstart with asking an agent to
install Paperclip, followed by npx and the Node.js prerequisite for
manual setup. Link to managed-install details and format FAQ entries
with Q/A labels and spacing.

Refs #14741, the merged README refresh. Related: #1921, an existing
proposal to replace the old Codex placeholder. This change uses the
current UI Codex asset. Searched open README logo PRs before opening
this follow-up.

## What Changed

- Add bold Q/A labels and paragraph breaks to all six FAQ entries, with
extra spacing between questions.
- Lead Quickstart with “Just ask your agent to install Paperclip” and a
link to the installation guide. Follow with `npx paperclipai@latest
onboard --yes` and the Node.js 24.11+ prerequisite for manual setup.
Replace the shell-installer blocks with the installation-guide link and
use npx for related setup commands.
- Add a maintenance FAQ identifying the Paperclip team, linking to
paperclip.ing, and citing over 2,700 merged pull requests with a link to
the merged PR list.
- Add “We're hiring” beneath the Contributing paragraph, linked to the
careers section.
- Add a “Sign up for the Paperclip Cloud waitlist” link below the
embedded video and above the main heading.
- Link fifteen guide pages from features, systems, setup, and deployment
text. Use published pages on docs.paperclip.ing.
- Add Gemini CLI, OpenCode, Pi, Hermes, Grok Build, and Kimi Code logos.
- Label Cursor Cloud and Hermes Gateway beside their shared brand marks.
- Use the existing UI Codex and Cursor assets.
- Remove the Bash and HTTP logo cells and arrange ten harness logos in
two rows of five. Set uniform image dimensions and align icons at the
top of each cell.
- Select existing dark-mode assets through picture elements.
- Remove the text roster that repeats the expanded table. Keep the
adapter documentation link.

## Verification

- Confirmed all six FAQ entries have Q/A labels and spacing, with their
wording preserved. Confirmed the first Quickstart subsection is “Just
ask your agent to install Paperclip.”
- Checked npx support against the published installation guide, npm
package metadata, and the CLI onboarding implementation. npm currently
publishes `paperclipai` with the expected binary and Node.js >=24.11.0
requirement. Checked Quickstart shell syntax and confirmed all other
README sections are unchanged by the Quickstart edit. No installer or
onboarding command was executed.
- Confirmed 2,710 merged pull requests through the GitHub search API on
September 30, 2026 (`repo:paperclipai/paperclip is:pr is:merged`,
`incomplete_results: false`). The FAQ uses “over 2,700” so the claim
remains valid as more PRs merge.
- Passed: `git diff --check`. The careers page loads and contains the
Careers section.
- Passed: local structure and asset checks. All sixteen SVG sources
exist and parse. All ten images have labels and dimensions. Each row
contains five logos.
- Checked the roster against the built-in adapter registry and UI brand
mapping. The table covers twelve branded adapter variants through shared
harness logos. Generic process and HTTP adapters are described beneath
the table. The retired ACPX adapter and Paperclip's own runner engine
are not separate external harness brands.
- The remaining logos were verified in the earlier GitHub dark-mode
render at 32 by 32 pixels. After removing Bash and HTTP, a local HTML
structure check confirmed two rows of five logos with the existing top
alignment.
- Passed: all fifteen new guide destinations and the waitlist URL
returned HTTP 200 with matching page titles. HTML link nesting is valid.
Approved four-pillars and roadmap content is preserved.
- Full typecheck, runtime tests, build, and browser suites were not
rerun for this Markdown-only change. No runtime source or image assets
changed.
- CI and automated review are pending. The PR is a draft.

## Risks

Low runtime risk. Only README.md changes. The table now references
existing UI asset paths, so future asset moves must update these links.
No new artwork or dependencies are added. The documentation links depend
on the published site paths. The primary Quickstart requires Node.js to
be installed already; this prerequisite is shown immediately above the
command.

## Model Used

OpenAI GPT-6 via Codex. The exact model variant and context-window size
were not exposed in this session. Used repository inspection, shell
tools, documentation editing, and browser verification. No subagents
were used.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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-09-30 13:23:58 -05:00
DottaandPaperclip 25c422ba7e fix(apps): request minimal Google service scopes (#14740)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Google connections give agents service-specific tools through
governed credentials.
> - Each connection has a reviewed OAuth scope set.
> - Docs, Sheets, and Slides request Drive permissions in addition to
their own service scopes.
> - Google documents these permissions as alternatives, not combined
requirements.
> - This pull request removes those extra permissions and redundant
Calendar write free/busy access.
> - Users grant fewer permissions without adding tools or changing
connection access policy.

## Linked Issues or Issue Description

Refs #13820. Related #14739 changes other connector permissions; it does
not reduce these Google profiles.

Companion broker PR:
https://github.com/paperclipai/paperclip-cloud/pull/615. Ship the
matching changes together after fresh-grant validation.

**What happened?**

Seven Google profiles request redundant scopes. Docs, Sheets, and Slides
request Drive scopes. Calendar write requests free/busy even though
calendar.events authorizes its availability tool.

**Expected behavior**

Each profile requests only the scopes required for its reviewed tools.
Managed and customer-owned OAuth methods use the same set.

**Steps to reproduce**

Inspect the Google profile registry and the four app definitions on the
base commit. Compare their scope sets with Google's MCP authorization
alternatives linked in the updated documentation.

**Paperclip version or commit**

Base: 94e8dec56b.

**Deployment mode**

Hosted and self-hosted Google Workspace connections.

## What Changed

- Docs, Sheets, and Slides read profiles request only their service
read-only scope. Write profiles request only their service write scope.
- Calendar write keeps calendar-list read-only and event access.
Calendar read keeps free/busy.
- Apply these sets to managed and customer-owned OAuth methods and their
exact-scope tests.
- Document scope rationale, old-grant behavior, and the coordinated
broker rollout.
- Preserve the 21-scope integration union. Drive and Workspace Search
still need their own Drive permissions.

## Verification

- `pnpm exec vitest run packages/shared/src/app-definitions.test.ts`: 25
passed.
- `pnpm -r typecheck`: passed with repository-pinned pnpm 9.15.4 after
refreshing locked dependencies.
- `pnpm build`: passed with repository-pinned pnpm 9.15.4.
- `pnpm test:run`: attempted on the machine's Node 26 runtime, then
interrupted after unrelated suite/collection failures. This is NOT a
passing full-local-suite result. CI uses Node 24.
- Node 24 focused diagnostic rerun: `workspace-runtime-exposure.test.ts`
and `paperclip-control-plane-port.test.ts`: 43 passed, 3 skipped. The
first suite hit a local preview-readiness timeout in CI; the failed
shard passed its single retry without code changes.
- Node 24 rerun of the three local assertion-failure suites
(`chat-discord-adapter-patch`, `ai-connections`, and
`heartbeat-active-run-output-watchdog`): 133 passed. These files were
not changed.
- Node 24 rerun of the changed manifest contract suite: 25 passed.
- Latest-head GitHub checks are green at
`da85dcbc89c44d88f3cabd5ada142c922fa51a3c`: 54 passed, 2 intentionally
skipped; no failed or pending checks. Includes typecheck, build,
general/serialized tests, all 8 browser E2E shards, Runner verification,
and canary packaging. Greptile 5/5, no review threads.
- Cross-repository comparison: all 16 app and broker profiles match
exactly.
- `git diff --check`: passed.
- Google definitions are reviewed JSON source inputs preserved by the
ingestion script. The generated TypeScript registry imports them; no
generic provider regeneration is needed.
- Fresh minimal-grant provider testing is outstanding. No new video was
recorded, and existing broader credentials are not proof of minimal
authorization.

## Risks

The Cloud broker must ship the matching exact scope sets. Mixed versions
fail closed. Validate fresh grants in staging before production.
Existing provider tokens are not retroactively narrowed; affected
managed connections must reconnect if their grants retain extra scopes
or omit explicit scope evidence at refresh. Do not revoke the shared
Google project to migrate one connection. This change does not grant
access, add tools, or alter the Google Chat unread-filter block.

## Model Used

OpenAI Codex, GPT-5-based coding agent, with reasoning, code execution,
and browser tools. The exact runtime model ID and context-window size
were not exposed to the agent.

## 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-09-30 13:10:42 -05:00
DottaandPaperclip d1f3e7bb0d docs: refresh README capabilities and roadmap (#14741)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The README introduces the product and directs people to setup and
the roadmap.
> - The product now supports more harnesses, connections, skills, and
team workflows than the README shows.
> - Some copy still describes available features as future work or makes
claims broader than the implementation.
> - This pull request updates the README and matching roadmap entries
from current source evidence.
> - Readers can see what they can use, what requires setup, and what
remains experimental.

## Linked Issues or Issue Description

**Issue type**

Outdated information and missing documentation.

**Where is the issue?**

README.md feature descriptions, four pillars, setup, FAQ, and roadmap;
related entries in ROADMAP.md.

**What's wrong?**

The README omits supported adapters and major connection and skills
workflows. It presents Connected Apps and Agent Chat as wholly future
work. Some budget, audit, and approval descriptions also need more
precise wording.

**Suggested fix**

Keep the existing structure, four-pillars picture, and completed roadmap
milestones. Extend the four-pillars table without removing its existing
content. Add concise descriptions of supported features. Correct
capability and setup claims. Distinguish available, experimental, and
planned work, and explain that the roadmap follows the default branch.

Searched open README and roadmap PRs and related documentation issues.
Refs #14640, which proposes a separate launch-video update; this change
preserves the existing video.

## What Changed

- Expand adapter coverage and describe model choice alongside durable
team context.
- Add six feature cards: connections, personal identities for shared
agents, Skill Studio, routines, artifacts and feedback, and team
templates.
- Describe experimental agent conversations and external chat/email
entry points.
- Correct budget, audit, approval, goal, session, secret, portability,
and multi-organization claims.
- Qualify export portability: plain environment values and local paths
can remain, so packages need review before sharing.
- Retain the four-pillars image and all existing table content; add
connection identities, skill history, team templates, and run history.
- Correct mention wake behavior, persistent npx data, source-build
prerequisites, and hosting guidance.
- Retain all 18 completed README roadmap milestones and its original
closing sentence. Add seven completed milestones: Connected Apps,
personal/shared AI accounts, Shared Agents Use Personal GitHub
Identities, skill version history, document comments and revisions,
company-wide search, and mixed-model/harness teams.
- Keep the README’s yellow roadmap entries to their names. Expand the
new milestones in ROADMAP.md alongside the existing status updates for
agent chat, memory, recovery, evaluations, and queue scope.
- Preserve all existing top-level section headings and their order. No
runtime files change.

Research: reviewed 393 candidate change summaries from a 60-day history
of 1,274 non-merge commits, then checked relevant implementation,
feature defaults, contracts, and current public adapter documentation.
The main gaps span adapters, connections, responsible identities,
skills, routines, deliverables, teams, chat/memory status, governance
claims, and setup.

Suggested follow-up work: refresh the product demo; add three concrete
use cases; shorten Quickstart by moving secondary setup paths into the
docs.

## Verification

- Passed: `git diff --check`.
- Passed: local link and asset targets, Markdown anchors, and HTML table
nesting in both edited files.
- Passed on the earlier revision: rendered README inspection on GitHub,
including the new feature cards and roadmap status labels.
- Passed: exact restoration checks for the original picture and both
requested passages, preservation of every original pillar-table cell,
and all 18 original checked roadmap items.
- Passed on this revision: seven new green milestones synchronized
between README.md and ROADMAP.md, three short yellow labels, local link
targets, table markup, and verification that README edits are confined
to its roadmap.
- Verified new milestone claims against AI Connections and managed
GitHub identity contracts, Skill Studio restore behavior, document
annotation/revision routes, company search, and the adapter registry.
- Passed on the earlier revision: `pnpm -r typecheck`.
- Passed on the earlier revision: `pnpm build`. No runtime code changed
in this documentation follow-up.
- `pnpm test:run` reported a failure in unchanged native-session
recovery code. Stopped the broader local run after reproducing it with
`pnpm exec vitest run --project @paperclipai/server
server/src/services/native-runtime/native-session-resume.test.ts
--no-file-parallelism --maxWorkers=1`: 40 passed, 1 failed. The failing
case is “archives a damaged prior epoch before completing guarded
same-task replacement with real runnerd”;
`retainedNativeCleanupJournalMatches` returned false at line 1125. The
full local suite did not complete.
- Previous revision `4bef0af3da13b03875efacd9e1f165bc69932b25` received
Greptile 5/5; the export wording finding remains addressed. A fresh
review is pending for this documentation follow-up.
- CI remains pending. This PR remains a draft; local runtime tests are
not green.
- Checked feature claims against the adapter registry, feature catalog,
Connections contracts and action UI, skill and team services, task
semantics, deployment docs, and source startup code.
- Browser suites were not run. This change edits documentation only.

## Risks

Low runtime risk: only README.md and ROADMAP.md change. The default
branch can lead published packages, so the roadmap now links to release
notes. Provider setup and feature flags still affect availability. Live
provider integrations were not requalified for this documentation pass.

## Model Used

OpenAI GPT-6 via Codex. The exact model variant and context-window size
were not exposed in this session. Used repository research, reasoning,
shell tools, and documentation editing. No subagents were used.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [ ] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] 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-09-30 13:02:58 -05:00
scotttongandClaude Opus 5.5 6aa908ef15 fix(heartbeat): cancel queued runs whose claim is permanently rejected (#14738)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The heartbeat scheduler claims queued runs for each agent in
`startNextQueuedRunForAgent`, and startup recovery calls it through
`resumeQueuedRuns`
> - `claimQueuedRun` can throw a 4xx `HttpError` that the run's own rows
decide, for example the 403 from #14043 ("Queued-message interrupt
authority is unavailable")
> - The claim loop does not catch that error. The run stays `queued`, so
every recovery pass and every restart claims it again and gets the same
error
> - During periodic recovery the error is logged, but it stops the claim
loop, so all queued runs of every agent after it wait. During startup
recovery the error is rethrown, so the server cannot boot
> - We saw this on a self-hosted instance: one card-answer run from
#14043 put the server in a crash loop for about 11 hours (216 failed
boots) until the run was cancelled by hand in the database
> - This pull request cancels a queued run when its claim fails with a
403 that cannot clear, keeps a run queued when its 4xx rejection can
clear later, and in both cases continues with the rest of the queue
> - The benefit is that one bad queued run can no longer stop the server
from starting or stall other agents. #14510 fixes the specific identity
mismatch; this change is the safety net for this whole class of error

## Linked Issues or Issue Description

Refs #14043

Refs #14510, #13539, #13315

## What Changed

- `server/src/services/heartbeat.ts`: The claim loop in
`startNextQueuedRunForAgent` catches errors from `claimQueuedRun` for
each run.
- A 403 is a permanent rejection. In the claim path it only comes from
the run's persisted identity (an unverifiable interrupt receipt, a
manual wake without a user), and those rows do not change. The loop
cancels that run with error code `queued_run_claim_rejected`.
`cancelRunInternal` also cancels the wakeup request and releases the
issue execution lock.
- The cancel runs after the agent start lock is released (`.finally()`),
because `cancelRunInternal` promotes the next queued run under the same
lock. A cancel inside the lock waits 30 seconds for the stale-lock
timeout.
- Any other 4xx (for example a 422 `responsible_user_unresolved`, or a
409) can clear later. The run stays queued, the loop logs a warning, and
it continues with the next run. A later recovery pass tries the run
again.
- Non-HTTP errors and 5xx errors (for example database errors) keep
propagating, as before. Startup still fails when the database or another
dependency is broken.
- If a cancel itself fails, the loop logs the error. The run stays
queued for the next recovery pass.
- `server/src/__tests__/heartbeat-queued-run-claim-isolation.test.ts`:
New embedded-Postgres tests with a mocked adapter:
- A queued-comment interrupt run with an unverifiable receipt is
cancelled, `resumeQueuedRuns()` resolves, and a second pass stays clean.
- A claimable run behind a rejected run of the same agent is claimed and
executed.
- A run with an unresolvable responsible user (422) stays queued, and
the claimable run behind it is executed.
- A rejected run for one agent does not stop the queue of another agent.

## Verification

- `cd server && npx vitest run
src/__tests__/heartbeat-queued-run-claim-isolation.test.ts` passes.
- Without the change in `heartbeat.ts`, all four tests fail (the 403
`Queued-message interrupt authority is unavailable` and the 422
`responsible_user_unresolved` escape `resumeQueuedRuns()`).
- All `heartbeat*`, `*queued*` and `run-identity` server suites pass
locally (1252/1253). The one local failure, `heartbeat-process-recovery`
"redacts opaque environment-bound credentials from Sentry diagnostics",
fails the same way on unchanged `master` on my machine and passes in CI.
- `pnpm -r typecheck`, `pnpm test:run` and `pnpm build` pass locally.

## Risks

- Behavior shift: a queued run whose claim fails with a 403 is now
cancelled, not left queued. Such a run could never start before this
change, so no runnable work is lost. The cancel reason and the
`queued_run_claim_rejected` error code make the cancel visible on the
run.
- A run with another 4xx rejection stays queued, as before, but it no
longer stops the rest of the queue. It logs a warning on each recovery
pass until the cause clears.
- Low risk otherwise: no schema, API or UI 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

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

## Checklist

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

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 10:41:17 -07:00
DottaandPaperclip 647e4adf27 fix(native): bind operator Stop to caller cancellation intent
Reserve an optional board request UUID under the run lock and retain it
through default Stop joins and native dispatch. Reject prior or competing
intents and require the same actor for idempotent retries.

Bind the Copilot denial fixture to its exact request and audited intent,
with versioned causal receipts and negative controls for earlier Stop.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 12:03:34 -05:00
DottaandPaperclip 94e8dec56b fix(runner): preserve tool outcomes through shutdown and restart (#14734)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The runner sends authorized tool calls to the server and saves their
results.
> - A provider turn can stop while a server write is still running.
> - The old shutdown path invented a failed result that could conflict
with the real result.
> - Truncated execution input and incomplete recovery records made the
failure harder to diagnose.
> - This pull request preserves exact inputs and actual outcomes through
shutdown and restart.
> - Tests force the race and crash boundaries so safe retries do not
repeat writes.

## Linked Issues or Issue Description

**What happened?**

Stopping a turn during a server tool call could record a false failure,
then reject the actual result as a conflict. The diagnostic input
formatter could truncate instruction content before execution. A crash
during saved-result delivery could leave that delivery permanently
indeterminate. Cleanup could hide the first failure, and a retry could
overwrite earlier run logs.

**Expected behavior**

Keep dispatched tools pending until their actual result is known.
Preserve accepted input bytes. Accept identical result delivery without
failing the task. Reject conflicting results with enough evidence to
diagnose them. Recover saved-result delivery without repeating the
business operation.

**Steps to reproduce**

1. Hold an instruction update at the filesystem commit barrier.
2. Stop its provider turn before the server returns the result.
3. Release the write, deliver its result, and replay the same result.
4. Repeat with a restart before and after the delivery receipt is saved.
5. Check that there is one write and one audit row, and that the exact
result survives.

**Paperclip version or commit**

The change was developed from `44736c9c7` and rebased onto `0e5830887`.

**Deployment mode**

Self-hosted server with the native runner. Tests use local runner
processes, scripted providers, and PostgreSQL.

Related work: #12353 added durable semantic tool receipts; #12384 added
durable Codex tool recovery; #12404 bound semantic tools to ACPX
sessions. #14633 covers separate native-provider cancellation and
qualification work. This PR addresses server semantic-tool outcomes and
their durable delivery. No duplicate fix was found. AgentMail discovery
is outside this PR.

## What Changed

- Close turn admission without inventing results for dispatched tools.
Keep pending calls and accept late actual results.
- Accept identical result replay with a diagnostic warning. Include call
identity and both result hashes in real conflict errors.
- Preserve exact execution arguments. Reject prohibited or oversized
input before dispatch. Keep diagnostic previews redacted and bounded.
- Commit instruction-attempt evidence before the filesystem write. Save
completed mutation receipts so concurrent and restarted duplicates
return the first result. Recheck authorization before replay. An attempt
without a completed result stays unknown and cannot execute again.
Definite pre-write failures save and replay their original error without
another write.
- Recover an interrupted saved-result delivery only for backends with
durable result receipts. Never replay an ordinary business operation
with an unknown outcome.
- Preserve the initiating error when cleanup also fails. Record
incomplete settlement evidence. Propagate typed unknown-outcome errors
through the native tool wrapper without creating a false completed tool
result.
- Append run-log attempts and restore the durable log before appending
after local file loss. Reject incomplete restores. Publish a restored
prefix only if the destination is absent so concurrent attempts cannot
overwrite new lines.
- Add deterministic race, crash, replay, authorization, exact-content,
and log-restoration tests. Document their assertions in
`packages/paperclip-runner/docs/durable-recovery.md`.

## Verification

- Current head: `7e088f4c7fba8ebabf98ae95485a5753b013d489`. All 55
applicable checks pass; four conditional/manual checks are skipped. This
includes build, typecheck, Rust, both runner TypeScript shards, server
and workspace tests, all eight browser shards, isolated runner
compilation, and the clean-install release dry run. [CI
run](https://github.com/paperclipai/paperclip/actions/runs/36746101110).
- Greptile reviewed this exact head at 5/5 with zero new findings. All
three earlier review threads are resolved.
- Focused local verification includes 11 instruction integration tests,
23 surrounding authority/tool tests, 26 run-log tests, and 169
controller/driver tests. The post-rebase controller/transport/runtime
selection passed 415 tests. The full Rust release suite passed 617 tests
with two ignored. The real-process SIGKILL recovery test passed three
consecutive runs.
- The fault matrix in
`packages/paperclip-runner/docs/durable-recovery.md` uses explicit
barriers, real PostgreSQL rollback, durable journal reloads, and killed
runner processes. It covers late results, identical and conflicting
replay, exact long content, concurrent log restoration, lost commit
acknowledgements, and definite failure replay after the original CAS
base becomes valid again. No paid model calls are needed.
- Full local recursive typecheck and build passed during implementation.
Server typecheck and the runner TypeScript build passed after the review
fixes. The broad local repository test run was stopped after repeated
database startup timeouts. Four timing/launch failures in an earlier
broad runner run passed focused reruns without changed assertions or
timeouts. These are local verification limitations; the complete
current-head CI suite is green. An earlier CI workspace job received an
infrastructure shutdown signal; its current-head replacement passed.

## Risks

- A stopped turn can remain blocked when a dispatched operation has no
proven result. The system does not guess its outcome or rerun its
effect.
- Conflicting results still fail settlement. Existing failed or
conflicting journals are not repaired automatically.
- Accepted semantic input is limited to 480 KiB of encoded JSON to fit
the encrypted transport. Larger input fails before execution.
- Instruction filesystem writes and database receipts are not one atomic
storage operation. A separately committed attempt and audit record
survive rollback. An attempt without a completed success or definite
pre-write failure receipt remains blocked as an unknown outcome. It is
not replayed or reported as success.
- Run-log restoration now reads the durable object before appending when
the local log is missing. Failed or incomplete reads reject the append.
- No schema migration, dependency change, workflow change, or AgentMail
change is included.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 11:54:56 -05:00
Nicky LeachandPaperclip af5c2d101c fix(paperclip-runner): deliver the shutdown settlement event past the terminal-turn gate (#14668)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The OpenCode driver maps provider events to runtime request events
> - A provider turn can end before a pending runtime request receives
its answer
> - The consumer reads one turn's events and stops at that turn's
terminal event
> - A settlement event that arrives after that terminal event never
reaches the consumer
> - This pull request settles the request inside its own turn, before
the terminal event
> - The benefit is reliable request settlement without weakening
late-frame protection

## Linked Issues or Issue Description

**What happened?**

A pending runtime request stayed open after an OpenCode turn failed
through `session.error`. Session shutdown then dropped its settlement
event as a late provider frame.

**Expected behavior**

The driver must deliver `runtime_request.expired` with the original
`turnId` and `itemId`, inside the same single read pass the consumer
performs on that turn.

**Steps to reproduce**

1. Start an OpenCode turn that creates a native runtime request.
2. Leave the request pending and fail the turn through `session.error`.
3. Close the session and inspect the emitted events.

**Paperclip version or commit**

`22d41c6081f05658e0d7c8485d0f22f35af4a79e`

**Deployment mode**

Built from source with the OpenCode driver test fixture.

## What Changed

- Settle a pending runtime request as soon as its own turn goes
terminal, before the terminal turn event.
- Add an optional `bypassTerminalTurnGate` parameter to the OpenCode
session emitter, and set it on the settlement emit.
- Keep a settlement loop in session close as a fallback for a request
whose turn never went terminal.
- Add a fixture trigger and a regression test that reads one turn in a
single pass.
- Keep the late provider frame gate unchanged for every provider event
path.

## Verification

- Run `pnpm vitest run
packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.test.ts`.
- Run `tsc -p tsconfig.json --noEmit` in `packages/paperclip-runner`.
- Run `tsc -p tsconfig.surfaces.json --noEmit` in
`packages/paperclip-runner`.
- Confirm that the regression test receives `runtime_request.expired`
with the original identifiers.
- Confirm that the late-frame tests still report dropped provider
frames.

## Risks

Four call sites now reach the settlement path: session close and the
three terminal turn paths (completed, cancelled, and failed). At the
three terminal turn paths the turn is still the active turn, so the gate
admits the settlement event with or without the parameter. Session close
is the only place where the parameter changes the result of the gate,
and only for a request whose turn already ended. Every provider event
path keeps the existing terminal-turn gate. The known driver test
failure is pre-existing and does not touch this change.

## Model Used

Claude Sonnet 5, with code execution and test assistance.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run the changed tests locally; the known pre-existing
failure remains documented above
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation, or no documentation change
applies
- [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 have addressed all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 09:48:14 -07:00
DottaandPaperclip 3c561642b4 fix(chat): resolve approvals and preserve unanswered questions (#14613)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Agents ask for decisions and optional details through cards in chat.
> - A clear approval in a message can leave the matching card pending.
> - An unanswered question can also block an unrelated later reply.
> - Decisions need a saved source message, while optional questions need
to remain answerable in history.
> - This pull request records conversational decisions and lets users
move on from questions and answer them later.

## Linked Issues or Issue Description

**What happened?**

Native Claude and Codex could act on approval in chat while the original
approval card stayed pending. Pending question forms stayed above the
composer, were absent from history, and could suppress later chat
replies. A late native question answer could wait for a finished run to
reconnect.

**Expected behavior**

The active agent records a clear approval or refusal against the exact
card and user message. Ambiguous replies do not grant consent. Users can
send another message without answering a question. The question remains
pending in history and can be reopened and answered later. The saved
answer reaches the agent.

**Steps to reproduce**

1. Ask an agent to propose work with a confirmation card, then approve
it in chat.
2. Check that the original card records that approval before work
starts.
3. Ask an interactive question, send an unrelated message, and reload.
4. Open the unanswered question from history and submit an answer.

Related work: #14408 added completion delivery. #14607 tests completion
reporting turns. Neither records conversational answers on approval
cards.

## What Changed

- Add a confirmation endpoint backed by a user comment, with schema
validation, OpenAPI discovery, and native Plan-mode access. Ask mode
remains read-only.
- Check company, active run, actor, current session, message provenance,
revision, and resolver policy. Save the decision and audit in one
transaction. Retries do not repeat effects. Emit resolution telemetry
after commit.
- Give fresh and resumed chat turns the actual pending confirmation
identities. Teach agents to save clear conversational decisions before
acting and to clarify ambiguity.
- Keep unanswered Agent Chat questions as compact history entries. A
newer user message closes the old form. Question cards never contribute
to composer pending counts or navigation, including after dismissing a
fresh form. The history card is the sole reminder; clicking it restores
that exact form and draft.
- Preserve Agent Chat questions when later messages or questions arrive.
Historical ordinary inputs no longer gate later chat replies.
Current-run requests, task execution, and governed approvals keep their
gates. Remove the special acknowledgement-publication proof helpers that
this rule replaces.
- Route answers to finished native runs through durable fresh-wake
delivery, with existing idempotency and source-question context. Settle
late replies against contiguous completed conversation turns and freeze
their history replay; failed, unhandled, and newly arriving messages
remain actionable.
- Add real-component Storybook scenarios, database and UI regressions,
and a three-turn native Claude/Codex E2E case. Capture distinct,
UI-ready screenshots and report the individual assertions.

## Verification

- Focused decision/publication/UI regressions after merging master: 288
passed; subsequent UI draft, failed-send, and conversation checks: 199
passed.
- Native question and durable delivery regressions: 106 passed,
including all four terminal run states and exactly-once late delivery.
Seven targeted regressions fail against the original implementation and
pass with the fix.
- Latest conversation/decision/native-delivery regressions after the
master merge: 121 passed. Covers completed progress, missing or failed
intervening turns, new messages during a late reply, stale sessions, and
frozen retry/replay boundaries. Four new assertions fail before the
ordering fix.
- E2E support suite after the master merge: 792 passed. Negative
controls reject expired cards, wrong questions/answers, stale or missing
replies, unrelated clarification forms, and unexpected tasks.
- The embedded-browser walkthrough caught one additional defect:
dismissing a fresh question still showed a composer badge. Both Cancel
and close-button regressions failed before the fix. The fix at
`65f2ade12` passes 170 chat-thread tests and 792 E2E support tests.
After merging master, 232 chat-thread/confirmation tests, server/UI
typechecks, and token gates pass. The preview and two-provider live E2E
pass at `e5512a206`; Greptile is 5/5 with zero unresolved threads at
that commit. All 55 checks are now successful at `e5512a206` (four
conditional checks skipped), including the aggregate verification gate
and clean-install canary test. The first attempt was interrupted by
simultaneous CI worker shutdowns; one failed-job rerun passed without
code changes.
- [Published
Storybook](https://d1p6rlowie26tp.cloudfront.net/storybook/branches/codex~2Fchat-approval-resolution/?path=/story/chat-comments-agent-chat-unanswered-questions--moved-on):
nine real-component scenarios. Manually exercised move on, reopen,
preserve draft, answer later, answer one of multiple questions, and a
custom mobile answer in the embedded browser. Retested fresh Cancel and
close-button dismissal in the updated build, then reopened and submitted
the preserved Green selection and inspected its answered receipt. Static
preview has no live model/backend; its callbacks are fixture responses.
- [First live
campaign](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36714504406-1/)
reproduced the late-answer completion-state defect on both providers
despite correct saved answers and acknowledgements. It also exposed a
valid imperative clarification rejected by the old oracle. Both issues
are fixed with regression controls; this failing run is retained as
evidence.
- [Four-cell
qualification](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36717804064-1/)
passed 4/4 at `2bf8a1009`: unanswered-question return and ambiguous
confirmation, each on native Claude and Codex. Inspected saved state,
source-message decisions, visible cards, and agent replies. Both
late-answer chats settled to waiting; no unrequested tasks were created.
[Final branch
rerun](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36719666238-1/)
passed 2/2 at `142630720`: the same unanswered-question journey after
merging master, plus an additional screenshot and browser assertion for
the actual late-answer acknowledgement.
- [Composer-reminder
E2E](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36727006818-1/)
passed 2/2 at `5b62c52d9`: native Claude and Codex, three turns each,
with explicit no-badge assertions before and after reload. Inspected
saved pending/answered state, both screenshots with a clear composer,
and actual Blue acknowledgements; all five behavioral matchers passed
per provider and neither created tasks. Cost coverage is partial; this
is bounded workflow qualification.
- [Fresh-dismissal
E2E](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36742773318-1/)
passed 2/2 at `e5512a206`: native Claude and Codex, including fresh
Cancel, clear composer, reopen, unrelated message, reload, late Blue
answer, and actual agent acknowledgement. All five behavioral matchers
pass per provider. Inspected the fresh-dismissal screenshots and saved
pending/answered identity; neither created tasks. Cost coverage is
partial (4/6 runs).
- Prior evidence remains available in [the earlier
campaign](https://d1p6rlowie26tp.cloudfront.net/runner-e2e/campaigns/gha-36642252725-1/).
Its early loading screenshot and overwritten final capture prompted the
UI-ready, distinct screenshot fixes.

## Risks

- The model interprets intent. The server verifies permission and
provenance; it does not infer consent from text. Ambiguous and unrelated
replies are not approvals.
- Historical questions can accumulate. They remain visible, pending, and
answerable; no automatic answer or expiry is invented.
- The change to completion gates is scoped to Agent Chat and ordinary
historical inputs. Current-turn and governed approvals retain their
existing controls.
- Live qualification is limited to the selected stories. Broader native
onboarding finalization remains separate work.
- No database migration. Telemetry adds no fields or values; the
contract and README document the commit boundary. Privacy review was
requested on the PR.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-30 11:46:46 -05:00
Dotta 22ded968dd docs(runner): correct denial settlement evidence limits 2026-09-30 11:33:55 -05:00
DottaandPaperclip 8040aa903c test(runner-e2e): reject coerced observation clock fields
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 11:33:41 -05:00
DottaandPaperclip eecd64509a fix(runner-e2e): require causal pre-Stop denial observations
Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 11:33:41 -05:00