@runcofactor/cli 0.13.0 → 0.15.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.
Files changed (149) hide show
  1. package/dist/account-62I7FG5G.js +255 -0
  2. package/dist/account-62I7FG5G.js.map +1 -0
  3. package/dist/{api-catalog-7HLEN7C2.js → api-catalog-CAJUASVC.js} +5 -5
  4. package/dist/{attachment-OVNQD6Z2.js → attachment-RL4AZUJE.js} +5 -5
  5. package/dist/augmentor-GAF3MFY6.js +198 -0
  6. package/dist/augmentor-GAF3MFY6.js.map +1 -0
  7. package/dist/{auth-VUHL74FH.js → auth-DURHUZDW.js} +3 -3
  8. package/dist/{chunk-YN763NWQ.js → chunk-26U3DGUM.js} +10 -4
  9. package/dist/chunk-26U3DGUM.js.map +1 -0
  10. package/dist/{chunk-JZMJUPZP.js → chunk-32P26BZT.js} +3 -3
  11. package/dist/chunk-32P26BZT.js.map +1 -0
  12. package/dist/{chunk-QQVWGWPI.js → chunk-5R4HMSNX.js} +8561 -1511
  13. package/dist/chunk-5R4HMSNX.js.map +1 -0
  14. package/dist/{chunk-VGTKUOYS.js → chunk-AQPJQ5AE.js} +2 -2
  15. package/dist/{chunk-CQE46HSM.js → chunk-CFJXYPTF.js} +14 -8
  16. package/dist/chunk-CFJXYPTF.js.map +1 -0
  17. package/dist/{chunk-NL7CVG56.js → chunk-CJEKEW7R.js} +57 -10
  18. package/dist/chunk-CJEKEW7R.js.map +1 -0
  19. package/dist/{chunk-Z5LUTUDN.js → chunk-G5SXUXSU.js} +3 -3
  20. package/dist/{chunk-ZTOE3ND3.js → chunk-HKQ5XQAQ.js} +4 -4
  21. package/dist/{chunk-PZ4LCN6K.js → chunk-IGHDIWZU.js} +2 -2
  22. package/dist/{chunk-QGI4UCJX.js → chunk-IWKJQZJQ.js} +124 -74
  23. package/dist/chunk-IWKJQZJQ.js.map +1 -0
  24. package/dist/{chunk-ZD3KHESI.js → chunk-KRWRUU6R.js} +27 -7
  25. package/dist/chunk-KRWRUU6R.js.map +1 -0
  26. package/dist/{chunk-CRHPDPRS.js → chunk-PXFDH6YL.js} +63 -8
  27. package/dist/{chunk-CRHPDPRS.js.map → chunk-PXFDH6YL.js.map} +1 -1
  28. package/dist/{chunk-EJ4U242G.js → chunk-UZ2ZA5A6.js} +2 -2
  29. package/dist/{chunk-EEN2TZUQ.js → chunk-VKBTI5EF.js} +3 -3
  30. package/dist/{chunk-ENDHMYEJ.js → chunk-ZXRVFFCY.js} +3 -3
  31. package/dist/{credential-LO2SEEHU.js → credential-JGVSEGVH.js} +5 -5
  32. package/dist/{credential-template-ZN7W7734.js → credential-template-CWWMOKB2.js} +5 -5
  33. package/dist/{debug-workflow-R3RYYAXK.js → debug-workflow-BXRU72YZ.js} +5 -5
  34. package/dist/{docs-DIAFBDXQ.js → docs-PVBXPTGR.js} +95 -11
  35. package/dist/docs-PVBXPTGR.js.map +1 -0
  36. package/dist/{doctor-NZPUSCRE.js → doctor-RHMKD4W5.js} +3 -3
  37. package/dist/{environment-RQVU4P5M.js → environment-WZKIO3R3.js} +5 -5
  38. package/dist/{feature-flag-XG26RURR.js → feature-flag-K5REGGDY.js} +98 -12
  39. package/dist/feature-flag-K5REGGDY.js.map +1 -0
  40. package/dist/index.js +107 -51
  41. package/dist/index.js.map +1 -1
  42. package/dist/{init-EDNLKGPT.js → init-FFUZO5D7.js} +5 -5
  43. package/dist/{install-FYZ3HNZK.js → install-XRKEQAFZ.js} +5 -5
  44. package/dist/{issues-NNRVTJ4L.js → issues-I3V6GEXU.js} +5 -5
  45. package/dist/{knobs-A2BOBH22.js → knobs-6WLJMB44.js} +7 -6
  46. package/dist/knobs-6WLJMB44.js.map +1 -0
  47. package/dist/{list-F33VZ4BJ.js → list-PHC7VYNS.js} +5 -5
  48. package/dist/{local-DQDTM3XA.js → local-VGYRSW22.js} +7 -7
  49. package/dist/{login-BUMVIB36.js → login-QPU2BKG2.js} +5 -5
  50. package/dist/{mcp-B5Y5CDMQ.js → mcp-LA452TOA.js} +9 -9
  51. package/dist/{mcp-B5Y5CDMQ.js.map → mcp-LA452TOA.js.map} +1 -1
  52. package/dist/{pdf-extract-ABWV3L5X.js → pdf-extract-YHE54XU4.js} +2 -2
  53. package/dist/product-RSZV5HMB.js +346 -0
  54. package/dist/product-RSZV5HMB.js.map +1 -0
  55. package/dist/{property-NJ4SRXQG.js → property-YP4GHQAR.js} +5 -5
  56. package/dist/{psql-VBZFCMNR.js → psql-XGLBI6T7.js} +3 -3
  57. package/dist/{record-WAO36O7G.js → record-KWKHP2ZY.js} +6 -6
  58. package/dist/{redis-DHZXHL4S.js → redis-VJGCUJPV.js} +3 -3
  59. package/dist/redis-VJGCUJPV.js.map +1 -0
  60. package/dist/{release-STJKUKTE.js → release-NDRHPW6V.js} +5 -5
  61. package/dist/{sandbox-DWSGLY7B.js → sandbox-OOCANWOG.js} +51 -7
  62. package/dist/sandbox-OOCANWOG.js.map +1 -0
  63. package/dist/{scenarios-HCIDY725.js → scenarios-2HRLCGFY.js} +5 -5
  64. package/dist/{session-Y5RHU54D.js → session-M4ULYDYP.js} +8 -9
  65. package/dist/session-M4ULYDYP.js.map +1 -0
  66. package/dist/{skill-23WAHUOB.js → skill-4DGPRDUC.js} +10 -10
  67. package/dist/{skill-23WAHUOB.js.map → skill-4DGPRDUC.js.map} +1 -1
  68. package/dist/skills/debug-run/SKILL.md +7 -1
  69. package/dist/skills/debug-run/history/1.3.1.md +279 -0
  70. package/dist/skills/debug-run/version.json +1 -1
  71. package/dist/skills/optimize-cache/SKILL.md +41 -4
  72. package/dist/{spec-LM5XHOQ5.js → spec-XZ2TKUFZ.js} +5 -5
  73. package/dist/{src-BGDRMOKC.js → src-2FK3JHGW.js} +315 -104
  74. package/dist/src-2FK3JHGW.js.map +1 -0
  75. package/dist/{src-NCJPUAE6.js → src-CV57ZD6I.js} +10 -8
  76. package/dist/{src-22RI5VP2.js → src-HL7HEJIW.js} +2 -2
  77. package/dist/{src-Y3K7UJEF.js → src-OU7544PM.js} +6 -4
  78. package/dist/{start-SWY55CZX.js → start-IYKF3C3X.js} +5 -5
  79. package/dist/{tag-YSU2XXPI.js → tag-T45MMSCH.js} +6 -6
  80. package/dist/{task-NLBKLD7D.js → task-MCUHAVTD.js} +5 -5
  81. package/dist/{test-suite-QCPWZ2LS.js → test-suite-BICBRSBP.js} +10 -8
  82. package/dist/{test-suite-QCPWZ2LS.js.map → test-suite-BICBRSBP.js.map} +1 -1
  83. package/dist/trace-2BAPMYAS.js +16 -0
  84. package/dist/{triage-TT4BMDBU.js → triage-M3RZ2ASB.js} +6 -6
  85. package/dist/{upgrade-6ZUFETKX.js → upgrade-4QCRAUHP.js} +3 -3
  86. package/dist/{workflow-2CX3ZNOQ.js → workflow-4J23FV7K.js} +86 -15
  87. package/dist/workflow-4J23FV7K.js.map +1 -0
  88. package/dist/{workflow-cache-GXNE6SU2.js → workflow-cache-XPSK6KC7.js} +26 -13
  89. package/dist/workflow-cache-XPSK6KC7.js.map +1 -0
  90. package/dist/{workflow-debug-PRX3DWGD.js → workflow-debug-W4USZH35.js} +9 -9
  91. package/dist/{workflow-proposals-BW327WGL.js → workflow-proposals-5E3DTYZB.js} +5 -7
  92. package/dist/workflow-proposals-5E3DTYZB.js.map +1 -0
  93. package/package.json +5 -1
  94. package/dist/chunk-CQE46HSM.js.map +0 -1
  95. package/dist/chunk-JZMJUPZP.js.map +0 -1
  96. package/dist/chunk-NL7CVG56.js.map +0 -1
  97. package/dist/chunk-QGI4UCJX.js.map +0 -1
  98. package/dist/chunk-QQVWGWPI.js.map +0 -1
  99. package/dist/chunk-YN763NWQ.js.map +0 -1
  100. package/dist/chunk-ZD3KHESI.js.map +0 -1
  101. package/dist/docs-DIAFBDXQ.js.map +0 -1
  102. package/dist/feature-flag-XG26RURR.js.map +0 -1
  103. package/dist/knobs-A2BOBH22.js.map +0 -1
  104. package/dist/redis-DHZXHL4S.js.map +0 -1
  105. package/dist/sandbox-DWSGLY7B.js.map +0 -1
  106. package/dist/session-Y5RHU54D.js.map +0 -1
  107. package/dist/src-BGDRMOKC.js.map +0 -1
  108. package/dist/trace-A3ZY6K26.js +0 -16
  109. package/dist/workflow-2CX3ZNOQ.js.map +0 -1
  110. package/dist/workflow-cache-GXNE6SU2.js.map +0 -1
  111. package/dist/workflow-proposals-BW327WGL.js.map +0 -1
  112. /package/dist/{api-catalog-7HLEN7C2.js.map → api-catalog-CAJUASVC.js.map} +0 -0
  113. /package/dist/{attachment-OVNQD6Z2.js.map → attachment-RL4AZUJE.js.map} +0 -0
  114. /package/dist/{auth-VUHL74FH.js.map → auth-DURHUZDW.js.map} +0 -0
  115. /package/dist/{chunk-VGTKUOYS.js.map → chunk-AQPJQ5AE.js.map} +0 -0
  116. /package/dist/{chunk-Z5LUTUDN.js.map → chunk-G5SXUXSU.js.map} +0 -0
  117. /package/dist/{chunk-ZTOE3ND3.js.map → chunk-HKQ5XQAQ.js.map} +0 -0
  118. /package/dist/{chunk-PZ4LCN6K.js.map → chunk-IGHDIWZU.js.map} +0 -0
  119. /package/dist/{chunk-EJ4U242G.js.map → chunk-UZ2ZA5A6.js.map} +0 -0
  120. /package/dist/{chunk-EEN2TZUQ.js.map → chunk-VKBTI5EF.js.map} +0 -0
  121. /package/dist/{chunk-ENDHMYEJ.js.map → chunk-ZXRVFFCY.js.map} +0 -0
  122. /package/dist/{credential-LO2SEEHU.js.map → credential-JGVSEGVH.js.map} +0 -0
  123. /package/dist/{credential-template-ZN7W7734.js.map → credential-template-CWWMOKB2.js.map} +0 -0
  124. /package/dist/{debug-workflow-R3RYYAXK.js.map → debug-workflow-BXRU72YZ.js.map} +0 -0
  125. /package/dist/{doctor-NZPUSCRE.js.map → doctor-RHMKD4W5.js.map} +0 -0
  126. /package/dist/{environment-RQVU4P5M.js.map → environment-WZKIO3R3.js.map} +0 -0
  127. /package/dist/{init-EDNLKGPT.js.map → init-FFUZO5D7.js.map} +0 -0
  128. /package/dist/{install-FYZ3HNZK.js.map → install-XRKEQAFZ.js.map} +0 -0
  129. /package/dist/{issues-NNRVTJ4L.js.map → issues-I3V6GEXU.js.map} +0 -0
  130. /package/dist/{list-F33VZ4BJ.js.map → list-PHC7VYNS.js.map} +0 -0
  131. /package/dist/{local-DQDTM3XA.js.map → local-VGYRSW22.js.map} +0 -0
  132. /package/dist/{login-BUMVIB36.js.map → login-QPU2BKG2.js.map} +0 -0
  133. /package/dist/{pdf-extract-ABWV3L5X.js.map → pdf-extract-YHE54XU4.js.map} +0 -0
  134. /package/dist/{property-NJ4SRXQG.js.map → property-YP4GHQAR.js.map} +0 -0
  135. /package/dist/{psql-VBZFCMNR.js.map → psql-XGLBI6T7.js.map} +0 -0
  136. /package/dist/{record-WAO36O7G.js.map → record-KWKHP2ZY.js.map} +0 -0
  137. /package/dist/{release-STJKUKTE.js.map → release-NDRHPW6V.js.map} +0 -0
  138. /package/dist/{scenarios-HCIDY725.js.map → scenarios-2HRLCGFY.js.map} +0 -0
  139. /package/dist/{spec-LM5XHOQ5.js.map → spec-XZ2TKUFZ.js.map} +0 -0
  140. /package/dist/{src-NCJPUAE6.js.map → src-CV57ZD6I.js.map} +0 -0
  141. /package/dist/{src-22RI5VP2.js.map → src-HL7HEJIW.js.map} +0 -0
  142. /package/dist/{src-Y3K7UJEF.js.map → src-OU7544PM.js.map} +0 -0
  143. /package/dist/{start-SWY55CZX.js.map → start-IYKF3C3X.js.map} +0 -0
  144. /package/dist/{tag-YSU2XXPI.js.map → tag-T45MMSCH.js.map} +0 -0
  145. /package/dist/{task-NLBKLD7D.js.map → task-MCUHAVTD.js.map} +0 -0
  146. /package/dist/{trace-A3ZY6K26.js.map → trace-2BAPMYAS.js.map} +0 -0
  147. /package/dist/{triage-TT4BMDBU.js.map → triage-M3RZ2ASB.js.map} +0 -0
  148. /package/dist/{upgrade-6ZUFETKX.js.map → upgrade-4QCRAUHP.js.map} +0 -0
  149. /package/dist/{workflow-debug-PRX3DWGD.js.map → workflow-debug-W4USZH35.js.map} +0 -0
