README invalid-options cell lists only count, key, text and duplicates; a
non-{key,text} option refuses invalid-request (Sage 28378, Filbert C1 28379).
Broker test pins the option shape cases. m1 and m2 killed; full gate passed
15:53:56-15:59:33Z on BASE 96656dd21.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
38 lines
2.7 KiB
Diff
38 lines
2.7 KiB
Diff
diff -ru r1tree/packages/bus/README.md verify/packages/bus/README.md
|
|
--- r1tree/packages/bus/README.md 2026-10-14 10:53:39.557838852 -0500
|
|
+++ verify/packages/bus/README.md 2026-10-14 10:53:39.033151464 -0500
|
|
@@ -208,15 +208,16 @@
|
|
block's `by` names the acting role and refused when launch state is revoked. S6 still owns launch allowlists,
|
|
capacity and actual spawning.
|
|
|
|
-`decision.raise` checks its choices in this order, and each refusal names one field:
|
|
+`decision.raise` checks its choices in this order, and each of these codes names one field:
|
|
|
|
| Code | Field | Refused when |
|
|
|---|---|---|
|
|
-| `invalid-options` | `options` | fewer than 2 or more than 9 options, an option that isn't `{key,text}` with a valid key and text, or duplicate keys |
|
|
+| `invalid-options` | `options` | not an array, fewer than 2 or more than 9 options, an option whose `key` isn't 1 to 160 letters, digits or `_.:/-` starting with a letter or digit, or whose `text` isn't a string of 1 to 1024 characters with no NUL, or duplicate keys |
|
|
| `invalid-recommendation` | `recommendation` | the value isn't exactly one option key; `"yes: a reason"` refuses, so the reason goes in `question` |
|
|
| `invalid-approval-choice` | `approvalChoice` | the value, or the default `yes` when it is omitted, isn't an option key |
|
|
|
|
The options come first, so a bad option list refuses `invalid-options` even when the recommendation also misses.
|
|
+An option that isn't an object with exactly `key` and `text` refuses `invalid-request`, like any other malformed argument.
|
|
|
|
Authorization requires the resolved option identified by `approvalChoice`
|
|
(default `yes`, which must exist), the same raiser role/run, action and target.
|
|
diff -ru r1tree/packages/bus/tests/broker.test.mjs verify/packages/bus/tests/broker.test.mjs
|
|
--- r1tree/packages/bus/tests/broker.test.mjs 2026-10-14 10:53:39.557838852 -0500
|
|
+++ verify/packages/bus/tests/broker.test.mjs 2026-10-14 10:53:39.033151464 -0500
|
|
@@ -176,6 +176,11 @@
|
|
() => raise(b, c, 'prd.approve', { options: [{ key: 'yes', text: 'a' }], recommendation: 'no' }),
|
|
/invalid-options/,
|
|
);
|
|
+ const shaped = (o) => raise(b, c, 'prd.approve', { options: [{ key: 'yes', text: 'a' }, o], recommendation: 'no' });
|
|
+ assert.throws(() => shaped({ key: 'no bad', text: 'b' }), /invalid-options/);
|
|
+ assert.throws(() => shaped({ key: 'no', text: '' }), /invalid-options/);
|
|
+ for (const o of [{ key: 'no' }, { key: 'no', text: 'b', why: 'c' }, 'no'])
|
|
+ assert.throws(() => shaped(o), /invalid-request/, 'a malformed option object is a malformed argument');
|
|
assert.deepEqual(count(), before, 'a refused raise writes no decision and no message');
|
|
assert.equal(call(b, c, 'inbox').length, 0);
|
|
const d = raise(b, c, 'prd.approve', { recommendation: 'yes' });
|