**#1 — Missing `description` field in fields table**
The create body example included `description` and the schema confirms
`description: z.string().optional().nullable()`, but the reference table
omitted it. Added as an optional field.
**#2 — Concurrency policy descriptions were inaccurate**
Original docs described both `coalesce_if_active` and `skip_if_active` as
variants of "skip", which was wrong. Source-verified against
`server/src/services/routines.ts` (dispatchRoutineRun, line 568):
const status = concurrencyPolicy === "skip_if_active" ? "skipped" : "coalesced";
Both policies write identical DB state (same linkedIssueId and
coalescedIntoRunId); the only difference is the run status value.
Descriptions now reflect this: both finalise the incoming run immediately
and link it to the active run — no new issue is created in either case.
Note: the reviewer's suggestion that `coalesce_if_active` "extends or
notifies" the active run was also not supported by the code; corrected
accordingly.
**#3 — `triggerId` undocumented in Manual Run**
`runRoutineSchema` accepts `triggerId` and the service genuinely uses it
(routines.ts:1029–1034): fetches the trigger, enforces that it belongs to
the routine (403) and is enabled (409), then passes it to dispatchRoutineRun
which records the run against the trigger and updates its `lastFiredAt`.
Added `triggerId` to the example body and documented all three behaviours.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Routines are recurring tasks that fire on a schedule, webhook, or API
call and create a heartbeat run for the assigned agent. Document the
full CRUD surface including:
- List / get routines
- Create with concurrency and catch-up policy options
- Add schedule, webhook, and api triggers
- Update / delete triggers, rotate webhook secrets
- Manual run and public trigger fire
- List run history
- Agent access rules (agents can only manage own routines)
- Routine lifecycle (active → paused → archived)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix goals-and-projects.md: `completed` is not a valid status — correct to
`achieved` and document all valid values (planned/active/achieved/cancelled)
- Fix issues.md: document that `expectedStatuses: ["in_progress"]` can be used
to re-claim a stale lock after a crashed run; clarify that `runId` in the
request body is not accepted (run ID comes from X-Paperclip-Run-Id header only)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Merge pr-verify.yml, pr-policy.yml, and pr-e2e.yml into a single
pr.yml with three parallel jobs (policy, verify, e2e). Benefits:
- Single concurrency group cancels all jobs on new push
- Consistent Node 24 across all jobs
- One file to maintain instead of three
The jobs still run independently (no artifact sharing) since pnpm
cache makes install fast and the upload/download overhead for
node_modules would negate the savings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align with e2e.yml and ensure CI tests exactly the committed
dependency tree. The pr-policy job already blocks lockfile changes
in PRs, so frozen-lockfile is safe here.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The playwright.config.ts had `reuseExistingServer: !!process.env.CI`
which meant CI would reuse (expect) an existing server while local
dev would start one. This is backwards — in CI Playwright should
manage the server, and in local dev you likely already have one
running.
Flip to `!process.env.CI` and remove the `CI: ""` env override
from the workflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>