@sun-asterisk/sungen 3.2.34 → 3.3.0-alpha.2

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 (889) hide show
  1. package/dist/basis/anchor-grammar.d.ts +32 -0
  2. package/dist/basis/anchor-grammar.d.ts.map +1 -0
  3. package/dist/basis/anchor-grammar.js +82 -0
  4. package/dist/basis/anchor-grammar.js.map +1 -0
  5. package/dist/basis/anchor-hash.d.ts +6 -0
  6. package/dist/basis/anchor-hash.d.ts.map +1 -0
  7. package/dist/basis/anchor-hash.js +28 -0
  8. package/dist/basis/anchor-hash.js.map +1 -0
  9. package/dist/basis/bm51-tables.d.ts +20 -0
  10. package/dist/basis/bm51-tables.d.ts.map +1 -0
  11. package/dist/basis/bm51-tables.js +71 -0
  12. package/dist/basis/bm51-tables.js.map +1 -0
  13. package/dist/basis/extract-spec-anchors.d.ts +39 -0
  14. package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
  15. package/dist/basis/extract-spec-anchors.js +81 -0
  16. package/dist/basis/extract-spec-anchors.js.map +1 -0
  17. package/dist/basis/migration-sentinel.d.ts +47 -0
  18. package/dist/basis/migration-sentinel.d.ts.map +1 -0
  19. package/dist/basis/migration-sentinel.js +219 -0
  20. package/dist/basis/migration-sentinel.js.map +1 -0
  21. package/dist/basis/spec-frontmatter.d.ts +18 -0
  22. package/dist/basis/spec-frontmatter.d.ts.map +1 -0
  23. package/dist/basis/spec-frontmatter.js +55 -0
  24. package/dist/basis/spec-frontmatter.js.map +1 -0
  25. package/dist/basis/spec-sections.d.ts +18 -0
  26. package/dist/basis/spec-sections.d.ts.map +1 -0
  27. package/dist/basis/spec-sections.js +27 -0
  28. package/dist/basis/spec-sections.js.map +1 -0
  29. package/dist/basis/test-basis-schema.d.ts +28 -0
  30. package/dist/basis/test-basis-schema.d.ts.map +1 -0
  31. package/dist/basis/test-basis-schema.js +141 -0
  32. package/dist/basis/test-basis-schema.js.map +1 -0
  33. package/dist/capabilities/discover.d.ts +4 -0
  34. package/dist/capabilities/discover.d.ts.map +1 -1
  35. package/dist/capabilities/discover.js +16 -2
  36. package/dist/capabilities/discover.js.map +1 -1
  37. package/dist/capabilities/registry.d.ts +15 -0
  38. package/dist/capabilities/registry.d.ts.map +1 -1
  39. package/dist/capabilities/registry.js.map +1 -1
  40. package/dist/cli/commands/audit.d.ts.map +1 -1
  41. package/dist/cli/commands/audit.js +10 -5
  42. package/dist/cli/commands/audit.js.map +1 -1
  43. package/dist/cli/commands/capability.d.ts.map +1 -1
  44. package/dist/cli/commands/capability.js +6 -2
  45. package/dist/cli/commands/capability.js.map +1 -1
  46. package/dist/cli/commands/contract-derive-command.d.ts +11 -0
  47. package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
  48. package/dist/cli/commands/contract-derive-command.js +99 -0
  49. package/dist/cli/commands/contract-derive-command.js.map +1 -0
  50. package/dist/cli/commands/contract.d.ts +17 -0
  51. package/dist/cli/commands/contract.d.ts.map +1 -0
  52. package/dist/cli/commands/contract.js +162 -0
  53. package/dist/cli/commands/contract.js.map +1 -0
  54. package/dist/cli/commands/defect.d.ts +7 -0
  55. package/dist/cli/commands/defect.d.ts.map +1 -0
  56. package/dist/cli/commands/defect.js +68 -0
  57. package/dist/cli/commands/defect.js.map +1 -0
  58. package/dist/cli/commands/delivery.d.ts.map +1 -1
  59. package/dist/cli/commands/delivery.js +96 -12
  60. package/dist/cli/commands/delivery.js.map +1 -1
  61. package/dist/cli/commands/generate.d.ts.map +1 -1
  62. package/dist/cli/commands/generate.js +3 -1
  63. package/dist/cli/commands/generate.js.map +1 -1
  64. package/dist/cli/commands/journey.d.ts.map +1 -1
  65. package/dist/cli/commands/journey.js +43 -15
  66. package/dist/cli/commands/journey.js.map +1 -1
  67. package/dist/cli/commands/next.d.ts +8 -0
  68. package/dist/cli/commands/next.d.ts.map +1 -1
  69. package/dist/cli/commands/next.js +68 -8
  70. package/dist/cli/commands/next.js.map +1 -1
  71. package/dist/cli/commands/triage.d.ts +7 -0
  72. package/dist/cli/commands/triage.d.ts.map +1 -0
  73. package/dist/cli/commands/triage.js +98 -0
  74. package/dist/cli/commands/triage.js.map +1 -0
  75. package/dist/cli/commands/update.d.ts +11 -0
  76. package/dist/cli/commands/update.d.ts.map +1 -1
  77. package/dist/cli/commands/update.js +31 -6
  78. package/dist/cli/commands/update.js.map +1 -1
  79. package/dist/cli/index.js +24 -33
  80. package/dist/cli/index.js.map +1 -1
  81. package/dist/cli/project-sungen-invocation.d.ts +7 -0
  82. package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
  83. package/dist/cli/project-sungen-invocation.js +76 -0
  84. package/dist/cli/project-sungen-invocation.js.map +1 -0
  85. package/dist/contract/approve-contract.d.ts +31 -0
  86. package/dist/contract/approve-contract.d.ts.map +1 -0
  87. package/dist/contract/approve-contract.js +87 -0
  88. package/dist/contract/approve-contract.js.map +1 -0
  89. package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
  90. package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
  91. package/dist/contract/assertion-matcher-vocabulary.js +100 -0
  92. package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
  93. package/dist/contract/build-contract-verdict.d.ts +32 -0
  94. package/dist/contract/build-contract-verdict.d.ts.map +1 -0
  95. package/dist/contract/build-contract-verdict.js +123 -0
  96. package/dist/contract/build-contract-verdict.js.map +1 -0
  97. package/dist/contract/build-trace-conformance.d.ts +18 -0
  98. package/dist/contract/build-trace-conformance.d.ts.map +1 -0
  99. package/dist/contract/build-trace-conformance.js +153 -0
  100. package/dist/contract/build-trace-conformance.js.map +1 -0
  101. package/dist/contract/classify-contract-change.d.ts +23 -0
  102. package/dist/contract/classify-contract-change.d.ts.map +1 -0
  103. package/dist/contract/classify-contract-change.js +98 -0
  104. package/dist/contract/classify-contract-change.js.map +1 -0
  105. package/dist/contract/classify-contract-unit.d.ts +18 -0
  106. package/dist/contract/classify-contract-unit.d.ts.map +1 -0
  107. package/dist/contract/classify-contract-unit.js +49 -0
  108. package/dist/contract/classify-contract-unit.js.map +1 -0
  109. package/dist/contract/classify-trace-conformance.d.ts +32 -0
  110. package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
  111. package/dist/contract/classify-trace-conformance.js +117 -0
  112. package/dist/contract/classify-trace-conformance.js.map +1 -0
  113. package/dist/contract/contract-git.d.ts +24 -0
  114. package/dist/contract/contract-git.d.ts.map +1 -0
  115. package/dist/contract/contract-git.js +144 -0
  116. package/dist/contract/contract-git.js.map +1 -0
  117. package/dist/contract/contract-hash.d.ts +7 -0
  118. package/dist/contract/contract-hash.d.ts.map +1 -0
  119. package/dist/contract/contract-hash.js +38 -0
  120. package/dist/contract/contract-hash.js.map +1 -0
  121. package/dist/contract/contract-report-file.d.ts +4 -0
  122. package/dist/contract/contract-report-file.d.ts.map +1 -0
  123. package/dist/contract/contract-report-file.js +60 -0
  124. package/dist/contract/contract-report-file.js.map +1 -0
  125. package/dist/contract/contract-schema.d.ts +71 -0
  126. package/dist/contract/contract-schema.d.ts.map +1 -0
  127. package/dist/contract/contract-schema.js +102 -0
  128. package/dist/contract/contract-schema.js.map +1 -0
  129. package/dist/contract/contract-units.d.ts +12 -0
  130. package/dist/contract/contract-units.d.ts.map +1 -0
  131. package/dist/contract/contract-units.js +96 -0
  132. package/dist/contract/contract-units.js.map +1 -0
  133. package/dist/contract/contracts-lock-file.d.ts +24 -0
  134. package/dist/contract/contracts-lock-file.d.ts.map +1 -0
  135. package/dist/contract/contracts-lock-file.js +140 -0
  136. package/dist/contract/contracts-lock-file.js.map +1 -0
  137. package/dist/contract/data-normalize.d.ts +10 -0
  138. package/dist/contract/data-normalize.d.ts.map +1 -0
  139. package/dist/contract/data-normalize.js +110 -0
  140. package/dist/contract/data-normalize.js.map +1 -0
  141. package/dist/contract/derive-free-feature.d.ts +38 -0
  142. package/dist/contract/derive-free-feature.d.ts.map +1 -0
  143. package/dist/contract/derive-free-feature.js +154 -0
  144. package/dist/contract/derive-free-feature.js.map +1 -0
  145. package/dist/contract/field-semantic-redaction.d.ts +21 -0
  146. package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
  147. package/dist/contract/field-semantic-redaction.js +118 -0
  148. package/dist/contract/field-semantic-redaction.js.map +1 -0
  149. package/dist/contract/free-feature-blocks.d.ts +10 -0
  150. package/dist/contract/free-feature-blocks.d.ts.map +1 -0
  151. package/dist/contract/free-feature-blocks.js +94 -0
  152. package/dist/contract/free-feature-blocks.js.map +1 -0
  153. package/dist/contract/lock-secret-guard.d.ts +22 -0
  154. package/dist/contract/lock-secret-guard.d.ts.map +1 -0
  155. package/dist/contract/lock-secret-guard.js +134 -0
  156. package/dist/contract/lock-secret-guard.js.map +1 -0
  157. package/dist/contract/lock-vs-git-head.d.ts +26 -0
  158. package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
  159. package/dist/contract/lock-vs-git-head.js +28 -0
  160. package/dist/contract/lock-vs-git-head.js.map +1 -0
  161. package/dist/contract/normalize-contract-step.d.ts +21 -0
  162. package/dist/contract/normalize-contract-step.d.ts.map +1 -0
  163. package/dist/contract/normalize-contract-step.js +70 -0
  164. package/dist/contract/normalize-contract-step.js.map +1 -0
  165. package/dist/contract/normalize-feature-steps.d.ts +7 -0
  166. package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
  167. package/dist/contract/normalize-feature-steps.js +127 -0
  168. package/dist/contract/normalize-feature-steps.js.map +1 -0
  169. package/dist/contract/oracle-strength.d.ts +12 -0
  170. package/dist/contract/oracle-strength.d.ts.map +1 -0
  171. package/dist/contract/oracle-strength.js +88 -0
  172. package/dist/contract/oracle-strength.js.map +1 -0
  173. package/dist/contract/project-contract-blockers.d.ts +10 -0
  174. package/dist/contract/project-contract-blockers.d.ts.map +1 -0
  175. package/dist/contract/project-contract-blockers.js +73 -0
  176. package/dist/contract/project-contract-blockers.js.map +1 -0
  177. package/dist/contract/record-contract-approval.d.ts +21 -0
  178. package/dist/contract/record-contract-approval.d.ts.map +1 -0
  179. package/dist/contract/record-contract-approval.js +98 -0
  180. package/dist/contract/record-contract-approval.js.map +1 -0
  181. package/dist/contract/render-free-gherkin.d.ts +40 -0
  182. package/dist/contract/render-free-gherkin.d.ts.map +1 -0
  183. package/dist/contract/render-free-gherkin.js +141 -0
  184. package/dist/contract/render-free-gherkin.js.map +1 -0
  185. package/dist/contract/render-trace-sentence.d.ts +20 -0
  186. package/dist/contract/render-trace-sentence.d.ts.map +1 -0
  187. package/dist/contract/render-trace-sentence.js +109 -0
  188. package/dist/contract/render-trace-sentence.js.map +1 -0
  189. package/dist/contract/render-trace-target.d.ts +14 -0
  190. package/dist/contract/render-trace-target.d.ts.map +1 -0
  191. package/dist/contract/render-trace-target.js +70 -0
  192. package/dist/contract/render-trace-target.js.map +1 -0
  193. package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
  194. package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
  195. package/dist/contract/resolve-unit-trace-identities.js +78 -0
  196. package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
  197. package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
  198. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
  199. package/dist/contract/trace/collect-trace-evidence.js +161 -0
  200. package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
  201. package/dist/contract/trace/identity-cache.d.ts +19 -0
  202. package/dist/contract/trace/identity-cache.d.ts.map +1 -0
  203. package/dist/contract/trace/identity-cache.js +104 -0
  204. package/dist/contract/trace/identity-cache.js.map +1 -0
  205. package/dist/contract/trace/select-final-attempt.d.ts +27 -0
  206. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
  207. package/dist/contract/trace/select-final-attempt.js +116 -0
  208. package/dist/contract/trace/select-final-attempt.js.map +1 -0
  209. package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
  210. package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
  211. package/dist/contract/trace/snapshot-html-renderer.js +172 -0
  212. package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
  213. package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
  214. package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
  215. package/dist/contract/trace/snapshot-resolver.js +65 -0
  216. package/dist/contract/trace/snapshot-resolver.js.map +1 -0
  217. package/dist/contract/trace/snapshot-store.d.ts +66 -0
  218. package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
  219. package/dist/contract/trace/snapshot-store.js +173 -0
  220. package/dist/contract/trace/snapshot-store.js.map +1 -0
  221. package/dist/contract/trace/target-identity.d.ts +74 -0
  222. package/dist/contract/trace/target-identity.d.ts.map +1 -0
  223. package/dist/contract/trace/target-identity.js +68 -0
  224. package/dist/contract/trace/target-identity.js.map +1 -0
  225. package/dist/contract/trace/test-step-join.d.ts +65 -0
  226. package/dist/contract/trace/test-step-join.d.ts.map +1 -0
  227. package/dist/contract/trace/test-step-join.js +80 -0
  228. package/dist/contract/trace/test-step-join.js.map +1 -0
  229. package/dist/contract/trace/trace-binding.d.ts +21 -0
  230. package/dist/contract/trace/trace-binding.d.ts.map +1 -0
  231. package/dist/contract/trace/trace-binding.js +88 -0
  232. package/dist/contract/trace/trace-binding.js.map +1 -0
  233. package/dist/contract/trace/trace-file-reader.d.ts +41 -0
  234. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
  235. package/dist/contract/trace/trace-file-reader.js +161 -0
  236. package/dist/contract/trace/trace-file-reader.js.map +1 -0
  237. package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
  238. package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
  239. package/dist/contract/trace/trace-fingerprint.js +96 -0
  240. package/dist/contract/trace/trace-fingerprint.js.map +1 -0
  241. package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
  242. package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
  243. package/dist/contract/trace/trace-identity-resolution.js +84 -0
  244. package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
  245. package/dist/contract/trace/trace-run-record.d.ts +30 -0
  246. package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
  247. package/dist/contract/trace/trace-run-record.js +121 -0
  248. package/dist/contract/trace/trace-run-record.js.map +1 -0
  249. package/dist/contract/trace/trace-steps.d.ts +19 -0
  250. package/dist/contract/trace/trace-steps.d.ts.map +1 -0
  251. package/dist/contract/trace/trace-steps.js +79 -0
  252. package/dist/contract/trace/trace-steps.js.map +1 -0
  253. package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
  254. package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
  255. package/dist/contract/trace/trace-zip-limits.js +52 -0
  256. package/dist/contract/trace/trace-zip-limits.js.map +1 -0
  257. package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
  258. package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
  259. package/dist/contract/trace/trace-zip-reader.js +186 -0
  260. package/dist/contract/trace/trace-zip-reader.js.map +1 -0
  261. package/dist/contract/verify-approval-decisions.d.ts +5 -0
  262. package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
  263. package/dist/contract/verify-approval-decisions.js +104 -0
  264. package/dist/contract/verify-approval-decisions.js.map +1 -0
  265. package/dist/decisions/append-decision.d.ts +12 -0
  266. package/dist/decisions/append-decision.d.ts.map +1 -0
  267. package/dist/decisions/append-decision.js +73 -0
  268. package/dist/decisions/append-decision.js.map +1 -0
  269. package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
  270. package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
  271. package/dist/decisions/confirmed-decision-commands.js +190 -0
  272. package/dist/decisions/confirmed-decision-commands.js.map +1 -0
  273. package/dist/decisions/decision-file.d.ts +31 -0
  274. package/dist/decisions/decision-file.d.ts.map +1 -0
  275. package/dist/decisions/decision-file.js +139 -0
  276. package/dist/decisions/decision-file.js.map +1 -0
  277. package/dist/decisions/decision-identity.d.ts +12 -0
  278. package/dist/decisions/decision-identity.d.ts.map +1 -0
  279. package/dist/decisions/decision-identity.js +78 -0
  280. package/dist/decisions/decision-identity.js.map +1 -0
  281. package/dist/decisions/decision-integrity-check.d.ts +12 -0
  282. package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
  283. package/dist/decisions/decision-integrity-check.js +102 -0
  284. package/dist/decisions/decision-integrity-check.js.map +1 -0
  285. package/dist/decisions/decision-schema.d.ts +42 -0
  286. package/dist/decisions/decision-schema.d.ts.map +1 -0
  287. package/dist/decisions/decision-schema.js +75 -0
  288. package/dist/decisions/decision-schema.js.map +1 -0
  289. package/dist/decisions/decision-source.d.ts +2 -0
  290. package/dist/decisions/decision-source.d.ts.map +1 -0
  291. package/dist/decisions/decision-source.js +18 -0
  292. package/dist/decisions/decision-source.js.map +1 -0
  293. package/dist/decisions/exclusive-file-create.d.ts +3 -0
  294. package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
  295. package/dist/decisions/exclusive-file-create.js +84 -0
  296. package/dist/decisions/exclusive-file-create.js.map +1 -0
  297. package/dist/decisions/git-head-trust.d.ts +7 -0
  298. package/dist/decisions/git-head-trust.d.ts.map +1 -0
  299. package/dist/decisions/git-head-trust.js +76 -0
  300. package/dist/decisions/git-head-trust.js.map +1 -0
  301. package/dist/decisions/human-confirmation.d.ts +35 -0
  302. package/dist/decisions/human-confirmation.d.ts.map +1 -0
  303. package/dist/decisions/human-confirmation.js +161 -0
  304. package/dist/decisions/human-confirmation.js.map +1 -0
  305. package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
  306. package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
  307. package/dist/decisions/legacy-waiver-migration.js +170 -0
  308. package/dist/decisions/legacy-waiver-migration.js.map +1 -0
  309. package/dist/decisions/read-decisions.d.ts +19 -0
  310. package/dist/decisions/read-decisions.d.ts.map +1 -0
  311. package/dist/decisions/read-decisions.js +90 -0
  312. package/dist/decisions/read-decisions.js.map +1 -0
  313. package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
  314. package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
  315. package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
  316. package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
  317. package/dist/decisions/waiver-decisions.d.ts +24 -0
  318. package/dist/decisions/waiver-decisions.d.ts.map +1 -0
  319. package/dist/decisions/waiver-decisions.js +46 -0
  320. package/dist/decisions/waiver-decisions.js.map +1 -0
  321. package/dist/exporters/csv-exporter.d.ts +4 -0
  322. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  323. package/dist/exporters/csv-exporter.js +1 -1
  324. package/dist/exporters/csv-exporter.js.map +1 -1
  325. package/dist/exporters/feature-parser.d.ts +8 -0
  326. package/dist/exporters/feature-parser.d.ts.map +1 -1
  327. package/dist/exporters/feature-parser.js +12 -0
  328. package/dist/exporters/feature-parser.js.map +1 -1
  329. package/dist/exporters/matrix/build.d.ts +3 -0
  330. package/dist/exporters/matrix/build.d.ts.map +1 -1
  331. package/dist/exporters/matrix/build.js +59 -19
  332. package/dist/exporters/matrix/build.js.map +1 -1
  333. package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
  334. package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
  335. package/dist/exporters/matrix/carry-manual-results.js +76 -6
  336. package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
  337. package/dist/exporters/matrix/export.d.ts +8 -2
  338. package/dist/exporters/matrix/export.d.ts.map +1 -1
  339. package/dist/exporters/matrix/export.js +16 -3
  340. package/dist/exporters/matrix/export.js.map +1 -1
  341. package/dist/exporters/matrix/gates.d.ts +6 -1
  342. package/dist/exporters/matrix/gates.d.ts.map +1 -1
  343. package/dist/exporters/matrix/gates.js +57 -128
  344. package/dist/exporters/matrix/gates.js.map +1 -1
  345. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  346. package/dist/exporters/matrix/render-csv.js +4 -1
  347. package/dist/exporters/matrix/render-csv.js.map +1 -1
  348. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
  349. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
  350. package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
  351. package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
  352. package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
  353. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  354. package/dist/exporters/matrix/render-xlsx.js +6 -0
  355. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  356. package/dist/exporters/matrix/types.d.ts +9 -1
  357. package/dist/exporters/matrix/types.d.ts.map +1 -1
  358. package/dist/exporters/matrix/types.js.map +1 -1
  359. package/dist/exporters/matrix/xlsx-cells.js +1 -1
  360. package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
  361. package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
  362. package/dist/exporters/playwright-report-parser.js +1 -0
  363. package/dist/exporters/playwright-report-parser.js.map +1 -1
  364. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  365. package/dist/exporters/scenario-merger.js +2 -0
  366. package/dist/exporters/scenario-merger.js.map +1 -1
  367. package/dist/exporters/types.d.ts +5 -0
  368. package/dist/exporters/types.d.ts.map +1 -1
  369. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  370. package/dist/generators/test-generator/code-generator.js +13 -0
  371. package/dist/generators/test-generator/code-generator.js.map +1 -1
  372. package/dist/graph/evaluate-graph.d.ts +23 -0
  373. package/dist/graph/evaluate-graph.d.ts.map +1 -0
  374. package/dist/graph/evaluate-graph.js +52 -0
  375. package/dist/graph/evaluate-graph.js.map +1 -0
  376. package/dist/graph/locate-finding.d.ts +20 -0
  377. package/dist/graph/locate-finding.d.ts.map +1 -0
  378. package/dist/graph/locate-finding.js +137 -0
  379. package/dist/graph/locate-finding.js.map +1 -0
  380. package/dist/graph/node-decl.d.ts +66 -0
  381. package/dist/graph/node-decl.d.ts.map +1 -0
  382. package/dist/graph/node-decl.js +8 -0
  383. package/dist/graph/node-decl.js.map +1 -0
  384. package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
  385. package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
  386. package/dist/graph/nodes/core-node-catalog.js +13 -0
  387. package/dist/graph/nodes/core-node-catalog.js.map +1 -0
  388. package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
  389. package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
  390. package/dist/graph/nodes/test-case-contract-nodes.js +59 -0
  391. package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
  392. package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
  393. package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
  394. package/dist/graph/nodes/test-case-nodes.js +66 -0
  395. package/dist/graph/nodes/test-case-nodes.js.map +1 -0
  396. package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
  397. package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
  398. package/dist/graph/nodes/unit-audit-nodes.js +95 -0
  399. package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
  400. package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
  401. package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
  402. package/dist/graph/nodes/unit-contract-node.js +88 -0
  403. package/dist/graph/nodes/unit-contract-node.js.map +1 -0
  404. package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
  405. package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
  406. package/dist/graph/nodes/unit-design-nodes.js +91 -0
  407. package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
  408. package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
  409. package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
  410. package/dist/graph/nodes/unit-execution-nodes.js +79 -0
  411. package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
  412. package/dist/graph/test-case-identity.d.ts +13 -0
  413. package/dist/graph/test-case-identity.d.ts.map +1 -0
  414. package/dist/graph/test-case-identity.js +106 -0
  415. package/dist/graph/test-case-identity.js.map +1 -0
  416. package/dist/graph/test-case-results.d.ts +11 -0
  417. package/dist/graph/test-case-results.d.ts.map +1 -0
  418. package/dist/graph/test-case-results.js +137 -0
  419. package/dist/graph/test-case-results.js.map +1 -0
  420. package/dist/graph/test-case-satisfied.d.ts +25 -0
  421. package/dist/graph/test-case-satisfied.d.ts.map +1 -0
  422. package/dist/graph/test-case-satisfied.js +51 -0
  423. package/dist/graph/test-case-satisfied.js.map +1 -0
  424. package/dist/graph/test-case-state-shape.d.ts +67 -0
  425. package/dist/graph/test-case-state-shape.d.ts.map +1 -0
  426. package/dist/graph/test-case-state-shape.js +3 -0
  427. package/dist/graph/test-case-state-shape.js.map +1 -0
  428. package/dist/graph/test-case-states.d.ts +9 -0
  429. package/dist/graph/test-case-states.d.ts.map +1 -0
  430. package/dist/graph/test-case-states.js +116 -0
  431. package/dist/graph/test-case-states.js.map +1 -0
  432. package/dist/graph/unit-artifact-probes.d.ts +19 -0
  433. package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
  434. package/dist/graph/unit-artifact-probes.js +133 -0
  435. package/dist/graph/unit-artifact-probes.js.map +1 -0
  436. package/dist/graph/unit-state-facts.d.ts +43 -0
  437. package/dist/graph/unit-state-facts.d.ts.map +1 -0
  438. package/dist/graph/unit-state-facts.js +87 -0
  439. package/dist/graph/unit-state-facts.js.map +1 -0
  440. package/dist/harness/audit.d.ts +11 -0
  441. package/dist/harness/audit.d.ts.map +1 -1
  442. package/dist/harness/audit.js +34 -9
  443. package/dist/harness/audit.js.map +1 -1
  444. package/dist/harness/catalog/gate-rules.yaml +647 -0
  445. package/dist/harness/counted-assertions.d.ts +2 -0
  446. package/dist/harness/counted-assertions.d.ts.map +1 -0
  447. package/dist/harness/counted-assertions.js +38 -0
  448. package/dist/harness/counted-assertions.js.map +1 -0
  449. package/dist/harness/defect-draft.d.ts +14 -0
  450. package/dist/harness/defect-draft.d.ts.map +1 -0
  451. package/dist/harness/defect-draft.js +143 -0
  452. package/dist/harness/defect-draft.js.map +1 -0
  453. package/dist/harness/defects.d.ts +24 -0
  454. package/dist/harness/defects.d.ts.map +1 -0
  455. package/dist/harness/defects.js +118 -0
  456. package/dist/harness/defects.js.map +1 -0
  457. package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
  458. package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
  459. package/dist/harness/gates/audit-gate-terms.js +72 -0
  460. package/dist/harness/gates/audit-gate-terms.js.map +1 -0
  461. package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
  462. package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
  463. package/dist/harness/gates/audit-gate-verdict.js +101 -0
  464. package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
  465. package/dist/harness/gates/audit-input-hash.d.ts +4 -0
  466. package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
  467. package/dist/harness/gates/audit-input-hash.js +96 -0
  468. package/dist/harness/gates/audit-input-hash.js.map +1 -0
  469. package/dist/harness/gates/audit-report-verification.d.ts +41 -0
  470. package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
  471. package/dist/harness/gates/audit-report-verification.js +236 -0
  472. package/dist/harness/gates/audit-report-verification.js.map +1 -0
  473. package/dist/harness/gates/decisions-hash.d.ts +13 -0
  474. package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
  475. package/dist/harness/gates/decisions-hash.js +72 -0
  476. package/dist/harness/gates/decisions-hash.js.map +1 -0
  477. package/dist/harness/gates/delivery-checklist.d.ts +21 -0
  478. package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
  479. package/dist/harness/gates/delivery-checklist.js +128 -0
  480. package/dist/harness/gates/delivery-checklist.js.map +1 -0
  481. package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
  482. package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
  483. package/dist/harness/gates/delivery-decision-gate.js +116 -0
  484. package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
  485. package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
  486. package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
  487. package/dist/harness/gates/delivery-decision-step.js +86 -0
  488. package/dist/harness/gates/delivery-decision-step.js.map +1 -0
  489. package/dist/harness/gates/gate-override-report.d.ts +59 -0
  490. package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
  491. package/dist/harness/gates/gate-override-report.js +86 -0
  492. package/dist/harness/gates/gate-override-report.js.map +1 -0
  493. package/dist/harness/gates/gate-override-scope.d.ts +18 -0
  494. package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
  495. package/dist/harness/gates/gate-override-scope.js +98 -0
  496. package/dist/harness/gates/gate-override-scope.js.map +1 -0
  497. package/dist/harness/gates/gate-override-validation.d.ts +25 -0
  498. package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
  499. package/dist/harness/gates/gate-override-validation.js +81 -0
  500. package/dist/harness/gates/gate-override-validation.js.map +1 -0
  501. package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
  502. package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
  503. package/dist/harness/gates/gate-rule-catalog.js +112 -0
  504. package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
  505. package/dist/harness/gates/gate-terms.d.ts +33 -0
  506. package/dist/harness/gates/gate-terms.d.ts.map +1 -0
  507. package/dist/harness/gates/gate-terms.js +41 -0
  508. package/dist/harness/gates/gate-terms.js.map +1 -0
  509. package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
  510. package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
  511. package/dist/harness/gates/in-run-decision-check.js +138 -0
  512. package/dist/harness/gates/in-run-decision-check.js.map +1 -0
  513. package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
  514. package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
  515. package/dist/harness/gates/journey-gate-inputs.js +81 -0
  516. package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
  517. package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
  518. package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
  519. package/dist/harness/gates/migrated-waiver-review.js +116 -0
  520. package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
  521. package/dist/harness/gates/resolve-rule.d.ts +59 -0
  522. package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
  523. package/dist/harness/gates/resolve-rule.js +41 -0
  524. package/dist/harness/gates/resolve-rule.js.map +1 -0
  525. package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
  526. package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
  527. package/dist/harness/gates/unit-gate-overrides.js +122 -0
  528. package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
  529. package/dist/harness/journey.d.ts +43 -1
  530. package/dist/harness/journey.d.ts.map +1 -1
  531. package/dist/harness/journey.js +207 -33
  532. package/dist/harness/journey.js.map +1 -1
  533. package/dist/harness/manifest.d.ts +12 -0
  534. package/dist/harness/manifest.d.ts.map +1 -1
  535. package/dist/harness/manifest.js +73 -45
  536. package/dist/harness/manifest.js.map +1 -1
  537. package/dist/harness/next-step.d.ts +37 -6
  538. package/dist/harness/next-step.d.ts.map +1 -1
  539. package/dist/harness/next-step.js +34 -174
  540. package/dist/harness/next-step.js.map +1 -1
  541. package/dist/harness/parse.d.ts +25 -0
  542. package/dist/harness/parse.d.ts.map +1 -1
  543. package/dist/harness/parse.js +38 -13
  544. package/dist/harness/parse.js.map +1 -1
  545. package/dist/harness/provenance.d.ts +29 -0
  546. package/dist/harness/provenance.d.ts.map +1 -1
  547. package/dist/harness/provenance.js +109 -9
  548. package/dist/harness/provenance.js.map +1 -1
  549. package/dist/harness/script-check.d.ts.map +1 -1
  550. package/dist/harness/script-check.js +29 -6
  551. package/dist/harness/script-check.js.map +1 -1
  552. package/dist/harness/sensors.d.ts +14 -3
  553. package/dist/harness/sensors.d.ts.map +1 -1
  554. package/dist/harness/sensors.js +64 -44
  555. package/dist/harness/sensors.js.map +1 -1
  556. package/dist/harness/triage-signals.d.ts +20 -0
  557. package/dist/harness/triage-signals.d.ts.map +1 -0
  558. package/dist/harness/triage-signals.js +30 -0
  559. package/dist/harness/triage-signals.js.map +1 -0
  560. package/dist/harness/triage-unit.d.ts +23 -0
  561. package/dist/harness/triage-unit.d.ts.map +1 -0
  562. package/dist/harness/triage-unit.js +142 -0
  563. package/dist/harness/triage-unit.js.map +1 -0
  564. package/dist/harness/triage.d.ts +28 -0
  565. package/dist/harness/triage.d.ts.map +1 -0
  566. package/dist/harness/triage.js +99 -0
  567. package/dist/harness/triage.js.map +1 -0
  568. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  569. package/dist/harness/viewpoint-ledger.js +2 -1
  570. package/dist/harness/viewpoint-ledger.js.map +1 -1
  571. package/dist/hooks/bash-write-targets.d.ts +15 -0
  572. package/dist/hooks/bash-write-targets.d.ts.map +1 -0
  573. package/dist/hooks/bash-write-targets.js +173 -0
  574. package/dist/hooks/bash-write-targets.js.map +1 -0
  575. package/dist/hooks/claude-hook-entry.d.ts +11 -0
  576. package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
  577. package/dist/hooks/claude-hook-entry.js +137 -0
  578. package/dist/hooks/claude-hook-entry.js.map +1 -0
  579. package/dist/hooks/claude-transcript-turn.d.ts +11 -0
  580. package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
  581. package/dist/hooks/claude-transcript-turn.js +143 -0
  582. package/dist/hooks/claude-transcript-turn.js.map +1 -0
  583. package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
  584. package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
  585. package/dist/hooks/guard-delivery-contract-rule.js +152 -0
  586. package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
  587. package/dist/hooks/guard-protected-paths.d.ts +9 -0
  588. package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
  589. package/dist/hooks/guard-protected-paths.js +107 -0
  590. package/dist/hooks/guard-protected-paths.js.map +1 -0
  591. package/dist/hooks/guard-rules.d.ts +37 -0
  592. package/dist/hooks/guard-rules.d.ts.map +1 -0
  593. package/dist/hooks/guard-rules.js +61 -0
  594. package/dist/hooks/guard-rules.js.map +1 -0
  595. package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
  596. package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
  597. package/dist/hooks/guard-tty-spoof-rule.js +21 -0
  598. package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
  599. package/dist/hooks/hand-back-core.d.ts +39 -0
  600. package/dist/hooks/hand-back-core.d.ts.map +1 -0
  601. package/dist/hooks/hand-back-core.js +122 -0
  602. package/dist/hooks/hand-back-core.js.map +1 -0
  603. package/dist/hooks/hook-cli-command.d.ts +9 -0
  604. package/dist/hooks/hook-cli-command.d.ts.map +1 -0
  605. package/dist/hooks/hook-cli-command.js +46 -0
  606. package/dist/hooks/hook-cli-command.js.map +1 -0
  607. package/dist/hooks/hook-registry.d.ts +10 -0
  608. package/dist/hooks/hook-registry.d.ts.map +1 -0
  609. package/dist/hooks/hook-registry.js +24 -0
  610. package/dist/hooks/hook-registry.js.map +1 -0
  611. package/dist/hooks/hook-result-contract.d.ts +50 -0
  612. package/dist/hooks/hook-result-contract.d.ts.map +1 -0
  613. package/dist/hooks/hook-result-contract.js +80 -0
  614. package/dist/hooks/hook-result-contract.js.map +1 -0
  615. package/dist/hooks/hook-toggles.d.ts +10 -0
  616. package/dist/hooks/hook-toggles.d.ts.map +1 -0
  617. package/dist/hooks/hook-toggles.js +107 -0
  618. package/dist/hooks/hook-toggles.js.map +1 -0
  619. package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
  620. package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
  621. package/dist/hooks/pre-tool-guard-hook.js +105 -0
  622. package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
  623. package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
  624. package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
  625. package/dist/hooks/session-start-unit-state-hook.js +57 -0
  626. package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
  627. package/dist/hooks/stop-next-step-hook.d.ts +16 -0
  628. package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
  629. package/dist/hooks/stop-next-step-hook.js +42 -0
  630. package/dist/hooks/stop-next-step-hook.js.map +1 -0
  631. package/dist/hooks/sungen-project-root.d.ts +19 -0
  632. package/dist/hooks/sungen-project-root.d.ts.map +1 -0
  633. package/dist/hooks/sungen-project-root.js +130 -0
  634. package/dist/hooks/sungen-project-root.js.map +1 -0
  635. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
  636. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
  637. package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
  638. package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
  639. package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
  640. package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
  641. package/dist/orchestrator/ai-skills/commands.js +16 -6
  642. package/dist/orchestrator/ai-skills/commands.js.map +1 -1
  643. package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
  644. package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
  645. package/dist/orchestrator/assets-drift.d.ts +5 -0
  646. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  647. package/dist/orchestrator/assets-drift.js +12 -3
  648. package/dist/orchestrator/assets-drift.js.map +1 -1
  649. package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
  650. package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
  651. package/dist/orchestrator/claude-hooks-install.js +203 -0
  652. package/dist/orchestrator/claude-hooks-install.js.map +1 -0
  653. package/dist/orchestrator/lockstep-version.d.ts +15 -5
  654. package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
  655. package/dist/orchestrator/lockstep-version.js +30 -17
  656. package/dist/orchestrator/lockstep-version.js.map +1 -1
  657. package/dist/orchestrator/project-initializer.d.ts +6 -0
  658. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  659. package/dist/orchestrator/project-initializer.js +24 -0
  660. package/dist/orchestrator/project-initializer.js.map +1 -1
  661. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  662. package/dist/orchestrator/screen-manager.js +4 -2
  663. package/dist/orchestrator/screen-manager.js.map +1 -1
  664. package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  665. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  666. package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  667. package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  668. package/dist/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  669. package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  670. package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  671. package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
  672. package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  673. package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
  674. package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
  675. package/dist/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  676. package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
  677. package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
  678. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  679. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  680. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  681. package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  682. package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  683. package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  684. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  685. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  686. package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  687. package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  688. package/dist/utils/safe-yaml-parse.d.ts +8 -0
  689. package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
  690. package/dist/utils/safe-yaml-parse.js +51 -0
  691. package/dist/utils/safe-yaml-parse.js.map +1 -0
  692. package/package.json +3 -3
  693. package/src/basis/anchor-grammar.ts +83 -0
  694. package/src/basis/anchor-hash.ts +27 -0
  695. package/src/basis/bm51-tables.ts +65 -0
  696. package/src/basis/extract-spec-anchors.ts +95 -0
  697. package/src/basis/migration-sentinel.ts +175 -0
  698. package/src/basis/spec-frontmatter.ts +68 -0
  699. package/src/basis/spec-sections.ts +35 -0
  700. package/src/basis/test-basis-schema.ts +81 -0
  701. package/src/capabilities/discover.ts +15 -2
  702. package/src/capabilities/registry.ts +16 -0
  703. package/src/cli/commands/audit.ts +10 -5
  704. package/src/cli/commands/capability.ts +4 -2
  705. package/src/cli/commands/contract-derive-command.ts +61 -0
  706. package/src/cli/commands/contract.ts +130 -0
  707. package/src/cli/commands/defect.ts +49 -0
  708. package/src/cli/commands/delivery.ts +92 -15
  709. package/src/cli/commands/generate.ts +3 -1
  710. package/src/cli/commands/journey.ts +41 -16
  711. package/src/cli/commands/next.ts +64 -10
  712. package/src/cli/commands/triage.ts +57 -0
  713. package/src/cli/commands/update.ts +35 -8
  714. package/src/cli/index.ts +24 -30
  715. package/src/cli/project-sungen-invocation.ts +39 -0
  716. package/src/contract/approve-contract.ts +94 -0
  717. package/src/contract/assertion-matcher-vocabulary.ts +93 -0
  718. package/src/contract/build-contract-verdict.ts +108 -0
  719. package/src/contract/build-trace-conformance.ts +100 -0
  720. package/src/contract/classify-contract-change.ts +92 -0
  721. package/src/contract/classify-contract-unit.ts +47 -0
  722. package/src/contract/classify-trace-conformance.ts +116 -0
  723. package/src/contract/contract-git.ts +106 -0
  724. package/src/contract/contract-hash.ts +34 -0
  725. package/src/contract/contract-report-file.ts +25 -0
  726. package/src/contract/contract-schema.ts +137 -0
  727. package/src/contract/contract-units.ts +52 -0
  728. package/src/contract/contracts-lock-file.ts +97 -0
  729. package/src/contract/data-normalize.ts +66 -0
  730. package/src/contract/derive-free-feature.ts +120 -0
  731. package/src/contract/field-semantic-redaction.ts +80 -0
  732. package/src/contract/free-feature-blocks.ts +56 -0
  733. package/src/contract/lock-secret-guard.ts +95 -0
  734. package/src/contract/lock-vs-git-head.ts +38 -0
  735. package/src/contract/normalize-contract-step.ts +74 -0
  736. package/src/contract/normalize-feature-steps.ts +93 -0
  737. package/src/contract/oracle-strength.ts +80 -0
  738. package/src/contract/project-contract-blockers.ts +36 -0
  739. package/src/contract/record-contract-approval.ts +70 -0
  740. package/src/contract/render-free-gherkin.ts +113 -0
  741. package/src/contract/render-trace-sentence.ts +98 -0
  742. package/src/contract/render-trace-target.ts +68 -0
  743. package/src/contract/resolve-unit-trace-identities.ts +35 -0
  744. package/src/contract/trace/collect-trace-evidence.ts +109 -0
  745. package/src/contract/trace/identity-cache.ts +61 -0
  746. package/src/contract/trace/select-final-attempt.ts +70 -0
  747. package/src/contract/trace/snapshot-html-renderer.ts +136 -0
  748. package/src/contract/trace/snapshot-resolver.ts +66 -0
  749. package/src/contract/trace/snapshot-store.ts +151 -0
  750. package/src/contract/trace/target-identity.ts +104 -0
  751. package/src/contract/trace/test-step-join.ts +104 -0
  752. package/src/contract/trace/trace-binding.ts +56 -0
  753. package/src/contract/trace/trace-file-reader.ts +133 -0
  754. package/src/contract/trace/trace-fingerprint.ts +68 -0
  755. package/src/contract/trace/trace-identity-resolution.ts +74 -0
  756. package/src/contract/trace/trace-run-record.ts +80 -0
  757. package/src/contract/trace/trace-steps.ts +88 -0
  758. package/src/contract/trace/trace-zip-limits.ts +77 -0
  759. package/src/contract/trace/trace-zip-reader.ts +127 -0
  760. package/src/contract/verify-approval-decisions.ts +60 -0
  761. package/src/decisions/append-decision.ts +35 -0
  762. package/src/decisions/confirmed-decision-commands.ts +149 -0
  763. package/src/decisions/decision-file.ts +93 -0
  764. package/src/decisions/decision-identity.ts +73 -0
  765. package/src/decisions/decision-integrity-check.ts +61 -0
  766. package/src/decisions/decision-schema.ts +76 -0
  767. package/src/decisions/decision-source.ts +14 -0
  768. package/src/decisions/exclusive-file-create.ts +42 -0
  769. package/src/decisions/git-head-trust.ts +32 -0
  770. package/src/decisions/human-confirmation.ts +119 -0
  771. package/src/decisions/legacy-waiver-migration.ts +135 -0
  772. package/src/decisions/read-decisions.ts +61 -0
  773. package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
  774. package/src/decisions/waiver-decisions.ts +56 -0
  775. package/src/exporters/csv-exporter.ts +5 -1
  776. package/src/exporters/feature-parser.ts +12 -0
  777. package/src/exporters/matrix/build.ts +62 -18
  778. package/src/exporters/matrix/carry-manual-results.ts +70 -7
  779. package/src/exporters/matrix/export.ts +17 -2
  780. package/src/exporters/matrix/gates.ts +62 -129
  781. package/src/exporters/matrix/render-csv.ts +4 -1
  782. package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
  783. package/src/exporters/matrix/render-xlsx.ts +6 -0
  784. package/src/exporters/matrix/types.ts +9 -1
  785. package/src/exporters/matrix/xlsx-cells.ts +1 -1
  786. package/src/exporters/playwright-report-parser.ts +1 -0
  787. package/src/exporters/scenario-merger.ts +2 -1
  788. package/src/exporters/types.ts +5 -0
  789. package/src/generators/test-generator/code-generator.ts +13 -0
  790. package/src/graph/evaluate-graph.ts +66 -0
  791. package/src/graph/locate-finding.ts +93 -0
  792. package/src/graph/node-decl.ts +72 -0
  793. package/src/graph/nodes/core-node-catalog.ts +15 -0
  794. package/src/graph/nodes/test-case-contract-nodes.ts +74 -0
  795. package/src/graph/nodes/test-case-nodes.ts +68 -0
  796. package/src/graph/nodes/unit-audit-nodes.ts +95 -0
  797. package/src/graph/nodes/unit-contract-node.ts +89 -0
  798. package/src/graph/nodes/unit-design-nodes.ts +89 -0
  799. package/src/graph/nodes/unit-execution-nodes.ts +77 -0
  800. package/src/graph/test-case-identity.ts +75 -0
  801. package/src/graph/test-case-results.ts +90 -0
  802. package/src/graph/test-case-satisfied.ts +55 -0
  803. package/src/graph/test-case-state-shape.ts +62 -0
  804. package/src/graph/test-case-states.ts +84 -0
  805. package/src/graph/unit-artifact-probes.ts +77 -0
  806. package/src/graph/unit-state-facts.ts +112 -0
  807. package/src/harness/audit.ts +46 -11
  808. package/src/harness/catalog/gate-rules.yaml +647 -0
  809. package/src/harness/counted-assertions.ts +33 -0
  810. package/src/harness/defect-draft.ts +115 -0
  811. package/src/harness/defects.ts +94 -0
  812. package/src/harness/gates/audit-gate-terms.ts +80 -0
  813. package/src/harness/gates/audit-gate-verdict.ts +78 -0
  814. package/src/harness/gates/audit-input-hash.ts +55 -0
  815. package/src/harness/gates/audit-report-verification.ts +201 -0
  816. package/src/harness/gates/decisions-hash.ts +42 -0
  817. package/src/harness/gates/delivery-checklist.ts +120 -0
  818. package/src/harness/gates/delivery-decision-gate.ts +139 -0
  819. package/src/harness/gates/delivery-decision-step.ts +89 -0
  820. package/src/harness/gates/gate-override-report.ts +114 -0
  821. package/src/harness/gates/gate-override-scope.ts +66 -0
  822. package/src/harness/gates/gate-override-validation.ts +75 -0
  823. package/src/harness/gates/gate-rule-catalog.ts +82 -0
  824. package/src/harness/gates/gate-terms.ts +59 -0
  825. package/src/harness/gates/in-run-decision-check.ts +99 -0
  826. package/src/harness/gates/journey-gate-inputs.ts +89 -0
  827. package/src/harness/gates/migrated-waiver-review.ts +68 -0
  828. package/src/harness/gates/resolve-rule.ts +94 -0
  829. package/src/harness/gates/unit-gate-overrides.ts +99 -0
  830. package/src/harness/journey.ts +215 -38
  831. package/src/harness/manifest.ts +69 -45
  832. package/src/harness/next-step.ts +60 -170
  833. package/src/harness/parse.ts +40 -13
  834. package/src/harness/provenance.ts +99 -11
  835. package/src/harness/script-check.ts +27 -6
  836. package/src/harness/sensors.ts +73 -47
  837. package/src/harness/triage-signals.ts +46 -0
  838. package/src/harness/triage-unit.ts +113 -0
  839. package/src/harness/triage.ts +127 -0
  840. package/src/harness/viewpoint-ledger.ts +2 -2
  841. package/src/hooks/bash-write-targets.ts +109 -0
  842. package/src/hooks/claude-hook-entry.ts +85 -0
  843. package/src/hooks/claude-transcript-turn.ts +96 -0
  844. package/src/hooks/guard-delivery-contract-rule.ts +110 -0
  845. package/src/hooks/guard-protected-paths.ts +71 -0
  846. package/src/hooks/guard-rules.ts +98 -0
  847. package/src/hooks/guard-tty-spoof-rule.ts +31 -0
  848. package/src/hooks/hand-back-core.ts +112 -0
  849. package/src/hooks/hook-cli-command.ts +17 -0
  850. package/src/hooks/hook-registry.ts +24 -0
  851. package/src/hooks/hook-result-contract.ts +114 -0
  852. package/src/hooks/hook-toggles.ts +66 -0
  853. package/src/hooks/pre-tool-guard-hook.ts +67 -0
  854. package/src/hooks/session-start-unit-state-hook.ts +56 -0
  855. package/src/hooks/stop-next-step-hook.ts +37 -0
  856. package/src/hooks/sungen-project-root.ts +80 -0
  857. package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
  858. package/src/orchestrator/ai-skills/commands.ts +22 -8
  859. package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
  860. package/src/orchestrator/assets-drift.ts +12 -5
  861. package/src/orchestrator/claude-hooks-install.ts +168 -0
  862. package/src/orchestrator/lockstep-version.ts +28 -15
  863. package/src/orchestrator/project-initializer.ts +22 -0
  864. package/src/orchestrator/screen-manager.ts +3 -1
  865. package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  866. package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  867. package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  868. package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  869. package/src/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  870. package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  871. package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  872. package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
  873. package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  874. package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
  875. package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
  876. package/src/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  877. package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
  878. package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
  879. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  880. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  881. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  882. package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  883. package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  884. package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  885. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  886. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  887. package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  888. package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  889. package/src/utils/safe-yaml-parse.ts +44 -0
