@muggleai/works 4.10.0 → 4.11.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.
Files changed (197) hide show
  1. package/README.md +3 -3
  2. package/dist/{chunk-RK6XKSZK.js → chunk-Q7WNEMN4.js} +109 -43
  3. package/dist/{chunk-UVXOHXY2.js → chunk-ZKRHFTIC.js} +832 -89
  4. package/dist/cli.js +2 -2
  5. package/dist/index.js +2 -2
  6. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  7. package/dist/plugin/.cursor-plugin/plugin.json +1 -1
  8. package/dist/plugin/README.md +4 -2
  9. package/dist/plugin/agents/acceptance-tester.md +24 -10
  10. package/dist/plugin/commands/m.md +7 -0
  11. package/dist/plugin/commands/mdo.md +7 -0
  12. package/dist/plugin/commands/mfeedback.md +7 -0
  13. package/dist/plugin/commands/mimport.md +7 -0
  14. package/dist/plugin/commands/mpr.md +7 -0
  15. package/dist/plugin/commands/mprefs.md +7 -0
  16. package/dist/plugin/commands/mregen.md +7 -0
  17. package/dist/plugin/commands/mrelease.md +7 -0
  18. package/dist/plugin/commands/mrepair.md +7 -0
  19. package/dist/plugin/commands/mstatus.md +7 -0
  20. package/dist/plugin/commands/mtest.md +7 -0
  21. package/dist/plugin/commands/mtestlocal.md +7 -0
  22. package/dist/plugin/commands/mtestprep.md +7 -0
  23. package/dist/plugin/commands/mupgrade.md +7 -0
  24. package/dist/plugin/scripts/ensure-electron-app.sh +35 -8
  25. package/dist/plugin/skills/_aliases.json +18 -0
  26. package/dist/plugin/skills/_shared/dev-server-readiness.md +231 -0
  27. package/dist/plugin/skills/_shared/failure-mode-handling.md +244 -0
  28. package/dist/plugin/skills/_shared/post-merge-cleanup.md +10 -0
  29. package/dist/plugin/skills/_shared/pr-followup-helpers.md +150 -0
  30. package/dist/plugin/skills/_shared/rebase-before-e2e.md +15 -0
  31. package/dist/plugin/skills/_shared/telemetry-emit.md +15 -0
  32. package/dist/plugin/skills/_shared/use-worktrees.md +53 -0
  33. package/dist/plugin/skills/do/build.md +51 -0
  34. package/dist/plugin/skills/do/e2e-acceptance.md +64 -19
  35. package/dist/plugin/skills/do/impact-analysis.md +47 -7
  36. package/dist/plugin/skills/do/open-prs.md +72 -74
  37. package/dist/plugin/skills/do/pre-flight.md +21 -14
  38. package/dist/plugin/skills/do/requirements.md +2 -2
  39. package/dist/plugin/skills/do/unit-tests.md +2 -2
  40. package/dist/plugin/skills/m/SKILL.md +8 -0
  41. package/dist/plugin/skills/mdo/SKILL.md +8 -0
  42. package/dist/plugin/skills/mfeedback/SKILL.md +8 -0
  43. package/dist/plugin/skills/mimport/SKILL.md +8 -0
  44. package/dist/plugin/skills/mpr/SKILL.md +8 -0
  45. package/dist/plugin/skills/mprefs/SKILL.md +8 -0
  46. package/dist/plugin/skills/mregen/SKILL.md +8 -0
  47. package/dist/plugin/skills/mrelease/SKILL.md +8 -0
  48. package/dist/plugin/skills/mrepair/SKILL.md +8 -0
  49. package/dist/plugin/skills/mstatus/SKILL.md +8 -0
  50. package/dist/plugin/skills/mtest/SKILL.md +8 -0
  51. package/dist/plugin/skills/mtestlocal/SKILL.md +8 -0
  52. package/dist/plugin/skills/mtestprep/SKILL.md +8 -0
  53. package/dist/plugin/skills/muggle/SKILL.md +9 -6
  54. package/dist/plugin/skills/muggle-do/SKILL.md +36 -61
  55. package/dist/plugin/skills/muggle-do-task/SKILL.md +134 -0
  56. package/dist/plugin/skills/muggle-feedback/SKILL.md +39 -0
  57. package/dist/plugin/skills/muggle-feedback/ops/delete.md +49 -0
  58. package/dist/plugin/skills/muggle-feedback/ops/list.md +65 -0
  59. package/dist/plugin/skills/muggle-feedback/ops/submit.md +130 -0
  60. package/dist/plugin/skills/muggle-pr-followup/SKILL.md +59 -0
  61. package/dist/plugin/skills/muggle-pr-followup/contract.md +191 -0
  62. package/dist/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +68 -43
  63. package/dist/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +86 -0
  64. package/dist/plugin/skills/muggle-preferences/SKILL.md +16 -108
  65. package/dist/plugin/skills/muggle-preferences/ops/change-one.md +10 -0
  66. package/dist/plugin/skills/muggle-preferences/ops/configure.md +49 -0
  67. package/dist/plugin/skills/muggle-preferences/ops/list.md +9 -0
  68. package/dist/plugin/skills/muggle-preferences/ops/reset.md +6 -0
  69. package/dist/plugin/skills/muggle-preferences/ops/set.md +10 -0
  70. package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +1 -1
  71. package/dist/plugin/skills/muggle-preferences/preference-gates/autoCleanup.md +11 -0
  72. package/dist/plugin/skills/muggle-preferences/preference-gates/autoCreatePR.md +13 -0
  73. package/dist/plugin/skills/muggle-preferences/preference-gates/autoDetectChanges.md +3 -3
  74. package/dist/plugin/skills/muggle-preferences/preference-gates/autoE2ETest.md +11 -0
  75. package/dist/plugin/skills/muggle-preferences/preference-gates/autoLogin.md +1 -1
  76. package/dist/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +2 -2
  77. package/dist/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +11 -0
  78. package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +19 -0
  79. package/dist/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -2
  80. package/dist/plugin/skills/muggle-preferences/preference-gates/autoUseWorktree.md +11 -0
  81. package/dist/plugin/skills/muggle-preferences/preference-gates/checkForUpdates.md +4 -4
  82. package/dist/plugin/skills/muggle-preferences/preference-gates/defaultExecutionMode.md +1 -1
  83. package/dist/plugin/skills/muggle-preferences/preference-gates/openTestResultsAfterRun.md +1 -1
  84. package/dist/plugin/skills/muggle-preferences/preference-gates/postPRVisualWalkthrough.md +8 -25
  85. package/dist/plugin/skills/muggle-preferences/preference-gates/showElectronBrowser.md +1 -1
  86. package/dist/plugin/skills/muggle-preferences/preference-gates/suggestRelatedTestCases.md +4 -4
  87. package/dist/plugin/skills/muggle-preferences/preference-gates/suggestRelatedUseCases.md +4 -4
  88. package/dist/plugin/skills/muggle-repair/SKILL.md +4 -2
  89. package/dist/plugin/skills/muggle-status/SKILL.md +8 -5
  90. package/dist/plugin/skills/muggle-test/SKILL.md +110 -86
  91. package/dist/plugin/skills/muggle-test-feature-local/SKILL.md +83 -62
  92. package/dist/plugin/skills/muggle-test-import/SKILL.md +28 -23
  93. package/dist/plugin/skills/muggle-test-prepare/SKILL.md +79 -18
  94. package/dist/plugin/skills/muggle-test-regenerate-missing/SKILL.md +34 -18
  95. package/dist/plugin/skills/muggle-test-regenerate-missing/evals/evals.json +9 -9
  96. package/dist/plugin/skills/muggle-upgrade/SKILL.md +4 -2
  97. package/dist/plugin/skills/muggle-works-npm-release/SKILL.md +6 -4
  98. package/dist/plugin/skills/mupgrade/SKILL.md +8 -0
  99. package/dist/release-manifest.json +4 -4
  100. package/dist/{src-GD3YFCCW.js → src-2G7ENRGI.js} +1 -1
  101. package/package.json +9 -7
  102. package/plugin/.claude-plugin/plugin.json +1 -1
  103. package/plugin/.cursor-plugin/plugin.json +1 -1
  104. package/plugin/README.md +4 -2
  105. package/plugin/agents/acceptance-tester.md +24 -10
  106. package/plugin/commands/m.md +7 -0
  107. package/plugin/commands/mdo.md +7 -0
  108. package/plugin/commands/mfeedback.md +7 -0
  109. package/plugin/commands/mimport.md +7 -0
  110. package/plugin/commands/mpr.md +7 -0
  111. package/plugin/commands/mprefs.md +7 -0
  112. package/plugin/commands/mregen.md +7 -0
  113. package/plugin/commands/mrelease.md +7 -0
  114. package/plugin/commands/mrepair.md +7 -0
  115. package/plugin/commands/mstatus.md +7 -0
  116. package/plugin/commands/mtest.md +7 -0
  117. package/plugin/commands/mtestlocal.md +7 -0
  118. package/plugin/commands/mtestprep.md +7 -0
  119. package/plugin/commands/mupgrade.md +7 -0
  120. package/plugin/scripts/ensure-electron-app.sh +35 -8
  121. package/plugin/skills/_aliases.json +18 -0
  122. package/plugin/skills/_shared/dev-server-readiness.md +231 -0
  123. package/plugin/skills/_shared/failure-mode-handling.md +244 -0
  124. package/plugin/skills/_shared/post-merge-cleanup.md +10 -0
  125. package/plugin/skills/_shared/pr-followup-helpers.md +150 -0
  126. package/plugin/skills/_shared/rebase-before-e2e.md +15 -0
  127. package/plugin/skills/_shared/telemetry-emit.md +15 -0
  128. package/plugin/skills/_shared/use-worktrees.md +53 -0
  129. package/plugin/skills/do/build.md +51 -0
  130. package/plugin/skills/do/e2e-acceptance.md +64 -19
  131. package/plugin/skills/do/impact-analysis.md +47 -7
  132. package/plugin/skills/do/open-prs.md +72 -74
  133. package/plugin/skills/do/pre-flight.md +21 -14
  134. package/plugin/skills/do/requirements.md +2 -2
  135. package/plugin/skills/do/unit-tests.md +2 -2
  136. package/plugin/skills/m/SKILL.md +8 -0
  137. package/plugin/skills/mdo/SKILL.md +8 -0
  138. package/plugin/skills/mfeedback/SKILL.md +8 -0
  139. package/plugin/skills/mimport/SKILL.md +8 -0
  140. package/plugin/skills/mpr/SKILL.md +8 -0
  141. package/plugin/skills/mprefs/SKILL.md +8 -0
  142. package/plugin/skills/mregen/SKILL.md +8 -0
  143. package/plugin/skills/mrelease/SKILL.md +8 -0
  144. package/plugin/skills/mrepair/SKILL.md +8 -0
  145. package/plugin/skills/mstatus/SKILL.md +8 -0
  146. package/plugin/skills/mtest/SKILL.md +8 -0
  147. package/plugin/skills/mtestlocal/SKILL.md +8 -0
  148. package/plugin/skills/mtestprep/SKILL.md +8 -0
  149. package/plugin/skills/muggle/SKILL.md +9 -6
  150. package/plugin/skills/muggle-do/SKILL.md +36 -61
  151. package/plugin/skills/muggle-do-task/SKILL.md +134 -0
  152. package/plugin/skills/muggle-feedback/SKILL.md +39 -0
  153. package/plugin/skills/muggle-feedback/ops/delete.md +49 -0
  154. package/plugin/skills/muggle-feedback/ops/list.md +65 -0
  155. package/plugin/skills/muggle-feedback/ops/submit.md +130 -0
  156. package/plugin/skills/muggle-pr-followup/SKILL.md +59 -0
  157. package/plugin/skills/muggle-pr-followup/contract.md +191 -0
  158. package/plugin/skills/muggle-pr-visual-walkthrough/SKILL.md +68 -43
  159. package/plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md +86 -0
  160. package/plugin/skills/muggle-preferences/SKILL.md +16 -108
  161. package/plugin/skills/muggle-preferences/ops/change-one.md +10 -0
  162. package/plugin/skills/muggle-preferences/ops/configure.md +49 -0
  163. package/plugin/skills/muggle-preferences/ops/list.md +9 -0
  164. package/plugin/skills/muggle-preferences/ops/reset.md +6 -0
  165. package/plugin/skills/muggle-preferences/ops/set.md +10 -0
  166. package/plugin/skills/muggle-preferences/preference-gates/README.md +1 -1
  167. package/plugin/skills/muggle-preferences/preference-gates/autoCleanup.md +11 -0
  168. package/plugin/skills/muggle-preferences/preference-gates/autoCreatePR.md +13 -0
  169. package/plugin/skills/muggle-preferences/preference-gates/autoDetectChanges.md +3 -3
  170. package/plugin/skills/muggle-preferences/preference-gates/autoE2ETest.md +11 -0
  171. package/plugin/skills/muggle-preferences/preference-gates/autoLogin.md +1 -1
  172. package/plugin/skills/muggle-preferences/preference-gates/autoPublishLocalResults.md +2 -2
  173. package/plugin/skills/muggle-preferences/preference-gates/autoRebase.md +11 -0
  174. package/plugin/skills/muggle-preferences/preference-gates/autoSelectLocalHost.md +19 -0
  175. package/plugin/skills/muggle-preferences/preference-gates/autoSelectProject.md +1 -2
  176. package/plugin/skills/muggle-preferences/preference-gates/autoUseWorktree.md +11 -0
  177. package/plugin/skills/muggle-preferences/preference-gates/checkForUpdates.md +4 -4
  178. package/plugin/skills/muggle-preferences/preference-gates/defaultExecutionMode.md +1 -1
  179. package/plugin/skills/muggle-preferences/preference-gates/openTestResultsAfterRun.md +1 -1
  180. package/plugin/skills/muggle-preferences/preference-gates/postPRVisualWalkthrough.md +8 -25
  181. package/plugin/skills/muggle-preferences/preference-gates/showElectronBrowser.md +1 -1
  182. package/plugin/skills/muggle-preferences/preference-gates/suggestRelatedTestCases.md +4 -4
  183. package/plugin/skills/muggle-preferences/preference-gates/suggestRelatedUseCases.md +4 -4
  184. package/plugin/skills/muggle-repair/SKILL.md +4 -2
  185. package/plugin/skills/muggle-status/SKILL.md +8 -5
  186. package/plugin/skills/muggle-test/SKILL.md +110 -86
  187. package/plugin/skills/muggle-test-feature-local/SKILL.md +83 -62
  188. package/plugin/skills/muggle-test-import/SKILL.md +28 -23
  189. package/plugin/skills/muggle-test-prepare/SKILL.md +79 -18
  190. package/plugin/skills/muggle-test-regenerate-missing/SKILL.md +34 -18
  191. package/plugin/skills/muggle-test-regenerate-missing/evals/evals.json +9 -9
  192. package/plugin/skills/muggle-upgrade/SKILL.md +4 -2
  193. package/plugin/skills/muggle-works-npm-release/SKILL.md +6 -4
  194. package/plugin/skills/mupgrade/SKILL.md +8 -0
  195. package/scripts/postinstall.mjs +11 -1
  196. package/dist/plugin/skills/do/validate-code.md +0 -38
  197. package/plugin/skills/do/validate-code.md +0 -38
