mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 07:10:34 +01:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The control plane must keep tasks moving when the server restarts > - The restart chaos harness (#19477) kills the server only at a random time after a task starts > - Many restart bugs depend on what the user or the run was doing at that moment: a comment just sent, a Retry just clicked, a run still queued, a long tool call, or a second crash during startup recovery > - The harness cannot aim at these moments yet, so these cases occur only by chance > - This pull request adds fault triggers that fire relative to a user action or a run state, and the K6 crash loop > - The benefit is that chaos waves can target these boundaries on purpose and replay them ## Linked Issues or Issue Description Refs #19477 **What is the problem?** The restart chaos harness fires each fault at a seeded random offset from task launch. It cannot fire a fault right after the harness posts a comment to an active run, right after a Retry click, while a run is queued, during a long tool call, or a second time while the server is in the `recovering` startup phase. **Why is it a problem?** These are the boundaries where restart bugs hide (plan faults K6 and K8, boundaries B1, B6 and B8). Random timing seldom hits them, and a replay cannot repeat them. **What is the proposed solution?** Add a `--triggers` option. Each task samples a trigger with its cell. The observer arms the fault when the trigger condition holds, then fires it after a seeded delay. Add the K6 crash-loop fault to the supervisor. ## What Changed - `types.ts`, `config.ts`: add `TRIGGER_IDS` (`time`, `comment`, `retry`, `queued`, `tool`), the `--triggers` option, and the `K6` fault kind. - `scheduler.ts`: sample a trigger per task. `comment` pairs only with C1 and `tool` only with B5. Each trigger has a seeded delay range. `retry` adds an extra K1 after the planned fault. A replay re-arms the task's own triggered faults. - `observer.ts`: arm each triggered fault from the observed state: the follow-up reached a running run, an accepted Retry, the first run still queued, or the first `bench.sh` progress. A trigger that can no longer hold is recorded as `triggerMissed`. - `supervisor.ts`: K6 kills the replacement again as soon as `/api/ready` reports `recovering` (or `ready`, if recovery was too fast to see), then once more just after `ready`. The receipt records the phase that each kill hit. - `main.ts`, `ledger.ts`: pass the trigger to the fault receipt, the timeline and the ledger. The summary shows the trigger in each cell. - `triggers.test.ts`: unit tests for planning, firing, misses, replay and the crash-loop phase rule. - `README.md`: document the triggers and K6. ## Verification - `pnpm exec vitest run --config tests/restart-chaos/vitest.config.ts` (52 tests pass). - `node scripts/typecheck-test-projects.mjs tests/restart-chaos` passes. - Live: `node cli/node_modules/tsx/dist/cli.mjs tests/restart-chaos/main.ts --env local --adapters codex,claude,opencode --faults K1,K6 --triggers comment,retry,queued,tool --concurrency 3 --tasks 6` runs waves with the new triggers. ## Risks - Low risk. The change is in the test harness only. The default trigger is `time`, so existing waves and replays keep their behavior. - A trigger can miss its window (for example, a run starts before the first poll). The ledger records the miss, so the task is not counted as a crossing of that boundary. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with tool use (shell, file edits). ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>