@muggleai/works 4.13.0 → 4.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-TWILR37J.js';
1
+ import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-YKR2TQ24.js';
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
4
  import { v4 } from 'uuid';
@@ -736,7 +736,7 @@ async function resolveGsScreenshotUrls(report, opts) {
736
736
  if (gsUrls.length === 0) {
737
737
  return report;
738
738
  }
739
- const mcps = await import('./src-BD5AM6OH.js');
739
+ const mcps = await import('./src-ECRJW2LY.js');
740
740
  const credentials = await mcps.getCallerCredentialsAsync();
741
741
  if (!credentials.bearerToken && !credentials.apiKey) {
742
742
  stderrWrite(
@@ -3838,6 +3838,9 @@ var TestCaseListInputSchema = z.object({
3838
3838
  var TestCaseGetInputSchema = z.object({
3839
3839
  testCaseId: IdSchema.describe("Test case ID (UUID) to retrieve")
3840
3840
  });
3841
+ var TestCaseAncestorsGetInputSchema = z.object({
3842
+ testCaseId: IdSchema.describe("Test case ID (UUID) to resolve the test-plan-graph ancestor chain for")
3843
+ });
3841
3844
  var TestCaseListByUseCaseInputSchema = z.object({
3842
3845
  useCaseId: IdSchema.describe("Use case ID (UUID) to list test cases for")
3843
3846
  });
@@ -4701,6 +4704,18 @@ var testCaseTools = [
4701
4704
  };
4702
4705
  }
4703
4706
  },
4707
+ {
4708
+ name: "muggle-remote-test-case-ancestors-get",
4709
+ description: "Resolve a test case's prerequisite chain from the project's test-plan graph. Returns { testCaseId, ancestors, orphan } where `ancestors` is an array of test case IDs ordered immediate-parent \u2192 root (empty when the case is a graph root). `orphan: true` means the case has no graph node, so it has no prerequisites. Call this before generating or replaying a script to ensure every prerequisite test case already has a ready script.",
4710
+ inputSchema: TestCaseAncestorsGetInputSchema,
4711
+ mapToUpstream: (input) => {
4712
+ const data = input;
4713
+ return {
4714
+ method: "GET",
4715
+ path: `${MUGGLE_TEST_PREFIX}/test-plan-graph/test-cases/${data.testCaseId}/ancestors`
4716
+ };
4717
+ }
4718
+ },
4704
4719
  {
4705
4720
  name: "muggle-remote-test-case-list-by-use-case",
4706
4721
  description: "List test cases for a specific use case.",
@@ -7305,6 +7320,7 @@ __export(e2e_exports2, {
7305
7320
  SecretListInputSchema: () => SecretListInputSchema,
7306
7321
  SecretUpdateInputSchema: () => SecretUpdateInputSchema,
7307
7322
  StripePaymentMethodIdSchema: () => StripePaymentMethodIdSchema,
7323
+ TestCaseAncestorsGetInputSchema: () => TestCaseAncestorsGetInputSchema,
7308
7324
  TestCaseCreateInputSchema: () => TestCaseCreateInputSchema,
7309
7325
  TestCaseGenerateFromPromptInputSchema: () => TestCaseGenerateFromPromptInputSchema,
7310
7326
  TestCaseGetInputSchema: () => TestCaseGetInputSchema,
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { runCli } from './chunk-QUWM3JQY.js';
3
- import './chunk-TWILR37J.js';
2
+ import { runCli } from './chunk-5G7WI7IY.js';
3
+ import './chunk-YKR2TQ24.js';
4
4
 
5
5
  // src/cli/main.ts
6
6
  runCli().catch((error) => {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-QUWM3JQY.js';
2
- export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-TWILR37J.js';
1
+ export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-5G7WI7IY.js';
2
+ export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-YKR2TQ24.js';
@@ -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": "4.13.0",
4
+ "version": "4.13.1",
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": "4.13.0",
5
+ "version": "4.13.1",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,41 @@
1
+ # Test Case Chain Readiness
2
+
3
+ A test case may depend on prerequisite ("parent") test cases in the project's **test-plan graph** — e.g. "edit item" depends on "create item". Before generating or replaying the chosen test case, every ancestor in that chain must already have a ready script, or the run starts from missing state and fails for the wrong reason.
4
+
5
+ This is the **graph the backend owns** — do not infer the chain from titles or `precondition` text. Read it from `muggle-remote-test-case-ancestors-get`.
6
+
7
+ **Ready** = `muggle-remote-test-script-list` (with the ancestor's `testCaseId`) returns at least one replayable/succeeded script — the same bar Step 5 uses to offer replay.
8
+
9
+ ## Procedure
10
+
11
+ Run once the target `testCaseId` is chosen and the local URL + services are confirmed (the generation calls below need `localUrl` and `cwd`).
12
+
13
+ 1. **Resolve the chain.** `muggle-remote-test-case-ancestors-get` with the target `testCaseId`. Response: `{ testCaseId, ancestors, orphan }`.
14
+ - `orphan: true` **or** empty `ancestors` → no prerequisites. Skip the rest; continue to Step 5.
15
+ - Otherwise `ancestors` is ordered **immediate-parent → root**. Reverse it to **root-first** so prerequisites are satisfied bottom-up.
16
+
17
+ 2. **For each ancestor, root-first:**
18
+ - Check readiness via `muggle-remote-test-script-list` (`projectId`, `testCaseId` = ancestor). Ready → skip to the next ancestor.
19
+ - Not ready → **generate its script only (never replay):**
20
+ 1. `muggle-remote-test-case-get` for the ancestor.
21
+ 2. Determine `freshSession` for that ancestor from its own content — same rules as Step 6.
22
+ 3. `muggle-local-execute-test-generation` with the ancestor test case, `localUrl`, `cwd`, and a long `timeoutMs` (see Step 6's timeout guidance). Do **not** call `muggle-local-execute-replay`.
23
+ 4. `muggle-local-publish-test-script` (`runId`, `cloudTestCaseId` = ancestor) so the generated script is promoted as that ancestor's canonical replay script — it now reads as ready for any case downstream.
24
+
25
+ 3. **All ancestors ready** → continue to Step 5 for the target test case.
26
+
27
+ ## When an ancestor's generation fails
28
+
29
+ If an ancestor's generation does not reach `passed` (read it via `muggle-local-run-result-get`, never the execute stdout tail), the target's prerequisite state is missing. **Halt the chain** and surface which ancestor failed and why, then ask via `AskUserQuestion`:
30
+
31
+ - **Stop** — don't run the target; the chain is broken.
32
+ - **Proceed anyway** — run the target without the prerequisite (likely to fail; only if the user judges the state already exists).
33
+ - **Give feedback** — invoke the `muggle-feedback` skill with the failed ancestor's `runId`.
34
+
35
+ Do not silently skip a failed ancestor and run the target.
36
+
37
+ ## Notes
38
+
39
+ - The target test case is **not** in its own `ancestors` list — only its prerequisites are.
40
+ - Each ancestor is a single path to the root (one parent per node), so the reversed list has no duplicates; generate each at most once per session.
41
+ - This walks the **full** chain to root, not just the immediate parent — a grandparent without a ready script is generated before its child.
@@ -127,6 +127,12 @@ Gate `autoSelectLocalHost` per `preference-gates/README.md` + `preference-gates/
127
127
 
128
128
  Remind them: local URL is only the execution target, not tied to cloud project config.
129
129
 
130
+ ### 4a. Satisfy the test case chain (prerequisite parents)
131
+
132
+ Before deciding the target's script, resolve its prerequisite chain from the backend test-plan graph and ensure every ancestor already has a ready script — generating any that don't, **test-generation only**, root-first. Follow [`_shared/test-case-chain-readiness.md`](../_shared/test-case-chain-readiness.md).
133
+
134
+ `muggle-remote-test-case-ancestors-get` returns the chain; an `orphan` test case has no prerequisites — skip straight to Step 5. Do **not** infer parents from `precondition` text; the graph is authoritative.
135
+
130
136
  ### 5. Existing scripts vs new generation
131
137
 
132
138
  `muggle-remote-test-script-list` with `testCaseId`.
@@ -247,6 +253,7 @@ After reporting results:
247
253
  - No silent auth skip.
248
254
  - **Never prompt for Electron launch approval** before execution — invoking this skill is the approval. Just run.
249
255
  - **Never diagnose a failed run from `execute`'s response stdout tail.** Always call `muggle-local-run-result-get` first; classify only from its structured fields and (when present) the artifacts it names. The execute tail is an excerpt and routinely truncates the failure cause.
256
+ - Satisfy the prerequisite chain (Step 4a) before generating or replaying the target. Read it from `muggle-remote-test-case-ancestors-get` — never infer parents from `precondition` text. Generate any not-ready ancestor test-generation-only, root-first.
250
257
  - If replayable scripts exist, do not default to generation without user choice.
251
258
  - No hiding failures: surface errors and artifact paths.
252
259
  - **Always offer the agent-guidance reminder after every Electron run** (Step 9b) — pass or fail — unless 9a already routed the user into `muggle-feedback`. Never silently end a run without giving the user a one-click path to flag what was wrong.
@@ -1,7 +1,7 @@
1
1
  {
2
- "release": "4.13.0",
3
- "buildId": "run-43-1",
4
- "commitSha": "a3ec4b55712543c6d821193998ef49ee93ad42bb",
5
- "buildTime": "2026-05-27T22:40:42Z",
2
+ "release": "4.13.1",
3
+ "buildId": "run-44-1",
4
+ "commitSha": "2a73f80aae062cd7e19babb81f87727ccbd9aff7",
5
+ "buildTime": "2026-05-28T07:33:33Z",
6
6
  "serviceName": "muggle-ai-works-mcp"
7
7
  }
@@ -1 +1 @@
1
- export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-TWILR37J.js';
1
+ export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-YKR2TQ24.js';
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": "4.13.0",
4
+ "version": "4.13.1",
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.0.99",
44
+ "electronAppVersion": "1.0.101",
45
45
  "downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
46
46
  "runtimeTargetDefault": "production",
47
47
  "checksums": {
48
- "darwin-arm64": "6bfad4f1db8ecabdf78c73094b6c10e1554b540a964ad3a545d7f13706aaa0ec",
49
- "darwin-x64": "2f8450becd36482842afa5059254e04229533999693feed99f77e4c87d01f2b1",
50
- "linux-x64": "302fd730e2ff3ef2f1d70ffbb86f0861ea3b4b1c1fdd81887c86c5172b20d9b6",
51
- "win32-x64": "c62660fd08eed2337ead48e60ff365a785e40fe36f8695bcc342aa83b1fc267c"
48
+ "darwin-arm64": "2c73d9aa22740b6fc90f8dadccdc137c6fa87f1ce17ad5bcfd3f721b305c4807",
49
+ "darwin-x64": "dcc5e05b8382a15058c691c109af313b07f91e6470bc4a5b7f789ba82e6b7fa3",
50
+ "linux-x64": "24eeb304e5d302372984f1d2d0a15e337dcf949f7cfcd7b8c351c7d0d9d6e784",
51
+ "win32-x64": "6a391b516eaf30052f84277b90fa12393d32c1428e3f87c2f0eca241e6504a93"
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": "4.13.0",
4
+ "version": "4.13.1",
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": "4.13.0",
5
+ "version": "4.13.1",
6
6
  "author": {
7
7
  "name": "Muggle AI",
8
8
  "email": "support@muggle-ai.com"
@@ -0,0 +1,41 @@
1
+ # Test Case Chain Readiness
2
+
3
+ A test case may depend on prerequisite ("parent") test cases in the project's **test-plan graph** — e.g. "edit item" depends on "create item". Before generating or replaying the chosen test case, every ancestor in that chain must already have a ready script, or the run starts from missing state and fails for the wrong reason.
4
+
5
+ This is the **graph the backend owns** — do not infer the chain from titles or `precondition` text. Read it from `muggle-remote-test-case-ancestors-get`.
6
+
7
+ **Ready** = `muggle-remote-test-script-list` (with the ancestor's `testCaseId`) returns at least one replayable/succeeded script — the same bar Step 5 uses to offer replay.
8
+
9
+ ## Procedure
10
+
11
+ Run once the target `testCaseId` is chosen and the local URL + services are confirmed (the generation calls below need `localUrl` and `cwd`).
12
+
13
+ 1. **Resolve the chain.** `muggle-remote-test-case-ancestors-get` with the target `testCaseId`. Response: `{ testCaseId, ancestors, orphan }`.
14
+ - `orphan: true` **or** empty `ancestors` → no prerequisites. Skip the rest; continue to Step 5.
15
+ - Otherwise `ancestors` is ordered **immediate-parent → root**. Reverse it to **root-first** so prerequisites are satisfied bottom-up.
16
+
17
+ 2. **For each ancestor, root-first:**
18
+ - Check readiness via `muggle-remote-test-script-list` (`projectId`, `testCaseId` = ancestor). Ready → skip to the next ancestor.
19
+ - Not ready → **generate its script only (never replay):**
20
+ 1. `muggle-remote-test-case-get` for the ancestor.
21
+ 2. Determine `freshSession` for that ancestor from its own content — same rules as Step 6.
22
+ 3. `muggle-local-execute-test-generation` with the ancestor test case, `localUrl`, `cwd`, and a long `timeoutMs` (see Step 6's timeout guidance). Do **not** call `muggle-local-execute-replay`.
23
+ 4. `muggle-local-publish-test-script` (`runId`, `cloudTestCaseId` = ancestor) so the generated script is promoted as that ancestor's canonical replay script — it now reads as ready for any case downstream.
24
+
25
+ 3. **All ancestors ready** → continue to Step 5 for the target test case.
26
+
27
+ ## When an ancestor's generation fails
28
+
29
+ If an ancestor's generation does not reach `passed` (read it via `muggle-local-run-result-get`, never the execute stdout tail), the target's prerequisite state is missing. **Halt the chain** and surface which ancestor failed and why, then ask via `AskUserQuestion`:
30
+
31
+ - **Stop** — don't run the target; the chain is broken.
32
+ - **Proceed anyway** — run the target without the prerequisite (likely to fail; only if the user judges the state already exists).
33
+ - **Give feedback** — invoke the `muggle-feedback` skill with the failed ancestor's `runId`.
34
+
35
+ Do not silently skip a failed ancestor and run the target.
36
+
37
+ ## Notes
38
+
39
+ - The target test case is **not** in its own `ancestors` list — only its prerequisites are.
40
+ - Each ancestor is a single path to the root (one parent per node), so the reversed list has no duplicates; generate each at most once per session.
41
+ - This walks the **full** chain to root, not just the immediate parent — a grandparent without a ready script is generated before its child.
@@ -127,6 +127,12 @@ Gate `autoSelectLocalHost` per `preference-gates/README.md` + `preference-gates/
127
127
 
128
128
  Remind them: local URL is only the execution target, not tied to cloud project config.
129
129
 
130
+ ### 4a. Satisfy the test case chain (prerequisite parents)
131
+
132
+ Before deciding the target's script, resolve its prerequisite chain from the backend test-plan graph and ensure every ancestor already has a ready script — generating any that don't, **test-generation only**, root-first. Follow [`_shared/test-case-chain-readiness.md`](../_shared/test-case-chain-readiness.md).
133
+
134
+ `muggle-remote-test-case-ancestors-get` returns the chain; an `orphan` test case has no prerequisites — skip straight to Step 5. Do **not** infer parents from `precondition` text; the graph is authoritative.
135
+
130
136
  ### 5. Existing scripts vs new generation
131
137
 
132
138
  `muggle-remote-test-script-list` with `testCaseId`.
@@ -247,6 +253,7 @@ After reporting results:
247
253
  - No silent auth skip.
248
254
  - **Never prompt for Electron launch approval** before execution — invoking this skill is the approval. Just run.
249
255
  - **Never diagnose a failed run from `execute`'s response stdout tail.** Always call `muggle-local-run-result-get` first; classify only from its structured fields and (when present) the artifacts it names. The execute tail is an excerpt and routinely truncates the failure cause.
256
+ - Satisfy the prerequisite chain (Step 4a) before generating or replaying the target. Read it from `muggle-remote-test-case-ancestors-get` — never infer parents from `precondition` text. Generate any not-ready ancestor test-generation-only, root-first.
250
257
  - If replayable scripts exist, do not default to generation without user choice.
251
258
  - No hiding failures: surface errors and artifact paths.
252
259
  - **Always offer the agent-guidance reminder after every Electron run** (Step 9b) — pass or fail — unless 9a already routed the user into `muggle-feedback`. Never silently end a run without giving the user a one-click path to flag what was wrong.