@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 +35 -10
- package/dist/legion.js +36 -11
- package/dist/skills/dispatch/SKILL.md +21 -18
- package/dist/skills/dispatch/references/asks.md +14 -7
- package/dist/skills/dispatch/references/examples.md +30 -15
- package/dist/skills/legion-architect/SKILL.md +3 -2
- package/dist/skills/legion-worker/references/merge-gate.md +5 -4
- package/package.json +1 -1
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: {
|
|
30159
|
-
|
|
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(
|
|
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("
|
|
30169
|
-
}), { max: 8 }).describe(
|
|
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: "
|
|
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
|
|
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(
|
|
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("
|
|
30193
|
-
}), { max: 8 }).describe(
|
|
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: {
|
|
30328
|
-
|
|
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(
|
|
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("
|
|
30338
|
-
}), { max: 8 }).describe(
|
|
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: "
|
|
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
|
|
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(
|
|
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("
|
|
30362
|
-
}), { max: 8 }).describe(
|
|
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.
|
|
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.
|
|
53
|
-
the
|
|
54
|
-
|
|
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
|
|
218
|
-
the
|
|
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.
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
description, and the human's free-text answer
|
|
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({
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 —
|
|
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
|
-
"
|
|
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: "
|
|
26
|
-
{ label: "Ship now", description: "Meets the demo deadline
|
|
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({
|
|
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
|
|
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:
|
|
70
|
-
|
|
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
|
|
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:
|
|
80
|
-
|
|
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;
|
|
266
|
-
with
|
|
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`
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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.
|