FlowDrop Workflow Specification 1.0-draft

A shipped side-effecting node type states its policy

"Has side effects" and "an operator should approve this" are two different questions that happen to coincide for an outbound call and diverge for a memory write. Leaving a shipped node type undecided delegates a governance decision to a fail-safe.

The rule

Normative: this is the rule
  1. Every node type an implementation ships whose executor declares that it has side effects must declare its confirmation policy explicitly, rather than leaving the requirement to be derived (RT-GATE-7).
  2. The derivation reads "mutates persistent state" as "performs an action an operator should approve", which is not the same question.
  3. A shipped declaration should be ask where the effect leaves the implementation's own boundary and skip where it does not.
  4. Where an implementation delivers such declarations to sites that already exist, it must write a policy only where none is stored: an administrator's own choice, a narrowed list of allowed controls, and a value still awaiting migration must all survive untouched.

What it means

"Mutates persistent state" and "an operator should approve this" are two different questions, and a node type that ships without an answer is not defaulting to a neutral position — it is letting the gate's own fail-safe answer a governance question nobody actually decided. The two questions happen to agree for a call that leaves the implementation's own boundary, which is exactly why it is easy to assume they always agree.

Once a shipped type has an answer, delivering it to a site that already exists is one-directional. The pass may fill in a policy that was never stored, but it must recognise every other shape as somebody's answer already: a stored policy, a narrowed list of controls with no policy yet, and an older tri-state waiting for a separate migration to translate all count, and none of them may be replaced by the shipped default.

Example

A confirmation mapping records a policy alongside which controls stay available. Left undecided, filling it in from what the type ships looks like this:

A node type's confirmation mapping, undecidedundecided
{ "policy": null, "authorControls": ["waive", "require"], "dynamicControls": [] }
The same mapping once the shipped policy is deliveredskip
{ "policy": "skip", "authorControls": ["waive", "require"], "dynamicControls": [] }

Where a policy was already stored, the same delivery finds nothing undecided to fill in — even on a node type whose shipped default disagrees with it:

An administrator's own choice, on a type shipped with skipuntouched
{ "policy": "ask", "authorControls": [], "dynamicControls": [] }
Rule identifiers are permanent and are never renumbered. Each implementation publishes its own standing against these rules; this specification does not.spec 1.0-draft · RT-GATE-15 · changed in spec 1.0