@sjawhar/claude-envoy 1.2.0 → 1.3.1
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/.claude-plugin/plugin.json +1 -1
- package/.omp-plugin/plugin.json +1 -1
- package/dist/envoy-channel.js +4 -2
- package/legion/skills/legion-architect/SKILL.md +5 -4
- package/legion/skills/legion-architect/references/acceptance.md +17 -11
- package/legion/skills/legion-architect/references/decomposition.md +7 -1
- package/legion/skills/legion-architect/references/design-gate.md +8 -4
- package/legion/skills/legion-architect/references/wake-routing.md +3 -2
- package/legion/skills/legion-controller/SKILL.md +7 -4
- package/legion/skills/legion-controller/references/admission.md +16 -10
- package/legion/skills/legion-controller/references/backlog-stewardship.md +7 -5
- package/legion/skills/legion-controller/references/daily-report.md +11 -8
- package/legion/skills/legion-controller/references/escalation.md +4 -2
- package/legion/skills/legion-controller/references/finding-asks.md +5 -3
- package/legion/skills/legion-controller/references/parked-decisions.md +4 -5
- package/legion/skills/legion-controller/references/session.md +5 -3
- package/legion/skills/legion-controller/references/slack-mentions.md +3 -1
- package/legion/skills/legion-controller/references/triage.md +4 -3
- package/legion/skills/legion-controller/references/wakes.md +14 -8
- package/legion/skills/legion-retro/SKILL.md +4 -3
- package/legion/skills/legion-worker/SKILL.md +1 -2
- package/legion/skills/legion-worker/references/conflicts-and-rewrites.md +4 -11
- package/legion/skills/legion-worker/references/merge-gate.md +10 -8
- package/package.json +2 -2
package/.omp-plugin/plugin.json
CHANGED
package/dist/envoy-channel.js
CHANGED
|
@@ -51316,6 +51316,7 @@ var legionIssue = object({
|
|
|
51316
51316
|
generation: number2().int().nonnegative(),
|
|
51317
51317
|
phase: _enum2(LEGION_PHASES),
|
|
51318
51318
|
status: nonEmptyString,
|
|
51319
|
+
tree: issueKey.optional(),
|
|
51319
51320
|
repo: nonEmptyString.optional(),
|
|
51320
51321
|
defaultBranch: nonEmptyString.optional(),
|
|
51321
51322
|
holdReason: literal("escalated").optional(),
|
|
@@ -51345,6 +51346,7 @@ var legionAdmission = object({
|
|
|
51345
51346
|
cap: number2().int().nonnegative(),
|
|
51346
51347
|
active: array(nonEmptyString),
|
|
51347
51348
|
waiting: array(nonEmptyString),
|
|
51349
|
+
trees: array(issueKey).optional(),
|
|
51348
51350
|
blocked: array(legionBlockedIssue),
|
|
51349
51351
|
free: number2().int().nonnegative().optional()
|
|
51350
51352
|
});
|
|
@@ -54334,9 +54336,9 @@ var import_nats2 = __toESM(require_mod4(), 1);
|
|
|
54334
54336
|
|
|
54335
54337
|
// package.json
|
|
54336
54338
|
var name = "@sjawhar/claude-envoy";
|
|
54337
|
-
var version2 = "1.
|
|
54339
|
+
var version2 = "1.3.1";
|
|
54338
54340
|
var legion = {
|
|
54339
|
-
daemonApiVersion:
|
|
54341
|
+
daemonApiVersion: 51
|
|
54340
54342
|
};
|
|
54341
54343
|
|
|
54342
54344
|
// src/channel-forwarder.ts
|
|
@@ -13,7 +13,7 @@ You own one issue tree from its first decision to the merge that closes it. The
|
|
|
13
13
|
|
|
14
14
|
- Act on delivered wakes and the live artifacts they name; build no wait loop, since every wake reaches you.
|
|
15
15
|
- Check each claim against the code as fetched now (the default branch your addressing line names, or the head under review), never the workspace as it was at admission, and tell every fresh reader you dispatch to do the same: the branch may have moved since.
|
|
16
|
-
- Before you end a turn that waits on a human, open what they must answer: a decision block, a `dispatch ask` or `dispatch request-approval`. A turn that ends with nothing open asks nobody, and the tree stops. Open an ordinary ask on the root issue itself, never a child: only a question a session of this tree opens on the root starts a wait on a person, so an ask on a child
|
|
16
|
+
- Before you end a turn that waits on a human, open what they must answer: a decision block, a `dispatch ask` or `dispatch request-approval`. A turn that ends with nothing open asks nobody, and the tree stops. Open an ordinary ask on the root issue itself, never a child: only a question a session of this tree opens on the root starts a wait on a person, so an ask on a child starts no wait and leaves the tree standing still. Once you have handed a root question to the human, end your turn: when nothing else of the tree is at work — no other issue of the tree in a phase, the `legion` label still on, and no person or outside session holding the root's Dispatch claim — the root returns its admission slot (`awaiting_person`) while this session stays live. Read the human's comments and replies as they arrive. Their answer gives this live claim a task naming what answered and what is still with them. The same holds once you request approval and `register_gate` that version: the registration hands the spec to the human, so end your turn there too, and the human's review, or a newer version once Dispatch shows the request back on your turn, gives you that task.
|
|
17
17
|
- Deliver every criterion of the root spec in this tree. Work leaves it only when a root splits, as a `dispatch ask` for the rest: work outside has no owner.
|
|
18
18
|
- A problem outside the tree is a `dispatch ask`, never an issue you file, because a person decides whether it needs one (`skill://legion-worker/references/findings.md`). A clear defect is the exception. Fix one in code this tree touches or depends on in this tree's pull request. Send any other to the controller, which gives it to the tree that owns that code.
|
|
19
19
|
- Before you write a spec or ask a person anything, read the repository's `STRATEGY.md` when it has one, then use a standard best-practice solution; ask only what neither settles, with one recommendation. A design that crosses a Boundary in that file goes to its owner before it is built. Find the standard with a web search and with how two or three well-regarded projects solve the problem. Cite them in a few lines of the spec's `Design`. A design far from the standard is a sign to fix the underlying problem, not to add a workaround.
|
|
@@ -30,6 +30,7 @@ You own one issue tree from its first decision to the merge that closes it. The
|
|
|
30
30
|
- Every child names the running system its criteria are proven on (the command, service or page the tester drives) and the repository skill that drives it. If the repository cannot exercise a criterion end to end, building that path is work of this tree.
|
|
31
31
|
- The issue's primary document is the root spec: extend it in place, because a second "spec" artifact replaces the human's document. Mark each requirement of it as a `requirement` block, and write the issue's Verification document (`verification.md`) beside it: one `check` block per thing that must be proved, each with `serves` naming the requirements it serves, its `surface` (`browser`, `cli` or `api`), its `run`, its `when` (`before_merge`, `after_merge` or `default_branch`) and its `negative_control`. The checks are the gate every later role reads: the implementer and the tester record a result against each, and the reviewer approves only once every `before_merge` check of the issue has a passing result current at the head. The waves and the plan's tasks go in the children and the planner's `plan` handoff, not the root spec.
|
|
32
32
|
- Read `skill://legion-architect/references/design-gate.md` before you write the root spec and before any edit to it after approval, because any new version closes the gate. It also says which gate runs, and that a sub-architect runs none.
|
|
33
|
+
- File every child of your decomposition before `dispatch request-approval`, and before `register_gate` under `gates.design: off`: the gate's opening starts your root's own first phase unless Dispatch shows an open child under it, so a child filed after it opens leaves the root working beside its children.
|
|
33
34
|
- A root architect then ends its turn and releases no wave until a delivered wake shows `design-approved`: the daemon starts no phase in the tree before it. A root that waited on a person's answer gets no `design-approved` notice: a resume task saying "this resume is your design-approved wake" is that wake. A sub-architect waits for none and releases its children with `release_children`.
|
|
34
35
|
|
|
35
36
|
## 2. Children in flight
|
|
@@ -38,13 +39,13 @@ You own one issue tree from its first decision to the merge that closes it. The
|
|
|
38
39
|
- Release every child as soon as it is filed, a later wave's included, each with `--blocked-by` the children it builds on, and never hold a release back for a close: a released child, held or running, keeps the root's close waiting, but once the root's own pull request has merged the root closes the moment its last released child leaves, and a child released after that finds no live tree and runs as an orphan root of its own.
|
|
39
40
|
- On each `child-closed`, read the child's handoff. Edit the spec of each open child the result changes, and take out each child it makes unneeded with `park_child` and say why with `dispatch comment`.
|
|
40
41
|
- Before you park a child for good (one made unneeded, or parked so its tree can finish), set the `--blocked-by` list of each sibling that waits on it again without it (one call with the rest of its list, or `--clear-blocked-by` when it was the only one), or park that sibling too: a parked child is stopped, not done, and its dependents stay held with no notice. A park followed by `rerun_child` keeps its dependents' links: they wait through the rerun and start when the rerun's merge closes the child.
|
|
41
|
-
- A released child
|
|
42
|
+
- A released child holds an admission slot of its own while a worker of it has work, and waits in the admission line for one, so a tree of four working issues holds four of the cap's issues. It never becomes a root while your tree is live.
|
|
42
43
|
- A root that waited in the admission queue, never ran and never left another tree joins your tree once a person makes it your child, if it is `todo`, and otherwise at your release of it (the `child-status` row of [wake routing](skill://legion-architect/references/wake-routing.md)); once in, it is held for its blockers like any child you release. A root that left another tree, handed over by its finished tree or admitted as an orphan, stays its own tree and never joins yours, even one that was your root's child before your root was admitted again. A labelled `todo` issue under a child you have not released, unless it ran as a tree of its own or left another tree, is held under that unreleased child (not a blocked-by hold): it waits for no slot until your release of it or of that child brings it in, with any `todo` child of its own.
|
|
43
44
|
- A release that cannot take a child in is refused 409 and writes nothing, its message naming the child and why: release the rest of the wave again without it. `CHILD_NOT_ADOPTABLE` is an issue that runs or ran as a tree of its own, carries a run handed over to it, or was handed over (or admitted as an orphan) as a root of its own: leave it there, or ask the controller. `CHILD_IN_OTHER_TREE` is another tree's child. When the tree it names is a root held under an unreleased child of yours (a root that queued and never ran, so it has no architect of its own), release that root, or the unreleased child it sits under, instead: its children come with it. Otherwise re-parent the child back in Dispatch, or ask that tree's architect or the controller.
|
|
44
45
|
|
|
45
46
|
## 3. Children complete
|
|
46
47
|
|
|
47
|
-
No notice marks the last child's close.
|
|
48
|
+
Your issue's own first phase does not start while Dispatch shows an open child under it, one you filed and have not released included: the daemon tells you once per issue and run of its tree with a `children-first` notice naming each open child and the Dispatch status that holds it, and starts the parent at its next admission slot once the last of them has left the workflow, closed, gone to `icebox`, or been moved out from under it, to another parent or to none. So file and release the whole wave at once, and park what should not run. No notice marks the last child's close. A child filed after your issue started runs beside it, and the daemon refuses the parent's `sign_off` while that child is in the workflow: run the parent's last round (section 4) so its head carries the child's merge.
|
|
48
49
|
|
|
49
50
|
## 4. Integration verification
|
|
50
51
|
|
|
@@ -66,7 +67,7 @@ The reviewer's `phase-finished` with an `APPROVED` review puts the issue in `acc
|
|
|
66
67
|
|
|
67
68
|
Accept only when every `before_merge` check of the issue's own Verification document has a passing result that is current at the approved head, every requirement the spec marks has a check (`dispatch read --issue <issue>` names each one that has none), and no criterion left the tree; on a parent, that head is section 4's last round. The issue's own checks at the issue's own head are the whole gate: a child's result against one of your checks proves nothing for you, because a child's pull request never makes a root check's result current. A child that carries part of a root requirement proves it with a check on the child's own Verification document whose `serves` names that requirement, which clears the root's coverage flag for it. An issue with no Verification document, or with no `before_merge` check, is a gap the tester and the reviewer name and neither refuses, so your acceptance is the only gate on it: name that gap in your acceptance comment and decide there, accepting the issue or sending it back with the checks you write yourself, which closes no design gate while dispatch://INFRA-175 has not shipped. A finding ask on the issue holds the acceptance until it is resolved or carries the controller's reply (`skill://legion-architect/references/acceptance.md`). Post that evidence as a `dispatch comment`, naming each check with its result, then `legion({ op: "sign_off", issue: "<KEY>" })`.
|
|
68
69
|
|
|
69
|
-
- `sign_off` works only in `accepting` (`SIGNOFF_OUTSIDE_ACCEPTING`)
|
|
70
|
+
- `sign_off` works only in `accepting` (`SIGNOFF_OUTSIDE_ACCEPTING`), and the daemon refuses it while an issue beneath it is still in the workflow (`SIGNOFF_CHILD_IN_WORKFLOW`, naming each one), so a parent is accepted after its children, on the head of its last round (section 4).
|
|
70
71
|
- When a check has no current passing result, or its result contradicts what you read: `request_backward_move` with `issue`, `to` (`implementing` or `testing`) and a `reason` naming the check by its block id. It counts a review round.
|
|
71
72
|
- On every end-game wake (`phase-finished`, `catch-up`, `checks-red`, `review-stuck`), read `gh pr view <n> --json mergeable,mergeStateStatus`, because a `CONFLICTING` pull request gets no CI and no wake. Then, and after acceptance, follow `skill://legion-architect/references/acceptance.md`.
|
|
72
73
|
|
|
@@ -34,9 +34,12 @@ legion({ op: "sign_off", issue: "LEGION-40" })
|
|
|
34
34
|
is in `accepting`, and the `phase-finished` notice that moved it there may never have reached you
|
|
35
35
|
(the daemon drops a notice to a failed architect, so a retried one learns of the wait from its
|
|
36
36
|
catch-up alone). Accept it as this section says, a parent only after its last round (below).
|
|
37
|
-
- The daemon
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
- The daemon refuses `sign_off` while an issue beneath the one you accept is still in the workflow
|
|
38
|
+
(`SIGNOFF_CHILD_IN_WORKFLOW`, naming each one): take each one to done, or out of the workflow
|
|
39
|
+
with `park_child`, and sign off again. A parent: sign off only after its last round (below). The
|
|
40
|
+
daemon then closes a parent that is not the root at its own merge, which under this rule comes
|
|
41
|
+
after its children's. One issue beneath never holds it: one the daemon itself holds at
|
|
42
|
+
`admitted` under an ancestor it has already accepted, which starts when that ancestor closes.
|
|
40
43
|
- `request_backward_move` names the issue, because your grant serves the tree; the daemon starts
|
|
41
44
|
that phase's role with your reason in its task.
|
|
42
45
|
- `handoff_complete` from you in `accepting` is refused `ACCEPTANCE_IS_SIGN_OFF`. CI red at the head
|
|
@@ -99,7 +102,8 @@ The daemon keeps this order from its fixed table; you start none of its steps:
|
|
|
99
102
|
4. The merger quotes what sits above the approved head
|
|
100
103
|
(`jj diff --from <approved-sha> --to <tip-sha> --summary`) in READY and sends the READY packet
|
|
101
104
|
with its completion. The daemon refuses a head carrying anything above the approved head but a
|
|
102
|
-
commit that changes only `docs/solutions/` and
|
|
105
|
+
commit that changes only `docs/solutions/` and a change whose every path is under `.legion/`,
|
|
106
|
+
which nothing writes or reads now, so nobody reviews one
|
|
103
107
|
(`READY_UNREVIEWED_CHANGE`). It
|
|
104
108
|
posts `READY #<n> at <current sha> (approved at <approved sha>) for <KEY> (<pr url>)` on the
|
|
105
109
|
Dispatch issue, publishes it to the project's merge queue role when one is set, and submits the
|
|
@@ -124,7 +128,7 @@ from `accepting` you send an issue back only to `implementing` or `testing`.
|
|
|
124
128
|
## A conflicting head
|
|
125
129
|
|
|
126
130
|
What returns the tree to review is a changed diff: a commit above the approved head that touches
|
|
127
|
-
anything outside `docs/solutions/`, other than
|
|
131
|
+
anything outside `docs/solutions/`, other than a change whose every path is under `.legion/`, or
|
|
128
132
|
a conflict-resolution merge whose fingerprint (the unchanged-diff check,
|
|
129
133
|
`skill://legion-worker/references/conflicts-and-rewrites.md`) differs from the approved head's.
|
|
130
134
|
A merge forced by a GitHub-reported conflict whose fingerprint is unchanged does
|
|
@@ -167,14 +171,15 @@ The merge closes the issue: when GitHub reports the pull request merged while th
|
|
|
167
171
|
`awaiting_merge` (a merge before that closes it the moment it gets there), the daemon writes `done`.
|
|
168
172
|
|
|
169
173
|
- A root whose merge lands while another issue of its tree is still in the workflow stays in
|
|
170
|
-
`awaiting_merge`,
|
|
174
|
+
`awaiting_merge`, its workers kept and live and no admission slot held, until the last of them
|
|
175
|
+
is done or parked. One
|
|
171
176
|
`pr-merged` notice names what it waits for and none follows as they depart, so read the pull
|
|
172
177
|
request on GitHub.
|
|
173
178
|
- A child's close reaches you as `child-closed`. The daemon retires five of its six claims and
|
|
174
179
|
leaves the implementer running, because it still owes the production check. When the issue's
|
|
175
180
|
pod and Sandbox go is in `skill://legion-worker/references/merge-gate.md`, *The production check
|
|
176
181
|
after the close*.
|
|
177
|
-
- A root's close writes `done`,
|
|
182
|
+
- A root's close writes `done`, releases any admission slot the tree's issues still held, and lingers the tree for
|
|
178
183
|
`linger_hours` with every member suspended. The linger's end, the tree's last step, waits until
|
|
179
184
|
every member's open production check has closed.
|
|
180
185
|
|
|
@@ -189,10 +194,11 @@ woke the last one and when the next is due).
|
|
|
189
194
|
When a person closes a root and it stays `done` through its linger, each child still in the
|
|
190
195
|
workflow is handed to Legion as a root of its own: `todo` with the `legion` label, its phase, gate,
|
|
191
196
|
phase records and pull request carried into a new generation, and that phase's role started. A
|
|
192
|
-
child that never started
|
|
193
|
-
|
|
194
|
-
and registers its own spec.
|
|
195
|
-
|
|
197
|
+
child that never started is handed over too, carrying no run, whatever held it at `admitted`: it
|
|
198
|
+
waits in the line for a slot and for any unfinished blocker, and its architect starts as a fresh
|
|
199
|
+
root and registers its own spec. Only a child that finished, was parked or was never released
|
|
200
|
+
stays. The child stays its own tree; reopening the old root does not take it back. Park a child
|
|
201
|
+
with `park_child` before then when its work should stop with the root.
|
|
196
202
|
|
|
197
203
|
If you are that child's architect:
|
|
198
204
|
|
|
@@ -16,7 +16,8 @@ and an earlier one with `--version <n>`. The child's Conversation lists every ve
|
|
|
16
16
|
Put every adopted child into the first wave and release it with
|
|
17
17
|
`legion({ op: "release_children", issues: ["LEGION-41", "LEGION-42"] })`. The daemon runs nothing on
|
|
18
18
|
a child until it is released. Once it is released, the daemon moves it to `todo` and, while the
|
|
19
|
-
root's design gate is open, starts its
|
|
19
|
+
root's design gate is open, starts its first phase itself at the child's own admission slot, and
|
|
20
|
+
not while Dispatch shows an open child under that child. It starts no sub-architect, and you start no
|
|
20
21
|
worker. A release is accepted whole whatever the `--blocked-by` links say: its answer names
|
|
21
22
|
`started` and `held` (each held child with the issues it waits on) beside `released`, and a held
|
|
22
23
|
child waits in your tree until Legion starts it.
|
|
@@ -66,9 +67,14 @@ EOF
|
|
|
66
67
|
- `--project` is the issue key's prefix before `-<n>` (`LEGSMOKE-3` → `LEGSMOKE`).
|
|
67
68
|
- In a root session `$LEGION_ISSUE` is the root (it equals `$LEGION_TREE`): pass it as `--parent`.
|
|
68
69
|
The daemon makes the sub-issue link from `--parent`.
|
|
70
|
+
- File every child before you request the root spec's approval, and before `register_gate` under
|
|
71
|
+
`gates.design: off`: the gate's opening starts the root's own first phase unless Dispatch shows
|
|
72
|
+
an open child under it, so a child filed after that leaves the root working beside its children.
|
|
69
73
|
- Order the returned keys into waves with `--blocked-by` links (a later wave's child blocked by the
|
|
70
74
|
children it builds on), then release every child at once with `release_children`: Legion holds a
|
|
71
75
|
released child until its last blocker closes, and a child is inert only until it is released.
|
|
76
|
+
Each issue of the tree whose worker has work holds an admission slot of its own, so a wave of
|
|
77
|
+
four working children takes four of the deployment's cap.
|
|
72
78
|
- Never release a child `--blocked-by` its own parent: the parent now merges last, so that child
|
|
73
79
|
would wait forever.
|
|
74
80
|
- Do not pass `--assignee`, because the default keeps the tree's questions in one Inbox: under the
|
|
@@ -35,12 +35,16 @@ evidence of a controller's `Filed for Legion from <role> on <issue>:` line
|
|
|
35
35
|
The approval step runs only when the `Design gate policy` sentence of your `Legion addressing` line
|
|
36
36
|
says `gates.design: root-issues`. When it says `gates.design: off`, write the spec and register it
|
|
37
37
|
with `register_gate` at its current version, with no approval step: do not request approval and do
|
|
38
|
-
not wait for `design-approved`; the gate opens at registration.
|
|
38
|
+
not wait for `design-approved`; the gate opens at registration. File every child of your
|
|
39
|
+
decomposition before that registration, since the gate's opening starts the root's own first phase
|
|
40
|
+
unless Dispatch shows an open child under it. A sub-architect on a child issue
|
|
39
41
|
has no policy line and never runs the gate.
|
|
40
42
|
|
|
41
43
|
## The armed gate
|
|
42
44
|
|
|
43
|
-
When the gate is armed, run this exact sequence before the tree's work starts
|
|
45
|
+
When the gate is armed, run this exact sequence before the tree's work starts, with every child of
|
|
46
|
+
your decomposition filed before step 4, since the gate's opening starts the root's own first phase
|
|
47
|
+
unless Dispatch shows an open child under it:
|
|
44
48
|
|
|
45
49
|
1. Extend the primary document in place:
|
|
46
50
|
|
|
@@ -121,8 +125,8 @@ Facts about the request:
|
|
|
121
125
|
never wrote is no registration: the gate is as it was. Read the document's latest version, check
|
|
122
126
|
it is the spec the human is asked to approve, and `register_gate` that version.
|
|
123
127
|
|
|
124
|
-
Then end your turn. The registration hands the spec to the human: when nothing else
|
|
125
|
-
|
|
128
|
+
Then end your turn. The registration hands the spec to the human: when nothing else of the tree is
|
|
129
|
+
at work, the root returns its admission slot and waits on its design gate (`awaiting_person`), as a
|
|
126
130
|
root question handed to the human does ("Every turn" in `skill://legion-architect/SKILL.md`). Stay
|
|
127
131
|
live to read the human's comments and replies. Their approval or changes request delivers your next
|
|
128
132
|
task, and so does a newer spec version once Dispatch shows the request back on your turn. While the
|
|
@@ -19,15 +19,16 @@ and 7 (a conflict, the hand-over, the close) is in
|
|
|
19
19
|
| Wake | Procedure |
|
|
20
20
|
| --- | --- |
|
|
21
21
|
| `carried-gate-opened` | Only a root whose catch-up said `carried` gets it. Its `version` and `reason`: a human approved the old root's spec document at `version`, which opened the gate this root carried; the daemon has released any READY it refused and started any child waiting on it. It is not `design-approved`: do not proceed to section 2 or release a wave because of it, and start nothing. |
|
|
22
|
-
| `child-status` | A child of your tree left the workflow or re-entered it, or joined your tree from the admission queue; the reason names the child and its new status, or reads `<KEY> joined the tree of <ROOT> from the admission queue`. `todo` (a human's move, your `release_children`, or your `rerun_child`) means it runs again under your tree from planning, and the daemon starts it; you start nothing. A child held for a blocker starts the same way once nothing holds it, and the reason, naming it and its root, says what cleared the hold: its last blocker's close, naming the issues it waited on, now done, or a person or you taking its blocked-by links off; you start nothing for it either. `backlog`, `icebox` or `triage` (a human's move, or your `park_child`) means the daemon has suspended its workers, and it advances no further until it is set back to `todo`. Joined from the admission queue means a root that waited for a slot and never ran, which a person made a child of your tree or your `release_children` adopted, now runs in your tree with no
|
|
22
|
+
| `child-status` | A child of your tree left the workflow or re-entered it, or joined your tree from the admission queue; the reason names the child and its new status, or reads `<KEY> joined the tree of <ROOT> from the admission queue`. `todo` (a human's move, your `release_children`, or your `rerun_child`) means it runs again under your tree from planning, and the daemon starts it; you start nothing. A child held for a blocker starts the same way once nothing holds it, and the reason, naming it and its root, says what cleared the hold: its last blocker's close, naming the issues it waited on, now done, or a person or you taking its blocked-by links off; you start nothing for it either. `backlog`, `icebox` or `triage` (a human's move, or your `park_child`) means the daemon has suspended its workers, and it advances no further until it is set back to `todo`. Joined from the admission queue means a root that waited for a slot and never ran, which a person made a child of your tree or your `release_children` adopted, now runs in your tree with no architect of its own and takes an admission slot of its own when its work starts, from planning when it is `todo` and parked otherwise; one that waits on an unfinished blocked-by issue is held for that blocker like any other child, and starts when nothing holds it; you start nothing. A reason saying an issue is beneath an ancestor whose reviewed head the daemon has already accepted is a person's `todo` the daemon recorded and holds at `admitted`: nothing starts it until that ancestor closes, and a `request_backward_move` of the ancestor is what runs it under the ancestor now. What the rest of the tree does is your decision. When a park leaves no child that an issue in `accepting` waits on, run that issue's last round (`skill://legion-architect/references/acceptance.md`). |
|
|
23
23
|
| `child-closed` | Read the child completion and remaining open children. Re-scope open work, park obsolete work for good with `park_child` (first take its link off each sibling that waits on it, or park that sibling too, as section 2 says), and file any new child the result calls for, after the red-team check in `skill://legion-architect/references/decomposition.md`, and release it at once with `release_children`, blocked by what it builds on (section 2). When a worker waits on this child for a missing surface (see `phase-finished`), tell it to continue with `envoy_publish` to its role topic. The last child's close is not the end-game (section 3). When it was the last child an issue in `accepting` waits on, run that issue's last round (`skill://legion-architect/references/acceptance.md`). |
|
|
24
24
|
| `child-release-stalled` | Its `reason` names a child your `release_children` released that your tree has not recorded, its parent, and why, one of three: the parent's release has not reached the daemon after three tries; or GitHub did not answer the App installation read of a repository on the child's parent chain, and the wave left the child unrecorded because a parent on that chain is not `todo`, or did not write the child `todo` because its parent is not recorded; or the daemon's recovery of such a repository, once GitHub answered, still left children unrecorded (one notice per tree lists them all, each with its parent). Read the parent's record with the `legion` tool's `read_record` (`issue` the parent); release the parent first when the `reason` says to, then run `release_children` for the child again once the parent is recorded in your tree, and tell the controller if it never is. |
|
|
25
25
|
| `child-not-recorded` | Its `reason` names a child your tree did not record and why: its repository resolves to none (neither it nor an ancestor names one, and the project has no default), or to one not mapped to the project, or to one the daemon leaves out for a missing GitHub App. The daemon said why on the child too. Set the child's repository to one of the project's (`dispatch issue-update --repo owner/name`), then release it again with `release_children`; tell the controller when the repository it needs is not served. |
|
|
26
|
+
| `children-first` | An issue of your tree starts no phase of its own while Dispatch shows an open child under it, a child you filed and have not released included. The reason names the parent and each open child with the Dispatch status that holds it, and each cycle it found (a child `blocked_by` an issue above it on its own parent chain, which only a person taking that link off ends: open a `dispatch ask`). It comes once per issue and run of its tree. Release every child that should run, and close, `park_child` or re-parent the rest; the daemon starts the parent's first phase at its next admission slot once the last open child has left the workflow. You start nothing. |
|
|
26
27
|
| `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 — except on a root whose catch-up said `handed_over`: its workers already run their phases, so start nothing; the approval releases any READY the gate refused. One whose `version` is the version a human's own answer to a decision block wrote, after an earlier approval (Dispatch carried that approval to it, "After approval" in `skill://legion-architect/references/design-gate.md`), opens nothing new: carry on, and release no wave because of it. A root that was waiting on a question in `awaiting_person` gets no such notice: the task that resumes it says "Your spec is approved at version N and the design gate is open: this resume is your design-approved wake", and that resume is this wake — proceed to section 2 on it. |
|
|
27
28
|
| `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 "The armed gate" in `skill://legion-architect/references/design-gate.md` says; end your turn; the gate is closed. On a root that was waiting on a question in `awaiting_person`, a review the human gave after the wait began comes in the resume task, not in this notice, whether it answered the wait or came after something else did: the task names the review with its version and reason, unless a later approval superseded it. A `version` below the latest, or a second request for one version, is a request that reached the daemon late: read it as the same section's last paragraph says. Each request arrives once. |
|
|
28
29
|
| `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 finishing phase's handoff on the Dispatch issue (`dispatch handoff-read --issue <issue> --phase <word>`); 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 the full condition in "After approval" of `skill://legion-architect/references/design-gate.md`: when the approved Summary, the requirements, the checks, the scope and the settled decisions still hold, the plan is the record; otherwise change the root spec and request approval again as that section 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 issue is in `accepting` and the acceptance is yours (section 6): read the evidence, then `sign_off` (a parent only after its last round, "The last round" in `skill://legion-architect/references/acceptance.md`) or send it back with `request_backward_move`. A `tester` notice with `verdict: "fail"` — its handoff carries `implementerProof.verdict: "rejected"`, or a failure naming a check with no current passing result — has gone back to the **implementer** by the daemon's table; never record that check's result 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: build the surface in this tree: a child issue (infrastructure, tooling, or a skill) after the red-team check in `skill://legion-architect/references/decomposition.md`, or, when the red team folds it, tell the waiting worker to move the issue back to `implementing` with `request_backward_move`, naming the surface. When it is a child, tell the waiting worker to continue with `envoy_publish` to its role topic once that child's `child-closed` arrives. That report is never a reason to advance the phase. |
|
|
29
30
|
| `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: no handoff is a commit, so every such push counts except a push by the review App (a planner's, tester's, reviewer's or architect's), and the head pushed onto a red the tester's red tests earned (a planned red) does not count either. 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, and no later CI red within the attempt that ran the count out (the counted head, and every head pushed on top of it until a push lands on a head CI judged green or on a settled head whose base branch requires no check and no workflow, the tester's red tests onto the held red included) sends the work back from `testing`, `reviewing`, `accepting`, `retro` or `merging` either: the issue stays in its phase until you move it, or a worker's own decision does (a tester's `fail`, a reviewer's request for changes). A head pushed onto green CI, or onto a settled head whose base branch requires no check and no workflow, leaves that attempt, so its red still comes as a `checks-red`. 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. In `accepting`, where no worker holds a phase, the move is yours: `request_backward_move` with `issue`, naming the failing checks. 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. 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 a conflict (`the head conflicts with <base>`), the required checks that failed (`CI is red at <head>`), or the merge queue's failed merge and its failing run (`the merge queue took pull request #<n> out at READY's 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; your own send-back from `accepting` by the reason you gave. 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, or when the merge queue fails the merge) are the rounds the cap is for. Each `review_round_cap` notice is a decision you make in the turn it wakes, never one left for the next round to make: read what every counted round found, choose one of the three below, act on it in the same turn, and post it as a `dispatch comment` on the issue naming the rounds you read and the choice. **Narrow**: the change itself is sound but each round finds more around it; tell the implementer and the reviewer (`envoy_publish` to each one's role topic) which checks of the issue the next round answers; a correctness finding is still fixed in this pull request, and so is a wording nit or any clear fix in a file it touches, so the `Fast-follow:` line carries only cleanup in files this pull request does not touch. **Split**: part of the work cannot settle in this pull request and is a separately deliverable change (`skill://legion-architect`, section 1). On a child, run the red-team check in `skill://legion-architect/references/decomposition.md`, then file that part as a child of this issue's parent, never of this one (this issue closes at its own merge, and the split part usually builds on this pull request's unmerged code): `dispatch issue --project <project> --parent <parent> --title '<outcome>' --blocked-by <this issue> --spec-file -`. Release it now with `release_children`: Legion holds it on that `--blocked-by` link until this issue closes, and starts it then. On the root, narrow it to what settles here and open a `dispatch ask` for the rest (`skill://legion-worker/references/findings.md`): a person decides whether that becomes an issue. Tell the implementer and the reviewer that this pull request no longer carries it. **Accept the rounds**: each round found less than the one before it, and the last found no defect in the change itself (a stale line, a comment that states an old default); let the loop run and say why in the comment. A later notice is a new decision: accept again only when its round found less than the round you last accepted, and otherwise narrow or split. A finding that changes what the spec requires or what a check proves is a decision block in the root spec ("After approval" in `skill://legion-architect/references/design-gate.md`), and `dispatch ask` is only for a decision that needs a human's authority; neither replaces the choice. Judge a worker's backward move by the reason that worker gives. A move you ordered for a conflict found before `awaiting_merge` ("A conflicting head" in `skill://legion-architect/references/acceptance.md`) is a conflict return. The merger's move back to `reviewing` for a READY refusal (`READY_UNREVIEWED_CHANGE`, or `READY_NOT_APPROVED` when its task names no approved head), and the reviewer's no-fix request for changes that follows it so the tester runs the head, are not the work going in circles either. A move that sends back code found wrong counts with the tester fails. |
|
|
30
|
-
| `pr-merged` | The pull request merged and the issue did not close; its `reason` says why. Merged before the issue reached `awaiting_merge`: the workflow runs on, and the merge closes the issue the moment it gets there, your acceptance and retro first. Merged while the rest of the tree still runs: the reason names the pull request and every issue the close waits for, and the root waits in `awaiting_merge`,
|
|
31
|
+
| `pr-merged` | The pull request merged and the issue did not close; its `reason` says why. Merged before the issue reached `awaiting_merge`: the workflow runs on, and the merge closes the issue the moment it gets there, your acceptance and retro first. Merged while the rest of the tree still runs: the reason names the pull request and every issue the close waits for, and the root waits in `awaiting_merge`, its workers kept and live and no admission slot held, until the last of them is done or parked ("The close" in `skill://legion-architect/references/acceptance.md`). Either way you start nothing and no further notice follows. |
|
|
31
32
|
| `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. |
|
|
32
33
|
| `pull-request-missing` | Its `reason` names the issue, the repository, the branch and the handoff commit: the issue's implementer completed at that commit and GitHub lists no open pull request on the branch, so the issue stays in `implementing`. Tell the implementer (`envoy_publish` to its role topic) to open the pull request from that branch; the daemon records it and moves the issue to `testing` once it is open. When the work should not go on, decide as the `pr-closed-unmerged` row says. It comes once per handoff commit. |
|
|
33
34
|
| `message-refused` | Dispatch refused a write the daemon was making on an issue of your tree, the way it would refuse every attempt, so the daemon makes it no more. A close reason and a READY packet are held to Dispatch's bounds at the call that carries them, so this is a refusal those checks did not predict. Read its `reason`: on a status write the daemon writes the status all the same, retrying it until Dispatch takes it, so the status is set unless Dispatch refused the status itself, which the reason says — with the status set, only the reason beside it is on no issue; with the status refused, the issue keeps the status it had while the daemon's own record reads the one the write carried, a disagreement no retry of the daemon's closes, so ask a person with `dispatch ask` to set that status on the issue, and the reason beside it may be posted already, which the reason says; on a message the message is on no issue and nothing else changed. Post what a person still needs on the issue yourself with `dispatch comment` — a refused READY packet is nobody's to send again, since the issue is in `awaiting_merge` where no worker holds a phase, and the merge the daemon submits is unaffected (`skill://legion-architect/references/merge-notices.md#message-refused`). |
|
|
@@ -81,7 +81,7 @@ Wake details: `skill://legion-controller/references/wakes.md`.
|
|
|
81
81
|
## Trees waiting on a root claim
|
|
82
82
|
|
|
83
83
|
A root architect whose claim on its root was refused waits, holding its slot, and nothing tells it
|
|
84
|
-
when the holder lets go. `dispatch read` each root in `admission.
|
|
84
|
+
when the holder lets go. `dispatch read` each root in `admission.trees` whose `phase` is still
|
|
85
85
|
`admitted`. When `Claimed by:` is `nobody` or ends `· not running`, `envoy_publish` `<KEY>: the
|
|
86
86
|
claim is free; claim it again.` to `notifications.role.<issues.<KEY>.architect.locator.claim>`.
|
|
87
87
|
|
|
@@ -112,9 +112,12 @@ you label at a person's request or file yourself.
|
|
|
112
112
|
A free slot is no reason to take an issue: a labelled root in `todo` takes the next slot through
|
|
113
113
|
`admission.waiting` without you, and a parked issue (status `backlog` or `icebox`) means "do not
|
|
114
114
|
run now". Move an issue out of `backlog` or `icebox` only on a request or a plan ruling that names
|
|
115
|
-
it, and cite that request.
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
it, and cite that request. A slot is one issue with work, a root or a child, not one tree: a tree
|
|
116
|
+
of four working issues holds four slots, and a tree whose root only waits holds none of its own,
|
|
117
|
+
so `admission.trees` is what names the roots of the live trees. The free slots are
|
|
118
|
+
`admission.cap` minus the issues in `admission.active` and the issues in `admission.waiting` that
|
|
119
|
+
are not in `admission.blocked`, since an issue its blockers or its own open children hold takes no
|
|
120
|
+
slot until they are done. Every move to `todo` you make is one of
|
|
118
121
|
these:
|
|
119
122
|
|
|
120
123
|
- a root you labelled at a person's request or filed for a clear defect no tree owns, at triage (a
|
|
@@ -2,21 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
`read_state` says where each issue Legion records stands, and its `phase` alone does not: an issue
|
|
4
4
|
is `admitted` from the moment the daemon records it until its first phase starts, whether it runs,
|
|
5
|
-
waits, or neither. Read its key against `admission` and its tree
|
|
5
|
+
waits, or neither. Read its key against `admission` and the root its own `tree` field names. A
|
|
6
|
+
slot is one issue with work, a root or a child, not one tree, so `admission.active` no longer says
|
|
7
|
+
which trees run: `admission.trees` does.
|
|
6
8
|
|
|
7
9
|
| What `read_state` shows | What it means | What you do |
|
|
8
10
|
|---|---|---|
|
|
9
|
-
| The key is in `admission.active` |
|
|
10
|
-
| The key is in `admission.
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
11
|
+
| The key is in `admission.active` | An issue holding a slot, a root or a child: a worker of it has work now. A root is here while its architect writes the spec (`admitted`, before its design gate first opens) and in each of its own phases; a child in each of its phases | Nothing, beyond [trees waiting on a root claim](skill://legion-controller/SKILL.md#trees-waiting-on-a-root-claim) |
|
|
12
|
+
| The key is in `admission.trees` | The root of a live tree: its lifecycle stands open and it does not linger, or it waits in the line or on a person. A tree is live whether or not any issue of it holds a slot, so this is the list that says which trees run, and `issues.<KEY>.tree` says which tree an issue stands in | Nothing: read it wherever you need the running trees |
|
|
13
|
+
| The key is in `admission.waiting` and not in `admission.blocked` | An issue waiting for a slot, in the line's own order: first the issues that held a slot and have work again, and the roots a person answered while they waited in `awaiting_person`, oldest first by when the work came back; then the issues whose first phase can start, by the Dispatch rank of their tree's root, and within one root's rank that tree's own issues before the root itself. A root that left another tree (handed over by its finished tree, or admitted as an orphan) waits here as its own root even under a live tree, the old root's return included: no tree adopts it | Nothing: it takes the next free slot by itself |
|
|
14
|
+
| `phase: awaiting_person`, `waitingOn` | A root that already ran and now waits only on a person: an answer to its architect's question (`waitingOn.kind` `ask`) or a review of its spec (`gate`). It holds no slot, its architect stays live to read the person's comments and replies, and its tree stays live. Unanswered, it is in neither `admission.active` nor `admission.waiting`, and only `admission.trees` names its tree; `waitingOn.answeredAt` means the daemon has promoted it to the front of `admission.waiting` | Nothing: it is not something to admit, label or park, and the slot it returned is no reason to take an issue ([Free slots](skill://legion-controller/SKILL.md#free-slots)). The daemon delivers the answer task to its architect at that promotion: at once, taking no slot, when the root's design gate has already opened, and at the next free slot while its architect is still writing the first spec. If its label goes or a person or outside session claims it on Dispatch, the daemon sends `unslotted` and does not resume work under another owner |
|
|
15
|
+
| The key is in `admission.blocked` | An issue Legion is waiting to start, with what it waits on: the Dispatch issues of its `blocked_by` links that nobody has finished, or, for a parent, the open children beneath it that children-first holds it for. It takes no slot until they are done, and one that is in the line stands in `admission.waiting` too | Nothing: a link's wait ends when each blocker reaches `done` (a person's close, or the blocker's own merge) or its link is taken off (by a person or the tree's architect), and a children-first wait ends when the last open child leaves the workflow, which is its tree's architect's work. Name the wait in the day's report |
|
|
16
|
+
| `phase: admitted`, in neither `admission.active` nor `admission.waiting`, and Dispatch shows a `child_of` parent | A child that has not started: it runs or waits with its tree, the root its `child_of` chain reaches. Under a root whose `phase` is `done` it waits with it. A labelled `todo` issue here is not in the line either: one whose recorded parent is in a live tree runs in that tree (the daemon adopted it there), or is held with that parent while the parent itself is held under an unreleased child, and one whose parent is not recorded but sits under a live tree is held under an unreleased child of that tree until its architect releases it or its parent. One a person moved to `todo` beneath an ancestor whose reviewed head the daemon has already accepted is held here until that ancestor closes. The unreleased-child hold is not `admission.blocked`, which names blocked-by links and children-first waits | Leave it to its tree. It runs again when its root does, or as a root of its own once it is `todo` with the `legion` label and no live tree is above it |
|
|
14
17
|
| `phase: admitted`, `status: todo`, in neither list, no parent | A root a person took out of the line by taking its label off | Nothing: the label puts it back in the line, and a person's label is their decision |
|
|
15
18
|
| `phase: done` while `status` is `in_progress`, `testing`, `needs_review` or `retro` | Legion is not running it under that status, and it sent the `unslotted` wake. Either someone other than Legion moved a root that waited for a slot there, and the daemon took it out of the workflow at that move since no slot would ever reach it; or a root waiting on a person could not be resumed — its `legion` label is gone, or a person or an outside session took its Dispatch claim — and the daemon took it out the same way, leaving the `in_progress` it ran with. A parked child stays parked. Legion starts nothing for any of them | Re-admit nothing yourself: `dispatch read` shows who works it now. Name it in your summary; `todo` with the `legion` label queues it again |
|
|
16
19
|
|
|
17
|
-
A root in the workflow
|
|
18
|
-
|
|
20
|
+
A root left in the workflow at a status only a running tree has (`in_progress`, `testing`,
|
|
21
|
+
`needs_review`, `retro`) whose tree is not live, and which no blocker hold and no children-first
|
|
22
|
+
wait explains, does not stay that way: every pass of admission (a Dispatch
|
|
19
23
|
event, the daemon's boot read, its tick) takes it out of the workflow and sends the `unslotted`
|
|
20
24
|
wake — an unanswered `awaiting_person` root only when its label or its Dispatch claim makes a
|
|
21
|
-
resume unsafe.
|
|
22
|
-
|
|
25
|
+
resume unsafe. Holding no slot is by itself no fault: a root in `accepting`, in `awaiting_merge`,
|
|
26
|
+
waiting on a person, waiting in the line, waiting on a blocker or waiting for its children holds
|
|
27
|
+
none while its tree runs. The wake is live only, so a controller that starts later finds such a
|
|
28
|
+
root by the last row, as its start procedure does.
|
|
@@ -18,9 +18,11 @@ Run this pass on the first turn of every UTC day and after every ruling from a p
|
|
|
18
18
|
1. Read the weekly-planning issue and select its newest `plan-week-*` artifact by its latest
|
|
19
19
|
`artifact.version` event. Read that artifact before changing any issue.
|
|
20
20
|
2. For every plan line whose issue key carries this project's prefix (`daemon.project` in
|
|
21
|
-
`read_state`), make the project's board order match the line order exactly, because
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
`read_state`), make the project's board order match the line order exactly, because board rank
|
|
22
|
+
is the order Legion admits by: an issue whose first phase can start takes the rank of its
|
|
23
|
+
tree's root, and an issue whose work came back goes ahead of all of them. Set the priority the
|
|
24
|
+
plan line states, and leave the priority where it states none; priority changes no admission
|
|
25
|
+
order. When one plan line lists
|
|
24
26
|
several issues, keep them in that order. Take the order from the plan alone, never from a
|
|
25
27
|
title or a route. Reorder with
|
|
26
28
|
`dispatch issue-update --issue <KEY> --before <OTHER>` or `--after <OTHER>`.
|
|
@@ -88,8 +90,8 @@ For work that a ruling of a person's, recorded in the plan with its link (the ru
|
|
|
88
90
|
above), says moves to Legion when its session stops, preserve its existing labels, add `legion`,
|
|
89
91
|
then set it `todo` with the `legion` tool's `set_status`. A plan row you wrote with no such ruling
|
|
90
92
|
behind it moves nothing. The label comes first: it is what
|
|
91
|
-
lets the daemon admit the root. Do not apply that recovery to an issue already in
|
|
92
|
-
tree; its architect and daemon own its lifecycle. Update the weekly-plan owner row after the move.
|
|
93
|
+
lets the daemon admit the root. Do not apply that recovery to an issue already in a live Legion
|
|
94
|
+
tree (a root in `admission.trees`, or an issue whose `tree` is one); its architect and daemon own its lifecycle. Update the weekly-plan owner row after the move.
|
|
93
95
|
|
|
94
96
|
## A root the plan defers
|
|
95
97
|
|
|
@@ -58,14 +58,17 @@ every issue by its `dispatch://` link and what it does for the reader, every pul
|
|
|
58
58
|
pull request under `External links:` is the one that merged.
|
|
59
59
|
- **Closed without a change.** Those with no pull request, each with the reason its closing
|
|
60
60
|
message gave (the `message.created` just before `issue.closed` among `Events:`).
|
|
61
|
-
- **Running.** Each root in `admission.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
61
|
+
- **Running.** Each root in `admission.trees`, the live trees, with its `issues.<KEY>.phase`, and
|
|
62
|
+
under it each issue of that tree in `admission.active`, the slot holders, with its own phase;
|
|
63
|
+
then the issues in `admission.waiting`. Name as waiting on a claim each root that this turn's
|
|
64
|
+
"Trees waiting on a root claim" check found, with the holder its `Claimed by:` line names.
|
|
65
|
+
- **Waiting on Dispatch links.** Each root and child in `admission.blocked`, with what it waits
|
|
66
|
+
on: the issues of its `blocked_by` links, or the open children children-first holds it for. A
|
|
67
|
+
link's wait ends when each blocker reaches `done` (a person's close, or the blocker's own
|
|
68
|
+
merge) or its link is taken off (by a person or the tree's architect), and a children-first wait
|
|
69
|
+
ends when the last open child leaves the workflow, so take nothing for them.
|
|
70
|
+
- **Free slots.** Counted as the skill's "Free slots" says, in issues rather than trees; each
|
|
71
|
+
stays free until an issue in the line takes it.
|
|
69
72
|
- **Open capabilities.** Each row of `read_state`'s `capabilities` whose `status` is `open`: its
|
|
70
73
|
name, its `detail`, and a deployment row's `configLine`. Say who acts on it, as
|
|
71
74
|
`skill://legion-controller/references/wakes.md` says for `tick`. With none open, say nothing of
|
|
@@ -9,8 +9,10 @@ it as a decision block and opens its own finding asks. Send a design decision ba
|
|
|
9
9
|
architect with `envoy_publish` to its role, because it is not yours to make.
|
|
10
10
|
|
|
11
11
|
For capacity, the only lever is order. You cannot change `admission.cap`: it is the operator's
|
|
12
|
-
`legion.yaml` setting, and `set_status` is your only admission move.
|
|
13
|
-
|
|
12
|
+
`legion.yaml` setting, and `set_status` is your only admission move. The cap counts issues at
|
|
13
|
+
work, a root or a child, not trees, so a tree's own children compete for it with every other
|
|
14
|
+
tree's. Read `admission.active`, `admission.waiting` and `admission.trees`, tell the architect
|
|
15
|
+
where its tree's issues stand in the line with `envoy_publish`, and
|
|
14
16
|
open a finding ask when the deployment needs a larger cap.
|
|
15
17
|
|
|
16
18
|
For a conflict between trees, read both roots in `read_state` and Dispatch, publish what you read
|
|
@@ -44,15 +44,17 @@ The work goes to whoever already owns that code. You file an issue only when nob
|
|
|
44
44
|
repository your addressing line lists. Otherwise open an ask for it, as `findings.md` says.
|
|
45
45
|
2. Search first (`skill://dispatch-first`). When an open issue tracks it, comment the evidence
|
|
46
46
|
there, reply `Filed dispatch://<that KEY>` under the evidence, and file nothing.
|
|
47
|
-
3. Find the running tree whose code it is: a root in `admission.
|
|
48
|
-
component match, read from `read_state` and `dispatch read`.
|
|
47
|
+
3. Find the running tree whose code it is: a root in `admission.trees`, the live trees, whose
|
|
48
|
+
repository and component match, read from `read_state` and `dispatch read`. Read it there
|
|
49
|
+
rather than in `admission.active`, which holds the issues at work: a tree runs whether or not
|
|
50
|
+
any issue of it holds a slot. When one matches, hand it over.
|
|
49
51
|
`envoy_publish` the defect, its evidence reference and the fix to that tree's architect topic,
|
|
50
52
|
`notifications.role.<issues.<KEY>.architect.locator.claim>`. The architect decides whether it
|
|
51
53
|
is a child of the tree or part of an open issue's work. Reply `Handed dispatch://<that KEY>`
|
|
52
54
|
under the evidence only when a live holder took the publish. When the root has no locator, or
|
|
53
55
|
the listener kept the publish for the role's next holder, reply nothing: no architect reads a
|
|
54
56
|
comment on its root, so the evidence stays unhandled, and catch-up step 4 lists it again at
|
|
55
|
-
your next start. Publish it again at your next wake. Once the root leaves `admission.
|
|
57
|
+
your next start. Publish it again at your next wake. Once the root leaves `admission.trees`,
|
|
56
58
|
no running tree owns the code, and step 4 files it. File nothing while a tree owns it: a
|
|
57
59
|
second issue splits the work.
|
|
58
60
|
4. No running tree owns that code: file it on the repository where the fix belongs, in the
|
|
@@ -125,11 +125,10 @@ an approval of a document that is not the root's primary one.
|
|
|
125
125
|
- It only questions the work: a question, a doubt about the premise, a request for changes that
|
|
126
126
|
only asks why. Leave it parked and answer the question in one reply:
|
|
127
127
|
- Answer from the record when it holds the answer: the issue and its spec (`dispatch read`,
|
|
128
|
-
`dispatch doc-read`), its handoffs (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
<root> to todo to run it.`
|
|
128
|
+
`dispatch doc-read`), its handoffs (`dispatch handoff-read --issue <KEY> --phase <word>`)
|
|
129
|
+
and its pull request. Write `Parked decision read: <ref> by <login> asks <the question in
|
|
130
|
+
a few words>.`, then the answer and where in the record it is, then `The tree stays parked.
|
|
131
|
+
Set <root> to todo to run it.`
|
|
133
132
|
- When the record does not answer it, write `Parked decision read: <ref> by <login> asks
|
|
134
133
|
<the question in a few words>. The record does not answer it, and <root> is parked, so
|
|
135
134
|
its architect cannot answer either. Set <root> to todo to bring its architect back to
|
|
@@ -26,9 +26,11 @@ answer to your ask, a mention), Envoy or Slack. No `legion controller start` can
|
|
|
26
26
|
## The `legion` tool
|
|
27
27
|
|
|
28
28
|
- `op: "read_state"` returns the daemon's whole state: `issues.<KEY>.phase`,
|
|
29
|
-
`issues.<KEY>.holdReason`, `issues.<KEY>.architect`, `
|
|
30
|
-
`admission.
|
|
31
|
-
`
|
|
29
|
+
`issues.<KEY>.holdReason`, `issues.<KEY>.architect`, `issues.<KEY>.tree` (the root of the
|
|
30
|
+
issue's tree), `admission.cap`, `admission.active` (the issues holding a slot, roots and
|
|
31
|
+
children), `admission.waiting` (the issues in the line, in its order), `admission.trees` (the
|
|
32
|
+
roots of the live trees), `admission.blocked`, `capabilities[]`, `daemon.project`, and
|
|
33
|
+
`settings` (the daemon's resolved `legion.yaml`, with no credential in it).
|
|
32
34
|
- `op: "set_status"` with `issue` and `status` (`todo`, `backlog` or `icebox`) moves an issue. Each
|
|
33
35
|
call mints its grant in-process from the secret the session registered with, so a stale secret
|
|
34
36
|
fails it with a 403. You cannot set `done`: only an issue's architect or the daemon closes an
|
|
@@ -113,7 +113,9 @@ architect for it, whatever it asks. For a person's mention, take the first of th
|
|
|
113
113
|
|
|
114
114
|
- **A question about state.** "What is Legion working on?", "Where is ACME-12?", "Why is it held?"
|
|
115
115
|
Answer from `read_state` and Dispatch as they stand now, never from memory: each issue's
|
|
116
|
-
`issues.<KEY>.phase`, its pull request, `admission.
|
|
116
|
+
`issues.<KEY>.phase` and `issues.<KEY>.tree`, its pull request, `admission.trees` for the trees
|
|
117
|
+
that run, and `admission.active` and `admission.waiting` for the issues at work and the issues
|
|
118
|
+
in the line. Say what you
|
|
117
119
|
read, citing for each fact the `read_state` field or the `dispatch read` line it came from.
|
|
118
120
|
- **A request for work.** Someone wants a change made, a bug fixed, something investigated. Search
|
|
119
121
|
first (`skill://dispatch-first`): when an open issue already tracks it, reply with that issue and
|
|
@@ -10,10 +10,11 @@ Read this on a `triage` wake, at every start, and when a person hands you an iss
|
|
|
10
10
|
match in one request, so no row is missed or repeated while the list changes.
|
|
11
11
|
2. The rows show no parent, so `dispatch read` each one and follow `Links:` up through each
|
|
12
12
|
`child_of` parent. A `child_of` under `Referenced by:` is a child of this issue, not its parent.
|
|
13
|
-
3. Leave a child
|
|
14
|
-
tree's architect owns it.
|
|
13
|
+
3. Leave a child whose `issues.<KEY>.tree` is a root in `admission.trees`, or that has an ancestor
|
|
14
|
+
that is, because that tree's architect owns it. `admission.trees` is the live trees: a slot is
|
|
15
|
+
one issue with work, so a running tree holds none of its own while its children work.
|
|
15
16
|
4. Every other row with no `issues.<KEY>` entry in `read_state` is a root to you, a child whose
|
|
16
|
-
tree is in
|
|
17
|
+
tree is not in `admission.trees` included. Read who set its label
|
|
17
18
|
("Triage a root", step 2). A root a person labelled is queued by the daemon and needs nothing
|
|
18
19
|
from you. Triage, as a root, each one whose label a session set.
|
|
19
20
|
5. A root `read_state` records and that is now in `triage` is one a person pulled back. Never
|
|
@@ -19,9 +19,11 @@ the same way and wakes nobody.
|
|
|
19
19
|
|
|
20
20
|
## `slot-free on <KEY>` (`{kind: "slot-free"}`)
|
|
21
21
|
|
|
22
|
-
The daemon released `<KEY>`
|
|
23
|
-
|
|
24
|
-
its own `awaiting-person` wake)
|
|
22
|
+
The daemon released the slot of `<KEY>` and no waiting issue took it: the work of that issue ended
|
|
23
|
+
or left the workflow — its merge, `accepting`, a blocker, its own children, a person
|
|
24
|
+
(`awaiting_person`, which also sends its own `awaiting-person` wake), or its tree finishing. A
|
|
25
|
+
slot is one issue with work, a root or a child, so the issue it names may be either. Name the free
|
|
26
|
+
slots; take nothing.
|
|
25
27
|
|
|
26
28
|
## `todo on <KEY>` (`{kind: "todo"}`)
|
|
27
29
|
|
|
@@ -46,10 +48,12 @@ because the operator closes or decides a deployment row, and the operator or the
|
|
|
46
48
|
fixes a live row's session.
|
|
47
49
|
|
|
48
50
|
`blocked`, when present, is `[{issue, blockedBy}, …]`: every root and child Legion is waiting to
|
|
49
|
-
start
|
|
51
|
+
start, each with what it waits on — the unfinished Dispatch issues of its `blocked_by` links, or,
|
|
52
|
+
for a parent, the open children beneath it that children-first holds it for. `read_state` shows the
|
|
50
53
|
same list under `admission.blocked`, and `legion state` prints it as `blocked on Dispatch links:`.
|
|
51
|
-
|
|
52
|
-
link is taken off (by a person or the tree's architect)
|
|
54
|
+
A link's wait ends when each blocker reaches `done` (a person's close, or the blocker's own merge) or its
|
|
55
|
+
link is taken off (by a person or the tree's architect), and a children-first wait ends when the
|
|
56
|
+
last open child leaves the workflow: name the waits in the day's report and
|
|
53
57
|
take nothing for them.
|
|
54
58
|
|
|
55
59
|
## `unslotted on <KEY>` (`{kind: "unslotted", reason}`)
|
|
@@ -69,8 +73,10 @@ A root whose architect asked a person a question, or handed its spec to a person
|
|
|
69
73
|
now waits only on them: the daemon returned its slot while the architect stays live to read the
|
|
70
74
|
person's comments and replies. Read `issues.<KEY>.waitingOn`. Do not park it or start anything, and
|
|
71
75
|
take nothing for the slot it returned: it is no reason to label or admit an issue ([Free
|
|
72
|
-
slots](skill://legion-controller/SKILL.md#free-slots)). The person's answer puts it
|
|
73
|
-
`admission.waiting` by itself, and
|
|
76
|
+
slots](skill://legion-controller/SKILL.md#free-slots)). The person's answer puts it among the
|
|
77
|
+
issues at the front of `admission.waiting` by itself, and its promotion gives its architect the
|
|
78
|
+
answer task: at once, holding no slot, when its design gate has already opened, and at the next
|
|
79
|
+
free slot while its architect is still writing the first spec. A lost label or a foreign
|
|
74
80
|
Dispatch claim sends the separate `unslotted` wake.
|
|
75
81
|
|
|
76
82
|
## `parked-decision on <KEY>` (`{kind: "parked-decision", decision, root, ref, actor, version?, reason?}`)
|
|
@@ -22,9 +22,10 @@ The head the merger names is the head the reviewer approved.
|
|
|
22
22
|
- **A change after the approved head** (`READY_UNREVIEWED_CHANGE`): the
|
|
23
23
|
daemon diffs the reviewer's approved head against the head on GitHub, and the issue goes back to
|
|
24
24
|
the reviewer for another review. READY still lets through a commit that changes only
|
|
25
|
-
`docs/solutions/`, which no role writes any more, and a
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
`docs/solutions/`, which no role writes any more, and a change whose every path is under
|
|
26
|
+
`.legion/`, where handoffs lived before they moved to the Dispatch issue and which nothing
|
|
27
|
+
writes or reads now, so nobody reviews a path there. Since retro commits nothing, an ordinary
|
|
28
|
+
head carries neither.
|
|
28
29
|
- `READY_UNREVIEWED_CHANGE` has more causes than a path outside retro's own. Every one of them
|
|
29
30
|
sends the head back to review and none is an error to retry; the complete list, with each
|
|
30
31
|
remedy, is the merger's own role prompt part.
|
|
@@ -38,7 +38,7 @@ Read each by its `skill://` link: a read by path stops at 300 lines.
|
|
|
38
38
|
| You write or edit the PR body, record a result against a check, read another phase's results, or run the simplify pass | `skill://legion-worker/references/pr-body.md` |
|
|
39
39
|
| Before a push, to check your commits' App identity | `skill://legion-worker/references/default-branch-check.md` |
|
|
40
40
|
| You reply on, list or resolve review threads, or judge a bot's finding | `skill://legion-worker/references/review-threads.md` |
|
|
41
|
-
| A conflict, a need only the base meets, a retarget, a parent's last round, comparing heads after a forward merge,
|
|
41
|
+
| A conflict, a need only the base meets, a retarget, a parent's last round, comparing heads after a forward merge, or rewriting a pushed commit | `skill://legion-worker/references/conflicts-and-rewrites.md` |
|
|
42
42
|
| You review or approve, build READY, or run the production check | `skill://legion-worker/references/merge-gate.md` |
|
|
43
43
|
| The issue renames a repository, package, or URL across the codebase | `skill://legion-worker/references/systematic-rename.md` |
|
|
44
44
|
| The issue deletes code, a command, or documentation | `skill://legion-worker/references/cleanup-deletion.md` |
|
|
@@ -51,7 +51,6 @@ Read each by its `skill://` link: a read by path stops at 300 lines.
|
|
|
51
51
|
- Before a push, read `jj -R "$LEGION_WORKSPACE" log -r 'ancestors(@, 5)'` (earlier phases' commits in it are expected) and run the identity check (`skill://legion-worker/references/default-branch-check.md`). Add no attribution trailer: the pane's jj adds `Omp-Session:`.
|
|
52
52
|
- Only work is pushed: code, red tests, a forward merge, a rewrite, and the empty commit that carries the pull request onto the commit you pushed (the bullet below). No commit message carries a line or bracket keyword that stops GitHub's workflows (`[skip ci]` and its kin), since every head needs its own checks and a base that requires a check will not merge a head whose checks never ran. Retro pushes nothing: it records what the work taught with `dispatch comment` on the issue.
|
|
53
53
|
- **After a push, read the pull request's head and check that it is your commit.** A branch and a pull request are two objects on GitHub: the push moves the branch, and GitHub then moves the pull request onto the new commit, which is what starts its checks. Twice on 2026-11-05 it did not, and the newer commit got no checks while Legion read, tested and would have merged the older one. The step applies once the branch has an open pull request, whose number your task's `Pull request:` line names (`gh pr list --repo <the issue's repository> --head legion/<KEY> --state open --json number --jq '.[0].number'` when it names none): run `gh pr view <n> --repo <the issue's repository> --json headRefOid --jq .headRefOid` about ten seconds after your push, again about ten seconds later, and a last time about thirty seconds after that, with a read that gives the pushed commit ending the step there and only the last read deciding a mismatch, and compare each answer with the commit you pushed, which `jj -R "$LEGION_WORKSPACE" log -r legion/<KEY>@origin --no-graph -T commit_id` prints in the 40 characters `headRefOid` answers in. This read is of the pull request's own head and of no check, so the wait it makes is not a wait on CI (`skill://legion-worker/references/pr-body.md#never-waiting-on-ci`). When the last read still is not your commit, carry the pull request with a commit of its own, an empty one when your work is complete and an empty one just as much when `@` holds work of yours, since a push of a commit the branch already holds moves no ref; the push section of your role prompt gives the one `jj` recipe, which leaves `@` and everything in it where it is. A new head makes every result recorded at the old head older, so record each `before_merge` check again at the new head. When that second push does not carry the pull request either, tell your architect the commit you pushed, the head each read gave and the time of each, and end the turn with a WAITING line naming that answer rather than completing: a phase completed here hands the next role a commit the pull request does not name. The push you make to answer an update task is the exception: that task has you answer the daemon and end the turn at once, so make this read in your next turn, before your phase completes. The merger pushes nothing, so this step never falls to it; it reports a mismatch it sees to the architect.
|
|
54
|
-
- A push refused because `legion handoffs import` moved `legion/<KEY>@origin` (its commit's message is `chore(legion): <KEY>'s handoffs are on its Dispatch issue now`) is cured by `jj -R "$LEGION_WORKSPACE" git fetch`, a forward merge with `legion/<KEY>@origin`, and the push (`skill://legion-worker/references/conflicts-and-rewrites.md`, *After the handoff import moved the branch*): never a rewrite.
|
|
55
54
|
- A planner whose issue moved back from implementing starts on the remote tip, `jj -R "$LEGION_WORKSPACE" new legion/<KEY>@origin`, so a commit it makes never sits on the implementer's unpushed commits.
|
|
56
55
|
|
|
57
56
|
## PR body, review, and the merge gate
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Part of `skill://legion-worker`. Read it when GitHub reports the pull request `CONFLICTING`, the
|
|
4
4
|
controller asks you to resolve a conflict, the change needs something only the base has, the pull
|
|
5
|
-
request is retargeted to a new base, you compare two heads after such a merge,
|
|
6
|
-
|
|
7
|
-
pushed.
|
|
5
|
+
request is retargeted to a new base, you compare two heads after such a merge, or you are about to
|
|
6
|
+
rewrite a commit you already pushed.
|
|
8
7
|
Every path it cites is in cybermonklabs/legion.
|
|
9
8
|
|
|
10
9
|
## Reintegrating the base
|
|
@@ -65,13 +64,6 @@ Every path it cites is in cybermonklabs/legion.
|
|
|
65
64
|
pushes its own commits* in `skill://legion-worker`; a merge is a code push like any other): the
|
|
66
65
|
merge descends from both the bookmark's old position and the destination, so it is a genuine
|
|
67
66
|
fast-forward and *Rewriting pushed commits* never applies.
|
|
68
|
-
- **After the handoff import moved the branch.** `legion handoffs import` moves `legion/<KEY>`
|
|
69
|
-
once, with a commit whose message is `chore(legion): <KEY>'s handoffs are on its Dispatch issue
|
|
70
|
-
now`, which removes the `.legion/` directory where handoffs lived before they moved to Dispatch.
|
|
71
|
-
A push it refuses as a moved branch is cured forward: `jj -R "$LEGION_WORKSPACE" git fetch`,
|
|
72
|
-
then `jj -R "$LEGION_WORKSPACE" new @- legion/<KEY>@origin -m "merge: legion/<KEY>@origin after
|
|
73
|
-
the handoff import"` (from `@-`, your own described tip, since your local bookmark may now
|
|
74
|
-
disagree with the remote one), `jj -R "$LEGION_WORKSPACE" new`, and the push — never a rewrite.
|
|
75
67
|
- **After a retarget.** Retargeting a pull request to a new base does not re-run Tests. Read
|
|
76
68
|
`base` again and merge the bookmark onto it in one command
|
|
77
69
|
(`base=$(gh pr view <n> -R <owner>/<repo> --json baseRefName -q '.baseRefName | @json') && jj -R "$LEGION_WORKSPACE" new legion/<KEY> "${base}@origin" -m "<message>"`) and push it the
|
|
@@ -105,7 +97,8 @@ fingerprint=$(set -o pipefail; jj -R "$LEGION_WORKSPACE" diff --from "fork_point
|
|
|
105
97
|
on a merge) and `index` lines (blob ids move when the base's copy of a file changed). What
|
|
106
98
|
is left is exactly the added and removed lines per file.
|
|
107
99
|
- The single fileset `'~(.legion | docs/solutions)'` leaves out `.legion/`, where handoffs lived
|
|
108
|
-
before they moved to Dispatch
|
|
100
|
+
before they moved to Dispatch and which nothing writes or reads now, so nobody reviews a path
|
|
101
|
+
there, and retro's learnings:
|
|
109
102
|
paths the merge gate lets through above an approval
|
|
110
103
|
(`skill://legion-worker/references/merge-gate.md`), which change
|
|
111
104
|
between one role's verified head and the next without changing the product. This is what lets
|
|
@@ -9,9 +9,10 @@ architect's acceptance, in `accepting` → retro → the merger's READY → the
|
|
|
9
9
|
issue → the implementer's production check, after the close. Every handoff is a record on the
|
|
10
10
|
Dispatch issue, never a commit, so the head that merges carries none. Retro commits nothing
|
|
11
11
|
(*Retro*, below), so the approved head is the head that merges. READY still lets a commit that
|
|
12
|
-
changes only `docs/solutions/` stand, and a
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
changes only `docs/solutions/` stand, and a change whose every path is under `.legion/`, where
|
|
13
|
+
handoffs lived before they moved to the Dispatch issue and which nothing writes or reads now, so
|
|
14
|
+
nobody reviews a path there, whatever GitHub's compare says the change did to it.
|
|
15
|
+
A conflict-forced merge goes back to the reviewer for a
|
|
15
16
|
confirmation or a new round, as the fingerprint decides (*The reviewer*, below, and
|
|
16
17
|
`skill://legion-worker/references/conflicts-and-rewrites.md`), unless READY refused it, and any
|
|
17
18
|
other change to the head voids it.
|
|
@@ -110,8 +111,8 @@ other change to the head voids it.
|
|
|
110
111
|
`REQUEST_CHANGES` when the code is at fault, and your own commit to fix when your prose broke
|
|
111
112
|
it. The architect reads your prose commits at its acceptance (*The architect's acceptance*,
|
|
112
113
|
below), and that read is no new round. A round after a READY refusal is the one exception. Its
|
|
113
|
-
approval needs the tester's results to be current at the head, or at an ancestor with only
|
|
114
|
-
under `.legion/`
|
|
114
|
+
approval needs the tester's results to be current at the head, or at an ancestor with only paths
|
|
115
|
+
under `.legion/` changed since. So there you fix no prose yourself, and you name each prose
|
|
115
116
|
finding in a `REQUEST_CHANGES`.
|
|
116
117
|
|
|
117
118
|
A reviewer's phase ends with its completion, not with its review. Every round records a handoff
|
|
@@ -133,8 +134,9 @@ reviewing until you finish.
|
|
|
133
134
|
- Between the reviewer's approval and retro the issue sits in `accepting` (Dispatch status
|
|
134
135
|
`needs_review`), where no worker is started: the tree's architect reads the evidence (the
|
|
135
136
|
tester's handoff, `dispatch results --issue <issue>` at the approved head and the reviewer's
|
|
136
|
-
approval of the head by SHA; the daemon
|
|
137
|
-
|
|
137
|
+
approval of the head by SHA; the daemon refuses the sign-off while an issue beneath it is still
|
|
138
|
+
in the workflow, `SIGNOFF_CHILD_IN_WORKFLOW`, so a parent is accepted after its children, on
|
|
139
|
+
the head of its last round, `skill://legion-architect`, section 4) and accepts with the
|
|
138
140
|
`legion` tool's `sign_off`, which moves the issue to retro, or sends it back to `implementing`
|
|
139
141
|
or `testing` with `request_backward_move` and a reason, which reaches the started worker's task
|
|
140
142
|
as its `Reason:` line and counts a review round. The acceptance comment names each check with
|
|
@@ -161,7 +163,7 @@ reviewing until you finish.
|
|
|
161
163
|
`dispatch comment` on the issue for the skill librarian, brings the PR body up to date and
|
|
162
164
|
completes (`skill://legion-retro` gives the steps), so the approved head is the head READY
|
|
163
165
|
names. Anything above the approved
|
|
164
|
-
head voids the approval, except
|
|
166
|
+
head voids the approval, except a change whose every path is under `.legion/` and a commit
|
|
165
167
|
that changes only `docs/solutions/`, which READY still lets through: READY is refused
|
|
166
168
|
`READY_UNREVIEWED_CHANGE`, naming the paths, and the merger tells the architect, who has it send
|
|
167
169
|
the head back to review instead of completing, the move's reason naming the refusal's code and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjawhar/claude-envoy",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Claude Code channel plugin for Legion's Envoy bus",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"AGENTS.md"
|
|
20
20
|
],
|
|
21
21
|
"legion": {
|
|
22
|
-
"daemonApiVersion":
|
|
22
|
+
"daemonApiVersion": 51
|
|
23
23
|
},
|
|
24
24
|
"repository": {
|
|
25
25
|
"type": "git",
|