@@ -0,0 +1,279 @@
1
+ ---
2
+ name: debug-run
3
+ description: Root-cause a Canary workflow run end-to-end. Materializes the run's diagnostic workspace and explores it with Read (multimodal), Bash, Grep, and Glob. Use when the user asks "why did this run fail/hang/take so long", references a runId, pastes a flows/?runId=... URL, or asks "what changed since it last passed".
4
+ allowed-tools: Read, Grep, Glob, Bash(canary workflow debug:*), Bash(canary workflow runs:*), Bash(jq:*), Bash(diff:*), Bash(sed -n:*), Bash(head:*), Bash(tail:*), Bash(wc:*), Bash(grep:*), Bash(find:*), Bash(ls:*), Bash(cat:*)
5
+ ---
6
+
7
+ <!-- AUTOGENERATED from packages/diagnostic-playbook/. Do not edit by hand. -->
8
+ <!-- After editing the partials, mint a new version: -->
9
+ <!-- bun run --filter=@canaryai/cli bump-skill debug-run [patch|minor|major] -->
10
+
11
+ # Workflow Run Debug Guide
12
+
13
+ You are debugging a Canary workflow run end-to-end. The same diagnostic data the v2 failure-diagnostic agent uses is available to you here — materialize it once, then explore.
14
+
15
+ ## Materialize the workspace
16
+
17
+ ```bash
18
+ canary workflow debug materialize <runId> --out ./diag-<runId>/
19
+ ```
20
+
21
+ This produces a structured workspace on disk. After it completes, all subsequent navigation uses Read/Bash/Grep against that directory. The workspace is the **single source of truth** — the v2 agent and you read the exact same files.
22
+
23
+ If you don't have a workflowId, list runs first:
24
+ ```bash
25
+ canary workflow runs list <workflowId>
26
+ ```
27
+
28
+ ## Your job
29
+
30
+ You are a senior QA engineer diagnosing why an end-to-end workflow test failed for a QA tester who has to **fix the test**. The reported failure is a **hypothesis**. Your job is to verify it with evidence and produce a tight, scannable report — see the output rubric.
31
+
32
+ The QA tester reads your `title` first, then `recommendation`. Make those two land. Everything else is supporting detail.
33
+
34
+ ## Failure categories — pick exactly one
35
+
36
+ - `software_bug` — defect in the application under test (4xx/5xx from app APIs, JS exceptions, broken UI, a behavior delta that is clearly broken)
37
+ - `dependency_issue` — required data, fixture, or external service was missing for the test
38
+ - `agent_confusion` — the AI test agent reasoned incorrectly, picked the wrong element, or got confused
39
+ - `platform_error` — defect in our test runner, harness, sandbox, or recording infrastructure
40
+ - `test_underspecified` — the test instructions themselves are wrong or ambiguous. **Only valid with positive evidence that the authored test changed or is genuinely ambiguous** (e.g. the History section reports AUTHORED TEST CHANGED, or two runs with the same instructions reasonably diverged). **Never** classify `test_underspecified` when the authored test is unchanged across a pass→fail boundary — an unchanged test that used to pass is not a test problem.
41
+ - `app_changed` — the application's behavior, labels, copy, or flow changed versus the last passing run **while the authored test stayed the same**, and you cannot verify from inside the sandbox whether the change was intentional. This is the correct verdict for an unchanged test that breaks because the app moved underneath it (e.g. a button relabeled "Login" → "Acting As"). Name the concrete delta and recommend "X appears to have changed to Y; update the test to match if intentional." Reserve `software_bug` for deltas that are clearly defects (error page, 5xx, broken layout); use `app_changed` when the new behavior looks deliberate or you simply cannot tell. **An `app_changed` verdict must be earned by the green-run comparison** (see compare-to-history): confirm the delta in both runs' evidence, never infer it from the pass→fail boundary alone. If the green baseline passed via cache replay while the failing run improvised a different live verification, that is verification drift (`agent_confusion`), not an app change.
42
+ - `data_collision` — the workflow interacted with the **wrong data**: a leftover org from a prior session, a duplicated row, a record from another run, the wrong tenant, etc. The point of diagnosis is *why the workflow drifted onto wrong data* — stale cached recipe pointing at the wrong DOM node, locator matching multiple elements, variable bound to an earlier session/org, agent fallback choosing the first match. **Do not** investigate the provenance of the colliding data.
43
+
44
+ Never mark `agent_confusion` or `platform_error` from a failed assertion alone. Look at multiple evidence sources first.
45
+
46
+ ## Output discipline (hard rules)
47
+
48
+ - **Never** mention internal artifact paths in any user-visible field. Banned substrings in `title`, `failurePoints`, `recommendation`, `evidence.description`, `evidence.detail`, `openQuestions`, `comparisonWithHistory`: `steps/`, `workflow/nodes/`, `logs/`, `thoughts/`, `history/last-green`, `history/runs/`, `browser/frames/`, `the ledger`, `the workspace`, `<stepId>`, `<nodeId>`. Speak in domain terms: "the authored step description", "the network log", "the agent thought at step 4", "the last-passing run on YYYY-MM-DD".
49
+ - **No section headings** inside `failurePoints` or `recommendation`. They are flat bullet lists.
50
+ - **No narrative paragraphs.** If you find yourself writing "Then…", "After that…", "Subsequently…" — collapse to a bullet.
51
+
52
+
53
+ ## Workspace layout
54
+
55
+ Your diagnostic workspace is at `{{workspacePath}}`. Everything you need is here. Read in three tiers:
56
+
57
+ **Tier 1 — always read first:**
58
+ - `summary.md` — run-level overview, step table, error counts, notable events, history hint, and pointers to the right rollup files
59
+ - `reported-failure.md` — the test runner's hypothesis (verify, do not trust)
60
+
61
+ **Tier 2 — drill-down per step:**
62
+ - `steps/<NNN>-<stepId>.md` — per-step rollup (timing, status, error, thoughts, in-window network/console events, navigation, assertions, artifact paths). Read the failed step's rollup first, then walk backwards.
63
+
64
+ **Tier 3 — windowed reads only:**
65
+ - `ledger.md` — full chronological narrative. **Do not read whole.** Open `ledger-index.md` first for the step→line-range mapping, then `bash("sed -n '<a>,<b>p' ledger.md")`.
66
+
67
+ ## Other artifacts
68
+
69
+ - `browser/frames/<NNNN>-<absoluteTsMs>.png` — screenshots per browser action. Read with `read_file`; the model sees them as vision input.
70
+ - `browser/doms/<NNNN>-<absoluteTsMs>.html` — composed self-contained HTML per action.
71
+ - `browser/a11y/<NNNN>-<absoluteTsMs>.yaml` — what the agent's accessibility view looked like.
72
+ - `browser/actions.jsonl` — parsed Playwright actions with timestamps. Use `jq` to filter.
73
+ - `browser/trace.zip` — raw Playwright trace (escape hatch).
74
+ - `workflow/nodes/<nodeId>.json` — full configJson per workflow node. Quote `actionDescription`, `inlineAssertions` from here.
75
+ - `workflow/snapshot.json` — full workflow snapshot the run executed.
76
+ - `thoughts/all.jsonl` — every agent thought with stepId, timestamp, content. Use `jq` to filter.
77
+ - `thoughts/by-step/<stepId>.md` — readable per-step thoughts.
78
+ - `timeline/{steps,actions,navigation,assertions,cache-decisions}.jsonl` — structured event streams.
79
+ - `logs/network.jsonl`, `logs/network-errors.jsonl` — network requests; errors are pre-filtered.
80
+ - `logs/console.jsonl`, `logs/console-errors.jsonl` — console logs; errors+warnings are pre-filtered.
81
+ - `logs/sentry-logs.jsonl`, `logs/sentry-spans.jsonl` — Sentry telemetry. May contain a `partial: true` first line if the Sentry token wasn't available.
82
+ - `variables/inputs.json`, `variables/lineage.jsonl` — run inputs + per-step variable captures.
83
+ - `history/recent-runs.jsonl` — last ~20 runs with status. Useful for picking a green run to compare.
84
+ - `history/runs/<runId>/` — comparison workspaces created by the `materialize_run` tool (in-process sandbox).
85
+ - `history/last-green/` — populated only if you materialize a prior passing run for comparison via the CLI command.
86
+ - `notes/` — your working memory. Write here with `write_file` (only the workspace, no path escapes).
87
+
88
+
89
+ ## Investigation procedure (Claude Code edition)
90
+
91
+ Follow this in order. Adapt the v2 agent's procedure to use Claude Code's built-in tools.
92
+
93
+ 1. **Anchor at the reported failure.** `Read summary.md` first — it has the run-level overview, the failed step's ordinal, the file path of the failed step's rollup, and the history hint. Treat the reported failure as a hypothesis, not a fact.
94
+ 2. **Verify with evidence — including visual evidence.** `Read steps/<NNN>-<failedStepId>.md` for the failure context. Read the screenshot file referenced there (`browser/frames/<NNNN>-...png`) — `Read` is multimodal, vision describes what's on screen. Look for unexpected modals, banners, blank areas, wrong brand, layout shifts. Cross-reference network errors and console errors in the rollup.
95
+ 3. **Walk backwards.** The reported failure is rarely the divergence point. Read the prior step's rollup (`steps/<NNN-1>-...md`), look at its screenshot, and ask: did this step actually accomplish its goal? Repeat going backwards until you find a step where the actual outcome diverged from the intended outcome.
96
+ 4. **Compare to history.** If `summary.md`'s history section shows recent passes, the most recent green run's testRunId and materialize command appear there. Run that command, then visually compare the suspect step's screenshot in both runs.
97
+ 5. **Present clear evidence.** Your write-up cites specific artifacts (file paths, timestamps, screenshot indices, network entries). When visual comparison is decisive, name both screenshot paths.
98
+
99
+ ## Important
100
+
101
+ - Never `Read ledger.md` without a specific window — open `ledger-index.md` first to find the line range, then `Bash sed -n '<a>,<b>p' ledger.md`.
102
+ - The workspace is the canonical data layer. If you can't answer a question from the workspace, that's a signal the materializer is missing a domain — file a follow-up rather than reaching for psql/sentry CLI directly.
103
+
104
+ ## Verifying the reported failure
105
+
106
+ The failure report (in `reported-failure.md` and the top of `summary.md`) is the **runner's hypothesis** about what failed. It is wrong often enough that you must always verify before forming a diagnosis.
107
+
108
+ Things that look like a step-3 failure but are really upstream:
109
+ - The agent on step 1 picked the wrong "Sign in" link, ended up on the consumer site instead of the staging site, and the failure surfaces as `AuthenticationError` two steps later.
110
+ - A cache-replay on step 2 used a stale selector that matched a hidden element; the step "succeeded" but didn't actually click anything; step 3 fails because the modal never opened.
111
+ - The runner timed out a step but the page actually loaded fine — the timeout is a platform issue, not the app's fault.
112
+
113
+ Always cross-reference at least three sources before forming a hypothesis:
114
+ 1. The screenshot at the failure timestamp (`browser/frames/...`)
115
+ 2. The agent's thoughts during the failed step (`thoughts/by-step/<stepId>.md`)
116
+ 3. Either the network errors (`logs/network-errors.jsonl`) OR the console errors (`logs/console-errors.jsonl`) within ±2s of the failure timestamp
117
+
118
+ If the screenshot, thoughts, and logs all paint the same picture, the reported failure is probably accurate. If any one disagrees, walk backwards (see procedure step 3).
119
+
120
+
121
+ ## Walking backwards
122
+
123
+ The visible failure is rarely the actual divergence. Common patterns:
124
+
125
+ - A `click` succeeded 3 steps ago but landed on the *wrong* element — the cache-replay layer hid the mismatch — and the failure surfaces only when the next required field can't be found.
126
+ - A cross-host navigation between two earlier steps invalidated the auth session, and the 401 doesn't appear until the next API call.
127
+ - A variable was captured from the wrong DOM element on step N, and step N+5 now has a meaningless `$var.X` value.
128
+ - The agent went down a wrong branch on a conditional, and the test ran a different path than intended.
129
+ - A prior step showed a validation banner or issue toast, but the workflow continued; the later step fails because the page never becomes ready.
130
+ - A non-blocking assertion or warning already proved a prerequisite was missing; a later action reports the same missing state as a blocking failure.
131
+ - A warning says an expected run, save, import, sync, or publish did not complete; the downstream failure is just the consequence of that missing prerequisite.
132
+
133
+ Walk-backwards algorithm:
134
+
135
+ 1. `read_file` `steps/<NNN-1>-<prevStepId>.md` for the step immediately before the failure.
136
+ 2. `read_file` its screenshot (`browser/frames/<NNNN>-...png`). **Look at it.** Did the step actually accomplish its goal?
137
+ 3. Compare to the instruction by `read_file` on `workflow/nodes/<nodeId>.json` — does the screenshot match the intent of `actionDescription` and `inlineAssertions`?
138
+ 4. Skim the rollup's "Agent thoughts" section. Was the agent confused? Did it pick the wrong element?
139
+ 5. Skim the rollup's "Navigation" section. A cross-host transition (⚠ marker) is a strong signal that auth state was lost between this step and the next.
140
+ 6. Check whether the step has warnings, non-blocking failures, cache fallback, validation banners, issue toasts, or visible error badges. Treat these as root-cause candidates even if the step status is `success`.
141
+ 7. If everything looks normal here, repeat with `steps/<NNN-2>-...md`, `<NNN-3>`, and so on.
142
+
143
+ Stop when you find a step where the actual outcome diverged from the intended outcome. That is your root-cause candidate. Cite that step's screenshot and the diverging detail in your `actuallyHappened` narration.
144
+
145
+ If the reported failure says a later state was not established, your final answer must name the earlier step that should have established it and the concrete evidence showing why it did not.
146
+
147
+
148
+ ## Visual evidence — when to read frames
149
+
150
+ A large fraction of diagnoses turn on what the page actually *looked like* at a given moment. Text alone cannot tell you:
151
+ - Whether an unexpected modal/banner is blocking the click target
152
+ - Whether the layout shifted such that the agent's selector resolved to a different element
153
+ - Whether the brand on screen matches what the test expected (cross-host redirects often land on a sibling brand)
154
+ - Whether a stale cached fragment is being shown
155
+ - Whether a button is disabled, missing, or moved
156
+
157
+ How to use vision:
158
+
159
+ - Use `read_file` on `browser/frames/<NNNN>-<absoluteTsMs>.png`. The file extension triggers multimodal output — the model receives the image as vision input on the same turn.
160
+ - For run-vs-run comparison, read the frame at the same step in `history/last-green/browser/frames/<NNNN>-...png` and the failing run's frame in adjacent `read_file` calls. Reason about the visual delta directly.
161
+ - When visual evidence is decisive, include a `before_after` entry in your `evidence[]` with the two image paths.
162
+
163
+ Do not use `bash` to view images — `read_file` is the only tool that returns vision content.
164
+
165
+
166
+ ## Comparing to a passing run — the green→red methodology
167
+
168
+ If `summary.md`'s history section names a recent green run, comparison is **required** — it is the highest-yield step for a pass→fail regression. A green→red boundary with an unchanged test eliminates only test-authoring causes. FOUR hypotheses stay live until the comparison discriminates between them: a legitimate app change (`app_changed`), an app regression (`software_bug`), an agent error (`agent_confusion`), and a platform error (`platform_error`). Never default to one of them — earn the verdict with evidence.
169
+
170
+ Procedure:
171
+
172
+ 1. **Materialize the green baseline.** `summary.md`'s "History" section names the green run and the exact mechanism for this workspace:
173
+ - In the in-process sandbox: call the `materialize_run` tool with the green run's id. The result names the comparison workspace path (`history/runs/<greenRunId>/`).
174
+ - In a CLI-materialized workspace: run the printed `canary workflow debug materialize <greenRunId> --out history/last-green/` command via `bash`.
175
+ Follow whichever instruction `summary.md` prints. `<green>` below means the comparison workspace path.
176
+ 2. **Establish execution mode on BOTH sides of the boundary — before any visual comparison.** Read each workspace's `timeline/cache-decisions.jsonl` and `thoughts/all.jsonl`. A cache-replayed run has few or no agent thoughts (it replayed recorded actions); a live-agent run has many. The mode pairing changes which hypotheses are plausible:
177
+ - **Green replayed, red fell to live agent** → the red run executed a *different procedure* than every green before it. Compare the recorded recipe's verification with what the live agent improvised — a verification-method mismatch points to `agent_confusion` (drift), and the cache miss/uncertainty itself may point to `platform_error`. Do NOT classify `app_changed` from a replay-vs-live pair without an independent, concrete app-behavior delta visible in both runs' frames.
178
+ - **Both live-agent** → thoughts diff cleanly; interpretation drift vs. a genuine page delta is directly observable.
179
+ - **Green replayed, red replay-failed** → suspect `platform_error` (replay machinery) or a genuine app change that broke the recorded selectors; the frames decide.
180
+ 3. **Visual comparison.** `read_file` the suspect step's screenshot in both runs:
181
+ - `browser/frames/<NNNN>-...png` — failing
182
+ - `<green>/browser/frames/<NNNN>-...png` — passing
183
+ The visual delta is often the smoking gun. Same screens → the app did not change; weigh the agent/platform hypotheses. (If the green workspace has no frames — no trace — fall back to thoughts and node-config diffs.)
184
+ 4. **Diff thoughts and node configs:**
185
+ - `bash diff thoughts/by-step/<stepId>.md <green>/thoughts/by-step/<stepId>.md`
186
+ - `bash diff workflow/snapshot.json <green>/workflow/snapshot.json | head -100`
187
+
188
+ Common signals from comparison:
189
+
190
+ - Identical authored workflow + visual/label delta **confirmed in both runs' frames** = **app changed**. Classify `app_changed` (intent unverifiable) unless the delta is clearly a defect (error page, 5xx, broken layout), in which case `software_bug`.
191
+ - Different workflow snapshot = **test changed** (possibly `test_underspecified` if the new instructions are ambiguous).
192
+ - Same screenshot but different thoughts = **agent interpretation drift** (`agent_confusion`, or `test_underspecified` if the test allowed the prior interpretation).
193
+ - Same everything but new network 5xx = **dependency/backend issue** (likely `software_bug` or `dependency_issue`).
194
+ - Green passed by cache replay while red improvised live = **verification drift**, not an app change — see step 2.
195
+
196
+ ## When comparison is unavailable
197
+
198
+ If the comparison workspace cannot be produced (the materialize tool/command fails), you have NOT performed the required comparison. Do not pick `app_changed` at high confidence on the regime steer alone — keep the live hypotheses in your writeup, record an explicit openQuestion that the green baseline could not be materialized for comparison, and cap your confidence accordingly.
199
+
200
+ ## The regime gates your verdict
201
+
202
+ `summary.md`'s History section reports a **Regime** and, when available, an **AUTHORED TEST UNCHANGED / CHANGED** line computed from a content fingerprint of the authored definition. Do not overrotate on a bare "last run green, this run red" — gate the conclusion on the regime:
203
+
204
+ - **`STABLE_REGRESSION` + AUTHORED TEST UNCHANGED** → the test did not change across the pass→fail boundary, so `test_underspecified` is **off the table** — but that alone does NOT pick a verdict. Run the methodology above to discriminate between `app_changed`, `software_bug`, `agent_confusion`, and `platform_error`. Only classify `app_changed` after confirming a concrete behavior delta against the green workspace; name the delta and record in `openQuestions` that you could not verify whether the change was intentional.
205
+ - **`STABLE_REGRESSION` + AUTHORED TEST CHANGED** → the test was edited; judge whether the new instructions are ambiguous (`test_underspecified`) before blaming the app.
206
+ - **`FLAKY`** → a single green→red does **NOT** justify `app_changed`. The test oscillates; weigh `agent_confusion`, intermittent `dependency_issue`, and `data_collision`. Comparison still helps, but only conclude `app_changed` with a **clear, persistent** behavior delta — never a one-off.
207
+ - **`NEW` / `PERSISTENT_FAIL`** → no stable green baseline; rely on the within-run procedure (verify + walk backwards).
208
+
209
+
210
+ ## Standing rules
211
+
212
+ ## Standing rule: auth errors after a cross-host transition
213
+
214
+ If the failure looks like a credential or session issue (401/403, "session expired", login redirect, "please sign in"), **first reconstruct the URL timeline around the failure**.
215
+
216
+ 1. Read the failed step's rollup (`steps/<NNN>-<stepId>.md`) — the "Navigation (in step window)" section lists URL transitions and marks cross-host transitions with `⚠ cross-host`.
217
+ 2. Skim the prior step's navigation as well — the cross-host hop often happens between steps.
218
+ 3. Compare host names case-insensitively, stripping a leading `www.`. So `staging.example.com` → `www.example.com` is a cross-host change; `www.example.com` ↔ `example.com` is not.
219
+
220
+ **If the hostname changed between two entries shortly before the auth failure, the test navigated off its authenticated origin. That is the root cause, not stale credentials.** Do not classify as `dependency_issue` (credentials problem) without ruling out cross-host.
221
+
222
+ Auth errors after a cross-host transition are almost never credential issues.
223
+
224
+
225
+ ## Standing rule: workflow variables and macros
226
+
227
+ Workflow steps can use **macros** and **variable references** in their configuration:
228
+
229
+ - **Macros** (generate values at runtime): `$MACRO_NAME(args)` — e.g. `$EMAIL()`, `$UUID()`, `$RANDOM_STRING(10)`. Used in `inputValues` on action nodes; resolved fresh each run.
230
+ - **Variable references** (reference values from earlier steps): `$var.variable_name`. Variables are created when a step's `inputValues` are resolved. **A variable defined in step N is NOT available within step N itself** — only in step N+1 and later. This is because variables are registered after the step's inputs are resolved.
231
+
232
+ Common variable-related failures:
233
+ - A step references `$var.X` where X is defined in that same step (will be unresolved → blank value used).
234
+ - A step references `$var.X` where X was defined in a step that was skipped or failed earlier.
235
+ - Misspelled variable names (e.g. `$var.client_name` vs `$var.clientName`).
236
+ - An `inputValue` was set without a matching `dataRequirements` entry — only inputs with a dataRequirement become variables.
237
+
238
+ When suggesting test instruction changes:
239
+ - Use `read_file` on `workflow/nodes/<nodeId>.json` to see the full configJson before proposing a `configPatch`.
240
+ - Preserve any existing `$var.` references and `$MACRO()` calls — don't break them.
241
+ - For array fields like `inlineAssertions` or `playbookSteps`, the `configPatch` must be a **full replacement array**, not a partial — read the existing array first and include the merged result.
242
+
243
+
244
+ ## Standing rule: assertion severity and step/run status
245
+
246
+ Assertion severity drives what a failure means — `fatal` halts the run at the failing step, `fail` marks the step (and ultimately the run) failed but execution continues, `warn` records a warning and the run still passes. Because `fail` and `warn` are non-blocking, later steps run normally after an assertion failure. Assertion records carry a `nonBlocking` flag reflecting how each was treated at run time.
247
+
248
+ When investigating:
249
+
250
+ - Open the step's rollup (`steps/<NNN>-<stepId>.md`) and look at the "Assertions" section. Each line shows `passed`/`FAILED`, severity, and a `nonBlocking` marker. Entries marked not-checked (`checked: false`) were configured on the node but never evaluated — the step broke before assertions ran; do not read them as failures.
251
+ - **Do not treat "failed assertion + completed step" on its own as evidence of `platform_error` or contradictory state.** For `warn`/`fail` severities (`nonBlocking` true), that combination is expected and carries no signal about the actual cause.
252
+ - A non-blocking failed assertion does not tell you which category applies. It only rules out one specific false-positive narrative (`platform_error` / bookkeeping). Continue investigating from network, console, thoughts, visual, and history. The actual cause may be any of `software_bug`, `dependency_issue`, `agent_confusion`, `test_underspecified`, or `platform_error`.
253
+
254
+ When `platform_error` is still a live possibility:
255
+
256
+ - A failed `fatal`-severity assertion (`nonBlocking: false`) alongside a step recorded as completed successfully. That is a genuine disagreement worth flagging.
257
+ - Infrastructure-level failures (browser session died, worker crash, our own stack traces) independent of any assertion outcome.
258
+
259
+ Always consult the assertions section of the rollup before writing a bookkeeping-bug narrative.
260
+
261
+
262
+ ## Reporting
263
+
264
+ The QA tester reading your report sees, by default, only the `title`, `Key Evidence`, and `Recommendation`. Everything else is twirl-down. Optimise for that.
265
+
266
+ - `title` — one sentence, concrete and specific. The thesis.
267
+ - `failurePoints` — 2–4 bullets describing the failure; quote the authored expectation inline only when it sharpens the point.
268
+ - `recommendation` — 1–3 imperative bullets matched to the failure category:
269
+ - `software_bug` → name the app defect; the underlying error is quoted in an evidence item
270
+ - `dependency_issue` → name the missing data/fixture/credential and where to provision
271
+ - `agent_confusion` → quote the confused thought, point at visual evidence the agent missed, suggest test-instruction tweaks
272
+ - `platform_error` → describe the harness failure, suggest filing a platform issue
273
+ - `test_underspecified` → quote the ambiguous instruction; provide a clearer rewording
274
+ - `data_collision` → explain *why* the workflow drifted onto wrong data (stale cached recipe, ambiguous locator, stale variable binding); propose a recipe/locator/variable fix only when confidence is ≥80
275
+ - `openQuestions` (optional) — what you couldn't determine. Skip if you have full conviction.
276
+
277
+ Never reference internal artifact paths (`steps/…`, `workflow/nodes/…`, `logs/…`, `thoughts/…`, `history/…`, `browser/frames/…`, "the ledger", "the workspace") in any field the QA tester sees. Speak in domain terms: "the authored step description", "the network log", "the agent thought at step 4".
278
+
279
+ Don't hand back "the run failed" or a Sentry error message alone. The whole point is to triangulate to a concrete cause.
@@ -1,3 +1,3 @@
1
1
  {
2
- "current": "1.3.0"
2
+ "current": "1.3.1"
3
3
  }
