@muggleai/works 5.0.3 → 5.0.4

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "muggle",
3
3
  "description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
4
- "version": "5.0.3",
4
+ "version": "5.0.4",
5
5
  "author": {
6
6
  "name": "Muggle AI",
7
7
  "email": "support@muggle-ai.com"
@@ -2,7 +2,7 @@
2
2
  "name": "muggle",
3
3
  "displayName": "Muggle AI",
4
4
  "description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
5
- "version": "5.0.3",
5
+ "version": "5.0.4",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,53 @@
1
+ # Debug a Failed Run — Shared Reference
2
+
3
+ > Presentation layer for a single failed run. Turns one non-passing terminal run — local or remote — into a debug path: **evidence → diagnosis → a guaranteed user choice that always offers "give feedback & rerun".** Used by `muggle-test` (Step 7C), `muggle-test-feature-local`, and the `muggle-do` e2e stage. Depends on [`failure-mode-handling.md`](./failure-mode-handling.md) for the bucket taxonomy and telemetry schema — never the reverse. Don't restate its tables; read them.
4
+
5
+ ## The guarantee
6
+
7
+ Every non-passing terminal run MUST route through this doc before it is reported. A failure is never summarized-and-dropped: the user is always shown *what happened* and is always presented a selection in which **"give feedback & rerun" is a first-class option**. "Skip — just report" stays selectable but is never the default.
8
+
9
+ The guarantee binds **interactive** callers. An autonomous caller with no user to prompt (the `acceptance-tester` agent) runs Steps 1–2 (evidence + diagnosis into its structured report) and skips Step 3's interactive offer.
10
+
11
+ ## Inputs (the caller passes these in)
12
+
13
+ - `runId` (local) or workflow runtime id (remote).
14
+ - `mode` — `replay` or `regen`, the mode that failed.
15
+ - `testCaseId`, `projectId`.
16
+ - A re-execute handle — the loop/tool the caller used to run this case, so a rerun re-enters the same execution path.
17
+
18
+ ## Step 1 — Gather evidence
19
+
20
+ Read **structured run fields**, never the `execute` stdout tail (see [`dev-loop/failures.md`](./dev-loop/failures.md)). Assemble:
21
+
22
+ - **Attempted steps + reasoning** — local: the attempted steps + `summaryStep` halt reason from `action-script.json` in `artifactsDir`; remote: the per-step list + `summaryStep` from `muggle-remote-wf-get-ts-gen-latest-run` / `muggle-remote-wf-get-ts-replay-latest-run`.
23
+ - **Visual evidence** — a failed run already preserves the full step-by-step on disk: every per-step frame under `<artifactsDir>/electron-runtime/screenshot/` (with per-step label data under `.../dataset/`), alongside the step script at `<artifactsDir>/action-script.json`. `run-result-get` returns `artifactsDir` — read the whole set there; don't trust a step's `screenshotLocalPath`, which points at the original runtime dir. Once published — failed runs are published too, see [`dev-loop/publish.md`](./dev-loop/publish.md) — the same frames are cloud-hosted per step as `screenshotUrl`, the form remote runs expose directly.
24
+ - **Verdict** — `Status` + `Error`.
25
+
26
+ ## Step 2 — Diagnose
27
+
28
+ Classify into the failure bucket per [`failure-mode-handling.md`](./failure-mode-handling.md) — §B for a replay failure, §C for a regen failure. That bucket **is** the initial diagnosis. Phrase it for a human ("Looks like a **stale script** — the selectors moved; the product itself probably still works"), not as a telemetry label. Emit the `replay-failure-classified` / `regen-failure-classified` event now, before presenting anything.
29
+
30
+ ## Step 3 — Present the debug card, then the guaranteed offer
31
+
32
+ Show the **debug card** first: attempted steps + reasoning, the failing step's screenshot (or a one-line note if a path is genuinely absent), and the one-line diagnosis.
33
+
34
+ Then present one `AskUserQuestion` whose options are:
35
+
36
+ 1. **Give feedback & rerun** — always present. Invoke the `muggle-feedback` skill with this run's anchor (`runId` local / `testScriptId` remote) so the user says what should have happened, then re-execute per Step 4.
37
+ 2. **The bucket's recommended action** from §B/§C (regenerate, report bug, share defect, retry…). Label it `(Recommended)` — it is the classifier's pick.
38
+ 3. **Retry as-is**.
39
+ 4. **Skip — just report** — last, never the default.
40
+
41
+ The bucket's recommended action and its alternatives live in `failure-mode-handling.md` §B/§C — read them there, don't restate them.
42
+
43
+ **Feedback anchor by lane.** Feedback attaches to a cloud action-script id. `muggle-feedback` owns resolving it: for a **local** run it publishes/uploads first when the run isn't already published; for a **remote** run it uses the existing script. Pass `runId` (local) or `testScriptId` (remote) and let it resolve the anchor — don't resolve or upload here.
44
+
45
+ ## Step 4 — Rerun (always regen)
46
+
47
+ On "give feedback & rerun": once `muggle-feedback` returns, re-execute the test case in **regen** mode — feedback adjusts the agent's course, so the prior script is discarded; replay is never the rerun path. Local: the regen branch of [`dev-loop/run.md`](./dev-loop/run.md). Remote: `muggle-remote-workflow-start-test-script-generation`. Read the new run's result back through this doc (Step 1) so a second failure is debugged too.
48
+
49
+ ## Step 5 — Resolve
50
+
51
+ Emit the `replay-failure-resolved` / `regen-failure-resolved` event with `userAction` set to the pick (`feedback-rerun`, the bucket action, `retry`, or `skip`) — one `*-classified` and one `*-resolved` per failure, per [`failure-mode-handling.md`](./failure-mode-handling.md) §D.
52
+
53
+ Process failures one at a time so the user isn't drowning in pickers.
@@ -1,6 +1,6 @@
1
1
  # PR metadata snapshot
2
2
 
3
- Fetch the fields the watcher and bootstrap need in one call.
3
+ Fetch the fields the watcher and bootstrap need.
4
4
 
5
5
  ```bash
6
6
  gh pr view <pr-number> --repo <owner>/<repo> \
@@ -10,4 +10,16 @@ gh pr view <pr-number> --repo <owner>/<repo> \
10
10
  - `state` is one of `OPEN`, `MERGED`, `CLOSED`.
11
11
  - `headRefOid` is the current head SHA — store as `head_sha` in `prs.json`.
12
12
  - `headRefName` is the branch — must match the working tree's branch in bootstrap.
13
- - `mergeable` is `MERGEABLE`, `CONFLICTING`, or `UNKNOWN` (GitHub still computing — treat as current this tick). `mergeStateStatus` carries the finer state: `DIRTY` = conflicts with base, `BEHIND` = out of date with base (no conflict), `CLEAN`/`BLOCKED`/`UNSTABLE`/`HAS_HOOKS` = current. The watcher dispatches a rebase on `CONFLICTING`/`DIRTY` **or** `BEHIND` — keeping the branch current with its base, a merge-ready gap no review or CI signal would surface.
13
+ - `mergeable` is `MERGEABLE`, `CONFLICTING`, or `UNKNOWN` (GitHub still computing — treat as not-conflicting this tick). The watcher's **conflict** signal is `mergeable == CONFLICTING` (corroborated by `mergeStateStatus == DIRTY`).
14
+
15
+ ## Behind-by (out-of-date detection)
16
+
17
+ `mergeStateStatus == BEHIND` is **not** a reliable out-of-date signal. GitHub collapses merge state into one value with precedence — `DIRTY` (conflict) and `BLOCKED` (missing required review, pending/failing required check) outrank `BEHIND` and mask it, and `BEHIND` surfaces *at all* only when the base enforces "require branches up to date." So a PR that is genuinely behind **and** awaiting review reports `BLOCKED`; `BEHIND` never shows, and its staleness goes unseen.
18
+
19
+ Detect out-of-date straight from commit ancestry instead — independent of merge-state precedence, review state, and branch protection:
20
+
21
+ ```bash
22
+ gh api repos/<owner>/<repo>/compare/<baseRefName>...<head_sha> --jq '.behind_by'
23
+ ```
24
+
25
+ `behind_by > 0` ⇒ the head is missing that many base commits ⇒ out of date. `0` ⇒ current with base. (`ahead_by` counts the head's own commits — ignore it.) This is the watcher's out-of-date trigger; it is exact even while `mergeable == UNKNOWN`.
@@ -8,7 +8,7 @@ Skills assume a working `gh auth status`. Auth errors surface verbatim from `gh`
8
8
 
9
9
  | Recipe | Use case |
10
10
  | :----- | :------- |
11
- | [`pr-metadata`](github-cli-recipes/pr-metadata.md) | Snapshot PR state, head SHA, branch — watcher + bootstrap. |
11
+ | [`pr-metadata`](github-cli-recipes/pr-metadata.md) | Snapshot PR state, head SHA, branch, conflict + `behind_by` out-of-date detection — watcher + bootstrap. |
12
12
  | [`submitted-reviews`](github-cli-recipes/submitted-reviews.md) | Fetch a review by id / watcher's body-only-review check. |
13
13
  | [`pr-checks`](github-cli-recipes/pr-checks.md) | Check-run rollup for the head SHA — watcher's CI poll. |
14
14
  | [`line-comments-for-review`](github-cli-recipes/line-comments-for-review.md) | Pull a review's line comments — `/muggle-do` per-comment routing. |
@@ -23,7 +23,7 @@ One per watcher iteration (idle or not).
23
23
 
24
24
  - `actionable_threads`: count of actionable items this tick — unresolved, non-outdated threads whose newest comment is unmarked, plus body-only reviews past `lastBodyReviewId` — **after** filtering by the escalated set.
25
25
  - `dispatched_review_ids`: owning review ids handed to `/muggle-do`. Empty when idle.
26
- - `rebase_needed`: true when the branch is behind (`BEHIND`) or conflicting (`DIRTY`/`CONFLICTING`) with its base. `false` when reviews were dispatched (reviews preempt the mergeability check).
26
+ - `rebase_needed`: true when the branch is behind its base (`behind_by > 0`) or conflicting (`mergeable == CONFLICTING`). `false` when reviews were dispatched (reviews preempt the mergeability check).
27
27
  - `dispatched_rebase`: true when this tick dispatched `/muggle-do` with a rebase directive.
28
28
  - `checks_red`: count of failing checks on the head SHA. `0` when reviews or a rebase were dispatched (both preempt the CI poll) or CI was green/pending.
29
29
  - `dispatched_ci_fix`: true when this tick dispatched `/muggle-do` with a fix-ci directive.
@@ -145,6 +145,8 @@ For each test case:
145
145
 
146
146
  **Overall:** PASS | FAIL | PARTIAL | INCONCLUSIVE | BLOCKED | SKIPPED — see [`../_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) section F for the canonical taxonomy.
