@sun-asterisk/sungen 3.2.32 → 3.2.34-beta.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 (503) hide show
  1. package/dist/cli/commands/audit.d.ts +5 -0
  2. package/dist/cli/commands/audit.d.ts.map +1 -1
  3. package/dist/cli/commands/audit.js +64 -11
  4. package/dist/cli/commands/audit.js.map +1 -1
  5. package/dist/cli/commands/capability.d.ts.map +1 -1
  6. package/dist/cli/commands/capability.js +40 -18
  7. package/dist/cli/commands/capability.js.map +1 -1
  8. package/dist/cli/commands/changed.d.ts.map +1 -1
  9. package/dist/cli/commands/changed.js +2 -3
  10. package/dist/cli/commands/changed.js.map +1 -1
  11. package/dist/cli/commands/dashboard.d.ts.map +1 -1
  12. package/dist/cli/commands/dashboard.js +2 -28
  13. package/dist/cli/commands/dashboard.js.map +1 -1
  14. package/dist/cli/commands/defect.d.ts +7 -0
  15. package/dist/cli/commands/defect.d.ts.map +1 -0
  16. package/dist/cli/commands/defect.js +68 -0
  17. package/dist/cli/commands/defect.js.map +1 -0
  18. package/dist/cli/commands/delivery.d.ts.map +1 -1
  19. package/dist/cli/commands/delivery.js +113 -59
  20. package/dist/cli/commands/delivery.js.map +1 -1
  21. package/dist/cli/commands/generate.d.ts.map +1 -1
  22. package/dist/cli/commands/generate.js +14 -7
  23. package/dist/cli/commands/generate.js.map +1 -1
  24. package/dist/cli/commands/results-merge.d.ts +9 -0
  25. package/dist/cli/commands/results-merge.d.ts.map +1 -1
  26. package/dist/cli/commands/results-merge.js +9 -12
  27. package/dist/cli/commands/results-merge.js.map +1 -1
  28. package/dist/cli/commands/results-sanitize.d.ts.map +1 -1
  29. package/dist/cli/commands/results-sanitize.js +2 -13
  30. package/dist/cli/commands/results-sanitize.js.map +1 -1
  31. package/dist/cli/commands/select.d.ts +12 -0
  32. package/dist/cli/commands/select.d.ts.map +1 -0
  33. package/dist/cli/commands/select.js +122 -0
  34. package/dist/cli/commands/select.js.map +1 -0
  35. package/dist/cli/commands/triage.d.ts +7 -0
  36. package/dist/cli/commands/triage.d.ts.map +1 -0
  37. package/dist/cli/commands/triage.js +98 -0
  38. package/dist/cli/commands/triage.js.map +1 -0
  39. package/dist/cli/commands/update.d.ts.map +1 -1
  40. package/dist/cli/commands/update.js +3 -0
  41. package/dist/cli/commands/update.js.map +1 -1
  42. package/dist/cli/commands/viewpoint.d.ts +7 -0
  43. package/dist/cli/commands/viewpoint.d.ts.map +1 -0
  44. package/dist/cli/commands/viewpoint.js +70 -0
  45. package/dist/cli/commands/viewpoint.js.map +1 -0
  46. package/dist/cli/index.js +13 -2
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/dashboard/snapshot-builder.d.ts.map +1 -1
  49. package/dist/dashboard/snapshot-builder.js +6 -10
  50. package/dist/dashboard/snapshot-builder.js.map +1 -1
  51. package/dist/dashboard/templates/index.html +1 -1
  52. package/dist/dashboard/types.d.ts +1 -0
  53. package/dist/dashboard/types.d.ts.map +1 -1
  54. package/dist/exporters/csv-exporter.d.ts +4 -0
  55. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  56. package/dist/exporters/csv-exporter.js +12 -11
  57. package/dist/exporters/csv-exporter.js.map +1 -1
  58. package/dist/exporters/feature-parser.d.ts +29 -0
  59. package/dist/exporters/feature-parser.d.ts.map +1 -1
  60. package/dist/exporters/feature-parser.js +44 -1
  61. package/dist/exporters/feature-parser.js.map +1 -1
  62. package/dist/exporters/json-exporter.d.ts.map +1 -1
  63. package/dist/exporters/json-exporter.js +7 -0
  64. package/dist/exporters/json-exporter.js.map +1 -1
  65. package/dist/exporters/locale-variants.d.ts +7 -1
  66. package/dist/exporters/locale-variants.d.ts.map +1 -1
  67. package/dist/exporters/locale-variants.js +23 -16
  68. package/dist/exporters/locale-variants.js.map +1 -1
  69. package/dist/exporters/manual-hybrid-oracle.d.ts +54 -0
  70. package/dist/exporters/manual-hybrid-oracle.d.ts.map +1 -0
  71. package/dist/exporters/manual-hybrid-oracle.js +114 -0
  72. package/dist/exporters/manual-hybrid-oracle.js.map +1 -0
  73. package/dist/exporters/matrix/build.d.ts.map +1 -1
  74. package/dist/exporters/matrix/build.js +68 -19
  75. package/dist/exporters/matrix/build.js.map +1 -1
  76. package/dist/exporters/matrix/carry-manual-results.d.ts +89 -0
  77. package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -0
  78. package/dist/exporters/matrix/carry-manual-results.js +302 -0
  79. package/dist/exporters/matrix/carry-manual-results.js.map +1 -0
  80. package/dist/exporters/matrix/export.d.ts +9 -1
  81. package/dist/exporters/matrix/export.d.ts.map +1 -1
  82. package/dist/exporters/matrix/export.js +21 -3
  83. package/dist/exporters/matrix/export.js.map +1 -1
  84. package/dist/exporters/matrix/gates.js +6 -0
  85. package/dist/exporters/matrix/gates.js.map +1 -1
  86. package/dist/exporters/matrix/render-csv.js +1 -1
  87. package/dist/exporters/matrix/render-csv.js.map +1 -1
  88. package/dist/exporters/matrix/render-testcase-sheet.d.ts.map +1 -1
  89. package/dist/exporters/matrix/render-testcase-sheet.js +10 -4
  90. package/dist/exporters/matrix/render-testcase-sheet.js.map +1 -1
  91. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  92. package/dist/exporters/matrix/render-xlsx.js +3 -0
  93. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  94. package/dist/exporters/matrix/types.d.ts +13 -1
  95. package/dist/exporters/matrix/types.d.ts.map +1 -1
  96. package/dist/exporters/matrix/types.js.map +1 -1
  97. package/dist/exporters/matrix/wording.d.ts +8 -1
  98. package/dist/exporters/matrix/wording.d.ts.map +1 -1
  99. package/dist/exporters/matrix/wording.js +37 -2
  100. package/dist/exporters/matrix/wording.js.map +1 -1
  101. package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
  102. package/dist/exporters/playwright-report-parser.js +1 -0
  103. package/dist/exporters/playwright-report-parser.js.map +1 -1
  104. package/dist/exporters/run-environment.d.ts +32 -0
  105. package/dist/exporters/run-environment.d.ts.map +1 -0
  106. package/dist/exporters/run-environment.js +125 -0
  107. package/dist/exporters/run-environment.js.map +1 -0
  108. package/dist/exporters/scenario-merger.d.ts +18 -0
  109. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  110. package/dist/exporters/scenario-merger.js +49 -3
  111. package/dist/exporters/scenario-merger.js.map +1 -1
  112. package/dist/exporters/test-data-resolver.d.ts +0 -4
  113. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  114. package/dist/exporters/test-data-resolver.js +0 -7
  115. package/dist/exporters/test-data-resolver.js.map +1 -1
  116. package/dist/exporters/types.d.ts +5 -0
  117. package/dist/exporters/types.d.ts.map +1 -1
  118. package/dist/exporters/xlsx-exporter.d.ts +2 -0
  119. package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
  120. package/dist/exporters/xlsx-exporter.js +7 -2
  121. package/dist/exporters/xlsx-exporter.js.map +1 -1
  122. package/dist/generators/gherkin-parser/index.d.ts +11 -4
  123. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  124. package/dist/generators/gherkin-parser/index.js +49 -19
  125. package/dist/generators/gherkin-parser/index.js.map +1 -1
  126. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +4 -0
  127. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  128. package/dist/generators/test-generator/adapters/appium/templates/steps/actions/reinstall-app-action.hbs +2 -2
  129. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +8 -2
  130. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/visible-with-role-variable-assertion.hbs +7 -3
  131. package/dist/generators/test-generator/adapters/appium/templates/test-file.hbs +68 -4
  132. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
  133. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
  134. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +7 -1
  135. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +8 -4
  136. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
  137. package/dist/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +5 -1
  138. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
  139. package/dist/generators/test-generator/code-generator.d.ts +2 -1
  140. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  141. package/dist/generators/test-generator/code-generator.js +90 -5
  142. package/dist/generators/test-generator/code-generator.js.map +1 -1
  143. package/dist/generators/test-generator/diagnostics.d.ts +36 -5
  144. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  145. package/dist/generators/test-generator/diagnostics.js +35 -4
  146. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  147. package/dist/generators/test-generator/patterns/index.d.ts +12 -2
  148. package/dist/generators/test-generator/patterns/index.d.ts.map +1 -1
  149. package/dist/generators/test-generator/patterns/index.js +15 -9
  150. package/dist/generators/test-generator/patterns/index.js.map +1 -1
  151. package/dist/generators/test-generator/patterns/types.d.ts +15 -0
  152. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  153. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts +5 -0
  154. package/dist/generators/test-generator/patterns/with-parent-scope.d.ts.map +1 -1
  155. package/dist/generators/test-generator/patterns/with-parent-scope.js +6 -0
  156. package/dist/generators/test-generator/patterns/with-parent-scope.js.map +1 -1
  157. package/dist/generators/test-generator/step-mapper.d.ts +46 -0
  158. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  159. package/dist/generators/test-generator/step-mapper.js +84 -9
  160. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  161. package/dist/generators/test-generator/utils/data-resolver.d.ts +25 -0
  162. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  163. package/dist/generators/test-generator/utils/data-resolver.js +39 -8
  164. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  165. package/dist/generators/test-generator/utils/selector-entry-fields.d.ts.map +1 -1
  166. package/dist/generators/test-generator/utils/selector-entry-fields.js +1 -0
  167. package/dist/generators/test-generator/utils/selector-entry-fields.js.map +1 -1
  168. package/dist/generators/test-generator/utils/selector-resolver.d.ts +37 -4
  169. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  170. package/dist/generators/test-generator/utils/selector-resolver.js +212 -79
  171. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  172. package/dist/harness/audit.d.ts +3 -0
  173. package/dist/harness/audit.d.ts.map +1 -1
  174. package/dist/harness/audit.js +60 -19
  175. package/dist/harness/audit.js.map +1 -1
  176. package/dist/harness/capability.d.ts +7 -1
  177. package/dist/harness/capability.d.ts.map +1 -1
  178. package/dist/harness/capability.js +15 -12
  179. package/dist/harness/capability.js.map +1 -1
  180. package/dist/harness/catalog/universal-viewpoints.yaml +5 -5
  181. package/dist/harness/config-file.d.ts +17 -0
  182. package/dist/harness/config-file.d.ts.map +1 -0
  183. package/dist/harness/config-file.js +100 -0
  184. package/dist/harness/config-file.js.map +1 -0
  185. package/dist/harness/counted-assertions.d.ts +2 -0
  186. package/dist/harness/counted-assertions.d.ts.map +1 -0
  187. package/dist/harness/counted-assertions.js +38 -0
  188. package/dist/harness/counted-assertions.js.map +1 -0
  189. package/dist/harness/data-driven-lint.d.ts.map +1 -1
  190. package/dist/harness/data-driven-lint.js +69 -27
  191. package/dist/harness/data-driven-lint.js.map +1 -1
  192. package/dist/harness/defect-draft.d.ts +14 -0
  193. package/dist/harness/defect-draft.d.ts.map +1 -0
  194. package/dist/harness/defect-draft.js +143 -0
  195. package/dist/harness/defect-draft.js.map +1 -0
  196. package/dist/harness/defects.d.ts +24 -0
  197. package/dist/harness/defects.d.ts.map +1 -0
  198. package/dist/harness/defects.js +118 -0
  199. package/dist/harness/defects.js.map +1 -0
  200. package/dist/harness/depth-lint.d.ts.map +1 -1
  201. package/dist/harness/depth-lint.js +2 -1
  202. package/dist/harness/depth-lint.js.map +1 -1
  203. package/dist/harness/flow-check.d.ts.map +1 -1
  204. package/dist/harness/flow-check.js +6 -2
  205. package/dist/harness/flow-check.js.map +1 -1
  206. package/dist/harness/keyword-match.d.ts +59 -0
  207. package/dist/harness/keyword-match.d.ts.map +1 -0
  208. package/dist/harness/keyword-match.js +86 -0
  209. package/dist/harness/keyword-match.js.map +1 -0
  210. package/dist/harness/manifest.d.ts.map +1 -1
  211. package/dist/harness/manifest.js +2 -2
  212. package/dist/harness/manifest.js.map +1 -1
  213. package/dist/harness/next-step.d.ts +2 -4
  214. package/dist/harness/next-step.d.ts.map +1 -1
  215. package/dist/harness/next-step.js +50 -5
  216. package/dist/harness/next-step.js.map +1 -1
  217. package/dist/harness/parse.d.ts +45 -0
  218. package/dist/harness/parse.d.ts.map +1 -1
  219. package/dist/harness/parse.js +142 -24
  220. package/dist/harness/parse.js.map +1 -1
  221. package/dist/harness/perf.d.ts +7 -1
  222. package/dist/harness/perf.d.ts.map +1 -1
  223. package/dist/harness/perf.js +13 -10
  224. package/dist/harness/perf.js.map +1 -1
  225. package/dist/harness/quality-gates.d.ts +9 -2
  226. package/dist/harness/quality-gates.d.ts.map +1 -1
  227. package/dist/harness/quality-gates.js +22 -8
  228. package/dist/harness/quality-gates.js.map +1 -1
  229. package/dist/harness/query-catalog.js +0 -0
  230. package/dist/harness/query-catalog.js.map +1 -1
  231. package/dist/harness/read-text.d.ts +21 -0
  232. package/dist/harness/read-text.d.ts.map +1 -1
  233. package/dist/harness/read-text.js +32 -1
  234. package/dist/harness/read-text.js.map +1 -1
  235. package/dist/harness/script-check.d.ts.map +1 -1
  236. package/dist/harness/script-check.js +7 -1
  237. package/dist/harness/script-check.js.map +1 -1
  238. package/dist/harness/secret-scan.d.ts +27 -1
  239. package/dist/harness/secret-scan.d.ts.map +1 -1
  240. package/dist/harness/secret-scan.js +57 -4
  241. package/dist/harness/secret-scan.js.map +1 -1
  242. package/dist/harness/select-by-ids.d.ts +31 -0
  243. package/dist/harness/select-by-ids.d.ts.map +1 -0
  244. package/dist/harness/select-by-ids.js +106 -0
  245. package/dist/harness/select-by-ids.js.map +1 -0
  246. package/dist/harness/sensors.d.ts +20 -1
  247. package/dist/harness/sensors.d.ts.map +1 -1
  248. package/dist/harness/sensors.js +133 -39
  249. package/dist/harness/sensors.js.map +1 -1
  250. package/dist/harness/spec-branches.d.ts +0 -18
  251. package/dist/harness/spec-branches.d.ts.map +1 -1
  252. package/dist/harness/spec-branches.js +24 -3
  253. package/dist/harness/spec-branches.js.map +1 -1
  254. package/dist/harness/spec-coverage.d.ts.map +1 -1
  255. package/dist/harness/spec-coverage.js +14 -4
  256. package/dist/harness/spec-coverage.js.map +1 -1
  257. package/dist/harness/triage-signals.d.ts +20 -0
  258. package/dist/harness/triage-signals.d.ts.map +1 -0
  259. package/dist/harness/triage-signals.js +30 -0
  260. package/dist/harness/triage-signals.js.map +1 -0
  261. package/dist/harness/triage-unit.d.ts +23 -0
  262. package/dist/harness/triage-unit.d.ts.map +1 -0
  263. package/dist/harness/triage-unit.js +142 -0
  264. package/dist/harness/triage-unit.js.map +1 -0
  265. package/dist/harness/triage.d.ts +28 -0
  266. package/dist/harness/triage.d.ts.map +1 -0
  267. package/dist/harness/triage.js +99 -0
  268. package/dist/harness/triage.js.map +1 -0
  269. package/dist/harness/ui-inventory.d.ts +40 -0
  270. package/dist/harness/ui-inventory.d.ts.map +1 -0
  271. package/dist/harness/ui-inventory.js +191 -0
  272. package/dist/harness/ui-inventory.js.map +1 -0
  273. package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
  274. package/dist/harness/viewpoint-baseline.js +7 -1
  275. package/dist/harness/viewpoint-baseline.js.map +1 -1
  276. package/dist/harness/viewpoint-draft-header.d.ts +7 -0
  277. package/dist/harness/viewpoint-draft-header.d.ts.map +1 -0
  278. package/dist/harness/viewpoint-draft-header.js +100 -0
  279. package/dist/harness/viewpoint-draft-header.js.map +1 -0
  280. package/dist/harness/viewpoint-ledger.d.ts +13 -3
  281. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  282. package/dist/harness/viewpoint-ledger.js +106 -19
  283. package/dist/harness/viewpoint-ledger.js.map +1 -1
  284. package/dist/harness/viewpoint-mode.d.ts +9 -0
  285. package/dist/harness/viewpoint-mode.d.ts.map +1 -0
  286. package/dist/harness/viewpoint-mode.js +52 -0
  287. package/dist/harness/viewpoint-mode.js.map +1 -0
  288. package/dist/harness/viewpoint-priority.d.ts +19 -0
  289. package/dist/harness/viewpoint-priority.d.ts.map +1 -0
  290. package/dist/harness/viewpoint-priority.js +36 -0
  291. package/dist/harness/viewpoint-priority.js.map +1 -0
  292. package/dist/harness/viewpoint-review-open.d.ts +6 -0
  293. package/dist/harness/viewpoint-review-open.d.ts.map +1 -0
  294. package/dist/harness/viewpoint-review-open.js +90 -0
  295. package/dist/harness/viewpoint-review-open.js.map +1 -0
  296. package/dist/harness/viewpoint-scan-refs.d.ts +50 -0
  297. package/dist/harness/viewpoint-scan-refs.d.ts.map +1 -0
  298. package/dist/harness/viewpoint-scan-refs.js +200 -0
  299. package/dist/harness/viewpoint-scan-refs.js.map +1 -0
  300. package/dist/harness/viewpoint-scan.d.ts +41 -0
  301. package/dist/harness/viewpoint-scan.d.ts.map +1 -0
  302. package/dist/harness/viewpoint-scan.js +118 -0
  303. package/dist/harness/viewpoint-scan.js.map +1 -0
  304. package/dist/harness/write-atomic.d.ts +2 -0
  305. package/dist/harness/write-atomic.d.ts.map +1 -0
  306. package/dist/harness/write-atomic.js +62 -0
  307. package/dist/harness/write-atomic.js.map +1 -0
  308. package/dist/orchestrator/ai-skills/writer.d.ts.map +1 -1
  309. package/dist/orchestrator/ai-skills/writer.js +15 -7
  310. package/dist/orchestrator/ai-skills/writer.js.map +1 -1
  311. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  312. package/dist/orchestrator/assets-drift.js +11 -6
  313. package/dist/orchestrator/assets-drift.js.map +1 -1
  314. package/dist/orchestrator/flow-manager.d.ts +0 -1
  315. package/dist/orchestrator/flow-manager.d.ts.map +1 -1
  316. package/dist/orchestrator/flow-manager.js +3 -52
  317. package/dist/orchestrator/flow-manager.js.map +1 -1
  318. package/dist/orchestrator/project-deps-sync.d.ts.map +1 -1
  319. package/dist/orchestrator/project-deps-sync.js +22 -1
  320. package/dist/orchestrator/project-deps-sync.js.map +1 -1
  321. package/dist/orchestrator/project-initializer.d.ts +8 -0
  322. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  323. package/dist/orchestrator/project-initializer.js +49 -7
  324. package/dist/orchestrator/project-initializer.js.map +1 -1
  325. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  326. package/dist/orchestrator/screen-manager.js +8 -62
  327. package/dist/orchestrator/screen-manager.js.map +1 -1
  328. package/dist/orchestrator/security-overrides-catalog.d.ts +39 -0
  329. package/dist/orchestrator/security-overrides-catalog.d.ts.map +1 -0
  330. package/dist/orchestrator/security-overrides-catalog.js +63 -0
  331. package/dist/orchestrator/security-overrides-catalog.js.map +1 -0
  332. package/dist/orchestrator/security-overrides.d.ts +51 -0
  333. package/dist/orchestrator/security-overrides.d.ts.map +1 -0
  334. package/dist/orchestrator/security-overrides.js +165 -0
  335. package/dist/orchestrator/security-overrides.js.map +1 -0
  336. package/dist/orchestrator/templates/ai-src/agents/discovery.md +11 -3
  337. package/dist/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
  338. package/dist/orchestrator/templates/ai-src/commands/create-test.md +32 -24
  339. package/dist/orchestrator/templates/ai-src/commands/review.md +2 -2
  340. package/dist/orchestrator/templates/ai-src/commands/run-test.md +78 -15
  341. package/dist/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
  342. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -0
  343. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +25 -1
  344. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +26 -8
  345. package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +5 -1
  346. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
  347. package/dist/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +13 -1
  348. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
  349. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
  350. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +18 -0
  351. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +63 -0
  352. package/dist/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +158 -0
  353. package/dist/orchestrator/templates/playwright.config.ts +4 -2
  354. package/dist/orchestrator/templates/specs-locale-fixture.ts +21 -9
  355. package/dist/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  356. package/dist/orchestrator/templates/specs-url-assert.d.ts +17 -1
  357. package/dist/orchestrator/templates/specs-url-assert.d.ts.map +1 -1
  358. package/dist/orchestrator/templates/specs-url-assert.js +38 -4
  359. package/dist/orchestrator/templates/specs-url-assert.js.map +1 -1
  360. package/dist/orchestrator/templates/specs-url-assert.ts +47 -4
  361. package/dist/orchestrator/templates/wdio.conf.ts +24 -1
  362. package/dist/orchestrator/trace-mode-install.d.ts +14 -0
  363. package/dist/orchestrator/trace-mode-install.d.ts.map +1 -0
  364. package/dist/orchestrator/trace-mode-install.js +132 -0
  365. package/dist/orchestrator/trace-mode-install.js.map +1 -0
  366. package/dist/orchestrator/viewpoint-pattern-catalog.d.ts +23 -0
  367. package/dist/orchestrator/viewpoint-pattern-catalog.d.ts.map +1 -0
  368. package/dist/orchestrator/viewpoint-pattern-catalog.js +48 -0
  369. package/dist/orchestrator/viewpoint-pattern-catalog.js.map +1 -0
  370. package/dist/orchestrator/viewpoint-scaffold.d.ts +3 -0
  371. package/dist/orchestrator/viewpoint-scaffold.d.ts.map +1 -0
  372. package/dist/orchestrator/viewpoint-scaffold.js +70 -0
  373. package/dist/orchestrator/viewpoint-scaffold.js.map +1 -0
  374. package/package.json +3 -3
  375. package/src/cli/commands/audit.ts +59 -12
  376. package/src/cli/commands/capability.ts +54 -19
  377. package/src/cli/commands/changed.ts +2 -4
  378. package/src/cli/commands/dashboard.ts +1 -26
  379. package/src/cli/commands/defect.ts +49 -0
  380. package/src/cli/commands/delivery.ts +106 -56
  381. package/src/cli/commands/generate.ts +15 -7
  382. package/src/cli/commands/results-merge.ts +9 -9
  383. package/src/cli/commands/results-sanitize.ts +2 -9
  384. package/src/cli/commands/select.ts +88 -0
  385. package/src/cli/commands/triage.ts +57 -0
  386. package/src/cli/commands/update.ts +3 -0
  387. package/src/cli/commands/viewpoint.ts +58 -0
  388. package/src/cli/index.ts +13 -2
  389. package/src/dashboard/snapshot-builder.ts +6 -8
  390. package/src/dashboard/templates/index.html +1 -1
  391. package/src/dashboard/types.ts +1 -0
  392. package/src/exporters/csv-exporter.ts +12 -11
  393. package/src/exporters/feature-parser.ts +44 -2
  394. package/src/exporters/json-exporter.ts +6 -1
  395. package/src/exporters/locale-variants.ts +23 -17
  396. package/src/exporters/manual-hybrid-oracle.ts +112 -0
  397. package/src/exporters/matrix/build.ts +71 -19
  398. package/src/exporters/matrix/carry-manual-results.ts +292 -0
  399. package/src/exporters/matrix/export.ts +24 -4
  400. package/src/exporters/matrix/gates.ts +6 -0
  401. package/src/exporters/matrix/render-csv.ts +1 -1
  402. package/src/exporters/matrix/render-testcase-sheet.ts +10 -4
  403. package/src/exporters/matrix/render-xlsx.ts +3 -0
  404. package/src/exporters/matrix/types.ts +13 -1
  405. package/src/exporters/matrix/wording.ts +36 -2
  406. package/src/exporters/playwright-report-parser.ts +1 -0
  407. package/src/exporters/run-environment.ts +89 -0
  408. package/src/exporters/scenario-merger.ts +51 -5
  409. package/src/exporters/test-data-resolver.ts +0 -6
  410. package/src/exporters/types.ts +5 -0
  411. package/src/exporters/xlsx-exporter.ts +7 -2
  412. package/src/generators/gherkin-parser/index.ts +50 -18
  413. package/src/generators/test-generator/adapters/adapter-interface.ts +6 -2
  414. package/src/generators/test-generator/adapters/appium/templates/steps/actions/reinstall-app-action.hbs +2 -2
  415. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/label-value-assertion.hbs +8 -2
  416. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/visible-with-role-variable-assertion.hbs +7 -3
  417. package/src/generators/test-generator/adapters/appium/templates/test-file.hbs +68 -4
  418. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/click-select-action.hbs +1 -1
  419. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/select-action.hbs +1 -1
  420. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/label-value-assertion.hbs +7 -1
  421. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/visible-with-role-variable-assertion.hbs +8 -4
  422. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/pick-option.hbs +13 -0
  423. package/src/generators/test-generator/adapters/playwright/templates/steps/partials/url-assertion.hbs +5 -1
  424. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +16 -0
  425. package/src/generators/test-generator/code-generator.ts +77 -5
  426. package/src/generators/test-generator/diagnostics.ts +36 -5
  427. package/src/generators/test-generator/patterns/index.ts +15 -8
  428. package/src/generators/test-generator/patterns/types.ts +15 -0
  429. package/src/generators/test-generator/patterns/with-parent-scope.ts +6 -0
  430. package/src/generators/test-generator/step-mapper.ts +90 -8
  431. package/src/generators/test-generator/utils/data-resolver.ts +41 -12
  432. package/src/generators/test-generator/utils/selector-entry-fields.ts +1 -0
  433. package/src/generators/test-generator/utils/selector-resolver.ts +238 -82
  434. package/src/harness/audit.ts +69 -24
  435. package/src/harness/capability.ts +23 -12
  436. package/src/harness/catalog/universal-viewpoints.yaml +5 -5
  437. package/src/harness/config-file.ts +66 -0
  438. package/src/harness/counted-assertions.ts +33 -0
  439. package/src/harness/data-driven-lint.ts +82 -24
  440. package/src/harness/defect-draft.ts +115 -0
  441. package/src/harness/defects.ts +94 -0
  442. package/src/harness/depth-lint.ts +2 -1
  443. package/src/harness/flow-check.ts +6 -2
  444. package/src/harness/keyword-match.ts +85 -0
  445. package/src/harness/manifest.ts +2 -2
  446. package/src/harness/next-step.ts +47 -5
  447. package/src/harness/parse.ts +151 -27
  448. package/src/harness/perf.ts +15 -7
  449. package/src/harness/quality-gates.ts +22 -8
  450. package/src/harness/query-catalog.ts +0 -0
  451. package/src/harness/read-text.ts +32 -1
  452. package/src/harness/script-check.ts +7 -1
  453. package/src/harness/secret-scan.ts +60 -4
  454. package/src/harness/select-by-ids.ts +83 -0
  455. package/src/harness/sensors.ts +141 -40
  456. package/src/harness/spec-branches.ts +6 -3
  457. package/src/harness/spec-coverage.ts +14 -4
  458. package/src/harness/triage-signals.ts +46 -0
  459. package/src/harness/triage-unit.ts +113 -0
  460. package/src/harness/triage.ts +127 -0
  461. package/src/harness/ui-inventory.ts +164 -0
  462. package/src/harness/viewpoint-baseline.ts +7 -1
  463. package/src/harness/viewpoint-draft-header.ts +55 -0
  464. package/src/harness/viewpoint-ledger.ts +113 -25
  465. package/src/harness/viewpoint-mode.ts +49 -0
  466. package/src/harness/viewpoint-priority.ts +38 -0
  467. package/src/harness/viewpoint-review-open.ts +51 -0
  468. package/src/harness/viewpoint-scan-refs.ts +154 -0
  469. package/src/harness/viewpoint-scan.ts +111 -0
  470. package/src/harness/write-atomic.ts +22 -0
  471. package/src/orchestrator/ai-skills/writer.ts +18 -3
  472. package/src/orchestrator/assets-drift.ts +10 -5
  473. package/src/orchestrator/flow-manager.ts +3 -53
  474. package/src/orchestrator/project-deps-sync.ts +23 -1
  475. package/src/orchestrator/project-initializer.ts +54 -6
  476. package/src/orchestrator/screen-manager.ts +7 -61
  477. package/src/orchestrator/security-overrides-catalog.ts +69 -0
  478. package/src/orchestrator/security-overrides.ts +149 -0
  479. package/src/orchestrator/templates/ai-src/agents/discovery.md +11 -3
  480. package/src/orchestrator/templates/ai-src/agents/reviewer.md +8 -0
  481. package/src/orchestrator/templates/ai-src/commands/create-test.md +32 -24
  482. package/src/orchestrator/templates/ai-src/commands/review.md +2 -2
  483. package/src/orchestrator/templates/ai-src/commands/run-test.md +78 -15
  484. package/src/orchestrator/templates/ai-src/skills/sungen-capture/mode-local.md +2 -2
  485. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +14 -0
  486. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +25 -1
  487. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +26 -8
  488. package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +5 -1
  489. package/src/orchestrator/templates/ai-src/skills/sungen-selector-fix/SKILL.md +58 -14
  490. package/src/orchestrator/templates/ai-src/skills/sungen-selector-keys/SKILL.md +13 -1
  491. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
  492. package/src/orchestrator/templates/ai-src/skills/sungen-tc-review/SKILL.md +7 -0
  493. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/SKILL.md +18 -0
  494. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/review-checklist.md +63 -0
  495. package/src/orchestrator/templates/ai-src/skills/sungen-viewpoint/viewpoint-template.md +158 -0
  496. package/src/orchestrator/templates/playwright.config.ts +4 -2
  497. package/src/orchestrator/templates/specs-locale-fixture.ts +21 -9
  498. package/src/orchestrator/templates/specs-pw-shape-reporter.ts +0 -0
  499. package/src/orchestrator/templates/specs-url-assert.ts +47 -4
  500. package/src/orchestrator/templates/wdio.conf.ts +24 -1
  501. package/src/orchestrator/trace-mode-install.ts +94 -0
  502. package/src/orchestrator/viewpoint-pattern-catalog.ts +61 -0
  503. package/src/orchestrator/viewpoint-scaffold.ts +36 -0
