Skip to content

Stopping a call

A rule carries a mode, and the mode is the only thing that changes between watching a run and stopping it. deny is the one to reach for first: the call is refused, and the reason goes back where the tool’s output would have gone.

const SEC_01 = Presets.requireBefore('restartService', 'queryMetrics', {
id: 'SEC-01',
description: 'restartService may not run before queryMetrics has returned',
mode: 'deny',
})

Instead of the tool’s result, an object it can read:

{
"blocked": true,
"message": "blocked by SEC-01: restartService may not run before queryMetrics has returned",
"violations": [{ "ruleId": "SEC-01", "seq": 0, "subformula": "O toolResult(queryMetrics)" }]
}

A model reads that, does the work the rule was asking for, and tries again. This is why deny composes with an agent in a way that throwing does not: an exception ends the run, while a refusal is information.

Event 0. The responder reached for restartService first — the red dashed path is the call that never happened. queryMetrics is what it did instead, after reading why it was stopped. Step forward with the transport to watch the restart succeed on the second attempt.

Look at the transport in that run: seven events, and none of them is the refused restartService. A call that was refused never happened, so there is nothing to record — the only evidence is the decision the guard made, which is what the red path is drawn from.

That is worth holding onto, because it has a consequence for verifying a rule set: a run recorded while a rule was enforcing has nothing left in it for that rule to catch.

The agent could reasonably do something else instead deny — this page
A person has to decide, and might take a while suspend
The rule is new and has to earn trust observe
Nothing downstream should happen and nobody will be asked abort, covered in enforcement