|
| 1 | +--- |
| 2 | +"@objectstack/spec": patch |
| 3 | +--- |
| 4 | + |
| 5 | +fix(spec): the three shipped confirmation-gate prescriptions state the gate in the present tense — they were denying a door that exists (#17487) |
| 6 | + |
| 7 | +Clause-②: no |
| 8 | + |
| 9 | +No accept-set change and no export moves. `ToolSchema` still refuses |
| 10 | +`requiresConfirmation` with a located parse error, `ActionSchema` still accepts |
| 11 | +`ai.requiresConfirmation` in both directions, and `check:authorable-surface` / |
| 12 | +`check:api-surface` are byte-identical across this diff. What moves is text. |
| 13 | + |
| 14 | +Three customer-facing prescriptions were written while the runtime confirmation |
| 15 | +door was a separate, unlanded change, and each said so in the present tense. The |
| 16 | +door has since landed on `main` — `actionConfirmationRefusal`, called pre-dispatch |
| 17 | +by `invokeBusinessAction` in `@objectstack/runtime`, with the `confirm` member |
| 18 | +grown on the MCP `run_action` tool in the same change. From that moment the |
| 19 | +published prose DENIED a door that exists, and it denied it in the dangerous direction: an author who |
| 20 | +reads it concludes the safety flag stops nothing and either arranges a human in |
| 21 | +the loop some other way or stops setting the flag — losing the gate exactly when |
| 22 | +it starts working. That is the ADR-0049 false-compliance defect with the sign |
| 23 | +flipped. |
| 24 | + |
| 25 | +**The three carriers**, all of them shipped text rather than comments: |
| 26 | + |
| 27 | +1. the `requiresConfirmation` entry of `TOOL_RETIRED_KEY_GUIDANCE` |
| 28 | + (`ai/tool.zod.ts`), which reaches consumers as the parse error on the |
| 29 | + `.strict()` `ToolSchema` — the one channel every consumer bumping |
| 30 | + `@objectstack/spec` is guaranteed to hit; |
| 31 | +2. the ADR-0087 D3 entry's `replacement`, and |
| 32 | +3. its `acceptanceCriteria` — what `spec-changes.json`, |
| 33 | + `docs/protocol-upgrade-guide.md` and `os migrate meta` project to consumers. |
| 34 | + |
| 35 | +FROM → TO, on the sharpest of the three (the acceptance criterion): |
| 36 | + |
| 37 | +``` |
| 38 | +was: Do NOT try to "prove the gate" by invoking the operation without the |
| 39 | + confirmation member: ... before that ships the call is not refused, it |
| 40 | + RUNS the destructive operation. |
| 41 | +now: ... that gate is PERFORMED: invoking the operation over an AI-exposed |
| 42 | + door without the confirmation member is REFUSED with |
| 43 | + ACTION_CONFIRMATION_REQUIRED (428) and nothing runs, so that call is a |
| 44 | + real check you can make rather than a destructive experiment. |
| 45 | +``` |
| 46 | + |
| 47 | +**The corrections carry the door's BOUNDS, because over-promising here is the |
| 48 | +same defect in the other direction.** Each prescription now states, as the door |
| 49 | +itself declares them: the refusal is `ACTION_CONFIRMATION_REQUIRED` / 428 naming |
| 50 | +the action and the member `confirm: true`; it is a GATE, not a queue — nothing |
| 51 | +is parked and a refused call did not run, no record read and none written; the |
| 52 | +enforced set is the doors that enforce the author's `ai.exposed` opt-in, today |
| 53 | +the action door reached from the MCP `run_action` tool, while REST `/actions` is |
| 54 | +not `ai.exposed`-gated and sits outside the gate; only the author's declared |
| 55 | +`ai.requiresConfirmation: true` refuses, while the wider listing heuristic |
| 56 | +advises and never refuses; and `confirm: true` is an unverifiable caller claim, |
| 57 | +so the gate makes FORGETTING loud without proving a human. |
| 58 | + |
| 59 | +`ai/tool-confirmation-prescription-tense.pin.test.ts` is the tie that was |
| 60 | +missing the first time: it reads the three shipped strings AND the runtime door, |
| 61 | +so a prescription that re-acquires a not-yet-shipped denial fails, and a door |
| 62 | +that is removed, narrowed off the DECLARED flag, unhooked from |
| 63 | +`invokeBusinessAction`, or widened onto REST `/actions` fails naming both files. |
| 64 | +The denial predicate is fed the three retired sentences verbatim, so it cannot |
| 65 | +pass by the prose merely falling silent. |
| 66 | + |
| 67 | +**On release ordering.** The door ships in the same release this correction |
| 68 | +does: the runtime changeset that carries it (`action-confirmation-gate-enforced`) |
| 69 | +is still pending alongside this one, and one `changeset version` run consumes |
| 70 | +both. A release cut before this lands is the failure this card exists to end — |
| 71 | +the runtime refusing calls while the published spec text tells authors the flag |
| 72 | +stops nothing. |
0 commit comments