@sun-asterisk/sungen 2.7.0-beta.0 → 3.0.0-beta.71

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 (256) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/commands/add.js +3 -3
  3. package/dist/cli/commands/add.js.map +1 -1
  4. package/dist/cli/commands/audit.d.ts +3 -0
  5. package/dist/cli/commands/audit.d.ts.map +1 -0
  6. package/dist/cli/commands/audit.js +134 -0
  7. package/dist/cli/commands/audit.js.map +1 -0
  8. package/dist/cli/commands/blindspot.d.ts +3 -0
  9. package/dist/cli/commands/blindspot.d.ts.map +1 -0
  10. package/dist/cli/commands/blindspot.js +58 -0
  11. package/dist/cli/commands/blindspot.js.map +1 -0
  12. package/dist/cli/commands/challenge.d.ts +3 -0
  13. package/dist/cli/commands/challenge.d.ts.map +1 -0
  14. package/dist/cli/commands/challenge.js +102 -0
  15. package/dist/cli/commands/challenge.js.map +1 -0
  16. package/dist/cli/commands/feedback.d.ts +3 -0
  17. package/dist/cli/commands/feedback.d.ts.map +1 -0
  18. package/dist/cli/commands/feedback.js +72 -0
  19. package/dist/cli/commands/feedback.js.map +1 -0
  20. package/dist/cli/commands/generate.d.ts.map +1 -1
  21. package/dist/cli/commands/generate.js +22 -0
  22. package/dist/cli/commands/generate.js.map +1 -1
  23. package/dist/cli/commands/ledger.d.ts +3 -0
  24. package/dist/cli/commands/ledger.d.ts.map +1 -0
  25. package/dist/cli/commands/ledger.js +71 -0
  26. package/dist/cli/commands/ledger.js.map +1 -0
  27. package/dist/cli/commands/manifest.d.ts +3 -0
  28. package/dist/cli/commands/manifest.d.ts.map +1 -0
  29. package/dist/cli/commands/manifest.js +101 -0
  30. package/dist/cli/commands/manifest.js.map +1 -0
  31. package/dist/cli/commands/script-check.d.ts +3 -0
  32. package/dist/cli/commands/script-check.d.ts.map +1 -0
  33. package/dist/cli/commands/script-check.js +97 -0
  34. package/dist/cli/commands/script-check.js.map +1 -0
  35. package/dist/cli/commands/trace.d.ts +3 -0
  36. package/dist/cli/commands/trace.d.ts.map +1 -0
  37. package/dist/cli/commands/trace.js +110 -0
  38. package/dist/cli/commands/trace.js.map +1 -0
  39. package/dist/cli/commands/update.d.ts.map +1 -1
  40. package/dist/cli/commands/update.js +22 -9
  41. package/dist/cli/commands/update.js.map +1 -1
  42. package/dist/cli/index.js +16 -0
  43. package/dist/cli/index.js.map +1 -1
  44. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/capture-variable.hbs +1 -0
  45. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +7 -0
  46. package/dist/generators/test-generator/patterns/capture-patterns.d.ts +16 -0
  47. package/dist/generators/test-generator/patterns/capture-patterns.d.ts.map +1 -0
  48. package/dist/generators/test-generator/patterns/capture-patterns.js +54 -0
  49. package/dist/generators/test-generator/patterns/capture-patterns.js.map +1 -0
  50. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  51. package/dist/generators/test-generator/patterns/index.js +2 -0
  52. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  53. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  54. package/dist/generators/test-generator/step-mapper.js +1 -0
  55. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  56. package/dist/generators/test-generator/utils/data-resolver.d.ts +5 -0
  57. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  58. package/dist/generators/test-generator/utils/data-resolver.js +17 -0
  59. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  60. package/dist/harness/audit.d.ts +24 -0
  61. package/dist/harness/audit.d.ts.map +1 -0
  62. package/dist/harness/audit.js +115 -0
  63. package/dist/harness/audit.js.map +1 -0
  64. package/dist/harness/blindspot.d.ts +15 -0
  65. package/dist/harness/blindspot.d.ts.map +1 -0
  66. package/dist/harness/blindspot.js +85 -0
  67. package/dist/harness/blindspot.js.map +1 -0
  68. package/dist/harness/catalog/universal-viewpoints.yaml +114 -0
  69. package/dist/harness/challenge.d.ts +21 -0
  70. package/dist/harness/challenge.d.ts.map +1 -0
  71. package/dist/harness/challenge.js +151 -0
  72. package/dist/harness/challenge.js.map +1 -0
  73. package/dist/harness/feedback.d.ts +29 -0
  74. package/dist/harness/feedback.d.ts.map +1 -0
  75. package/dist/harness/feedback.js +106 -0
  76. package/dist/harness/feedback.js.map +1 -0
  77. package/dist/harness/intent.d.ts +11 -0
  78. package/dist/harness/intent.d.ts.map +1 -0
  79. package/dist/harness/intent.js +86 -0
  80. package/dist/harness/intent.js.map +1 -0
  81. package/dist/harness/ledger.d.ts +42 -0
  82. package/dist/harness/ledger.d.ts.map +1 -0
  83. package/dist/harness/ledger.js +171 -0
  84. package/dist/harness/ledger.js.map +1 -0
  85. package/dist/harness/manifest.d.ts +42 -0
  86. package/dist/harness/manifest.d.ts.map +1 -0
  87. package/dist/harness/manifest.js +209 -0
  88. package/dist/harness/manifest.js.map +1 -0
  89. package/dist/harness/parse.d.ts +22 -0
  90. package/dist/harness/parse.d.ts.map +1 -0
  91. package/dist/harness/parse.js +163 -0
  92. package/dist/harness/parse.js.map +1 -0
  93. package/dist/harness/script-check.d.ts +16 -0
  94. package/dist/harness/script-check.d.ts.map +1 -0
  95. package/dist/harness/script-check.js +169 -0
  96. package/dist/harness/script-check.js.map +1 -0
  97. package/dist/harness/secret-scan.d.ts +8 -0
  98. package/dist/harness/secret-scan.d.ts.map +1 -0
  99. package/dist/harness/secret-scan.js +88 -0
  100. package/dist/harness/secret-scan.js.map +1 -0
  101. package/dist/harness/sensors.d.ts +88 -0
  102. package/dist/harness/sensors.d.ts.map +1 -0
  103. package/dist/harness/sensors.js +232 -0
  104. package/dist/harness/sensors.js.map +1 -0
  105. package/dist/harness/trace.d.ts +31 -0
  106. package/dist/harness/trace.d.ts.map +1 -0
  107. package/dist/harness/trace.js +173 -0
  108. package/dist/harness/trace.js.map +1 -0
  109. package/dist/orchestrator/ai-rules-updater.d.ts +1 -0
  110. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  111. package/dist/orchestrator/ai-rules-updater.js +55 -11
  112. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  113. package/dist/orchestrator/figma/spec-figma-renderer.d.ts +2 -2
  114. package/dist/orchestrator/figma/spec-figma-renderer.js +2 -2
  115. package/dist/orchestrator/figma/spec-figma-section-renderers.d.ts +1 -1
  116. package/dist/orchestrator/figma/spec-figma-section-renderers.js +1 -1
  117. package/dist/orchestrator/project-initializer.d.ts +5 -0
  118. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  119. package/dist/orchestrator/project-initializer.js +26 -6
  120. package/dist/orchestrator/project-initializer.js.map +1 -1
  121. package/dist/orchestrator/templates/ai-instructions/claude-agent-challenge.md +46 -0
  122. package/dist/orchestrator/templates/ai-instructions/claude-agent-discovery.md +32 -0
  123. package/dist/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +37 -0
  124. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-flow.md +3 -3
  125. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +5 -5
  126. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +45 -13
  127. package/dist/orchestrator/templates/ai-instructions/claude-cmd-design.md +12 -0
  128. package/dist/orchestrator/templates/ai-instructions/claude-cmd-feedback.md +36 -0
  129. package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +27 -30
  130. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +8 -3
  131. package/dist/orchestrator/templates/ai-instructions/claude-config.md +1 -4
  132. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-mode-figma-mcp.md +82 -0
  133. package/dist/orchestrator/templates/ai-instructions/{github-skill-sungen-figma-source.md → claude-skill-capture-mode-figma-pat.md} +14 -48
  134. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-mode-live.md +60 -0
  135. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-mode-local.md +38 -0
  136. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture.md +35 -0
  137. package/dist/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md +84 -0
  138. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +57 -11
  139. package/dist/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +41 -31
  140. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +53 -1
  141. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-flow.md +3 -3
  142. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +4 -4
  143. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +27 -11
  144. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-design.md +13 -0
  145. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-feedback.md +24 -0
  146. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +20 -30
  147. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +6 -3
  148. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +1 -4
  149. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-mcp.md +82 -0
  150. package/{src/orchestrator/templates/ai-instructions/claude-skill-figma-source.md → dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-pat.md} +14 -48
  151. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-live.md +60 -0
  152. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-local.md +38 -0
  153. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture.md +35 -0
  154. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +84 -0
  155. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +62 -16
  156. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +41 -31
  157. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +40 -1
  158. package/dist/orchestrator/templates/qa-context.md +90 -0
  159. package/dist/orchestrator/templates/readme.md +16 -13
  160. package/dist/orchestrator/templates/specs-test-data.ts +9 -0
  161. package/dist/tools/figma/figma-auth.d.ts +5 -2
  162. package/dist/tools/figma/figma-auth.d.ts.map +1 -1
  163. package/dist/tools/figma/figma-auth.js +19 -9
  164. package/dist/tools/figma/figma-auth.js.map +1 -1
  165. package/docs/orchestration-spec.md +267 -0
  166. package/package.json +10 -6
  167. package/src/cli/commands/add.ts +3 -3
  168. package/src/cli/commands/audit.ts +92 -0
  169. package/src/cli/commands/blindspot.ts +48 -0
  170. package/src/cli/commands/challenge.ts +55 -0
  171. package/src/cli/commands/feedback.ts +65 -0
  172. package/src/cli/commands/generate.ts +19 -0
  173. package/src/cli/commands/ledger.ts +61 -0
  174. package/src/cli/commands/manifest.ts +55 -0
  175. package/src/cli/commands/script-check.ts +50 -0
  176. package/src/cli/commands/trace.ts +60 -0
  177. package/src/cli/commands/update.ts +30 -10
  178. package/src/cli/index.ts +16 -0
  179. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/capture-variable.hbs +1 -0
  180. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/all-contain-assertion.hbs +7 -0
  181. package/src/generators/test-generator/patterns/capture-patterns.ts +59 -0
  182. package/src/generators/test-generator/patterns/index.ts +2 -0
  183. package/src/generators/test-generator/step-mapper.ts +1 -0
  184. package/src/generators/test-generator/utils/data-resolver.ts +20 -0
  185. package/src/harness/audit.ts +112 -0
  186. package/src/harness/blindspot.ts +51 -0
  187. package/src/harness/catalog/universal-viewpoints.yaml +114 -0
  188. package/src/harness/challenge.ts +131 -0
  189. package/src/harness/feedback.ts +84 -0
  190. package/src/harness/intent.ts +58 -0
  191. package/src/harness/ledger.ts +155 -0
  192. package/src/harness/manifest.ts +173 -0
  193. package/src/harness/parse.ts +145 -0
  194. package/src/harness/script-check.ts +149 -0
  195. package/src/harness/secret-scan.ts +51 -0
  196. package/src/harness/sensors.ts +279 -0
  197. package/src/harness/trace.ts +138 -0
  198. package/src/orchestrator/ai-rules-updater.ts +57 -10
  199. package/src/orchestrator/figma/spec-figma-renderer.ts +2 -2
  200. package/src/orchestrator/figma/spec-figma-section-renderers.ts +1 -1
  201. package/src/orchestrator/project-initializer.ts +30 -7
  202. package/src/orchestrator/templates/ai-instructions/claude-agent-challenge.md +46 -0
  203. package/src/orchestrator/templates/ai-instructions/claude-agent-discovery.md +32 -0
  204. package/src/orchestrator/templates/ai-instructions/claude-agent-reviewer.md +37 -0
  205. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-flow.md +3 -3
  206. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +5 -5
  207. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +45 -13
  208. package/src/orchestrator/templates/ai-instructions/claude-cmd-design.md +12 -0
  209. package/src/orchestrator/templates/ai-instructions/claude-cmd-feedback.md +36 -0
  210. package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +27 -30
  211. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +8 -3
  212. package/src/orchestrator/templates/ai-instructions/claude-config.md +1 -4
  213. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-figma-mcp.md +82 -0
  214. package/{dist/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md → src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-figma-pat.md} +14 -48
  215. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-live.md +60 -0
  216. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-mode-local.md +38 -0
  217. package/src/orchestrator/templates/ai-instructions/claude-skill-capture.md +35 -0
  218. package/src/orchestrator/templates/ai-instructions/claude-skill-harness-audit.md +84 -0
  219. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-fix.md +57 -11
  220. package/src/orchestrator/templates/ai-instructions/claude-skill-selector-keys.md +41 -31
  221. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +53 -1
  222. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-flow.md +3 -3
  223. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +4 -4
  224. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +27 -11
  225. package/src/orchestrator/templates/ai-instructions/copilot-cmd-design.md +13 -0
  226. package/src/orchestrator/templates/ai-instructions/copilot-cmd-feedback.md +24 -0
  227. package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +20 -30
  228. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +6 -3
  229. package/src/orchestrator/templates/ai-instructions/copilot-config.md +1 -4
  230. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-mcp.md +82 -0
  231. package/{dist/orchestrator/templates/ai-instructions/claude-skill-figma-source.md → src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-figma-pat.md} +14 -48
  232. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-live.md +60 -0
  233. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-mode-local.md +38 -0
  234. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture.md +35 -0
  235. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-harness-audit.md +84 -0
  236. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +62 -16
  237. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-keys.md +41 -31
  238. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +40 -1
  239. package/src/orchestrator/templates/qa-context.md +90 -0
  240. package/src/orchestrator/templates/readme.md +16 -13
  241. package/src/orchestrator/templates/specs-test-data.ts +9 -0
  242. package/src/tools/figma/figma-auth.ts +20 -9
  243. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +0 -142
  244. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +0 -112
  245. package/dist/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +0 -73
  246. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +0 -142
  247. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +0 -112
  248. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +0 -73
  249. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-figma.md +0 -142
  250. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-live.md +0 -112
  251. package/src/orchestrator/templates/ai-instructions/claude-skill-capture-local.md +0 -73
  252. package/src/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md +0 -151
  253. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-figma.md +0 -142
  254. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-live.md +0 -112
  255. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-capture-local.md +0 -73
  256. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-figma-source.md +0 -151
