@muggleai/works 4.11.4 → 4.12.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/{chunk-E52757MK.js → chunk-2DVZ2LYO.js} +5 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/scripts/ensure-electron-app.sh +29 -4
- package/dist/plugin/skills/_shared/github-cli-recipes/line-comments-for-review.md +8 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/loop-user-identity.md +9 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/pr-edit.md +8 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/pr-metadata.md +12 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/push-to-branch.md +10 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/reply-line-comment.md +10 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +15 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/top-level-comment.md +7 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +33 -0
- package/dist/plugin/skills/_shared/github-cli-recipes/verify-working-tree.md +17 -0
- package/dist/plugin/skills/_shared/github-cli-recipes.md +20 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers/allow-list.md +53 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers/classify.md +48 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +40 -0
- package/dist/plugin/skills/_shared/pr-followup-helpers.md +8 -146
- package/dist/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +25 -0
- package/dist/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +19 -0
- package/dist/plugin/skills/_shared/telemetry-events/muggle-do-resolve-reminder.md +19 -0
- package/dist/plugin/skills/_shared/telemetry-events/pr-followup-bootstrap.md +20 -0
- package/dist/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +23 -0
- package/dist/plugin/skills/_shared/telemetry-events.md +15 -0
- package/dist/plugin/skills/do/address-reviews.md +137 -0
- package/dist/plugin/skills/do/build.md +5 -5
- package/dist/plugin/skills/do/open-prs/forward.md +80 -0
- package/dist/plugin/skills/do/open-prs/update.md +54 -0
- package/dist/plugin/skills/do/open-prs.md +6 -102
- package/dist/plugin/skills/do/per-comment-replies.md +61 -0
- package/dist/plugin/skills/do/resolve-reminder.md +70 -0
- package/dist/plugin/skills/muggle-do/SKILL.md +41 -45
- package/dist/plugin/skills/muggle-pr-followup/CLAUDE.md +25 -0
- package/dist/plugin/skills/muggle-pr-followup/SKILL.md +21 -43
- package/dist/plugin/skills/muggle-pr-followup/bootstrap.md +88 -0
- package/dist/plugin/skills/muggle-pr-followup/contract.md +44 -161
- package/dist/plugin/skills/muggle-pr-followup/output-templates/bootstrap.md +42 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates/escalation.md +32 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates/help.md +17 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +17 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +12 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates/watcher-log.md +21 -0
- package/dist/plugin/skills/muggle-pr-followup/output-templates.md +14 -0
- package/dist/plugin/skills/muggle-pr-followup/state-schemas.md +104 -0
- package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +3 -3
- package/dist/release-manifest.json +4 -4
- package/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/scripts/ensure-electron-app.sh +29 -4
- package/plugin/skills/_shared/github-cli-recipes/line-comments-for-review.md +8 -0
- package/plugin/skills/_shared/github-cli-recipes/loop-user-identity.md +9 -0
- package/plugin/skills/_shared/github-cli-recipes/pr-edit.md +8 -0
- package/plugin/skills/_shared/github-cli-recipes/pr-metadata.md +12 -0
- package/plugin/skills/_shared/github-cli-recipes/push-to-branch.md +10 -0
- package/plugin/skills/_shared/github-cli-recipes/reply-line-comment.md +10 -0
- package/plugin/skills/_shared/github-cli-recipes/submitted-reviews.md +15 -0
- package/plugin/skills/_shared/github-cli-recipes/top-level-comment.md +7 -0
- package/plugin/skills/_shared/github-cli-recipes/unresolved-threads.md +33 -0
- package/plugin/skills/_shared/github-cli-recipes/verify-working-tree.md +17 -0
- package/plugin/skills/_shared/github-cli-recipes.md +20 -0
- package/plugin/skills/_shared/pr-followup-helpers/allow-list.md +53 -0
- package/plugin/skills/_shared/pr-followup-helpers/classify.md +48 -0
- package/plugin/skills/_shared/pr-followup-helpers/reply-routing.md +40 -0
- package/plugin/skills/_shared/pr-followup-helpers.md +8 -146
- package/plugin/skills/_shared/telemetry-events/muggle-do-cycle.md +25 -0
- package/plugin/skills/_shared/telemetry-events/muggle-do-escalation.md +19 -0
- package/plugin/skills/_shared/telemetry-events/muggle-do-resolve-reminder.md +19 -0
- package/plugin/skills/_shared/telemetry-events/pr-followup-bootstrap.md +20 -0
- package/plugin/skills/_shared/telemetry-events/pr-followup-tick.md +23 -0
- package/plugin/skills/_shared/telemetry-events.md +15 -0
- package/plugin/skills/do/address-reviews.md +137 -0
- package/plugin/skills/do/build.md +5 -5
- package/plugin/skills/do/open-prs/forward.md +80 -0
- package/plugin/skills/do/open-prs/update.md +54 -0
- package/plugin/skills/do/open-prs.md +6 -102
- package/plugin/skills/do/per-comment-replies.md +61 -0
- package/plugin/skills/do/resolve-reminder.md +70 -0
- package/plugin/skills/muggle-do/SKILL.md +41 -45
- package/plugin/skills/muggle-pr-followup/CLAUDE.md +25 -0
- package/plugin/skills/muggle-pr-followup/SKILL.md +21 -43
- package/plugin/skills/muggle-pr-followup/bootstrap.md +88 -0
- package/plugin/skills/muggle-pr-followup/contract.md +44 -161
- package/plugin/skills/muggle-pr-followup/output-templates/bootstrap.md +42 -0
- package/plugin/skills/muggle-pr-followup/output-templates/escalation.md +32 -0
- package/plugin/skills/muggle-pr-followup/output-templates/help.md +17 -0
- package/plugin/skills/muggle-pr-followup/output-templates/inline-reply.md +17 -0
- package/plugin/skills/muggle-pr-followup/output-templates/resolve-reminder.md +12 -0
- package/plugin/skills/muggle-pr-followup/output-templates/watcher-log.md +21 -0
- package/plugin/skills/muggle-pr-followup/output-templates.md +14 -0
- package/plugin/skills/muggle-pr-followup/state-schemas.md +104 -0
- package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +3 -3
- package/scripts/postinstall.mjs +36 -5
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Reply routing
|
|
2
|
+
|
|
3
|
+
GitHub's PR APIs are not uniform across comment types. Route by parent type.
|
|
4
|
+
|
|
5
|
+
## Line-level review comment (most common)
|
|
6
|
+
|
|
7
|
+
A comment attached to a specific file:line that belongs to a review thread.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gh api \
|
|
11
|
+
--method POST \
|
|
12
|
+
-H "Accept: application/vnd.github+json" \
|
|
13
|
+
/repos/<owner>/<repo>/pulls/<number>/comments/<comment_id>/replies \
|
|
14
|
+
-f body="Done in $(git rev-parse --short HEAD) — renamed \`fooBar\` to \`foo_bar\`."
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The reply lands in the same review thread with `in_reply_to_id = <comment_id>`.
|
|
18
|
+
|
|
19
|
+
## Review body (CHANGES_REQUESTED with no inline comments)
|
|
20
|
+
|
|
21
|
+
A reviewer left a summary review with `state: CHANGES_REQUESTED` and a body, but **no** inline comments. GitHub has no "reply to review body" endpoint — post a top-level PR comment that references the review:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
gh pr comment <number> --repo <owner>/<repo> --body "Re: review #<review_id> — done in $(git rev-parse --short HEAD)."
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Failing CI check
|
|
28
|
+
|
|
29
|
+
No reply. The fix commit IS the response. Include the failing check name in the commit subject:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
fix(ci): typecheck — narrow type of foo
|
|
33
|
+
fix(ci): lint — remove unused import
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Never
|
|
37
|
+
|
|
38
|
+
- Never post a top-level comment in reply to a line-level comment. It loses thread context.
|
|
39
|
+
- Never `gh pr review --comment` for replies — that endpoint is for *new* reviews.
|
|
40
|
+
- Never reply twice to the same comment. The cursor in `last_seen.json` is the only re-entry guard; advance it after every reply.
|
|
@@ -1,151 +1,13 @@
|
|
|
1
1
|
# PR follow-up helpers
|
|
2
2
|
|
|
3
|
-
Generic operational guidance for
|
|
3
|
+
Generic operational guidance for PR-review follow-up. Caller-agnostic — the watcher fetches reviews, the caller (today: `/muggle-do` in address-reviews mode) reads these files to classify and decide what to do.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Each section is its own file — load only what the current step needs.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Index
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
gh pr view <number> --repo <owner>/<repo> --json reviewRequests,author
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
`reviewRequests` is an array of `{ login? , slug? }`. User reviewers have `login`; team reviewers have `slug` (and `name`). Expand teams to member logins:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
gh api orgs/<org>/teams/<slug>/members --jq '.[].login'
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Record `prAuthor = author.login` for the exclusion step.
|
|
24
|
-
|
|
25
|
-
### Step 2: CODEOWNERS
|
|
26
|
-
|
|
27
|
-
Look for the file in this order — first hit wins:
|
|
28
|
-
|
|
29
|
-
1. `.github/CODEOWNERS`
|
|
30
|
-
2. `CODEOWNERS`
|
|
31
|
-
3. `docs/CODEOWNERS`
|
|
32
|
-
|
|
33
|
-
Read from the PR's **head branch** (not master), because a PR that adds CODEOWNERS should be allowed to take effect once merged but is informational while open. In practice this means:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
gh api repos/<owner>/<repo>/contents/.github/CODEOWNERS?ref=<head_sha> --jq '.content' | base64 -d
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Parse line-by-line:
|
|
40
|
-
|
|
41
|
-
- Skip blank lines and lines starting with `#`.
|
|
42
|
-
- Each line is `<pattern> <owner1> <owner2> ...`.
|
|
43
|
-
- Owners are either `@user` or `@org/team`. Strip the leading `@`.
|
|
44
|
-
- For our purposes we don't need to match `<pattern>` against changed files — CODEOWNERS membership for the *repo* is enough. Collect the union of all owners across all lines.
|
|
45
|
-
|
|
46
|
-
Expand `@org/team` to member logins via the orgs/teams/members endpoint (same as Step 1).
|
|
47
|
-
|
|
48
|
-
If no CODEOWNERS file exists in any of the three locations, the CODEOWNERS contribution is empty. Don't fail.
|
|
49
|
-
|
|
50
|
-
### Step 3: filter
|
|
51
|
-
|
|
52
|
-
Allow-list = (requested reviewers ∪ CODEOWNERS) − `{prAuthor}` − bot logins.
|
|
53
|
-
|
|
54
|
-
Bot logins are any login matching:
|
|
55
|
-
|
|
56
|
-
- Ends with `[bot]` (e.g. `dependabot[bot]`)
|
|
57
|
-
- Exact match in the standard list: `dependabot`, `github-actions`, `renovate`, `mergify`
|
|
58
|
-
|
|
59
|
-
A comment author not in the allow-list is silently ignored — do not reply, do not address.
|
|
60
|
-
|
|
61
|
-
## Reply routing
|
|
62
|
-
|
|
63
|
-
GitHub's PR APIs are not uniform across comment types. Route by parent type.
|
|
64
|
-
|
|
65
|
-
### Line-level review comment
|
|
66
|
-
|
|
67
|
-
A comment attached to a specific file:line that belongs to a review thread. This is the **most common** path.
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
gh api \
|
|
71
|
-
--method POST \
|
|
72
|
-
-H "Accept: application/vnd.github+json" \
|
|
73
|
-
/repos/<owner>/<repo>/pulls/<number>/comments/<comment_id>/replies \
|
|
74
|
-
-f body="Done in $(git rev-parse --short HEAD) — renamed \`fooBar\` to \`foo_bar\`."
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The reply lands in the same review thread. The reply itself becomes a new line-level comment with `in_reply_to_id = <comment_id>`.
|
|
78
|
-
|
|
79
|
-
### Review body (CHANGES_REQUESTED with no inline comments)
|
|
80
|
-
|
|
81
|
-
A reviewer left a summary review with `state: CHANGES_REQUESTED` and a body, but **no** inline comments. GitHub has no "reply to review body" endpoint — post a top-level PR comment that references the review:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
gh pr comment <number> --repo <owner>/<repo> --body "Re: review #<review_id> — done in $(git rev-parse --short HEAD)."
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Failing CI check
|
|
88
|
-
|
|
89
|
-
No reply. The fix commit IS the response. Include the failing check name in the commit subject so the connection is obvious in `git log`:
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
fix(ci): typecheck — narrow type of foo
|
|
93
|
-
fix(ci): lint — remove unused import
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Never
|
|
97
|
-
|
|
98
|
-
- Never post a top-level comment in reply to a line-level comment. It loses thread context and pollutes the PR conversation tab.
|
|
99
|
-
- Never `gh pr review --comment` for replies — that endpoint is for *new* reviews, not replies.
|
|
100
|
-
- Never reply twice to the same comment. The cursor in `last_seen.json` is the only re-entry guard; advance it after every reply.
|
|
101
|
-
|
|
102
|
-
## Classify
|
|
103
|
-
|
|
104
|
-
Classify the **review as a unit** — but reply per line comment (threaded), not per review.
|
|
105
|
-
|
|
106
|
-
| Class | Signal | Action |
|
|
107
|
-
| :---- | :----- | :----- |
|
|
108
|
-
| **actionable** | Review names at least one concrete change or asks an answerable question. Soft phrasing counts when there's a concrete referent. | Treat as amended requirements; run **one** implementation cycle for the whole review; reply **threaded per line comment** referencing the new SHA (top-level only when the review is body-only). |
|
|
109
|
-
| **ambiguous** | No actionable signal — pure vibes, contradictory, or depends on knowledge the loop can't access. | Escalate once with two interpretations; pause the PR. |
|
|
110
|
-
|
|
111
|
-
Default to **actionable**. CI catches wrong attempts; reviewers correct on the next round. Escalation is a round-trip with an absent user — reserve it.
|
|
112
|
-
|
|
113
|
-
Reply shape (all replies for one review reference the same SHA):
|
|
114
|
-
|
|
115
|
-
- **threaded** (default): `Done in <sha> — <attribution>. (Review #<review_id>, cycle <status>.)`
|
|
116
|
-
- **top-level** (fallback, body-only reviews): `Re: review #<review_id> — addressed in <sha>, cycle <status>.`
|
|
117
|
-
- **ambiguous**: no bot reply.
|
|
118
|
-
|
|
119
|
-
### Worked examples — Actionable reviews
|
|
120
|
-
|
|
121
|
-
| Review (summarized) | Why actionable |
|
|
122
|
-
| :------------------ | :------------- |
|
|
123
|
-
| 3 comments: "rename `fooBar` to `foo_bar`", "use `const` here", "fix this typo" | Three concrete edits |
|
|
124
|
-
| 1 comment: "could the procedure be simpler?" | Soft-phrased but the intent is clear — simplify; pick the best interpretation, run the cycle, reply with what was changed |
|
|
125
|
-
| Review body: "Mostly looks good. Two things: extract the validation into a helper, and add a null check before the lookup." Plus 0 line comments. | Two concrete directives in the body |
|
|
126
|
-
| 4 comments: "why this approach?", "is this called from X?", "does this need to handle empty array?", "what's the perf here?" | All questions but each is answerable; cycle dispatches an "answer + maybe-fix" pass and the reply summary captures each answer |
|
|
127
|
-
| 1 comment: "rewrite this module — the architecture doesn't match the spec" | Substantive rebuild, but the direction is clear: redo the module per the spec |
|
|
128
|
-
| 1 comment: "I'd lean toward the bar.ts pattern" | Concrete referent (bar.ts) — apply that pattern |
|
|
129
|
-
|
|
130
|
-
The single review goes through one full cycle regardless of comment count.
|
|
131
|
-
|
|
132
|
-
### Worked examples — Ambiguous reviews
|
|
133
|
-
|
|
134
|
-
| Review (summarized) | Why ambiguous |
|
|
135
|
-
| :------------------ | :------------ |
|
|
136
|
-
| 1 comment: "👀" / "hmm" / ":thinking:" | No signal at all |
|
|
137
|
-
| 1 comment: "this is wrong" with no target or direction | Asserts a problem but doesn't propose a fix |
|
|
138
|
-
| 2 comments: "use X" + "but actually don't use X" | Self-contradicting — can't reconcile without the reviewer |
|
|
139
|
-
| 1 comment: "we discussed this offline — please address" | References context the loop doesn't have |
|
|
140
|
-
| 1 comment: "won't this break the prod migration we did last week?" | Implicit change request gated on knowledge the loop can't access |
|
|
141
|
-
| Mixed: 2 concrete directives + 1 comment "but also, rethink the whole approach" | The "rethink the whole approach" subverts the other two; escalate to confirm scope |
|
|
142
|
-
|
|
143
|
-
Escalate per the caller's escalation procedure (write the review id to the cursor's escalated set, emit one terminal message with both interpretations, pause the PR until the user resolves).
|
|
144
|
-
|
|
145
|
-
### Borderline rule
|
|
146
|
-
|
|
147
|
-
If you can paraphrase the review's intent as **"do X"** with X being a concrete change (one or several) — it's actionable. Pick the best interpretation and dispatch the cycle.
|
|
148
|
-
|
|
149
|
-
If you can paraphrase it only as **"the reviewer is dissatisfied but I can't tell with what"** — it's ambiguous.
|
|
150
|
-
|
|
151
|
-
When the review mixes both ("3 concrete directives + 1 dissatisfaction"), the safer move is usually to action the concrete directives and ask about the dissatisfaction in the reply summary. Pure ambiguity means *nothing* in the review is actionable.
|
|
9
|
+
| Section | Use case |
|
|
10
|
+
| :------ | :------- |
|
|
11
|
+
| [`allow-list`](pr-followup-helpers/allow-list.md) | Resolve who counts as a reviewer (requested reviewers ∪ CODEOWNERS − bots − author). |
|
|
12
|
+
| [`reply-routing`](pr-followup-helpers/reply-routing.md) | Pick the right reply endpoint per comment type (line, body-only, CI failure). |
|
|
13
|
+
| [`classify`](pr-followup-helpers/classify.md) | Per-review binary label: actionable vs ambiguous, with worked examples + borderline rule. |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# `muggle-do:cycle`
|
|
2
|
+
|
|
3
|
+
One per address-reviews invocation, regardless of outcome.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"skill": "muggle-do",
|
|
8
|
+
"event": "cycle",
|
|
9
|
+
"session_slug": "<slug>",
|
|
10
|
+
"repo": "<owner>/<repo>",
|
|
11
|
+
"pr_number": <int>,
|
|
12
|
+
"review_ids_in": [<int>, ...],
|
|
13
|
+
"review_ids_actionable": [<int>, ...],
|
|
14
|
+
"review_ids_ambiguous": [<int>, ...],
|
|
15
|
+
"head_sha_before": "<sha-or-null>",
|
|
16
|
+
"head_sha_after": "<sha-or-null>",
|
|
17
|
+
"outcome": "pushed" | "escalated" | "mixed" | "no-op"
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`outcome`:
|
|
22
|
+
- `"pushed"` — at least one actionable, no ambiguous, push succeeded.
|
|
23
|
+
- `"escalated"` — all reviews were ambiguous; no push.
|
|
24
|
+
- `"mixed"` — both branches happened in the same invocation.
|
|
25
|
+
- `"no-op"` — every input id was already in the escalated set; no work.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `muggle-do:escalation`
|
|
2
|
+
|
|
3
|
+
Zero or one per address-reviews invocation. Fires when `/muggle-do` emits a terminal escalation message to the user.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"skill": "muggle-do",
|
|
8
|
+
"event": "escalation",
|
|
9
|
+
"session_slug": "<slug>",
|
|
10
|
+
"repo": "<owner>/<repo>",
|
|
11
|
+
"pr_number": <int>,
|
|
12
|
+
"kind": "ambiguous-review" | "design-adjustment",
|
|
13
|
+
"review_ids": [<int>, ...]
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`kind`:
|
|
18
|
+
- `"ambiguous-review"` — one or more reviews classified ambiguous in this batch.
|
|
19
|
+
- `"design-adjustment"` — mid-cycle, the work surfaced a design-level conflict.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# `muggle-do:resolve-reminder`
|
|
2
|
+
|
|
3
|
+
Zero or one per cycle. Fires after the resolve-reminder stage scans threads — only when actionables ran.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"skill": "muggle-do",
|
|
8
|
+
"event": "resolve-reminder",
|
|
9
|
+
"session_slug": "<slug>",
|
|
10
|
+
"repo": "<owner>/<repo>",
|
|
11
|
+
"pr_number": <int>,
|
|
12
|
+
"addressed_by_loop": <int>,
|
|
13
|
+
"addressed_by_human": <int>,
|
|
14
|
+
"not_addressed": <int>,
|
|
15
|
+
"comment_posted": true | false
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
- `comment_posted`: false when there were zero addressed-by-loop threads; telemetry still emits so dashboards see the scan happened.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# `muggle-pr-followup:bootstrap`
|
|
2
|
+
|
|
3
|
+
One per successful bootstrap, after state seeding and before the first watcher dispatches.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"skill": "muggle-pr-followup",
|
|
8
|
+
"event": "bootstrap",
|
|
9
|
+
"caller": "<caller-name>",
|
|
10
|
+
"session_slug": "<slug>",
|
|
11
|
+
"repo": "<owner>/<repo>",
|
|
12
|
+
"pr_number": <int>,
|
|
13
|
+
"cursor_review_id": <int>,
|
|
14
|
+
"resume": true | false
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
- `caller`: `"user"` for direct invocation; another skill name if relayed.
|
|
19
|
+
- `cursor_review_id`: `0` if no prior submitted reviews; otherwise the highest existing review id.
|
|
20
|
+
- `resume`: true when `--resume` was used.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# `muggle-pr-followup:tick`
|
|
2
|
+
|
|
3
|
+
One per watcher iteration (idle or not).
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"skill": "muggle-pr-followup",
|
|
8
|
+
"event": "tick",
|
|
9
|
+
"session_slug": "<slug>",
|
|
10
|
+
"repo": "<owner>/<repo>",
|
|
11
|
+
"pr_number": <int>,
|
|
12
|
+
"reviews_seen": <int>,
|
|
13
|
+
"dispatched_review_ids": [<int>, ...],
|
|
14
|
+
"terminal": true | false,
|
|
15
|
+
"idle": true | false,
|
|
16
|
+
"tick_duration_ms": <int>
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `reviews_seen`: count of new submitted reviews past the cursor, **after** filtering by the escalated set.
|
|
21
|
+
- `dispatched_review_ids`: review ids handed to `/muggle-do`. Empty when idle.
|
|
22
|
+
- `terminal`: true when this tick observed the PR merged or closed and wrote `result.md`.
|
|
23
|
+
- `idle`: true when no reviews were dispatched this tick.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Telemetry Event Catalog
|
|
2
|
+
|
|
3
|
+
Canonical shapes for `muggle-local-telemetry-event-emit` events. Emission mechanics: [`telemetry-emit.md`](telemetry-emit.md).
|
|
4
|
+
|
|
5
|
+
All events share two top-level fields: `skill` and `event`. The rest is event-specific — read only the file for the event you're emitting.
|
|
6
|
+
|
|
7
|
+
## Index
|
|
8
|
+
|
|
9
|
+
| Event | When |
|
|
10
|
+
| :---- | :--- |
|
|
11
|
+
| [`muggle-pr-followup:tick`](telemetry-events/pr-followup-tick.md) | Every watcher iteration (idle or not). |
|
|
12
|
+
| [`muggle-pr-followup:bootstrap`](telemetry-events/pr-followup-bootstrap.md) | Successful bootstrap, before first watcher dispatches. |
|
|
13
|
+
| [`muggle-do:cycle`](telemetry-events/muggle-do-cycle.md) | Every address-reviews invocation, regardless of outcome. |
|
|
14
|
+
| [`muggle-do:escalation`](telemetry-events/muggle-do-escalation.md) | When `/muggle-do` emits a terminal escalation message. |
|
|
15
|
+
| [`muggle-do:resolve-reminder`](telemetry-events/muggle-do-resolve-reminder.md) | After the resolve-reminder stage scans threads. |
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Address-Reviews Orchestrator
|
|
2
|
+
|
|
3
|
+
The entry procedure for `/muggle-do`'s **address-reviews** mode — invoked by the watcher loop ([`../muggle-pr-followup/contract.md`](../muggle-pr-followup/contract.md)) when new submitted reviews land on a PR. Orchestrates the cycle: read reviews → classify → execute work on actionables → escalate ambiguous → push and refresh PR → reply per comment → resolve-reminder → respawn watcher.
|
|
4
|
+
|
|
5
|
+
## Turn preamble
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
**/muggle-do address-reviews** — handling <count> review(s) on <owner>/<repo>#<n>.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Input
|
|
12
|
+
|
|
13
|
+
`$ARGUMENTS` carries:
|
|
14
|
+
- PR URL: `<owner>/<repo>#<n>` derivable from the URL.
|
|
15
|
+
- Session slug: `<slug>`.
|
|
16
|
+
- List of review ids: one or more integers.
|
|
17
|
+
|
|
18
|
+
Exact phrasing comes from the watcher's dispatch (see [`../muggle-pr-followup/contract.md`](../muggle-pr-followup/contract.md#step-5-if-one-or-more-new-reviews-dispatch)). Parse all three out of the directive text.
|
|
19
|
+
|
|
20
|
+
## Inputs from disk
|
|
21
|
+
|
|
22
|
+
Read from `.muggle-do/sessions/<slug>/`:
|
|
23
|
+
|
|
24
|
+
- `prs.json` — to locate the PR's local checkout path (the `repo` field maps to a configured local repo) and capture `head_sha_before`.
|
|
25
|
+
- `last_seen.json` — for `pushed_shas[]` (used by the resolve-reminder stage) and to update the cursor.
|
|
26
|
+
- `state.md` — for the cached `loop_user` login (used by resolve-reminder thread classification).
|
|
27
|
+
|
|
28
|
+
## Procedure
|
|
29
|
+
|
|
30
|
+
### Step 1 — Read every listed review off GitHub
|
|
31
|
+
|
|
32
|
+
For each review id in the input:
|
|
33
|
+
|
|
34
|
+
- Fetch reviews per [`../_shared/github-cli-recipes/submitted-reviews.md`](../_shared/github-cli-recipes/submitted-reviews.md) (cursor 0; filter to the specific id).
|
|
35
|
+
- Fetch its line comments per [`../_shared/github-cli-recipes/line-comments-for-review.md`](../_shared/github-cli-recipes/line-comments-for-review.md).
|
|
36
|
+
|
|
37
|
+
Group into one combined batch.
|
|
38
|
+
|
|
39
|
+
### Step 2 — Classify each review
|
|
40
|
+
|
|
41
|
+
Apply the classify rule in [`../_shared/pr-followup-helpers/classify.md`](../_shared/pr-followup-helpers/classify.md). Two outcomes per review:
|
|
42
|
+
|
|
43
|
+
- **Actionable** — at least one concrete change request, or an answerable question with a target.
|
|
44
|
+
- **Ambiguous** — no actionable signal.
|
|
45
|
+
|
|
46
|
+
Build two sets: `actionable_review_ids` and `ambiguous_review_ids`. Their union is the input list.
|
|
47
|
+
|
|
48
|
+
### Step 3 — Handle ambiguous (if any)
|
|
49
|
+
|
|
50
|
+
For each id in `ambiguous_review_ids`:
|
|
51
|
+
|
|
52
|
+
1. Append it to `last_seen.escalated_review_ids` so the watcher won't re-dispatch it.
|
|
53
|
+
|
|
54
|
+
Emit **one** terminal escalation message (not one per ambiguous review) per [`../muggle-pr-followup/output-templates/escalation.md`](../muggle-pr-followup/output-templates/escalation.md) (ambiguous template). The message lists every ambiguous review and its comments inline. Emit an event with `kind: "ambiguous-review"` per [`../_shared/telemetry-events/muggle-do-escalation.md`](../_shared/telemetry-events/muggle-do-escalation.md).
|
|
55
|
+
|
|
56
|
+
The user clarifies on GitHub by submitting a new review. The next watcher tick picks it up.
|
|
57
|
+
|
|
58
|
+
### Step 4 — Handle actionables (if any)
|
|
59
|
+
|
|
60
|
+
If `actionable_review_ids` is empty, skip Steps 4 and 5; proceed to Step 6 (cursor + respawn). Otherwise:
|
|
61
|
+
|
|
62
|
+
#### 4a. Flatten the work
|
|
63
|
+
|
|
64
|
+
The actionable reviews together carry a flat list of change items, one per line comment plus any directive in the review body. Each item is design, code logic, or test in nature; the cycle does **not** treat each item as a separate cycle iteration — it plans them together and runs the work **once** for the whole batch.
|
|
65
|
+
|
|
66
|
+
#### 4b. Apply design + code-logic changes
|
|
67
|
+
|
|
68
|
+
Invoke [`build.md`](build.md) with the review-derived requirements: for each comment, what to change and where. `build.md` makes the edits in the working tree but does not commit.
|
|
69
|
+
|
|
70
|
+
If `build.md` reports that the requested work requires rethinking the design (e.g. the requested change conflicts with a load-bearing invariant), exit early per Step 7 (design-adjustment escalation).
|
|
71
|
+
|
|
72
|
+
#### 4c. Create or update unit tests
|
|
73
|
+
|
|
74
|
+
Invoke [`unit-tests.md`](unit-tests.md). Cover the surface that just changed; respect existing test conventions.
|
|
75
|
+
|
|
76
|
+
#### 4d. Run ONE E2E acceptance pass
|
|
77
|
+
|
|
78
|
+
Invoke [`e2e-acceptance.md`](e2e-acceptance.md). One pass covering all related test cases for this PR, not one pass per comment. Use the `autoE2ETest` gate per its usual contract.
|
|
79
|
+
|
|
80
|
+
#### 4e. Create or update the PR
|
|
81
|
+
|
|
82
|
+
Invoke [`open-prs/update.md`](open-prs/update.md) (pass the PR URL + slug + existing PR number). It pushes, refreshes title/description on state change, posts a fresh walkthrough comment, and appends the new SHA to `last_seen.pushed_shas[]`. Capture the new `head_sha`.
|
|
83
|
+
|
|
84
|
+
#### 4f. Post per-comment inline replies
|
|
85
|
+
|
|
86
|
+
Invoke [`per-comment-replies.md`](per-comment-replies.md) with the actionable reviews and the new SHA. One reply per comment, in its own thread, describing what was done for it.
|
|
87
|
+
|
|
88
|
+
#### 4g. Run the resolve-reminder stage
|
|
89
|
+
|
|
90
|
+
Invoke [`resolve-reminder.md`](resolve-reminder.md). Scans unresolved threads, classifies, and posts a top-level PR comment listing addressed-by-loop thread ids.
|
|
91
|
+
|
|
92
|
+
### Step 5 — Update session state
|
|
93
|
+
|
|
94
|
+
- `last_seen.cycles_completed` += 1
|
|
95
|
+
- `last_seen.last_pushed_sha` = the new head SHA (update.md already wrote this; verify)
|
|
96
|
+
- `last_seen.reviewId` = max(input review ids ∪ last_seen.reviewId)
|
|
97
|
+
|
|
98
|
+
### Step 6 — Respawn the watcher
|
|
99
|
+
|
|
100
|
+
Refresh PR state per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). If the PR is now merged or closed:
|
|
101
|
+
|
|
102
|
+
1. Write `result.md` per [`../muggle-pr-followup/state-schemas.md`](../muggle-pr-followup/state-schemas.md#resultmd).
|
|
103
|
+
2. Do **not** respawn the watcher.
|
|
104
|
+
|
|
105
|
+
Otherwise, dispatch the next watcher as the last action of this turn:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
/loop 1m /muggle:muggle-pr-followup <slug> <n>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Step 7 — Telemetry
|
|
112
|
+
|
|
113
|
+
Emit one event per [`../_shared/telemetry-events/muggle-do-cycle.md`](../_shared/telemetry-events/muggle-do-cycle.md). `outcome` is one of:
|
|
114
|
+
|
|
115
|
+
- `"pushed"` — actionables ran and at least one push succeeded.
|
|
116
|
+
- `"escalated"` — only ambiguous; no push.
|
|
117
|
+
- `"mixed"` — both branches ran.
|
|
118
|
+
- `"no-op"` — every input id was already in `escalated_review_ids` (the watcher shouldn't have dispatched, but defensive coverage).
|
|
119
|
+
|
|
120
|
+
Emit additional events as Steps fired them (escalation event in Step 3; resolve-reminder event in Step 4g).
|
|
121
|
+
|
|
122
|
+
## Design-adjustment escalation (Step 4b early exit)
|
|
123
|
+
|
|
124
|
+
When `build.md` returns `failed: design-adjustment`:
|
|
125
|
+
|
|
126
|
+
1. Append the affected review ids to `last_seen.escalated_review_ids`.
|
|
127
|
+
2. Emit one terminal message per [`../muggle-pr-followup/output-templates/escalation.md`](../muggle-pr-followup/output-templates/escalation.md) (design-adjustment template).
|
|
128
|
+
3. Emit the `escalation` telemetry event with `kind: "design-adjustment"`.
|
|
129
|
+
4. Skip to Step 6 (respawn watcher). The watcher continues polling — the user can override the design conflict by submitting a new review.
|
|
130
|
+
|
|
131
|
+
Do **not** push, do **not** post replies, do **not** run resolve-reminder. The cycle ended on a design conflict; the work was not applied.
|
|
132
|
+
|
|
133
|
+
## Invariants
|
|
134
|
+
|
|
135
|
+
- One `/muggle-do` invocation = at most one push and one resolve-reminder, regardless of how many reviews are in the batch.
|
|
136
|
+
- Every input review id ends up in either the cursor (handled) or `escalated_review_ids` (skipped) — never both, never neither.
|
|
137
|
+
- The watcher is respawned exactly when the PR is still open at the end of the cycle.
|
|
@@ -41,11 +41,11 @@ Per repo:
|
|
|
41
41
|
|
|
42
42
|
If a requirement is fundamentally unimplementable as written, halt and escalate with the specific blocker — do not ship a half-finished implementation.
|
|
43
43
|
|
|
44
|
-
## Re-entry from
|
|
44
|
+
## Re-entry from the address-reviews flow
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
The address-reviews orchestrator ([`address-reviews.md`](address-reviews.md)) invokes this stage when reviewers submit comments that require code/design changes. When re-entered:
|
|
47
47
|
|
|
48
|
-
- The
|
|
48
|
+
- The orchestrator passes the actionable reviews' bodies + line comments as the requirements amendment for this iteration. Treat them as additions to the goal/AC.
|
|
49
49
|
- Continue on the existing branch — do not re-create the worktree.
|
|
50
|
-
-
|
|
51
|
-
-
|
|
50
|
+
- After this stage, the orchestrator runs unit-tests → ONE E2E pass → create-or-update PR (push to the existing branch; refresh title/desc if state changed) → per-comment inline replies → resolve-reminder → respawn the watcher.
|
|
51
|
+
- If the requested work cannot be implemented without rethinking design (e.g. a load-bearing invariant must change), return `failed: design-adjustment` and let the orchestrator escalate via the design-adjustment terminal message. Do not partially implement.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Open PR — forward mode
|
|
2
|
+
|
|
3
|
+
Forward pipeline's Stage 7. Invoked by `/muggle-do` after stages 1–6 of a fresh feature. Creates the PR via `gh pr create`, seeds session state, dispatches the first watcher.
|
|
4
|
+
|
|
5
|
+
## Turn preamble
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
**Stage 7 — Create PR** — pushing the branch and opening the PR.
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Inputs
|
|
12
|
+
|
|
13
|
+
- Per-repo: name, path, branch.
|
|
14
|
+
- Requirements: goal, acceptance criteria.
|
|
15
|
+
- **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).
|
|
16
|
+
|
|
17
|
+
## Per repo
|
|
18
|
+
|
|
19
|
+
0. **`autoCreatePR` gate** — apply per [`../../muggle-preferences/preference-gates/autoCreatePR.md`](../../muggle-preferences/preference-gates/autoCreatePR.md). On skip, record the reason in `result.md` and move on.
|
|
20
|
+
|
|
21
|
+
1. **Push:** `git push -u origin <branch>` in the repo directory.
|
|
22
|
+
|
|
23
|
+
2. **Title** (under 70 chars):
|
|
24
|
+
- E2E report exists and has failures → `[E2E FAILING] <goal>`
|
|
25
|
+
- No E2E report (validation was `unit-only` or `skip`) → `[UNVERIFIED] <goal>` or `[UNIT-ONLY] <goal>` to match the validation strategy
|
|
26
|
+
- Otherwise → `<goal>`
|
|
27
|
+
|
|
28
|
+
3. **Body** — assemble in order:
|
|
29
|
+
- `## Goal` — from requirements.
|
|
30
|
+
- `## Acceptance Criteria` — bulleted; omit if empty.
|
|
31
|
+
- `## Changes` — summary of what changed in this repo.
|
|
32
|
+
- `## Validation` — one line: link to E2E report, `unit-only`, or `skip — <reason>`.
|
|
33
|
+
- **If an E2E report exists,** invoke [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) Mode B to render the walkthrough block. Embed the returned `body` verbatim. If no report, skip this block entirely.
|
|
34
|
+
|
|
35
|
+
4. **Create:** `gh pr create --title "..." --body "..." --head <branch>`. Capture the PR URL and number.
|
|
36
|
+
|
|
37
|
+
5. **Overflow comment:** if the walkthrough skill returned a non-null `comment`, post it once per [`../../_shared/github-cli-recipes/top-level-comment.md`](../../_shared/github-cli-recipes/top-level-comment.md). Never post when `comment` is `null`.
|
|
38
|
+
|
|
39
|
+
## Stage 8 handoff
|
|
40
|
+
|
|
41
|
+
After every repo is processed, build the watcher manifest and dispatch one watcher loop per opened PR. The dispatches are the LAST action this stage takes.
|
|
42
|
+
|
|
43
|
+
Write `.muggle-do/sessions/<slug>/prs.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#prsjson):
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
[{ "repo": "owner/repo", "number": 142, "url": "...", "head_sha": "...", "state": "open" }]
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Seed `.muggle-do/sessions/<slug>/last_seen.json` per [`../../muggle-pr-followup/state-schemas.md`](../../muggle-pr-followup/state-schemas.md#last_seenjson) — empty cursor shape with `pushed_shas: []`. Forward mode never has prior reviews to skip, so `reviewId: 0`.
|
|
50
|
+
|
|
51
|
+
**Do not** seed `cycle.json` or `requirements.md`. The watcher is a dumb pipe; `/muggle-do` reads reviews off GitHub.
|
|
52
|
+
|
|
53
|
+
For each entry in `prs.json`, dispatch its watcher:
|
|
54
|
+
```
|
|
55
|
+
/loop 1m /muggle:muggle-pr-followup <slug> <pr-number>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If `prs.json` is empty, **do not dispatch** — record the reason in `result.md` and exit.
|
|
59
|
+
|
|
60
|
+
## Invariants
|
|
61
|
+
|
|
62
|
+
- PR creation per non-skipped repo; walkthrough block via Mode B; `prs.json`+`last_seen.json` seeded (no `cycle.json`, no `requirements.md`); `/loop` dispatch is the last action.
|
|
63
|
+
|
|
64
|
+
## Output
|
|
65
|
+
|
|
66
|
+
**PRs Created:** repo → URL
|
|
67
|
+
**Skipped:** repo → reason (when `autoCreatePR` short-circuited)
|
|
68
|
+
**Overflow comments posted:** repo → PR #
|
|
69
|
+
**Stage 8:** `Watching <N> PR(s) — one /loop 1m /muggle:muggle-pr-followup <slug> <pr#> per PR` | `No PRs to watch — stage 8 not dispatched`
|
|
70
|
+
**Errors:** repo → message
|
|
71
|
+
|
|
72
|
+
## Post-merge cleanup
|
|
73
|
+
|
|
74
|
+
Gated by `autoCleanup`. Fires in a follow-up turn after merge — never from this stage. See [`../../_shared/post-merge-cleanup.md`](../../_shared/post-merge-cleanup.md).
|
|
75
|
+
|
|
76
|
+
Append one short reminder tied to the gate value:
|
|
77
|
+
|
|
78
|
+
- `always` → `Once merged, I'll run the cleanup sequence automatically.`
|
|
79
|
+
- `never` → omit.
|
|
80
|
+
- `ask` / absent → `Once merged, I'll check with you about cleanup.`
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Update PR — address-reviews mode
|
|
2
|
+
|
|
3
|
+
Invoked by `/muggle-do`'s address-reviews orchestrator after stages 3–6 ran on the existing PR. The PR already exists; this stage pushes the branch, refreshes title/description if state changed, and posts a fresh walkthrough.
|
|
4
|
+
|
|
5
|
+
Does **not** create a PR, seed session state, or dispatch a watcher (`/muggle-do` respawns the watcher at the end of its address-reviews cycle).
|
|
6
|
+
|
|
7
|
+
## Turn preamble
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
**Stage 7 — Update PR** — pushing the branch and refreshing the PR.
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Inputs
|
|
14
|
+
|
|
15
|
+
- Per-repo: path, branch (head ref name).
|
|
16
|
+
- The existing PR URL + number from `.muggle-do/sessions/<slug>/prs.json`.
|
|
17
|
+
- **Optional** E2E acceptance report from stage 6. Produced by [`../e2e-acceptance.md`](../e2e-acceptance.md); schema in [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md).
|
|
18
|
+
|
|
19
|
+
## Procedure
|
|
20
|
+
|
|
21
|
+
Skip `autoCreatePR` (it gates creation, not update). The PR's title is left intact unless state changed in Step 3.
|
|
22
|
+
|
|
23
|
+
1. **Push:** per [`../../_shared/github-cli-recipes/push-to-branch.md`](../../_shared/github-cli-recipes/push-to-branch.md). Capture the new SHA.
|
|
24
|
+
|
|
25
|
+
2. **Append new SHA** to `last_seen.json[<key>].pushed_shas` (the resolve-reminder stage uses this to recognize threads addressed by the loop). Set `last_seen.last_pushed_sha` to the new SHA too.
|
|
26
|
+
|
|
27
|
+
3. **Refresh title if state changed.** Compare the new state against the current PR title prefix:
|
|
28
|
+
- E2E now passing, current title has `[E2E FAILING]` → strip the prefix per [`../../_shared/github-cli-recipes/pr-edit.md`](../../_shared/github-cli-recipes/pr-edit.md).
|
|
29
|
+
- E2E now failing, current title has no `[E2E FAILING]` → add the prefix.
|
|
30
|
+
- Validation now ran (was unit-only/skip, now has E2E report) → strip `[UNVERIFIED]` or `[UNIT-ONLY]`.
|
|
31
|
+
- Otherwise → no title change.
|
|
32
|
+
|
|
33
|
+
4. **Refresh body when validation outcome changed** — only when the `## Validation` section's content differs from what's in the body. Use the `--body-file` form in [`../../_shared/github-cli-recipes/pr-edit.md`](../../_shared/github-cli-recipes/pr-edit.md). Preserve `## Goal` and `## Acceptance Criteria` verbatim.
|
|
34
|
+
|
|
35
|
+
5. **Visual walkthrough comment** — if an E2E report exists, invoke [`../../muggle-pr-visual-walkthrough/SKILL.md`](../../muggle-pr-visual-walkthrough/SKILL.md) Mode A. Always a fresh comment per cycle; do not edit prior walkthrough comments.
|
|
36
|
+
|
|
37
|
+
6. **Overflow comment** — same rule as forward mode: post when the walkthrough skill returns non-null `comment`, via [`../../_shared/github-cli-recipes/top-level-comment.md`](../../_shared/github-cli-recipes/top-level-comment.md).
|
|
38
|
+
|
|
39
|
+
## Handoff
|
|
40
|
+
|
|
41
|
+
Return control to `/muggle-do`'s address-reviews orchestrator. The orchestrator runs the remaining stages (per-comment replies → resolve-reminder → respawn watcher).
|
|
42
|
+
|
|
43
|
+
## Invariants
|
|
44
|
+
|
|
45
|
+
- Push; new SHA appended to `pushed_shas`; title/body refreshed only on state change; walkthrough comment via Mode A.
|
|
46
|
+
- No `gh pr create`, no `/loop` dispatch.
|
|
47
|
+
|
|
48
|
+
## Output
|
|
49
|
+
|
|
50
|
+
**PR updated:** URL (new SHA: `<short-sha>`)
|
|
51
|
+
**Title refreshed:** yes | no
|
|
52
|
+
**Body refreshed:** yes | no
|
|
53
|
+
**Walkthrough comment:** posted | skipped (no report)
|
|
54
|
+
**Overflow comment:** posted | skipped
|