--- id: INT-5 family: RT-INT level: core profiles: [runtime] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/rt-int/int-5 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # INT-5 — Cancel and pause signals are observed between job iterations *RT-INT (Part II) · level: core · profiles: runtime · added in 1.0* A signal never interrupts a job mid-flight. It is observed at the boundary between iterations, which is why a cancelled run has no half-executed node. ## The rule > **Normative.** This is the rule. > > 1. An engine polls for a pending signal between job iterations; the in-flight job always finishes first, and the absence of a signal continues the loop. > > 2. A cancel signal marks the run cancelled, stamps its execution time, and announces the outcome twice: a cancellation event and a run-completed announcement carrying the cancelled status, so that cancellation is announced like any other terminal outcome (ORC-15). > > 3. It then answers with status `cancelled` and metadata naming the engine, the signal and the reason. > > 4. A pause signal pauses the run and announces only the pause, with no completion announcement, answers with status `paused` and the same metadata keys, and leaves the signal record pending, because that record is the run's resume key. ## What it means A cancel and a pause are both observed only at the boundary between job iterations, never mid-node — the job already running always finishes first. Past that boundary the two diverge in a way that is easy to get backwards. Cancel is terminal: it announces the cancellation itself, and separately announces the run as complete (carrying the cancelled status), because anything that only listens for completion — a session closing out, a parent run waiting on this one — must hear that the run is over. Pause is not terminal: it announces only the pause, and nothing tells a completion listener the run has ended, because it has not. The signal a pause left behind stays exactly as it was, because that record is the same one a later resolution resumes against (INT-3). ## Example The same kind of poll, answered with a cancel and with a pause. ```json title="A run answering a pending cancel" verdict="cancelled" { "status": "cancelled", "metadata": { "signal_id": "signal-1", "reason": "operator stopped the run" } } ``` ```json title="The same run, answering a pending pause instead" verdict="paused" { "status": "paused", "metadata": { "signal_id": "signal-1" } } ``` Only the cancel is followed by a second, completion announcement; the pause produces exactly one. ## Related rules - Names: INT-17, ORC-15 - Referenced by: INT-16, INT-17 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.