@@ -17,6 +17,8 @@ import {
17
17
  installMobileDriver,
18
18
  } from './mobile-runtime-scaffolder';
19
19
  import { emitAppiumEnvironment, runAppiumEnvironmentSetup, appiumEnvironmentRerunCommand } from './appium-environment-setup';
20
+ import { ensureSecurityOverrides, reportSecurityOverrides } from './security-overrides';
21
+ import { readTextFile } from '../harness/read-text';
20
22
 
21
23
  export { MobileInitOptions };
22
24
 
@@ -94,6 +96,14 @@ export class ProjectInitializer {
94
96
  private cwd: string;
95
97
  private createdItems: string[] = [];
96
98
  private skippedItems: string[] = [];
99
+ /**
100
+ * Actions the user asked for that could NOT be performed. Kept apart from `skippedItems`:
101
+ * that list renders under "Already exists", which is a statement of fact about the project —
102
+ * printing "package.json scripts (invalid JSON)" under it tells the user the opposite of what
103
+ * happened. An action that was not done needs its own heading, or the init summary reads as a
104
+ * clean success while `npm test` is missing.
105
+ */
106
+ private notDoneItems: string[] = [];
97
107
  /** set by createCodexMCPConfig when the project isn't Codex-trusted (config would never load) */
98
108
  private codexTrustWarning = false;
99
109
  private agents: AdapterKey[];
@@ -135,6 +145,7 @@ export class ProjectInitializer {
135
145
  : this.baseCwd;
136
146
  this.createdItems = [];
137
147
  this.skippedItems = [];
148
+ this.notDoneItems = [];
138
149
 
139
150
  console.log(`🚀 Initializing Sungen ${this.mobileOnly ? 'mobile-only ' : ''}project...\n`);
140
151
 
@@ -439,9 +450,17 @@ export class ProjectInitializer {
439
450
 
440
451
  if (existed) {
441
452
  try {
442
- config = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
443
- } catch {
444
- this.skippedItems.push(`${displayName} (invalid JSON, skipped)`);
453
+ // via readTextFile: a UTF-8 BOM is the one thing `JSON.parse` rejects that every other tool
454
+ // reading this file ignores, and it is invisible in an editor. A config the rest of the
455
+ // toolchain loads fine must not cost the user their MCP servers here.
456
+ config = JSON.parse(readTextFile(filePath));
457
+ } catch (e) {
458
+ // Anything still unparseable is genuinely broken. Say WHERE — "is not valid JSON" alone
459
+ // leaves the user to find a missing comma in a file they did not know was the problem.
460
+ this.notDoneItems.push(
461
+ `${displayName} (${(e as Error).message.split('\n')[0]}) — MCP servers not registered; `
462
+ + `fix the JSON and re-run \`sungen init\``,
463
+ );
445
464
  return;
446
465
  }
447
466
  }
@@ -487,6 +506,13 @@ export class ProjectInitializer {
487
506
  });
488
507
  }
489
508
 
509
+ if (this.notDoneItems.length > 0) {
510
+ console.log('\n⚠ Not done — needs your attention:');
511
+ this.notDoneItems.forEach(item => {
512
+ console.log(` ✗ ${item}`);
513
+ });
514
+ }
515
+
490
516
  if (this.codexTrustWarning) {
491
517
  console.log('\n⚠ Codex: this project is not trusted yet, so .codex/config.toml (the MCP browser');
492
518
  console.log(' config for run-test) will be SILENTLY IGNORED by Codex. To fix, either:');
@@ -685,6 +711,13 @@ export class ProjectInitializer {
685
711
  // Ensure standard scripts exist in package.json
686
712
  this.ensurePackageScripts(packageJsonPath);
687
713
 
714
+ // Pin the transitive packages that would otherwise make `npm audit` red here. This MUST happen
715
+ // before the install below: npm reads `overrides` at resolution time, so a lockfile written
716
+ // first would already hold the vulnerable versions. See security-overrides.ts for why the pins
717
+ // cannot simply live in sungen's own manifest.
718
+ const overridePlan = ensureSecurityOverrides(packageJsonPath);
719
+ reportSecurityOverrides(overridePlan);
720
+
688
721
  // Mobile-only drops @playwright/test (no web runner needed). `ajv`/`ajv-formats` back the API
689
722
  // Driver's `expect {{name.body}} matches schema [Ref]` (loaded lazily; harmless if unused).
690
723
  // fast-xml-parser: the API driver's XML request/response support lazy-requires it
@@ -696,7 +729,7 @@ export class ProjectInitializer {
696
729
 
697
730
  let missingDeps: string[] = requiredDeps;
698
731
  try {
699
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
732
+ const packageJson = JSON.parse(readTextFile(packageJsonPath));
700
733
  const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
701
734
  missingDeps = requiredDeps.filter(d => !deps[d]);
702
735
  } catch {
@@ -705,6 +738,12 @@ export class ProjectInitializer {
705
738
 
706
739
  if (missingDeps.length === 0) {
707
740
  console.log('✓ All dependencies already installed\n');
741
+ // Nothing to install means nothing re-resolves, so overrides just written would sit in
742
+ // package.json while the lockfile keeps the vulnerable tree. Re-resolve once so they land.
743
+ if (overridePlan?.add.length) {
744
+ console.log('📦 Re-resolving the tree so the new security overrides take effect...\n');
745
+ execSync('npm install', execOpts);
746
+ }
708
747
  } else {
709
748
  console.log(`📦 Installing ${missingDeps.join(', ')}...\n`);
710
749
  execSync(`npm install -D ${missingDeps.join(' ')}`, execOpts);
@@ -725,8 +764,17 @@ export class ProjectInitializer {
725
764
  private ensurePackageScripts(packageJsonPath: string): void {
726
765
  let packageJson: Record<string, any>;
727
766
  try {
728
- packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
729
- } catch {
767
+ // via readTextFile: a package.json carrying a UTF-8 BOM is one npm reads without complaint,
768
+ // so it must not be treated as unparseable here. That was the trigger that actually reached
769
+ // this catch — genuinely broken JSON aborts `npm install` a few lines below instead.
770
+ packageJson = JSON.parse(readTextFile(packageJsonPath));
771
+ } catch (e) {
772
+ // Returning here used to add nothing and say nothing, so init reported success and the user
773
+ // met `npm error Missing script: "test"` later with nothing pointing back to this run.
774
+ this.notDoneItems.push(
775
+ `package.json scripts (${(e as Error).message.split('\n')[0]}) — `
776
+ + `fix the JSON and re-run \`sungen init\`, or add the scripts by hand`,
777
+ );
730
778
  return;
731
779
  }
732
780
 
@@ -5,10 +5,10 @@
5
5
 
6
6
  import * as fs from 'fs';
7
7
  import * as path from 'path';
8
- import { chromium } from '@playwright/test';
9
8
  import { readCapabilities } from '../harness/capability';
10
9
  import { testDataHeader, ensureTestDataGuideFiles } from './test-data-guide';
11
10
  import { resolveWebBaseUrl } from '../exporters/env-qa';
11
+ import { viewpointScaffold } from './viewpoint-scaffold';
12
12
 
13
13
  export interface ScreenOptions {
14
14
  name: string;
@@ -158,68 +158,11 @@ export class ScreenManager {
158
158
  fs.writeFileSync(specPath, this.generateSpecTemplate(options, screenName), 'utf-8');
159
159
  }
160
160
 
161
- // Generate requirements test-viewpoint.md (only on first screen creation)
161
+ // Generate requirements test-viewpoint.md (only on first screen creation): the QA template,
162
+ // samples inside comments, so an untouched file declares nothing (see viewpoint-scaffold.ts).
162
163
  const viewpointPath = path.join(requirementsDir, 'test-viewpoint.md');
163
164
  if (!fs.existsSync(viewpointPath)) {
164
- fs.writeFileSync(viewpointPath, [
165
- `# ${options.name} — Test Viewpoints`,
166
- '',
167
- '## Edge Cases',
168
- '',
169
- '<!-- Sample — replace with actual edge cases for this screen:',
170
- '- Paste emoji into text fields (e.g., 🎉👋) — should accept or sanitize?',
171
- '- Input 10,000+ characters into free text — truncate or reject?',
172
- '- Double-click Submit rapidly — should only create 1 record',
173
- '- Browser back button after successful submit — should not re-submit',
174
- '-->',
175
- '',
176
- '## Known Issues',
177
- '',
178
- '<!-- Sample — replace with actual known issues:',
179
- '- [BUG-001] Date picker does not work on Safari < 16',
180
- '- [BUG-002] File upload silently fails for files > 20MB (no error shown)',
181
- '- Search does not handle Vietnamese accents correctly ("Nguyên" ≠ "Nguyen")',
182
- '-->',
183
- '',
184
- '## Design Decisions',
185
- '',
186
- '<!-- Sample — replace with actual design decisions:',
187
- '- Show all validation errors at once (not one at a time) — per UX review',
188
- '- Cancel button resets form completely (no draft saving)',
189
- '- Anonymous mode hides sender name but keeps department visible',
190
- '-->',
191
- '',
192
- '## UI Patterns Identified',
193
- '',
194
- '<!-- Check applicable patterns for this screen (from sungen-viewpoint skill):',
195
- '',
196
- '| # | Pattern | Applicable? | Notes |',
197
- '|---|---------|-------------|-------|',
198
- '| 1 | Form & Inputs | ☐ | |',
199
- '| 2 | Data Table | ☐ | |',
200
- '| 3 | Create / Add | ☐ | |',
201
- '| 4 | Update / Edit | ☐ | |',
202
- '| 5 | Delete | ☐ | |',
203
- '| 6 | Search | ☐ | |',
204
- '| 7 | Filter | ☐ | |',
205
- '| 8 | Pagination | ☐ | |',
206
- '| 9 | Modal / Dialog | ☐ | |',
207
- '| 10 | List / Card | ☐ | |',
208
- '-->',
209
- '',
210
- '## Priority Viewpoints',
211
- '',
212
- '<!-- Rate importance for this screen (High / Medium / Low / Skip):',
213
- '',
214
- '| VP | Priority | Reason |',
215
- '|---|----------|--------|',
216
- '| VP-UI | High | Complex form with many states |',
217
- '| VP-VAL | High | 14 validation rules from spec |',
218
- '| VP-LOGIC | Medium | Standard CRUD, no complex business rules |',
219
- '| VP-SEC | Low | Internal tool, basic auth only |',
220
- '-->',
221
- '',
222
- ].join('\n'), 'utf-8');
165
+ fs.writeFileSync(viewpointPath, viewpointScaffold(options.name, isMobile), 'utf-8');
223
166
  }
224
167
 
225
168
  // Auto-screenshot: capture page only when --capture is set and not mobile (requires --path)
@@ -272,6 +215,9 @@ export class ScreenManager {
272
215
 
273
216
  let browser;
274
217
  try {
218
+ // Loaded here, not at module top: @playwright/test is a peerDependency a mobile project never
219
+ // installs, and `sungen add` loads this module on every platform (#865).
220
+ const { chromium } = await import('@playwright/test');
275
221
  browser = await chromium.launch();
276
222
  const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
277
223
  await page.goto(url, { waitUntil: 'networkidle', timeout: 15000 });
@@ -0,0 +1,69 @@
1
+ /**
2
+ * npm `overrides` a sungen project needs in order to pass `npm audit`.
3
+ *
4
+ * Why this lives in the CLI instead of in `packages/core/package.json`: npm honours `overrides`
5
+ * ONLY in the root `package.json` of the project doing the installing. A block declared by a
6
+ * DEPENDENCY is inert — it is not read, not merged, and not carried in the published tarball. So
7
+ * the monorepo root can (and does) pin these for itself while every consumer of the published
8
+ * packages still resolves the vulnerable versions. Repo green, install red, and nobody working in
9
+ * the repo ever sees what a consumer sees. Issue #764.
10
+ *
11
+ * Sungen already writes to the consuming project's `package.json` (standard scripts on `init`,
12
+ * family version pinning on `update`), so the overrides go in on the same two passes. That makes
13
+ * the fix reachable the ordinary way: a new project is clean from its first install, an existing
14
+ * one becomes clean on the next `sungen update`.
15
+ *
16
+ * Every entry below is here because NOTHING ELSE CLEARS IT — the offending package is either at its
17
+ * latest published version already, or is hard-pinned by an unmaintained parent. Bumping sungen's
18
+ * own declared ranges does not move any of them: `@sungen/driver-mobile` is already on the newest
19
+ * appium (3.x) and webdriverio (9.x), and npm's own `fix available` for that chain is a DOWNGRADE
20
+ * to appium 1.22.3 / webdriverio 8.14.6, not a fix.
21
+ *
22
+ * Measured on a clean-room install of the published 3.2.32 family (2026-09-23): 25 findings
23
+ * (12 moderate, 13 high) without this block, 0 with it.
24
+ */
25
+
26
+ export interface SecurityOverride {
27
+ /** Package to pin, as it appears in `overrides`. */
28
+ pkg: string;
29
+ /** Range to pin it to — the lowest published version clear of the advisory. */
30
+ range: string;
31
+ /** Advisory + the path that drags the vulnerable copy in, so a reader can re-check the entry. */
32
+ why: string;
33
+ }
34
+
35
+ /**
36
+ * The pinned set. Keep it MINIMAL: an entry earns its place only while a clean install is red
37
+ * without it. When an upstream finally ships a fix inside its own declared range, delete the entry
38
+ * rather than raising it — a stale override silently holds a whole subtree back.
39
+ */
40
+ export const SECURITY_OVERRIDES: SecurityOverride[] = [
41
+ {
42
+ pkg: 'uuid',
43
+ range: '^11.1.1',
44
+ // exceljs 4.4.0 IS the latest (published 2024-12-20) and hard-declares "uuid": "^8.3.0".
45
+ // There is no newer exceljs to bump to, which is why npm reports fixAvailable: false.
46
+ why: 'GHSA-w5hq-g745-h8pq (moderate) — uuid@8.3.2 via exceljs@4.4.0, which is unmaintained and pins ^8.3.0',
47
+ },
48
+ {
49
+ pkg: 'morgan',
50
+ range: '^1.12.1',
51
+ // @appium/base-driver pins the exact version "1.11.0", so no resolution reaches 1.12.x on its own.
52
+ why: 'GHSA-jxfw-x594-9x9m (moderate) — morgan@1.11.0 exact-pinned by @appium/base-driver',
53
+ },
54
+ {
55
+ pkg: 'serialize-javascript',
56
+ range: '^7.1.2',
57
+ why: 'GHSA-5c6j-r48x-rmvq (high) + GHSA-qj8w-gfj5-8c6v (moderate) — serialize-javascript@6.0.2 via mocha (^6.0.2)',
58
+ },
59
+ {
60
+ pkg: '@puppeteer/browsers',
61
+ range: '^3.2.3',
62
+ // The vulnerable package is extract-zip, whose latest (2.0.1) IS the flagged version — there is
63
+ // nothing to pin it to. @puppeteer/browsers 3.x dropped extract-zip for modern-tar, so the pin
64
+ // goes on the parent instead. @wdio/utils asks for ^2.2.0 but imports only install, canDownload,
65
+ // resolveBuildId, detectBrowserPlatform, Browser, ChromeReleaseChannel and computeExecutablePath
66
+ // — all seven still exported by 3.2.3, verified against @wdio/utils@9.32.0.
67
+ why: 'GHSA-jmr9-qjv8-65gv + GHSA-7pqw-9j4j-h8q3 (high) — extract-zip@2.0.1 via @puppeteer/browsers@2.x ← @wdio/utils; extract-zip has no fixed release, 3.x replaced it with modern-tar',
68
+ },
69
+ ];
@@ -0,0 +1,149 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { SECURITY_OVERRIDES, SecurityOverride } from './security-overrides-catalog';
4
+
5
+ /**
6
+ * Merge the security-override catalog into a consuming project's `package.json`.
7
+ *
8
+ * The catalog itself — which packages, which ranges, and why each one cannot be cleared any other
9
+ * way — lives in `security-overrides-catalog.ts`. That is the file to edit when an advisory moves;
10
+ * this one holds only the merge, the write and the reporting, which do not change when it does.
11
+ */
12
+
13
+ export { SECURITY_OVERRIDES } from './security-overrides-catalog';
14
+ export type { SecurityOverride } from './security-overrides-catalog';
15
+
16
+ export interface OverridePlan {
17
+ /** Entries missing from the project, to be written. */
18
+ add: SecurityOverride[];
19
+ /** Entries the project already pins itself — left untouched, reported so the user can judge. */
20
+ existing: Array<{ pkg: string; declared: string; wanted: string }>;
21
+ /** Set when the pins were needed but the write failed — `add` is then empty, nothing was applied. */
22
+ writeFailed?: boolean;
23
+ /** Lockfile of a package manager that ignores `overrides`, when the project has one. */
24
+ foreignLockfile?: 'yarn' | 'pnpm';
25
+ }
26
+
27
+ /**
28
+ * Decide what a project's `overrides` block is missing. Pure — no I/O, so the tests and `--dry-run`
29
+ * can plan without touching anything.
30
+ *
31
+ * A pin the project already declares is NEVER rewritten, even when it differs from ours. Someone who
32
+ * typed a range into their own `package.json` had a reason (a private mirror, a pinned fork, a
33
+ * downgrade forced by another tool), and silently overwriting it would be the more surprising bug.
34
+ * It is reported instead, so a still-vulnerable pin is visible rather than swallowed.
35
+ */
36
+ export function planSecurityOverrides(pkgJson: Record<string, any>): OverridePlan {
37
+ const current: Record<string, unknown> =
38
+ pkgJson.overrides && typeof pkgJson.overrides === 'object' ? pkgJson.overrides : {};
39
+
40
+ const add: SecurityOverride[] = [];
41
+ const existing: OverridePlan['existing'] = [];
42
+
43
+ for (const entry of SECURITY_OVERRIDES) {
44
+ const declared = current[entry.pkg];
45
+ if (typeof declared === 'string') {
46
+ if (declared !== entry.range) existing.push({ pkg: entry.pkg, declared, wanted: entry.range });
47
+ continue;
48
+ }
49
+ // A nested override object ({ "uuid": { ".": "^11" } }) is a deliberate, more specific shape —
50
+ // treat it as the project's own decision and leave it alone.
51
+ if (declared !== undefined) {
52
+ existing.push({ pkg: entry.pkg, declared: JSON.stringify(declared), wanted: entry.range });
53
+ continue;
54
+ }
55
+ add.push(entry);
56
+ }
57
+
58
+ return { add, existing };
59
+ }
60
+
61
+ /**
62
+ * Write the missing overrides into a project's `package.json`.
63
+ *
64
+ * Best-effort by design, exactly like the rest of the project-file touching in `init` / `update`: an
65
+ * unreadable or malformed `package.json` means we skip silently rather than fail the command the
66
+ * user actually ran. The audit gate is not worth losing a scaffold over.
67
+ *
68
+ * Must run BEFORE the project's `npm install`, or the first resolution pass writes a lockfile that
69
+ * already pins the vulnerable versions.
70
+ *
71
+ * @param dryRun plan only — report what would change and write nothing
72
+ * @returns the plan that was applied, or null when there was no `package.json` to apply it to
73
+ */
74
+ export function ensureSecurityOverrides(packageJsonPath: string, dryRun = false): OverridePlan | null {
75
+ let pkgJson: Record<string, any>;
76
+ try {
77
+ pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
78
+ } catch {
79
+ return null;
80
+ }
81
+
82
+ const plan = planSecurityOverrides(pkgJson);
83
+ plan.foreignLockfile = detectForeignLockfile(path.dirname(packageJsonPath));
84
+
85
+ if (plan.add.length && !dryRun) {
86
+ const overrides: Record<string, unknown> =
87
+ pkgJson.overrides && typeof pkgJson.overrides === 'object' ? pkgJson.overrides : {};
88
+ for (const entry of plan.add) overrides[entry.pkg] = entry.range;
89
+ pkgJson.overrides = overrides;
90
+ try {
91
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8');
92
+ } catch {
93
+ // Read-only checkout, root-owned file, read-only container mount. `sungen update` in
94
+ // particular has ALREADY reinstalled globally by the time it gets here, so throwing would
95
+ // abandon the AI-rules refresh and the family sync over a hardening step. Report and move on.
96
+ return { add: [], existing: plan.existing, foreignLockfile: plan.foreignLockfile, writeFailed: true };
97
+ }
98
+ }
99
+
100
+ return plan;
101
+ }
102
+
103
+ /**
104
+ * npm is the only package manager that reads a top-level `overrides` block. Yarn wants
105
+ * `resolutions`, pnpm wants `pnpm.overrides` — so on those projects the block we write is inert and
106
+ * the install stays vulnerable. We do NOT guess at the equivalent field (getting a resolutions
107
+ * pattern subtly wrong is worse than not writing one), but silence would be the same class of bug
108
+ * as #764 itself: a fix that looks applied and is not. So: say so.
109
+ */
110
+ function detectForeignLockfile(dir: string): 'yarn' | 'pnpm' | undefined {
111
+ if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
112
+ if (fs.existsSync(path.join(dir, 'yarn.lock'))) return 'yarn';
113
+ return undefined;
114
+ }
115
+
116
+ /** Print what `ensureSecurityOverrides` did, in the voice the surrounding commands already use. */
117
+ export function reportSecurityOverrides(plan: OverridePlan | null, dryRun = false): void {
118
+ if (!plan) return;
119
+
120
+ if (plan.writeFailed) {
121
+ console.warn(
122
+ '⚠️ Could not write the security overrides into package.json (read-only file?). Nothing else\n' +
123
+ ' failed. Add this block by hand to keep `npm audit` clean:\n' +
124
+ ` "overrides": ${JSON.stringify(Object.fromEntries(SECURITY_OVERRIDES.map((o) => [o.pkg, o.range])), null, 2).replace(/\n/g, '\n ')}\n`,
125
+ );
126
+ return;
127
+ }
128
+
129
+ if (plan.add.length) {
130
+ const verb = dryRun ? '[dry-run] would add' : 'Added';
131
+ console.log(`🔒 ${verb} ${plan.add.length} security override(s) to package.json — npm honours these only here, not from sungen's own manifest:`);
132
+ for (const entry of plan.add) console.log(` • ${entry.pkg}@${entry.range} — ${entry.why}`);
133
+ console.log('');
134
+ }
135
+
136
+ if (plan.existing.length) {
137
+ console.log('🔒 Left your own overrides alone (sungen never rewrites a pin you declared):');
138
+ for (const e of plan.existing) console.log(` – ${e.pkg}: ${e.declared} (sungen would use ${e.wanted})`);
139
+ console.log(' If `npm audit` still flags one of these, raise it by hand.\n');
140
+ }
141
+
142
+ if (plan.foreignLockfile && (plan.add.length || plan.existing.length)) {
143
+ const field = plan.foreignLockfile === 'pnpm' ? '"pnpm": { "overrides": … }' : '"resolutions"';
144
+ console.warn(
145
+ `⚠️ This project has a ${plan.foreignLockfile} lockfile. ${plan.foreignLockfile} ignores npm's "overrides" —\n` +
146
+ ` mirror the block into ${field} as well, or the pins do nothing here.\n`,
147
+ );
148
+ }
149
+ }
@@ -9,7 +9,9 @@ You are a **test-design context explorer**. You run in an **isolated context** s
9
9
  ## Explore (do NOT ask the user to pick a source — read all that exist)
10
10
  - `requirements/spec.md` — primary behavior source.
11
11
  - `requirements/spec_figma.md` — Figma supplement (if present; do NOT call Figma MCP when this exists).
12
- - `requirements/ui/*` images — layout/visual context.
12
+ - `requirements/ui/*` images — read **every** image (group primary vs states/variants when there are many, but open them all).
13
+ - `requirements/ui/figma-meta.md` — Figma MCP capture: `## Components`, `## Text Content`.
14
+ - `requirements/ui-inventory.md` — an existing Design Inventory: keep its `UI-NNN` ids.
13
15
  - Live page — only if a base URL is configured and reachable: `browser_navigate` + `browser_snapshot` for real element roles/names. Fall back gracefully if it requires login / fails.
14
16
 
15
17
  ## Cross-check
@@ -20,7 +22,13 @@ Flag any **conflicts** between sources (field names, labels, behavior, states th
20
22
  SOURCES: spec=<yes/no, completeness high|med|low> | figma=<...> | ui=<n images> | live=<reached|offline>
21
23
  PAGE TYPE: <e.g. ecommerce-list / form / auth / ...>
22
24
  RECOMMENDED ROUTE: <spec-first | source-first | ...> — authoritative source: <which>
23
- CONFLICTS: <list, or "none">
25
+ CONFLICTS: <list, or "none"> — each conflict on a design item also appears in UI INVENTORY with source `conflict`
26
+ UI INVENTORY: images read: <read>/<total> · figma-meta.md: <read|absent> · spec_figma.md: <read|absent>
27
+ | UI-001 | <item> | <component|column|button|field|state|annotation> | spec+design | <image> |
28
+ | UI-014 | <item> | column | design-only | <image> |
29
+ | UI-015 | <item> | column | conflict — <how spec and design disagree> | <image> |
30
+ → one row per item the design shows (format and id rules: `sungen-tc-generation` § Design Inventory);
31
+ omit the block only when the unit has no design source
24
32
  KEY FACTS (condensed):
25
33
  - Sections: <list>
26
34
  - Fields/validation: <key constraints + exact error messages>
@@ -29,4 +37,4 @@ KEY FACTS (condensed):
29
37
  ASSUMPTIONS / MISSING INFO: <what's unknown — to be marked in output>
30
38
  ```
31
39
 
32
- Keep it tight. Do not generate test cases — that is the orchestrator's job. Do not write files.
40
+ Keep it tight — except UI INVENTORY, which is listed in full: it is the checklist the orchestrator writes to `ui-inventory.md`. Do not generate test cases — that is the orchestrator's job. Do not write files.
@@ -10,6 +10,8 @@ You are an **independent Senior QA Reviewer**. You did **not** write these tests
10
10
  - `qa/<screens|flows>/<name>/features/<name>.feature` — the scenarios under review.
11
11
  - `qa/<screens|flows>/<name>/requirements/test-viewpoint.md` — the viewpoint overview (priority).
12
12
  - `qa/<screens|flows>/<name>/requirements/spec.md` — source of truth for behavior.
13
+ - `qa/<screens|flows>/<name>/requirements/ui/*` images, `ui/figma-meta.md`, `spec_figma.md` — the design, when present. Open **every** image.
14
+ - `qa/<screens|flows>/<name>/requirements/ui-inventory.md` — the Design Inventory create-test wrote (`UI-NNN` rows).
13
15
  - `.sungen/reports/<name>-audit.json` — the deterministic findings (don't repeat them; go deeper).
14
16
 
15
17
  ## What to judge (semantic — the gate misses these)
@@ -25,6 +27,7 @@ You are an **independent Senior QA Reviewer**. You did **not** write these tests
25
27
  - **Flows self-clean.** A CRUD/auth chain deletes what it created (final `@api:delete_*`) or is `@cleanup`-tagged.
26
28
  - **Idempotency uses the DB oracle.** A "no double-charge / exactly once" claim is proven by `@concurrent` + a `@query` count, not HTTP status alone (status can lie under a race).
27
29
  - **Auth negatives** exist for protected mutations (401/403), not just the happy path.
30
+ 7. **Design ↔ Feature** (only when the unit holds design sources). Read the design yourself — do not trust the inventory to be complete. Report: items the design shows that are **missing from `ui-inventory.md`**; inventory items **mislabelled** `spec+design` that `spec.md` never names (design-only) or names differently (conflict); and `design-only`/`conflict` items whose `@ui:` scenario does not actually prove them, or whose `# UI-DEFERRED:` reason does not hold. The audit only sees what the inventory lists — you are the check on the inventory itself.
28
31
 
29
32
  ## Output (do NOT edit any file)
30
33
  Return a concise verdict:
@@ -38,6 +41,11 @@ ISSUES (most important first):
38
41
  FIX: <the exact Gherkin step(s) to add/change>
39
42
  2. ...
40
43
 
44
+ DESIGN DIFF (omit when the unit has no design source):
45
+ - not inventoried: <item> (<image>)
46
+ - mislabelled: UI-NNN <item> — is <design-only|conflict>, not spec+design
47
+ - unproven: UI-NNN <item> — <why the @ui scenario / deferral does not hold>
48
+
41
49
  STRENGTHS: <1-2 lines, what is genuinely good>
42
50
  ```
43
51
 
@@ -64,7 +64,8 @@ restated from screen specs the project does not hold, say so: the audit reports
64
64
  `SPEC-RESTATED-UNVERIFIED` because `specFR 100%` over a hand-copied list certifies the copy, not
65
65
  the source.
66
66
 
67
- **The viewpoint carries BOTH classification axes.** `VP-LOGIC / VP-VAL / VP-SEC / VP-NAV` classify
67
+ **A viewpoint you draft (mode 2, step 3) carries BOTH classification axes** — on a QA-written one
68
+ (mode 1) a missing axis or guarantee line is a row in `viewpoint-review.md`, not an edit. `VP-LOGIC / VP-VAL / VP-SEC / VP-NAV` classify
68
69
  by TECHNICAL RISK; `BF / AF / EF` classify by BUSINESS BRANCH. They answer different questions and
69
70
  neither replaces the other — a reviewer needs to see both, so use the compound id
70
71
  (`VP-SEC-EF02-001`) and give the viewpoint a section per flow as well as its priority table by
@@ -81,8 +82,8 @@ questions and only one of them is a yardstick:
81
82
  | `flow-contract.yaml` | the USE CASE — actor · trigger · goal · precondition · both guarantees · the flow inventory | `flowCoverage` |
82
83
  | `test-viewpoint.md` | the CLAIMS the suite must prove — cross-screen concerns, edge cases, design decisions, open questions, priorities | `atomicLedger` · `traceability` |
83
84
 
84
- If `requirements/test-viewpoint.md` is missing, **write it before generating** (`add-flow` scaffolds
85
- a template; a run that deletes or replaces it has removed the yardstick). Without it two scored
85
+ If `requirements/test-viewpoint.md` is missing or still the scaffold, **draft it before generating**
86
+ (mode 2, step 3 — `add-flow` scaffolds the template; a run that deletes or replaces it has removed the yardstick). Without it two scored
86
87
  axes are excluded and four sensors cannot run at all — the atomic ledger, the
87
88
  declaration-integrity checks, the browser-gesture check and the two-way continuity check — so the
88
89
  audit reports `VIEWPOINT-MISSING` and the result is *unmeasured*, not passing. And the reason the
@@ -95,8 +96,8 @@ ordering choice: a yardstick derived from the scenarios reads 100% by constructi
95
96
  dropped along the way stops being missing from anything. `sungen audit` now reports
96
97
  `VIEWPOINT-ADOPTED-POST-HOC` on the first sighting of a viewpoint alongside an existing suite and
97
98
  holds `atomicLedger` + `traceability` as unverified until a human accepts it — so the honest move
98
- is to write the claims from `spec.md` and the contract, mark plainly that they are a draft for QA
99
- review, and let the QA revise before `--accept-viewpoint`. **You never run `--accept-viewpoint` yourself** — `sungen next` lists it as a `⚖ decide` step for exactly this reason: an agent accepting the yardstick it wrote in the same session makes `atomicLedger` and `traceability` read 100% against its own checklist, and the Exception Flow it forgot stops being missing from anything. Present the acceptance to the QA (`AskUserQuestion`) with what the file declares, and stop.
99
+ is to write the claims from `spec.md` and the contract, mark the file `drafted-by: ai` (its first
100
+ line), and let the QA revise before `--accept-viewpoint`. **You never run `--accept-viewpoint` yourself** — `sungen next` lists it as a `⚖ decide` step for exactly this reason: an agent accepting the yardstick it wrote in the same session makes `atomicLedger` and `traceability` read 100% against its own checklist, and the Exception Flow it forgot stops being missing from anything. Present the acceptance to the QA in the hand-back (`AskUserQuestion`) with what the file declares — never as a question mid-run.
100
101
 
101
102
  **When you give a claim an id, a scenario must carry that id.** The id is the contract: a claim
102
103
  whose id no scenario carries is reported MISSING, and word overlap will not rescue it. Several
@@ -110,8 +111,9 @@ narrow the claim to what is actually proven.
110
111
 
111
112
  **Priority comes from the declaration.** A scenario tagged `@high` under a viewpoint row that says
112
113
  `Low` is `PRIORITY-CONTRADICTED` — a smoke run selects on the tag, so it picks up work the QA
113
- deliberately deprioritised. Inherit the declared priority; if the tag is right, fix the
114
- declaration instead of leaving both on record.
114
+ deliberately deprioritised. Inherit the declared priority; if the tag is right, the declaration is
115
+ what is wrong — fix it in your own draft (mode 2), or report it in `viewpoint-review.md` for the QA
116
+ (mode 1). Never leave both on record silently.
115
117
 
116
118
  ---
117
119
 
@@ -205,26 +207,15 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
205
207
  **Screen requirements** — check `<base>/${input:name}/requirements/`:
206
208
  {{/cap}}
207
209
  - If `spec.md` exists → read it as PRIMARY source (sections, fields, validation rules, business rules, states).
210
+ - `test-viewpoint.md` → **Viewpoint — review or draft** below, once every source is read. No question here.
208
211
  {{#cap parallel-subagents}}
209
- - If `test-viewpoint.md` exists → read it. If it only contains HTML comments (scaffold template), use `AskUserQuestion` to ask:
210
- - **Fill test-viewpoint.md first** — I'll help you identify edge cases, known issues, and design decisions for this screen before generating tests
211
- - **Continue without it** — generate tests from spec and other sources only
212
-
213
- **A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations as part of generating tests. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch and ask** — propose the diff (ids added / removed and why) and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves, so an unannounced rewrite lowers the score rather than raising it.
214
212
 
215
213
  **Context discovery (prefer an isolated agent).** Reading all sources here can flood this context. **Claude Code:** spawn the **`sungen-discovery`** sub-agent (Task tool, `subagent_type: sungen-discovery`) to read spec/figma/ui/live in isolation and return a **compact discovery report** (sources, completeness, conflicts, recommended route, key facts); use that report instead of pasting raw sources. **Copilot / no sub-agents:** do the reading inline as below.
216
214
  {{/cap}}
217
- {{^cap parallel-subagents}}
218
- - If `test-viewpoint.md` exists → read it. If it only contains HTML comments (scaffold template), ask:
219
- - **1) Fill test-viewpoint.md first** — identify edge cases, known issues, and design decisions before generating tests
220
- - **2) Continue without it** — generate tests from spec and other sources only
221
-
222
- **A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations while generating tests. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch and ask** — propose the diff (ids added / removed and why) and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves.
223
- {{/cap}}
224
215
 
225
216
  **Auto-detect visual source** — do NOT ask the user to pick a source. Instead, check what already exists and use it:
226
217
  1. If `spec_figma.md` exists → read it as Figma supplement (PAT flow already completed during `add-screen`). Do NOT call any `mcp__figma__*` tool.
227
- 2. If `ui/` has images (`.png`, `.jpg`, etc.) → read them for visual context (layout, element positions, states).
218
+ 2. If `ui/` has images (`.png`, `.jpg`, etc.) or `ui/figma-meta.md` → read **all** of them; they feed the Design Inventory (below), not just visual context.
228
219
  {{#cap parallel-subagents}}
229
220
  3. If neither exists → use `AskUserQuestion` to ask: *"No visual source found. Pick one:"* — then invoke the **`sungen-capture`** skill with the matching **mode** (read only that mode's file):
230
221
  - **Figma PAT** — ask for URL, run `sungen add --screen <screen> --figma '<url>'` via Bash, then `sungen-capture` **mode figma-pat**
@@ -242,7 +233,19 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
242
233
 
243
234
  (When `spec_figma.md` exists, that is also `sungen-capture` **mode figma-pat**; when `ui/` images exist, that is **mode local**.)
244
235
 
245
- **Cross-check**: if both `spec.md` and visual sources exist, flag any discrepancies (missing fields, different labels) before moving on. When `spec_figma.md` is present, follow the Figma supplement rules in `sungen-tc-generation` skill (reading order, Text Inventory, conflict handling).
236
+ **Cross-check + Design Inventory**: when the unit holds any design source (`ui/` images, `ui/figma-meta.md`, `spec_figma.md`), follow `sungen-tc-generation` § **Design Inventory** (reading order, one `UI-NNN` row per item, `spec+design` / `design-only` / `conflict`) and **write `requirements/ui-inventory.md`** before generating — from the discovery report's UI INVENTORY block when a sub-agent read the sources. Every `design-only` / `conflict` item must then be covered (`@ui:UI-NNN`) or deferred with a reason (`# UI-DEFERRED: UI-NNN — <reason>`) in the `.feature`; `sungen audit` reports `UI-ITEM-UNCOVERED` otherwise. Show the user the conflicts and design-only items — they are decisions, not details.
237
+
238
+ **Viewpoint — review or draft (no question asked).** Run `sungen viewpoint scan --screen <name> --json` (a flow: `--flow <name>`). It reads ids and item numbers only. Its `mode` (1 or 2) and `modeReason` name the row below — follow them; the table explains them:
239
+
240
+ | `requirements/test-viewpoint.md` | Mode | You |
241
+ |---|---|---|
242
+ | missing; nothing but the scaffold (headings, `<…>` placeholders, empty tables); or ONE OR MORE VP rows and every one of them lacks a `Kỳ vọng` | **2 — draft** | Write it from `sungen-viewpoint/viewpoint-template.md`, first line `drafted-by: ai`, keeping any row already there. Each row answers "test CÁI GÌ" and "kỳ vọng ra sao"; where the spec states the expected result, write it; only what the spec leaves open becomes a closed question in mục 5, never an invented expectation; every accepted-input class the spec names (whitelist, value list, conversion) gets an "accepted, no error" row, citing the list by name; a VP that needs a real device, account or time is `# MANUAL/ENV`. Then scan again. |
243
+ | first line `drafted-by: ai` | **2 — re-review** | Your draft, not yet accepted: you may revise it, from the spec and the review. |
244
+ | anything else — QA-written, with or without VP ids (a scaffold from an older sungen reads as this row too: delete the file to have it drafted) | **1 — review only** | Never edit it. Generate from it as written; a gap is reported, not filled. |
245
+
246
+ Then review it with `sungen-viewpoint/review-checklist.md` and the scan JSON (mode 2: fix your draft until only QA decisions remain) and write `requirements/viewpoint-review.md`, overwritten each run. Mode 2 also runs `sungen audit --screen <name> --no-baseline` before generating. Keep the review's row count for the hand-back.
247
+
248
+ **A filled `test-viewpoint.md` is an INPUT — never an output.** Do NOT rewrite, re-order, or replace its viewpoint declarations as part of generating tests — your own draft included: a draft is revised from the spec, never from the scenarios. It is the yardstick two scored axes measure the suite against (`traceability`, `atomicLedger`): rewrite it to match what you just generated and both read 100% by construction, while any viewpoint you quietly dropped stops being missing from anything. If the declared taxonomy genuinely does not fit the screen, **report the mismatch in `viewpoint-review.md`** — the diff (ids added / removed and why) — and let the QA decide. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and stops scoring both axes when this file moves, so an unannounced rewrite lowers the score rather than raising it.
246
249
 
247
250
  Summarize what you found in requirements and present to the user.
248
251
 
@@ -284,6 +287,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
284
287
  - **BALANCE** → stop expanding secondary viewpoints; add business-core scenarios first.
285
288
  - **TRACE** → align `VP-` ids with the viewpoint-overview.
286
289
  - Stop when the gate PASSes and findings clear, **or** the budget is exhausted → report residual gaps honestly (never fake a pass).
290
+ - **Repair never edits a QA-written viewpoint (mode 1).** A finding whose fix is an edit to `test-viewpoint.md` becomes a row in `viewpoint-review.md` for the QA when it cites one of the file's VP ids (the checklist's audit rule; anything else goes in the hand-back); in a mode-2 draft, fix the draft.
287
291
 
288
292
  5.6. **Record (reuse + observability).** Build the manifest and report usage:
289
293
  - `sungen manifest --screen <name>` — fingerprints for next-run change detection. On a **re-run**, start the whole command by `sungen manifest --screen <name> --diff` and only regenerate scenarios whose spec section changed (keep/regenerate/retire).
@@ -297,7 +301,7 @@ If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the d
297
301
  > **No parallel fan-out here.** Copilot has no sub-agents, so generation is sequential (the Claude Code variant fans out one `sungen-generator` per viewpoint group and merges). Same output, no speedup.
298
302
  5.3. **Standardize field test-data — Data Factory (when the unit has input fields).** For each input field, author the field-map `qa/data-factory/<name>.fields.yaml` (field → catalog `type` + real `constraints` + `errorMap`), then run `sungen data lint --screen ${input:name}` and `sungen data gen --screen ${input:name}` per the **`sungen-data-factory`** skill. `data gen` **MERGES** into `test-data.yaml` (replaces only its field keys, preserves the rest), so it is safe here. Weave the standardized boundary/invalid sets into `@cases` with `CHK-*` trace. Then `… data validate` (values correct) + `… data crosscheck` (testcase↔data agree); for a stateful precondition, `… data state --scaffold <name>` to auto-draft → fill entities + confirm with QA → `… data state`, weave the `@manual:data-setup` `Background` (works spec+viewpoint only). **Same standard as `/sungen:create-data-test`, applied inline — do NOT run that command separately afterwards.** No input fields (navigation/list) → skip.
299
303
  5.4. **Depth self-check (deterministic — BEFORE the audit).** Run `sungen depth-lint --screen ${input:name}`. It splits every shallow business-critical scenario into **DEEPEN IN PLACE** (add a real value assertion — the printed `template` is a theme-keyed hint, apply judgment to the actual claim; never fake one onto a visibility/behavior scenario) and **CROSS-SCREEN** (route to a flow / tag `@manual:Mx` + reason — removes it from the depth denominator honestly). Act on both, re-run until `deepen` is empty (or only honest over-counts remain), THEN gate. Lifts first-pass `businessDepth` mechanically instead of via 2–3 repair rounds.
300
- 5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria (does each scenario's steps PROVE its title/viewpoint? observable Thens? business-critical assertion depth?). Merge both sets of issues; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass.
304
+ 5.5. **Quality gate & repair (harness — always run).** Per `sungen-harness-audit`: run `sungen audit --screen ${input:name}` (structural), THEN do an **independent semantic review inline** using the `sungen-reviewer` criteria (does each scenario's steps PROVE its title/viewpoint? observable Thens? business-critical assertion depth?). Merge both sets of issues; if gate FAILs / findings exist, repair (budget 3) and re-audit — GATE missing theme → generate it (cross-screen → **automate it in the flow** via `/sungen:add-flow`, NOT a full `@manual` screen duplicate — `sungen audit` flags an automatable `@manual` as `MANUAL-AUTOMATABLE`; reserve `@manual:Mx` for true judgment/missing-capability); DEPTH → add data assertions; BALANCE → add business-core first; TRACE → align VP ids. Never fake a pass. Repair never edits a QA-written viewpoint (mode 1): a finding whose fix is an edit to `test-viewpoint.md` and cites one of its VP ids becomes a row in `viewpoint-review.md`; in a mode-2 draft, fix the draft.
301
305
  5.6. **Record.** `sungen manifest --screen ${input:name}`. Ledger **each phase** (not just repair) — pick one `runId` at the start and pass it so `trace`/`ledger report` show THIS run, not a mix: `sungen ledger record --screen ${input:name} --run <runId> --step <discovery|viewpoint|gherkin|audit|repair:N> --ms <elapsed>`. On re-run, start with `sungen manifest --screen ${input:name} --diff` and only regenerate changed sections.
302
306
  6. **Converge — show the trace.** Run `sungen trace --screen ${input:name}` and present: process map (phases + repair rounds), bottlenecks, **HUMAN-LOOP FOCUS** (@manual to verify), audit score + gate + residual gaps. Then offer next steps based on which tier was just generated:
303
307
  {{/cap}}
@@ -363,9 +367,13 @@ Do not stop after writing the files. Close every run with, in this order:
363
367
  1. **The traceability check below** — an untagged requirement becomes an uncovered gap at delivery.
364
368
  2. **The harness result in one line** — score, gate verdict, and the axis the `SCORE-CAPPED` finding
365
369
  names (that finding is the single answer to "how do I raise the score").
366
- 3. **`AskUserQuestion` with the next actions** — never end with prose alone. Offer
370
+ 3. **The viewpoint review in one line** — `Viewpoint review: N điểm cần QA xem` (N = the `[ ]` rows
371
+ of `requirements/viewpoint-review.md`).
372
+ 4. **`AskUserQuestion` with the next actions** — never end with prose alone. Offer
367
373
  `/sungen:run-test <name>` (recommended once the tiers are written), re-running `create-test` to
368
- extend, and "Done for now". A run that ends without this leaves the operator guessing.
374
+ extend, "Mở viewpoint-review.md" when N > 0, and "Done for now". After a mode-2 draft also list
375
+ the decision `sungen audit --screen <name> --accept-viewpoint` — for the QA to run once the draft
376
+ is reviewed; you never run it yourself. A run that ends without this leaves the operator guessing.
369
377
 
370
378
  ### Requirement traceability
371
379