@@ -0,0 +1,60 @@
1
+ # Capture mode: live
2
+
3
+ Navigate a running application, take **one accessibility snapshot** and **one screenshot**, and save them as visual context for test generation. Use when the app is live (dev, staging, or production with read-only access) and you want tests grounded in the actual rendered UI. Handles auth gracefully: if the page redirects to login, ask the user to sign in manually rather than injecting cookies.
4
+
5
+ ## Prerequisites
6
+
7
+ - Playwright MCP connected.
8
+ - Dev/staging server reachable (or a public URL).
9
+ - `playwright.config.ts` exists at the project root (for `baseURL` fallback).
10
+
11
+ ## Steps
12
+
13
+ ### 1. Resolve target URL
14
+
15
+ 1. `Live URL` field in `requirements/spec.md` (Overview section)
16
+ 2. `baseURL` from `playwright.config.ts` + `URL Path` from `spec.md`
17
+ 3. Neither → `AskUserQuestion`: *"Paste the full URL for the page to scan"*
18
+
19
+ ### 2. Navigate
20
+
21
+ `browser_navigate` to the resolved URL.
22
+
23
+ ### 3. Handle auth redirect
24
+
25
+ If the page redirects to a login route (URL contains `/login`, `/signin`, `/auth`, or content indicates a login screen):
26
+ 1. Tell the user which login URL they landed on.
27
+ 2. `AskUserQuestion`:
28
+ - **I'll log in manually** — wait for confirmation, then re-navigate to the target URL
29
+ - **Skip live scan** — switch to mode `local`
30
+ - **Cancel**
31
+ 3. **Never** inject cookies or localStorage via `browser_evaluate` / `browser_run_code`. Auth belongs to the user.
32
+
33
+ ### 4. Snapshot
34
+
35
+ Take **ONE** `browser_snapshot`. This accessibility tree is the primary AI context — roles, names, text, structure that tc-generation uses to identify sections and fields.
36
+
37
+ ### 5. Screenshot (recommended)
38
+
39
+ Take **ONE** `browser_take_screenshot` with `fullPage: true`. Save to `requirements/ui/live-<timestamp>.png`, where `<timestamp>` is `YYYYMMDD-HHMM` local time (e.g. `live-20260421-1430.png`).
40
+
41
+ ### 6a. Verify unauthenticated redirect target (flow capture only)
42
+
43
+ When capturing for a **flow** with security scenarios (e.g. "unauthenticated user cannot access X"):
44
+ 1. Open a **fresh incognito/unauthenticated** context (no storage state).
45
+ 2. `browser_navigate` to the protected route.
46
+ 3. Record the **actual redirect URL** — do NOT assume `/login`; it may be `/register`, `/`, etc.
47
+ 4. Report the redirect target: *"Unauthenticated access to `/dashboard` redirects to `/register`"*.
48
+ 5. The caller must use the **actual redirect URL** in Gherkin assertions, never an assumed one.
49
+
50
+ Skip if the flow has no security scenarios or the user says to skip.
51
+
52
+ ### 6. Detect discrepancies vs spec
53
+
54
+ If `spec.md` exists, cross-check the snapshot against spec sections: fields in spec but not in snapshot → *missing in UI*; elements in snapshot but not in spec → *missing in spec*. Report findings but **do not** auto-edit `spec.md`.
55
+
56
+ ### 7. Report back
57
+
58
+ > Captured live page `<URL>`: Snapshot N interactive elements · Screenshot `requirements/ui/live-<timestamp>.png` · Discrepancies vs spec: <count or "none">
59
+
60
+ Hand back to the calling command. Scans **exactly one** page per invocation.
@@ -0,0 +1,38 @@
1
+ # Capture mode: local
2
+
3
+ Use **pre-existing images** in `requirements/ui/` as visual context. No network, no MCP, no live site — works for any design tool (Figma export, Sketch, Penpot, Zeplin, hand-drawn, staging screenshots). This is the **baseline fallback**: if the live domain is down and Figma MCP isn't configured, this always works as long as the user drops images in the folder.
4
+
5
+ ## Steps
6
+
7
+ ### 1. List available images
8
+
9
+ Glob `requirements/ui/*.{png,jpg,jpeg,webp,gif}` and report count + filenames. Filter out metadata files (e.g. `figma-meta.md` written by mode figma-mcp) — those are read by `tc-generation` separately, not treated as images here.
10
+
11
+ ### 2. Handle empty folder
12
+
13
+ If no images found:
14
+ 1. Tell the user the folder is empty, with the full path so they can open it in Finder.
15
+ 2. `AskUserQuestion`:
16
+ - **I'll drop images now** — wait for confirmation, then re-glob
17
+ - **Switch to Figma** — switch to mode `figma-mcp`
18
+ - **Switch to live page scan** — switch to mode `live`
19
+ - **Cancel** — abort create-test
20
+ 3. If "drop images now", wait for confirmation (e.g. "done") then re-run step 1.
21
+
22
+ ### 3. Read images for context
23
+
24
+ Use the `Read` tool on each image — Claude Code reads PNG/JPG/WebP directly as visual context. For large sets (>10 images), ask which are primary and which are states/variants to avoid loading too much at once.
25
+
26
+ ### 4. Summarize
27
+
28
+ > Loaded N image(s) from `requirements/ui/`:
29
+ > - `<filename-1>` — <one-line description of what's visible>
30
+ > - `<filename-2>` — <one-line description>
31
+
32
+ Hand back to the calling command.
33
+
34
+ ## File naming hints for users
35
+
36
+ Nudge users toward consistent filenames (don't enforce):
37
+ - `<section>-default.png` / `-error.png` / `-loading.png` / `-empty.png` — section states
38
+ - `full-page.png` / `viewport.png` — whole screen (auto-generated by `sungen add --capture`)
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: sungen-capture
3
+ description: 'Acquire visual/design context for test generation from one of four sources (modes): figma-mcp, figma-pat, live, local. Auto-loaded by create-test/add-screen when a visual source is needed, or when --figma flag / spec_figma.md is present. Router skill — read only the mode file you need.'
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## Purpose
8
+
9
+ Bring **visual + design context** into test generation so `sungen-tc-generation` can author Gherkin + test-data grounded in the real UI. This is a **router**: pick exactly **one mode** for the run, then read only that mode's file. Do **not** read all four.
10
+
11
+ This skill never generates Gherkin or `selectors.yaml` — it only acquires context and reports back to the calling command.
12
+
13
+ ## Pick the mode
14
+
15
+ | Mode | Read | Use when | Needs |
16
+ |---|---|---|---|
17
+ | **figma-mcp** | `mode-figma-mcp.md` | Pre-launch / Figma is source of truth, **Figma Dev Mode MCP** connected | Figma MCP + frame URL |
18
+ | **figma-pat** | `mode-figma-pat.md` | `--figma` flag was used, or `requirements/spec_figma.md` exists (synthesize narrative from cached raw node JSON) | `sungen figma auth` PAT |
19
+ | **live** | `mode-live.md` | App is running (dev/staging/prod read-only) and you want the actual rendered UI | Playwright MCP + reachable URL |
20
+ | **local** | `mode-local.md` | Images already dropped in `requirements/ui/` (any design tool, screenshots, mockups) — baseline fallback, no network | nothing |
21
+
22
+ ### How the mode is chosen (when the caller didn't specify)
23
+
24
+ 1. `requirements/spec_figma.md` exists → **figma-pat** (PAT flow already ran during `add-screen`).
25
+ 2. `requirements/ui/` has images → **local**.
26
+ 3. Neither → ask the user which source (figma-mcp / live / local), then load that one mode file.
27
+
28
+ Modes are **mutually exclusive per run**, but the user can run `create-test` again with a different mode to layer context. All modes write to `requirements/ui/` and report back.
29
+
30
+ ## What this skill (any mode) does NOT do
31
+
32
+ - Does not generate Gherkin — that's `sungen-tc-generation`.
33
+ - Does not write `selectors.yaml` — that's `/sungen:run-test`.
34
+ - Does not inject auth/cookies — the user logs in manually (see `live`).
35
+ - Does not crawl or generate images.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: sungen-harness-audit
3
+ description: 'How to read `sungen audit` output and repair test-design findings. Auto-loaded by the design orchestrator.'
4
+ user-invocable: false
5
+ ---
6
+
7
+ ## What `sungen audit` measures
8
+
9
+ `sungen audit --screen <name>` runs deterministic sensors over `features/<name>.feature` + `requirements/test-viewpoint.md` and writes `.sungen/reports/<name>-audit.json`. It is the **gate** the orchestrator repairs against. Run with `--json` to parse it.
10
+
11
+ ### Report shape (key fields)
12
+ ```jsonc
13
+ {
14
+ "score": { "overall": 3.9, "coverage": 0.4, "businessDepth": 0.18, "balance": 0.5, "traceability": 0.7 },
15
+ "gateStatus": "PASS" | "FAIL",
16
+ "gate": { "pageType": "ecommerce-list", "themesCovered": 2, "themesTotal": 5,
17
+ "gaps": [ { "theme": "cart-correctness", "keywords": [...] } ] },
18
+ "depth": { "businessCriticalShallow": 9, "businessCriticalTotal": 11,
19
+ "shallowBusinessCritical": [ { "name": "...", "category": "PRODUCT" } ] },
20
+ "balance": { "imbalanced": true, "coreCount": 11, "secondaryCount": 22, "byBucket": {...} },
21
+ "duplicates": { "clusters": [ { "sameDataLikely": false, "scenarios": [...] } ] },
22
+ "trace": { "mappedRatio": 0.4, "note": "..." },
23
+ "findings": [ "GATE: ...", "DEPTH: ...", "BALANCE: ...", "TRACE: ..." ]
24
+ }
25
+ ```
26
+ - **`overall` score is business-weighted** (coverage 0.4 + businessDepth 0.3 + balance 0.15 + traceability 0.15). It is intentionally strict on business value — a high count with shallow business coverage scores low. Don't optimize the count; optimize coverage + depth.
27
+ - Exit code **2** when `gateStatus == FAIL` (usable in CI / loop).
28
+
29
+ ## Finding → repair mapping
30
+
31
+ | Finding prefix | Meaning | Repair action |
32
+ |---|---|---|
33
+ | **GATE** | a critical theme for the page-type has no covering scenario | Generate scenarios for that theme. **If cross-screen** (cart-correctness, product-detail-consistency, filter-result-correctness, multi-item cart) → do NOT fake it on a single screen; plan a **flow** (`/sungen:add-flow`) and record the deferral. |
34
+ | **DEPTH** | business-critical scenarios assert only visibility/navigation | Replace `Then User see [X] page/section` with **observable data assertions**: `Then User see [X] with {{value}}`, `Then User see [T] table match data:`. Capture real expected values into `test-data.yaml`. |
35
+ | **BALANCE** | secondary viewpoints (UI/validation/security) outweigh business-core | **Stop expanding** secondary viewpoints; generate the missing business-core scenarios first. Do not add more subscription/UI variants while core is thin. |
36
+ | **TRACE** | scenarios use ad-hoc `VP-<CAT>-NNN` codes not linked to the viewpoint-overview | Make each scenario map to a viewpoint-overview id (align category codes, or add a mapping comment). |
37
+ | **UNIVERSAL** | a universal theme (error/empty-state, accessibility) is absent | Low priority — add if in scope; otherwise note as out-of-scope with reason. |
38
+
39
+ ## P5 steps for deep cross-screen / list coverage
40
+
41
+ Use these when repairing GATE/DEPTH findings for the hard viewpoints (cart/detail/filter correctness). They need **runtime data mode** (the default).
42
+
43
+ - **Capture a value to compare across screens** (product-detail-consistency, cart-correctness):
44
+ ```gherkin
45
+ When User remember [Product Name] text as {{selected_product_name}}
46
+ And User remember [Product Price] text as {{selected_product_price}}
47
+ And User click [View Product] link
48
+ Then User see [Detail Product Name] header with {{selected_product_name}}
49
+ And User see [Detail Product Price] text with {{selected_product_price}}
50
+ ```
51
+ `remember` stores the element's text/value at runtime; later `{{var}}` resolves to it. This proves the detail/cart shows the SAME product, not a random one.
52
+
53
+ - **Assert every item in a result matches** (category/brand-filter-correctness):
54
+ ```gherkin
55
+ When User click [Women] link
56
+ And User click [Dress] link
57
+ Then User see all [Result Product Name] contain {{selected_category}}
58
+ ```
59
+ `see all [X] contain {{v}}` asserts EVERY matching element contains the value → "all displayed products belong to the selected category/brand", not just one.
60
+
61
+ > Cross-screen flows (home → detail/cart): if the target screen is a separate screen, prefer a **flow** (`/sungen:add-flow`) so the journey is one test. On a single screen, keep the cross-screen assertion but tag `@manual` with a `# Deferred to a flow` comment.
62
+
63
+ ## Repair loop rules
64
+
65
+ 1. **Budget = 3 rounds.** Re-run `sungen audit` after each repair; track score delta.
66
+ 2. **Stop when** `gateStatus == PASS` AND `findings` empty — or budget exhausted.
67
+ 3. **Never fake a pass.** A shallow `see [Cart] page` does not satisfy `cart-correctness`. If a gap is genuinely cross-screen or needs capabilities the DSL lacks (e.g. capture an element value to compare elsewhere), **report it as a residual gap / flow item** instead of forcing a green gate.
68
+ 4. **EP/data families are OK.** A `duplicates` cluster with `sameDataLikely=false` is an intentional equivalence-partition family (e.g. many invalid-email cases) — keep it; only collapse `sameDataLikely=true` exact duplicates.
69
+
70
+ ## Discovery / fallback tree (when input is limited)
71
+
72
+ ```
73
+ spec.md đủ tốt? → YES: Spec-first
74
+ │ NO
75
+ source code có? → YES: Source-first (mine behavior từ code)
76
+ │ NO
77
+ testcase cũ tương tự?→ YES: History-first
78
+ │ NO
79
+ domain rủi ro+defect?→ YES: Defect-first
80
+ │ NO
81
+ → hỏi QA; QA chưa phản hồi → OUTPUT kèm ASSUMPTION LIST rõ ràng (không stall)
82
+ ```
83
+
84
+ See `docs/orchestration-spec.md` for the full flow and `reports/sungen_refactor_spec.md` for the design rationale.
@@ -55,13 +55,23 @@ When running Phase 0 for a **flow** (`qa/flows/<name>/`), check existing screen
55
55
  - Read `baseURL` from `playwright.config.ts`.
56
56
  - `browser_navigate` to the page URL.
57
57
  - If redirected to login → **ask the user to log in manually in the MCP browser**, wait for confirmation, then continue. Never use `sungen makeauth`. Never inject cookies via `browser_evaluate`.
58
- 5. **Snapshot**: take **ONE** `browser_snapshot`. All Phase 0 selectors come from this single snapshot.
58
+ 5. **Snapshot**: Wait for the page to fully load before snapshotting.
59
+ - Check if the page is still loading (spinner visible, skeleton placeholders, empty table with 0 rows). If so, use `browser_wait_for` to wait until content is rendered.
60
+ - Then take **ONE** `browser_snapshot`. All Phase 0 selectors come from this single snapshot.
59
61
  6. **Generate YAML entries**:
60
62
  - Keys: follow `sungen-selector-keys` (lowercase, Unicode preserved, `--type` / `--N` suffixes).
61
- - Selector priority: follow the table in **Diagnosis & Fix § Step 3** (`testid` > `role`+name > `placeholder` > `label` > `locator` > `text`).
63
+ - Selector priority: follow the table in **Diagnosis & Fix § Step 3** (`testid` > `role`+name > `label` > `placeholder` > `text` > `locator` CSS last resort).
62
64
  - Copy names **character-for-character** from the snapshot. Never infer from the Gherkin label.
63
65
  - If an element is auto-inferable per `sungen-selector-keys` § Auto-Infer, **omit it** from YAML — keep the file minimal.
64
66
  - **i18n sites**: if the site supports multiple languages, use `{{variable}}` in `name`/`value` fields instead of hardcoded text. Add corresponding `lbl_*` keys to `test-data.yaml` + locale overlay files (see `sungen-selector-keys` § i18n).
67
+ - **Selector quality rule**: the Playwright MCP accessibility tree snapshot gives you roles and accessible names directly — use them. Do NOT write XPath or class-based CSS selectors. Only write `type: locator` when no role/text/label/placeholder/testid is available, and restrict the CSS to `#id` or `[data-*]` / `[aria-*]` attribute selectors.
68
+ 6b. **Cross-verify Gherkin labels vs snapshot** (prevents the #1 production failure):
69
+ - For **every** `[Reference]` in the `.feature` that will rely on auto-infer (not written to YAML), check the snapshot:
70
+ - `[X] button` — is there a button with accessible name **exactly** `X`?
71
+ - `[X] field` — does an input have placeholder **exactly** `X`? Does it even have a placeholder?
72
+ - `[X] heading` / `text` / `message` — is that text literally visible in the snapshot?
73
+ - If any mismatch → write an explicit YAML entry using the real DOM name. Do not leave a mismatch to be caught at runtime.
74
+ - **Typical mismatch cases**: Gherkin uses English label (`[Submit]`) but app displays Vietnamese (`"Gửi"`); placeholder is descriptive (`"Nhập email của bạn"`) not a bare field name (`"Email"`); button text includes an icon glyph before/after the word.
65
75
  7. **Substring ambiguity check**: for each `role` + `name` selector, check if any other element in the snapshot has a name that **contains** this name as a substring (e.g., `"Đăng ký"` vs `"Đăng ký bằng Google"`). If yes → add `exact: true` to prevent strict mode violation at runtime.
66
76
  8. **Merge, don't overwrite**: preserve the page selector and any user-authored entries in `selectors.yaml`. Only add missing keys.
67
77
  9. **Show summary + confirm**: list the keys that will be added, ask the user to approve, then write the file.
@@ -69,9 +79,13 @@ When running Phase 0 for a **flow** (`qa/flows/<name>/`), check existing screen
69
79
 
70
80
  ### Common Phase 0 pitfalls
71
81
 
72
- - Writing keys inferred from the Gherkin label instead of the snapshot name → Phase 1 will fail with "no element found".
82
+ - Writing keys inferred from the Gherkin label instead of the snapshot name → Phase 1 will fail with `No element found`.
73
83
  - Skipping Phase 0.5 when an auth redirect happened → snapshot captures the login page, all selectors wrong.
84
+ - Taking snapshot while page is still loading (spinner visible, table empty) → selectors for dynamic content will be missing or wrong.
85
+ - Skipping step 6b for "simple" elements like buttons → silent mismatch between Gherkin label and DOM name fails at runtime.
74
86
  - Using `browser_evaluate` alone to scrape cookies → misses httpOnly session cookies. Always use `browser_storage_state` (or the `browser_run_code` fallback).
87
+ - Writing XPath or class-based CSS selectors → breaks on DOM/style refactoring. Use role/testid/text/label/placeholder from the accessibility tree.
88
+ - Falling back to `locator: 'div.some-class > span'` when the element IS visible in the accessibility snapshot with a role + name → the snapshot gives you `getByRole` for free; use it.
75
89
  - Overwriting user-authored selectors → always merge.
76
90
 
77
91
  ---
@@ -98,12 +112,12 @@ When running Phase 0 for a **flow** (`qa/flows/<name>/`), check existing screen
98
112
  |---|---|---|
99
113
  | 1 | `testid` | Dev annotation `data-testid=X` in component metadata |
100
114
  | 2 | `role` + name | Component type is Button/Link + has text label |
101
- | 3 | `placeholder` | Component type is Input/Field + has placeholder text |
102
- | 4 | `label` | Component has associated label text (not placeholder) |
103
- | 5 | `locator` (CSS) | No accessible name derivable from Figma data |
104
- | 6 | `text` | Plain text node (not inside interactive component) |
115
+ | 3 | `label` | Component has associated label text (not placeholder) |
116
+ | 4 | `placeholder` | Component type is Input/Field + has placeholder text |
117
+ | 5 | `text` | Plain text node (not inside interactive component) |
118
+ | 6 | `locator` (CSS) | Last resort `#id` or `[attr=value]` only, never classes or XPath |
105
119
 
106
- See `sungen-figma-source` skill for the authoritative heuristics table mapping Figma signals to YAML entry types.
120
+ See `sungen-capture` skill (mode figma-pat) for the authoritative heuristics table mapping Figma signals to YAML entry types.
107
121
 
108
122
  4. **Write entries**: add each entry to `selectors.yaml`, prefixed with the required comment:
109
123
  ```yaml
@@ -271,12 +285,24 @@ Selector priority (use first applicable):
271
285
 
272
286
  | Priority | type | When |
273
287
  |---|---|---|
274
- | 1 | `testid` | `data-testid` exists |
275
- | 2 | `role` + exact name | Interactive elements |
276
- | 3 | `placeholder` | Input with placeholder |
277
- | 4 | `label` | Form field with `<label>` |
278
- | 5 | `locator` (CSS) | No accessible name |
279
- | 6 | `text` | Static text only |
288
+ | 1 | `testid` | `data-testid` or any stable test attribute exists |
289
+ | 2 | `role` + exact name | Interactive elements with an accessible name |
290
+ | 3 | `label` | Form field with a visible `<label>` |
291
+ | 4 | `placeholder` | Input/textarea with a placeholder attribute |
292
+ | 5 | `text` | Static visible text content |
293
+ | 6 | `locator` (CSS) | Last resort — `#id` or `[attr=value]` **only** (see restrictions below) |
294
+
295
+ > ⚠️ **Playwright best practice** ([source](https://playwright.dev/docs/best-practices#use-locators)): user-facing locators (`role`, `label`, `text`, `placeholder`, `testid`) are resilient to refactoring and far less likely to break. CSS class selectors and XPath break whenever a developer renames a class or restructures the DOM — even without changing the UI.
296
+ >
297
+ > **Never write these in `selectors.yaml`**:
298
+ > - XPath: `xpath=//div[@class='...']` or `//button[contains(@class,'btn')]`
299
+ > - Class-based CSS: `div.btn-primary`, `.modal-footer > .submit-btn`
300
+ > - Deep structural CSS: `div:nth-child(3) > ul > li > button`
301
+ >
302
+ > **Acceptable CSS (last resort only)**:
303
+ > - Stable `id`: `#submit-button` (only if the id is truly stable and not dynamic)
304
+ > - Data attributes: `[data-id="123"]`, `[aria-controls="menu"]`
305
+ > - Input type: `input[type="file"]` (when no testid/label exists)
280
306
 
281
307
  **Exact name rule**: copy name character-for-character from snapshot. Never infer from Gherkin label.
282
308
 
@@ -290,9 +316,9 @@ Common fixes:
290
316
  - Name mismatch → copy exact name from snapshot
291
317
  - Multiple matches → add `nth` or `exact: true`
292
318
  - Substring ambiguity (e.g., `"Submit"` matches `"Submit"` and `"Submit & Continue"`) → add `exact: true`
293
- - No accessible name → use `testid` or `locator` (CSS)
319
+ - No accessible name → use `testid`; only fall back to `locator` CSS as last resort
294
320
  - Element in iframe → add `frame` field
295
- - Dynamic content → use `testid` or structural `role` + `nth`
321
+ - Dynamic content → use `testid` or `role` + `nth`
296
322
 
297
323
  ### Step 4: Recompile After Fix
298
324
 
@@ -309,6 +335,26 @@ Then re-run only the current phase's failing tests, not all tests.
309
335
 
310
336
  ---
311
337
 
338
+ ## Common Failure Patterns
339
+
340
+ Quick reference for the most frequent production failures:
341
+
342
+ | Symptom | Root cause | Fix |
343
+ |---------|-----------|-----|
344
+ | `No element found` on button/link/heading | Gherkin `[Reference]` label ≠ DOM accessible name (different language or text) | Write explicit YAML: `type: role, value: button, name: "<exact DOM name>"` |
345
+ | `No element found` on `[X] field` | Field has no placeholder, or placeholder ≠ X | Write explicit YAML: `type: label, value: "Actual label"` or `type: placeholder, value: "Actual placeholder"` |
346
+ | `No element found` on `[X] text` / `message` | Visible text differs from Gherkin label, or text is dynamic | Write explicit YAML or use `{{variable}}` for dynamic content |
347
+ | `strict mode violation` | Multiple elements match the same name/text | Add `exact: true` to YAML entry, or add `nth` |
348
+ | `toBeVisible` timeout on dynamic content | Snapshot was taken while page was still loading | Wait for spinner/skeleton to clear before snapshotting; add `browser_wait_for` |
349
+ | All tests fail with page navigate error | Page selector URL wrong or baseURL mismatch | Re-check `playwright.config.ts` `baseURL` and page selector `value` path |
350
+ | Auth redirect on every test | `specs/.auth/<role>.json` missing or expired | Run Phase 0.5 to capture fresh session |
351
+ | Table row assertions fail | `columns` config has wrong indices | Count column headers left-to-right (0-indexed) from snapshot |
352
+ | Wrong text assertions on locale page | Hardcoded Vietnamese/English text in YAML `name`/`value` | Use `{{lbl_*}}` variables with locale overlay files |
353
+ | Element inside iframe not found | `frame` field missing in YAML entry | Add `frame: "iframe[src*='...']"` to the selector entry |
354
+ | Selector breaks after UI redesign with no functional change | CSS class or XPath used — brittle to style refactoring | Rewrite with `role`/`testid`/`label`/`text` from accessibility snapshot |
355
+
356
+ ---
357
+
312
358
  ## Table Selectors
313
359
 
314
360
  For table patterns, add table selectors with `columns` config:
@@ -166,37 +166,47 @@ Resolver searches in this order:
166
166
 
167
167
  If no YAML key exists, the resolver infers from the Gherkin element type:
168
168
 
169
- | Gherkin | Inferred locator |
170
- |---|---|
171
- | `[X] button` | `getByRole('button', { name: 'X' })` |
172
- | `[X] link` | `getByRole('link', { name: 'X' })` |
173
- | `[X] heading` / `header` | `getByRole('heading', { name: 'X' })` |
174
- | `[X] checkbox` | `getByRole('checkbox', { name: 'X' })` |
175
- | `[X] radio` | `getByRole('radio', { name: 'X' })` |
176
- | `[X] field` | `getByPlaceholder('X')` |
177
- | `[X] text` / `message` / `label` | `getByText('X')` |
178
- | `[X] logo/image/icon` | `getByRole('img', { name: 'X' })` |
179
- | `[X] search` | `getByRole('searchbox', { name: 'X' })` |
180
- | `[X] option` | `getByRole('option', { name: 'X' })` |
181
- | `[X] slider` | `getByRole('slider', { name: 'X' })` |
182
- | `[X] toggle` | `getByRole('switch', { name: 'X' })` |
183
- | `[X] tab` | `getByRole('tab', { name: 'X' })` |
184
- | `[X] table` | `getByRole('table', { name: 'X' })` |
185
- | `[X] list` | `getByRole('list', { name: 'X' })` |
186
- | `[X] column` | `getByRole('columnheader', { name: 'X' })` |
187
- | `[X] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'X' })` |
188
- | `[X] dropdown` / `select` | `getByRole('combobox', { name: 'X' })` |
189
- | `[X] menuitem` | `getByRole('menuitem', { name: 'X' })` |
190
- | `[X] progressbar` | `getByRole('progressbar', { name: 'X' })` |
191
- | `[X] section` | `getByRole('region', { name: 'X' })` |
192
- | `[X] card` | `getByRole('article', { name: 'X' })` |
193
- | `[X] item` | `getByRole('listitem', { name: 'X' })` |
194
- | `[X] cell` | `getByRole('cell', { name: 'X' })` |
195
- | `[X] spinner` | `getByRole('status', { name: 'X' })` |
196
- | `[X] breadcrumb` | `getByRole('navigation', { name: 'X' })` |
197
- | `[X] badge` / `tooltip` / `tag` | `getByText('X')` |
198
-
199
- **Only add a YAML entry when** the auto-inferred locator won't work (wrong name, need testid, need nth, etc.).
169
+ > ⚠️ **Auto-infer pitfall the #1 cause of selector failures in production.**
170
+ >
171
+ > `[X] button` auto-infers as `getByRole('button', { name: 'X' })`. This **only works** when the button's accessible name in the DOM is **exactly `X`** — same language, same text, same casing.
172
+ >
173
+ > The Gherkin `[Reference]` is your human label for the element, **not** the DOM name. If the app is in Vietnamese (or any language where the Gherkin label differs from DOM text), auto-infer will produce `No element found` at runtime. **Write an explicit YAML entry** with the real DOM name instead.
174
+ >
175
+ > **Decision rule**: auto-infer is safe ONLY when you have confirmed in the snapshot that the DOM element's accessible name / placeholder text is literally `X`. When in doubt → write YAML.
176
+
177
+ | Gherkin | Inferred locator | Safe when… |
178
+ |---|---|---|
179
+ | `[X] button` | `getByRole('button', { name: 'X' })` | Button's accessible name = X |
180
+ | `[X] link` | `getByRole('link', { name: 'X' })` | Link text = X |
181
+ | `[X] heading` / `header` | `getByRole('heading', { name: 'X' })` | Heading text = X |
182
+ | `[X] checkbox` | `getByRole('checkbox', { name: 'X' })` | Checkbox label = X |
183
+ | `[X] radio` | `getByRole('radio', { name: 'X' })` | Radio label = X |
184
+ | `[X] field` | `getByPlaceholder('X')` | Placeholder text = X AND field has a placeholder |
185
+ | `[X] text` / `message` / `label` | `getByText('X')` | Visible text = X (partial match) |
186
+ | `[X] logo/image/icon` | `getByRole('img', { name: 'X' })` | Image alt = X |
187
+ | `[X] search` | `getByRole('searchbox', { name: 'X' })` | Searchbox label = X |
188
+ | `[X] option` | `getByRole('option', { name: 'X' })` | Option text = X |
189
+ | `[X] slider` | `getByRole('slider', { name: 'X' })` | Slider label = X |
190
+ | `[X] toggle` | `getByRole('switch', { name: 'X' })` | Toggle label = X |
191
+ | `[X] tab` | `getByRole('tab', { name: 'X' })` | Tab text = X |
192
+ | `[X] table` | `getByRole('table', { name: 'X' })` | Table aria-label = X |
193
+ | `[X] list` | `getByRole('list', { name: 'X' })` | List aria-label = X |
194
+ | `[X] column` | `getByRole('columnheader', { name: 'X' })` | Column header text = X |
195
+ | `[X] dialog` / `modal` / `drawer` | `getByRole('dialog', { name: 'X' })` | Dialog aria-label/heading = X |
196
+ | `[X] dropdown` / `select` | `getByRole('combobox', { name: 'X' })` | Combobox label = X |
197
+ | `[X] menuitem` | `getByRole('menuitem', { name: 'X' })` | Menu item text = X |
198
+ | `[X] progressbar` | `getByRole('progressbar', { name: 'X' })` | Progressbar label = X |
199
+ | `[X] section` | `getByRole('region', { name: 'X' })` | Section aria-label = X |
200
+ | `[X] card` | `getByRole('article', { name: 'X' })` | Card aria-label = X |
201
+ | `[X] item` | `getByRole('listitem', { name: 'X' })` | List item text = X |
202
+ | `[X] cell` | `getByRole('cell', { name: 'X' })` | Cell text = X |
203
+ | `[X] spinner` | `getByRole('status', { name: 'X' })` | Spinner aria-label = X |
204
+ | `[X] breadcrumb` | `getByRole('navigation', { name: 'X' })` | Navigation aria-label = X |
205
+ | `[X] badge` / `tooltip` / `tag` | `getByText('X')` | Visible text = X |
206
+
207
+ **Special note on `[X] field`**: `getByPlaceholder('X')` only works when (1) the field has a placeholder attribute AND (2) the placeholder text equals X. For fields without placeholders (floating labels, aria-label), write explicit YAML: `type: label, value: "Actual label text"`.
208
+
209
+ **Only add a YAML entry when** auto-infer cannot work: DOM name differs from Gherkin label, need `testid`, need `nth`, need `exact: true`, or the field type requires explicit config.
200
210
 
201
211
  ### Types requiring YAML entry (no auto-infer)
202
212
 
@@ -7,7 +7,7 @@ user-invocable: false
7
7
  ## ⚠️ Gotchas — read before generating
8
8
 
9
9
  - `spec_figma.md` exists → read file only, **NEVER** call `mcp__figma__*`
10
- → PAT auth flow already done by `sungen-figma-source`; re-calling fails or duplicates work.
10
+ → PAT auth flow already done by `sungen-capture` (mode figma-pat); re-calling fails or duplicates work.
11
11
 
12
12
  - `selectors.yaml` → do **NOT** generate — handled by `run-test`
13
13
  → Selectors need live DOM inspection via Playwright MCP, only `run-test` triggers it.
@@ -208,6 +208,45 @@ Security: [S1 – admin only]
208
208
 
209
209
  **✅ Good** — see admin notice example above: `Display surfaces` lists every URL spec mentions as output, `Cross-surface rules` maps each admin action to its user-facing outcome, `Inclusive bounds` flags every `<=`/`>=` for BVA. Every item maps to a VP-ID in `Tier 1 output`.
210
210
 
211
+ #### Critical business-viewpoint pre-gate — pass `sungen audit` on the FIRST pass
212
+
213
+ > The harness gate FAILS (and forces repair rounds → wasted tokens) when a page-type's critical **business** viewpoints are missing or **shallow**. Generate them correctly the first time. A business-critical `Then` must assert **DATA**, never just `see [X] page/section/modal`.
214
+
215
+ **By page-type, generate a DEEP scenario for each (before expanding UI/validation/subscription):**
216
+
217
+ | Page-type | Must-cover viewpoints (each with a data assertion) |
218
+ |---|---|
219
+ | **e-commerce list / home** | list-data (card has image+name+price+add) · product-detail-consistency · cart-correctness · category-filter-correctness · **brand-filter-correctness (separate from category)** · add-to-cart success · nav-core |
220
+ | **form** | required-validation · format/boundary · submit-success |
221
+ | **auth** | valid-login · invalid-credential · access-control |
222
+
223
+ **Required assertion shapes (use these, not bare visibility):**
224
+ - Card info: assert at **card level** (image+name+price together), e.g. `User see all [Product Card] contain {{...}}` — not `see [Section]`.
225
+ - Cross-screen consistency (detail/cart): **capture then compare** —
226
+ ```gherkin
227
+ When User remember [Product Name] text as {{selected_product_name}}
228
+ And User remember [Product Price] text as {{selected_product_price}}
229
+ And User click [View Product] link
230
+ Then User see [Detail Product Name] header with {{selected_product_name}}
231
+ And User see [Detail Product Price] text contains {{selected_product_price}}
232
+ ```
233
+ Cross-screen target → tag `@manual` + `# Deferred to a flow (home -> detail)`.
234
+ - Filter result (category AND brand, separately): `Then User see all [Result Product Name] contain {{selected_category}}` — proves EVERY item belongs, not one.
235
+
236
+ **Depth is a GATE dimension (harness-roadmap P1) — self-raise, never silently go shallow:**
237
+ - For every data-correctness theme the catalog marks `depth.requires: data-assertion`, emit its `depth.template` shape by **default** — don't wait for the repair loop. `sungen audit` measures `businessDepth` (ratio of these scenarios that assert data) against an intent threshold (functional ≥ 0.70); below it the **gate FAILs**.
238
+ - `depth.cross_screen: true` (cart / detail / filter / brand correctness) → write the deep capture/compare shape but tag `@manual` + `# Deferred to a flow (...)`. These are excluded from the ratio (they're correctly deferred), so they don't hurt depth.
239
+ - **If the spec lacks the concrete value** a deep assertion needs (exact message, price, count): still write the deep shape with a `{{var}}` placeholder and leave a `# SPEC-GAP: <field> value not in spec` comment — do **not** downgrade to `see [X] section`. A visible gap is better than a silent shallow pass.
240
+ - **Blind-Spot Memory:** before finishing, run `sungen blindspot list --prompt` (Bash) and make sure the suite satisfies each recorded pattern (e.g. "for any Add/Create action: check success + resulting data state + duplicate/double-submit"). These are gaps QA hit before — don't repeat them.
241
+
242
+ **First-pass anti-patterns (exactly what the gate/reviewer reject — avoid them):**
243
+ - Title↔steps mismatch (e.g. a "no-result" scenario that clicks a query which returns products).
244
+ - Tautology `Then`: `click [Next Slide]` → `see [Carousel] section` (proves nothing).
245
+ - Business-critical scenario ending at `see [Added] modal` / `see [Cart] page` with no data assertion.
246
+ - Brand filter covered only as navigation (must assert products belong to the brand).
247
+
248
+ **Balance:** cover all the above (deep) BEFORE expanding subscription / UI-presence / extra validation edge cases.
249
+
211
250
  #### Tier 1 guard — minimum before writing scenarios
212
251
 
213
252
  | Spec section | Minimum requirement | Tag |
@@ -0,0 +1,90 @@
1
+ # Project Context
2
+
3
+ > Read by the AI before generating test cases for any screen in this project.
4
+ > Fill in what applies — leave sections empty if not relevant.
5
+ > **The more specific you are, the more accurate the generated test cases.**
6
+
7
+ ---
8
+
9
+ ## Project Overview
10
+
11
+ **Application:**
12
+ <!-- One sentence: what does this app do? -->
13
+ <!-- Example: B2B award nomination platform for enterprise HR teams. -->
14
+
15
+ **Target users:**
16
+ <!-- Who uses this app and in what context? -->
17
+ <!-- Example: HR managers submit nominations; employees view results. -->
18
+
19
+ **Domain notes:**
20
+ <!-- Key terminology, conventions, or constraints the AI should know. -->
21
+ <!-- Example: "Nomination = an award record. Once submitted, status cannot revert to Draft." -->
22
+ <!-- Example: "All monetary values are in JPY. No decimal places." -->
23
+
24
+ ---
25
+
26
+ ## Auth Roles
27
+
28
+ > The AI maps these directly to `@auth:X` tags and generates permission-boundary test scenarios.
29
+ > Leave the table empty (or delete it) if the app has no auth system.
30
+
31
+ | Role | Can do | Cannot do |
32
+ |------|--------|-----------|
33
+ | | | |
34
+
35
+ <!--
36
+ Example:
37
+ | Role | Can do | Cannot do |
38
+ |---------|---------------------------------------------|--------------------------------------|
39
+ | admin | All CRUD, manage users, configure settings | Nothing blocked |
40
+ | manager | Create/edit records, view reports | Delete records, manage users |
41
+ | staff | View and submit own records only | Edit others' records, view reports |
42
+ -->
43
+
44
+ ---
45
+
46
+ ## Testing Strategy
47
+
48
+ **Focus areas** — what to cover thoroughly:
49
+ <!-- List from: functional, security, ui, accessibility, performance -->
50
+ <!-- Example: functional, security -->
51
+
52
+ **Mandatory coverage:**
53
+ <!-- Rules that override the AI's default tier decisions for every screen. -->
54
+ <!-- Example: "Every screen with admin-only actions MUST have a non-admin blocked-access scenario." -->
55
+ <!-- Example: "All free-text inputs MUST have XSS + SQL injection scenarios regardless of screen risk level." -->
56
+
57
+ **Deprioritize / skip:**
58
+ <!-- What to move to @low or skip entirely for this project. -->
59
+ <!-- Example: "Skip VP-UI cosmetic checks (label/placeholder presence) — handled separately by design review." -->
60
+ <!-- Example: "Skip accessibility scenarios — separate audit planned." -->
61
+
62
+ ---
63
+
64
+ ## Global Business Rules
65
+
66
+ > Rules that apply across multiple screens.
67
+ > The AI adds these to the Coverage Map for every screen as `[G]`-tagged Business rules.
68
+ > Screen-specific rules belong in `requirements/spec.md`, not here.
69
+
70
+ <!-- - Soft-delete only: records are never hard-deleted, only marked inactive -->
71
+ <!-- - All timestamps stored in UTC, displayed in UTC+7 -->
72
+ <!-- - Pagination default: 20 items per page; max 100 -->
73
+ <!-- - File uploads: PNG/JPG/PDF only, max 5 MB -->
74
+ <!-- - After any write operation, the list view must refresh automatically -->
75
+
76
+ ---
77
+
78
+ ## Error Message Patterns
79
+
80
+ > If your app follows consistent validation error formats, list them here.
81
+ > The AI uses these to fill `test-data.yaml` error keys when `spec.md` doesn't specify exact text.
82
+ > Leave empty to let the AI infer from spec.md.
83
+
84
+ - Required field: `<!-- "This field is required" -->`
85
+ - Max length: `<!-- "Must be X characters or less" -->`
86
+ - Min length: `<!-- "Must be at least X characters" -->`
87
+ - Invalid format: `<!-- "Invalid format" -->`
88
+ - Unique constraint: `<!-- "Already exists" -->`
89
+ - Not found: `<!-- "Not found" -->`
90
+ - Unauthorized: `<!-- "You do not have permission to perform this action" -->`
@@ -12,14 +12,16 @@ sungen generate → compiles Gherkin + selectors + data → Playwright .spec.ts
12
12
  ## Directory Structure
13
13
 
14
14
  ```
15
- ├── qa/screens/<name>/
16
- │ ├── features/ # .feature files (Gherkin)
17
- │ ├── selectors/ # Element locator YAML mappings
18
- │ ├── test-data/ # Test data YAML values
19
- └── requirements/ # Screen specs, UI designs, notes
20
- ├── spec.md # Structured screen specification
21
- ├── ui/ # Screenshots, mockups, design images
22
- └── test-viewpoint.md # Edge cases, decisions (optional)
15
+ ├── qa/
16
+ │ ├── context.md # Project-wide context: roles, testing strategy, global rules (fill once)
17
+ │ ├── screens/<name>/
18
+ ├── features/ # .feature files (Gherkin)
19
+ │ ├── selectors/ # Element locator YAML mappings
20
+ ├── test-data/ # Test data YAML values
21
+ │ └── requirements/ # Screen specs, UI designs, notes
22
+ ├── spec.md # Structured screen specification
23
+ │ │ ├── ui/ # Screenshots, mockups, design images
24
+ │ │ └── test-viewpoint.md # Edge cases, decisions (optional)
23
25
  ├── specs/
24
26
  │ └── generated/ # Auto-generated Playwright tests
25
27
  ├── .claude/
@@ -66,11 +68,12 @@ Scaffolds `qa/screens/<name>/` with empty feature, selectors, test-data, and req
66
68
  | `/sungen:create-test login` | `/sungen-create-test login` |
67
69
 
68
70
  AI acts as a **Senior QA Engineer**:
69
- 1. Reads `requirements/spec.md` for screen specs (fields, validation, business rules, states)
70
- 2. Optionally explores the live page via Playwright MCP to verify and supplement
71
- 3. Identifies screen sections asks user which to focus on
72
- 4. Generates **20+ scenarios per viewpoint** (UI/UX, Validation, Logic, Security) for each section
73
- 5. Confirms test plan before generating `.feature` + `test-data.yaml`
71
+ 1. Reads `qa/context.md` for project-wide context (roles, testing strategy, global rules)
72
+ 2. Reads `requirements/spec.md` for screen specs (fields, validation, business rules, states)
73
+ 3. Optionally explores the live page via Playwright MCP to verify and supplement
74
+ 4. Identifies screen sections asks user which to focus on
75
+ 5. Generates **20+ scenarios per viewpoint** (UI/UX, Validation, Logic, Security) for each section
76
+ 6. Confirms test plan before generating `.feature` + `test-data.yaml`
74
77
 
75
78
  ### Step 3: Compile & run tests
76
79