@sjawhar/opencode-legion-envoy 6.4.1 → 6.5.0
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/README.md +13 -36
- package/bin/dispatch +6 -0
- package/dist/dispatch.js +18648 -0
- package/dist/src/server.js +238 -3570
- package/package.json +4 -3
- package/skills/dispatch/SKILL.md +85 -97
- package/skills/dispatch/references/api.md +4 -4
- package/skills/dispatch/references/asks.md +34 -54
- package/skills/dispatch/references/document-edits.md +24 -21
- package/skills/dispatch/references/documents.md +75 -72
- package/skills/dispatch/references/examples.md +37 -67
- package/skills/dispatch/references/issues.md +48 -48
- package/skills/dispatch/references/messages.md +18 -25
- package/skills/dispatch/references/reading.md +10 -10
- package/skills/dispatch-brainstorming/SKILL.md +19 -15
- package/skills/dispatch-first/SKILL.md +7 -7
- package/skills/envoy/SKILL.md +3 -2
- package/skills/legion-architect/SKILL.md +47 -49
- package/skills/legion-controller/SKILL.md +38 -32
- package/skills/legion-retro/SKILL.md +7 -8
- package/skills/legion-worker/SKILL.md +3 -3
- package/skills/legion-worker/references/merge-gate.md +3 -3
- package/src/server.ts +54 -36
|
@@ -23,7 +23,7 @@ separate coordinator to finish necessary work.
|
|
|
23
23
|
product, scope, design, and cross-phase decisions the same way: `envoy_publish` to your own
|
|
24
24
|
encoded token. You decide whether one needs the human and write its decision block yourself
|
|
25
25
|
(section 1 says what one does to an approved root spec); a worker never writes one. Any role may
|
|
26
|
-
use `
|
|
26
|
+
use `dispatch ask` directly for a standalone to-do only a human can complete, and replies return
|
|
27
27
|
to the asking session.
|
|
28
28
|
- The daemon starts each role as its own process with the issue's context already in its
|
|
29
29
|
environment. Never hand-format a role token: the daemon encodes one as
|
|
@@ -33,7 +33,7 @@ separate coordinator to finish necessary work.
|
|
|
33
33
|
the `roleToken` helper from `@legion/contracts` exactly the way the daemon does.
|
|
34
34
|
- There is no label vocabulary. Dispatch status replaces the board, and the design gate
|
|
35
35
|
is a human approving the root spec document at a version in Dispatch, requested with
|
|
36
|
-
`
|
|
36
|
+
`dispatch request-approval` — not a label and not an ask. Never attempt to apply a label.
|
|
37
37
|
- Deferring necessary work is failure. The sole valid deferral is a new child issue you
|
|
38
38
|
create and continue to own. Re-file a genuinely independent child through the
|
|
39
39
|
controller rather than treating it as an abandoned dependency.
|
|
@@ -59,35 +59,32 @@ exercise a criterion end to end, building that path is a child issue of this tre
|
|
|
59
59
|
- **No children:** choose a single-issue tree only when its acceptance criteria can be
|
|
60
60
|
completed and integrated as one unit. Otherwise create complete child issues with:
|
|
61
61
|
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
title: "<child outcome>",
|
|
67
|
-
spec: "<acceptance criteria, scope, and context>"
|
|
68
|
-
})
|
|
62
|
+
```bash
|
|
63
|
+
dispatch issue --project <project> --parent <root issue> --title '<child outcome>' --spec-file - <<'EOF'
|
|
64
|
+
<acceptance criteria, scope, and context>
|
|
65
|
+
EOF
|
|
69
66
|
```
|
|
70
67
|
|
|
71
|
-
|
|
68
|
+
`--project` is the issue key's prefix before `-<n>` (e.g. `LEGSMOKE-3` → `LEGSMOKE`) — not
|
|
72
69
|
the role-token `<project>` (the daemon's own project, e.g. `acme`), a different string. A
|
|
73
70
|
root session has `LEGION_TREE == LEGION_ISSUE`. The daemon establishes the sub-issue
|
|
74
|
-
relationship from
|
|
75
|
-
inert until released. Do not pass
|
|
71
|
+
relationship from `--parent`. Keep the returned issue keys in ordered waves; a child is
|
|
72
|
+
inert until released. Do not pass `--assignee`: the default keeps the tree's questions in one
|
|
76
73
|
Inbox — under the shared token a child inherits its parent's assignee (the human who
|
|
77
74
|
answers the tree's asks); under a personal token it goes to that token's owner, whom
|
|
78
|
-
`
|
|
75
|
+
`dispatch whoami` names. Set it only when a human told you a specific person owns that child.
|
|
79
76
|
|
|
80
77
|
Specifications written into Dispatch follow `skill://dispatch`'s [Writing a spec](skill://dispatch/SKILL.md#writing-a-spec).
|
|
81
78
|
Wave releases, child closures, and your own status are visible from the issue tree and the
|
|
82
|
-
handoffs; do not narrate them into the spec or a `
|
|
83
|
-
clear is a `
|
|
79
|
+
handoffs; do not narrate them into the spec or a `dispatch message`. A to-do only a human can
|
|
80
|
+
clear is a `dispatch ask`.
|
|
84
81
|
|
|
85
82
|
The issue's primary document **is** the root specification. Extend it in place: a new version
|
|
86
83
|
that adds only the evidence each decision needs and what the human decides, each as a
|
|
87
84
|
[decision block](skill://dispatch/SKILL.md#decision-blocks). The decomposition and its waves, how each
|
|
88
85
|
outcome is proven, and the integration test are your own calls: they go in the child issues and
|
|
89
86
|
the planner's `.legion/<issue>/plan.json`, not the root spec. Never post a second "spec" artifact beside
|
|
90
|
-
it (`
|
|
87
|
+
it (`dispatch artifact` with the primary document's name replaces the human's document; do not do
|
|
91
88
|
that).
|
|
92
89
|
The design gate's approval step runs only when the `Design gate policy` sentence of your
|
|
93
90
|
`Legion addressing` line says `gates.design: root-issues`. When it says `gates.design: off`, write
|
|
@@ -97,47 +94,46 @@ sub-architect on a child issue has no policy line and never runs the gate: the r
|
|
|
97
94
|
covers the tree. When the gate is armed, run this exact sequence **before the tree's work starts**:
|
|
98
95
|
|
|
99
96
|
```text
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
dispatch doc-edit --issue <root issue> --ops-json-file - <<'EOF' # extend the primary document in place
|
|
98
|
+
...
|
|
99
|
+
EOF
|
|
100
|
+
# then settle its decision blocks (below)
|
|
101
|
+
dispatch request-approval --issue <root issue> --summary '<what the human is approving>'
|
|
102
|
+
# the primary document by default; prints "Approval requested for spec.md (document id <UUID>) at version <N> …"
|
|
106
103
|
legion({
|
|
107
104
|
op: "register_gate",
|
|
108
105
|
issue: "<root issue>",
|
|
109
|
-
artifactId:
|
|
110
|
-
version:
|
|
106
|
+
artifactId: "<UUID>", // the document id from that text, such as 4e0aca36-77b3-43bd-96cf-d58890ae64e4
|
|
107
|
+
version: <N>, // the version number the human is asked to approve
|
|
111
108
|
})
|
|
112
109
|
```
|
|
113
110
|
|
|
114
111
|
The decision blocks come first: settle every one as
|
|
115
112
|
[Approval of a spec](skill://dispatch/SKILL.md#approval-of-a-spec) says before you request approval;
|
|
116
|
-
`
|
|
113
|
+
`dispatch request-approval` refuses while one is open. Each answer reaches you, since you follow
|
|
117
114
|
every ask you open. An approval request carries nothing new: request it only once the human has
|
|
118
115
|
agreed to every point in the spec, so a point they have not agreed to gets its own decision block
|
|
119
|
-
first, or comes out of the spec.
|
|
116
|
+
first, or comes out of the spec. `--summary` says in one to three sentences what the human is
|
|
120
117
|
approving and nothing else: no commentary and no open question.
|
|
121
118
|
|
|
122
|
-
`
|
|
119
|
+
`dispatch request-approval` opens a system question on the document with the fixed options
|
|
123
120
|
`Approve` and `Request changes`; a human answers it from the Inbox or approves from the
|
|
124
|
-
document's own header. Never open a `
|
|
121
|
+
document's own header. Never open a `dispatch ask` with an `Approve` option yourself: an
|
|
125
122
|
ordinary question is not a gate and the daemon ignores its answer. Copy `artifactId` and
|
|
126
|
-
`version` from the
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
document id is never the slug or file name you passed in (`spec`, `spec.md`): the daemon
|
|
123
|
+
`version` from the text `dispatch request-approval` prints: "Approval requested for spec.md
|
|
124
|
+
(document id <UUID>) at version <N> (ask <id>)", followed by the question the human's Inbox shows.
|
|
125
|
+
The document id is never the slug or file name you passed in (`spec`, `spec.md`): the daemon
|
|
130
126
|
recognizes the document's approval events by that id and takes no other value; the `legion` tool
|
|
131
|
-
looks a slug or file name up in Dispatch and hands the daemon the id. Calling `
|
|
132
|
-
waits on the human, with the same
|
|
133
|
-
it "already waits on the human"), so it is safe to repeat; a different
|
|
127
|
+
looks a slug or file name up in Dispatch and hands the daemon the id. Calling `dispatch request-approval` again while that request
|
|
128
|
+
waits on the human, with the same `--summary`, changes nothing and returns it (its text says
|
|
129
|
+
it "already waits on the human"), so it is safe to repeat; a different `--summary` is refused then.
|
|
134
130
|
A newer version of the spec moves the open request to that version and leaves it waiting on you,
|
|
135
131
|
with no wake when the edit was yours: once the human has agreed to every point in it, call again
|
|
136
132
|
to hand the same request back at the latest version. If its text instead reads "spec.md (document
|
|
137
133
|
id <UUID>) is already approved at version <N>" — a human approved from the document header before
|
|
138
134
|
you asked — still call `register_gate` with that id and version: the daemon reads the approval
|
|
139
135
|
from Dispatch as it registers, opens the gate, and delivers `design-approved` at once. The same
|
|
140
|
-
read covers a human who answers the question between your `
|
|
136
|
+
read covers a human who answers the question between your `dispatch request-approval` and
|
|
141
137
|
`register_gate` calls, so an approval is never lost to timing; you never approve anything
|
|
142
138
|
yourself.
|
|
143
139
|
|
|
@@ -196,7 +192,7 @@ The daemon moves each released child to `todo` and, while the root's design gate
|
|
|
196
192
|
its phases itself from its fixed workflow table, each phase worker as its own process with the
|
|
197
193
|
child's context already in its environment; it starts no sub-architect, and you start no worker.
|
|
198
194
|
Park while children are in flight. On each child closure, re-scope open work, take obsolete work
|
|
199
|
-
out of the workflow with `park_child` (saying why on the issue with `
|
|
195
|
+
out of the workflow with `park_child` (saying why on the issue with `dispatch comment`), and
|
|
200
196
|
release the next wave only when it now makes sense. There is no inter-child
|
|
201
197
|
dependency mechanism to encode.
|
|
202
198
|
|
|
@@ -238,12 +234,12 @@ the task.
|
|
|
238
234
|
Wait for the implementer to report its durable retro result. Retro output is
|
|
239
235
|
`docs/solutions/`, its last commit removing the issue's `.legion/<issue>/` from the head a human
|
|
240
236
|
merges, the PR body content the repository's instructions derive from the pull request's changed
|
|
241
|
-
paths at that head, and one `
|
|
237
|
+
paths at that head, and one `dispatch message` on the issue; it must write no handoff or
|
|
242
238
|
rewrite the reviewer-approved head. When the implementer reports that it cannot
|
|
243
239
|
compute that body content or do the work a line of it affirms, that its read of the body failed or
|
|
244
240
|
came back empty, or that GitHub refused the body, it has pushed nothing and is still in its phase.
|
|
245
241
|
Answer it with `envoy_publish` to its role topic, saying how from the deployment instructions;
|
|
246
|
-
when they do not say, open a `
|
|
242
|
+
when they do not say, open a `dispatch ask` naming the missing instruction.
|
|
247
243
|
|
|
248
244
|
## 6. Architect sign-off and merge
|
|
249
245
|
|
|
@@ -276,7 +272,7 @@ The daemon keeps this order from its fixed table; you start none of its steps:
|
|
|
276
272
|
It drives the changed path in production through the user's own access path and records
|
|
277
273
|
what it saw on the pull request and on this issue. Sign off only after the implementer's production
|
|
278
274
|
report exists. A defect it finds is a corrective child issue of this tree, not a note on a
|
|
279
|
-
closed one; if the implementer cannot perform the deploy, it opens a `
|
|
275
|
+
closed one; if the implementer cannot perform the deploy, it opens a `dispatch ask` that starts
|
|
280
276
|
with the production gap and why it matters, then names the required step, its risk, and
|
|
281
277
|
outcome-named options. The issue waits for that answer.
|
|
282
278
|
|
|
@@ -299,12 +295,12 @@ This merge happens only when GitHub reports `CONFLICTING`
|
|
|
299
295
|
wake — `phase-finished`, `catch-up`, `checks-red`, `review-stuck` — because a `CONFLICTING`
|
|
300
296
|
PR gets no CI and no wake announces it. The moment you see it, tell the worker holding the issue's
|
|
301
297
|
phase (`envoy_publish` to its role topic) to move the issue back to `implementing` with
|
|
302
|
-
`request_backward_move`; in `awaiting_merge`, where no worker holds a phase, open a `
|
|
298
|
+
`request_backward_move`; in `awaiting_merge`, where no worker holds a phase, open a `dispatch ask`
|
|
303
299
|
naming the conflict for the human who merges. Do not let the merger send a READY packet for an
|
|
304
300
|
obsolete approval.
|
|
305
301
|
|
|
306
302
|
If a worker reports that `legion threads resolve` exited 1 naming a review thread GitHub refused
|
|
307
|
-
to resolve, open a `
|
|
303
|
+
to resolve, open a `dispatch ask` that names the thread's URL and GitHub's message for a human to
|
|
308
304
|
resolve it by hand, with options for resolved / could not; the merger does not complete while it
|
|
309
305
|
is open. That is the one review-thread step a human takes: the review App cannot resolve a thread
|
|
310
306
|
on a pull request the implementer opened, and the implementer's and merger's runs of the command
|
|
@@ -323,7 +319,9 @@ After the merge result and the implementer's production report are recorded, pos
|
|
|
323
319
|
close this issue with `sign_off`, which writes `done`:
|
|
324
320
|
|
|
325
321
|
```text
|
|
326
|
-
|
|
322
|
+
dispatch comment --issue LEGION-40 --body-file - <<'EOF'
|
|
323
|
+
<sign-off: scope, integration evidence, review, retro, merge, and the implementer's production report>
|
|
324
|
+
EOF
|
|
327
325
|
legion({ op: "sign_off", issue: "LEGION-40" })
|
|
328
326
|
```
|
|
329
327
|
|
|
@@ -346,10 +344,10 @@ active phase worker.
|
|
|
346
344
|
| `design-approved` | Its `version` is the approved one. A human approved the root spec document at its current version; the gate is open. Proceed to section 2. |
|
|
347
345
|
| `design-changes-requested` | Its `version` and `reason`. A human asked for changes to the root spec at `version`, for `reason`. Revise the spec as the reason asks and request approval again as section 1 says; stay parked; the gate is closed. |
|
|
348
346
|
| `phase-finished` | The daemon has already moved the issue to its next phase by its fixed table and started that phase's role; you start nothing. Read the committed handoff for the finishing phase; if it shows unresolved gaps, tell the role now working the issue (`envoy_publish` to its role topic). A `planner` notice that names a departure from the spec's design defers to section 1's full condition: when the approved Summary, Acceptance, scope and settled decisions still hold, the plan is the record; otherwise change the root spec and request approval again as section 1 says. A `reviewer` notice whose GitHub review is `CHANGES_REQUESTED` needs nothing from you: the daemon has returned the issue to `implementing` (Dispatch `in_progress`) and started the **implementer**, whose correction goes through the tester and the reviewer again, never straight to retro. A `reviewer` notice with an `APPROVED` review means the daemon has started retro (step 5). An `implementer` notice for `production_check` is its production report: read the record on the pull request and the issue, then run step 7. A `tester` notice with `verdict: "fail"` — its handoff carries `implementerProof.verdict: "rejected"`, or a failure naming the production-like proof — has gone back to the **implementer** by the daemon's table; never supply the proof from another role. A worker that reports no surface reaches the changed path sends that report instead of completing its phase, so the daemon starts nothing more on that issue and the worker stays idle in its session, not suspended: file a child issue in this tree to build the surface (infrastructure, tooling, or a skill), and when that child's `child-closed` arrives, tell the waiting worker to continue with `envoy_publish` to its role topic. That report is never a reason to advance the phase. |
|
|
349
|
-
| `pr-blocked` | Its `reason` names the pull request and the `max_fix_attempts` it reached. The count is of heads pushed onto a red verdict that changed something outside `.legion/` — handoff-only pushes (`.legion/` paths only) never count, a push by the review App (a planner's, tester's, reviewer's or architect's) never counts, and the head after a red the tester's red tests earned (a review-App push that changed a path outside `.legion/`, however many handoff-only pushes follow it) does not count either — so after the tester's handoff-only push onto the implementer's red, the implementer's next push does count; a push the daemon cannot classify (a listener without `changed_paths`, a list the listener stopped at 100 paths or 32,768 runes of text, a push listing no commits) does. Published once per exhausted count, not on every later red verdict for that count. Read the failed CI evidence and recovery attempts. The notice moves nothing: the issue stays in its phase
|
|
347
|
+
| `pr-blocked` | Its `reason` names the pull request and the `max_fix_attempts` it reached, or reads `Issue reached review_round_cap=<N>.` (the end of this row). The count is of heads pushed onto a red verdict that changed something outside `.legion/` — handoff-only pushes (`.legion/` paths only) never count, a push by the review App (a planner's, tester's, reviewer's or architect's) never counts, and the head after a red the tester's red tests earned (a review-App push that changed a path outside `.legion/`, however many handoff-only pushes follow it) does not count either — so after the tester's handoff-only push onto the implementer's red, the implementer's next push does count; a push the daemon cannot classify (a listener without `changed_paths`, a list the listener stopped at 100 paths or 32,768 runes of text, a push listing no commits) does. Published once per exhausted count, not on every later red verdict for that count. Read the failed CI evidence and recovery attempts. The notice moves nothing: the issue stays in its phase. In `implementing`, give the implementer the failing checks (`envoy_publish` to its role topic). In any later phase a worker holds, tell that worker (`envoy_publish` to its role topic) to move the issue back to `implementing` with `request_backward_move`, naming the failing checks, and the daemon starts the implementer; or file a corrective child. In `awaiting_merge`, where no worker holds a phase and a backward move is refused, open a `dispatch ask` naming the failing checks for the human who merges, as section 6 does for a conflict there. Do not treat the blocked PR as final. A `review_round_cap` reason is the implementer's round count instead: every move back to an earlier phase counts one, and the notice comes again with each round past the cap. It moves nothing either, since the round that reached the cap has already started its worker. Tell the rounds apart by what announced each: a tester's fail by its `phase-finished` with `verdict: "fail"`; a request for changes by the reviewer's `phase-finished` over a `CHANGES_REQUESTED` review; the daemon's own move by a `checks-red` notice, whose reason names either a conflict (`the head conflicts with <base>`) or the required checks that failed (`CI is red at <head>`); a worker's `request_backward_move` by a `phase-finished` from the role that asked, whose reason reaches only the task of the worker the move started, so ask that worker. Judge the cap by the rounds that are not conflicts. Conflict returns need nothing from you beyond the next round. Tester fails, requests for changes and CI-red returns (a `checks-red` notice is raised for CI only when a required check fails on code the branch pushed) are the work going in circles: narrow it, re-plan it with the responsible worker, or ask a human with `dispatch ask`. Judge a worker's backward move by the reason that worker gives. A move you ordered for a conflict found before `awaiting_merge` (section 6) is a conflict return. The merger's move back to `reviewing` because its task names no approved head is not the work going in circles either. A move that sends back code found wrong counts with the tester fails. |
|
|
350
348
|
| `pr-merged` | Its `reason` names the pull request. The PR merged, under the repository's rules, before the issue reached `awaiting_merge`. The workflow runs on and asks no one to merge it: the daemon starts the **implementer** on the production check once the issue gets there, and you start nothing. Its `phase-finished` for `production_check` is what brings you to step 7: verify the record on the pull request and this issue first, then sign off naming it with `sign_off`. A merge is not the close. |
|
|
351
349
|
| `pr-closed-unmerged` | Decide from current scope whether the work is reopened, started over (`park_child` then `rerun_child`, for a child), or ended with a reason. Delegate the repository action to the responsible phase worker and keep ownership. |
|
|
352
|
-
| A reply on an ask you follow | Interpret the reply in the issue's design context. Answer in its thread (`
|
|
350
|
+
| A reply on an ask you follow | Interpret the reply in the issue's design context. Answer in its thread (`dispatch comment --reply-to <comment id>`; under an open ask whose next move is yours, such as the approval request you must revise or hand back, `--reply-to-ask <ask id> --turn agent`, since a default-turn reply hands that request back to the human and a corrected `--summary` is then refused), then adjust the plan or relay it via `envoy_publish` to the responsible worker's role token; scope and product decisions remain with you. |
|
|
353
351
|
| `worker-died` | Its `role` and `phase`. That role's claim failed: its launches or prompts ran out. For a phase worker the daemon holds the issue (phase `held`) and starts nothing more on it. Reassess the work, then decide with `retry_or_escalate`: `retry` when the failure looks agent-specific or transient, `escalate` to hand the held issue to the controller when it looks environmental. |
|
|
354
352
|
| `held` | Its `role` and `phase` (the phase the issue left), or `phase` with `reason: "escalated"`. Without `reason`, that phase's worker ran out of launches or prompts: the issue is held (phase `held`), the `worker-died` that comes with it is yours to answer with `retry_or_escalate` as that row says, and the controller hears of the hold too. With `reason: "escalated"`, it records your own `escalate`: the controller has the issue now, and you start nothing for it. |
|
|
355
353
|
| `ready-refused` | Its `version` and `reason`. The merger's READY was refused, and its packet is kept with the completion so no second READY is ever needed. With `version` greater than 0, `reason` reads `READY refused: approve design version <N> before requesting READY.`: the root's spec is already registered at that version, so get it approved (section 1), and the daemon advances the merge and posts the kept packet the moment it is. With `version` 0, `reason` reads `READY refused: no design version is approved; register and approve the tree's spec before requesting READY.`: the root has no spec registered yet, so register it and get it approved (section 1) exactly as above; the daemon releases the kept packet the same way — at registration itself when that opens the gate (`gates.design: off`, or Dispatch already shows the version approved), otherwise the moment a human approves the version you registered. Either way, nothing else is needed once the gate opens. A `reason` starting `READY_PACKET_MISSING` names a READY refused before the daemon kept packets: that READY is void and the issue stays in merging, so start it over (`park_child` then `rerun_child`, for a child) or end it. |
|
|
@@ -361,14 +359,14 @@ cross-tree conflict. Report those to the controller with `envoy_publish` to the
|
|
|
361
359
|
your `Legion addressing` line names. Handle everything else in the
|
|
362
360
|
tree. A product, scope, or design decision that needs the human, yours or one a worker escalated,
|
|
363
361
|
is a decision block you write (section 1 says what one does to the root spec's gate). A standalone
|
|
364
|
-
human to-do may use `
|
|
362
|
+
human to-do may use `dispatch ask`; workers may reach the human directly with it the same way. Do not
|
|
365
363
|
create a wait loop for any wake source.
|
|
366
364
|
|
|
367
365
|
Never yield while waiting on a human. A human is waiting on you only where an open ask sits in
|
|
368
|
-
their inbox, so open it before you stop: a decision block in the spec, `
|
|
369
|
-
standalone human to-do, or `
|
|
366
|
+
their inbox, so open it before you stop: a decision block in the spec, `dispatch ask` for a
|
|
367
|
+
standalone human to-do, or `dispatch request-approval` for the spec gate. Otherwise proceed:
|
|
370
368
|
proceeding is the default, and a stop that waits on nobody stalls the tree until someone notices.
|
|
371
369
|
|
|
372
370
|
## Architecture components
|
|
373
371
|
|
|
374
|
-
Bootstrap on a root whose project has an architecture source: in the root's first PR (the implement worker pushes it), write `.dispatch/architecture/<id>.md` files for the planned components — front matter `title`, `parent`, `depends_on`, `external`; no `paths` yet. The importer reads the source branch's head, so the sync and the attach below work only once that PR has merged to the source branch: until then leave the root on `inherit` (the attach would answer `400 COMPONENTS_INPUT`, the component does not exist yet). After the merge, `
|
|
372
|
+
Bootstrap on a root whose project has an architecture source: in the root's first PR (the implement worker pushes it), write `.dispatch/architecture/<id>.md` files for the planned components — front matter `title`, `parent`, `depends_on`, `external`; no `paths` yet. The importer reads the source branch's head, so the sync and the attach below work only once that PR has merged to the source branch: until then leave the root on `inherit` (the attach would answer `400 COMPONENTS_INPUT`, the component does not exist yet). After the merge, run `dispatch architecture-sync --project <KEY>` and attach the root with `dispatch issue-update --issue <root> --components-json '{"mode":"explicit","ids":[…]}'`. Children inherit the root's attachment; give a child its own `--components-json` only when it changes a narrower set, and `{"mode":"none","reason":"…"}` when it is not architectural work. Attach before decomposing, and require every implementer to change the component file beside the code it describes in the same review.
|
|
@@ -108,9 +108,9 @@ else:
|
|
|
108
108
|
as the matching wake below. A parked tree (root phase `done`: it lingers or is closed) needs
|
|
109
109
|
nothing from you: a failed architect ignores the park and reads `failed` until the tree closes.
|
|
110
110
|
2. List the project's triage issues handed to Legion with
|
|
111
|
-
`
|
|
112
|
-
When its first line ends `(showing 1-250 of N)`, read the next page with
|
|
113
|
-
on until you have all N rows. The rows show no parent, so open each row with `
|
|
111
|
+
`dispatch issues --project <PROJECT> --status triage --label legion --limit 250 --offset 0`.
|
|
112
|
+
When its first line ends `(showing 1-250 of N)`, read the next page with `--offset 250`, and so
|
|
113
|
+
on until you have all N rows. The rows show no parent, so open each row with `dispatch read`
|
|
114
114
|
and follow `Links:` up through each `child_of` parent (a `child_of` under `Referenced by:` is a
|
|
115
115
|
child of this issue, not its parent). Leave a child that has an ancestor in `admission.active`
|
|
116
116
|
or `admission.waiting`: that tree's architect owns it. Triage every other row as a root,
|
|
@@ -137,8 +137,8 @@ only when you take it or file it for Legion, so the label means Legion has the i
|
|
|
137
137
|
A person's label is their decision: never take it off. A child needs no label: it runs under its
|
|
138
138
|
tree's architect once its root is admitted. `legion status <KEY> todo` admits a root, or a child
|
|
139
139
|
outside a live tree (admitted as a root of its own), only while it carries the label, so an issue
|
|
140
|
-
you hand over or file for Legion to run carries it first (`
|
|
141
|
-
`
|
|
140
|
+
you hand over or file for Legion to run carries it first (`--label` on `dispatch issue-update` or
|
|
141
|
+
`dispatch issue`). Taking the label off a waiting root drops it from the waiting line; taking it
|
|
142
142
|
off an admitted tree does not stop it.
|
|
143
143
|
|
|
144
144
|
## Trees waiting on a root claim (Go daemon)
|
|
@@ -147,7 +147,7 @@ A Go root architect whose claim on its root issue was refused starts nothing and
|
|
|
147
147
|
its slot, until the claim is free; nothing tells it when a session holder lets go without
|
|
148
148
|
replying. So every turn rechecks them ([Turn discipline](#turn-discipline)), the daemon's `tick`
|
|
149
149
|
included, which comes on its interval even with every slot taken: read each root in
|
|
150
|
-
`admission.active` whose `issues.<KEY>.phase` is still `admitted` with `
|
|
150
|
+
`admission.active` whose `issues.<KEY>.phase` is still `admitted` with `dispatch read`. When its
|
|
151
151
|
`Claimed by:` line is `nobody` or ends `· not running`, tell that tree's architect to claim again
|
|
152
152
|
with `envoy_publish` to `notifications.role.` followed by its claim token,
|
|
153
153
|
`issues.<KEY>.architect.locator.claim` in `legion state --json`. A claim that is its architect's
|
|
@@ -199,16 +199,16 @@ only labelled roots, so every root it ran since the daemon required the label ca
|
|
|
199
199
|
labelled root in `todo` is the daemon's to admit or queue, one in `triage` is yours to triage
|
|
200
200
|
(step 2 above), and one anywhere else was parked by Legion or by a person. A child you take becomes
|
|
201
201
|
a root of its own: the daemon admits a labelled `todo` child whose tree Legion does not run as a
|
|
202
|
-
new tree. The `
|
|
202
|
+
new tree. The `dispatch issues` rows show no labels and no children, so the listing below filters
|
|
203
203
|
neither: both are checked on each candidate (the table's first rows). List the `todo` issues one
|
|
204
|
-
priority at a time,
|
|
204
|
+
priority at a time, `--priority 0` first, then `1`, `2`, `3`, and `none` (no priority)
|
|
205
205
|
last, keeping the listing's order within each, which is the board's rank:
|
|
206
206
|
|
|
207
207
|
```text
|
|
208
|
-
|
|
208
|
+
dispatch issues --project <PROJECT> --status todo --priority 0 --limit 250 --offset 0
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
-
When the first line ends `(showing 1-250 of N)`, the next page is
|
|
211
|
+
When the first line ends `(showing 1-250 of N)`, the next page is `--offset 250`, then `500`. Read
|
|
212
212
|
pages only as far as you need: stop listing once the free slots are filled. `<PROJECT>` is the
|
|
213
213
|
Dispatch project key, the prefix of this deployment's issue keys (`PROJ-12` → `PROJ`), which is
|
|
214
214
|
also `daemon.project` in `legion state --json`: the project key exactly as `legion.yaml` writes it.
|
|
@@ -217,14 +217,14 @@ the row shows one, comes after the claim) is claimed, as the table below says: s
|
|
|
217
217
|
reading it.
|
|
218
218
|
|
|
219
219
|
**Walk.** Take the remaining rows in that order until the free slots are filled. Read each one with
|
|
220
|
-
`
|
|
220
|
+
`dispatch read --issue <KEY>` and skip it when any of these holds. `dispatch read` shows only
|
|
221
221
|
the issue's last 10 events, so the rows that read `Events:` are best-effort: the pull-request row
|
|
222
222
|
leans on `External links:`, and the label row is the one that never depends on history.
|
|
223
223
|
|
|
224
224
|
| Skip when | How you check it |
|
|
225
225
|
|---|---|
|
|
226
226
|
| It carries the `legion` label | `Labels:` lists `legion`, in any case. Legion has the issue or had it, as **Candidates** above says. |
|
|
227
|
-
| It has any child | `
|
|
227
|
+
| It has any child | `dispatch read --ref dispatch://<KEY>/children` lists any child, open or `done`. It is an umbrella, and a finished umbrella is still no leaf. That also skips an issue whose only child is done, which is accepted. Its open children are candidates themselves, each in its own place in the order. |
|
|
228
228
|
| An ancestor is Legion's | Follow `Links:` up through each `child_of` parent, reading each one, and skip when any ancestor carries the `legion` label or is recorded under `issues` in `legion state --json`, whatever its status: a Legion tree, running or parked, owns its children. An ancestor's claim or route does not skip the issue: a coordinator holding an umbrella files `todo` leaves for others to pick up, and the claim on the issue itself is what keeps two sessions off the same work. A `child_of` under `Referenced by:` is a child of this issue, not its parent. |
|
|
229
229
|
| Someone is designing it | `Open asks:` lists any ask, a `Spec approval: awaiting …` line shows the spec waits on a human, or `Events:` show an `artifact.version` or an `ask.opened` from the last seven days: a session or a person is shaping it even when nobody claims or routes it. |
|
|
230
230
|
| Legion ran it without the label now on it | `legion state --json` records it under `issues`, whatever its status, or `Events:` show a status write by `session legion-daemon:<PROJECT>`, the daemon's actor on every `legion status` (yours included) and on its own `in_progress` at admission. That covers a root a person took the label off, and one that ran before the daemon required the label and never had it. Name each one you skip for this in your summary. The walk never sends a root Legion already ran back into Legion: a person does that with the label and `todo`, and you do it only when a wake below says to (`worker-died`). |
|
|
@@ -232,15 +232,15 @@ leans on `External links:`, and the label row is the one that never depends on h
|
|
|
232
232
|
| Its route reaches a running session | `Route:` names a route with nothing after it, or with `(held by …)`. `(nobody holds it right now)` and `(that session is not running right now)` reach nobody; `(the Envoy listener did not answer, …)` counts as reaching someone. `Route: none` is free. |
|
|
233
233
|
| A pull request is linked or named | `External links:` lists a pull request (kind `github_pr`, or a URL ending `/pull/<n>`), or a comment or message among `Events:` names one. You cannot read GitHub, so an open, merged, or closed pull request all count. A person who wants Legion on it anyway hands it over themselves: the label, then `todo`. |
|
|
234
234
|
| Its assignee is working it | `Assignee:` names a person who holds the claim (the row above), or whose own comment or message among `Events:` says they are working on it. The assignee alone is who answers the issue's questions, not who works it. |
|
|
235
|
-
| It is outside this deployment's scope | Read the scope the deployment instructions state against the title and, when the title does not settle it, the spec (`
|
|
235
|
+
| It is outside this deployment's scope | Read the scope the deployment instructions state against the title and, when the title does not settle it, the spec (`dispatch doc-read --issue <KEY>`). When in doubt, skip it. With no scope stated, every issue of the project is in scope. |
|
|
236
236
|
|
|
237
237
|
**Take.** For each candidate that passes, in order:
|
|
238
238
|
|
|
239
|
-
1. Add the label and keep the labels it has, which `Labels:` lists (`none` is no labels).
|
|
240
|
-
|
|
239
|
+
1. Add the label and keep the labels it has, which `Labels:` lists (`none` is no labels). The
|
|
240
|
+
`--label` flags replace the whole set, so a label you leave out is removed.
|
|
241
241
|
|
|
242
242
|
```text
|
|
243
|
-
|
|
243
|
+
dispatch issue-update --issue <KEY> --label <each current label> --label legion
|
|
244
244
|
```
|
|
245
245
|
|
|
246
246
|
2. It is already in `todo`, so the label admits it: the daemon records it and gives it the free
|
|
@@ -250,7 +250,9 @@ leans on `External links:`, and the label row is the one that never depends on h
|
|
|
250
250
|
step 4 gives (which follows the design gate policy):
|
|
251
251
|
|
|
252
252
|
```text
|
|
253
|
-
|
|
253
|
+
dispatch comment --issue <KEY> --body-file - <<'EOF'
|
|
254
|
+
Legion took this issue: it was the highest-priority open issue nobody else was working on. Assigned to <login>, who will get this tree's questions and its design approval. To stop Legion, move the issue to backlog. To keep Legion off it for good, also take the legion label off; taking the label off alone does not stop a tree that has started.
|
|
255
|
+
EOF
|
|
254
256
|
```
|
|
255
257
|
|
|
256
258
|
The daemon admits each root when Dispatch's event reaches it; the next `legion state --json`
|
|
@@ -264,28 +266,32 @@ change and why, and what is running.
|
|
|
264
266
|
|
|
265
267
|
**Where.** On the issue the deployment instructions name for Legion's reports. With none named,
|
|
266
268
|
on the project's `Legion daily report` issue:
|
|
267
|
-
`
|
|
269
|
+
`dispatch search --query '"Legion daily report"' --project <PROJECT>` finds it. When it
|
|
268
270
|
does not exist, create it once and park it in `icebox`, so nobody takes it as work; it never
|
|
269
271
|
carries the `legion` label:
|
|
270
272
|
|
|
271
273
|
```text
|
|
272
|
-
|
|
274
|
+
dispatch issue --project <PROJECT> --title 'Legion daily report' --spec-file - <<'EOF'
|
|
275
|
+
## Summary
|
|
276
|
+
|
|
277
|
+
Legion's controller posts one message here each day: what Legion finished, what it closed without a change and why, and what is running. This issue is not work, so it carries no `legion` label and stays in icebox.
|
|
278
|
+
EOF
|
|
273
279
|
legion status <report KEY> icebox
|
|
274
280
|
```
|
|
275
281
|
|
|
276
282
|
**When.** On your first turn of each UTC day, whatever it is: your start, or a wake of any kind.
|
|
277
283
|
While you are registered, the daemon's `tick` gives you a turn at least every
|
|
278
284
|
`controller_wake_interval_seconds`. After the turn's own work, read the report issue with
|
|
279
|
-
`
|
|
285
|
+
`dispatch read`, and post when its `Events:` show no `message.created` from today.
|
|
280
286
|
|
|
281
|
-
**What.** One `
|
|
287
|
+
**What.** One `dispatch message --issue <report KEY> --body-file -` of at most 2,000 characters,
|
|
282
288
|
written as `skill://dispatch`'s "Writing for the human" says: every issue by its key and title,
|
|
283
289
|
every pull request by its URL.
|
|
284
290
|
|
|
285
|
-
- **Finished.** `
|
|
286
|
-
previous report's time, or 24 hours ago>
|
|
291
|
+
- **Finished.** `dispatch issues --project <PROJECT> --status done --updated-since <the
|
|
292
|
+
previous report's time, or 24 hours ago> --limit 250`, read every page, and keep the issues
|
|
287
293
|
`legion state --json` records under `issues` whose `issue.closed` event is after the previous
|
|
288
|
-
report. For each, `
|
|
294
|
+
report. For each, `dispatch read` it: the pull request under `External links:` is the one that
|
|
289
295
|
merged.
|
|
290
296
|
- **Closed without a change.** Those with no pull request, each with the reason its closing
|
|
291
297
|
message gave (the `message.created` just before `issue.closed` among `Events:`).
|
|
@@ -326,7 +332,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
|
|
|
326
332
|
relevant Dispatch issue. A stale or duplicate wake may cost a read, never a wrong action.
|
|
327
333
|
- **Controller state is disposable.** Do not reconstruct or preserve local controller
|
|
328
334
|
bookkeeping between turns.
|
|
329
|
-
- **Write for a human.** Every `
|
|
335
|
+
- **Write for a human.** Every `dispatch comment`, `dispatch message`, and `dispatch ask` you
|
|
330
336
|
post follows `skill://dispatch`'s "Writing for the human" rules: plain sentences, every
|
|
331
337
|
identifier expanded on first use, no coined shorthand. A triage note that reads like a log
|
|
332
338
|
line is not a triage note.
|
|
@@ -339,7 +345,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
|
|
|
339
345
|
| `slot-free on <KEY>` from the Go daemon (payload `{kind: "slot-free"}`) | the root whose slot the daemon released with no waiting root to take it | Verify a free slot in `legion state --json`, then fill it ([Keeping the slots full](#keeping-the-slots-full-go-daemon)) |
|
|
340
346
|
| `todo on <KEY>` from the Go daemon (payload `{kind: "todo"}`) | an issue not handed to Legion that changed while in `todo` and a slot stood free, sent half a minute later | Verify a free slot, then walk the whole `todo` list ([Keeping the slots full](#keeping-the-slots-full-go-daemon)) |
|
|
341
347
|
| `tick on <PROJECT>` from the Go daemon (payload `{kind: "tick", openCapabilities?: [<name>, …]}`) | the project key; the daemon's periodic wake, whatever the slots; `openCapabilities` names the deployment capabilities with no decision, each with its detail and `capabilities.decided.<name>` line under `capabilities` in `legion state --json` | Recheck the trees waiting on a claim, then walk if a slot is free — a gap never stops the walk; post the day's report if this is the day's first turn, naming each open capability in it (the operator closes or decides it) |
|
|
342
|
-
| Architect escalation (controller-actionable only: re-file a child as a root issue, capacity, cross-tree conflicts) | request + context | Judge and act; the owning architect writes an issue-design decision as a decision block and opens `
|
|
348
|
+
| Architect escalation (controller-actionable only: re-file a child as a root issue, capacity, cross-tree conflicts) | request + context | Judge and act; the owning architect writes an issue-design decision as a decision block and opens `dispatch ask` only for a human to-do |
|
|
343
349
|
| Mention | Slack/GitHub PR @mention text | Answer, or route to the owning issue's architect role |
|
|
344
350
|
| `held on <KEY>` from the Go daemon (payload `{kind: "held", phase, role?, reason?}`) | the held issue, the phase it left, and the role whose claim failed, or `reason: "escalated"` | Verify the hold in `legion state` (the issue's phase is `held`). Without `reason`, a phase worker's launches or prompts ran out and the tree's architect decides retry or escalate: no action. With `reason: "escalated"` (on the record, `issues.<KEY>.holdReason` is `escalated`), the architect sent it to you: handle it as an architect escalation below. Parking the tree is `legion status <root> backlog`; setting the root back to `todo` later re-admits it as a new generation, which starts again from its architect |
|
|
345
351
|
| `worker-died on <KEY>` from the Go daemon with `role: "architect"` | the tree root whose architect's claim failed, and the phase the root was in | The tree's architect ran out of launches or prompts and the daemon relaunches nothing; every other notice of the tree goes to that architect, so nobody inside the tree can act. Verify in `legion state` (`issues.<KEY>.architect.state` is `failed`); if the root's phase is `done`, the tree is already parked: no action. Otherwise re-admit the tree (`legion status <root> backlog`, then `todo`: a new generation, whose architect starts again with fresh budgets) or leave it parked and say why on the issue |
|
|
@@ -347,7 +353,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
|
|
|
347
353
|
|
|
348
354
|
## New issue triage
|
|
349
355
|
|
|
350
|
-
1. Read `legion state --json`, then inspect the reported Dispatch issue with `
|
|
356
|
+
1. Read `legion state --json`, then inspect the reported Dispatch issue with `dispatch read`.
|
|
351
357
|
Verify the issue is in this project, is eligible for a root process, and whether it
|
|
352
358
|
has pre-existing children. Dispatch and daemon state, not the wake text, decide triage.
|
|
353
359
|
Note the `Assignee:` line: that human answers the tree's asks, and their Inbox opens on
|
|
@@ -371,7 +377,7 @@ priority first, then board rank ([Keeping the slots full](#keeping-the-slots-ful
|
|
|
371
377
|
place. A root never waits for capacity in `backlog`: in `todo` the
|
|
372
378
|
daemon's admission queue holds it (`admission.waiting`), so park only a root that should not
|
|
373
379
|
run now. Do not triage a system-created child as a root issue.
|
|
374
|
-
4. When you post a triage note (a `
|
|
380
|
+
4. When you post a triage note (a `dispatch comment` on the issue saying what you decided and
|
|
375
381
|
why), name who will be asked with the assignee sentence: `Assigned to <login>, who will get
|
|
376
382
|
this tree's questions and its design approval`, or, when the `Assignee:` line says
|
|
377
383
|
`unassigned`, `Unassigned — nobody's Inbox shows this tree's questions or its design approval
|
|
@@ -396,14 +402,14 @@ or when a wake tells you to re-admit it (`worker-died`).
|
|
|
396
402
|
|
|
397
403
|
Only decide controller-actionable escalations: re-filing independent work, capacity, and
|
|
398
404
|
cross-tree conflicts. The owning architect writes an issue-design decision as a decision block and
|
|
399
|
-
uses `
|
|
405
|
+
uses `dispatch ask` only for a human to-do, not the controller.
|
|
400
406
|
|
|
401
407
|
For an independence judgment, verify the child and its parent against current daemon state
|
|
402
408
|
and the Dispatch issue. If the work belongs in an independent root:
|
|
403
409
|
|
|
404
|
-
1. File a **fresh root issue** with `
|
|
405
|
-
add
|
|
406
|
-
|
|
410
|
+
1. File a **fresh root issue** with `dispatch issue --project <KEY> --title '<title>' --spec-file -`
|
|
411
|
+
(no `--parent`; add `--label legion`, without which it is never admitted).
|
|
412
|
+
`--project` is the issue key's prefix before `-<n>` (e.g. `LEGSMOKE-3` → `LEGSMOKE`): the
|
|
407
413
|
project key exactly as `legion.yaml` writes it, which `legion state --json` shows as
|
|
408
414
|
`daemon.project`. It is not the lowercase project token in role names such as
|
|
409
415
|
`legion-<project>-controller`.
|
|
@@ -36,7 +36,7 @@ retrospective's durable output.
|
|
|
36
36
|
and records it on the PR and the issue: the agent that developed it is responsible for testing
|
|
37
37
|
in production. The architect's sign-off waits for that record.
|
|
38
38
|
The record is the pull request's `Production:` line, one pull-request comment, and a
|
|
39
|
-
`
|
|
39
|
+
`dispatch message` on the issue, each naming what was driven, how, what was observed, and the
|
|
40
40
|
merge commit. A defect the production check finds becomes a corrective child issue of the same tree,
|
|
41
41
|
owned by the architect and implemented by the same implementer; the parent stays open until it lands.
|
|
42
42
|
|
|
@@ -157,16 +157,15 @@ Then push both commits with one `legion push`, so one CI run covers them. When t
|
|
|
157
157
|
refused after step 4 wrote the body, write `<dir>/before.md` back the same way before you report
|
|
158
158
|
the refusal to the architect, so the body matches the head GitHub has. After the push, post one
|
|
159
159
|
Dispatch message on
|
|
160
|
-
the issue —
|
|
160
|
+
the issue — `--issue` is your `LEGION_ISSUE`; Legion issues live on Dispatch, never on a GitHub
|
|
161
161
|
issue, and the `gh` shim refuses every GitHub-issue write — naming the documents, the
|
|
162
162
|
one-to-three most useful takeaways, the two proofs you read, and the production check that
|
|
163
163
|
follows the merge. The message must carry this revived implementer's structured
|
|
164
164
|
attribution footer with `phase` set to `retro`; the body is capped at 2,000 characters:
|
|
165
165
|
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
body: `## Retro Complete
|
|
166
|
+
```bash
|
|
167
|
+
dispatch message --issue <KEY> --body-file - <<'EOF'
|
|
168
|
+
## Retro Complete
|
|
170
169
|
|
|
171
170
|
**Learnings documented in:**
|
|
172
171
|
- docs/solutions/<path>.md
|
|
@@ -178,8 +177,8 @@ dispatch_message({
|
|
|
178
177
|
|
|
179
178
|
**Production check:** <what the implementer will drive after the merge, or the deploy/restart step a human will have to perform first>
|
|
180
179
|
|
|
181
|
-
<!-- legion: {"session":"<session-id>","phase":"retro"}
|
|
182
|
-
|
|
180
|
+
<!-- legion: {"session":"<session-id>","phase":"retro"} -->
|
|
181
|
+
EOF
|
|
183
182
|
```
|
|
184
183
|
|
|
185
184
|
The `docs/solutions/` commit, the removal of `.legion/<issue>/`, the PR body lines those commits
|
|
@@ -66,7 +66,7 @@ above), carrying the verified facts and the decision needed. A `write` to `agent
|
|
|
66
66
|
agents inside your own process, not the architect's separate one. Never write a decision block
|
|
67
67
|
into a spec yourself: the architect decides whether the human must answer it and writes the block,
|
|
68
68
|
since a new version of an approved root spec closes the tree's design gate. A standalone to-do
|
|
69
|
-
only a human can do is a `
|
|
69
|
+
only a human can do is a `dispatch ask`, and its replies return to your own session.
|
|
70
70
|
|
|
71
71
|
Because the same agent works its role until the issue closes, you may receive more than one
|
|
72
72
|
assignment across your lifetime: your session stays live after your phase ends, and when a later
|
|
@@ -228,7 +228,7 @@ subcommand's `comment`, `create`, `edit`, `close`, `reopen`, `delete`, `pin`, `u
|
|
|
228
228
|
`lock`, `unlock`, and `develop`, and any raw `gh api` call to an `/issues` path whose method is not
|
|
229
229
|
GET (an explicit `-X`, or the POST that `-f`/`-F`/`--input` imply; pull-request conversation
|
|
230
230
|
comments live on that path too, so edit them with `gh pr comment`) — printing
|
|
231
|
-
|
|
231
|
+
``Legion issues live on Dispatch; use `dispatch message` or `dispatch comment` on <your LEGION_ISSUE>``:
|
|
232
232
|
Legion never reads or writes a GitHub issue. `pr comment`, `pr review`,
|
|
233
233
|
`api …/pulls/…`, `api graphql`, and issue reads are unaffected. The credential reaches `legion`
|
|
234
234
|
through the file `$LEGION_GRANT_FILE` names, written by the extension before each of your bash
|
|
@@ -488,6 +488,6 @@ decision required.
|
|
|
488
488
|
|
|
489
489
|
Never yield while blocked on a decision someone else owns. Before you stop, make the block visible
|
|
490
490
|
where its owner will see it: a product, scope, design, lifecycle, or cross-phase decision goes to
|
|
491
|
-
the owning architect as above, and a standalone human to-do goes in `
|
|
491
|
+
the owning architect as above, and a standalone human to-do goes in `dispatch ask`. Otherwise
|
|
492
492
|
proceed: proceeding is the default, and a phase that stops silently holds its issue until someone
|
|
493
493
|
notices.
|
|
@@ -96,7 +96,7 @@ review posted without a completion leaves the issue in reviewing until you finis
|
|
|
96
96
|
`; ` on the one READY line, or `none` — quoted from the `## For the reviewer` block at that same
|
|
97
97
|
head (or one line saying the body carries no brief — the packet still goes out), then the
|
|
98
98
|
`--summary` output and the PR body's gate facts. The merger sends it as the `summary` of its
|
|
99
|
-
`handoff_complete` with `ready: true`; the daemon posts it as a `
|
|
99
|
+
`handoff_complete` with `ready: true`; the daemon posts it as a `dispatch message` on the issue,
|
|
100
100
|
publishes it to the project's merge queue role when one is set, and says on the issue when that
|
|
101
101
|
role has no live holder. The READY packet names both the implementer's and tester's `E2E` lines;
|
|
102
102
|
a missing one is reported to the architect instead of completing. Legion never merges.
|
|
@@ -111,10 +111,10 @@ review posted without a completion leaves the issue in reviewing until you finis
|
|
|
111
111
|
this, since a staging gate does not run every resource production does. If the slot fails on
|
|
112
112
|
the change, the implementer owns the fix and the next slot.
|
|
113
113
|
The record has three places: the PR body's `Production:` line, one pull-request comment
|
|
114
|
-
carrying the Legion footer, and a `
|
|
114
|
+
carrying the Legion footer, and a `dispatch message` on the issue — the reviewer and merger
|
|
115
115
|
read GitHub, the architect reads the issue. When the deploy that carries the merge has not
|
|
116
116
|
happened (a shared profile still holding the previous plugin release, a daemon still running
|
|
117
|
-
the previous commit, a slot nobody has run), open a `
|
|
117
|
+
the previous commit, a slot nobody has run), open a `dispatch ask` that starts with the
|
|
118
118
|
production gap and why it matters, then names the required install or restart step, its risk,
|
|
119
119
|
and outcome-named options. Keep the `Production:` line at `pending <what is missing>`, and
|
|
120
120
|
complete the check once the human answers. Never record a staging pass as the production check,
|