Confirmation gate (dry run)
When a machine calls a destructive command without confirm, it doesn't execute — only the affected count comes back.
await oniyanma.execute('deleteSelection'){
"preview": true,
"command": "deleteSelection",
"wouldAffect": {
"points": 128340,
"note": "count on a resident (currently on-screen LOD sample) basis"
},
"note": "Not executed. To run this, call again with the same arguments plus confirm:true (undoable, but while collaborating it applies to every participant's screen immediately)"
}If the count looks right, call again with confirm: true added to the same arguments.
await oniyanma.execute('deleteSelection', { confirm: true }) // → { ok: true }Which commands this applies to
| Command | What the dry run returns |
|---|---|
hideSelection | Selected point count (resident-based) |
deleteSelection | Same |
reclassifySelection | Same |
colorSelection | Same |
clearEdits | Edit count + "other participants' edits are cleared too while collaborating" |
deleteFinding | Finding count + "the record stays and can be restored even after withdrawal" |
revertBatch | The count of batches that would revert (applied state). A batch made by someone else can't be reverted |
When there's no selection, it doesn't just end with "0" — it returns a reason, like { points: 0, note: 'No selection (select something first)' }. Zero and "you haven't selected anything at all" call for a different next move from an agent's point of view.
Who this applies to
| Actor | Gate |
|---|---|
ai — the AI console | Applies |
api — via window.oniyanma / MCP | Applies |
human — UI buttons / ⌘K / shortcuts | Doesn't apply |
A human sees the result of their own action on screen, so a second confirmation is only noise. A machine can move on to the next call without seeing the result, so it's stopped once here.
The exception is "Clear all edits" — since it clears other people's edits too while collaborating, the UI side also shows a confirmation dialog with the count.
There's another, different gate too
acceptBatch / confirmFinding / rejectFinding can't be executed from a machine even with confirm:true (the human-only gate). The dry run is "stop once and ask for confirmation"; this other one is a different, stronger gate — "a machine simply isn't permitted to do this at all".
Why this lives in the command layer, not the prompt
You could write "please confirm before a destructive operation" into the system prompt. It's actually written there too. But that alone is not a defense layer.
- Behavior changes with the model
- Instructions dilute over a long conversation
- Prompt injection can override it
- A path called directly from
window.oniyanmaor MCP has no prompt in the loop at all
Holding confirmation as structure in the command layer (the dryRun flag in registry.ts) means it always stops once, no matter which path it's called from or which model is behind it. Whoever adds a command just writes dryRun, and it applies across every path.
How to read the count
wouldAffect.points is resident-based — the count within the LOD sample currently on screen. It's not a scan of every point in the source. It grows as you move closer.
Treat it not as an exact "how many points are in this range" but as a number for confirming the order of magnitude of what would disappear if you ran it now. → reference overview
Evaluation
Whether the model can go through the two steps — "preview the count → confirm: true" — is measured as the eval set's guarded tier (13 cases). The decision to downgrade a model is made by looking at this pass rate.