@@ -12,6 +12,9 @@ import { parse as parseYaml } from 'yaml';
12
12
  import { ScenarioInfo, ViewpointEntry, idPrefix } from './parse';
13
13
  import { readTextFile } from './read-text';
14
14
  import { keywordHit, hasKeyword } from './keyword-match';
15
+ import { countedAssertions } from './counted-assertions';
16
+ import { CATALOG_GATE_RULES, GateRules } from './gates/resolve-rule';
17
+ import { ruleVerdict, sensorSeverityOf } from './gates/gate-terms';
15
18
 
16
19
  // Business-critical category keywords (matched by CONTAINMENT against the VP category, so a
17
20
  // compound category like LIST-DISPLAY / ADD-TO-CART / PRODUCT-DISCOVERY classifies correctly).
@@ -275,6 +278,8 @@ export function assertionDepth(
275
278
  scenarios: ScenarioInfo[],
276
279
  dataThemes: CatalogTheme[] = [],
277
280
  focus = 'functional',
281
+ /** The unit's gate rules; the catalog alone (today's levels) by default. */
282
+ rules: GateRules = CATALOG_GATE_RULES,
278
283
  ): DepthResult {
279
284
  const nonManual = scenarios.filter((s) => !s.manual);
280
285
  const shallow = nonManual.filter((s) => s.shallow);
@@ -298,8 +303,7 @@ export function assertionDepth(
298
303
  const ratio = required.length ? 1 - reqShallow.length / required.length : 1;
299
304
 
300
305
  const threshold = DEPTH_THRESHOLDS[focus] ?? DEPTH_THRESHOLDS.functional;
301
- let verdict: DepthVerdict = 'pass';
302
- if (ratio < threshold) verdict = WARN_ONLY_FOCUS.has(focus) ? 'warn' : 'fail';
306
+ const verdict = ruleVerdict(rules, 'audit.assertion-depth', ratio < threshold, WARN_ONLY_FOCUS.has(focus));
303
307
 
304
308
  return {
305
309
  total: nonManual.length,
@@ -710,7 +714,10 @@ export interface ClaimUnproven {
710
714
  claim: string; // the claim keyword matched in the title
711
715
  need: string; // the assertion shape the steps must contain
712
716
  hint: string; // how to fix
713
- severity: 'fail' | 'warn';
717
+ /** Resolved from the row's catalog rule (fail = blocks when under the ratio; info only via an override). */
718
+ severity: 'fail' | 'warn' | 'info';
719
+ /** The gate rule that decided `severity` (`claim.*`, or `claim.partial-proof`). */
720
+ rule: string;
714
721
  }
715
722
 
716
723
  export interface ClaimProofResult {
@@ -725,16 +732,17 @@ export interface ClaimProofResult {
725
732
  }
726
733
 
727
734
  interface ClaimRule {
735
+ /** The catalog rule (`claim.*`) whose resolved severity a missing proof gets (OES-11.2). */
736
+ rule: string;
728
737
  claim: string;
729
738
  title: RegExp; // claim keyword(s) in the title
730
739
  proof: RegExp; // required assertion shape in the steps
731
740
  need: string;
732
741
  hint: string;
733
- severity: 'fail' | 'warn';
734
742
  // Optional: even when `proof` matches, if `underproof` also matches the proof is
735
- // PARTIAL (the right shape exists but on the wrong/another element) → a warn-level
736
- // finding. e.g. an "each card exposes <action>" claim that has a see-all on price
737
- // but asserts the actions with singular presence.
743
+ // PARTIAL (the right shape exists but on the wrong/another element) → a finding at the
744
+ // `claim.partial-proof` rule's level. e.g. an "each card exposes <action>" claim that has
745
+ // a see-all on price but asserts the actions with singular presence.
738
746
  underproof?: RegExp;
739
747
  underNeed?: string;
740
748
  underHint?: string;
@@ -748,29 +756,30 @@ const CLAIM_RULES: ClaimRule[] = [
748
756
  // catch, so proving it with a substring proves the opposite of what the title says. Found on
749
757
  // a real basic flow whose seven confirmation rows all used `contains` while claiming the six
750
758
  // values "survive unchanged" (#599).
759
+ rule: 'claim.unchanged-preserved',
751
760
  claim: 'unchanged/preserved',
752
761
  title: /\b(unchanged|unmodified|un-?edited|identical|preserved|intact|verbatim|as entered|without (?:any )?(?:change|modification))\b/,
753
762
  proof: /^(?![\s\S]*\bcontains \{\{)/,
754
763
  need: 'exact-value assertions (`see [X] text with {{v}}` / `field with {{v}}`) for the values the title says are unchanged',
755
764
  hint: 'swap `contains {{v}}` for `with {{v}}` on the continuity rows. A substring match cannot distinguish "unchanged" from "changed by adding a prefix" — and if the screen genuinely renders extra text around the value, say so in the title instead of claiming exactness.',
756
- severity: 'warn',
757
765
  },
758
766
  {
759
767
  // An ORDER claim ("sorted by date descending", "ties broken by last-updated") is invisible to
760
768
  // a presence check: `see [List] table` passes whatever order the rows are in. It sits ahead of
761
769
  // the generic rules so "all results sorted …" is judged as an ordering claim, not an all-claim.
762
770
  // A tiebreaker is a Tier-1 guard in the tc-generation skill, yet no rule recognised it (#810).
771
+ rule: 'claim.ordering-sort',
763
772
  claim: 'ordering/sort',
764
773
  title: /\b(ascending|descending|sorted|sorts|sort order|ordered by|order by|in (?:chronological|alphabetical|reverse|numeric) order|(?:newest|oldest|latest|earliest|highest|lowest) first|tie-?break(?:s|er|ers)?|ties?)\b|降順|昇順|並び順|giảm dần|tăng dần|sắp xếp/,
765
774
  proof: /match data|is sorted|sorted (?:ascending|descending)|\brow \d+\b|\.first\.|\.last\.|\[\d+\]\.|order by/,
766
775
  need: 'an order-sensitive assertion (`table match data:` rows in the expected order, `is sorted ascending|descending`, or positional `row N` checks)',
767
776
  hint: 'a presence check passes in any order — assert the rows in their expected sequence (`User see [T] table match data:`), or the column sort state; a tiebreak needs two rows sharing the primary key.',
768
- severity: 'fail',
769
777
  },
770
778
  {
771
779
  // A LIMIT claim ("never exceeds 10", "at most 5 files") is a count claim in disguise.
772
780
  // Ahead of 'no-side-effect', whose negation+effect pattern would otherwise swallow
773
781
  // "never exceeds 10 records" and ask for a duplicate-count proof.
782
+ rule: 'claim.limit-cap',
774
783
  claim: 'limit/cap',
775
784
  // The quantity must be ≥2 ("at most ONE order" is a no-duplicate claim — left to the rules
776
785
  // below) and not a duration ("up to 30 seconds" is a timing claim, not a cap).
@@ -778,51 +787,50 @@ const CLAIM_RULES: ClaimRule[] = [
778
787
  proof: /\bcount\b|tohavecount|table with|row with \{\{|match data|is at most|\bexactly\b|field with \{\{|\berror\b|invalid|is disabled/,
779
788
  need: 'a count/boundary assertion (count is N, `is at most`, the N+1th input rejected or truncated)',
780
789
  hint: 'assert the boundary itself — the count at the cap, or the value/error when one more is attempted — not just that the list or field is present.',
781
- severity: 'fail',
782
790
  },
783
791
  {
792
+ rule: 'claim.all-every-each',
784
793
  claim: 'all/every/each',
785
794
  title: /\b(all|every|each)\b/,
786
795
  proof: /\bsee all\b/,
787
796
  need: 'a `User see all …` assertion (every element, not one)',
788
797
  hint: 'assert across all matched elements — for per-card structure use the all-card DSL (roadmap Q2).',
789
- severity: 'fail',
790
798
  // singular action presence under an "each/every" claim = partial proof
791
799
  underproof: /\bsee \[[^\]]+\] (link|button)\b/,
792
800
  underNeed: 'an all-card assertion for the claimed action (not single presence)',
793
801
  underHint: 'the actions are asserted once, not per-card — wrap them with the all-card DSL `User see all [Card] contain [Action]` (roadmap Q2).',
794
802
  },
795
803
  {
804
+ rule: 'claim.only-belong-to',
796
805
  claim: 'only/belong-to',
797
806
  title: /\b(only|belongs? to|exclusively)\b/,
798
807
  proof: /\bsee all\b[^.]*\bcontain/,
799
808
  need: 'all-match (`User see all … contains …`)',
800
809
  hint: 'all displayed items must match the facet; "no items OUTSIDE" is UI-limited → verify via hybrid API/DB or mark @manual with reason.',
801
- severity: 'warn',
802
810
  },
803
811
  {
812
+ rule: 'claim.single-exactly-one',
804
813
  claim: 'single/exactly-one',
805
814
  title: /\b(a single|single|exactly one|just one|only one)\b/,
806
815
  proof: /\bcount\b|\btable with\b|\bexactly\b|tohavecount/,
807
816
  need: 'a count assertion (e.g. count is 1)',
808
817
  hint: 'assert the quantity, not just presence.',
809
- severity: 'fail',
810
818
  },
811
819
  {
820
+ rule: 'claim.correct-matching-identity',
812
821
  claim: 'correct/matching/identity',
813
822
  title: /\b(correct|matching|the same|same (product|name|price|value|item)|consistency|identity|lands? in|is the (product|item))\b/,
814
823
  proof: /\bremember\b/,
815
824
  need: 'capture + compare (`User remember … as {{v}}` then assert {{v}})',
816
825
  hint: 'remember the value on the source, then assert it on the target (cross-screen → defer to a flow as @manual).',
817
- severity: 'fail',
818
826
  },
819
827
  {
828
+ rule: 'claim.changes-toggles',
820
829
  claim: 'changes/toggles',
821
830
  title: /\b(changes?|toggles?|updates?|reflects?|reopens?)\b/,
822
831
  proof: /\bremember\b|\bis hidden\b/,
823
832
  need: 'a state delta (before ≠ after, or a visible→hidden contrast)',
824
833
  hint: 'capture the before-state and assert the after-state differs, or assert the visible/hidden transition.',
825
- severity: 'warn',
826
834
  },
827
835
  {
828
836
  // GENERAL — mutation-absence. A title asserts that a STATE-CHANGING action does NOT
@@ -833,6 +841,7 @@ const CLAIM_RULES: ClaimRule[] = [
833
841
  // count/contrast (record count unchanged) or defer to @manual. This is the general
834
842
  // category behind "browser back does not re-submit", "does not re-charge the card",
835
843
  // "double-click does not create two orders" — not a per-feature keyword.
844
+ rule: 'claim.no-side-effect',
836
845
  claim: 'no-side-effect/no-duplicate',
837
846
  // The negation must attach to an EFFECT — something created, sent, stored, charged, fired
838
847
  // twice — not to the INPUT being refused. "duplicate address is rejected" is an observable
@@ -850,33 +859,33 @@ const CLAIM_RULES: ClaimRule[] = [
850
859
  proof: /\bcount\b|ok_count|status_counts|row with \{\{|table with|tohavecount|is hidden|are hidden|is disabled|are disabled|not complete|no longer/,
851
860
  need: 'a record/request-count proof (count stays at one, e.g. `User see [Table] row with {{count}}`, an API `{{name.ok_count}}` invariant, or a `@query` DB count) or @manual with a request-count oracle',
852
861
  hint: 'a "does-not-happen / does-not-repeat" claim about a state-changing action is NOT proven by a terminal `see [...] page` — that page is identical whether or not the action (re-)fired. Prove the side-effect count is unchanged, or mark @manual with a setup→action→assert-no-duplicate oracle.',
853
- severity: 'fail',
854
862
  },
855
863
  {
864
+ rule: 'claim.hidden-rejected',
856
865
  claim: 'hidden/rejected/not-complete',
857
866
  title: /\b(hidden|closed|dismiss(es|ed)?|not complete|rejected|inert)\b/,
858
867
  proof: /\bis hidden\b|\bare hidden\b|message is hidden|not complete|\bhidden\b/,
859
868
  need: 'a negative / hidden assertion (`… is hidden`)',
860
869
  hint: 'assert the absence/hidden state that the title claims, not just an unrelated visible element.',
861
- severity: 'fail',
862
870
  },
863
871
  {
872
+ rule: 'claim.cleared-emptied',
864
873
  claim: 'cleared/emptied',
865
874
  title: /\b(cleared|clears|emptied|empties|reset to empty|wiped)\b/,
866
875
  proof: /\bis empty\b|with \{\{empty|with ['"]?['"]?\s*$|\bempty\b/,
867
876
  need: 'an empty/cleared assertion after the action (e.g. `field with {{empty_value}}` / `is empty`)',
868
877
  hint: 'prove the value is actually gone — return to the screen and assert the field is empty, not just that the action ran.',
869
- severity: 'fail',
870
878
  },
871
879
  {
880
+ rule: 'claim.restored-preserved',
872
881
  claim: 'restored/preserved',
873
882
  title: /\b(restored|preserved|persists?|retained|remembered|kept)\b/,
874
883
  proof: /\bremember\b|with \{\{|field with/,
875
884
  need: 'the value re-asserted after the transition (capture or `field with {{v}}` after returning)',
876
885
  hint: 'prove the value survives — assert the field still holds the typed value after the reload/return, not just that it was typed.',
877
- severity: 'warn',
878
886
  },
879
887
  {
888
+ rule: 'claim.independent-separate',
880
889
  claim: 'independent/separate',
881
890
  title: /\b(independent|separate|isolat(ed|es)|per[- ]tab|two tabs|each tab)\b/,
882
891
  // A storage `does not exist` check on the OTHER tenant's key proves isolation
@@ -885,23 +894,22 @@ const CLAIM_RULES: ClaimRule[] = [
885
894
  proof: /\bcontext\b|tab a|tab b|second (tab|context)|does not exist/,
886
895
  need: 'a multi-context proof (tab A vs tab B)',
887
896
  hint: 'independence across tabs/contexts is rarely DSL-expressible — mark @manual with a clear setup/action/oracle.',
888
- severity: 'warn',
889
897
  },
890
898
  {
899
+ rule: 'claim.sanitized-inert',
891
900
  claim: 'sanitized/inert',
892
901
  title: /\b(sanitized|sanitised|escaped|inert|not executed|not rendered|stripped)\b/,
893
902
  proof: /field with \{\{|payload|inert|toContainText|is hidden/,
894
903
  need: 'the payload echoed as inert text (`field with {{payload}}`) + no execution',
895
904
  hint: 'prove the payload round-trips as literal text and triggers nothing — assert the field value and the absence of any effect.',
896
- severity: 'warn',
897
905
  },
898
906
  {
907
+ rule: 'claim.announces-aria',
899
908
  claim: 'announces/aria',
900
909
  title: /\b(announce[sd]?|aria|screen[- ]reader|programmatically associated)\b/,
901
910
  proof: /aria|role|@manual|describedby|is focused|tab order/,
902
911
  need: 'an aria/role assertion (or @manual with a screen-reader oracle)',
903
912
  hint: 'ARIA announcement is usually not DSL-expressible — assert aria attributes if possible, else @manual with an NVDA/VoiceOver oracle.',
904
- severity: 'warn',
905
913
  },
906
914
  {
907
915
  // GENERAL CATCH-ALL (last) — any negative/absence title not handled by a specific
@@ -911,6 +919,7 @@ const CLAIM_RULES: ClaimRule[] = [
911
919
  // only a positive presence. WARN, because a positive proxy is sometimes a valid
912
920
  // negative proof (e.g. "stayed on the login page"); the semantic reviewer is the
913
921
  // authoritative recall layer for the residue this can't judge structurally.
922
+ rule: 'claim.negative-absence',
914
923
  claim: 'negative-claim/absence',
915
924
  title: /(\bno\b|\bnot\b|n['’]t\b|\bnever\b|\bwithout\b|\bcannot\b|prevent|block|avoid|reject|disabl|\bdeny\b|denies|\bkhông\b|\bchưa\b)/i,
916
925
  // `does not exist` covers the storage-absence shape — the broad "any storage
@@ -920,7 +929,6 @@ const CLAIM_RULES: ClaimRule[] = [
920
929
  proof: /is hidden|are hidden|is empty|no longer|not complete|disabl|invalid|rejected|\berror\b|\bcount\b|row with \{\{|table with|\bremember\b|\bexactly\b|tohavecount|does not exist|tab order/i,
921
930
  need: 'a proof of the ABSENCE — a contrast/empty/hidden/error/count assertion, or @manual with an oracle',
922
931
  hint: 'a negative claim ("no / not / không …") is not proven by a positive `see [X]` that looks the same whether or not the claim holds. Assert the contrast (state hidden/empty, error shown, count unchanged), or mark @manual.',
923
- severity: 'warn',
924
932
  },
925
933
  ];
926
934
 
@@ -947,7 +955,14 @@ export interface TaxonomyResult {
947
955
 
948
956
  const TAXONOMY_KNOWN = new Set(['LIST', 'PRODUCT', 'CART', 'FILTER', 'NAV', 'VAL', 'SEC']);
949
957
 
950
- const CATEGORY_SIGNALS: { cat: string; re: RegExp }[] = [
958
+ /**
959
+ * Words of ACCESS — a title about who may reach something. They make the robustness/routing words
960
+ * below security evidence ("deep link without authentication"); alone those words describe routing.
961
+ */
962
+ const ACCESS_CONTEXT = /\b(xss|sql|injection|without authentication|unauthenticated|unauthori[sz]ed|without an? (?:authenticated|valid|active) \w+|without (?:permission|login|logging in|signing in|an? account|access)|not (?:logged|signed) in|logged[- ]out|direct(?:ly)? access\w*|auth[- ]?guard|forbidden|\b403\b|(?:no|insufficient|missing) permissions?|permission required|session expired|expired session|tamper\w*)\b/;
963
+
964
+ /** `requires`: the signal counts only when the title ALSO matches it (#888). */
965
+ const CATEGORY_SIGNALS: { cat: string; re: RegExp; requires?: RegExp }[] = [
951
966
  { cat: 'FILTER', re: /\b(categor(y|ies)|sub-?categor\w*|expand\w*|collaps\w*|\bfacet\b|filter\w*|belongs? to)\b/ },
952
967
  { cat: 'CART', re: /\b(add(ed|ing)? to cart|added (dialog|modal|message|confirmation)|cart (page|table|line|item)|view cart|continue shopping|quantit)\b/ },
953
968
  { cat: 'PRODUCT', re: /\b(product detail|product-detail|view product|product page|same product|product name and price|product identity|detail product)\b/ },
@@ -959,9 +974,16 @@ const CATEGORY_SIGNALS: { cat: string; re: RegExp }[] = [
959
974
  // SEC, so the linter told QA to re-tag genuine auth-gate tests as navigation — diluting the
960
975
  // visibility of the security suite (QA field report, 3.2.23). The guard vocabulary below is
961
976
  // what makes the INTENT matchable, and GUARD_INTENT then wins over a mere observable.
962
- { cat: 'SEC', re: /\b(xss|sql|injection|payload|without authentication|unauthenticated|without an? (?:authenticated|valid|active) \w+|direct(?:ly)? access\w*|deep[- ]link\w*|auth[- ]?guard|not skippable|without having (?:completed|submitted|logged)|remains? unauthenticated|\binert\b|tamper\w*|malformed|url parameter|query param\w*|falls? back|gracefull?y|without a crash|not[- ]found|\b404\b|special character|abuse)\b/ },
977
+ { cat: 'SEC', re: /\b(xss|sql|injection|payload|without authentication|unauthenticated|without an? (?:authenticated|valid|active) \w+|direct(?:ly)? access\w*|auth[- ]?guard|not skippable|without having (?:completed|submitted|logged)|remains? unauthenticated|\binert\b|tamper\w*|malformed|special character|abuse)\b/ },
978
+ // Robustness and routing words are SEC evidence only beside an ACCESS word. Alone they describe
979
+ // routing — "Unknown route shows the 404 page", "Deep link opens the item", "the tab from the url
980
+ // parameter" — and the linter told QA to re-tag those navigation tests as VP-SEC (#888).
981
+ { cat: 'SEC', re: /\b(deep[- ]link\w*|url parameter|query param\w*|falls? back|gracefull?y|without a crash|not[- ]found|\b404\b)\b/, requires: ACCESS_CONTEXT },
963
982
  ];
964
983
 
984
+ const signalMatches = (c: { re: RegExp; requires?: RegExp }, title: string): boolean =>
985
+ c.re.test(title) && (!c.requires || c.requires.test(title));
986
+
965
987
  /**
966
988
  * Categories whose signal describes the test's INTENT/risk rather than the observable action.
967
989
  * When one of these matches, a competing observable-only category (NAV: "redirects", "navigates")
@@ -979,14 +1001,19 @@ export function taxonomyLint(scenarios: ScenarioInfo[]): TaxonomyResult {
979
1001
  if (!cat || !TAXONOMY_KNOWN.has(cat)) continue;
980
1002
  checked++;
981
1003
  const title = s.name.toLowerCase();
982
- const matched = [...new Set(CATEGORY_SIGNALS.filter((c) => c.re.test(title)).map((c) => c.cat))];
1004
+ const matched = [...new Set(CATEGORY_SIGNALS.filter((c) => signalMatches(c, title)).map((c) => c.cat))];
983
1005
  if (matched.includes(cat)) continue; // title supports its own category → fine
1006
+ // A gate (`requires`) only stops a word from SUGGESTING its category. An author who already
1007
+ // chose that category is supported by the word alone: a VP-SEC "Deep link to the filtered
1008
+ // list …" stays SEC instead of being pushed toward FILTER (#888 review).
1009
+ if (CATEGORY_SIGNALS.some((c) => c.cat === cat && c.requires && c.re.test(title))) continue;
984
1010
  // The declared category may be an INTENT category whose signal this title spells
985
1011
  // differently; never "correct" it toward a category that only names the observable.
986
1012
  const suppressed = INTENT_OVER_OBSERVABLE[cat];
987
1013
  const others = matched.filter((c) => c !== cat && !(suppressed && suppressed.has(c)));
988
1014
  if (others.length === 1) { // unambiguous mismatch
989
- const sig = CATEGORY_SIGNALS.find((c) => c.cat === others[0])!;
1015
+ // The entry that MATCHED — a category can have several (SEC: guard words, gated robustness words).
1016
+ const sig = CATEGORY_SIGNALS.find((c) => c.cat === others[0] && signalMatches(c, title))!;
990
1017
  const m = title.match(sig.re);
991
1018
  mislabeled.push({ name: s.name, current: cat, suggested: others[0], signal: m ? m[0] : others[0] });
992
1019
  }
@@ -994,7 +1021,12 @@ export function taxonomyLint(scenarios: ScenarioInfo[]): TaxonomyResult {
994
1021
  return { total: scenarios.length, checked, mislabeled };
995
1022
  }
996
1023
 
997
- export function claimProof(scenarios: ScenarioInfo[], focus = 'functional'): ClaimProofResult {
1024
+ /**
1025
+ * `rules` resolves each row's catalog rule for the unit being audited (the catalog alone by default —
1026
+ * today's levels). A rule switched `off` by a gate-override is not measured: its unproven claim is
1027
+ * neither counted nor reported (a partial-proof switched off leaves the claim proven).
1028
+ */
1029
+ export function claimProof(scenarios: ScenarioInfo[], focus = 'functional', rules: GateRules = CATALOG_GATE_RULES): ClaimProofResult {
998
1030
  const measured = scenarios.filter((s) => !s.manual);
999
1031
  const unproven: ClaimUnproven[] = [];
1000
1032
  let withClaims = 0;
@@ -1003,19 +1035,17 @@ export function claimProof(scenarios: ScenarioInfo[], focus = 'functional'): Cla
1003
1035
  const title = s.name.toLowerCase();
1004
1036
  const rule = CLAIM_RULES.find((r) => r.title.test(title));
1005
1037
  if (!rule) continue; // no claim → not measured
1038
+ const miss = !rule.proof.test(s.stepsText)
1039
+ // proof shape entirely absent → the claim's own rule decides the level
1040
+ ? { rule: rule.rule, need: rule.need, hint: rule.hint }
1041
+ : rule.underproof && rule.underproof.test(s.stepsText)
1042
+ // right shape exists but only as a partial proof
1043
+ ? { rule: 'claim.partial-proof', need: rule.underNeed ?? rule.need, hint: rule.underHint ?? rule.hint }
1044
+ : null;
1045
+ const severity = miss ? sensorSeverityOf(rules.resolve(miss.rule)) : undefined;
1046
+ if (miss && severity === null && miss.rule === rule.rule) continue; // the claim's rule is off for this unit
1006
1047
  withClaims++;
1007
- if (!rule.proof.test(s.stepsText)) {
1008
- // proof shape entirely absent → fail at the rule's severity
1009
- unproven.push({ name: s.name, claim: rule.claim, need: rule.need, hint: rule.hint, severity: rule.severity });
1010
- } else if (rule.underproof && rule.underproof.test(s.stepsText)) {
1011
- // right shape exists but only as a partial proof → warn
1012
- unproven.push({
1013
- name: s.name, claim: rule.claim,
1014
- need: rule.underNeed ?? rule.need,
1015
- hint: rule.underHint ?? rule.hint,
1016
- severity: 'warn',
1017
- });
1018
- }
1048
+ if (miss && severity) unproven.push({ name: s.name, claim: rule.claim, need: miss.need, hint: miss.hint, severity, rule: miss.rule });
1019
1049
  }
1020
1050
 
1021
1051
  const proven = withClaims - unproven.length;
@@ -1023,10 +1053,7 @@ export function claimProof(scenarios: ScenarioInfo[], focus = 'functional'): Cla
1023
1053
  const threshold = DEPTH_THRESHOLDS[focus] ?? DEPTH_THRESHOLDS.functional;
1024
1054
 
1025
1055
  const hasFail = unproven.some((u) => u.severity === 'fail');
1026
- let verdict: DepthVerdict = 'pass';
1027
- if (ratio < threshold) {
1028
- verdict = WARN_ONLY_FOCUS.has(focus) || !hasFail ? 'warn' : 'fail';
1029
- }
1056
+ const verdict = ruleVerdict(rules, 'audit.claim-proof', ratio < threshold, WARN_ONLY_FOCUS.has(focus) || !hasFail);
1030
1057
 
1031
1058
  return { total: measured.length, withClaims, proven, unproven, ratio, focus, threshold, verdict };
1032
1059
  }
@@ -1058,9 +1085,8 @@ export function numericClaimGaps(scenarios: ScenarioInfo[]): Array<{ name: strin
1058
1085
  if (!m) continue;
1059
1086
  const claimed = NUMBER_WORDS[m[1]] ?? Number(m[1]);
1060
1087
  if (!Number.isFinite(claimed) || claimed < 2) continue;
1061
- // Only value-bearing assertions count: `see [X] … with/contains {{v}}`. A visibility check
1062
- // does not demonstrate one of N values.
1063
- const asserted = (s.stepsText.match(/\bsee \[[^\]]+\][^|]*?\b(?:with|contains) \{\{/g) ?? []).length;
1088
+ // Values, positive states and indicator presence count; plain text visibility does not (#866).
1089
+ const asserted = countedAssertions(s.stepsText);
1064
1090
  if (asserted > 0 && asserted < claimed) out.push({ name: s.name, claimed, asserted, noun: m[2] });
1065
1091
  }
1066
1092
  return out;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Triage signal library — the ordered message patterns `sungen triage` matches a red scenario's
3
+ * error against. Seeded from the repair rules (`harness/repair.ts`, driver-mobile `mobile-repair.ts`);
4
+ * the patterns are COPIED, not imported, because core never loads a driver at runtime. The parity
5
+ * check in tests/harness/triage-classification.run.ts keeps the environment rules in step.
6
+ *
7
+ * Order matters and is the classification order: environment first (nothing about the test or the
8
+ * app can be judged when the session never started), then test defects (the test never reached the
9
+ * app). Assertions are decided in triage.ts from the parsed Expected/Received, not here.
10
+ */
11
+ export type SignalClass = 'environment' | 'test-defect';
12
+
13
+ export interface TriageSignal {
14
+ id: string;
15
+ class: SignalClass;
16
+ match: RegExp;
17
+ }
18
+
19
+ export const TRIAGE_SIGNALS: TriageSignal[] = [
20
+ // --- environment: the run could not reach a usable app/session -----------------------------------
21
+ { id: 'env-network', class: 'environment', match: /net::ERR_[A-Z_]+|\bECONNREFUSED\b|\bENOTFOUND\b|\bEAI_AGAIN\b|\bETIMEDOUT\b/ },
22
+ // mirrors mobile-session-not-created
23
+ { id: 'env-session-not-created', class: 'environment', match: /A new session could not be created|session not created/i },
24
+ // mirrors mobile-driver-proxy-lost
25
+ { id: 'env-driver-proxy-lost', class: 'environment', match: /Could not proxy command to (?:the )?remote server|socket hang up|ECONNRESET/ },
26
+ // mirrors mobile-instrumentation-failed
27
+ { id: 'env-instrumentation-failed', class: 'environment', match: /instrumentation process (?:cannot|could not) be (?:initialized|started)|Cannot start the instrumentation process/ },
28
+ // mirrors mobile-chromedriver-mismatch
29
+ { id: 'env-chromedriver-mismatch', class: 'environment', match: /No Chromedriver found|chromedriver.*(?:version|mismatch)|Chrome version must be/i },
30
+ // mirrors mobile-webview-context-absent
31
+ { id: 'env-webview-context-absent', class: 'environment', match: /no WEBVIEW\/CHROMIUM context appeared within/ },
32
+ { id: 'env-auth-state-missing', class: 'environment', match: /storageState|\.auth\/[\w.-]+\.json|ENOENT[^\n]*\.auth/ },
33
+ { id: 'env-base-url-unresolved', class: 'environment', match: /Cannot navigate to invalid URL|baseURL (?:is )?(?:not set|undefined)|Invalid URL/ },
34
+ { id: 'env-browser-closed', class: 'environment', match: /Target page, context or browser has been closed|browserType\.launch/ },
35
+
36
+ // --- test defect: the test could not reach the element or its data -------------------------------
37
+ { id: 'test-strict-mode', class: 'test-defect', match: /strict mode violation/ },
38
+ { id: 'test-locator-unresolved', class: 'test-defect', match: /locator\.\w+: [^\n]*(?:Timeout|timeout)[^\n]*exceeded[\s\S]*waiting for |resolved to 0 elements/ },
39
+ { id: 'test-element-absent', class: 'test-defect', match: /no such element|Element not found:|An element could not be located/ },
40
+ { id: 'test-data-missing', class: 'test-defect', match: /Test data key not found:|@cases dataset "[^"]+" not found/ },
41
+ { id: 'test-step-unmatched', class: 'test-defect', match: /\[sungen\] step "[^"]*" matched no pattern|\bSG\d{3}\b/ },
42
+ { id: 'test-tap-intercepted', class: 'test-defect', match: /element click intercepted|is not clickable at point|element is obscured|intercepts pointer events/i },
43
+ ];
44
+
45
+ /** A failure that is only Playwright's test-level timeout — no locator, no assertion detail (→ unclassified). */
46
+ export const BARE_TIMEOUT = /^(?:Error:\s*)?Test timeout of \d+ms exceeded\.?$/;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * `sungen triage` IO: find a unit's feature(s) and result file(s), join them on the same seam
3
+ * delivery and the dashboard use (`mergeFeatureAndSpec` + `resolveResultVariants`), classify each
4
+ * scenario, and persist `.sungen/triage/<unit>.json`. Read-only apart from that one report file.
5
+ */
6
+ import * as fs from 'fs';
7
+ import * as path from 'path';
8
+ import { parseFeatureMetadata } from '../exporters/feature-parser';
9
+ import { loadPlaywrightReport, resolveResultsPath } from '../exporters/playwright-report-parser';
10
+ import { collectQaEnvSecretDenylist } from '../exporters/qa-env-secret-denylist';
11
+ import { isSensitiveKey } from '../exporters/sensitive-key';
12
+ import { resolveResultVariants } from '../exporters/result-variants';
13
+ import { mergeFeatureAndSpec } from '../exporters/scenario-merger';
14
+ import { parseSpecFile } from '../exporters/spec-parser';
15
+ import { loadTestData } from '../exporters/test-data-resolver';
16
+ import type { ResolvedUnit } from '../cli/resolve-unit';
17
+ import { classifyScenario, TriageClass, TriageRow } from './triage';
18
+
19
+ export interface TriageReport {
20
+ unit: string;
21
+ generatedAt: string;
22
+ /** Result files read, relative to the project root. Empty → nothing has run yet. */
23
+ resultFiles: string[];
24
+ counts: Partial<Record<TriageClass, number>>;
25
+ rows: TriageRow[];
26
+ }
27
+
28
+ /**
29
+ * Values that must never reach a triage evidence line or a defect record: the resolved `${QA_*}`
30
+ * secrets AND the literal values of credential-named test-data keys — an assertion on a password
31
+ * field prints that value in its Expected/Received.
32
+ */
33
+ export function unitSecrets(testData: Record<string, string>, cwd: string): string[] {
34
+ const literal = Object.entries(testData)
35
+ .filter(([k, v]) => isSensitiveKey(k) && typeof v === 'string' && v.length >= 3 && !v.includes('${'))
36
+ .map(([, v]) => String(v));
37
+ return [...new Set([...collectQaEnvSecretDenylist(testData, cwd).values, ...literal])].sort((a, b) => b.length - a.length);
38
+ }
39
+
40
+ function generatedDir(cwd: string, u: ResolvedUnit): string {
41
+ return path.join(cwd, 'specs', 'generated', u.unitId);
42
+ }
43
+
44
+ /**
45
+ * Every result file of one feature, labelled by variant: `<base>-test-result.json` (no label),
46
+ * `<base>-test-result.<os|env>[.<env>].json` (label = the middle part). A mobile unit has only
47
+ * per-OS files, so all of them are read rather than the first one found. Falls back to the shared
48
+ * lookup (incl. `test-results/results.json`) when the generated dir holds none.
49
+ */
50
+ function resultFilesFor(cwd: string, genDir: string, base: string): Array<{ file: string; variant?: string }> {
51
+ const prefix = `${base}-test-result`;
52
+ const own = fs.existsSync(genDir)
53
+ ? fs.readdirSync(genDir).filter((f) => f.startsWith(prefix) && f.endsWith('.json')).sort()
54
+ : [];
55
+ if (own.length > 0) {
56
+ return own.map((f) => {
57
+ const variant = f.slice(prefix.length, -'.json'.length).replace(/^\./, '');
58
+ return { file: path.join(genDir, f), ...(variant ? { variant } : {}) };
59
+ });
60
+ }
61
+ const shared = resolveResultsPath(cwd, genDir, base);
62
+ return shared ? [{ file: shared }] : [];
63
+ }
64
+
65
+ export function triageUnit(cwd: string, u: ResolvedUnit): TriageReport {
66
+ const genDir = generatedDir(cwd, u);
67
+ const featuresDir = path.join(u.dir, 'features');
68
+ const features = fs.existsSync(featuresDir) ? fs.readdirSync(featuresDir).filter((f) => f.endsWith('.feature')).sort() : [];
69
+ const rows: TriageRow[] = [];
70
+ const resultFiles: string[] = [];
71
+
72
+ for (const f of features) {
73
+ const base = f.replace(/\.feature$/, '');
74
+ const files = resultFilesFor(cwd, genDir, base);
75
+ if (files.length === 0) continue;
76
+ const merged = mergeFeatureAndSpec(parseFeatureMetadata(path.join(featuresDir, f)), parseSpecFile(path.join(genDir, `${base}.spec.ts`)));
77
+ const dataFile = path.join(u.dir, 'test-data', `${base}.yaml`);
78
+ const testData = fs.existsSync(dataFile) ? loadTestData(dataFile) : {};
79
+ const secrets = unitSecrets(testData, cwd);
80
+
81
+ for (const { file, variant } of files) {
82
+ resultFiles.push(path.relative(cwd, file));
83
+ const results = loadPlaywrightReport(file);
84
+ for (const m of merged) {
85
+ for (const v of resolveResultVariants(m, results, testData)) {
86
+ const r = classifyScenario({ unit: u.unitId, title: `${m.feature.name}${v.nameSuffix}`, tags: m.feature.tags, result: v.result, variant }, secrets);
87
+ if (r) rows.push(r);
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ const counts: Partial<Record<TriageClass, number>> = {};
94
+ for (const r of rows) counts[r.class] = (counts[r.class] ?? 0) + 1;
95
+ return { unit: u.unitId, generatedAt: new Date().toISOString(), resultFiles, counts, rows };
96
+ }
97
+
98
+ export function triageReportPath(cwd: string, unitId: string): string {
99
+ return path.join(cwd, '.sungen', 'triage', `${unitId.replace(/\//g, '-')}.json`);
100
+ }
101
+
102
+ /** The last triage of a unit, or null when `sungen triage` has not run for it. */
103
+ export function readTriageReport(cwd: string, unitId: string): TriageReport | null {
104
+ try { return JSON.parse(fs.readFileSync(triageReportPath(cwd, unitId), 'utf-8')) as TriageReport; } catch { return null; }
105
+ }
106
+
107
+ /** Persist under `.sungen/triage/<unit>.json` (a flow `flows/x` → `flows-x.json`); returns the path. */
108
+ export function writeTriageReport(cwd: string, report: TriageReport): string {
109
+ const out = triageReportPath(cwd, report.unit);
110
+ fs.mkdirSync(path.dirname(out), { recursive: true });
111
+ fs.writeFileSync(out, `${JSON.stringify(report, null, 2)}\n`, 'utf-8');
112
+ return out;
113
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * `sungen triage` — classify each red or flaky scenario of a run into exactly one class, with the
3
+ * rule that fired and one evidence line. Deterministic and read-only; it reports, it never gates.
4
+ *
5
+ * Order (first match wins):
6
+ * 1. known-defect `@known-defect` / `@known-defect:<id>` — an expected red.
7
+ * 2. blocked-capability `@manual:*` / `@requires:*`, or skipped by design.
8
+ * 3. environment the session or network never gave the test a usable app.
9
+ * 4. test-defect the test could not reach its element or data.
10
+ * 5. product-candidate an assertion whose Expected and Received both exist and differ.
11
+ * 6. unclassified anything else — left for the agent or QA, with the raw first message.
12
+ * A `passed` scenario that needed a retry is `flaky` (green, listed separately).
13
+ *
14
+ * 5 is tested before 3 and 4 in code: a parsed Expected/Received pair that differs means the app
15
+ * answered, which outranks any wrapper text (a test timeout around the assertion included).
16
+ *
17
+ * A bare test timeout (no locator, no assertion) is `unclassified` too: a slow environment, a page
18
+ * that hangs on a product bug and a test waiting on the wrong thing all print the same line.
19
+ *
20
+ * An assertion on an element that never appeared (`Received: <element(s) not found>`) is NOT a test
21
+ * defect: a wrong selector and a missing message look identical, so it is left for judgment rather
22
+ * than hiding a possible product bug behind "fix the selector".
23
+ */
24
+ import { redactSecrets } from '../exporters/api-testcase-formatter';
25
+ import { parseExpectedReceived } from '../exporters/playwright-report-parser';
26
+ import type { PlaywrightResult } from '../exporters/types';
27
+ import { BARE_TIMEOUT, TRIAGE_SIGNALS } from './triage-signals';
28
+
29
+ export type TriageClass =
30
+ | 'known-defect' | 'blocked-capability' | 'environment' | 'test-defect' | 'product-candidate' | 'unclassified' | 'flaky';
31
+
32
+ export interface TriageInput {
33
+ unit: string;
34
+ title: string;
35
+ tags: string[];
36
+ result?: PlaywrightResult;
37
+ /** Result-file variant (`android`, `ios`, an env name) when the unit has several. */
38
+ variant?: string;
39
+ }
40
+
41
+ export interface TriageRow {
42
+ unit: string;
43
+ scenario: string;
44
+ variant?: string;
45
+ class: TriageClass;
46
+ ruleId: string;
47
+ evidence: string;
48
+ ids: string[];
49
+ legacy: string[];
50
+ defectId?: string;
51
+ tracePath?: string;
52
+ /** product-candidate only: the two halves of the assertion, for a defect draft. */
53
+ expected?: string;
54
+ received?: string;
55
+ }
56
+
57
+ const EVIDENCE_MAX = 200;
58
+ const VIEWPOINT_ID = /\b(?:VP|FL)-[A-Z0-9]+(?:-[A-Z0-9]+)*\b/gi;
59
+ const ELEMENT_ABSENT = /Received:\s*<element\(s\) not found>/;
60
+
61
+ /** The part of a message the run itself wrote: before `Call log:`, without `Locator:` echo lines. */
62
+ const runHead = (m: string): string => m.split(/\n\s*Call log:/)[0].replace(/^\s*Locator:.*$/gm, '');
63
+
64
+ /** Every failure message, stack frames and a leading `Error:` dropped. */
65
+ function messagesOf(result: PlaywrightResult): string[] {
66
+ const raw = result.errorMessages?.length ? result.errorMessages : [result.error ?? ''];
67
+ return raw.map((m) => m.split(/\n\s*at\s/)[0].replace(/^Error:\s*/i, '').trim()).filter(Boolean);
68
+ }
69
+
70
+ function evidenceLine(text: string, secrets: string[]): string {
71
+ const flat = redactSecrets(text, secrets).replace(/\s+/g, ' ').trim();
72
+ return flat.length > EVIDENCE_MAX ? `${flat.slice(0, EVIDENCE_MAX - 1)}…` : flat;
73
+ }
74
+
75
+ /** Classify one scenario. Null when it needs no triage (clean pass, or never ran). */
76
+ export function classifyScenario(input: TriageInput, secrets: string[] = []): TriageRow | null {
77
+ const { result, tags } = input;
78
+ if (!result) return null;
79
+ const base = {
80
+ unit: input.unit,
81
+ scenario: input.title,
82
+ ...(input.variant ? { variant: input.variant } : {}),
83
+ ids: [...new Set([input.title, ...tags].join(' ').match(VIEWPOINT_ID) ?? [])],
84
+ legacy: tags.filter((t) => t.startsWith('@legacy:')).map((t) => t.slice('@legacy:'.length)),
85
+ ...(result.tracePath ? { tracePath: result.tracePath } : {}),
86
+ };
87
+ const row = (cls: TriageClass, ruleId: string, evidence: string): TriageRow =>
88
+ ({ ...base, class: cls, ruleId, evidence: evidenceLine(evidence, secrets) });
89
+
90
+ if (result.status === 'passed') {
91
+ return (result.attempts ?? 1) > 1 ? row('flaky', 'passed-after-retry', `passed on attempt ${result.attempts}`) : null;
92
+ }
93
+ const messages = messagesOf(result);
94
+ const first = messages[0] ?? result.status;
95
+
96
+ const known = tags.find((t) => t === '@known-defect' || t.startsWith('@known-defect:'));
97
+ if (known) {
98
+ const r = row('known-defect', 'tag-known-defect', first);
99
+ const id = known.split(':')[1];
100
+ return id ? { ...r, defectId: id } : r;
101
+ }
102
+ if (tags.some((t) => t.startsWith('@manual'))) return row('blocked-capability', 'tag-manual', `${tags.find((t) => t.startsWith('@manual'))} — ${first}`);
103
+ if (tags.some((t) => t.startsWith('@requires:'))) return row('blocked-capability', 'tag-requires', `${tags.find((t) => t.startsWith('@requires:'))} — ${first}`);
104
+ if (result.status === 'skipped') return row('blocked-capability', 'status-skipped', 'skipped');
105
+
106
+ // An assertion with both halves decides the case even when a timeout wraps it.
107
+ for (const m of messages) {
108
+ const { expected, received } = parseExpectedReceived(m);
109
+ if (expected && received && !ELEMENT_ABSENT.test(m) && expected !== received) {
110
+ return { ...row('product-candidate', 'assertion-mismatch', `Expected ${expected} · Received ${received}`),
111
+ expected: evidenceLine(expected, secrets), received: evidenceLine(received, secrets) };
112
+ }
113
+ }
114
+ for (const s of TRIAGE_SIGNALS) {
115
+ // Environment signals read only what the RUN said, never the test's own selector text that a
116
+ // message echoes in `Locator:` / `Call log:` — `getByText('Invalid URL')` is a missing message,
117
+ // not a bad base URL. Test-defect signals need the call log (`waiting for …`), so they read it all.
118
+ const hit = messages.find((m) => s.match.test(s.class === 'environment' ? runHead(m) : m));
119
+ if (hit) return row(s.class, s.id, hit);
120
+ }
121
+ const absent = messages.find((m) => ELEMENT_ABSENT.test(m));
122
+ if (absent) return row('unclassified', 'assertion-element-absent', absent);
123
+ if (messages.length > 0 && messages.every((m) => BARE_TIMEOUT.test(m))) {
124
+ return row('unclassified', 'bare-timeout', `${first} No locator or assertion detail: a slow environment, a hanging page, or a wait in the test. Re-run once, then read the trace's last action.`);
125
+ }
126
+ return row('unclassified', 'no-signal', first);
127
+ }