147
147
 
148
+ Failed runs use the same evidence + diagnosis assembly as the interactive debug path ([`../_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) Steps 1–2) — write that evidence into the **Failed** block above. This stage is autonomous, so it skips Step 3's interactive offer.
149
+
148
150
  ## Hard constraints
149
151
 
150
152
  - **Do NOT shut down the dev server.** The caller manages dev-server lifecycle.
@@ -31,7 +31,7 @@ If `prs.json[0].state` on disk is already `merged` or `closed`, this slot was fi
31
31
 
32
32
  ### Step 1 — Refresh PR state
33
33
 
34
- Per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). Update `prs.json[0].head_sha` and `prs.json[0].state` from the response; keep `mergeable` / `mergeStateStatus` from the same call for Step 5.
34
+ Per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). Update `prs.json[0].head_sha` and `prs.json[0].state` from the response; keep `mergeable` (conflict signal) for Step 5, and run the recipe's `compare` call to capture `behind_by` (out-of-date signal) for Step 5.
35
35
 
36
36
  ### Step 2 — Termination check
37
37
 
@@ -79,10 +79,12 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
79
79
 
80
80
  ### Step 5 — No actionable feedback → keep the branch rebased on its base
81
81
 
82
- A merge-ready branch is **current with its base** — neither conflicting nor behind. Read `mergeable` / `mergeStateStatus` from the Step 1 metadata; the branch needs a rebase when either:
82
+ A merge-ready branch is **current with its base** — neither conflicting nor behind. From the Step 1 metadata, the branch needs a rebase when either:
83
83
 
84
- - `mergeable == CONFLICTING` or `mergeStateStatus == DIRTY` — conflicts with the base, **or**
85
- - `mergeStateStatus == BEHIND` — out of date with the base, no conflict. An unrebased branch never becomes merge-ready on its own, and is merge-blocked wherever the base requires up-to-date branches.
84
+ - `mergeable == CONFLICTING` (corroborated by `mergeStateStatus == DIRTY`) — conflicts with the base, **or**
85
+ - `behind_by > 0` — out of date with the base. Read this from the `compare` call (commit ancestry), **never** from `mergeStateStatus == BEHIND`: GitHub masks `BEHIND` behind `DIRTY`/`BLOCKED` and only surfaces it under "require branches up to date" protection, so a stale PR that is also awaiting review or has a red required check reports `BLOCKED` — and its staleness would go unseen. See [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md#behind-by-out-of-date-detection).
86
+
87
+ This trigger is **independent of approval and CI state**: an out-of-date branch is rebased whether or not it has been reviewed, approved, or has green checks. The watcher acts on staleness directly — it never waits for an approval to surface it.
86
88
 
87
89
  If a rebase is due **and** `conflict_resolve_attempts[head_sha] < 2` **and** `head_sha` ∉ `conflict_escalated_shas` → dispatch and exit:
88
90
 
@@ -96,7 +98,7 @@ If a rebase is due **and** `conflict_resolve_attempts[head_sha] < 2` **and** `he
96
98
  4. Append a dispatching line to `followup.log`; emit a `tick` event with `rebase_needed: true`, `dispatched_rebase: true`.
97
99
  5. Exit. The dev cycle owns the PR; its respawn restarts the watcher, whose next tick re-checks the branch against its base on the new head — the rebase is its own verify loop, bounded by the per-SHA attempt budget.
98
100
 
99
- Branch current with its base (`CLEAN` / `BLOCKED` / `UNSTABLE` / `HAS_HOOKS`), `mergeable == UNKNOWN` (GitHub still computing — treat as current this tick), or budget spent (`conflict_resolve_attempts[head_sha] >= 2` or `head_sha` ∈ `conflict_escalated_shas`) → fall through to CI.
101
+ Otherwise — `behind_by == 0` and not conflicting (`mergeable == UNKNOWN` is fine here: `behind_by` is exact while GitHub is still computing conflict state, so a stale branch still triggers), or budget spent (`conflict_resolve_attempts[head_sha] >= 2` or `head_sha` ∈ `conflict_escalated_shas`) → fall through to CI.
100
102
 
101
103
  ### Step 6 — No actionable feedback, branch current → poll CI for the head SHA
102
104
 
@@ -297,7 +297,7 @@ Checkout flow FAILED 15.7s 12 https://www.muggle-ai.co
297
297
  Total: 3 tests | 2 passed | 1 failed | 37.1s
298
298
  ```
299
299
 
300
- For failures: show which step failed, the local screenshot path, and a suggestion.
300
+ For failures, don't hand-write a verdict in the summary — route each through the debug path (Step 7C).
301
301
 
302
302
  ## Step 7B: Execute — Remote Mode
303
303
 
@@ -341,20 +341,11 @@ Login with invalid creds COMPLETED rt-def456
341
341
  Checkout flow QUEUED rt-ghi789
342
342
  ```
343
343
 
344
- ## Step 7C: Route failures through the failure-mode handler
344
+ ## Step 7C: Route every failed run through the debug path
345
345
 
346
- For every run with `status: "failed"` (or any non-passing terminal state) from 7A or 7B, follow [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md):
346
+ For every run with `status: "failed"` (or any non-passing terminal state) from 7A or 7B, route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md). This is **mandatory** — a failure is never reported without it. The debug path gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always an option and "skip" is never the default.
347
347
 
348
- - **Replay-mode failures** — section B (buckets: `infra` / `stale-script` / `product-defect`).
349
- - **Regen-mode failures** — section C (buckets: `transient` / `infra` / `agent-course` / `product-uxux`).
350
-
351
- For each failed run:
352
- 1. Read the run with `muggle-local-run-result-get` (local) or `muggle-remote-wf-get-ts-gen-latest-run` / `muggle-remote-wf-get-ts-replay-latest-run` (remote) and extract signals per the heuristics in the shared doc.
353
- 2. Emit `replay-failure-classified` or `regen-failure-classified` via `muggle-local-telemetry-event-emit` **before** asking the user.
354
- 3. Present the recommended action via `AskUserQuestion` along with the alternatives the shared doc lists for that bucket.
355
- 4. After the user picks, emit the matching `*-resolved` event with `userAction` set to what they chose.
356
-
357
- Process failures one at a time so the user isn't drowning in pickers — but emit telemetry per failure regardless.
348
+ Pass it per failed run: the `runId` (local) or workflow runtime id (remote), the `mode` that failed, `testCaseId`, `projectId`, and the execution handle (local: the dev loop from "Run the dev loop"; remote: 7B's workflow-start) so a rerun re-enters the same path. Process failures one at a time so the user isn't drowning in pickers.
358
349
 
359
350
  ## Step 8: Open Results in Browser
360
351
 
@@ -403,23 +394,22 @@ Once a PR exists for this work, offer to keep watching its review thread.
403
394
 
404
395
  The `/mprfollowup` shortcut starts the same watcher manually at any time.
405
396
 
406
- ## Step 10: Offer feedback on failures
407
-
408
- After the report is complete, if **any** test in the run had a `failed` or unexpected status (or the user verbally flags something looked off), suggest the feedback skill:
397
+ ## Step 10: Offer feedback on a clean pass
409
398
 
410
- > "Looks like `<N>` test(s) didn't go as expected. Want to leave feedback on what should've happened? It triggers regeneration on the affected scripts."
399
+ Failures already got a guaranteed feedback-&-rerun offer in Step 7C's debug path — don't re-ask for them here.
411
400
 
412
- Use `AskUserQuestion`:
413
- - **Yes — give feedback** → invoke the `muggle-feedback` skill via the `Skill` tool. Pass the failed run's `runId` (local) or `testScriptId` (remote) as anchor context so the submit flow opens with the correct script already loaded.
401
+ This step is only for a run that **passed** but the user flags as off (a misclick, wrong element, a summary that doesn't match intent). When that happens, use `AskUserQuestion`:
402
+ - **Yes — give feedback** → invoke the `muggle-feedback` skill via the `Skill` tool, passing the run's `runId` (local) or `testScriptId` (remote) as anchor context so the submit flow opens with the correct script already loaded.
414
403
  - **No — skip**
415
404
 
416
- This is a suggestion, not automatic invocation. Skip silently if every test passed cleanly.
405
+ Skip silently if nothing looked off.
417
406
 
418
407
  ## Non-negotiables
419
408
 
420
409
  Each rule below is covered in-step above; these are the ones this skill most often violates, kept here as reinforcement:
421
410
 
422
411
  - **Test-case shape** — never skip the generate→review cycle, never consolidate the generator's micro-tests, one atomic behavior per test case. Creating test cases directly or merging the generator's output is the single most frequent mistake.
412
+ - **Every failure routes through the debug path** — no failed run is summarized-and-dropped. Step 7C → [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) is mandatory, "give feedback & rerun" is always offered, and "skip" is never the default.
423
413
  - **Confirm intent before acting** — local vs remote; never guess the localhost/preview URL.
424
414
  - **PR URLs run in a dedicated worktree** — never switch the user's main checkout; pass that worktree as `cwd`.
425
415
  - **Every selection uses `AskUserQuestion`** — never ask the user to type a number; the user picks the project (never auto-select).
@@ -174,22 +174,13 @@ Read the run record per [`../_shared/dev-loop/failures.md`](../_shared/dev-loop/
174
174
 
175
175
  - Include in the report: status, duration, pass/fail summary, per-step summary (passed runs), artifact paths, errors if failed, and script view URL when publishing ran.
176
176
 
177
- ### 9a. Route failures through the failure-mode handler
177
+ ### 9a. Route a failed run through the debug path
178
178
 
179
- If the run's status is `failed` or any non-passing terminal state, follow [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md):
179
+ If the run's status is `failed` or any non-passing terminal state, route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) — **mandatory**; a failure is never reported without it. It gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always offered and "skip" is never the default.
180
180
 
181
- - **Replay-mode run failed** (the user picked an existing script in Step 5) → section B (buckets: `infra` / `stale-script` / `product-defect`).
182
- - **Regen-mode run failed** (the user picked "Generate new script" or no script existed) → section C (buckets: `transient` / `infra` / `agent-course` / `product-uxux`).
181
+ Pass it: the `runId`, the `mode` that failed (replay if the user picked an existing script in Step 5, else regen), `testCaseId`, `projectId`, and the local execution handle so a rerun re-enters the same path.
183
182
 
184
- Steps:
185
- 1. Read the run via `muggle-local-run-result-get` and extract signals per the heuristics in the shared doc.
186
- 2. Emit `replay-failure-classified` or `regen-failure-classified` via `muggle-local-telemetry-event-emit` **before** asking the user.
187
- 3. Present the recommended action via `AskUserQuestion` with the alternatives the shared doc lists for that bucket.
188
- 4. After the user picks, emit the matching `*-resolved` event with `userAction`.
189
-
190
- If the user picks `muggle-feedback` from any bucket's options, invoke the `muggle-feedback` skill via the `Skill` tool, passing the just-finished `runId` so the submit flow opens with this run preloaded.
191
-
192
- Skip silently when the run passed cleanly — failure-mode events are by definition about failures.
183
+ Skip only when the run passed cleanly — the debug path is by definition about failures.
193
184
 
194
185
  ### 9b. Remind the user to guide the agent (every Electron invocation)
195
186
 
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "5.0.3",
3
- "buildId": "run-51-1",
4
- "commitSha": "7285eaa7458b2a240299e20be18ba94590413f2e",
5
- "buildTime": "2026-06-09T19:26:19Z",
2
+ "release": "5.0.4",
3
+ "buildId": "run-52-1",
4
+ "commitSha": "d27f03da1295aa4e58c8e2ba6a26a0e76c7700c9",
5
+ "buildTime": "2026-06-09T21:46:24Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@muggleai/works",
3
3
  "mcpName": "io.github.multiplex-ai/muggle",
4
- "version": "5.0.3",
4
+ "version": "5.0.4",
5
5
  "description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -41,14 +41,14 @@
41
41
  "test:watch": "vitest"
42
42
  },
43
43
  "muggleConfig": {
44
- "electronAppVersion": "1.2.2",
44
+ "electronAppVersion": "1.2.3",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "45c09f605d05fc72c60fae54847a689e1858aac9e2c4acca7f25c17a8cd1ad7b",
49
- "darwin-x64": "b662a57106f1d90c646180ac506d2f567bbbcea33b3fe5ecb9e83b8166426400",
50
- "linux-x64": "2f86a28e2dc9c7777710c31001686596ce36c560c93e93c53c9bcc4470c07be4",
51
- "win32-x64": "42f3f28e58efb207a0f2b4993cbc3f2232c30e20960b29b56a45e4c387777346"
48
+ "darwin-arm64": "f46cfc5f052021f13de7d7721276d58863b958ec717631e98b97b7cd3d0fe4fa",
49
+ "darwin-x64": "e2254373a0bb3fffa46b236629c5d54a611ab05e138104a98f6f60a5d1280805",
50
+ "linux-x64": "ff5698fdbc1d65f436b75d860ebe50ee7171c7726565fa0ab2149a6f1cde4d13",
51
+ "win32-x64": "35ffa7af1767e802c7670c85205ea11961cb5583aa5dc30947d142eb7c734ff5"
52
52
  }
53
53
  },
54
54
  "dependencies": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "muggle",
3
3
  "description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
4
- "version": "5.0.3",
4
+ "version": "5.0.4",
5
5
  "author": {
6
6
  "name": "Muggle AI",
7
7
  "email": "support@muggle-ai.com"
@@ -2,7 +2,7 @@
2
2
  "name": "muggle",
3
3
  "displayName": "Muggle AI",
4
4
  "description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
5
- "version": "5.0.3",
5
+ "version": "5.0.4",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,53 @@
1
+ # Debug a Failed Run — Shared Reference
2
+
3
+ > Presentation layer for a single failed run. Turns one non-passing terminal run — local or remote — into a debug path: **evidence → diagnosis → a guaranteed user choice that always offers "give feedback & rerun".** Used by `muggle-test` (Step 7C), `muggle-test-feature-local`, and the `muggle-do` e2e stage. Depends on [`failure-mode-handling.md`](./failure-mode-handling.md) for the bucket taxonomy and telemetry schema — never the reverse. Don't restate its tables; read them.
4
+
5
+ ## The guarantee
6
+
7
+ Every non-passing terminal run MUST route through this doc before it is reported. A failure is never summarized-and-dropped: the user is always shown *what happened* and is always presented a selection in which **"give feedback & rerun" is a first-class option**. "Skip — just report" stays selectable but is never the default.
8
+
9
+ The guarantee binds **interactive** callers. An autonomous caller with no user to prompt (the `acceptance-tester` agent) runs Steps 1–2 (evidence + diagnosis into its structured report) and skips Step 3's interactive offer.
10
+
11
+ ## Inputs (the caller passes these in)
12
+
13
+ - `runId` (local) or workflow runtime id (remote).
14
+ - `mode` — `replay` or `regen`, the mode that failed.
15
+ - `testCaseId`, `projectId`.
16
+ - A re-execute handle — the loop/tool the caller used to run this case, so a rerun re-enters the same execution path.
17
+
18
+ ## Step 1 — Gather evidence
19
+
20
+ Read **structured run fields**, never the `execute` stdout tail (see [`dev-loop/failures.md`](./dev-loop/failures.md)). Assemble:
21
+
22
+ - **Attempted steps + reasoning** — local: the attempted steps + `summaryStep` halt reason from `action-script.json` in `artifactsDir`; remote: the per-step list + `summaryStep` from `muggle-remote-wf-get-ts-gen-latest-run` / `muggle-remote-wf-get-ts-replay-latest-run`.
23
+ - **Visual evidence** — a failed run already preserves the full step-by-step on disk: every per-step frame under `<artifactsDir>/electron-runtime/screenshot/` (with per-step label data under `.../dataset/`), alongside the step script at `<artifactsDir>/action-script.json`. `run-result-get` returns `artifactsDir` — read the whole set there; don't trust a step's `screenshotLocalPath`, which points at the original runtime dir. Once published — failed runs are published too, see [`dev-loop/publish.md`](./dev-loop/publish.md) — the same frames are cloud-hosted per step as `screenshotUrl`, the form remote runs expose directly.
24
+ - **Verdict** — `Status` + `Error`.
25
+
26
+ ## Step 2 — Diagnose
27
+
28
+ Classify into the failure bucket per [`failure-mode-handling.md`](./failure-mode-handling.md) — §B for a replay failure, §C for a regen failure. That bucket **is** the initial diagnosis. Phrase it for a human ("Looks like a **stale script** — the selectors moved; the product itself probably still works"), not as a telemetry label. Emit the `replay-failure-classified` / `regen-failure-classified` event now, before presenting anything.
29
+
30
+ ## Step 3 — Present the debug card, then the guaranteed offer
31
+
32
+ Show the **debug card** first: attempted steps + reasoning, the failing step's screenshot (or a one-line note if a path is genuinely absent), and the one-line diagnosis.
33
+
34
+ Then present one `AskUserQuestion` whose options are:
35
+
36
+ 1. **Give feedback & rerun** — always present. Invoke the `muggle-feedback` skill with this run's anchor (`runId` local / `testScriptId` remote) so the user says what should have happened, then re-execute per Step 4.
37
+ 2. **The bucket's recommended action** from §B/§C (regenerate, report bug, share defect, retry…). Label it `(Recommended)` — it is the classifier's pick.
38
+ 3. **Retry as-is**.
39
+ 4. **Skip — just report** — last, never the default.
40
+
41
+ The bucket's recommended action and its alternatives live in `failure-mode-handling.md` §B/§C — read them there, don't restate them.
42
+
43
+ **Feedback anchor by lane.** Feedback attaches to a cloud action-script id. `muggle-feedback` owns resolving it: for a **local** run it publishes/uploads first when the run isn't already published; for a **remote** run it uses the existing script. Pass `runId` (local) or `testScriptId` (remote) and let it resolve the anchor — don't resolve or upload here.
44
+
45
+ ## Step 4 — Rerun (always regen)
46
+
47
+ On "give feedback & rerun": once `muggle-feedback` returns, re-execute the test case in **regen** mode — feedback adjusts the agent's course, so the prior script is discarded; replay is never the rerun path. Local: the regen branch of [`dev-loop/run.md`](./dev-loop/run.md). Remote: `muggle-remote-workflow-start-test-script-generation`. Read the new run's result back through this doc (Step 1) so a second failure is debugged too.
48
+
49
+ ## Step 5 — Resolve
50
+
51
+ Emit the `replay-failure-resolved` / `regen-failure-resolved` event with `userAction` set to the pick (`feedback-rerun`, the bucket action, `retry`, or `skip`) — one `*-classified` and one `*-resolved` per failure, per [`failure-mode-handling.md`](./failure-mode-handling.md) §D.
52
+
53
+ Process failures one at a time so the user isn't drowning in pickers.
@@ -1,6 +1,6 @@
1
1
  # PR metadata snapshot
2
2
 
3
- Fetch the fields the watcher and bootstrap need in one call.
3
+ Fetch the fields the watcher and bootstrap need.
4
4
 
5
5
  ```bash
6
6
  gh pr view <pr-number> --repo <owner>/<repo> \
@@ -10,4 +10,16 @@ gh pr view <pr-number> --repo <owner>/<repo> \
10
10
  - `state` is one of `OPEN`, `MERGED`, `CLOSED`.
11
11
  - `headRefOid` is the current head SHA — store as `head_sha` in `prs.json`.
12
12
  - `headRefName` is the branch — must match the working tree's branch in bootstrap.
13
- - `mergeable` is `MERGEABLE`, `CONFLICTING`, or `UNKNOWN` (GitHub still computing — treat as current this tick). `mergeStateStatus` carries the finer state: `DIRTY` = conflicts with base, `BEHIND` = out of date with base (no conflict), `CLEAN`/`BLOCKED`/`UNSTABLE`/`HAS_HOOKS` = current. The watcher dispatches a rebase on `CONFLICTING`/`DIRTY` **or** `BEHIND` — keeping the branch current with its base, a merge-ready gap no review or CI signal would surface.
13
+ - `mergeable` is `MERGEABLE`, `CONFLICTING`, or `UNKNOWN` (GitHub still computing — treat as not-conflicting this tick). The watcher's **conflict** signal is `mergeable == CONFLICTING` (corroborated by `mergeStateStatus == DIRTY`).
14
+
15
+ ## Behind-by (out-of-date detection)
16
+
17
+ `mergeStateStatus == BEHIND` is **not** a reliable out-of-date signal. GitHub collapses merge state into one value with precedence — `DIRTY` (conflict) and `BLOCKED` (missing required review, pending/failing required check) outrank `BEHIND` and mask it, and `BEHIND` surfaces *at all* only when the base enforces "require branches up to date." So a PR that is genuinely behind **and** awaiting review reports `BLOCKED`; `BEHIND` never shows, and its staleness goes unseen.
18
+
19
+ Detect out-of-date straight from commit ancestry instead — independent of merge-state precedence, review state, and branch protection:
20
+
21
+ ```bash
22
+ gh api repos/<owner>/<repo>/compare/<baseRefName>...<head_sha> --jq '.behind_by'
23
+ ```
24
+
25
+ `behind_by > 0` ⇒ the head is missing that many base commits ⇒ out of date. `0` ⇒ current with base. (`ahead_by` counts the head's own commits — ignore it.) This is the watcher's out-of-date trigger; it is exact even while `mergeable == UNKNOWN`.
@@ -8,7 +8,7 @@ Skills assume a working `gh auth status`. Auth errors surface verbatim from `gh`
8
8
 
9
9
  | Recipe | Use case |
10
10
  | :----- | :------- |
11
- | [`pr-metadata`](github-cli-recipes/pr-metadata.md) | Snapshot PR state, head SHA, branch — watcher + bootstrap. |
11
+ | [`pr-metadata`](github-cli-recipes/pr-metadata.md) | Snapshot PR state, head SHA, branch, conflict + `behind_by` out-of-date detection — watcher + bootstrap. |
12
12
  | [`submitted-reviews`](github-cli-recipes/submitted-reviews.md) | Fetch a review by id / watcher's body-only-review check. |
13
13
  | [`pr-checks`](github-cli-recipes/pr-checks.md) | Check-run rollup for the head SHA — watcher's CI poll. |
14
14
  | [`line-comments-for-review`](github-cli-recipes/line-comments-for-review.md) | Pull a review's line comments — `/muggle-do` per-comment routing. |
@@ -23,7 +23,7 @@ One per watcher iteration (idle or not).
23
23
 
24
24
  - `actionable_threads`: count of actionable items this tick — unresolved, non-outdated threads whose newest comment is unmarked, plus body-only reviews past `lastBodyReviewId` — **after** filtering by the escalated set.
25
25
  - `dispatched_review_ids`: owning review ids handed to `/muggle-do`. Empty when idle.
26
- - `rebase_needed`: true when the branch is behind (`BEHIND`) or conflicting (`DIRTY`/`CONFLICTING`) with its base. `false` when reviews were dispatched (reviews preempt the mergeability check).
26
+ - `rebase_needed`: true when the branch is behind its base (`behind_by > 0`) or conflicting (`mergeable == CONFLICTING`). `false` when reviews were dispatched (reviews preempt the mergeability check).
27
27
  - `dispatched_rebase`: true when this tick dispatched `/muggle-do` with a rebase directive.
28
28
  - `checks_red`: count of failing checks on the head SHA. `0` when reviews or a rebase were dispatched (both preempt the CI poll) or CI was green/pending.
29
29
  - `dispatched_ci_fix`: true when this tick dispatched `/muggle-do` with a fix-ci directive.
@@ -145,6 +145,8 @@ For each test case:
145
145
 
146
146
  **Overall:** PASS | FAIL | PARTIAL | INCONCLUSIVE | BLOCKED | SKIPPED — see [`../_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) section F for the canonical taxonomy.
147
147
 
148
+ Failed runs use the same evidence + diagnosis assembly as the interactive debug path ([`../_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) Steps 1–2) — write that evidence into the **Failed** block above. This stage is autonomous, so it skips Step 3's interactive offer.
149
+
148
150
  ## Hard constraints
149
151
 
150
152
  - **Do NOT shut down the dev server.** The caller manages dev-server lifecycle.
@@ -31,7 +31,7 @@ If `prs.json[0].state` on disk is already `merged` or `closed`, this slot was fi
31
31
 
32
32
  ### Step 1 — Refresh PR state
33
33
 
34
- Per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). Update `prs.json[0].head_sha` and `prs.json[0].state` from the response; keep `mergeable` / `mergeStateStatus` from the same call for Step 5.
34
+ Per [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md). Update `prs.json[0].head_sha` and `prs.json[0].state` from the response; keep `mergeable` (conflict signal) for Step 5, and run the recipe's `compare` call to capture `behind_by` (out-of-date signal) for Step 5.
35
35
 
36
36
  ### Step 2 — Termination check
37
37
 
@@ -79,10 +79,12 @@ The watcher does **not** classify. Classification, batching, replying, escalatio
79
79
 
80
80
  ### Step 5 — No actionable feedback → keep the branch rebased on its base
81
81
 
82
- A merge-ready branch is **current with its base** — neither conflicting nor behind. Read `mergeable` / `mergeStateStatus` from the Step 1 metadata; the branch needs a rebase when either:
82
+ A merge-ready branch is **current with its base** — neither conflicting nor behind. From the Step 1 metadata, the branch needs a rebase when either:
83
83
 
84
- - `mergeable == CONFLICTING` or `mergeStateStatus == DIRTY` — conflicts with the base, **or**
85
- - `mergeStateStatus == BEHIND` — out of date with the base, no conflict. An unrebased branch never becomes merge-ready on its own, and is merge-blocked wherever the base requires up-to-date branches.
84
+ - `mergeable == CONFLICTING` (corroborated by `mergeStateStatus == DIRTY`) — conflicts with the base, **or**
85
+ - `behind_by > 0` — out of date with the base. Read this from the `compare` call (commit ancestry), **never** from `mergeStateStatus == BEHIND`: GitHub masks `BEHIND` behind `DIRTY`/`BLOCKED` and only surfaces it under "require branches up to date" protection, so a stale PR that is also awaiting review or has a red required check reports `BLOCKED` — and its staleness would go unseen. See [`../_shared/github-cli-recipes/pr-metadata.md`](../_shared/github-cli-recipes/pr-metadata.md#behind-by-out-of-date-detection).
86
+
87
+ This trigger is **independent of approval and CI state**: an out-of-date branch is rebased whether or not it has been reviewed, approved, or has green checks. The watcher acts on staleness directly — it never waits for an approval to surface it.
86
88
 
87
89
  If a rebase is due **and** `conflict_resolve_attempts[head_sha] < 2` **and** `head_sha` ∉ `conflict_escalated_shas` → dispatch and exit:
88
90
 
@@ -96,7 +98,7 @@ If a rebase is due **and** `conflict_resolve_attempts[head_sha] < 2` **and** `he
96
98
  4. Append a dispatching line to `followup.log`; emit a `tick` event with `rebase_needed: true`, `dispatched_rebase: true`.
97
99
  5. Exit. The dev cycle owns the PR; its respawn restarts the watcher, whose next tick re-checks the branch against its base on the new head — the rebase is its own verify loop, bounded by the per-SHA attempt budget.
98
100
 
99
- Branch current with its base (`CLEAN` / `BLOCKED` / `UNSTABLE` / `HAS_HOOKS`), `mergeable == UNKNOWN` (GitHub still computing — treat as current this tick), or budget spent (`conflict_resolve_attempts[head_sha] >= 2` or `head_sha` ∈ `conflict_escalated_shas`) → fall through to CI.
101
+ Otherwise — `behind_by == 0` and not conflicting (`mergeable == UNKNOWN` is fine here: `behind_by` is exact while GitHub is still computing conflict state, so a stale branch still triggers), or budget spent (`conflict_resolve_attempts[head_sha] >= 2` or `head_sha` ∈ `conflict_escalated_shas`) → fall through to CI.
100
102
 
101
103
  ### Step 6 — No actionable feedback, branch current → poll CI for the head SHA
102
104
 
@@ -297,7 +297,7 @@ Checkout flow FAILED 15.7s 12 https://www.muggle-ai.co
297
297
  Total: 3 tests | 2 passed | 1 failed | 37.1s
298
298
  ```
299
299
 
300
- For failures: show which step failed, the local screenshot path, and a suggestion.
300
+ For failures, don't hand-write a verdict in the summary — route each through the debug path (Step 7C).
301
301
 
302
302
  ## Step 7B: Execute — Remote Mode
303
303
 
@@ -341,20 +341,11 @@ Login with invalid creds COMPLETED rt-def456
341
341
  Checkout flow QUEUED rt-ghi789
342
342
  ```
343
343
 
344
- ## Step 7C: Route failures through the failure-mode handler
344
+ ## Step 7C: Route every failed run through the debug path
345
345
 
346
- For every run with `status: "failed"` (or any non-passing terminal state) from 7A or 7B, follow [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md):
346
+ For every run with `status: "failed"` (or any non-passing terminal state) from 7A or 7B, route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md). This is **mandatory** — a failure is never reported without it. The debug path gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always an option and "skip" is never the default.
347
347
 
348
- - **Replay-mode failures** — section B (buckets: `infra` / `stale-script` / `product-defect`).
349
- - **Regen-mode failures** — section C (buckets: `transient` / `infra` / `agent-course` / `product-uxux`).
350
-
351
- For each failed run:
352
- 1. Read the run with `muggle-local-run-result-get` (local) or `muggle-remote-wf-get-ts-gen-latest-run` / `muggle-remote-wf-get-ts-replay-latest-run` (remote) and extract signals per the heuristics in the shared doc.
353
- 2. Emit `replay-failure-classified` or `regen-failure-classified` via `muggle-local-telemetry-event-emit` **before** asking the user.
354
- 3. Present the recommended action via `AskUserQuestion` along with the alternatives the shared doc lists for that bucket.
355
- 4. After the user picks, emit the matching `*-resolved` event with `userAction` set to what they chose.
356
-
357
- Process failures one at a time so the user isn't drowning in pickers — but emit telemetry per failure regardless.
348
+ Pass it per failed run: the `runId` (local) or workflow runtime id (remote), the `mode` that failed, `testCaseId`, `projectId`, and the execution handle (local: the dev loop from "Run the dev loop"; remote: 7B's workflow-start) so a rerun re-enters the same path. Process failures one at a time so the user isn't drowning in pickers.
358
349
 
359
350
  ## Step 8: Open Results in Browser
360
351
 
@@ -403,23 +394,22 @@ Once a PR exists for this work, offer to keep watching its review thread.
403
394
 
404
395
  The `/mprfollowup` shortcut starts the same watcher manually at any time.
405
396
 
406
- ## Step 10: Offer feedback on failures
407
-
408
- After the report is complete, if **any** test in the run had a `failed` or unexpected status (or the user verbally flags something looked off), suggest the feedback skill:
397
+ ## Step 10: Offer feedback on a clean pass
409
398
 
410
- > "Looks like `<N>` test(s) didn't go as expected. Want to leave feedback on what should've happened? It triggers regeneration on the affected scripts."
399
+ Failures already got a guaranteed feedback-&-rerun offer in Step 7C's debug path — don't re-ask for them here.
411
400
 
412
- Use `AskUserQuestion`:
413
- - **Yes — give feedback** → invoke the `muggle-feedback` skill via the `Skill` tool. Pass the failed run's `runId` (local) or `testScriptId` (remote) as anchor context so the submit flow opens with the correct script already loaded.
401
+ This step is only for a run that **passed** but the user flags as off (a misclick, wrong element, a summary that doesn't match intent). When that happens, use `AskUserQuestion`:
402
+ - **Yes — give feedback** → invoke the `muggle-feedback` skill via the `Skill` tool, passing the run's `runId` (local) or `testScriptId` (remote) as anchor context so the submit flow opens with the correct script already loaded.
414
403
  - **No — skip**
415
404
 
416
- This is a suggestion, not automatic invocation. Skip silently if every test passed cleanly.
405
+ Skip silently if nothing looked off.
417
406
 
418
407
  ## Non-negotiables
419
408
 
420
409
  Each rule below is covered in-step above; these are the ones this skill most often violates, kept here as reinforcement:
421
410
 
422
411
  - **Test-case shape** — never skip the generate→review cycle, never consolidate the generator's micro-tests, one atomic behavior per test case. Creating test cases directly or merging the generator's output is the single most frequent mistake.
412
+ - **Every failure routes through the debug path** — no failed run is summarized-and-dropped. Step 7C → [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) is mandatory, "give feedback & rerun" is always offered, and "skip" is never the default.
423
413
  - **Confirm intent before acting** — local vs remote; never guess the localhost/preview URL.
424
414
  - **PR URLs run in a dedicated worktree** — never switch the user's main checkout; pass that worktree as `cwd`.
425
415
  - **Every selection uses `AskUserQuestion`** — never ask the user to type a number; the user picks the project (never auto-select).
@@ -174,22 +174,13 @@ Read the run record per [`../_shared/dev-loop/failures.md`](../_shared/dev-loop/
174
174
 
175
175
  - Include in the report: status, duration, pass/fail summary, per-step summary (passed runs), artifact paths, errors if failed, and script view URL when publishing ran.
176
176
 
177
- ### 9a. Route failures through the failure-mode handler
177
+ ### 9a. Route a failed run through the debug path
178
178
 
179
- If the run's status is `failed` or any non-passing terminal state, follow [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md):
179
+ If the run's status is `failed` or any non-passing terminal state, route through [`_shared/debug-failed-run.md`](../_shared/debug-failed-run.md) — **mandatory**; a failure is never reported without it. It gathers evidence (attempted steps + reasoning + screenshot), diagnoses via [`_shared/failure-mode-handling.md`](../_shared/failure-mode-handling.md) (§B replay / §C regen), shows the debug card, and presents the guaranteed selection in which **"give feedback & rerun"** is always offered and "skip" is never the default.
180
180
 
181
- - **Replay-mode run failed** (the user picked an existing script in Step 5) → section B (buckets: `infra` / `stale-script` / `product-defect`).
182
- - **Regen-mode run failed** (the user picked "Generate new script" or no script existed) → section C (buckets: `transient` / `infra` / `agent-course` / `product-uxux`).
181
+ Pass it: the `runId`, the `mode` that failed (replay if the user picked an existing script in Step 5, else regen), `testCaseId`, `projectId`, and the local execution handle so a rerun re-enters the same path.
183
182
 
184
- Steps:
185
- 1. Read the run via `muggle-local-run-result-get` and extract signals per the heuristics in the shared doc.
186
- 2. Emit `replay-failure-classified` or `regen-failure-classified` via `muggle-local-telemetry-event-emit` **before** asking the user.
187
- 3. Present the recommended action via `AskUserQuestion` with the alternatives the shared doc lists for that bucket.
188
- 4. After the user picks, emit the matching `*-resolved` event with `userAction`.
189
-
190
- If the user picks `muggle-feedback` from any bucket's options, invoke the `muggle-feedback` skill via the `Skill` tool, passing the just-finished `runId` so the submit flow opens with this run preloaded.
191
-
192
- Skip silently when the run passed cleanly — failure-mode events are by definition about failures.
183
+ Skip only when the run passed cleanly — the debug path is by definition about failures.
193
184
 
194
185
  ### 9b. Remind the user to guide the agent (every Electron invocation)
195
186