Files
PaperClipAI/tests
DottaandClaude 5ab98b0063 test(restart-chaos): add database contention workload and universal checks U1-U4 (#20421)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The restart chaos harness (`tests/restart-chaos/`) runs real agent
tasks on an isolated control plane and grades them.
> - Two production failures on 2026-11-09 passed the harness. Its tasks
made little output and little accounting, so database write contention
never happened (#20385). Its grading was per workload, so a task stuck
for a reason no scenario targeted was not caught (#20361).
> - The harness needs a contention workload and checks that apply to
every task.
> - This pull request adds the L1 workload, a `--db-pressure` knob, and
the universal checks U1–U4.
> - The benefit is that the #20385 failure class and unexplained stuck
or misleading tasks now fail a wave.

## Linked Issues or Issue Description

Refs #20385, #20383, #20361.

**What happened?**

The harness ran real embedded PostgreSQL, but no task streamed enough
run-log output while usage receipts committed. The #20385 receipt race
(SQLSTATE 40001, retained outbox, `native_event_replay_conflict`) could
not occur. Also, no rule checked every task for an owner or an
actionable item, for retry loops, for diagnosable failures, or for stale
notices.

**Expected behavior**

A chaos wave can create run-row contention between run-log writes and
accounting writes and check that accounting stays exact. Every task of
every wave gets scenario-independent liveness and notice checks.

**Steps to reproduce**

Run an L1 wave with `--db-pressure 4` against the parent of the #20385
merge (red), then against master (green). Commands are in Verification.

## What Changed

- `contention.ts` (new): workload L1 (five 3,000-line shell outputs as
five tool calls, then a brief), its accounting oracle, and
`RunRowPressure`, the `--db-pressure <writers>` knob. The writers run
`update heartbeat_runs set updated_at = updated_at` on the wave
company's running runs, in the wave's own isolated database only.
- L1 oracle: no `native_event_replay_conflict` or
`runner_event_commit_stalled`; each producer event journaled once; a
terminal receipt for each succeeded native run; finished runs accounted;
per-run cost equals its cost events; the board's spend equals the
cost-event sum with no runs pending accounting; and proof that the task
produced contention.
- `universal.ts` (new): U1 liveness, U2 no silent retry loop, U3
diagnosable failures, U4 no stale notices. `grader.ts` grades them on
every task. U1, U2 and U4 fail a task. U3 is a warning.
- `invariants.ts`: `readUniversalDbEvidence` reads failed-run error text
and recovery-action causes from the wave database at wave end, for U3.
- `universal-audit.ts` (new): runs U1–U4 over saved wave evidence to
measure false positives and bound headroom.
- `contention-db.test.ts` (new): on real PostgreSQL, under the pressure
writers, the pre-#20385 repeatable-read receipt write exhausts its
retries with 40001 and the current writer commits.
- Small registry edits: `types.ts` (L1 id, `dbPressure`, optional
`contention` and `universal` fields), `workloads.ts` (L1 entry),
`config.ts` (`--db-pressure`, L1 not a default), `main.ts` (start and
stop the writers, read database evidence before teardown), `ledger.ts`
(universal verdicts and warnings in the ledger and `SUMMARY.md`).
- README: "Database contention" and "Universal checks" sections, with
the audit table and bound reasons.

## Verification

- `contention-db.test.ts` (real embedded PostgreSQL): with
`--db-pressure` writers (4), the pre-#20385 repeatable-read receipt
write exhausted its retries with 40001 in 8 of 8 attempts; the current
READ COMMITTED `persistUsageReceipt` committed 8 of 8. This is the
harness-level red/green for #20385.
- Live L1 waves (`--env local --adapters codex,claude --workloads L1
--faults K1 --concurrency 4 --tasks 4 --seed 20385 --db-pressure 4`),
red on the #20385 parent `bf818280f2` with this harness overlaid and
green on this branch: queued behind the shared one-wave-at-a-time lock
and not yet run. The first red attempt failed at startup (the fresh
checkout lacked a built plugin SDK; no tasks ran). Live results are not
claimed here.

- `pnpm exec vitest run --config tests/restart-chaos/vitest.config.ts`:
all harness unit tests pass, including the new `universal.test.ts`,
`contention.test.ts` and `contention-db.test.ts`.
- `node scripts/typecheck-test-projects.mjs tests/restart-chaos`:
passes.
- Universal-check audit over 74 saved waves (1,592 tasks): U1 7 flags
(one C1 stall and six R1 runs queued 8 min behind a retry row, the
#20361 shape), U2 1, U3 22, U4 0. None of U1, U2 or U4 flags a passing
task or an all-pass wave. U3 flags 3 passing tasks (all
`adapter_failed`), so it ships as a warning.

## Risks

- U1, U2 and U4 can now fail a task that passed R1–R6 and T. The audit
found no such case in 70 saved waves. The bounds are
environment-configurable.
- `--db-pressure` is opt-in and writes no values. It writes only to the
wave's own temporary database.
- Other agents edit the same harness. This change keeps registry edits
small; `grader.ts` and `invariants.ts` changes are additive.
- No product code changes.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used through Claude
Code with tool use (shell, file editing, GitHub CLI).

## Checklist

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

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-11-09 22:02:57 -06:00
..