@@ -12,7 +12,7 @@ allowed-tools: Read, Grep, Glob, Bash(canary workflow debug:*), Bash(canary work
12
12
 
13
13
  You are building the deterministic cache + playbook for a workflow from the
14
14
  evidence of a real run — the same procedure the server's async cache-optimizer
15
- agent follows, driven manually through the canary CLI.
15
+ agent follows, driven manually through the `canary` CLI.
16
16
 
17
17
  ## Materialize the workspace
18
18
 
@@ -53,8 +53,15 @@ thoughts, and the run's variable/macro records. Work methodically:
53
53
  2. **Pick harvestable nodes.** Only nodes whose step SUCCEEDED are
54
54
  harvestable. A node that succeeded in a run that later failed is still
55
55
  valid — often the most valuable, since that run won't be green soon.
56
- Cache-replayed nodes (their trace actions sit under a `Cache Replay:`
57
- group) carry nothing new — skip them.
56
+ Where a harvestable node's actions live depends on how it executed:
57
+ - Agent-executed (cache miss/fallback): under its `Step N:` trace group.
58
+ - Replayed WITH healing (`l2_gap` / `recovery`): under its
59
+ `Cache Replay N:` group — replayed actions and the healing agent's live
60
+ actions are recorded together there, and ALL of them are evidence of the
61
+ proven path. Harvest these exactly like agent steps.
62
+ `optimizer/segments.json` resolves each segment to its `nodeId`; trust it.
63
+ A CLEANLY replayed node (its step needed no healing) carries nothing new —
64
+ skip it.
58
65
  3. **Per node, reconstruct the true path.** Cross-reference the node's trace
59
66
  actions with the agent's tool calls and thoughts. Identify what actually
60
67
  accomplished the task versus exploration.
@@ -78,6 +85,11 @@ gap. Core actions are:
78
85
  - **Captures**: values the agent saved for downstream steps (e.g.
79
86
  `browser_evaluate` with `saveAs`). These become context extractors on the
80
87
  cache row — `declaredOutputs` stay reserved for DOM-captured values.
88
+ You may author a new capture when the run evidence shows the app generated
89
+ a value that later cacheable work depends on, even if the live agent did not
90
+ capture it. The capture expression must read visible DOM or the current URL,
91
+ return a single string, and save the key used by later `$var.key` /
92
+ `{{var.key}}` references.
81
93
  - **Non-browser effects**: reading email/inbox, running python, reading or
82
94
  verifying downloads. These are invisible in the browser trace — source them
83
95
  from the agent's tool-call records and thoughts. They become playbook steps
@@ -110,9 +122,28 @@ future runs work with fresh data:
110
122
  re-resolves selector text from run state. When a locator can only be
111
123
  disambiguated by a run-specific value, bind it to the variable that
112
124
  produced the value — never anchor on the literal.
125
+ - **App-generated values the live agent missed** are still recoverable here.
126
+ If the app creates a value during this run (receipt number, confirmation
127
+ code, generated entity ID, auto-derived title or name, URL slug) and a
128
+ later locator, assertion, or download check depends on it, call
129
+ `declare_dynamic_variable` with the observed value before building
130
+ locators. Then add a cached `capture` action that saves the same key before
131
+ the first dependent cached action, and use `$var.key` / `{{var.key}}` where
132
+ the generated value appears later.
133
+ Constants chosen by the workflow (names, dates, dropdown options, payment
134
+ types) do not need this treatment unless they are app-generated.
135
+ This is a REQUIREMENT, not a suggestion: once you suspect a distinguishing
136
+ value is app-generated (you saw the app derive it, the workflow never typed
137
+ it, or it differs from what an earlier step entered), you may NOT anchor on
138
+ the literal and you may NOT silently gap the step. Find the value on-path
139
+ (a heading, breadcrumb, row cell, or the URL of a page the step already
140
+ visits), capture it, and bind the locator to the capture. Gap only when no
141
+ on-path capture source exists — and say so in the gap reason.
113
142
  - **Gaps** are honest: a `gap` compiled entry means "the replay agent performs
114
143
  this step live". A gap replays slower but correctly; a bad cached locator
115
- replays fast and wrong. Prefer the gap.
144
+ replays fast and wrong. Prefer the gap — except where the only obstacle is
145
+ an app-generated value with a visible capture source (see above): there the
146
+ capture-bound locator is the correct outcome, not a gap.
116
147
  - **Volatile identifiers** (seeded entity numbers, ULIDs/UUIDs, timestamps,
117
148
  framework-generated class hashes) WILL differ next run even though they
118
149
  point at a real element today. Structural prefixes (e.g. a stable
@@ -181,6 +212,12 @@ UNVERIFIED locator must never be committed.
181
212
  recipe depended on must survive into the new recipe (as a token, a variable
182
213
  binding, or a macro binding). The commit validates this and rejects recipes
183
214
  that inline run-specific values.
215
+ - **Declared dynamic variables must be captured.** If you call
216
+ `declare_dynamic_variable` and later use that key in a locator, assertion,
217
+ playbook param, or action arg, the committed recipe must include a cached
218
+ `capture` action whose `args.saveAs` is the same key. Put the capture before
219
+ the first mutation or verification that requires the value; otherwise replay
220
+ will fail before it can hydrate the selector.
184
221
  - The node hash is recomputed server-side from the node context with your
185
222
  playbook applied; the next run computes the same hash and replays your
186
223
  recipe. You never supply a hash.
@@ -12,7 +12,7 @@ import {
12
12
  workflowToSpec,
13
13
  writeNodeIds,
14
14
  writeWorkflowId
15
- } from "./chunk-YN763NWQ.js";
15
+ } from "./chunk-26U3DGUM.js";
16
16
  import {
17
17
  fetchOrExit
18
18
  } from "./chunk-3CZU7XCS.js";
@@ -20,15 +20,15 @@ import {
20
20
  getArgValue,
21
21
  hasFlag,
22
22
  resolveAppUrl
23
- } from "./chunk-PZ4LCN6K.js";
23
+ } from "./chunk-IGHDIWZU.js";
24
24
  import {
25
25
  isSpecFile,
26
26
  readableSpecDirs,
27
27
  specDir,
28
28
  specExtension,
29
29
  splitSpecExtension
30
- } from "./chunk-JZMJUPZP.js";
31
- import "./chunk-QGI4UCJX.js";
30
+ } from "./chunk-32P26BZT.js";
31
+ import "./chunk-IWKJQZJQ.js";
32
32
  import "./chunk-VKVL7WBN.js";
33
33
 
34
34
  // src/spec/index.ts
@@ -977,4 +977,4 @@ export {
977
977
  stampedSpecPath,
978
978
  uniqueName
979
979
  };
980
- //# sourceMappingURL=spec-LM5XHOQ5.js.map
980
+ //# sourceMappingURL=spec-XZ2TKUFZ.js.map