@@ -0,0 +1,130 @@
1
+ # Submit feedback
2
+
3
+ Resolve the action script being commented on, render it for review, collect feedback against one or more steps and/or the whole script, then submit each piece as its own server-side row.
4
+
5
+ ## 1. Resolve the action script (the "anchor")
6
+
7
+ Pick the first applicable path. Stop at the first that yields an `actionScriptId`.
8
+
9
+ ### 1a. Dashboard URL in user's prompt
10
+
11
+ A Muggle dashboard URL looks like `https://app.muggle-ai.com/muggleTestV0/dashboard/projects/<projectId>/...`. Scan the user's recent message for any `https://app.muggle-ai.com/...` URL.
12
+
13
+ - Extract any UUID-shaped path segments. If `/projects/<uuid>` is present, capture as `projectId`. If `/test-scripts/<uuid>` is present, capture as `testScriptId`.
14
+ - If a `testScriptId` was captured: call `muggle-remote-test-script-get` to get the script and read `actionScriptId` off it. Done — proceed to step 2.
15
+ - If only a `projectId` was captured: use it as the project for path 1c and continue to picker.
16
+ - If parsing yields nothing actionable: fall through to 1b.
17
+
18
+ ### 1b. Recent local run (chained or just-finished)
19
+
20
+ If this skill was invoked by another skill (`muggle-test`, `muggle-test-feature-local`) the caller MUST pass the just-finished `runId` as context. If you have a `runId`:
21
+
22
+ 1. `muggle-local-run-result-get` with the `runId`.
23
+ 2. The result includes the test case context. If the run was already published (`muggle-local-publish-test-script` was called), the resulting `testScriptId` gives you the cloud `actionScriptId` via `muggle-remote-test-script-get`.
24
+ 3. **If the run was NOT published**, upload it first via `muggle-remote-local-run-upload` (passing the `runId`'s test case context and `actionScript` payload). Use the returned cloud `actionScriptId`.
25
+
26
+ If no `runId` was passed but the user is plausibly continuing from a recent test:
27
+
28
+ 1. `muggle-local-list-sessions` and pick sessions completed in the last 10 minutes for the current project.
29
+ 2. If exactly one fresh session exists, offer it as the default via `AskUserQuestion` ("Feedback on the run from <X> minutes ago?" with **Yes / Pick a different run**).
30
+ 3. If multiple, present the top 3 via `AskUserQuestion` (most recent first).
31
+ 4. Once picked, follow the publish-or-upload path above.
32
+
33
+ If neither chained nor recent fits, fall through to 1c.
34
+
35
+ ### 1c. Picker (project → test case → run)
36
+
37
+ 1. **Project.** Read `muggle-local-last-project-get`. If set, use it. Else `muggle-remote-project-list` with `AskUserQuestion` (top 5 by recency, plus "Show full list"). Persist the pick with `muggle-local-last-project-set`.
38
+ 2. **Test case.** `muggle-remote-test-case-list` with `projectId`, then `AskUserQuestion`. Top 5 by recency plus "Show full list". Rank by relevance if the user mentioned anything specific.
39
+ 3. **Run / script.** `muggle-remote-test-script-list` with `testCaseId`. Show via `AskUserQuestion` with: name + status + updatedAt. Top 5 by recency.
40
+ 4. `muggle-remote-test-script-get` on the picked one → note `actionScriptId`.
41
+
42
+ ## 2. Render the script for review
43
+
44
+ Always render before asking for feedback — the user must see the steps to reference them by index.
45
+
46
+ `muggle-remote-action-script-get` with the resolved `actionScriptId`.
47
+
48
+ Print:
49
+
50
+ - **Header** — project name, test case title, script name, status, run url (if available). For remote, include the dashboard link.
51
+ - **Steps** — numbered list, **1-based**, in order:
52
+ - `Step <n>: <action label> on <element text or id> — <briefExplanation>`
53
+ - If `screenshotPath` is present (local) or `screenshotUrl` (remote), append `[screenshot: <path>]` so the user can open it manually.
54
+ - **Summary** — print `summary` from the action script if present, else "No summary recorded".
55
+
56
+ ## 3. Collect feedback (batch)
57
+
58
+ ### 3a. Pick the scope (entity type)
59
+
60
+ Use `AskUserQuestion` to scope which targets:
61
+
62
+ > "Where is the problem?"
63
+ > - One specific step
64
+ > - Multiple steps
65
+ > - The whole script's outcome / summary
66
+ > - Multiple steps **and** the whole outcome
67
+
68
+ ### 3b. Pick the step(s) — clickable picker
69
+
70
+ When 3a includes any step-level scope, present the rendered steps as a **clickable `AskUserQuestion` picker** — never as a typed number.
71
+
72
+ - **Option format** — Label: `Step <n>: <action label> on <element text or id>` (≤80 chars). Description: the step's `briefExplanation` (≤120 chars).
73
+ - **Multi-select** — `multiSelect: true` for "Multiple steps" or "Multiple steps and the whole outcome"; `multiSelect: false` for "One specific step".
74
+ - **Long scripts (>10 steps)** — rank by keyword overlap with the user's prompt (label or briefExplanation); fall back to the first 10 if no match. Append **"Show all steps"** as a final option that re-asks with the full list — never silently truncate.
75
+
76
+ For each selected step, prompt in plain text:
77
+
78
+ > "What should step `<n>` have done instead?"
79
+
80
+ For the whole-script scope, prompt:
81
+
82
+ > "What's wrong with the overall outcome?"
83
+
84
+ Validate each paragraph is non-empty (re-prompt if blank). Build an in-memory list of feedback pieces:
85
+
86
+ ```
87
+ [
88
+ { kind: "step", stepNumber: 3, text: "..." },
89
+ { kind: "step", stepNumber: 7, text: "..." },
90
+ { kind: "actionScript", text: "..." },
91
+ ]
92
+ ```
93
+
94
+ Before submitting, re-confirm the full set with the user via `AskUserQuestion`:
95
+
96
+ > "Submit these <N> feedback entries?" — **Submit / Edit / Cancel**.
97
+
98
+ ## 4. Submit
99
+
100
+ For each piece, call `muggle-remote-user-feedback-create` once. Map fields:
101
+
102
+ | Piece kind | `target.targetType` | `target.targetId` |
103
+ |---|---|---|
104
+ | Step `n` (1-based) | `"step"` | `` `${actionScriptId}:${n - 1}` `` (convert to 0-based) |
105
+ | Whole script | `"actionScript"` | `actionScriptId` |
106
+
107
+ Always pass `projectId` and `feedbackText`. Capture each response — note `feedback.id` and `feedbackAnalysisWorkflowRuntimeId` (may be undefined).
108
+
109
+ If a single create call fails, log the error, continue with the rest, and report the failure at the end. Do not abort the batch.
110
+
111
+ ## 5. Report
112
+
113
+ Print one line per submitted feedback in this shape:
114
+
115
+ ```
116
+ ✓ feedback <id> — <target description> [analysis runtime: <id>]
117
+ ```
118
+
119
+ End with a one-line note:
120
+
121
+ > "Regeneration runs in the background. Re-run this test case later to use the updated script."
122
+
123
+ If any pieces failed, list them under a `Failed:` header with the error.
124
+
125
+ ## Non-negotiables
126
+
127
+ - Always render the script (step 2) before collecting feedback.
128
+ - One create call per feedback piece — never concatenate paragraphs across targets.
129
+ - Convert step numbers from 1-based (UI) to 0-based (wire) at submit time.
130
+ - If the user came from a non-uploaded local run, do the upload silently before submit; do not ask for permission for the upload itself.
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: muggle-pr-followup
3
+ description: Generic per-PR follow-up loop. One polling tick per dispatch. Watches one PR for new submitted reviews; when an actionable review lands, invokes the caller's implementation cycle (build/test/walkthrough/push handler the caller declares), then resumes polling. Use as `/loop 1m /muggle:muggle-pr-followup <session-slug> <pr-number>`. Caller-agnostic — `muggle-do` is the first caller but not the last.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Muggle PR Follow-up
8
+
9
+ > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-pr-followup"`.
10
+
11
+ A generic loop that babysits one open PR until it's merged or closed. Polls for submitted reviews; on an actionable review, dispatches the caller's implementation cycle to re-build, re-test, refresh the walkthrough, and push.
12
+
13
+ **Per-PR isolation.** One dispatch per PR, not per session. Multi-PR work runs N independent loops.
14
+
15
+ ## Input
16
+
17
+ `$ARGUMENTS = <session-slug> <pr-number>`. The session-slug is the directory basename under `.muggle-<caller>/sessions/` (e.g. `.muggle-do/sessions/`) that this loop reads its state from. The pr-number identifies which PR in that session's manifest this loop watches.
18
+
19
+ - Empty / `help` / `?` → list active `(slug, pr-number)` pairs across known callers, exit.
20
+ - One argument → ambiguous; list PRs under that slug, exit.
21
+ - Two arguments → resolve and run one tick.
22
+
23
+ ## Contract
24
+
25
+ The per-tick contract — termination check, allow-list resolution, review polling, classify, cycle dispatch, escalation, telemetry — lives in [`contract.md`](contract.md). Read it before driving a tick.
26
+
27
+ ## Caller-supplied implementation cycle
28
+
29
+ The skill itself is caller-agnostic. When an actionable review lands, it invokes the **implementation cycle** declared by the caller in the session's `cycle.json`:
30
+
31
+ ```json
32
+ {
33
+ "cycleName": "muggle-do dev cycle",
34
+ "steps": [
35
+ { "stage": 3, "file": "../do/build.md" },
36
+ { "stage": 4, "file": "../do/impact-analysis.md" },
37
+ { "stage": 5, "file": "../do/unit-tests.md" },
38
+ { "stage": 6, "file": "../do/e2e-acceptance.md" },
39
+ { "name": "post-walkthrough", "skill": "muggle-pr-visual-walkthrough", "mode": "A" }
40
+ ],
41
+ "pushHandler": "git push origin <branch>"
42
+ }
43
+ ```
44
+
45
+ The cycle's job: read the amended `requirements.md`, run each declared step, push to the existing branch. The cycle returns one of `pushed | escalated | failed`. The skill doesn't care what's inside the steps — it just iterates them, captures the outcome, and writes a reply summary referencing the new SHA.
46
+
47
+ Callers without a `cycle.json` are rejected with `no cycle declared — caller must seed cycle.json at dispatch time`.
48
+
49
+ ## Subagent dispatch (optional)
50
+
51
+ A caller may declare `"useSubagent": true` in `cycle.json`. When set, the implementation cycle runs as a separate Claude subagent rather than inline in the loop's tick — gives stronger isolation per PR but adds overhead per cycle. Default is inline (which is itself isolated per-tick via `/loop`).
52
+
53
+ ## Design adjustment escalation
54
+
55
+ When the implementation cycle reports back that the review requires not just code change but a **design adjustment** beyond what the current requirements support (e.g. the build stage discovers the requested change conflicts with a load-bearing assumption), the cycle returns `failed: design-adjustment`. The loop treats this like an ambiguous escalation but with a different terminal message that points at the design conflict and asks the user to decide.
56
+
57
+ ## Why a separate skill (and not e.g. inside the caller's own skill folder)
58
+
59
+ `/loop` dispatches via slash command; slash commands resolve to top-level skills under `plugin/skills/`. A per-tick loop driven by `/loop` therefore has to live as a top-level skill. Putting the loop's content directly inside a caller-specific folder would make `/loop`-dispatch impossible (or fragile via shell-only entry points). Keeping the loop generic and caller-agnostic is what lets `/loop` dispatch into it cleanly.
@@ -0,0 +1,191 @@
1
+ # PR follow-up per-tick contract
2
+
3
+ Caller-agnostic per-tick contract for the [muggle-pr-followup](SKILL.md) skill. One tick = one polling iteration scoped to one PR.
4
+
5
+ ## Turn preamble
6
+
7
+ ```
8
+ **PR follow-up** — polling <repo>#<pr-number>, tick #<K>.
9
+ ```
10
+
11
+ Resolve `<K>` from `idle_tick_count + cycles_completed` in this PR's state slot.
12
+
13
+ ## When this contract may break the caller's "no questions" rule
14
+
15
+ Most callers' forward pipelines never ask the user mid-cycle. This loop, however, may emit a single escalation message when a submitted review is ambiguous (see [classify](#step-6-classify-the-review) below). By the time the loop is polling, the user has walked away from the forward pipeline; forcing a guess on an ambiguous review is worse than pausing.
16
+
17
+ Escalation is the **only** user-facing path. Otherwise the cycle runs silently end to end.
18
+
19
+ ## Inputs
20
+
21
+ Read these from `.muggle-<caller>/sessions/<slug>/` (the caller's session dir):
22
+
23
+ - `state.md` — session metadata (for context when classifying reviews).
24
+ - `prs.json` — list of `{repo, number, url, head_sha, state, escalated?, cycling?}`. This loop touches only the entry whose `number` matches the dispatched PR number.
25
+ - `last_seen.json` — keyed by `"<owner>/<repo>#<n>"`. For this PR: `{reviewId, last_pushed_sha, idle_tick_count, cycles_completed, escalated_review_ids[]}`.
26
+ - `cycle.json` — caller's declared implementation cycle (see [SKILL.md](SKILL.md#caller-supplied-implementation-cycle)).
27
+
28
+ If any of these don't exist or the PR isn't in `prs.json`, the tick is a no-op — log an error to `followup.log` and exit.
29
+
30
+ ## Per-tick contract
31
+
32
+ ### Step 1: Refresh this PR's state
33
+
34
+ ```bash
35
+ gh pr view <number> --repo <repo> --json state,mergedAt,closedAt,headRefOid
36
+ ```
37
+
38
+ If `state` is `MERGED` or `CLOSED`, mark this entry terminal in `prs.json`. Update `head_sha` if it changed.
39
+
40
+ ### Step 2: Termination check
41
+
42
+ If this PR is terminal: write a per-PR section into `result.md` (URL, final state, `cycles_completed`, count escalated, final SHA), emit final telemetry, **do not schedule another tick**. Other PRs in the session have their own loops; they terminate independently.
43
+
44
+ ### Step 3: Resolve the reviewer allow-list (every tick)
45
+
46
+ ```bash
47
+ gh pr view <number> --repo <repo> --json reviewRequests,author
48
+ ```
49
+
50
+ Add requested reviewers. Add CODEOWNERS by parsing `.github/CODEOWNERS` (or `CODEOWNERS` / `docs/CODEOWNERS`) from the PR's head branch. Remove the PR author and any bot accounts (logins ending in `[bot]`, plus the standard list: `dependabot`, `github-actions`, `renovate`, `mergify`).
51
+
52
+ ### Step 4: Pull new submitted reviews
53
+
54
+ ```bash
55
+ gh api repos/<owner>/<repo>/pulls/<number>/reviews --paginate
56
+ ```
57
+
58
+ Filter to reviews where:
59
+
60
+ - `submitted_at` is non-null (skip drafts — `PENDING` reviews are still being composed).
61
+ - `id > last_seen.reviewId`.
62
+ - `user.login` is in the allow-list.
63
+ - `id` is not in `escalated_review_ids`.
64
+ - `state` is `CHANGES_REQUESTED` or `COMMENTED`, OR `APPROVED` with at least one line comment or a non-empty body.
65
+
66
+ ### Step 5: Pick the oldest new review
67
+
68
+ If no new review past the cursor: increment `idle_tick_count`, append a heartbeat line to `followup.log`, exit. Next tick fires in 1 min via `/loop`.
69
+
70
+ If one or more: take the oldest by `submitted_at`. Fetch its associated line comments (`gh api repos/<owner>/<repo>/pulls/<n>/comments` filtered by `pull_request_review_id`). Reset `idle_tick_count` to 0.
71
+
72
+ **At most one review per tick.** If two reviews land between ticks, the second waits.
73
+
74
+ ### Step 6: Classify the review
75
+
76
+ Apply the classify rule in [`../_shared/pr-followup-helpers.md`](../_shared/pr-followup-helpers.md). The rule applies to the **review as a unit**. Two outcomes:
77
+
78
+ - **Actionable** → continue to Step 7.
79
+ - **Ambiguous** → continue to Step 8.
80
+
81
+ ### Step 7: Dispatch the implementation cycle
82
+
83
+ When the review is actionable:
84
+
85
+ 1. **Pause polling** for this PR (set `cycling: true` on this PR's entry in `prs.json`).
86
+ 2. **Amend `requirements.md`** in the session dir with a new `## Amendment — review <review_id> by <login> (<timestamp>)` section pasting the review body and each comment (with `<file>:<line>` context).
87
+ 3. **Invoke the implementation cycle** declared in the caller's `cycle.json`. Iterate the `steps[]` in order. Each step is either a markdown file to follow, a skill to invoke, or a shell command (per the `cycle.json` schema in SKILL.md). When a step fails, the cycle returns `failed: <step-name>`; the loop escalates per Step 8 with the failure as the reason.
88
+ 4. **Push** via `cycle.json`'s `pushHandler`. Set `last_seen.last_pushed_sha` to the new HEAD.
89
+ 5. **Reply** with one summary via `gh pr comment <n>`:
90
+ ```
91
+ Addressed review <review_id> in <sha> — cycle ran clean (or: with <N> failures, see walkthrough).
92
+ ```
93
+ 6. **Resume polling**: clear `cycling: true`, increment `cycles_completed`, advance `last_seen.reviewId` past this review.
94
+ 7. Emit per-cycle telemetry.
95
+
96
+ If the cycle returns `failed: design-adjustment` (the cycle discovered the review can't be implemented without rethinking the design itself, not just the code), escalate per Step 8 with a `design-adjustment` reason — the terminal message asks the user to confirm the design intent before retrying.
97
+
98
+ ### Step 8: Escalate
99
+
100
+ When the review is ambiguous, or the cycle failed:
101
+
102
+ 1. Add the review id to `last_seen.escalated_review_ids`.
103
+ 2. Append a `followup.log` entry describing the review and the reason.
104
+ 3. Pause this PR's loop by writing `escalated: true` against this PR's entry in `prs.json`.
105
+ 4. End the turn with a **single terminal message** to the user:
106
+
107
+ ```
108
+ **PR follow-up escalation — <repo>#<number> — review <review_id>**
109
+
110
+ <reviewer-login> submitted a review I can't act on coherently:
111
+
112
+ > <quoted review body, or "(no body)" if empty>
113
+
114
+ Comments:
115
+ - <file>:<line> — <quoted comment body>
116
+
117
+ [For ambiguous]
118
+ Best two interpretations:
119
+ 1. <one-line interpretation A>
120
+ 2. <one-line interpretation B>
121
+
122
+ [For cycle failure]
123
+ The implementation cycle failed at <step-name>: <reason>.
124
+
125
+ Reply on the review yourself, leave a follow-up comment, or tell me which way to go.
126
+ ```
127
+
128
+ The user clears the escalation by replying on GitHub (next tick sees a new submitted review past the cursor) or by giving a directive in this terminal session.
129
+
130
+ ### Step 9: Emit tick-summary telemetry and exit
131
+
132
+ Emit one tick event per `muggle-local-telemetry-skill-emit`. Exit the turn.
133
+
134
+ ## Reply routing
135
+
136
+ - **Summary reply on a review**: `gh pr comment <number> --body "..."` referencing the review id and the new SHA. There's no "reply to a review" endpoint.
137
+ - **Reply to a specific line comment** (optional): `POST /repos/{owner}/{repo}/pulls/{n}/comments/{comment_id}/replies`.
138
+ - **Never post the same summary twice** — `last_seen.reviewId` is the only re-entry guard.
139
+
140
+ ## Telemetry
141
+
142
+ **Per-cycle** (one event per actionable review handled):
143
+
144
+ ```json
145
+ {
146
+ "skill": "muggle-pr-followup",
147
+ "event": "cycle",
148
+ "caller": "<caller>",
149
+ "session_slug": "<slug>",
150
+ "repo": "<repo>",
151
+ "pr_number": <n>,
152
+ "review_id": <id>,
153
+ "outcome": "pushed|escalated|failed:<step>",
154
+ "comment_count": <count>,
155
+ "head_sha_before": "<sha>",
156
+ "head_sha_after": "<sha-or-null>"
157
+ }
158
+ ```
159
+
160
+ **Per-tick summary** (always one, even idle):
161
+
162
+ ```json
163
+ {
164
+ "skill": "muggle-pr-followup",
165
+ "event": "tick",
166
+ "session_slug": "<slug>",
167
+ "repo": "<repo>",
168
+ "pr_number": <n>,
169
+ "reviews_seen": <count>,
170
+ "review_picked": true|false,
171
+ "cycle_dispatched": true|false,
172
+ "tick_duration_ms": <ms>
173
+ }
174
+ ```
175
+
176
+ ## Output
177
+
178
+ This stage produces no console output beyond:
179
+ - The turn preamble (always).
180
+ - An escalation terminal message (only when escalating).
181
+ - The final `result.md` summary section for this PR (only on the terminating tick — written to disk, not printed).
182
+
183
+ ## Self-check before ending the turn
184
+
185
+ - [ ] `last_seen.json` advanced for any review handled.
186
+ - [ ] `prs.json` reflects current state (terminal marked; `escalated`/`cycling` flags consistent).
187
+ - [ ] `followup.log` has at minimum a heartbeat or per-review line for this tick.
188
+ - [ ] Telemetry events emitted (per-cycle when applicable + per-tick).
189
+ - [ ] If pushed, `last_pushed_sha` is set and `cycles_completed` incremented.
190
+ - [ ] If escalated, `escalated_review_ids` contains the review id.
191
+ - [ ] If terminal, the loop is NOT continued.
@@ -1,19 +1,22 @@
1
1
  ---
2
2
  name: muggle-pr-visual-walkthrough
3
- description: Renders and posts a visual walkthrough of Muggle AI E2E acceptance test results to a PR — per-test-case dashboard links, step-by-step screenshots, and pass/fail summary — using the `muggle build-pr-section` CLI for deterministic formatting with automatic fit-vs-overflow. Use at the end of any Muggle test run (local or remote) to give PR reviewers clickable visual evidence that user flows work. Triggers on 'post results to PR', 'attach walkthrough to PR', 'share E2E screenshots on the PR', 'add visual walkthrough to PR'.
3
+ description: Renders and posts a visual walkthrough of Muggle AI E2E acceptance test results to a PR — per-test-case dashboard links, step-by-step screenshots, and pass/fail summary — using the `muggle build-pr-section` CLI for deterministic formatting with automatic fit-vs-overflow. Use at the end of any Muggle Test test run (local or remote) to give PR reviewers clickable visual evidence that user flows work. Triggers on 'post results to PR', 'attach walkthrough to PR', 'share E2E screenshots on the PR', 'add visual walkthrough to PR'.
4
4
  ---
5
5
 
6
- # Muggle PR Visual Walkthrough
6
+ # Muggle Test PR Visual Walkthrough
7
+
8
+ > Telemetry first step: see [`_shared/telemetry-emit.md`](../_shared/telemetry-emit.md). Use `skillName: "muggle-pr-visual-walkthrough"`.
7
9
 
8
10
  Renders a visual walkthrough of Muggle AI E2E acceptance test results and posts it to a PR. Each test case is linked to its detail page on the Muggle AI dashboard, so PR reviewers can click through to see step-by-step screenshots and action scripts — not just a pass/fail flag.
9
11
 
10
- This is the **canonical PR-walkthrough workflow** shared across every Muggle entry point:
12
+ This is the **canonical PR-walkthrough workflow** shared across every Muggle Test entry point:
11
13
 
12
14
  | Caller | Mode | When to invoke |
13
15
  | :--- | :--- | :--- |
14
- | `muggle-test` | **Mode A** (post to existing PR) | After publishing results, user opts in via `AskQuestion` |
15
- | `muggle-test-feature-local` | **Mode A** (post to existing PR) | After publishing the run, user opts in via `AskQuestion` |
16
+ | `muggle-test` | **Mode A** (post to existing PR) | After publishing results, user opts in via `AskUserQuestion` |
17
+ | `muggle-test-feature-local` | **Mode A** (post to existing PR) | After publishing the run, user opts in via `AskUserQuestion` |
16
18
  | `muggle-do` / `open-prs.md` | **Mode B** (render-only for embedding) | During PR creation — caller embeds `body` in `gh pr create` and posts `comment` as follow-up |
19
+ | `muggle-test` Mode C / `acceptance-tester` agent | **Mode C** (embed in verdict comment) | Inside a open-PR sweep orchestrator — caller folds the rendered body into a single per-PR verdict comment instead of posting separately |
17
20
 
18
21
  Rendering is always done by `muggle build-pr-section`, a battle-tested CLI that handles deterministic markdown layout, per-step screenshots, and automatic fit-vs-overflow (oversized content spills into a follow-up comment). Never hand-write the walkthrough markdown.
19
22
 
@@ -64,42 +67,48 @@ Every caller must build an `E2eReport` JSON object and have it in conversation c
64
67
  "failureStepIndex": 2,
65
68
  "error": "Element not found: Click checkout button",
66
69
  "artifactsDir": "/Users/.../~/.muggle-ai/sessions/<runId>"
70
+ },
71
+ {
72
+ "name": "Clear search input restores full list",
73
+ "description": "Verify clearing the search input restores all options.",
74
+ "useCaseName": "Filter Dropdowns",
75
+ "testCaseId": "<UUID>",
76
+ "runId": "<UUID>",
77
+ "viewUrl": "https://www.muggle-ai.com/...",
78
+ "status": "inconclusive",
79
+ "steps": [],
80
+ "reason": "No replayable script exists yet — needs first generation run."
67
81
  }
68
82
  ]
69
83
  }
70
84
  ```
71
85
 
72
- Required fields per test: `name`, `testCaseId`, `runId`, `viewUrl`, `status`, `steps[]` with `{stepIndex, action, screenshotUrl}`. Failed tests additionally require `failureStepIndex` and `error`.
86
+ Required fields per test: `name`, `testCaseId`, `runId`, `viewUrl`, `status`, `steps[]` with `{stepIndex, action, screenshotUrl}`.
73
87
 
74
- **Optional but recommended** per test:
75
- - `description` — a one-line summary of what the test case verifies. Shown in the collapsible header for each test and helps reviewers understand the test without expanding it. Pull from the test case's `title`/`description` via `muggle-remote-test-case-get`.
76
- - `useCaseName` — the parent use case title. When present on any test, the overview list is grouped by use case; otherwise it is rendered as a flat list. Pull from `muggle-remote-use-case-get` using the test case's parent use-case id.
77
- - `testScriptId` and `artifactsDir` are also optional.
78
-
79
- If any required field is missing, stop and tell the caller exactly what's missing. Never fabricate data.
88
+ - **Failed** tests additionally require `failureStepIndex` and `error`.
89
+ - **Inconclusive** tests additionally require `reason` (one short sentence on why the result is neither pass nor fail). `steps[]` may be empty — that's fine. Inconclusive is for runs that couldn't be classified pass/fail (no replayable script, environment precondition unmet, infra error blocked execution, agent stalled before reaching the assertion). **Never silently drop these — always emit them as `inconclusive`.** The CLI counts them in the overview and renders an `⚠️` row with the dashboard link so reviewers can click through. If you find yourself wanting to skip a test or hand-write a comment because the schema "doesn't fit," that is the schema fitting — use `inconclusive`.
80
90
 
81
- ## Step 1: Gather the `E2eReport`
91
+ ### Verdict
82
92
 
83
- How to assemble the JSON depends on which caller you are:
93
+ The renderer computes a verdict from the tests and emits a `**Verdict:** ✅ PASS | ❌ FAIL | ⚠️ INCONCLUSIVE` line at the top of the overview. The policy is strict:
84
94
 
85
- ### From `muggle-test` / `muggle-test-feature-local` (local mode)
95
+ - Any failed test → **FAIL** (regardless of how many passed or are inconclusive).
96
+ - No failures but any inconclusive → **INCONCLUSIVE**.
97
+ - All passed → **PASS**.
98
+ - Empty report → no verdict line.
86
99
 
87
- After `muggle-local-publish-test-script` returns `{testScriptId, viewUrl, ...}` for each run:
100
+ You do not compute or render the verdict yourself — the CLI does. Never write a "Verdict: PASS" line into a hand-edited summary; it will conflict with the CLI's computed verdict.
88
101
 
89
- 1. Call `muggle-remote-test-script-get` with `testScriptId` to fetch the published script.
90
- 2. Extract `steps[]` — for each step, build `{stepIndex: <index>, action: operation.action, screenshotUrl: operation.screenshotUrl}`.
91
- 3. Determine `status` from the local run result (`muggle-local-run-result-get`).
92
- 4. For failures, read `failureStepIndex`, `error`, and `artifactsDir` from the run result.
93
- 5. Assemble the `E2eReport` with `projectId` from the test run.
94
- 6. Populate `description` (test case title/description) and `useCaseName` (parent use case title) on each report entry — optional but strongly recommended; they drive the grouped overview and the per-test collapsible headers. Prefer values already in your conversation context from earlier steps (e.g. a test case you just created or selected, or a use case you confirmed); only call `muggle-remote-test-case-get` / `muggle-remote-use-case-get` for anything you don't already have.
95
-
96
- ### From `muggle-do` (`open-prs.md`)
102
+ **Optional but recommended** per test:
103
+ - `description` — a one-line summary of what the test case verifies. Shown in the collapsible header for each test and helps reviewers understand the test without expanding it. Pull from the test case's `title`/`description` via `muggle-remote-test-case-get`.
104
+ - `useCaseName` — the parent use case title. When present on any test, the overview list is grouped by use case; otherwise it is rendered as a flat list. Pull from `muggle-remote-use-case-get` using the test case's parent use-case id.
105
+ - `testScriptId` and `artifactsDir` are also optional.
97
106
 
98
- The `e2e-acceptance.md` stage already produces an `E2eReport` with the exact shape above — that is the report's native output format. Pass it through unchanged.
107
+ If any required field is missing, stop and tell the caller exactly what's missing. Never fabricate data.
99
108
 
100
- ### Direct invocation (user asked to post existing results)
109
+ ## Step 1: Assemble the `E2eReport`
101
110
 
102
- The caller must have already executed tests and published them. If the `E2eReport` is not in context, stop and tell the user to run `muggle-test` or `muggle-test-feature-local` first.
111
+ Read `plugin/skills/muggle-pr-visual-walkthrough/e2e-report-assembly.md` for the full assembly guide.
103
112
 
104
113
  ## Step 2: Render via `muggle build-pr-section`
105
114
 
@@ -126,7 +135,7 @@ gh pr view --json number,url,title 2>/dev/null
126
135
  ```
127
136
 
128
137
  - **PR exists** → continue to 3A.2
129
- - **No PR exists** → use `AskQuestion`:
138
+ - **No PR exists** → use `AskUserQuestion`:
130
139
  - "Create a new PR with the visual walkthrough in the body"
131
140
  - "Skip posting"
132
141
  - If the user chooses to create a new PR, switch to Mode B and return the rendered `body`/`comment` to the caller for embedding in `gh pr create`. Do not create the PR directly from this skill unless the caller has no better way to do it.
@@ -134,20 +143,16 @@ gh pr view --json number,url,title 2>/dev/null
134
143
 
135
144
  ### 3A.2: Post the body as a PR comment
136
145
 
146
+ Extract the `body` field with `jq -r` (not `sed`) so JSON escape sequences are properly decoded, then pipe to `--body-file -`:
147
+
137
148
  ```bash
138
- gh pr comment <pr-number> --body "$(cat <<'EOF'
139
- <contents of body field from CLI output>
140
- EOF
141
- )"
149
+ jq -r '.body' /tmp/muggle-pr-section.json | gh pr comment <pr-number> --body-file -
142
150
  ```
143
151
 
144
152
  ### 3A.3: Post the overflow comment only if the CLI emitted one
145
153
 
146
154
  ```bash
147
- gh pr comment <pr-number> --body "$(cat <<'EOF'
148
- <contents of comment field from CLI output>
149
- EOF
150
- )"
155
+ jq -r '.comment' /tmp/muggle-pr-section.json | gh pr comment <pr-number> --body-file -
151
156
  ```
152
157
 
153
158
  **Skip this step entirely if `comment` is `null`** — do not post a placeholder. The CLI decides fit-vs-overflow; never post the overflow comment speculatively.
@@ -169,16 +174,35 @@ Instead of posting, **return** the CLI output to the caller's context so they ca
169
174
  3. **Post `comment` as a follow-up only if the CLI emitted one:**
170
175
 
171
176
  ```bash
172
- gh pr comment <new-pr-number> --body "$(cat <<'EOF'
173
- <contents of comment field>
174
- EOF
175
- )"
177
+ jq -r '.comment' /tmp/muggle-pr-section.json | gh pr comment <new-pr-number> --body-file -
176
178
  ```
177
179
 
178
180
  Skip if `comment` is `null`.
179
181
 
180
182
  In Mode B, this skill does not call `gh pr comment` or `gh pr create` itself — the caller owns PR creation because it also owns branch pushing, title building (including `[E2E FAILING]` prefix on failures), and multi-repo orchestration.
181
183
 
184
+ ## Step 3 — Mode C: Embed mode for open-PR sweep orchestrators
185
+
186
+ Used when invoked as a sub-step of a open-PR sweep orchestrator (see `plugin/skills/muggle-test/SKILL.md` Mode C) rather than as a top-level user invocation. The orchestrator's `acceptance-tester` subagent (see `plugin/agents/acceptance-tester.md`) composes a **single per-PR verdict comment** and folds the walkthrough into it — posting separately would create 2–3 disparate comments per test cycle and clutter the PR.
187
+
188
+ ### 3C.1: Detect embed mode
189
+
190
+ The caller passes `mode: "embed"` as a skill argument. Default behavior (no `mode` passed, or `mode: "post"`) is Mode A — unchanged.
191
+
192
+ ### 3C.2: Render but do not post
193
+
194
+ Run `muggle build-pr-section` exactly as in Step 2. Then, **instead of calling `gh pr comment`**:
195
+
196
+ 1. **Return** the CLI output (`{ body, comment }`) to the caller as this skill's result.
197
+ 2. Do **not** find a PR, do **not** post a standalone comment, do **not** prompt the user.
198
+ 3. If `comment` is non-null (overflow case), return it alongside `body` — the orchestrator decides how to handle overflow (typically: inline `body` in the verdict comment, post `comment` as a follow-up).
199
+
200
+ ### 3C.3: Hand off
201
+
202
+ The orchestrator (`acceptance-tester`) concatenates the returned `body` into its verdict comment template alongside the verdict summary, change-list, and any other sections it owns, then posts a single `gh pr comment` itself. This skill's job ends at returning the rendered markdown.
203
+
204
+ In Mode C, the same fit-vs-overflow contract from Step 2 applies — never modify the CLI's output, never fabricate fields, never post anything. The caller owns posting.
205
+
182
206
  ## Tool Reference
183
207
 
184
208
  | Phase | Tool |
@@ -188,14 +212,15 @@ In Mode B, this skill does not call `gh pr comment` or `gh pr create` itself —
188
212
  | Find existing PR (Mode A) | `gh pr view` |
189
213
  | Post comment(s) (Mode A) | `gh pr comment` |
190
214
  | Create new PR (Mode B, caller handles) | `gh pr create` |
191
- | User confirmation (Mode A no-PR branch) | `AskQuestion` |
215
+ | User confirmation (Mode A no-PR branch) | `AskUserQuestion` |
192
216
 
193
217
  ## Guardrails
194
218
 
195
- - **Never hand-write the walkthrough markdown** — always call `muggle build-pr-section`. The CLI is the single source of truth for formatting.
219
+ - **Never hand-write the walkthrough markdown** — always call `muggle build-pr-section`. The CLI is the single source of truth for formatting. If a test outcome doesn't fit `passed | failed`, that's what `inconclusive` is for — never fall back to a hand-written summary, a custom table, a "Verdict: PASS" header, a `Tested on:`/`Project:` footer, or any other freeform text. The CLI already emits per-test-case dashboard links (no project-level link), uses `https://www.muggle-ai.com/...` URLs (never the test target's `localhost` URL), and computes the verdict — anything you would manually add is wrong by construction.
196
220
  - **Never modify the CLI's output** — post `body` and (if present) `comment` verbatim. Any reformatting defeats the fit-vs-overflow budget math.
197
221
  - **Never invent report fields** — if `projectId`, a per-test `viewUrl`, or per-step `screenshotUrl` is missing, stop and report what's missing. Do not fabricate URLs or fill in placeholders.
198
222
  - **Never post the overflow comment when `comment` is `null`** — the CLI decides fit-vs-overflow.
199
223
  - **Never create a PR without confirmation in Mode A** — if no PR exists, ask the user or switch to Mode B and hand back to the caller.
200
224
  - **Don't run tests** — this skill only renders and posts existing results. If the `E2eReport` is not in context, redirect the caller to `muggle-test`, `muggle-test-feature-local`, or `muggle-do`.
201
- - **Mode A vs Mode B is chosen by the caller, not the user** — `muggle-test` always uses Mode A; `muggle-do` always uses Mode B. Don't ask the user which mode to use.
225
+ - **Mode is chosen by the caller, not the user** — `muggle-test` top-level uses Mode A; `muggle-do` uses Mode B; open-PR sweep orchestrators (`muggle-test` Mode C / `acceptance-tester`) pass `mode: "embed"` for Mode C. Don't ask the user which mode to use.
226
+ - **Never post in Mode C** — when `mode: "embed"` is passed, return the rendered body to the caller and stop. The orchestrator owns the single verdict comment.