Commit Graph
3 Commits
Author SHA1 Message Date
DottaandPaperclip 9966f31bee fix(chat): keep permission failures scoped to the rejected operation (#16847)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - External channels deliver agent replies through a durable
publication queue.
> - A provider can reject one operation while other operations remain
allowed.
> - The shared error classifier treated generic 403 and permission
errors as failures of the whole connection.
> - Failure handlers then changed the user's enabled setting and removed
all assigned channel tools.
> - This pull request limits permission failures to the rejected
operation and preserves connection intent during authentication
failures.
> - Unrelated work can continue, while confirmed authentication failures
still stop endpoint traffic.

## Linked Issues or Issue Description

Refs #16137. Follows #16138, which distinguishes local authorization
errors from provider errors. This change also narrows provider
permission failures. Related #16806 handles a separate task-continuation
tool-binding defect.

A provider 403 or missing-scope response currently disables a connection
that may still support other operations. The expected behavior is a
visible operation failure with unrelated work preserved. Confirmed
authentication failures must stop sends without changing the user's
enabled setting.

## What Changed

- Classify generic 403, adapter permission errors, and Slack
missing-scope/no-permission responses as failed operations.
- Preserve rate-limit retries, known destination quarantine, and
confirmed authentication failures.
- Preserve connection status and enabled intent when publication,
provider-reply, or form-open authentication fails. The endpoint still
enters attention and its runtime stops.
- Add GitHub regressions for retained discovery and successful later
publication after 403, and no further sends after 401.
- Mark authentication health failed and fence persistent receiver
startup, background reconciliation, and receiver callbacks. Keep signed
GitHub lifecycle events available during an authentication stop. Verify
Discord reconciliation and Photon restart preserve the stop, while
transient Discord disconnects still recover.
- Update provider, publication, and modal regression expectations and
the execution contract and verification maps.

## Verification

- Red: five new classifier cases returned endpoint attention before the
repair. The signed-installation-removal regression also reproduced a
blocked lifecycle event after a 401 before narrowing the receiver guard.
- Green: all 35 classifier tests pass.
- Green: 19 PostgreSQL-backed cases pass through the production channel
services, including GitHub discovery/publication, Slack provider replies
and question modals, Telegram credential/destination failures, rate
limiting, and Discord/Photon authentication-stop persistence.
- Map structural checks and `git diff --check` pass.
- `pnpm -r typecheck` and `pnpm build` pass. All CI gates are green on
`7e379bcd98aa8363e42efe7f8a4b2589b7111ae6`; Greptile is 5/5 on that
exact commit with no unresolved findings.
- The monolithic local `pnpm test:run` was started, then stopped after
its revision passed the full CI matrix and was superseded by the
authentication-stop repair. Final full-suite verification passed in CI
shards; all 19 final local provider regressions pass.
- The tests run from this source checkout on macOS arm64 with isolated
PostgreSQL and controlled provider failures. They do not prove live
GitHub recovery or deployment. No live connection settings were changed.

## Risks

- Permission failures now leave unrelated work available. The rejected
operation remains failed and is not automatically replayed. Provider
authorization still applies to every request.
- Keeping a connection enabled must not bypass an authentication stop.
GitHub verifies blocked tool discovery and later sends; Discord and
Photon verify background reconciliation and restart cannot clear the
stop. Failed connection health is an execution gate while the endpoint
requires attention.
- Explicit disable, disconnect, signed installation revocation, and
existing destination-specific denial handling remain unchanged. No
migration or API schema change is required.
- Previously disabled connections are not automatically re-enabled
because an upgrade cannot safely infer the user's intent.

## Model Used

- OpenAI Codex, GPT-6 family. The runtime does not expose the exact
deployment model ID or context-window size. Used reasoning, shell tools,
repository edits, 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-10-19 09:54:22 -05:00
Naeem Akhtar 0ed760ce9a fix(server): keep local authorization failures from disabling chat endpoints (#16138)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Chat endpoints publish agent replies to providers such as GitHub,
and a durable outbox classifies each send failure
> - A GitHub review run that fails posts a "review failed" reply. When
the run has no request binding, Paperclip throws its own `forbidden()`
before any GitHub request
> - The classifier reads that local 403 as a provider credential
failure. The endpoint goes to `attention`, its tool connection is
disabled, and new `pull_request` webhooks are dropped
> - One failed review can stop all reviews on that endpoint until an
operator reconnects it
> - This pull request classifies Paperclip's own 401/403 `HttpError`
without a provider status as a failure of that publication only
> - The benefit is that only real provider credential failures lock an
endpoint

## Linked Issues or Issue Description

Fixes: #16137

## What Changed

- `server/src/services/chat-publication-errors.ts`: an `HttpError`
(Paperclip's own class) with status 401 or 403 and no numeric
`details.providerStatus` returns `{ kind: "failed" }`. The check runs
before the credential branch.
- Provider errors do not change. Adapter
`AuthenticationError`/`PermissionError`, Octokit errors (named
`HttpError`, but not this class) and Paperclip-wrapped provider
rejections that carry `providerStatus` still return
`endpoint_attention`.
- `server/src/services/chat-publication-errors.test.ts`: a new test
covers a local `forbidden()`, a local `unauthorized()` and a wrapped
provider 403.

## Verification

- `pnpm --filter @paperclipai/server vitest run
src/services/chat-publication-errors.test.ts`
- I ran the classifier source with type stripping on Node 22: local
`forbidden("GitHub failure has no request binding")` → `failed`; local
`unauthorized()` → `failed`; `new HttpError(403, …, { providerStatus:
403 })` → `endpoint_attention`; an Octokit-shaped 403 →
`endpoint_attention`.
- I applied the same change to the built `dist` of a self-hosted install
and called its classifier with the same four errors. The results were
the same.

## Risks

- Low risk. The change applies only to Paperclip's own `HttpError` with
status 401/403 and no provider status. Such an error now fails one
publication and does not disable the endpoint. Code that throws a local
401/403 to report a provider credential problem must attach
`providerStatus`. I found no such caller in `server/src/services`.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`, Anthropic), in Claude Code with
tool use (shell, file edits, test runs). It helped to find the cause,
write the change and the test, and run the checks.

## 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 (classifier checked with
type stripping; the full vitest suite runs in CI)
- [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
2026-10-19 08:57:18 -05:00
DottaandPaperclip 6abeb67334 feat: add opt-in chat provider and data foundation (#13100)
Add dormant provider contracts, qualified patched adapters, tenant-scoped persistence and lifecycle ownership without activating chat routes. Preserve the experimental integration as dependent PR #13038.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-09 13:49:12 -05:00