verify_expression strings that satisfy the gate correctly.
The Three Reversibility Tiers
Every action schema carries areversibility field set when the action is discovered from the target application’s runtime. The daemon reads this field and applies the corresponding tier rules before touching the probe.
read — No state change
read — No state change
A
read action retrieves data without modifying any application state. There is no confidence gate and no verification requirement. You can call read actions at any time, regardless of the probe’s current confidence score.Confidence required: Noneverify_expression required: NoExamples: get_thread, search, list_contacts, read_document, get_calendar_eventsIf you call a read action and the probe is still initializing (confidence below 0.40), the daemon returns a 503 confidence_too_low error. This is not a safety gate — it is simply the probe not being ready yet.reversible_write — Undoable change
reversible_write — Undoable change
A
reversible_write action modifies application state in a way that can be undone — for example, archiving an email (which can be unarchived), adding a label (which can be removed), or creating a draft (which can be deleted).Confidence required: >= 0.80verify_expression required: No (optional but recommended for critical workflows)Examples: archive, label, move_to_folder, mark_read, star, create_draftIf the probe’s confidence is below 0.80 when you dispatch a reversible_write action, the daemon rejects the request immediately with 503 confidence_too_low. Wait for the probe to reach a higher confidence before retrying — this usually resolves within a few poll cycles.irreversible_write — Permanent change
irreversible_write — Permanent change
An
irreversible_write action causes a side effect that cannot be undone: sending an email, permanently deleting a record, submitting a purchase, sending a message, or submitting a form.Confidence required: >= 0.95verify_expression required: Yes — the daemon rejects the request with 400 missing_verify_expression if you omit itExamples: send_reply, delete_permanently, purchase, submit_form, send_messageThe verify_expression is evaluated against the post-action state. If the expression evaluates to true, the daemon returns a 200 success response. If it evaluates to false — or if the timeout elapses before it becomes true — the daemon returns 422 verification_failed. The action has already executed at this point, so design your expressions to confirm a durable state change, not just that the action ran.The Irreversible Write Gate
When you callPOST /action with an irreversible_write action, the daemon enforces the gate synchronously before dispatching. A request missing verify_expression is rejected outright — the action does not execute.
Rejected request — missing verify_expression:
verify_expression present:
Dangerous Name Heuristic
As an additional safety layer, the daemon inspects the action name itself before dispatching — even when averify_expression is present. If the action name contains any of the following substrings, the daemon treats the action as potentially irreversible and requires a verify_expression regardless of the schema’s declared reversibility tier:
delete · destroy · purge · wipe · reset · clear_all · terminate · shutdown · kill
This heuristic catches cases where an action’s schema metadata may not yet be available — for example, when the PID cannot be resolved and the daemon cannot look up the action schema. In that situation, an action named delete_attachment or purge_queue would be rejected with 400 dangerous_action_unverified unless a verify_expression accompanies the request.
The dangerous name heuristic is a fallback, not a substitute for correct schema metadata. If you author custom action schemas, set the
reversibility field accurately. The heuristic only fires when schema lookup fails or the name pattern matches.Writing verify_expression Strings
A verify_expression is a JavaScript-like expression evaluated against the post-action SubstrateState. It must return a boolean. The daemon polls the state until the expression returns true or the verify_timeout_ms deadline passes.
Supported Operators
Expression Examples
verify_timeout_ms
The verify_timeout_ms field controls how long the daemon polls the post-action state waiting for your expression to return true. The valid range is 100–30000 ms, and the default is 5000 ms (5 seconds).
Choose a timeout that reflects the real latency of the state change you are verifying:
- For UI changes that are visible within milliseconds,
1000–2000ms is plenty. - For operations that trigger server-side writes (sending an email, submitting a form), use
5000–10000ms. - For long-running background operations, go up to
30000ms — but consider whether a separate polling loop is a better pattern for your use case.
Python SDK Enforcement
The Python SDK enforces the irreversible write contract at the client level, before the request is even sent. If you callsession.execute() on an irreversible_write action with verify=False, the SDK raises NSPIrreversibleNotConfirmedError locally — no network request is made.
Verification Failure Response
If the action executes but the post-action state never satisfies yourverify_expression before the timeout, the daemon returns a 422 verification_failed response:
