@sjawhar/pi-legion-envoy 5.30.13 → 5.30.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/envoy.js CHANGED
@@ -30005,6 +30005,8 @@ function dispatchToolSchema(spec, z2, opts) {
30005
30005
  }
30006
30006
  var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference. An external reference addresses an existing Dispatch issue, including one linked to that GitHub pull request; only dispatch_issue with external creates a native issue.";
30007
30007
  var OWNER_REFERENCE = "Exactly one of issue and project is required. An issue is a native KEY or external owner/repo#n reference; a project is a project key such as CORE and addresses an unlinked project document named by artifact.";
30008
+ var ASK_QUESTION_CONTRACT = "The question carries the problem the reader recognises and why it matters now, what constrains " + "the answer, and the recommendation with its reason. It asks how to solve the problem or which " + "outcome is wanted; never enumerate choices in the question.";
30009
+ var ASK_OPTIONS_CONTRACT = "Options carry the genuinely different approaches. Each option has a label, and its description " + "says what that approach costs.";
30008
30010
  function documentOwnerValidation(requireArtifact, alwaysRequireArtifact = false) {
30009
30011
  return {
30010
30012
  check: (value) => {
@@ -30155,18 +30157,31 @@ var dispatchToolSpecs = [
30155
30157
  },
30156
30158
  {
30157
30159
  name: "dispatch_ask",
30158
- example: { issue: "DSP-1", question: "Ship this?" },
30159
- description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " + "use dispatch_message instead. A to-do a human must complete is a question phrased as that to-do, with the options you want (for example Done / Can't). " + "Anything you are blocked on a human for, including a credential or grant to renew, an approval, or a decision, is an ask, never a message. " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". A quote anchor is pinned to its block. Question is at most ${ASK_QUESTION_MAX} ` + `characters and has at most 8 options. ${OWNER_REFERENCE}`,
30160
+ example: {
30161
+ issue: "DSP-1",
30162
+ question: "The release cannot pass its review gate because the revised plan is unreviewed. " + "How should we proceed? Recommendation: review the plan before release to keep the review gate.",
30163
+ options: [
30164
+ {
30165
+ label: "Review the revised plan",
30166
+ description: "Delays release for review but keeps the release gate."
30167
+ },
30168
+ {
30169
+ label: "Release without review",
30170
+ description: "Ships sooner but bypasses the review gate."
30171
+ }
30172
+ ]
30173
+ },
30174
+ description: "Open a durable, answerable decision on an issue or project document. Do not use it for a " + "status update or discussion; use dispatch_message instead. " + ASK_QUESTION_CONTRACT + " " + ASK_OPTIONS_CONTRACT + " For an action only a human can perform, state what it changes and risks as constraints. " + "Anything you are blocked on a human for, including a credential or grant to renew, an " + "approval, or a decision, is an ask, never a message. " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". ` + `A quote anchor is pinned to its block. Question is at most ${ASK_QUESTION_MAX} characters ` + `and has at most 8 options. ${OWNER_REFERENCE}`,
30160
30175
  arguments: (z2) => ({
30161
30176
  issue: z2.string().describe(ISSUE_REFERENCE).optional(),
30162
30177
  project: z2.string().describe("Project key owning the document.").optional(),
30163
30178
  artifact: z2.string().describe("Project document artifact id, slug, or filename.").optional(),
30164
30179
  ref: z2.string().describe("Optional dispatch:// reference (issue, document, message, or ask); appended to the question and rendered as a link.").optional(),
30165
- question: z2.string({ max: ASK_QUESTION_MAX }).describe(`Decision question, at most ${ASK_QUESTION_MAX} characters.`),
30180
+ question: z2.string({ max: ASK_QUESTION_MAX }).describe(`${ASK_QUESTION_CONTRACT} At most ${ASK_QUESTION_MAX} characters.`),
30166
30181
  options: z2.array(z2.object({
30167
30182
  label: z2.string().describe("Selectable option label."),
30168
- description: z2.string().describe("Optional option context.").optional()
30169
- }), { max: 8 }).describe("Up to 8 choices, each an object { label, description? } (never a bare string).").optional(),
30183
+ description: z2.string().optional().describe("What this option costs.")
30184
+ }), { max: 8 }).optional().describe(`${ASK_OPTIONS_CONTRACT} Up to 8 objects { label, description? }.`),
30170
30185
  multiple: z2.boolean().describe("Whether multiple choices may be selected.").optional(),
30171
30186
  urgency: z2.enum(ASK_URGENCIES).describe("Optional decision urgency.").optional(),
30172
30187
  anchor: z2.object({
@@ -30181,16 +30196,26 @@ var dispatchToolSpecs = [
30181
30196
  name: "dispatch_edit_ask",
30182
30197
  example: {
30183
30198
  ask: "01234567-0000-4000-8000-000000000001",
30184
- question: "Ship the revised plan?"
30199
+ question: "The release cannot pass its review gate because the revised plan is unreviewed. " + "How should we proceed? Recommendation: review the plan before release to keep the review gate.",
30200
+ options: [
30201
+ {
30202
+ label: "Review the revised plan",
30203
+ description: "Delays release for review but keeps the release gate."
30204
+ },
30205
+ {
30206
+ label: "Release without review",
30207
+ description: "Ships sooner but bypasses the review gate."
30208
+ }
30209
+ ]
30185
30210
  },
30186
- description: "Edit an open question in place. Use it to correct or refine the same decision; retract the " + "old ask and open a new one when the decision itself changes. Previous text remains in the " + "event log. Only the asking session can edit it; answered or resolved asks cannot be edited. " + "An ask that lives as an `ask` block in a document is written in the document too, changing " + "only the fields you name - pass urgency alone and the question's wording, formatting, links " + "and comment anchors are untouched - so the edit writes a document version and closes a " + "spec's design gate until that version is " + "approved; text the block cannot carry back unchanged is refused, naming the field - an " + 'option label containing ": ", the separator between a label and its description, is one ' + "example.",
30211
+ description: "Edit an open question in place. Use it to correct or refine the same decision; retract the " + "old ask and open a new one when the decision itself changes. " + ASK_QUESTION_CONTRACT + " " + ASK_OPTIONS_CONTRACT + " Previous text remains in the event log. Only the asking session can edit it; answered or " + "resolved asks cannot be edited. An ask that lives as an `ask` block in a document is written " + "in the document too, changing only the fields you name - pass urgency alone and the " + "question's wording, formatting, links and comment anchors are untouched - so the edit " + "writes a document version and closes a spec's design gate until that version is approved; " + "text the block cannot carry back unchanged is refused, naming the field - an option label " + 'containing ": ", the separator between a label and its description, is one example.',
30187
30212
  arguments: (z2) => ({
30188
30213
  ask: z2.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
30189
- question: z2.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
30214
+ question: z2.string({ max: ASK_QUESTION_MAX }).optional().describe(`${ASK_QUESTION_CONTRACT} Replaces the ask's question; at most ${ASK_QUESTION_MAX} characters.`),
30190
30215
  options: z2.array(z2.object({
30191
30216
  label: z2.string().describe("Selectable option label."),
30192
- description: z2.string().describe("Optional option context.").optional()
30193
- }), { max: 8 }).describe("Replacement choices, at most 8.").optional(),
30217
+ description: z2.string().optional().describe("What this option costs.")
30218
+ }), { max: 8 }).optional().describe(`${ASK_OPTIONS_CONTRACT} Replaces the ask's options; up to 8 objects { label, description? }.`),
30194
30219
  multiple: z2.boolean().describe("Whether multiple choices may be selected.").optional(),
30195
30220
  urgency: z2.enum(ASK_URGENCIES).describe("Replacement decision urgency.").optional()
30196
30221
  }),
package/dist/legion.js CHANGED
@@ -30174,6 +30174,8 @@ function dispatchToolSchema(spec, z2, opts) {
30174
30174
  }
30175
30175
  var ISSUE_REFERENCE = "An issue is a native KEY or external owner/repo#n reference. An external reference addresses an existing Dispatch issue, including one linked to that GitHub pull request; only dispatch_issue with external creates a native issue.";
30176
30176
  var OWNER_REFERENCE = "Exactly one of issue and project is required. An issue is a native KEY or external owner/repo#n reference; a project is a project key such as CORE and addresses an unlinked project document named by artifact.";
30177
+ var ASK_QUESTION_CONTRACT = "The question carries the problem the reader recognises and why it matters now, what constrains " + "the answer, and the recommendation with its reason. It asks how to solve the problem or which " + "outcome is wanted; never enumerate choices in the question.";
30178
+ var ASK_OPTIONS_CONTRACT = "Options carry the genuinely different approaches. Each option has a label, and its description " + "says what that approach costs.";
30177
30179
  function documentOwnerValidation(requireArtifact, alwaysRequireArtifact = false) {
30178
30180
  return {
30179
30181
  check: (value) => {
@@ -30324,18 +30326,31 @@ var dispatchToolSpecs = [
30324
30326
  },
30325
30327
  {
30326
30328
  name: "dispatch_ask",
30327
- example: { issue: "DSP-1", question: "Ship this?" },
30328
- description: "Open a durable, answerable decision on an issue or project document. Do not use it for a status update or discussion; " + "use dispatch_message instead. A to-do a human must complete is a question phrased as that to-do, with the options you want (for example Done / Can't). " + "Anything you are blocked on a human for, including a credential or grant to renew, an approval, or a decision, is an ask, never a message. " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". A quote anchor is pinned to its block. Question is at most ${ASK_QUESTION_MAX} ` + `characters and has at most 8 options. ${OWNER_REFERENCE}`,
30329
+ example: {
30330
+ issue: "DSP-1",
30331
+ question: "The release cannot pass its review gate because the revised plan is unreviewed. " + "How should we proceed? Recommendation: review the plan before release to keep the review gate.",
30332
+ options: [
30333
+ {
30334
+ label: "Review the revised plan",
30335
+ description: "Delays release for review but keeps the release gate."
30336
+ },
30337
+ {
30338
+ label: "Release without review",
30339
+ description: "Ships sooner but bypasses the review gate."
30340
+ }
30341
+ ]
30342
+ },
30343
+ description: "Open a durable, answerable decision on an issue or project document. Do not use it for a " + "status update or discussion; use dispatch_message instead. " + ASK_QUESTION_CONTRACT + " " + ASK_OPTIONS_CONTRACT + " For an action only a human can perform, state what it changes and risks as constraints. " + "Anything you are blocked on a human for, including a credential or grant to renew, an " + "approval, or a decision, is an ask, never a message. " + "Anchor a document question, thread reply_to/reply_to_ask, or cite a dispatch:// " + `reference \u2014 it must be answerable from its own text and anchor alone, never "see above". ` + `A quote anchor is pinned to its block. Question is at most ${ASK_QUESTION_MAX} characters ` + `and has at most 8 options. ${OWNER_REFERENCE}`,
30329
30344
  arguments: (z2) => ({
30330
30345
  issue: z2.string().describe(ISSUE_REFERENCE).optional(),
30331
30346
  project: z2.string().describe("Project key owning the document.").optional(),
30332
30347
  artifact: z2.string().describe("Project document artifact id, slug, or filename.").optional(),
30333
30348
  ref: z2.string().describe("Optional dispatch:// reference (issue, document, message, or ask); appended to the question and rendered as a link.").optional(),
30334
- question: z2.string({ max: ASK_QUESTION_MAX }).describe(`Decision question, at most ${ASK_QUESTION_MAX} characters.`),
30349
+ question: z2.string({ max: ASK_QUESTION_MAX }).describe(`${ASK_QUESTION_CONTRACT} At most ${ASK_QUESTION_MAX} characters.`),
30335
30350
  options: z2.array(z2.object({
30336
30351
  label: z2.string().describe("Selectable option label."),
30337
- description: z2.string().describe("Optional option context.").optional()
30338
- }), { max: 8 }).describe("Up to 8 choices, each an object { label, description? } (never a bare string).").optional(),
30352
+ description: z2.string().optional().describe("What this option costs.")
30353
+ }), { max: 8 }).optional().describe(`${ASK_OPTIONS_CONTRACT} Up to 8 objects { label, description? }.`),
30339
30354
  multiple: z2.boolean().describe("Whether multiple choices may be selected.").optional(),
30340
30355
  urgency: z2.enum(ASK_URGENCIES).describe("Optional decision urgency.").optional(),
30341
30356
  anchor: z2.object({
@@ -30350,16 +30365,26 @@ var dispatchToolSpecs = [
30350
30365
  name: "dispatch_edit_ask",
30351
30366
  example: {
30352
30367
  ask: "01234567-0000-4000-8000-000000000001",
30353
- question: "Ship the revised plan?"
30368
+ question: "The release cannot pass its review gate because the revised plan is unreviewed. " + "How should we proceed? Recommendation: review the plan before release to keep the review gate.",
30369
+ options: [
30370
+ {
30371
+ label: "Review the revised plan",
30372
+ description: "Delays release for review but keeps the release gate."
30373
+ },
30374
+ {
30375
+ label: "Release without review",
30376
+ description: "Ships sooner but bypasses the review gate."
30377
+ }
30378
+ ]
30354
30379
  },
30355
- description: "Edit an open question in place. Use it to correct or refine the same decision; retract the " + "old ask and open a new one when the decision itself changes. Previous text remains in the " + "event log. Only the asking session can edit it; answered or resolved asks cannot be edited. " + "An ask that lives as an `ask` block in a document is written in the document too, changing " + "only the fields you name - pass urgency alone and the question's wording, formatting, links " + "and comment anchors are untouched - so the edit writes a document version and closes a " + "spec's design gate until that version is " + "approved; text the block cannot carry back unchanged is refused, naming the field - an " + 'option label containing ": ", the separator between a label and its description, is one ' + "example.",
30380
+ description: "Edit an open question in place. Use it to correct or refine the same decision; retract the " + "old ask and open a new one when the decision itself changes. " + ASK_QUESTION_CONTRACT + " " + ASK_OPTIONS_CONTRACT + " Previous text remains in the event log. Only the asking session can edit it; answered or " + "resolved asks cannot be edited. An ask that lives as an `ask` block in a document is written " + "in the document too, changing only the fields you name - pass urgency alone and the " + "question's wording, formatting, links and comment anchors are untouched - so the edit " + "writes a document version and closes a spec's design gate until that version is approved; " + "text the block cannot carry back unchanged is refused, naming the field - an option label " + 'containing ": ", the separator between a label and its description, is one example.',
30356
30381
  arguments: (z2) => ({
30357
30382
  ask: z2.string().describe("Ask id (uuid); an 8+ hex prefix unique among this session's own open asks works too."),
30358
- question: z2.string({ max: ASK_QUESTION_MAX }).describe(`Replacement decision question, at most ${ASK_QUESTION_MAX} characters.`).optional(),
30383
+ question: z2.string({ max: ASK_QUESTION_MAX }).optional().describe(`${ASK_QUESTION_CONTRACT} Replaces the ask's question; at most ${ASK_QUESTION_MAX} characters.`),
30359
30384
  options: z2.array(z2.object({
30360
30385
  label: z2.string().describe("Selectable option label."),
30361
- description: z2.string().describe("Optional option context.").optional()
30362
- }), { max: 8 }).describe("Replacement choices, at most 8.").optional(),
30386
+ description: z2.string().optional().describe("What this option costs.")
30387
+ }), { max: 8 }).optional().describe(`${ASK_OPTIONS_CONTRACT} Replaces the ask's options; up to 8 objects { label, description? }.`),
30363
30388
  multiple: z2.boolean().describe("Whether multiple choices may be selected.").optional(),
30364
30389
  urgency: z2.enum(ASK_URGENCIES).describe("Replacement decision urgency.").optional()
30365
30390
  }),
@@ -33834,7 +33859,7 @@ import { logger } from "@oh-my-pi/pi-utils";
33834
33859
  // package.json
33835
33860
  var package_default = {
33836
33861
  name: "@sjawhar/pi-legion-envoy",
33837
- version: "5.30.13",
33862
+ version: "5.30.15",
33838
33863
  type: "module",
33839
33864
  omp: {
33840
33865
  extensions: [
@@ -49,9 +49,11 @@ not share this session's vocabulary, and is often on a phone. Write for that per
49
49
  - Expand every identifier the first time it appears: an issue key gets its title, a PR number its
50
50
  title, a file what it is for, a session id who it is. Link a URL rather than pasting a bare id.
51
51
  - A question lives in the spec or discussion it came from, placed as
52
- [Decision blocks](#decision-blocks) says, never as a compressed standalone ask. Give the reader
53
- the options, what each costs, and your recommendation with its reason; do not prescribe yourself
54
- a form.
52
+ [Decision blocks](#decision-blocks) says, never as a compressed standalone ask. The question
53
+ carries the problem the reader recognises and why it matters now, what constrains the answer, and
54
+ the recommendation with its reason. It asks how to solve the problem or which outcome is wanted;
55
+ never enumerate choices in the question. The options carry the genuinely different approaches.
56
+ Each option has a label, and its description says what that approach costs.
55
57
  - Describe a change by what its reader stands to lose, not by what the system does. The
56
58
  engineering sentence names the change; the reader's sentence names who can do what today, what
57
59
  they will not be able to do after it, what still works, and what you cannot tell. It is a
@@ -214,8 +216,9 @@ Every `dispatch_ask` passes four gates first:
214
216
  gate: it is your own `dispatch_ask` to Sami on your own issue.
215
217
  2. **Is there genuine uncertainty, and have you measured what you can?** If there is none, it is
216
218
  a plan you execute. The one legitimate ask without uncertainty is permission for an action
217
- only a human can authorise — a production write, an external send, a console action — and then
218
- the question is that action in one sentence, with options that name its outcomes (below).
219
+ only a human can authorise — a production write, an external send, a console action. Start it
220
+ with the problem and why the action is needed, then state what the action changes and risks;
221
+ its options name the outcomes.
219
222
  Measure before you write: how many are affected, whether anything reaches the path, what the
220
223
  current state already is. The measurement decides whether a human is needed at all, and when
221
224
  one is, it turns a research request he cannot answer into a decision he can. Put the
@@ -267,13 +270,11 @@ It returns `details` `{ issue, ask, follows: { ask } }` for an issue or `{ proje
267
270
 
268
271
  References belong in the question text; `ref` is sugar that appends its `dispatch://` value to the question as a rendered link.
269
272
 
270
- An ask is read on a phone by someone who has not read the code. Open with one or two plain
271
- sentences: what needs deciding and why it matters now. Each option is a button with a label and
272
- one sentence saying what happens if it is chosen; never enumerate choices in prose. Put the
273
- recommendation and its reason last, in `question`. Never put file paths, line numbers, sequence
274
- numbers, document versions, or role tokens in the question; if the human needs that detail, anchor
275
- the ask to the document passage instead. Apply the phone test from "Writing for the human" before
276
- posting. Anchor a document question with `anchor: { artifact, quote, occurrence? }`; `occurrence`
273
+ An ask is read on a phone by someone who has not read the code. Write its question and options as
274
+ [Writing for the human](#writing-for-the-human) says, and apply its phone test before posting.
275
+ Never put file paths, line numbers, sequence numbers, document versions, or role tokens in the
276
+ question; if the human needs that detail, anchor the ask to the document passage instead. Anchor a
277
+ document question with `anchor: { artifact, quote, occurrence? }`; `occurrence`
277
278
  is zero-based and selects a repeated quote. A quote anchor is pinned to its lowest complete
278
279
  containing block while retaining its quote as display text, so rewording the passage keeps it
279
280
  attached; a quote spanning top-level blocks, and existing anchors without a block, stay readable
@@ -314,12 +315,14 @@ Before saying you are waiting for human input, call `dispatch_open_asks`. With n
314
315
  **Anything you are blocked on a human for is an open ask.** An agent waits on a human only through
315
316
  an open ask. An approval, a credential or grant to renew, a setting only they can change, a review
316
317
  click, a decision, or a conflict between two of their own rules: open a `dispatch_ask` the moment
317
- you know, the action as the question. Never write it
318
- into a spec, a comment reply, a message, or a pull-request body: nothing in those paths reaches
319
- the human's Inbox, and a human who is not reading your document does not know they are the
320
- blocker. Before asking, try to remove the step: a value already on the machine, a permission you
321
- already hold, an API that replaces the click. One ask per item, `urgency: "high"` when work is
322
- stopped on it; while it is open, keep working on everything that is not.
318
+ you know. Start with the problem and why it matters, then the constraints, options and their
319
+ costs, and your recommendation. For an action only the human can perform, state what it changes
320
+ and risks; never make the action itself the question. Never write it into a spec, a comment reply,
321
+ a message, or a pull-request body: nothing in those paths reaches the human's Inbox, and a human
322
+ who is not reading your document does not know they are the blocker. Before asking, try to remove
323
+ the step: a value already on the machine, a permission you already hold, an API that replaces the
324
+ click. One ask per item, `urgency: "high"` when work is stopped on it; while it is open, keep
325
+ working on everything that is not.
323
326
 
324
327
  Once an ask is open (who answers it, handing a human a to-do, editing, retracting or resolving it,
325
328
  answering a clarification, whose turn a reply gives), see
@@ -15,14 +15,21 @@ It returns `details` `{ session, owner, service }`: `owner` is the lowercase log
15
15
 
16
16
  ## Handing a human a to-do, editing, resolving, and replying
17
17
 
18
- A to-do handed to a human is an ordinary question: phrase the to-do as the question and give it
19
- the options that name its outcomes, in the human's words - there is no fixed vocabulary and the
20
- server treats no label specially. If an outcome needs a reason, say so in that option's
21
- description, and the human's free-text answer carries it:
18
+ A to-do handed to a human still follows the question and options contract that `skill://dispatch`'s
19
+ "Writing for the human" states. For a human-only action, what it changes and risks constrains the
20
+ answer. There is no fixed vocabulary and the server treats no label specially.
21
+ If an outcome needs a reason, say so in that option's description, and the human's free-text answer
22
+ carries it:
22
23
  ```ts
23
- dispatch_ask({ issue: "DSP-42",
24
- question: "Run the production deploy for #19125?",
25
- options: [{ label: "Deployed" }, { label: "Blocked", description: "Say what is missing." }] })
24
+ dispatch_ask({
25
+ issue: "DSP-42",
26
+ question:
27
+ "The verified fix remains unavailable in production because deployment is pending. Deploying changes production and could expose a deployment problem. How should we proceed? Recommendation: deploy the verified fix now because it restores the intended behavior.",
28
+ options: [
29
+ { label: "Deploy the verified fix", description: "Restores the fix but can expose a deployment problem." },
30
+ { label: "Hold the deploy", description: "Avoids a production change now but leaves production without the fix." },
31
+ ],
32
+ })
26
33
  ```
27
34
 
28
35
  Correct or refine an open ask in place instead of opening a second question:
@@ -8,22 +8,21 @@ message that should not be sent, and a draft placed where the human reads it.
8
8
  Before — a wall of text hides the decision and makes the choices unclickable:
9
9
 
10
10
  ```text
11
- We need to settle the release gate because the deploy branch has the migration and the
12
- dashboard changes, I checked the staging result and it is fine except the release notes are
13
- not reviewed, so should we ship today, wait for docs, or cut the dashboard from this release?
14
- I think waiting is safest but the customer demo is tomorrow and the list above is probably stale.
11
+ The deploy branch has the migration and dashboard changes. Staging is fine, but release notes are
12
+ not reviewed before tomorrow's customer demo. Review the notes, ship without them, or cut the
13
+ dashboard from the release. Waiting is safest, but the list above may be stale.
15
14
  ```
16
15
 
17
- After — anchor the decision and make each option a button:
16
+ After — state the problem and make each genuinely different option a button:
18
17
 
19
18
  ```ts
20
19
  dispatch_ask({
21
20
  issue: "LEGION-815",
22
21
  question:
23
- "Choose the release gate. Recommendation: ship after release-note review, since the tested deployment is otherwise ready.",
22
+ "Release notes are unreviewed, and tomorrow's customer demo means the release cannot wait for a later review. How should we proceed? Recommendation: review the notes, then ship, to keep the release complete and reviewed.",
24
23
  options: [
25
- { label: "Review notes, then ship", description: "Keeps the release intact and reviewed." },
26
- { label: "Ship now", description: "Meets the demo deadline; release notes follow later." },
24
+ { label: "Review notes, then ship", description: "Delays release for review but keeps the release complete and reviewed." },
25
+ { label: "Ship now", description: "Meets the demo deadline but leaves the release notes unreviewed." },
27
26
  ],
28
27
  urgency: "high",
29
28
  anchor: { artifact: "spec", quote: "Release requires reviewed operator instructions before deployment." },
@@ -54,11 +53,19 @@ dispatch_artifact({ issue: "OPS-52", name: "cu-update-2026-09-15.md", content: "
54
53
  dispatch_doc_edit({ issue: "OPS-52", artifact: "spec", ops: [
55
54
  { op: "insert", after: "## Context", markdown: "## Draft (artifact cu-update-2026-09-15.md)" },
56
55
  ]})
57
- dispatch_ask({ issue: "OPS-52", question: "Send the customer update as drafted?", options: [...] })
56
+ dispatch_ask({
57
+ issue: "OPS-52",
58
+ question:
59
+ "Customers need an update today, but the draft is only in a separate file, so the reader cannot review it in context. How should we proceed? Recommendation: put the draft in the spec before sending it.",
60
+ options: [
61
+ { label: "Put the draft in the spec", description: "Adds a spec edit before sending but lets the reader review it in context." },
62
+ { label: "Keep the separate file", description: "Saves the spec edit but leaves the reader to find the draft." },
63
+ ],
64
+ })
58
65
  ```
59
66
 
60
67
  After — the draft is a section of the spec, and the ask anchors there. If it really must be a
61
- file (something to send as-is), the spec and the ask both link the slug from the upload result:
68
+ file, the spec and the ask both link the slug from the upload result:
62
69
 
63
70
  ```ts
64
71
  dispatch_doc_edit({ issue: "OPS-52", artifact: "spec", ops: [
@@ -66,17 +73,25 @@ dispatch_doc_edit({ issue: "OPS-52", artifact: "spec", ops: [
66
73
  ]})
67
74
  dispatch_ask({
68
75
  issue: "OPS-52",
69
- question: "Send the customer update as drafted?",
70
- options: [...],
76
+ question:
77
+ "Customers need an update today, and the reviewed text is ready in the spec. Sending it cannot be recalled. How should we proceed? Recommendation: send the reviewed update.",
78
+ options: [
79
+ { label: "Send the reviewed update", description: "Delivers the update today but makes its text external." },
80
+ { label: "Hold the update", description: "Avoids sending now but leaves customers without the update." },
81
+ ],
71
82
  anchor: { artifact: "spec", quote: "Hi team," },
72
83
  })
73
84
  // or, for a real file — the spec links it where the reader needs it, and so does the ask:
74
85
  dispatch_doc_edit({ issue: "OPS-52", artifact: "spec", ops: [
75
- { op: "insert", after: "## Context", markdown: "## Draft\n\nThe update to send as-is: dispatch://OPS-52/artifact/cu-update-2026-09-15-md" },
86
+ { op: "insert", after: "## Context", markdown: "## Draft\n\nThe update to send: dispatch://OPS-52/artifact/cu-update-2026-09-15-md" },
76
87
  ]})
77
88
  dispatch_ask({
78
89
  issue: "OPS-52",
79
- question: "Send this customer update as-is? dispatch://OPS-52/artifact/cu-update-2026-09-15-md",
80
- options: [...],
90
+ question:
91
+ "Customers need an update today, and its reviewed text is linked from the spec. Sending it cannot be recalled. How should we proceed? Recommendation: send the reviewed update.",
92
+ options: [
93
+ { label: "Send the reviewed update", description: "Delivers the linked update today but makes its text external." },
94
+ { label: "Hold the update", description: "Avoids sending now but leaves customers without the update." },
95
+ ],
81
96
  })
82
97
  ```
@@ -262,8 +262,9 @@ Preserve this order exactly:
262
262
  task. It drives the changed path in production through the user's own access path and records
263
263
  what it saw on the pull request and on this issue. Close only after the implementer's production
264
264
  report exists. A defect it finds is a corrective child issue of this tree, not a note on a
265
- closed one; a deploy the implementer cannot perform is its `dispatch_ask` naming that deploy,
266
- with options for its outcomes, and the issue waits for it.
265
+ closed one; if the implementer cannot perform the deploy, it opens a `dispatch_ask` that starts
266
+ with the production gap and why it matters, then names the required step, its risk, and
267
+ outcome-named options. The issue waits for that answer.
267
268
 
268
269
  What returns the tree to review: a changed diff — a commit above the approved head that
269
270
  touches anything outside `docs/solutions/`, or a conflict-resolution merge whose fingerprint
@@ -96,7 +96,8 @@ completion leaves the issue in reviewing until you finish.
96
96
  carrying the Legion footer, and a `dispatch_message` on the issue — the reviewer and merger
97
97
  read GitHub, the architect reads the issue. When the deploy that carries the merge has not
98
98
  happened (a shared profile still holding the previous plugin release, a daemon still running
99
- the previous commit, a slot nobody has run), open a `dispatch_ask` naming the exact install or
100
- restart step, with options for its outcomes, keep the `Production:` line at `pending <what is
101
- missing>`, and complete the check once the human answers that it is done. Never record a
102
- staging pass as the production check, and never let the architect sign off on a `pending` line.
99
+ the previous commit, a slot nobody has run), open a `dispatch_ask` that starts with the
100
+ production gap and why it matters, then names the required install or restart step, its risk,
101
+ and outcome-named options. Keep the `Production:` line at `pending <what is missing>`, and
102
+ complete the check once the human answers. Never record a staging pass as the production check,
103
+ and never let the architect sign off on a `pending` line.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjawhar/pi-legion-envoy",
3
- "version": "5.30.13",
3
+ "version": "5.30.15",
4
4
  "type": "module",
5
5
  "omp": {
6
6
  "extensions": [