Files
PaperClipAI/server/src/__tests__
DottaandPaperclip 67948173f4 fix(sentry): report saved-message task attempt failures (#18541)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Tasks retain user messages when an execution attempt cannot finish.
> - The task interruption projection drives the saved-message failure
notice.
> - That state can occur without a new terminal run transition, which
the existing Sentry reporter requires.
> - This pull request reports that failed task state through the
existing Sentry capture path.
> - Operators can find the failure through the same tag and saved run
links.

## Linked Issues or Issue Description

Refs #13446 and #16300. The related PR search found no open
implementation of this change.

**What happened?**

A task can show “Couldn’t finish this attempt. Your message is saved.”
without a matching run-failure Sentry event. A stale saved-message wait
can produce this state after the previous run succeeded.

**Expected behavior**

When run-failure reporting is enabled, this failed task state also
reports with `event_kind=run_failure`.

**Steps to reproduce**

1. Enable the backend Sentry DSN and
`PAPERCLIP_SENTRY_RUN_FAILURES=unexpected` or `all`.
2. Leave a saved-message wait on an unfinished task after its last run
has ended.
3. Read the task after the wait grace period expires.
4. The task shows the failure notice. Before this change, that read does
not report it to Sentry.

**Paperclip version or commit**

Base commit: `e122478368`.

## What Changed

- Report the system-owned failed presentation from the existing batch
task reader. The pure projection remains unchanged.
- Reuse `captureRunFailure()` with `event_kind=run_failure`,
`failure_source=task_interruption`, and
`error_code=task_attempt_failed`.
- Preserve the actual saved run status and company, agent, task and run
references. Load the run agent's adapter through a company-scoped join
in the existing run query, including after reassignment. Add no database
query or background timer.
- Send fixed error text. Do not read chat bodies, prompts or raw run
diagnostics for this event.
- Suppress repeated reports for the same company/task/run/intent with a
bounded process-local cache. Failed or disabled captures do not consume
the report.
- Document the enabled modes, event fields, duplicate behavior and cache
limits.

## Verification

- Regression before implementation: the two new Sentry tests failed
because the capture entry point was absent; the existing 38 Sentry tests
passed.
- Focused verification: 332 tests passed across
`run-failure-sentry.test.ts`, `task-interruption-query.test.ts`,
`task-interruption-presentation.test.ts`, and
`run-failure-report.test.ts`. The reassignment regression first
reproduced the missing adapter, then passed after the query correction.
- Command: `PAPERCLIP_TEST_POSTGRES_ADMIN_URL=<local-test-admin-url>
pnpm exec vitest run server/src/__tests__/run-failure-sentry.test.ts
server/src/__tests__/task-interruption-query.test.ts
server/src/services/task-interruption-presentation.test.ts
server/src/services/__tests__/run-failure-report.test.ts`.
- PostgreSQL tests used isolated databases on a local PostgreSQL 17
server, with automatic cleanup. Initial embedded starts failed because
installation scripts had not restored library links; after repair, the
host semaphore limit prevented new clusters. The existing
external-database helper supplied the working test path.
- `pnpm -r typecheck` passed.
- `pnpm build` passed.
- `git diff --check` passed.
- `pnpm test:run` was attempted. It stopped in the unchanged chat
integration shard collection step with “No test found” for line filters.
The complete local suite has not passed.
- Sentry capture assertions use the SDK test double. Live Sentry
ingestion and a deployed browser journey were not tested.

## Risks

- An enabled instance can send more Sentry events when task reads
discover retained failures. It can emit a task-state event alongside the
separate terminal run event. The source tag distinguishes them.
- Deduplication is process-local and retains 1,000 reports. Restarts,
multiple replicas or cache eviction can report a retained failure again.
- No schema, permission, execution or UI changes. The existing opt-in
reporting gate stays in place.

## Model Used

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

## Checklist

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

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-11-02 08:17:22 -06:00
..
…

Server Tests

Server tests that need a real PostgreSQL process must use ./helpers/embedded-postgres.ts instead of constructing embedded-postgres directly.

The shared helper creates a throwaway data directory and a reserved-safe loopback port for each test database. This protects the live Paperclip control-plane Postgres from server vitest runs; see PAP-2033 for the incident that introduced this guard.