From f87db64ba9a79770252563e78cc5585ae5090bd7 Mon Sep 17 00:00:00 2001 From: Aron Prins Date: Mon, 23 Mar 2026 10:21:34 +0100 Subject: [PATCH] docs(api/routines): address three review findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **#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 --- docs/api/routines.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/api/routines.md b/docs/api/routines.md index f685f6ba..eb6b9adc 100644 --- a/docs/api/routines.md +++ b/docs/api/routines.md @@ -45,6 +45,7 @@ Fields: | Field | Required | Description | |-------|----------|-------------| | `title` | yes | Routine name | +| `description` | no | Human-readable description of the routine | | `assigneeAgentId` | yes | Agent who receives each run | | `projectId` | yes | Project this routine belongs to | | `goalId` | no | Goal to link runs to | @@ -58,9 +59,9 @@ Fields: | Value | Behaviour | |-------|-----------| -| `coalesce_if_active` (default) | Skip the new run if one is already in progress | -| `skip_if_active` | Same as coalesce but without queuing | -| `always_enqueue` | Always enqueue, regardless of active runs | +| `coalesce_if_active` (default) | Incoming run is immediately finalised as `coalesced` and linked to the active run — no new issue is created | +| `skip_if_active` | Incoming run is immediately finalised as `skipped` and linked to the active run — no new issue is created | +| `always_enqueue` | Always create a new run regardless of active runs | **Catch-up policies:** @@ -150,6 +151,7 @@ Generates a new signing secret for webhook triggers. The previous secret is imme POST /api/routines/{routineId}/run { "source": "manual", + "triggerId": "{triggerId}", "payload": { "context": "..." }, "idempotencyKey": "my-unique-key" } @@ -157,6 +159,8 @@ POST /api/routines/{routineId}/run Fires a run immediately, bypassing the schedule. Concurrency policy still applies. +`triggerId` is optional. When supplied, the server validates the trigger belongs to this routine (`403`) and is enabled (`409`), then records the run against that trigger and updates its `lastFiredAt`. Omit it for a generic manual run with no trigger attribution. + ## Fire Public Trigger ```