@sjawhar/opencode-legion-envoy 9.0.0 → 9.1.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/dist/dispatch.js +35 -27
- package/dist/src/server.js +16 -15
- package/package.json +1 -1
- package/skills/AGENTS.md +7 -6
- package/skills/dispatch/SKILL.md +54 -169
- package/skills/dispatch-first/SKILL.md +23 -17
- package/skills/dispatch-writing-specs/SKILL.md +76 -0
- package/skills/leading-a-work-stream/SKILL.md +96 -0
- package/skills/leading-a-work-stream/references/daily-plan.md +8 -0
- package/skills/leading-a-work-stream/references/decision-rights.md +6 -0
- package/skills/leading-a-work-stream/references/direction-and-coaching.md +13 -0
- package/skills/leading-a-work-stream/references/dispatch-upkeep.md +7 -0
- package/skills/leading-a-work-stream/references/sources.md +9 -0
- package/skills/leading-a-work-stream/references/speed-tick.md +44 -0
- package/skills/leading-a-work-stream/references/user-quotes.md +7 -0
- package/skills/legion-architect/SKILL.md +4 -2
- package/skills/legion-architect/references/acceptance.md +11 -3
- package/skills/legion-architect/references/design-gate.md +32 -17
- package/skills/legion-architect/references/wake-routing.md +2 -2
- package/skills/legion-controller/SKILL.md +27 -16
- package/skills/legion-controller/references/backlog-stewardship.md +17 -2
- package/skills/legion-controller/references/daily-report.md +4 -4
- package/skills/legion-controller/references/finding-asks.md +111 -14
- package/skills/legion-controller/references/slack-mentions.md +2 -2
- package/skills/legion-controller/references/triage.md +9 -5
- package/skills/legion-worker/SKILL.md +5 -4
- package/skills/legion-worker/references/conflicts-and-rewrites.md +23 -16
- package/skills/legion-worker/references/findings.md +126 -31
- package/skills/legion-worker/references/merge-gate.md +48 -17
- package/skills/legion-worker/references/pr-body.md +9 -5
- package/skills/dispatch/references/api.md +0 -21
- package/skills/dispatch/references/asks.md +0 -43
- package/skills/dispatch/references/document-edits.md +0 -59
- package/skills/dispatch/references/documents.md +0 -79
- package/skills/dispatch/references/examples.md +0 -85
- package/skills/dispatch/references/issues.md +0 -66
- package/skills/dispatch/references/messages.md +0 -31
- package/skills/dispatch/references/reading.md +0 -32
- package/skills/dispatch-brainstorming/SKILL.md +0 -56
|
@@ -6,9 +6,8 @@ Read this on a `triage` wake, at every start, and when a person hands you an iss
|
|
|
6
6
|
## At every start
|
|
7
7
|
|
|
8
8
|
1. List the project's triage issues handed to Legion:
|
|
9
|
-
`dispatch issues --project <PROJECT> --status triage --label legion --
|
|
10
|
-
|
|
11
|
-
on until you have all N rows.
|
|
9
|
+
`dispatch issues --project <PROJECT> --status triage --label legion --all`. `--all` reads every
|
|
10
|
+
match in one request, so no row is missed or repeated while the list changes.
|
|
12
11
|
2. The rows show no parent, so `dispatch read` each one and follow `Links:` up through each
|
|
13
12
|
`child_of` parent. A `child_of` under `Referenced by:` is a child of this issue, not its parent.
|
|
14
13
|
3. Leave a child that has an ancestor in `admission.active` or `admission.waiting`, because that
|
|
@@ -37,13 +36,18 @@ Read this on a `triage` wake, at every start, and when a person hands you an iss
|
|
|
37
36
|
`actor` is this session (`dispatch whoami` names it) or an earlier one of yours. For a request
|
|
38
37
|
that is an ask, an earlier session is yours when its reply under that ask (`dispatch read
|
|
39
38
|
--ref`) starts `Filed dispatch://<this KEY>` after a newest answer of `File it for Legion`.
|
|
39
|
+
- Your own filing for a clear defect no tree owns hands it over too: its spec as filed holds a
|
|
40
|
+
`Filed for Legion from <role> on <issue>: <evidence>` line, and its `actor` is a session of
|
|
41
|
+
yours. An earlier session is yours when its reply under that evidence (a comment or an ask)
|
|
42
|
+
starts `Filed dispatch://<this KEY>`.
|
|
40
43
|
- Any other actor hands over nothing. Leave the issue in `triage` and ask the person on your
|
|
41
44
|
report issue whether Legion should take it, naming the issue and who labelled it, with the
|
|
42
45
|
options `Admit it` and `Leave it`. On `Admit it`, go on to step 3. Either way, reply under the
|
|
43
46
|
ask `Admitted dispatch://<KEY>` or `Not admitted: <reason>`, because the start procedure's
|
|
44
47
|
catch-up reads that reply as done.
|
|
45
|
-
3. Admit it (`set_status` to `todo`) when a person handed it over,
|
|
46
|
-
plan or the deployment instructions say to wait or put it out of
|
|
48
|
+
3. Admit it (`set_status` to `todo`) when a person or your clear-defect filing handed it over,
|
|
49
|
+
unless the request, the weekly plan or the deployment instructions say to wait or put it out of
|
|
50
|
+
scope:
|
|
47
51
|
`legion({ op: "set_status", issue: "<issue>", status: "todo" })`.
|
|
48
52
|
4. When one of those says to wait, park it with `set_status` to `backlog`, or `icebox` when the
|
|
49
53
|
request asks for a longer deferral, instead of leaving it in `triage`; the label stays. Never
|
|
@@ -35,7 +35,7 @@ Read each by its `skill://` link: a read by path stops at 300 lines.
|
|
|
35
35
|
| You write or edit the PR body, record or verify a proof, or run the simplify pass | `skill://legion-worker/references/pr-body.md` |
|
|
36
36
|
| Before a push, to check your commits' App identity | `skill://legion-worker/references/default-branch-check.md` |
|
|
37
37
|
| You reply on, list or resolve review threads, or judge a bot's finding | `skill://legion-worker/references/review-threads.md` |
|
|
38
|
-
| A conflict, a retarget, comparing heads after a
|
|
38
|
+
| A conflict, a need only the base meets, a retarget, comparing heads after a forward merge, or rewriting a pushed commit | `skill://legion-worker/references/conflicts-and-rewrites.md` |
|
|
39
39
|
| You write the `skip-checks: true` trailer, or expect a body edit to re-run a check | `skill://legion-worker/references/skip-checks-trailer.md` |
|
|
40
40
|
| You review or approve, build READY, or run the production check | `skill://legion-worker/references/merge-gate.md` |
|
|
41
41
|
| The issue renames a repository, package, or URL across the codebase | `skill://legion-worker/references/systematic-rename.md` |
|
|
@@ -52,12 +52,13 @@ Read each by its `skill://` link: a read by path stops at 300 lines.
|
|
|
52
52
|
## PR body, review, and the merge gate
|
|
53
53
|
|
|
54
54
|
- The implementer opens the pull request with the line `Dispatch: <KEY>` in its body, the daemon's link to the issue when the branch name is ambiguous. Later phases push to that branch and edit that pull request, never a new one.
|
|
55
|
-
- **No deferrals.** A finding that changes behaviour, hides an error, or breaks a gate is fixed in this pull request
|
|
55
|
+
- **No deferrals.** A finding that changes behaviour, hides an error, or breaks a gate is fixed in this pull request, and so is a wording nit or any clear fix in a file it touches: a later round costs a CI pass and a re-read of the whole change. The body's one `Fast-follow:` line reads "none", or names cleanup in files this pull request does not touch.
|
|
56
|
+
- **The reviewer fixes a prose-only finding itself** (wording, a count, a tense, a citation) in its own commit, pushed before its review. The exception is the round after a READY refusal. Code or behaviour goes back (`skill://legion-worker/references/merge-gate.md`).
|
|
56
57
|
- **The merge gate**, in order: the tester's evidence green → the reviewer's approval of the head → the architect's acceptance → retro → the merger's READY → the merge, which closes the issue → the implementer's production check, after the close. When the daemon accepts READY, it submits the merge of READY's head, unless the answer's note begins `MANUAL_MERGE_REQUIRED:`, where a person merges it; no role runs `gh pr merge`.
|
|
57
58
|
- Append `<!-- legion: {"session":"<session-id>","phase":"<phase>"} -->` to every pull-request comment and review you post: the daemon finds the session behind a review by it.
|
|
58
59
|
- Never write a GitHub issue, by `gh issue` or a non-GET `gh api` on `/issues` (post or edit a PR conversation comment with `gh pr comment`): Legion's issues live on Dispatch. Never run `gh config set` or `gh alias set`, and leave `GH_TOKEN`, `GITHUB_TOKEN` and `GH_HOST` empty: the daemon rewrites your gh directory in place, and a set variable outranks it.
|
|
59
|
-
- Before you report a resource unreachable, check `AGENT_SECRETS_URL` and `AGENT_SECRETS_KEY_DIR` (then `agent-secrets <SECRET> -- <command>`; sjawhar/legion `docs/kubernetes.md`, "Operator configuration") and `AWS_CONFIG_FILE` (read its profiles): a deployment can give your pod either. `agent-secrets` refuses a secret its grant lacks and names it; that refusal is final. Your `task` subagents and background jobs inherit both, and your `gh` and `git`.
|
|
60
|
+
- Before you report a resource unreachable, check `AGENT_SECRETS_URL` and `AGENT_SECRETS_KEY_DIR` (then `agent-secrets <SECRET> -- <command>`; sjawhar/legion `docs/kubernetes.md`, "Operator configuration") and `AWS_CONFIG_FILE` (read its profiles): a deployment can give your pod either. `agent-secrets` refuses a secret its grant lacks and names it; that refusal is final. Your `task` subagents and background jobs inherit both, and your `gh` and `git`. Request a secret only to use it for your issue's work, never to learn whether it exists. A request for a secret your role does not hold reaches a person's Inbox.
|
|
60
61
|
|
|
61
62
|
## Deployment instructions
|
|
62
63
|
|
|
63
|
-
Deployment instructions in your prompt override this skill where they conflict, except four rules: no deferrals; bringing the base into the branch only on a real conflict or a retarget (`skill://legion-worker/references/conflicts-and-rewrites.md#reintegrating-the-base`); the implementer's own proof on a production-like surface at the head that merges, an applied simplify head included (`skill://legion-worker/references/pr-body.md#what-a-proof-is`, `skill://legion-worker/references/pr-body.md#the-rules-every-phases-evidence-follows`); and the implementer's production check after the close (`skill://legion-worker/references/merge-gate.md#the-production-check-after-the-close`).
|
|
64
|
+
Deployment instructions in your prompt override this skill where they conflict, except four rules: no deferrals; bringing the base into the branch only on a real conflict, a need only the base meets, or a retarget (`skill://legion-worker/references/conflicts-and-rewrites.md#reintegrating-the-base`); the implementer's own proof on a production-like surface at the head that merges, an applied simplify head included (`skill://legion-worker/references/pr-body.md#what-a-proof-is`, `skill://legion-worker/references/pr-body.md#the-rules-every-phases-evidence-follows`); and the implementer's production check after the close (`skill://legion-worker/references/merge-gate.md#the-production-check-after-the-close`).
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
# Conflicts, retargets, fingerprints, and rewriting pushed commits
|
|
2
2
|
|
|
3
3
|
Part of `skill://legion-worker`. Read it when GitHub reports the pull request `CONFLICTING`, the
|
|
4
|
-
controller asks you to resolve a conflict, the
|
|
5
|
-
compare two heads after such a merge, or you are about to
|
|
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, or you are about to
|
|
6
|
+
rewrite a commit you already pushed.
|
|
6
7
|
Every path it cites is in sjawhar/legion.
|
|
7
8
|
|
|
8
9
|
## Reintegrating the base
|
|
9
10
|
|
|
10
|
-
- **
|
|
11
|
-
|
|
11
|
+
- **Merge the base forward only on a real conflict, a need only the base meets, or a retarget, and
|
|
12
|
+
never with `jj rebase`.**
|
|
12
13
|
The implementer merges the base into the issue branch only when GitHub reports it `CONFLICTING`, the controller asks
|
|
13
|
-
because of a conflict,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
the merge
|
|
14
|
+
because of a conflict, the change needs something that exists only on the base (a fix for its
|
|
15
|
+
only red check, or a sentence it must change), or after the pull request is retargeted to a new
|
|
16
|
+
base. Otherwise, never reintegrate the base to pick up the default branch or refresh CI. Each
|
|
17
|
+
merge is a new head, reruns CI and can void a review. A single failed CI job is re-run on its
|
|
18
|
+
own (*Never waiting on CI* in `skill://legion-worker/references/pr-body.md`). After any forward merge, build the branch and
|
|
19
|
+
run its proof again at the merge head, even with no text conflict: a clean merge once changed a
|
|
20
|
+
function's arity under the branch's own callers. Before you race another tree's pull request on
|
|
21
|
+
shared files, `envoy_publish` to its implementer's role topic, ask when its next push lands, and
|
|
22
|
+
merge once, after it. A forward merge that leaves the branch's diff unchanged is a
|
|
23
|
+
confirmation, not a new round (see *The unchanged-diff check* below). The check compares the
|
|
24
|
+
pull request's own lines file by file: a changed file sends the head through the tester again,
|
|
25
|
+
and your comment names it. Before merging, record
|
|
19
26
|
the fingerprint at the current tip; after pushing the merged branch, record it at the new
|
|
20
27
|
tip; post one PR comment (Legion footer):
|
|
21
|
-
`
|
|
28
|
+
`forward merge <old-tip-sha> → <new-tip-sha>; fingerprint <before> → <after>; unchanged|changed`.
|
|
22
29
|
On the tmux runtime, where issue workspaces are still jj workspaces of one shared clone,
|
|
23
30
|
`jj undo`, `jj abandon` and `jj op restore` rewrite the shared operation log, so a mistake there
|
|
24
31
|
is recovered forward (`jj -R "$LEGION_WORKSPACE" new`, or `jj -R "$LEGION_WORKSPACE" restore
|
|
@@ -57,7 +64,7 @@ Every path it cites is in sjawhar/legion.
|
|
|
57
64
|
|
|
58
65
|
## The unchanged-diff check
|
|
59
66
|
|
|
60
|
-
The fingerprint every role compares after a
|
|
67
|
+
The fingerprint every role compares after a forward merge (every flag and the fileset
|
|
61
68
|
verified on jj 0.45.1):
|
|
62
69
|
|
|
63
70
|
```bash
|
|
@@ -70,16 +77,16 @@ fingerprint=$(set -o pipefail; jj -R "$LEGION_WORKSPACE" diff --from "fork_point
|
|
|
70
77
|
|
|
71
78
|
- `<head-sha>` is a full commit SHA; a jj commit id is the git SHA GitHub shows.
|
|
72
79
|
- `fork_point(${base}@origin | <head-sha>)` is the base the branch was cut from *at that head*:
|
|
73
|
-
the old base for the
|
|
80
|
+
the old base for the head before the merge, the new base for the merge head, so one command serves
|
|
74
81
|
both sides. `base` is the pull request's base branch as a jj string literal, as in the merge
|
|
75
82
|
above.
|
|
76
|
-
- A head the
|
|
83
|
+
- A head the merge replaced is still addressable by its SHA in the shared workspace. The check
|
|
77
84
|
prints a fingerprint only when every step of it succeeded: the base read, the fetch and the
|
|
78
85
|
diff (`pipefail` keeps the diff's failure through `sed` and `sha256sum`, which would otherwise
|
|
79
86
|
hash empty input to `e3b0c442…`). A nonzero exit or no printed fingerprint (a failed read of the
|
|
80
87
|
base, or a SHA the workspace cannot resolve) counts as a changed diff — never as unchanged.
|
|
81
88
|
- `--context 0` drops context lines; the `sed` drops `@@` hunk headers (line positions move
|
|
82
|
-
on a
|
|
89
|
+
on a merge) and `index` lines (blob ids move when the base's copy of a file changed). What
|
|
83
90
|
is left is exactly the added and removed lines per file.
|
|
84
91
|
- The single fileset `'~(.legion | docs/solutions)'` leaves out the handoff ledger and retro's
|
|
85
92
|
learnings: process artifacts the merge gate already exempts from re-review
|
|
@@ -91,7 +98,7 @@ fingerprint=$(set -o pipefail; jj -R "$LEGION_WORKSPACE" diff --from "fork_point
|
|
|
91
98
|
`.legion/` is gone, jj warns `No matching entries for paths: .legion` on stderr; the hash is
|
|
92
99
|
unaffected.
|
|
93
100
|
|
|
94
|
-
Where each role gets its two heads: the implementer — the tip before and after its own
|
|
101
|
+
Where each role gets its two heads: the implementer — the tip before and after its own forward merge;
|
|
95
102
|
the tester — the head its `E2E` line names and the new head; the reviewer — the `commit_id` of
|
|
96
103
|
its last submitted review (`gh api --paginate repos/{owner}/{repo}/pulls/{n}/reviews --jq '.[] | {commit_id, state, user: .user.login, body}'`, whose pages concatenate in order, so the last line is the last submitted review, and whose body tells a no-fix request that answered a READY refusal from any other)
|
|
97
104
|
and the new head; the merger never computes a fingerprint — it quotes the `--summary` lines
|
|
@@ -3,12 +3,27 @@
|
|
|
3
3
|
Read this when you find a problem the issue you work does not cover: a defect in another
|
|
4
4
|
component, repository or tool, a gap in Legion itself, or a production check's `fail`. It holds for
|
|
5
5
|
every Legion role (each phase worker, each architect, the controller) and for each of their
|
|
6
|
-
subagents, and it replaces the filing step of `skill://dispatch-first` and `skill://dispatch`.
|
|
6
|
+
subagents, and it replaces the filing step of `skill://dispatch-first` and `skill://dispatch`. The
|
|
7
|
+
controller fixes nothing itself: it hands a finding to the tree that owns the code, as
|
|
8
|
+
`skill://legion-controller`, "Findings, and the issues you file", says.
|
|
7
9
|
|
|
8
|
-
##
|
|
10
|
+
## Fix it where you are, else hand it over, and ask only for a decision
|
|
9
11
|
|
|
10
|
-
A finding outside your issue
|
|
11
|
-
|
|
12
|
+
A finding outside your issue never becomes a `dispatch issue` you file. Take the first of these
|
|
13
|
+
three steps that fits:
|
|
14
|
+
|
|
15
|
+
1. **Fix it here.** A defect with a clear fix in code your tree touches or depends on goes into
|
|
16
|
+
your tree's own pull request, while you are in that code. The fix needs no choice a person must
|
|
17
|
+
make, and the evidence shows the defect. Say in your handoff and in the pull request body what
|
|
18
|
+
you fixed beside the issue's own work. A fix deferred to another issue is a fix nobody makes.
|
|
19
|
+
2. **Hand it over.** Any other clear defect goes to the controller with its evidence, as [Send a
|
|
20
|
+
finding to the controller](#send-a-finding-to-the-controller) says. The controller gives it to
|
|
21
|
+
the running tree whose code it is. Only when no tree owns that code does it file a Legion root.
|
|
22
|
+
3. **Ask.** A finding that needs a person's authority, taste or risk appetite is a `dispatch ask`
|
|
23
|
+
with one recommendation, as [Where it goes](#where-it-goes) says: whether the work is wanted at
|
|
24
|
+
all, which of several designs, who owns it, or a change of scope, cost or risk.
|
|
25
|
+
|
|
26
|
+
A fix you are not sure of is not step 1: hand it over, or ask when a person must decide.
|
|
12
27
|
|
|
13
28
|
- A problem inside your issue is not such a finding: fix it in your change, since nothing needed
|
|
14
29
|
for correctness is deferred.
|
|
@@ -17,21 +32,89 @@ whether it needs an issue, where, and whether Legion works it.
|
|
|
17
32
|
rules*), which may file it as a child of the tree. Anything else, in the same
|
|
18
33
|
repository or not, is a finding.
|
|
19
34
|
- Search first (`skill://dispatch-first`): when an open issue already tracks the problem, comment
|
|
20
|
-
the evidence on that issue and ask nothing. When an open ask on the report issue already
|
|
21
|
-
about it (`dispatch open-asks --project <PROJECT>` lists them), add your evidence under that
|
|
22
|
-
(`dispatch comment --issue <REPORT KEY> --reply-to-ask '<ask id>' --body-file -`, the
|
|
23
|
-
stdin) and open no second one.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
the evidence on that issue and send or ask nothing. When an open ask on the report issue already
|
|
36
|
+
asks about it (`dispatch open-asks --project <PROJECT>` lists them), add your evidence under that
|
|
37
|
+
ask (`dispatch comment --issue <REPORT KEY> --reply-to-ask '<ask id>' --body-file -`, the
|
|
38
|
+
evidence on stdin) and open no second one.
|
|
39
|
+
|
|
40
|
+
These issues are filed:
|
|
41
|
+
|
|
42
|
+
- an architect's children of its own tree (`dispatch issue --parent`, `skill://legion-architect`)
|
|
43
|
+
- a Legion root the controller files for a clear defect no running tree owns
|
|
44
|
+
- an issue a person asked the controller to file, in a direct message, in a Slack request, or in
|
|
45
|
+
their answer to an ask
|
|
46
|
+
- the report issue itself, which the controller creates once when the project has none
|
|
47
|
+
|
|
48
|
+
`skill://legion-controller`, "Findings, and the issues you file", and
|
|
49
|
+
`skill://legion-controller/references/daily-report.md` say how.
|
|
50
|
+
|
|
51
|
+
## Send a finding to the controller
|
|
52
|
+
|
|
53
|
+
Post the evidence first as a `dispatch comment` on the report issue ([Where it goes](#where-it-goes)
|
|
54
|
+
says which), its first line exactly `Clear defect from <your role token>`. It prints
|
|
55
|
+
`Posted comment <id>`. Then send the controller one message with
|
|
56
|
+
`envoy_publish` to the controller topic your `Legion addressing` line names, with
|
|
57
|
+
`expects_reply: none`. It holds:
|
|
58
|
+
|
|
59
|
+
- your role token, from your `Legion addressing` line
|
|
60
|
+
- the defect, as its reader recognises it, and the issue it came from (`dispatch://<KEY>`)
|
|
61
|
+
- where the fix belongs: the repository and the component
|
|
62
|
+
- the fix
|
|
63
|
+
- the evidence comment, `dispatch://<REPORT KEY>/comment/<id>`
|
|
64
|
+
|
|
65
|
+
The controller hands it to the running tree whose code it is, and files a Legion root only when no
|
|
66
|
+
tree owns that code. Either way it replies under your evidence comment with where the work went.
|
|
67
|
+
You file nothing, and you wait for nothing. When the report issue is missing or closed, put the
|
|
68
|
+
evidence in the message itself. A production check's `Production:` line then names the defect as
|
|
69
|
+
sent to the controller.
|
|
70
|
+
|
|
71
|
+
### When no controller takes it
|
|
72
|
+
|
|
73
|
+
The controller topic is a live wake: a message published while no controller runs reaches nobody,
|
|
74
|
+
and no controller reads it later. `envoy_publish`'s own answer tells you whether one took it. A
|
|
75
|
+
publish to a role answers with its live `holder`. With no live controller it fails instead, with
|
|
76
|
+
`no holder for role legion-<project>-controller` or a holder that lapsed, and the listener delivers
|
|
77
|
+
nothing (`packages/envoy/cmd/listener`, the test "unheld role returns 404 without publishing").
|
|
78
|
+
Then make the finding an ask, as [What the ask says](#what-the-ask-says) spells it, on the first
|
|
79
|
+
of these that holds, so a person sees it and the controller finds it when it returns:
|
|
80
|
+
|
|
81
|
+
1. **The report issue is open:** ask there, the question opening `Clear defect from <your role
|
|
82
|
+
token>` and `--ref` naming your evidence comment. Then reply `Asked dispatch://<REPORT
|
|
83
|
+
KEY>/ask/<id>` under that comment, so the controller takes the ask and not the comment. The
|
|
84
|
+
report issue's assignee sees the ask, and the controller's catch-up takes it.
|
|
85
|
+
2. **The report issue is missing or closed:** ask on your own issue, the evidence posted there as
|
|
86
|
+
a comment first. Then publish the ask's reference to your tree's architect (`skill://legion-worker`,
|
|
87
|
+
*Stop rules*). An architect holds its own. The architect holds your issue's
|
|
88
|
+
acceptance until a controller has taken the ask (`skill://legion-architect`, "Acceptance and the
|
|
89
|
+
merge"). That hold is what keeps the ask readable: an open ask on a closed issue drops out of
|
|
90
|
+
the controller's own listing (`asks.go`'s `listOpenAsks` takes `i.closed_at is null`), so an
|
|
91
|
+
issue that closed over one hides it for good.
|
|
92
|
+
3. **Your own issue is closed too** (Dispatch refuses the ask `409 ISSUE_CLOSED`, as on a
|
|
93
|
+
production check): put the report issue back in reach yourself, with the `dispatch` commands
|
|
94
|
+
below, and ask there. Never `legion({op: "set_status"})`, which the controller's report steps
|
|
95
|
+
(`skill://legion-controller/references/daily-report.md`) use: that op is the controller's
|
|
96
|
+
alone, and your session is refused `set_status is not
|
|
97
|
+
available to a phase-worker session` (`packages/pi-legion/src/tools.ts`'s `OPERATIONS`). No
|
|
98
|
+
other issue can hold an answerable ask, so this is the one case a role writes the report issue.
|
|
99
|
+
- It exists and is closed: `dispatch issue-update --issue <REPORT KEY> --status icebox`. Send
|
|
100
|
+
the status by itself. A closed issue takes a reopening status alone, and refuses it beside
|
|
101
|
+
an assignee or any other field (`api/issue_patch.go`, the `before.ClosedAt` branch). This is
|
|
102
|
+
the one lifecycle status your own prompt lets you write. The report issue is in no tree, so
|
|
103
|
+
the daemon re-asserts nothing on it: `workflow`'s `sessionStatusWrite` acts only for a
|
|
104
|
+
session that claims the issue's tree, or for an admitted root.
|
|
105
|
+
- A search finds none: create it as "Where it goes" names it, `dispatch issue --project
|
|
106
|
+
<PROJECT> --title 'Legion daily report' --spec-file -`, with the Summary
|
|
107
|
+
`skill://legion-controller/references/daily-report.md` gives, then park it with
|
|
108
|
+
`dispatch issue-update --issue <NEW KEY> --status icebox`. It carries no `legion` label.
|
|
109
|
+
- Then post the evidence there and ask there, as [What the ask says](#what-the-ask-says)
|
|
110
|
+
spells it. Say in your summary that you reopened or created it, so the controller knows.
|
|
111
|
+
|
|
112
|
+
Name the ask in your summary, and in a production check's `Production:` line.
|
|
30
113
|
|
|
31
114
|
## Where it goes
|
|
32
115
|
|
|
33
|
-
|
|
34
|
-
reports, else the project's `Legion daily report`, which
|
|
116
|
+
An ask goes on the controller's report issue whenever it is open: the issue the deployment
|
|
117
|
+
instructions name for Legion's reports, else the project's `Legion daily report`, which
|
|
35
118
|
`dispatch search --query '"Legion daily report"' --project <PROJECT>` finds. It stays open in
|
|
36
119
|
`icebox`, so the ask stays answerable whatever happens to the issue it came from; once an issue
|
|
37
120
|
closes, Dispatch takes its open asks out of the Inbox and refuses their answers
|
|
@@ -42,49 +125,61 @@ When the project has no report issue yet, or a person closed it (`dispatch read`
|
|
|
42
125
|
done`, and Dispatch refuses the ask with `409 ISSUE_CLOSED`), do not create or reopen one yourself
|
|
43
126
|
(the controller does): send the finding to the controller as text, with `envoy_publish` to the
|
|
44
127
|
controller topic your `Legion addressing` line names (`expects_reply: none`), holding the problem,
|
|
45
|
-
the issue it came from and the
|
|
46
|
-
opens the ask.
|
|
47
|
-
controller.
|
|
128
|
+
the issue it came from, the evidence and the decision it needs. The controller creates or reopens
|
|
129
|
+
the report issue and opens the ask. When that publish fails because no controller holds the role,
|
|
130
|
+
take step 2 or 3 of [When no controller takes it](#when-no-controller-takes-it). A production
|
|
131
|
+
check's `Production:` line then names the finding as sent to the controller, or names the ask.
|
|
48
132
|
|
|
49
|
-
## What
|
|
133
|
+
## What the ask says
|
|
50
134
|
|
|
51
135
|
The question stands alone, since the ask view shows no comment. It holds at most 800 characters,
|
|
52
136
|
the `Ref: <reference>` line `--ref` appends included (about 75 characters for a comment's
|
|
53
|
-
reference).
|
|
137
|
+
reference). Its first line names who asks: `Clear defect from <your role token>` for a clear
|
|
138
|
+
defect no controller took, else `Finding from <your role token>`. The architect's acceptance and the
|
|
139
|
+
controller's catch-up find a finding ask by that line. Then it carries:
|
|
54
140
|
|
|
55
141
|
- the problem, as its reader recognises it, and the issue it came from (`dispatch://<KEY>`);
|
|
56
142
|
- where the fix would belong: the repository or layer, and a plain statement that it is not
|
|
57
143
|
Legion's when it is not. A problem is not Legion's because you work in Legion: name the
|
|
58
144
|
component that misbehaved;
|
|
59
|
-
- your recommendation and its reason.
|
|
145
|
+
- the decision a person must make, and your recommendation and its reason. A clear defect no
|
|
146
|
+
controller took carries the fix instead, and its options ask where the work goes, with
|
|
147
|
+
`Hand it to the owning tree` first and recommended.
|
|
60
148
|
|
|
61
149
|
The evidence (the commands, their output and its time, the file and line, the pull request) does
|
|
62
|
-
not fit. Post it first as a `dispatch comment` on the
|
|
63
|
-
|
|
150
|
+
not fit. Post it first as a `dispatch comment` on the issue the ask goes on, which prints `Posted
|
|
151
|
+
comment <id>`, and cite that comment with `--ref`, the one reference an ask takes. That issue,
|
|
152
|
+
`<ASK KEY>` below, is the report issue, except as [When no controller takes
|
|
153
|
+
it](#when-no-controller-takes-it) says:
|
|
64
154
|
|
|
65
155
|
```bash
|
|
66
|
-
dispatch comment --issue <
|
|
156
|
+
dispatch comment --issue <ASK KEY> --body-file - <<'EOF'
|
|
67
157
|
<the evidence: commands, output with its time, file:line, links>
|
|
68
158
|
EOF
|
|
69
|
-
#
|
|
70
|
-
# `File
|
|
71
|
-
|
|
159
|
+
# Keep `File it for Legion` only when your Legion addressing line lists the repository where the
|
|
160
|
+
# fix belongs. For a clear defect no controller took, replace the `File an issue` option below with
|
|
161
|
+
# 'Hand it to the owning tree: <the tree, when you know it>', the first option and recommended.
|
|
162
|
+
dispatch ask --issue <ASK KEY> --ref 'dispatch://<ASK KEY>/comment/<id>' --question-file - \
|
|
72
163
|
--option 'File an issue: <what it would track, and who would own it>' \
|
|
73
164
|
--option 'File it for Legion: Legion works it once it is filed' \
|
|
74
165
|
--option 'Do not file: <what stays as it is>' <<'EOF'
|
|
166
|
+
Finding from <your role token>
|
|
75
167
|
<the problem and dispatch://<KEY> it came from; where the fix belongs, and that it is not Legion's when it is not; your recommendation and why>
|
|
76
168
|
EOF
|
|
77
169
|
```
|
|
78
170
|
|
|
79
171
|
Legion refuses to record an issue on a repository the project does not map, hence that condition.
|
|
80
172
|
|
|
81
|
-
## Tell the controller
|
|
173
|
+
## Tell the controller about the ask
|
|
82
174
|
|
|
83
175
|
The person answers in Dispatch, and the answer reaches only the ask's followers. So once the ask is
|
|
84
176
|
open, `envoy_publish` its reference, `dispatch://<REPORT KEY>/ask/<id>` (the id from the
|
|
85
177
|
`Asked <id> on …` line), to the controller topic your `Legion addressing` line names, with
|
|
86
178
|
`expects_reply: none`. The controller follows the ask and files what the person's answer asks for;
|
|
87
179
|
you file nothing, whatever the answer says. The controller itself skips this step, since it follows
|
|
88
|
-
each ask it opens.
|
|
180
|
+
each ask it opens. When that publish names no holder, do nothing more for an ask on the report
|
|
181
|
+
issue: the controller's catch-up follows it at its next start.
|
|
89
182
|
|
|
90
|
-
|
|
183
|
+
An ask on the report issue blocks nothing of your own issue: its work goes on. One on your own
|
|
184
|
+
issue holds its acceptance, as step 2 of [When no controller takes
|
|
185
|
+
it](#when-no-controller-takes-it) says.
|
|
@@ -67,7 +67,7 @@ it, and any other change to the head voids it.
|
|
|
67
67
|
Legion footer), and a `comments[]` array of `{path, line, side, body}`, one entry per
|
|
68
68
|
finding — never one `pr review` call per finding (each submission fires a `pr-review` wake).
|
|
69
69
|
A `COMMENT` decides nothing. After a
|
|
70
|
-
|
|
70
|
+
forward merge, compute the fingerprint (*The unchanged-diff check* in
|
|
71
71
|
`skill://legion-worker/references/conflicts-and-rewrites.md`) at the
|
|
72
72
|
`commit_id` of your last submitted review and at the new head. Equal and that review was
|
|
73
73
|
`APPROVE`: submit one more `APPROVE` naming the new head by SHA, its body naming both SHAs
|
|
@@ -75,24 +75,45 @@ it, and any other change to the head voids it.
|
|
|
75
75
|
that review was `COMMENT` or `REQUEST_CHANGES`: continue that round against the new head;
|
|
76
76
|
nothing restarts. Different, or either run printed no fingerprint: a new round — thermo again,
|
|
77
77
|
one review. A return whose task's `Reason:` names a READY refusal is never a confirmation, even
|
|
78
|
-
after a
|
|
78
|
+
after a forward merge, and a no-fix `REQUEST_CHANGES` that answered one is never continued: the round
|
|
79
79
|
after it reviews the refused change in full from the last `APPROVE` (*Retro's commits do not
|
|
80
80
|
void the reviewer's approval* below).
|
|
81
81
|
- Answer every thread you opened, and every thread a bot opened that is none of Legion's role
|
|
82
82
|
Apps, as `skill://legion-worker/references/review-threads.md` says; the same reference says
|
|
83
83
|
when every thread is settled enough to approve, and resolving one never gates your approval.
|
|
84
|
+
- **Fix a prose-only finding yourself** — wording, a count, a tense, a citation — in your own
|
|
85
|
+
commit on the pull request, and list it in your review. Send the work back only for a finding
|
|
86
|
+
that touches code or behaviour. Push the fix **before** you submit the round's review, and
|
|
87
|
+
review the head that push made. A change pushed above the head you approved leaves the approval
|
|
88
|
+
standing for nothing: the round goes stuck and your architect is told (`ApprovalStands` in
|
|
89
|
+
`packages/daemon/internal/classify/decisions.go`, `stuckApprovedOtherCode` in
|
|
90
|
+
`packages/daemon/internal/workflow/review.go`, and the cases "the approval, then a code push"
|
|
91
|
+
and "a push since the approved head changed code, then an approval of the head" in
|
|
92
|
+
`packages/daemon/internal/workflow/review_test.go`). That push carries no `skip-checks: true`
|
|
93
|
+
line, so GitHub runs the branch's workflows on it. Wait for that head's required checks to be
|
|
94
|
+
green, and approve only then. The daemon sends nothing back for a red at a head the review App
|
|
95
|
+
pushed (`PlannedRed` in `classify/decisions.go`), so your own read is the only one. A red you
|
|
96
|
+
approve over reaches nobody: the tree runs on to the merge, where GitHub holds the pull request
|
|
97
|
+
under the base branch's required checks until someone reads them. A red there is a
|
|
98
|
+
`REQUEST_CHANGES` when the code is at fault, and your own commit to fix when your prose broke
|
|
99
|
+
it. The architect reads your prose commits at its acceptance (*The architect's acceptance*,
|
|
100
|
+
below), and that read is no new round. A round after a READY refusal is the one exception. Its
|
|
101
|
+
approval needs the tester's `E2E` line to name the head with only `.legion/` changed since. So
|
|
102
|
+
there you fix no prose yourself, and you name each prose finding in a `REQUEST_CHANGES`.
|
|
84
103
|
|
|
85
104
|
A reviewer's phase ends with its completion, not with its review. Every round writes a handoff
|
|
86
105
|
and takes this order: read CI as above; write, commit and push the handoff; submit the review of
|
|
87
106
|
the head that push made, by its SHA; then complete. A red at the code is a `REQUEST_CHANGES`
|
|
88
107
|
naming the check, never an approval. A request for changes does not wait, since it stands
|
|
89
|
-
whatever CI says and the issue leaves reviewing with it. The approval waits on nothing at
|
|
90
|
-
handoff commit either: it ends the round whatever CI says there, since the round reads no CI
|
|
108
|
+
whatever CI says and the issue leaves reviewing with it. The approval waits on nothing at a
|
|
109
|
+
handoff-only commit either: it ends the round whatever CI says there, since the round reads no CI
|
|
91
110
|
verdict, and a red the daemon reads later — at that commit or any above it — is the code's red
|
|
92
111
|
and resumes the implementer from wherever the issue is (reviewing, retro or merging) without the
|
|
93
|
-
reviewer. A
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
reviewer. A head your own push changed beyond `.legion/` is the exception. The daemon marks it a
|
|
113
|
+
planned red and sends nothing back for it, so wait for its checks yourself (*Fix a prose-only
|
|
114
|
+
finding yourself*, above). A review of a head the handoff push then replaces names a head the pull
|
|
115
|
+
request no longer has. The daemon moves the issue once both are in — the decision GitHub reports
|
|
116
|
+
and your completion, in either order — so a review posted without a completion leaves the issue in
|
|
96
117
|
reviewing until you finish.
|
|
97
118
|
|
|
98
119
|
## The architect's acceptance
|
|
@@ -103,9 +124,14 @@ reviewing until you finish.
|
|
|
103
124
|
approval of the head by SHA, and for a parent that every child is done) and accepts with the
|
|
104
125
|
`legion` tool's `sign_off`, which moves the issue to retro, or sends it back to `implementing`
|
|
105
126
|
or `testing` with `request_backward_move` and a reason, which reaches the started worker's task
|
|
106
|
-
as its `Reason:` line and counts a review round. The
|
|
107
|
-
|
|
108
|
-
|
|
127
|
+
as its `Reason:` line and counts a review round. The architect also reads the reviewer's own
|
|
128
|
+
prose commits here, with the rest of the evidence, and that read is no new round. It does not
|
|
129
|
+
accept while the issue holds a finding ask no controller has taken (`findings.md`, "When no
|
|
130
|
+
controller takes it"). The acceptance asks no `Production:` line of anyone: that line is written
|
|
131
|
+
after the close (*The production check after the close*, below).
|
|
132
|
+
CI red at the head in `accepting` returns the issue to `implementing` as it does in review. A
|
|
133
|
+
head the review App pushed beyond `.legion/` is the exception: the daemon marks it a planned red
|
|
134
|
+
and acts on it nowhere, and GitHub holds the merge under the base branch's own rules.
|
|
109
135
|
|
|
110
136
|
## Retro
|
|
111
137
|
|
|
@@ -246,11 +272,13 @@ reviewing until you finish.
|
|
|
246
272
|
previous release, a daemon still running the previous commit, a deploy nobody has run): the
|
|
247
273
|
summary names what is missing, and the `Production:` line stays at
|
|
248
274
|
`pending deploy of <merge sha>`.
|
|
249
|
-
- `fail`, for a defect:
|
|
250
|
-
`skill://legion-worker/references/findings.md`
|
|
251
|
-
topic,
|
|
252
|
-
|
|
253
|
-
|
|
275
|
+
- `fail`, for a defect: file no issue, and take the path
|
|
276
|
+
`skill://legion-worker/references/findings.md` gives it. A defect with a clear fix goes to the
|
|
277
|
+
controller topic, with its evidence comment on the controller's report issue. A defect that
|
|
278
|
+
needs a decision is a `dispatch ask` on the report issue, and you publish its reference to the
|
|
279
|
+
controller topic. Either names this issue, the pull request, the merge commit, what you drove
|
|
280
|
+
and what failed. Name the message or the ask (`dispatch://<REPORT KEY>/ask/<id>`) in the
|
|
281
|
+
`Production:` line and in the summary.
|
|
254
282
|
- **Nothing waits in the session for a deploy.** A `pending` ends the look. Where no wake is
|
|
255
283
|
queued yet, the daemon suspends your claim with its session kept, and the issue's Sandbox goes
|
|
256
284
|
with its pod and disk; where a wake arrived while the look was open, the next look starts at once
|
|
@@ -278,8 +306,11 @@ reviewing until you finish.
|
|
|
278
306
|
run because production did not carry the merge within the bound.
|
|
279
307
|
- **The record lives on the pull request alone.** Dispatch refuses a message, a comment or an ask
|
|
280
308
|
on a closed issue (`ISSUE_CLOSED`), so the deployment instructions' "on the pull request and the
|
|
281
|
-
issue" is the pull request for a closed issue
|
|
282
|
-
|
|
309
|
+
issue" is the pull request for a closed issue. A defect reaches Dispatch by the two paths above:
|
|
310
|
+
a clear defect as the message to the controller, which gives it to the tree that owns that code,
|
|
311
|
+
and any other as the ask on the
|
|
312
|
+
controller's report issue. The architect accepted the issue before the merge and is asked
|
|
313
|
+
nothing after it. `pass` or
|
|
283
314
|
`fail` closes the check: your claim is retired and the issue's Sandbox goes with its pod and
|
|
284
315
|
disk, for a root as for a child. Neither ending retires or suspends anything of an issue back in
|
|
285
316
|
the workflow (a root reopened inside its linger): its claim and pod are the new run's.
|
|
@@ -43,7 +43,7 @@ Verified the implementer's proof by <re-running its command | driving the same s
|
|
|
43
43
|
**Production:** <what was checked in production, how, what was observed> — merge commit <sha>; woken by <event>.
|
|
44
44
|
(written by the implementer from the production check after the merge closes the issue, naming what woke that look; `pending deploy of <sha>` until then)
|
|
45
45
|
|
|
46
|
-
**Fast-follow:**
|
|
46
|
+
**Fast-follow:** "none", or one named cleanup item in a file this pull request does not touch, and where it will land.
|
|
47
47
|
|
|
48
48
|
**Chain:** stacked on <base bookmark> frozen at <sha> / not stacked.
|
|
49
49
|
```
|
|
@@ -124,13 +124,13 @@ and the tester's proof below are both this proof.
|
|
|
124
124
|
tester names that missing surface as the blocker instead of passing the phase. Environment or
|
|
125
125
|
secret-scrub evidence (e.g. "`LEGION_*`/`DISPATCH_*`/`ENVOY_*` unset") is recorded once, in
|
|
126
126
|
`.legion/<issue>/test.json`, and only when the issue's acceptance criteria call for it — never
|
|
127
|
-
re-pasted into the PR body each round. After a
|
|
127
|
+
re-pasted into the PR body each round. After a forward merge, compute the
|
|
128
128
|
fingerprint (*The unchanged-diff check* in
|
|
129
129
|
`skill://legion-worker/references/conflicts-and-rewrites.md`) at the head your `E2E` line
|
|
130
130
|
names and at the new head. Equal: re-run only the
|
|
131
131
|
bare gates — the repository's CI green at the new head and its smoke check — and change the
|
|
132
132
|
`E2E` line's head to the new SHA with
|
|
133
|
-
`
|
|
133
|
+
`forward-merge re-check <old-sha> → <new-sha>: fingerprint unchanged, bare gates only`. The
|
|
134
134
|
real-surface verification is not repeated. Different: a full test round.
|
|
135
135
|
- **The implementer runs `skill://ce-simplify-code` once per pull request, in its first
|
|
136
136
|
implementing round, after its own proof and before it completes that round, when the diff
|
|
@@ -144,8 +144,12 @@ and the tester's proof below are both this proof.
|
|
|
144
144
|
That cost is why 0-applied is the expected outcome and a pass that applies is spent sparingly.
|
|
145
145
|
The reviewer's pair runs at the head each round reviews. Record both in the `Thermo` line.
|
|
146
146
|
- **No deferrals** is the body's rule (*PR body, review, and the merge gate* in
|
|
147
|
-
`skill://legion-worker`):
|
|
148
|
-
|
|
147
|
+
`skill://legion-worker`): a wording nit, and any clear fix in a file this pull request touches,
|
|
148
|
+
is made in the running round, because a later round costs a CI pass and a re-read of the whole
|
|
149
|
+
change (the operator's answer on that case: fix it while you are there, and defer no fix to
|
|
150
|
+
another issue). The `Fast-follow:` line reads
|
|
151
|
+
`none`, or names only cleanup in files this pull request does not touch.
|
|
152
|
+
A base frozen for others to stack on is never rewritten (*Rewriting pushed commits* in
|
|
149
153
|
`skill://legion-worker/references/conflicts-and-rewrites.md`); the `Chain` line records it.
|
|
150
154
|
- **GitHub refuses a pull request body over 65,536 characters.** Each verification round links its
|
|
151
155
|
evidence (the run, the comment) rather than inlining it once the body passes about 48,000
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Authentication and the HTTP API
|
|
2
|
-
|
|
3
|
-
Read this to set up a Dispatch token, or to call a route no `dispatch` command covers.
|
|
4
|
-
|
|
5
|
-
## Agent authentication
|
|
6
|
-
|
|
7
|
-
- Use a personal token. A human mints it in Dispatch **Settings → Agent tokens**. Supply it as `DISPATCH_TOKEN` or as `dispatch.token` in the session's `envoy.json`. The server records that human as the owner of your writes.
|
|
8
|
-
- Which `envoy.json`: the session's own directory under an Oh My Pi profile other than `default`, a Claude Code `CLAUDE_CONFIG_DIR` or an OpenCode `OPENCODE_CONFIG_DIR`. Otherwise the file `ENVOY_CONFIG_FILE` names, else `~/.config/legion/envoy.json` (under `$XDG_CONFIG_HOME` when set).
|
|
9
|
-
- The plugin passes its choice in `ENVOY_CONFIG_FILE` with `DISPATCH_HOST`. In a Claude Code Bash that lacks both, `CLAUDE_CODE_CHILD_SESSION=1` makes the command read `CLAUDE_CONFIG_DIR`'s file. A Legion pane reads the `DISPATCH_TOKEN_FILE` path the daemon sets.
|
|
10
|
-
- A `dispatch.token` written `!<command>` is a command that prints the token.
|
|
11
|
-
- A checkout's `.envoy/envoy.json` sets `dispatch.serverUrl` and `dispatch.token` only together. Its `envoy` section is not read. A file's token goes only to its own server: a `DISPATCH_URL` for another server needs `DISPATCH_TOKEN` or `DISPATCH_TOKEN_FILE`.
|
|
12
|
-
- Never configure `DISPATCH_AGENT_TOKEN` (the shared devbox fallback) for one agent.
|
|
13
|
-
- Never set the sign-in callback origin in an agent's `envoy.json`. It is `DISPATCH_SERVER_URL` in the deployment `compose/.env`: the exact URL humans type. `<DISPATCH_SERVER_URL>/auth/callback` is registered on the sign-in client (`DISPATCH_SIGNIN_CLIENT_ID`).
|
|
14
|
-
|
|
15
|
-
## Finding a route
|
|
16
|
-
|
|
17
|
-
- `GET /api/v1` (no credential) lists every route as `{method, path, auth, description}`. `auth` is `public`, `any`, `human` (a bearer gets `403 HUMAN_ONLY`) or `bearer`.
|
|
18
|
-
- `404 NOT_FOUND` with "GET /api/v1 lists every route" means a wrong path. Read the index, do not guess.
|
|
19
|
-
- Branch on an error's `code`, never its text.
|
|
20
|
-
- `GET /api/v1/issues` returns every match unpaged, or one page with `limit` (1–250) or `offset`: `{issues, total, limit, offset}`. Only the unpaged array is exact: a page walk can repeat or skip an issue that changes. `cursor` is `400 INVALID_QUERY`. `dispatch issues` pages for you.
|
|
21
|
-
- Event logs page with `after` or `before` and `limit`. `GET /api/v1/search` takes `limit` up to 50 with no next page. Other routes do not page.
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Asks after they open: who answers, editing, resolving, replying, and following
|
|
2
|
-
|
|
3
|
-
Read this once an ask is open. Whether to ask, and how to write it, is "Before you ask" in `skill://dispatch`.
|
|
4
|
-
|
|
5
|
-
## Who answers an ask
|
|
6
|
-
|
|
7
|
-
- An ask goes to the issue's assignee's Inbox: the `Assignee:` that `dispatch read` prints decides whose, not the project's default. On an unassigned issue it is in nobody's default Inbox or `Needs you` count. A project's default assignee fills in only when an issue is created with nobody named and nothing earlier in the chain below names someone; an issue created with an explicit nobody, set to nobody later, or created before the default was set stays unassigned.
|
|
8
|
-
- `dispatch whoami` prints whom you act for: your token owner's email, or no owner (a service token shows as `<namespace>/<name>`, as your writes do). An issue you create goes to your owner, else inherits its parent's assignee, else goes to the project's default assignee when a person set one on the Settings page, else stays unassigned.
|
|
9
|
-
- On an unassigned issue where the answer matters, assign it to your owner, or name in the question who should answer. Assign with `PATCH /api/v1/issues/{key}` and `{"assignee": "<email>"}`. An email nobody signed in with gets `ASSIGNEE_NOT_ALLOWED`.
|
|
10
|
-
- Never reassign an issue a human holds to get a faster answer. That is the human's call.
|
|
11
|
-
|
|
12
|
-
## Handing a human a to-do, editing, resolving, and replying
|
|
13
|
-
|
|
14
|
-
- A to-do follows the question-and-options contract of "Writing for the human". For a human-only action, what it changes and risks constrains the answer. No label is special. If an outcome needs a reason, say so in its description.
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
dispatch ask --issue DSP-42 \
|
|
18
|
-
--question 'The fix is merged but cannot run in production: the signing certificate it needs expired, and only its owner can renew it in the registrar console. Renewing replaces the certificate every client checks. How should we proceed? Recommendation: renew it now because the fix cannot run without it.' \
|
|
19
|
-
--option 'Renew the certificate: Lets the fix run but replaces the certificate every client checks.' \
|
|
20
|
-
--option 'Leave it expired: Changes nothing now but leaves the fix unable to run.'
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
- Correct an open ask in place with `dispatch edit-ask`, not a second ask, while the same decision stays open. The human then reconfirms. You cannot edit an answered or resolved ask. If the decision of an open ask changed, retract it and open a new one. If the decision of an answered ask changed, open a new one.
|
|
24
|
-
- `edit-ask` on a block ask writes the block too, so it mints a version and closes a spec's design gate until approved. Change anything else about the block with `dispatch doc-edit`. A retry with unchanged fields is safe.
|
|
25
|
-
- A human can change an answer. A new `ask.answered` carries `previous_answer`. Act on the newest.
|
|
26
|
-
- When the selected option and the typed text disagree, the text is the answer. Act on it. To clarify, open a new ask.
|
|
27
|
-
- Retract a moot or superseded ask, or resolve one whose answer you found:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
dispatch resolve-ask --ask <id> --kind retracted --reason 'A newer ask supersedes this question.'
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
- Use `retracted` for obsolete, `resolved` for found. Always give a reason: the question stays in its card. Resolution never records a human decision. An answered ask cannot be resolved.
|
|
34
|
-
- `doc-edit` refuses to delete an open ask's block. A block deleted another way (an upload, the browser) closes its ask. Restoring it reopens the ask.
|
|
35
|
-
- Reply under an ask with `dispatch comment --reply-to-ask <id>`. Close your review comment with `dispatch resolve-comment` ([Documents](skill://dispatch/references/documents.md#comments-and-suggestions)).
|
|
36
|
-
- A human reply while the ask is open (`ask_state: open`) is a request for clarification, not an answer. Answer in the thread with `--reply-to-ask`, or reword with `edit-ask`. Do not open a second ask.
|
|
37
|
-
- Each reply sets whose turn it is. Your default reply (`--turn human`) puts the ask in the human's `Waiting on you`. For any progress or working-on-it note, use `--turn agent`. A human reply hands the turn to you. Reads show it as `waiting_on`.
|
|
38
|
-
|
|
39
|
-
## Following
|
|
40
|
-
|
|
41
|
-
- You follow an ask you opened or replied to, or one a human added you to. Its answer, edits, resolution and replies reach your agent topic directly.
|
|
42
|
-
- Leave or rejoin: `dispatch follow --ask <id> --action unfollow` (or `follow`). `--ask` takes a full id, a `dispatch://KEY/ask/<id>`, or an 8+ hex prefix unique among your open asks. Removal arrives as `ask.follower_removed`, an add as `ask.follower_added`.
|
|
43
|
-
- No write subscribes you to an owner. Replies to your comments and new comments on your documents also reach you. For everything else, subscribe: `envoy_subscribe notifications.dispatch.issue.<KEY>.>` or `envoy_subscribe notifications.dispatch.document.<PROJECT>.<SLUG>.>`. The topic carries every event. `notify` controls only wake and routed delivery. A human can unsubscribe you (`subscription.removed`).
|