@sun-asterisk/sungen 3.2.35 → 3.3.0-alpha.10

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 (969) 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/case-triage-hint.d.ts +14 -0
  41. package/dist/cli/case-triage-hint.d.ts.map +1 -0
  42. package/dist/cli/case-triage-hint.js +23 -0
  43. package/dist/cli/case-triage-hint.js.map +1 -0
  44. package/dist/cli/commands/audit.js +1 -1
  45. package/dist/cli/commands/audit.js.map +1 -1
  46. package/dist/cli/commands/capability.js +1 -1
  47. package/dist/cli/commands/capability.js.map +1 -1
  48. package/dist/cli/commands/contract-derive-command.d.ts +12 -0
  49. package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
  50. package/dist/cli/commands/contract-derive-command.js +113 -0
  51. package/dist/cli/commands/contract-derive-command.js.map +1 -0
  52. package/dist/cli/commands/contract.d.ts +20 -0
  53. package/dist/cli/commands/contract.d.ts.map +1 -0
  54. package/dist/cli/commands/contract.js +195 -0
  55. package/dist/cli/commands/contract.js.map +1 -0
  56. package/dist/cli/commands/delivery.d.ts.map +1 -1
  57. package/dist/cli/commands/delivery.js +109 -19
  58. package/dist/cli/commands/delivery.js.map +1 -1
  59. package/dist/cli/commands/gate.d.ts.map +1 -1
  60. package/dist/cli/commands/gate.js +2 -1
  61. package/dist/cli/commands/gate.js.map +1 -1
  62. package/dist/cli/commands/generate.d.ts.map +1 -1
  63. package/dist/cli/commands/generate.js +17 -3
  64. package/dist/cli/commands/generate.js.map +1 -1
  65. package/dist/cli/commands/journey.d.ts.map +1 -1
  66. package/dist/cli/commands/journey.js +47 -17
  67. package/dist/cli/commands/journey.js.map +1 -1
  68. package/dist/cli/commands/next.d.ts +13 -0
  69. package/dist/cli/commands/next.d.ts.map +1 -1
  70. package/dist/cli/commands/next.js +98 -9
  71. package/dist/cli/commands/next.js.map +1 -1
  72. package/dist/cli/commands/triage.d.ts +2 -1
  73. package/dist/cli/commands/triage.d.ts.map +1 -1
  74. package/dist/cli/commands/triage.js +45 -3
  75. package/dist/cli/commands/triage.js.map +1 -1
  76. package/dist/cli/commands/update.d.ts +11 -0
  77. package/dist/cli/commands/update.d.ts.map +1 -1
  78. package/dist/cli/commands/update.js +37 -8
  79. package/dist/cli/commands/update.js.map +1 -1
  80. package/dist/cli/index.js +24 -33
  81. package/dist/cli/index.js.map +1 -1
  82. package/dist/cli/json-error-on-exit.d.ts +34 -0
  83. package/dist/cli/json-error-on-exit.d.ts.map +1 -0
  84. package/dist/cli/json-error-on-exit.js +63 -0
  85. package/dist/cli/json-error-on-exit.js.map +1 -0
  86. package/dist/cli/project-sungen-invocation.d.ts +13 -0
  87. package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
  88. package/dist/cli/project-sungen-invocation.js +95 -0
  89. package/dist/cli/project-sungen-invocation.js.map +1 -0
  90. package/dist/cli/run-command-hints.d.ts +9 -0
  91. package/dist/cli/run-command-hints.d.ts.map +1 -0
  92. package/dist/cli/run-command-hints.js +84 -0
  93. package/dist/cli/run-command-hints.js.map +1 -0
  94. package/dist/cli/waiting-for-you-block.d.ts +18 -0
  95. package/dist/cli/waiting-for-you-block.d.ts.map +1 -0
  96. package/dist/cli/waiting-for-you-block.js +22 -0
  97. package/dist/cli/waiting-for-you-block.js.map +1 -0
  98. package/dist/contract/accept-opaque-steps.d.ts +3 -0
  99. package/dist/contract/accept-opaque-steps.d.ts.map +1 -0
  100. package/dist/contract/accept-opaque-steps.js +114 -0
  101. package/dist/contract/accept-opaque-steps.js.map +1 -0
  102. package/dist/contract/approve-contract.d.ts +38 -0
  103. package/dist/contract/approve-contract.d.ts.map +1 -0
  104. package/dist/contract/approve-contract.js +93 -0
  105. package/dist/contract/approve-contract.js.map +1 -0
  106. package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
  107. package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
  108. package/dist/contract/assertion-matcher-vocabulary.js +100 -0
  109. package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
  110. package/dist/contract/build-contract-verdict.d.ts +32 -0
  111. package/dist/contract/build-contract-verdict.d.ts.map +1 -0
  112. package/dist/contract/build-contract-verdict.js +123 -0
  113. package/dist/contract/build-contract-verdict.js.map +1 -0
  114. package/dist/contract/build-trace-conformance.d.ts +22 -0
  115. package/dist/contract/build-trace-conformance.d.ts.map +1 -0
  116. package/dist/contract/build-trace-conformance.js +151 -0
  117. package/dist/contract/build-trace-conformance.js.map +1 -0
  118. package/dist/contract/classify-contract-change.d.ts +24 -0
  119. package/dist/contract/classify-contract-change.d.ts.map +1 -0
  120. package/dist/contract/classify-contract-change.js +98 -0
  121. package/dist/contract/classify-contract-change.js.map +1 -0
  122. package/dist/contract/classify-contract-unit.d.ts +18 -0
  123. package/dist/contract/classify-contract-unit.d.ts.map +1 -0
  124. package/dist/contract/classify-contract-unit.js +49 -0
  125. package/dist/contract/classify-contract-unit.js.map +1 -0
  126. package/dist/contract/classify-trace-conformance.d.ts +47 -0
  127. package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
  128. package/dist/contract/classify-trace-conformance.js +164 -0
  129. package/dist/contract/classify-trace-conformance.js.map +1 -0
  130. package/dist/contract/contract-git.d.ts +24 -0
  131. package/dist/contract/contract-git.d.ts.map +1 -0
  132. package/dist/contract/contract-git.js +144 -0
  133. package/dist/contract/contract-git.js.map +1 -0
  134. package/dist/contract/contract-hash.d.ts +7 -0
  135. package/dist/contract/contract-hash.d.ts.map +1 -0
  136. package/dist/contract/contract-hash.js +38 -0
  137. package/dist/contract/contract-hash.js.map +1 -0
  138. package/dist/contract/contract-report-file.d.ts +4 -0
  139. package/dist/contract/contract-report-file.d.ts.map +1 -0
  140. package/dist/contract/contract-report-file.js +60 -0
  141. package/dist/contract/contract-report-file.js.map +1 -0
  142. package/dist/contract/contract-schema.d.ts +92 -0
  143. package/dist/contract/contract-schema.d.ts.map +1 -0
  144. package/dist/contract/contract-schema.js +124 -0
  145. package/dist/contract/contract-schema.js.map +1 -0
  146. package/dist/contract/contract-units.d.ts +12 -0
  147. package/dist/contract/contract-units.d.ts.map +1 -0
  148. package/dist/contract/contract-units.js +96 -0
  149. package/dist/contract/contract-units.js.map +1 -0
  150. package/dist/contract/contracts-lock-file.d.ts +24 -0
  151. package/dist/contract/contracts-lock-file.d.ts.map +1 -0
  152. package/dist/contract/contracts-lock-file.js +141 -0
  153. package/dist/contract/contracts-lock-file.js.map +1 -0
  154. package/dist/contract/data-normalize.d.ts +10 -0
  155. package/dist/contract/data-normalize.d.ts.map +1 -0
  156. package/dist/contract/data-normalize.js +110 -0
  157. package/dist/contract/data-normalize.js.map +1 -0
  158. package/dist/contract/derive-free-feature.d.ts +49 -0
  159. package/dist/contract/derive-free-feature.d.ts.map +1 -0
  160. package/dist/contract/derive-free-feature.js +183 -0
  161. package/dist/contract/derive-free-feature.js.map +1 -0
  162. package/dist/contract/field-semantic-redaction.d.ts +21 -0
  163. package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
  164. package/dist/contract/field-semantic-redaction.js +118 -0
  165. package/dist/contract/field-semantic-redaction.js.map +1 -0
  166. package/dist/contract/free-feature-blocks.d.ts +10 -0
  167. package/dist/contract/free-feature-blocks.d.ts.map +1 -0
  168. package/dist/contract/free-feature-blocks.js +94 -0
  169. package/dist/contract/free-feature-blocks.js.map +1 -0
  170. package/dist/contract/lock-secret-guard.d.ts +22 -0
  171. package/dist/contract/lock-secret-guard.d.ts.map +1 -0
  172. package/dist/contract/lock-secret-guard.js +134 -0
  173. package/dist/contract/lock-secret-guard.js.map +1 -0
  174. package/dist/contract/lock-vs-git-head.d.ts +26 -0
  175. package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
  176. package/dist/contract/lock-vs-git-head.js +28 -0
  177. package/dist/contract/lock-vs-git-head.js.map +1 -0
  178. package/dist/contract/normalize-contract-step.d.ts +21 -0
  179. package/dist/contract/normalize-contract-step.d.ts.map +1 -0
  180. package/dist/contract/normalize-contract-step.js +70 -0
  181. package/dist/contract/normalize-contract-step.js.map +1 -0
  182. package/dist/contract/normalize-feature-steps.d.ts +7 -0
  183. package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
  184. package/dist/contract/normalize-feature-steps.js +127 -0
  185. package/dist/contract/normalize-feature-steps.js.map +1 -0
  186. package/dist/contract/oracle-strength.d.ts +12 -0
  187. package/dist/contract/oracle-strength.d.ts.map +1 -0
  188. package/dist/contract/oracle-strength.js +88 -0
  189. package/dist/contract/oracle-strength.js.map +1 -0
  190. package/dist/contract/project-contract-blockers.d.ts +10 -0
  191. package/dist/contract/project-contract-blockers.d.ts.map +1 -0
  192. package/dist/contract/project-contract-blockers.js +75 -0
  193. package/dist/contract/project-contract-blockers.js.map +1 -0
  194. package/dist/contract/record-contract-approval.d.ts +36 -0
  195. package/dist/contract/record-contract-approval.d.ts.map +1 -0
  196. package/dist/contract/record-contract-approval.js +126 -0
  197. package/dist/contract/record-contract-approval.js.map +1 -0
  198. package/dist/contract/render-free-gherkin.d.ts +42 -0
  199. package/dist/contract/render-free-gherkin.d.ts.map +1 -0
  200. package/dist/contract/render-free-gherkin.js +147 -0
  201. package/dist/contract/render-free-gherkin.js.map +1 -0
  202. package/dist/contract/render-trace-sentence.d.ts +20 -0
  203. package/dist/contract/render-trace-sentence.d.ts.map +1 -0
  204. package/dist/contract/render-trace-sentence.js +109 -0
  205. package/dist/contract/render-trace-sentence.js.map +1 -0
  206. package/dist/contract/render-trace-target.d.ts +14 -0
  207. package/dist/contract/render-trace-target.d.ts.map +1 -0
  208. package/dist/contract/render-trace-target.js +70 -0
  209. package/dist/contract/render-trace-target.js.map +1 -0
  210. package/dist/contract/resolve-unit-trace-identities.d.ts +20 -0
  211. package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
  212. package/dist/contract/resolve-unit-trace-identities.js +62 -0
  213. package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
  214. package/dist/contract/trace/collect-trace-evidence.d.ts +44 -0
  215. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
  216. package/dist/contract/trace/collect-trace-evidence.js +219 -0
  217. package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
  218. package/dist/contract/trace/identity-cache.d.ts +19 -0
  219. package/dist/contract/trace/identity-cache.d.ts.map +1 -0
  220. package/dist/contract/trace/identity-cache.js +104 -0
  221. package/dist/contract/trace/identity-cache.js.map +1 -0
  222. package/dist/contract/trace/read-file-once.d.ts +20 -0
  223. package/dist/contract/trace/read-file-once.d.ts.map +1 -0
  224. package/dist/contract/trace/read-file-once.js +135 -0
  225. package/dist/contract/trace/read-file-once.js.map +1 -0
  226. package/dist/contract/trace/scenario-id-claims.d.ts +11 -0
  227. package/dist/contract/trace/scenario-id-claims.d.ts.map +1 -0
  228. package/dist/contract/trace/scenario-id-claims.js +89 -0
  229. package/dist/contract/trace/scenario-id-claims.js.map +1 -0
  230. package/dist/contract/trace/select-final-attempt.d.ts +29 -0
  231. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
  232. package/dist/contract/trace/select-final-attempt.js +119 -0
  233. package/dist/contract/trace/select-final-attempt.js.map +1 -0
  234. package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
  235. package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
  236. package/dist/contract/trace/snapshot-html-renderer.js +172 -0
  237. package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
  238. package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
  239. package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
  240. package/dist/contract/trace/snapshot-resolver.js +65 -0
  241. package/dist/contract/trace/snapshot-resolver.js.map +1 -0
  242. package/dist/contract/trace/snapshot-store.d.ts +66 -0
  243. package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
  244. package/dist/contract/trace/snapshot-store.js +173 -0
  245. package/dist/contract/trace/snapshot-store.js.map +1 -0
  246. package/dist/contract/trace/target-identity.d.ts +74 -0
  247. package/dist/contract/trace/target-identity.d.ts.map +1 -0
  248. package/dist/contract/trace/target-identity.js +68 -0
  249. package/dist/contract/trace/target-identity.js.map +1 -0
  250. package/dist/contract/trace/test-step-join.d.ts +65 -0
  251. package/dist/contract/trace/test-step-join.d.ts.map +1 -0
  252. package/dist/contract/trace/test-step-join.js +80 -0
  253. package/dist/contract/trace/test-step-join.js.map +1 -0
  254. package/dist/contract/trace/trace-binding.d.ts +22 -0
  255. package/dist/contract/trace/trace-binding.d.ts.map +1 -0
  256. package/dist/contract/trace/trace-binding.js +91 -0
  257. package/dist/contract/trace/trace-binding.js.map +1 -0
  258. package/dist/contract/trace/trace-file-reader.d.ts +47 -0
  259. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
  260. package/dist/contract/trace/trace-file-reader.js +137 -0
  261. package/dist/contract/trace/trace-file-reader.js.map +1 -0
  262. package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
  263. package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
  264. package/dist/contract/trace/trace-fingerprint.js +96 -0
  265. package/dist/contract/trace/trace-fingerprint.js.map +1 -0
  266. package/dist/contract/trace/trace-freshness.d.ts +27 -0
  267. package/dist/contract/trace/trace-freshness.d.ts.map +1 -0
  268. package/dist/contract/trace/trace-freshness.js +146 -0
  269. package/dist/contract/trace/trace-freshness.js.map +1 -0
  270. package/dist/contract/trace/trace-identity-resolution.d.ts +28 -0
  271. package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
  272. package/dist/contract/trace/trace-identity-resolution.js +87 -0
  273. package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
  274. package/dist/contract/trace/trace-run-record.d.ts +32 -0
  275. package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
  276. package/dist/contract/trace/trace-run-record.js +135 -0
  277. package/dist/contract/trace/trace-run-record.js.map +1 -0
  278. package/dist/contract/trace/trace-steps.d.ts +19 -0
  279. package/dist/contract/trace/trace-steps.d.ts.map +1 -0
  280. package/dist/contract/trace/trace-steps.js +79 -0
  281. package/dist/contract/trace/trace-steps.js.map +1 -0
  282. package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
  283. package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
  284. package/dist/contract/trace/trace-zip-limits.js +52 -0
  285. package/dist/contract/trace/trace-zip-limits.js.map +1 -0
  286. package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
  287. package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
  288. package/dist/contract/trace/trace-zip-reader.js +186 -0
  289. package/dist/contract/trace/trace-zip-reader.js.map +1 -0
  290. package/dist/contract/verify-approval-decisions.d.ts +5 -0
  291. package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
  292. package/dist/contract/verify-approval-decisions.js +109 -0
  293. package/dist/contract/verify-approval-decisions.js.map +1 -0
  294. package/dist/decisions/append-decision.d.ts +12 -0
  295. package/dist/decisions/append-decision.d.ts.map +1 -0
  296. package/dist/decisions/append-decision.js +73 -0
  297. package/dist/decisions/append-decision.js.map +1 -0
  298. package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
  299. package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
  300. package/dist/decisions/confirmed-decision-commands.js +190 -0
  301. package/dist/decisions/confirmed-decision-commands.js.map +1 -0
  302. package/dist/decisions/decision-file.d.ts +31 -0
  303. package/dist/decisions/decision-file.d.ts.map +1 -0
  304. package/dist/decisions/decision-file.js +139 -0
  305. package/dist/decisions/decision-file.js.map +1 -0
  306. package/dist/decisions/decision-identity.d.ts +12 -0
  307. package/dist/decisions/decision-identity.d.ts.map +1 -0
  308. package/dist/decisions/decision-identity.js +78 -0
  309. package/dist/decisions/decision-identity.js.map +1 -0
  310. package/dist/decisions/decision-integrity-check.d.ts +12 -0
  311. package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
  312. package/dist/decisions/decision-integrity-check.js +102 -0
  313. package/dist/decisions/decision-integrity-check.js.map +1 -0
  314. package/dist/decisions/decision-schema.d.ts +43 -0
  315. package/dist/decisions/decision-schema.d.ts.map +1 -0
  316. package/dist/decisions/decision-schema.js +76 -0
  317. package/dist/decisions/decision-schema.js.map +1 -0
  318. package/dist/decisions/decision-source.d.ts +2 -0
  319. package/dist/decisions/decision-source.d.ts.map +1 -0
  320. package/dist/decisions/decision-source.js +18 -0
  321. package/dist/decisions/decision-source.js.map +1 -0
  322. package/dist/decisions/exclusive-file-create.d.ts +3 -0
  323. package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
  324. package/dist/decisions/exclusive-file-create.js +84 -0
  325. package/dist/decisions/exclusive-file-create.js.map +1 -0
  326. package/dist/decisions/git-head-trust.d.ts +19 -0
  327. package/dist/decisions/git-head-trust.d.ts.map +1 -0
  328. package/dist/decisions/git-head-trust.js +128 -0
  329. package/dist/decisions/git-head-trust.js.map +1 -0
  330. package/dist/decisions/human-confirmation.d.ts +35 -0
  331. package/dist/decisions/human-confirmation.d.ts.map +1 -0
  332. package/dist/decisions/human-confirmation.js +161 -0
  333. package/dist/decisions/human-confirmation.js.map +1 -0
  334. package/dist/decisions/legacy-waiver-migration.d.ts +38 -0
  335. package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
  336. package/dist/decisions/legacy-waiver-migration.js +179 -0
  337. package/dist/decisions/legacy-waiver-migration.js.map +1 -0
  338. package/dist/decisions/read-decisions.d.ts +19 -0
  339. package/dist/decisions/read-decisions.d.ts.map +1 -0
  340. package/dist/decisions/read-decisions.js +90 -0
  341. package/dist/decisions/read-decisions.js.map +1 -0
  342. package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
  343. package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
  344. package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
  345. package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
  346. package/dist/decisions/waiver-decisions.d.ts +24 -0
  347. package/dist/decisions/waiver-decisions.d.ts.map +1 -0
  348. package/dist/decisions/waiver-decisions.js +46 -0
  349. package/dist/decisions/waiver-decisions.js.map +1 -0
  350. package/dist/exporters/csv-exporter.d.ts +11 -2
  351. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  352. package/dist/exporters/csv-exporter.js +8 -4
  353. package/dist/exporters/csv-exporter.js.map +1 -1
  354. package/dist/exporters/matrix/build.d.ts +3 -0
  355. package/dist/exporters/matrix/build.d.ts.map +1 -1
  356. package/dist/exporters/matrix/build.js +10 -9
  357. package/dist/exporters/matrix/build.js.map +1 -1
  358. package/dist/exporters/matrix/export.d.ts +9 -1
  359. package/dist/exporters/matrix/export.d.ts.map +1 -1
  360. package/dist/exporters/matrix/export.js +13 -4
  361. package/dist/exporters/matrix/export.js.map +1 -1
  362. package/dist/exporters/matrix/gates.d.ts +6 -1
  363. package/dist/exporters/matrix/gates.d.ts.map +1 -1
  364. package/dist/exporters/matrix/gates.js +57 -128
  365. package/dist/exporters/matrix/gates.js.map +1 -1
  366. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  367. package/dist/exporters/matrix/render-csv.js +3 -0
  368. package/dist/exporters/matrix/render-csv.js.map +1 -1
  369. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
  370. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
  371. package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
  372. package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
  373. package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
  374. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  375. package/dist/exporters/matrix/render-xlsx.js +3 -0
  376. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  377. package/dist/exporters/matrix/types.d.ts +4 -1
  378. package/dist/exporters/matrix/types.d.ts.map +1 -1
  379. package/dist/exporters/matrix/types.js.map +1 -1
  380. package/dist/exporters/matrix/xlsx-cells.js +1 -1
  381. package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
  382. package/dist/exporters/test-data-resolver.d.ts.map +1 -1
  383. package/dist/exporters/test-data-resolver.js +2 -12
  384. package/dist/exporters/test-data-resolver.js.map +1 -1
  385. package/dist/exporters/xlsx-exporter.d.ts +3 -2
  386. package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
  387. package/dist/exporters/xlsx-exporter.js +4 -4
  388. package/dist/exporters/xlsx-exporter.js.map +1 -1
  389. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  390. package/dist/generators/gherkin-parser/index.js +0 -1
  391. package/dist/generators/gherkin-parser/index.js.map +1 -1
  392. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
  393. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
  394. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
  395. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  396. package/dist/generators/test-generator/code-generator.js +18 -4
  397. package/dist/generators/test-generator/code-generator.js.map +1 -1
  398. package/dist/generators/test-generator/diagnostics.d.ts +3 -9
  399. package/dist/generators/test-generator/diagnostics.d.ts.map +1 -1
  400. package/dist/generators/test-generator/diagnostics.js +3 -9
  401. package/dist/generators/test-generator/diagnostics.js.map +1 -1
  402. package/dist/generators/test-generator/patterns/types.d.ts +1 -1
  403. package/dist/generators/test-generator/patterns/types.d.ts.map +1 -1
  404. package/dist/generators/test-generator/step-mapper.d.ts +0 -8
  405. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  406. package/dist/generators/test-generator/step-mapper.js +8 -52
  407. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  408. package/dist/generators/test-generator/utils/data-resolver.d.ts +0 -16
  409. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  410. package/dist/generators/test-generator/utils/data-resolver.js +0 -59
  411. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  412. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  413. package/dist/generators/test-generator/utils/selector-resolver.js +2 -10
  414. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  415. package/dist/graph/board-human-actions.d.ts +5 -0
  416. package/dist/graph/board-human-actions.d.ts.map +1 -0
  417. package/dist/graph/board-human-actions.js +83 -0
  418. package/dist/graph/board-human-actions.js.map +1 -0
  419. package/dist/graph/evaluate-graph.d.ts +41 -0
  420. package/dist/graph/evaluate-graph.d.ts.map +1 -0
  421. package/dist/graph/evaluate-graph.js +77 -0
  422. package/dist/graph/evaluate-graph.js.map +1 -0
  423. package/dist/graph/human-action.d.ts +21 -0
  424. package/dist/graph/human-action.d.ts.map +1 -0
  425. package/dist/graph/human-action.js +3 -0
  426. package/dist/graph/human-action.js.map +1 -0
  427. package/dist/graph/locate-finding.d.ts +20 -0
  428. package/dist/graph/locate-finding.d.ts.map +1 -0
  429. package/dist/graph/locate-finding.js +137 -0
  430. package/dist/graph/locate-finding.js.map +1 -0
  431. package/dist/graph/manual-triage-decisions.d.ts +19 -0
  432. package/dist/graph/manual-triage-decisions.d.ts.map +1 -0
  433. package/dist/graph/manual-triage-decisions.js +53 -0
  434. package/dist/graph/manual-triage-decisions.js.map +1 -0
  435. package/dist/graph/node-decl.d.ts +75 -0
  436. package/dist/graph/node-decl.d.ts.map +1 -0
  437. package/dist/graph/node-decl.js +11 -0
  438. package/dist/graph/node-decl.js.map +1 -0
  439. package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
  440. package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
  441. package/dist/graph/nodes/core-node-catalog.js +13 -0
  442. package/dist/graph/nodes/core-node-catalog.js.map +1 -0
  443. package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
  444. package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
  445. package/dist/graph/nodes/test-case-contract-nodes.js +72 -0
  446. package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
  447. package/dist/graph/nodes/test-case-nodes.d.ts +29 -0
  448. package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
  449. package/dist/graph/nodes/test-case-nodes.js +95 -0
  450. package/dist/graph/nodes/test-case-nodes.js.map +1 -0
  451. package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
  452. package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
  453. package/dist/graph/nodes/unit-audit-nodes.js +96 -0
  454. package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
  455. package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
  456. package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
  457. package/dist/graph/nodes/unit-contract-node.js +96 -0
  458. package/dist/graph/nodes/unit-contract-node.js.map +1 -0
  459. package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
  460. package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
  461. package/dist/graph/nodes/unit-design-nodes.js +91 -0
  462. package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
  463. package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
  464. package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
  465. package/dist/graph/nodes/unit-execution-nodes.js +79 -0
  466. package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
  467. package/dist/graph/test-case-identity.d.ts +13 -0
  468. package/dist/graph/test-case-identity.d.ts.map +1 -0
  469. package/dist/graph/test-case-identity.js +106 -0
  470. package/dist/graph/test-case-identity.js.map +1 -0
  471. package/dist/graph/test-case-results.d.ts +12 -0
  472. package/dist/graph/test-case-results.d.ts.map +1 -0
  473. package/dist/graph/test-case-results.js +161 -0
  474. package/dist/graph/test-case-results.js.map +1 -0
  475. package/dist/graph/test-case-satisfied.d.ts +26 -0
  476. package/dist/graph/test-case-satisfied.d.ts.map +1 -0
  477. package/dist/graph/test-case-satisfied.js +55 -0
  478. package/dist/graph/test-case-satisfied.js.map +1 -0
  479. package/dist/graph/test-case-state-shape.d.ts +73 -0
  480. package/dist/graph/test-case-state-shape.d.ts.map +1 -0
  481. package/dist/graph/test-case-state-shape.js +3 -0
  482. package/dist/graph/test-case-state-shape.js.map +1 -0
  483. package/dist/graph/test-case-states.d.ts +9 -0
  484. package/dist/graph/test-case-states.d.ts.map +1 -0
  485. package/dist/graph/test-case-states.js +116 -0
  486. package/dist/graph/test-case-states.js.map +1 -0
  487. package/dist/graph/unit-artifact-probes.d.ts +19 -0
  488. package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
  489. package/dist/graph/unit-artifact-probes.js +135 -0
  490. package/dist/graph/unit-artifact-probes.js.map +1 -0
  491. package/dist/graph/unit-results-freshness.d.ts +29 -0
  492. package/dist/graph/unit-results-freshness.d.ts.map +1 -0
  493. package/dist/graph/unit-results-freshness.js +213 -0
  494. package/dist/graph/unit-results-freshness.js.map +1 -0
  495. package/dist/graph/unit-state-facts.d.ts +43 -0
  496. package/dist/graph/unit-state-facts.d.ts.map +1 -0
  497. package/dist/graph/unit-state-facts.js +87 -0
  498. package/dist/graph/unit-state-facts.js.map +1 -0
  499. package/dist/harness/audit.d.ts +14 -2
  500. package/dist/harness/audit.d.ts.map +1 -1
  501. package/dist/harness/audit.js +20 -21
  502. package/dist/harness/audit.js.map +1 -1
  503. package/dist/harness/catalog/gate-rules.yaml +647 -0
  504. package/dist/harness/defect-draft.d.ts.map +1 -1
  505. package/dist/harness/defect-draft.js +12 -2
  506. package/dist/harness/defect-draft.js.map +1 -1
  507. package/dist/harness/defects.d.ts +14 -0
  508. package/dist/harness/defects.d.ts.map +1 -1
  509. package/dist/harness/defects.js +14 -10
  510. package/dist/harness/defects.js.map +1 -1
  511. package/dist/harness/flow-check.d.ts +9 -0
  512. package/dist/harness/flow-check.d.ts.map +1 -1
  513. package/dist/harness/flow-check.js +11 -0
  514. package/dist/harness/flow-check.js.map +1 -1
  515. package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
  516. package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
  517. package/dist/harness/gates/audit-gate-terms.js +72 -0
  518. package/dist/harness/gates/audit-gate-terms.js.map +1 -0
  519. package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
  520. package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
  521. package/dist/harness/gates/audit-gate-verdict.js +102 -0
  522. package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
  523. package/dist/harness/gates/audit-input-hash.d.ts +6 -0
  524. package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
  525. package/dist/harness/gates/audit-input-hash.js +124 -0
  526. package/dist/harness/gates/audit-input-hash.js.map +1 -0
  527. package/dist/harness/gates/audit-report-verification.d.ts +43 -0
  528. package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
  529. package/dist/harness/gates/audit-report-verification.js +241 -0
  530. package/dist/harness/gates/audit-report-verification.js.map +1 -0
  531. package/dist/harness/gates/decisions-hash.d.ts +13 -0
  532. package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
  533. package/dist/harness/gates/decisions-hash.js +72 -0
  534. package/dist/harness/gates/decisions-hash.js.map +1 -0
  535. package/dist/harness/gates/delivery-checklist.d.ts +24 -0
  536. package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
  537. package/dist/harness/gates/delivery-checklist.js +161 -0
  538. package/dist/harness/gates/delivery-checklist.js.map +1 -0
  539. package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
  540. package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
  541. package/dist/harness/gates/delivery-decision-gate.js +116 -0
  542. package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
  543. package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
  544. package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
  545. package/dist/harness/gates/delivery-decision-step.js +86 -0
  546. package/dist/harness/gates/delivery-decision-step.js.map +1 -0
  547. package/dist/harness/gates/gate-override-report.d.ts +59 -0
  548. package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
  549. package/dist/harness/gates/gate-override-report.js +86 -0
  550. package/dist/harness/gates/gate-override-report.js.map +1 -0
  551. package/dist/harness/gates/gate-override-scope.d.ts +18 -0
  552. package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
  553. package/dist/harness/gates/gate-override-scope.js +98 -0
  554. package/dist/harness/gates/gate-override-scope.js.map +1 -0
  555. package/dist/harness/gates/gate-override-validation.d.ts +25 -0
  556. package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
  557. package/dist/harness/gates/gate-override-validation.js +81 -0
  558. package/dist/harness/gates/gate-override-validation.js.map +1 -0
  559. package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
  560. package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
  561. package/dist/harness/gates/gate-rule-catalog.js +112 -0
  562. package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
  563. package/dist/harness/gates/gate-terms.d.ts +33 -0
  564. package/dist/harness/gates/gate-terms.d.ts.map +1 -0
  565. package/dist/harness/gates/gate-terms.js +41 -0
  566. package/dist/harness/gates/gate-terms.js.map +1 -0
  567. package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
  568. package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
  569. package/dist/harness/gates/in-run-decision-check.js +166 -0
  570. package/dist/harness/gates/in-run-decision-check.js.map +1 -0
  571. package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
  572. package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
  573. package/dist/harness/gates/journey-gate-inputs.js +81 -0
  574. package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
  575. package/dist/harness/gates/migrated-waiver-import-bounds.d.ts +13 -0
  576. package/dist/harness/gates/migrated-waiver-import-bounds.d.ts.map +1 -0
  577. package/dist/harness/gates/migrated-waiver-import-bounds.js +141 -0
  578. package/dist/harness/gates/migrated-waiver-import-bounds.js.map +1 -0
  579. package/dist/harness/gates/migrated-waiver-review.d.ts +16 -0
  580. package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
  581. package/dist/harness/gates/migrated-waiver-review.js +114 -0
  582. package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
  583. package/dist/harness/gates/resolve-rule.d.ts +59 -0
  584. package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
  585. package/dist/harness/gates/resolve-rule.js +41 -0
  586. package/dist/harness/gates/resolve-rule.js.map +1 -0
  587. package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
  588. package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
  589. package/dist/harness/gates/unit-gate-overrides.js +122 -0
  590. package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
  591. package/dist/harness/journey.d.ts +64 -1
  592. package/dist/harness/journey.d.ts.map +1 -1
  593. package/dist/harness/journey.js +258 -34
  594. package/dist/harness/journey.js.map +1 -1
  595. package/dist/harness/manifest.d.ts +12 -0
  596. package/dist/harness/manifest.d.ts.map +1 -1
  597. package/dist/harness/manifest.js +71 -43
  598. package/dist/harness/manifest.js.map +1 -1
  599. package/dist/harness/next-step.d.ts +58 -4
  600. package/dist/harness/next-step.d.ts.map +1 -1
  601. package/dist/harness/next-step.js +55 -204
  602. package/dist/harness/next-step.js.map +1 -1
  603. package/dist/harness/parse.d.ts +7 -0
  604. package/dist/harness/parse.d.ts.map +1 -1
  605. package/dist/harness/parse.js +18 -2
  606. package/dist/harness/parse.js.map +1 -1
  607. package/dist/harness/provenance.d.ts +29 -0
  608. package/dist/harness/provenance.d.ts.map +1 -1
  609. package/dist/harness/provenance.js +109 -9
  610. package/dist/harness/provenance.js.map +1 -1
  611. package/dist/harness/script-check.d.ts.map +1 -1
  612. package/dist/harness/script-check.js +22 -5
  613. package/dist/harness/script-check.js.map +1 -1
  614. package/dist/harness/sensors.d.ts +14 -3
  615. package/dist/harness/sensors.d.ts.map +1 -1
  616. package/dist/harness/sensors.js +41 -38
  617. package/dist/harness/sensors.js.map +1 -1
  618. package/dist/harness/triage-manual-classification.d.ts +32 -0
  619. package/dist/harness/triage-manual-classification.d.ts.map +1 -0
  620. package/dist/harness/triage-manual-classification.js +56 -0
  621. package/dist/harness/triage-manual-classification.js.map +1 -0
  622. package/dist/harness/unit-paths.d.ts +8 -0
  623. package/dist/harness/unit-paths.d.ts.map +1 -1
  624. package/dist/harness/unit-paths.js +23 -1
  625. package/dist/harness/unit-paths.js.map +1 -1
  626. package/dist/hooks/bash-read-only-segment.d.ts +9 -0
  627. package/dist/hooks/bash-read-only-segment.d.ts.map +1 -0
  628. package/dist/hooks/bash-read-only-segment.js +168 -0
  629. package/dist/hooks/bash-read-only-segment.js.map +1 -0
  630. package/dist/hooks/bash-write-targets.d.ts +25 -0
  631. package/dist/hooks/bash-write-targets.d.ts.map +1 -0
  632. package/dist/hooks/bash-write-targets.js +266 -0
  633. package/dist/hooks/bash-write-targets.js.map +1 -0
  634. package/dist/hooks/claude-hook-entry.d.ts +11 -0
  635. package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
  636. package/dist/hooks/claude-hook-entry.js +137 -0
  637. package/dist/hooks/claude-hook-entry.js.map +1 -0
  638. package/dist/hooks/claude-transcript-turn.d.ts +11 -0
  639. package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
  640. package/dist/hooks/claude-transcript-turn.js +143 -0
  641. package/dist/hooks/claude-transcript-turn.js.map +1 -0
  642. package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
  643. package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
  644. package/dist/hooks/guard-delivery-contract-rule.js +152 -0
  645. package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
  646. package/dist/hooks/guard-protected-paths.d.ts +13 -0
  647. package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
  648. package/dist/hooks/guard-protected-paths.js +116 -0
  649. package/dist/hooks/guard-protected-paths.js.map +1 -0
  650. package/dist/hooks/guard-rules.d.ts +20 -0
  651. package/dist/hooks/guard-rules.d.ts.map +1 -0
  652. package/dist/hooks/guard-rules.js +130 -0
  653. package/dist/hooks/guard-rules.js.map +1 -0
  654. package/dist/hooks/guard-tty-spoof-rule.d.ts +17 -0
  655. package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
  656. package/dist/hooks/guard-tty-spoof-rule.js +22 -0
  657. package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
  658. package/dist/hooks/hand-back-core.d.ts +42 -0
  659. package/dist/hooks/hand-back-core.d.ts.map +1 -0
  660. package/dist/hooks/hand-back-core.js +128 -0
  661. package/dist/hooks/hand-back-core.js.map +1 -0
  662. package/dist/hooks/hook-cli-command.d.ts +9 -0
  663. package/dist/hooks/hook-cli-command.d.ts.map +1 -0
  664. package/dist/hooks/hook-cli-command.js +46 -0
  665. package/dist/hooks/hook-cli-command.js.map +1 -0
  666. package/dist/hooks/hook-registry.d.ts +10 -0
  667. package/dist/hooks/hook-registry.d.ts.map +1 -0
  668. package/dist/hooks/hook-registry.js +24 -0
  669. package/dist/hooks/hook-registry.js.map +1 -0
  670. package/dist/hooks/hook-result-contract.d.ts +50 -0
  671. package/dist/hooks/hook-result-contract.d.ts.map +1 -0
  672. package/dist/hooks/hook-result-contract.js +80 -0
  673. package/dist/hooks/hook-result-contract.js.map +1 -0
  674. package/dist/hooks/hook-toggles.d.ts +10 -0
  675. package/dist/hooks/hook-toggles.d.ts.map +1 -0
  676. package/dist/hooks/hook-toggles.js +107 -0
  677. package/dist/hooks/hook-toggles.js.map +1 -0
  678. package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
  679. package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
  680. package/dist/hooks/pre-tool-guard-hook.js +105 -0
  681. package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
  682. package/dist/hooks/session-start-unit-state-hook.d.ts +14 -0
  683. package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
  684. package/dist/hooks/session-start-unit-state-hook.js +60 -0
  685. package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
  686. package/dist/hooks/stop-next-step-hook.d.ts +16 -0
  687. package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
  688. package/dist/hooks/stop-next-step-hook.js +43 -0
  689. package/dist/hooks/stop-next-step-hook.js.map +1 -0
  690. package/dist/hooks/sungen-project-root.d.ts +19 -0
  691. package/dist/hooks/sungen-project-root.d.ts.map +1 -0
  692. package/dist/hooks/sungen-project-root.js +130 -0
  693. package/dist/hooks/sungen-project-root.js.map +1 -0
  694. package/dist/index.d.ts.map +1 -1
  695. package/dist/index.js +1 -2
  696. package/dist/index.js.map +1 -1
  697. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
  698. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
  699. package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
  700. package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
  701. package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
  702. package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
  703. package/dist/orchestrator/ai-skills/commands.js +11 -3
  704. package/dist/orchestrator/ai-skills/commands.js.map +1 -1
  705. package/dist/orchestrator/assets-drift.d.ts +5 -0
  706. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  707. package/dist/orchestrator/assets-drift.js +12 -3
  708. package/dist/orchestrator/assets-drift.js.map +1 -1
  709. package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
  710. package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
  711. package/dist/orchestrator/claude-hooks-install.js +203 -0
  712. package/dist/orchestrator/claude-hooks-install.js.map +1 -0
  713. package/dist/orchestrator/lockstep-version.d.ts +15 -5
  714. package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
  715. package/dist/orchestrator/lockstep-version.js +30 -17
  716. package/dist/orchestrator/lockstep-version.js.map +1 -1
  717. package/dist/orchestrator/project-initializer.d.ts +6 -0
  718. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  719. package/dist/orchestrator/project-initializer.js +24 -0
  720. package/dist/orchestrator/project-initializer.js.map +1 -1
  721. package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  722. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +6 -26
  723. package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  724. package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  725. package/dist/orchestrator/templates/ai-src/commands/create-test.md +17 -16
  726. package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  727. package/dist/orchestrator/templates/ai-src/commands/delivery.md +4 -0
  728. package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
  729. package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  730. package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
  731. package/dist/orchestrator/templates/ai-src/commands/review.md +4 -0
  732. package/dist/orchestrator/templates/ai-src/commands/run-test.md +6 -8
  733. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  734. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  735. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  736. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.claude.md +11 -0
  737. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
  738. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
  739. package/dist/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
  740. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
  741. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
  742. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
  743. package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  744. package/dist/orchestrator/templates/specs-test-data.ts +4 -22
  745. package/dist/utils/safe-yaml-parse.d.ts +8 -0
  746. package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
  747. package/dist/utils/safe-yaml-parse.js +51 -0
  748. package/dist/utils/safe-yaml-parse.js.map +1 -0
  749. package/package.json +3 -3
  750. package/src/basis/anchor-grammar.ts +83 -0
  751. package/src/basis/anchor-hash.ts +27 -0
  752. package/src/basis/bm51-tables.ts +65 -0
  753. package/src/basis/extract-spec-anchors.ts +95 -0
  754. package/src/basis/migration-sentinel.ts +175 -0
  755. package/src/basis/spec-frontmatter.ts +68 -0
  756. package/src/basis/spec-sections.ts +35 -0
  757. package/src/basis/test-basis-schema.ts +81 -0
  758. package/src/capabilities/discover.ts +15 -2
  759. package/src/capabilities/registry.ts +16 -0
  760. package/src/cli/case-triage-hint.ts +31 -0
  761. package/src/cli/commands/audit.ts +1 -1
  762. package/src/cli/commands/capability.ts +1 -1
  763. package/src/cli/commands/contract-derive-command.ts +72 -0
  764. package/src/cli/commands/contract.ts +164 -0
  765. package/src/cli/commands/delivery.ts +106 -19
  766. package/src/cli/commands/gate.ts +2 -1
  767. package/src/cli/commands/generate.ts +16 -3
  768. package/src/cli/commands/journey.ts +45 -18
  769. package/src/cli/commands/next.ts +92 -11
  770. package/src/cli/commands/triage.ts +41 -3
  771. package/src/cli/commands/update.ts +41 -10
  772. package/src/cli/index.ts +24 -30
  773. package/src/cli/json-error-on-exit.ts +72 -0
  774. package/src/cli/project-sungen-invocation.ts +59 -0
  775. package/src/cli/run-command-hints.ts +47 -0
  776. package/src/cli/waiting-for-you-block.ts +27 -0
  777. package/src/contract/accept-opaque-steps.ts +114 -0
  778. package/src/contract/approve-contract.ts +101 -0
  779. package/src/contract/assertion-matcher-vocabulary.ts +93 -0
  780. package/src/contract/build-contract-verdict.ts +108 -0
  781. package/src/contract/build-trace-conformance.ts +103 -0
  782. package/src/contract/classify-contract-change.ts +92 -0
  783. package/src/contract/classify-contract-unit.ts +47 -0
  784. package/src/contract/classify-trace-conformance.ts +170 -0
  785. package/src/contract/contract-git.ts +106 -0
  786. package/src/contract/contract-hash.ts +34 -0
  787. package/src/contract/contract-report-file.ts +25 -0
  788. package/src/contract/contract-schema.ts +166 -0
  789. package/src/contract/contract-units.ts +52 -0
  790. package/src/contract/contracts-lock-file.ts +98 -0
  791. package/src/contract/data-normalize.ts +66 -0
  792. package/src/contract/derive-free-feature.ts +153 -0
  793. package/src/contract/field-semantic-redaction.ts +80 -0
  794. package/src/contract/free-feature-blocks.ts +56 -0
  795. package/src/contract/lock-secret-guard.ts +95 -0
  796. package/src/contract/lock-vs-git-head.ts +38 -0
  797. package/src/contract/normalize-contract-step.ts +74 -0
  798. package/src/contract/normalize-feature-steps.ts +93 -0
  799. package/src/contract/oracle-strength.ts +80 -0
  800. package/src/contract/project-contract-blockers.ts +38 -0
  801. package/src/contract/record-contract-approval.ts +110 -0
  802. package/src/contract/render-free-gherkin.ts +118 -0
  803. package/src/contract/render-trace-sentence.ts +98 -0
  804. package/src/contract/render-trace-target.ts +68 -0
  805. package/src/contract/resolve-unit-trace-identities.ts +58 -0
  806. package/src/contract/trace/collect-trace-evidence.ts +178 -0
  807. package/src/contract/trace/identity-cache.ts +61 -0
  808. package/src/contract/trace/read-file-once.ts +95 -0
  809. package/src/contract/trace/scenario-id-claims.ts +60 -0
  810. package/src/contract/trace/select-final-attempt.ts +77 -0
  811. package/src/contract/trace/snapshot-html-renderer.ts +136 -0
  812. package/src/contract/trace/snapshot-resolver.ts +66 -0
  813. package/src/contract/trace/snapshot-store.ts +151 -0
  814. package/src/contract/trace/target-identity.ts +104 -0
  815. package/src/contract/trace/test-step-join.ts +104 -0
  816. package/src/contract/trace/trace-binding.ts +59 -0
  817. package/src/contract/trace/trace-file-reader.ts +144 -0
  818. package/src/contract/trace/trace-fingerprint.ts +68 -0
  819. package/src/contract/trace/trace-freshness.ts +110 -0
  820. package/src/contract/trace/trace-identity-resolution.ts +77 -0
  821. package/src/contract/trace/trace-run-record.ts +96 -0
  822. package/src/contract/trace/trace-steps.ts +88 -0
  823. package/src/contract/trace/trace-zip-limits.ts +77 -0
  824. package/src/contract/trace/trace-zip-reader.ts +127 -0
  825. package/src/contract/verify-approval-decisions.ts +64 -0
  826. package/src/decisions/append-decision.ts +35 -0
  827. package/src/decisions/confirmed-decision-commands.ts +149 -0
  828. package/src/decisions/decision-file.ts +93 -0
  829. package/src/decisions/decision-identity.ts +73 -0
  830. package/src/decisions/decision-integrity-check.ts +61 -0
  831. package/src/decisions/decision-schema.ts +77 -0
  832. package/src/decisions/decision-source.ts +14 -0
  833. package/src/decisions/exclusive-file-create.ts +42 -0
  834. package/src/decisions/git-head-trust.ts +76 -0
  835. package/src/decisions/human-confirmation.ts +119 -0
  836. package/src/decisions/legacy-waiver-migration.ts +146 -0
  837. package/src/decisions/read-decisions.ts +61 -0
  838. package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
  839. package/src/decisions/waiver-decisions.ts +56 -0
  840. package/src/exporters/csv-exporter.ts +12 -4
  841. package/src/exporters/matrix/build.ts +11 -9
  842. package/src/exporters/matrix/export.ts +16 -4
  843. package/src/exporters/matrix/gates.ts +62 -129
  844. package/src/exporters/matrix/render-csv.ts +3 -0
  845. package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
  846. package/src/exporters/matrix/render-xlsx.ts +3 -0
  847. package/src/exporters/matrix/types.ts +4 -1
  848. package/src/exporters/matrix/xlsx-cells.ts +1 -1
  849. package/src/exporters/test-data-resolver.ts +2 -10
  850. package/src/exporters/xlsx-exporter.ts +5 -4
  851. package/src/generators/gherkin-parser/index.ts +0 -1
  852. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/contain-text-assertion.hbs +1 -2
  853. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/fill-action.hbs +1 -13
  854. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/contain-text-assertion.hbs +1 -9
  855. package/src/generators/test-generator/code-generator.ts +17 -4
  856. package/src/generators/test-generator/diagnostics.ts +3 -9
  857. package/src/generators/test-generator/patterns/types.ts +0 -2
  858. package/src/generators/test-generator/step-mapper.ts +9 -56
  859. package/src/generators/test-generator/utils/data-resolver.ts +0 -53
  860. package/src/generators/test-generator/utils/selector-resolver.ts +2 -10
  861. package/src/graph/board-human-actions.ts +80 -0
  862. package/src/graph/evaluate-graph.ts +97 -0
  863. package/src/graph/human-action.ts +33 -0
  864. package/src/graph/locate-finding.ts +93 -0
  865. package/src/graph/manual-triage-decisions.ts +55 -0
  866. package/src/graph/node-decl.ts +83 -0
  867. package/src/graph/nodes/core-node-catalog.ts +15 -0
  868. package/src/graph/nodes/test-case-contract-nodes.ts +90 -0
  869. package/src/graph/nodes/test-case-nodes.ts +100 -0
  870. package/src/graph/nodes/unit-audit-nodes.ts +96 -0
  871. package/src/graph/nodes/unit-contract-node.ts +100 -0
  872. package/src/graph/nodes/unit-design-nodes.ts +89 -0
  873. package/src/graph/nodes/unit-execution-nodes.ts +77 -0
  874. package/src/graph/test-case-identity.ts +75 -0
  875. package/src/graph/test-case-results.ts +111 -0
  876. package/src/graph/test-case-satisfied.ts +58 -0
  877. package/src/graph/test-case-state-shape.ts +67 -0
  878. package/src/graph/test-case-states.ts +84 -0
  879. package/src/graph/unit-artifact-probes.ts +79 -0
  880. package/src/graph/unit-results-freshness.ts +165 -0
  881. package/src/graph/unit-state-facts.ts +112 -0
  882. package/src/harness/audit.ts +31 -18
  883. package/src/harness/catalog/gate-rules.yaml +647 -0
  884. package/src/harness/defect-draft.ts +13 -2
  885. package/src/harness/defects.ts +22 -9
  886. package/src/harness/flow-check.ts +11 -0
  887. package/src/harness/gates/audit-gate-terms.ts +80 -0
  888. package/src/harness/gates/audit-gate-verdict.ts +79 -0
  889. package/src/harness/gates/audit-input-hash.ts +79 -0
  890. package/src/harness/gates/audit-report-verification.ts +206 -0
  891. package/src/harness/gates/decisions-hash.ts +42 -0
  892. package/src/harness/gates/delivery-checklist.ts +152 -0
  893. package/src/harness/gates/delivery-decision-gate.ts +139 -0
  894. package/src/harness/gates/delivery-decision-step.ts +89 -0
  895. package/src/harness/gates/gate-override-report.ts +114 -0
  896. package/src/harness/gates/gate-override-scope.ts +66 -0
  897. package/src/harness/gates/gate-override-validation.ts +75 -0
  898. package/src/harness/gates/gate-rule-catalog.ts +82 -0
  899. package/src/harness/gates/gate-terms.ts +59 -0
  900. package/src/harness/gates/in-run-decision-check.ts +124 -0
  901. package/src/harness/gates/journey-gate-inputs.ts +89 -0
  902. package/src/harness/gates/migrated-waiver-import-bounds.ts +103 -0
  903. package/src/harness/gates/migrated-waiver-review.ts +121 -0
  904. package/src/harness/gates/resolve-rule.ts +94 -0
  905. package/src/harness/gates/unit-gate-overrides.ts +99 -0
  906. package/src/harness/journey.ts +287 -39
  907. package/src/harness/manifest.ts +67 -43
  908. package/src/harness/next-step.ts +91 -193
  909. package/src/harness/parse.ts +20 -2
  910. package/src/harness/provenance.ts +99 -11
  911. package/src/harness/script-check.ts +20 -5
  912. package/src/harness/sensors.ts +47 -40
  913. package/src/harness/triage-manual-classification.ts +76 -0
  914. package/src/harness/unit-paths.ts +19 -0
  915. package/src/hooks/bash-read-only-segment.ts +130 -0
  916. package/src/hooks/bash-write-targets.ts +195 -0
  917. package/src/hooks/claude-hook-entry.ts +85 -0
  918. package/src/hooks/claude-transcript-turn.ts +96 -0
  919. package/src/hooks/guard-delivery-contract-rule.ts +110 -0
  920. package/src/hooks/guard-protected-paths.ts +80 -0
  921. package/src/hooks/guard-rules.ts +117 -0
  922. package/src/hooks/guard-tty-spoof-rule.ts +34 -0
  923. package/src/hooks/hand-back-core.ts +118 -0
  924. package/src/hooks/hook-cli-command.ts +17 -0
  925. package/src/hooks/hook-registry.ts +24 -0
  926. package/src/hooks/hook-result-contract.ts +114 -0
  927. package/src/hooks/hook-toggles.ts +66 -0
  928. package/src/hooks/pre-tool-guard-hook.ts +67 -0
  929. package/src/hooks/session-start-unit-state-hook.ts +59 -0
  930. package/src/hooks/stop-next-step-hook.ts +38 -0
  931. package/src/hooks/sungen-project-root.ts +80 -0
  932. package/src/index.ts +1 -2
  933. package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
  934. package/src/orchestrator/ai-skills/commands.ts +17 -5
  935. package/src/orchestrator/assets-drift.ts +12 -5
  936. package/src/orchestrator/claude-hooks-install.ts +168 -0
  937. package/src/orchestrator/lockstep-version.ts +28 -15
  938. package/src/orchestrator/project-initializer.ts +22 -0
  939. package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  940. package/src/orchestrator/templates/ai-src/commands/add-flow.md +6 -26
  941. package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  942. package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  943. package/src/orchestrator/templates/ai-src/commands/create-test.md +17 -16
  944. package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  945. package/src/orchestrator/templates/ai-src/commands/delivery.md +4 -0
  946. package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
  947. package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  948. package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
  949. package/src/orchestrator/templates/ai-src/commands/review.md +4 -0
  950. package/src/orchestrator/templates/ai-src/commands/run-test.md +6 -8
  951. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  952. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  953. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  954. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.claude.md +11 -0
  955. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
  956. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
  957. package/src/orchestrator/templates/ai-src/skills/sungen-delivery/SKILL.md +1 -2
  958. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +4 -5
  959. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +8 -24
  960. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +3 -4
  961. package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  962. package/src/orchestrator/templates/specs-test-data.ts +4 -22
  963. package/src/utils/safe-yaml-parse.ts +44 -0
  964. package/dist/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
  965. package/dist/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
  966. package/dist/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
  967. package/src/generators/test-generator/adapters/appium/templates/steps/assertions/expanded-assertion.hbs +0 -2
  968. package/src/generators/test-generator/adapters/playwright/templates/steps/actions/date-picker-unsupported.hbs +0 -5
  969. package/src/generators/test-generator/adapters/playwright/templates/steps/assertions/expanded-assertion.hbs +0 -12
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Limits for reading an untrusted Playwright trace.zip (DOS-14.7), and the one error every trace
3
+ * refusal raises. A trace is attacker-shaped input: a report can point at any file, and a zip can
4
+ * claim small sizes and inflate to gigabytes, so every number below is checked BEFORE inflating and
5
+ * again WHILE inflating (the inflater is capped at the declared size).
6
+ *
7
+ * file size 20 MB a real trace is ~0.6 MB per attempt, max 1.3 MB measured (phase 07)
8
+ * entries 10 000
9
+ * one entry 16 MB uncompressed
10
+ * all entries 64 MB uncompressed (each raisable by env: traceZipLimits)
11
+ * ratio 100 : 1 per entry (a bomb is ~1000 : 1)
12
+ *
13
+ * An entry NAME is a key and nothing else: names with `..`, a leading `/`, a drive letter, a
14
+ * backslash or a NUL are refused outright rather than "sanitized", because nothing legitimate in a
15
+ * trace looks like that.
16
+ */
17
+ export interface TraceZipLimits {
18
+ maxZipBytes: number;
19
+ maxEntries: number;
20
+ maxEntryBytes: number;
21
+ maxTotalBytes: number;
22
+ maxRatio: number;
23
+ }
24
+
25
+ const MB = 1024 * 1024;
26
+
27
+ export const TRACE_ZIP_LIMITS: Readonly<TraceZipLimits> = Object.freeze({
28
+ maxZipBytes: 20 * MB,
29
+ maxEntries: 10_000,
30
+ maxEntryBytes: 16 * MB,
31
+ maxTotalBytes: 64 * MB,
32
+ maxRatio: 100,
33
+ });
34
+
35
+ /**
36
+ * The limits in force: the defaults, each raisable by env for unusually large traces —
37
+ * `SUNGEN_TRACE_MAX_ZIP_MB`, `SUNGEN_TRACE_MAX_ENTRY_MB`, `SUNGEN_TRACE_MAX_TOTAL_MB` (positive numbers;
38
+ * anything else is ignored, so a typo can never turn a cap into zero or infinity).
39
+ */
40
+ export function traceZipLimits(env: Record<string, string | undefined> = process.env): TraceZipLimits {
41
+ const mb = (name: string, fallback: number): number => {
42
+ const v = Number(env[name]);
43
+ return Number.isFinite(v) && v > 0 && v <= 4096 ? Math.floor(v * MB) : fallback;
44
+ };
45
+ return {
46
+ ...TRACE_ZIP_LIMITS,
47
+ maxZipBytes: mb('SUNGEN_TRACE_MAX_ZIP_MB', TRACE_ZIP_LIMITS.maxZipBytes),
48
+ maxEntryBytes: mb('SUNGEN_TRACE_MAX_ENTRY_MB', TRACE_ZIP_LIMITS.maxEntryBytes),
49
+ maxTotalBytes: mb('SUNGEN_TRACE_MAX_TOTAL_MB', TRACE_ZIP_LIMITS.maxTotalBytes),
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Trace format versions this reader was verified against: 8 = Playwright 1.57, 9 = 1.63, 10 = 1.64
55
+ * (one shared call id for a library call and its runner step; stacks keyed by that id). Anything
56
+ * else — a newer format included — is refused until it has been checked the same way.
57
+ */
58
+ export const SUPPORTED_TRACE_VERSIONS: ReadonlySet<number> = new Set([8, 9, 10]);
59
+
60
+ export type TraceRejectCode =
61
+ | 'zip.too-large' | 'zip.too-many-entries' | 'zip.entry-too-large' | 'zip.total-too-large' | 'zip.ratio'
62
+ | 'zip.entry-name' | 'zip.malformed' | 'zip.unsupported' | 'trace.version-unsupported' | 'trace.malformed';
63
+
64
+ /** A trace that was refused before anything in it was trusted. `code` is stable; `message` names the cause. */
65
+ export class TraceRejected extends Error {
66
+ constructor(public readonly code: TraceRejectCode, message: string) {
67
+ super(`${code}: ${message}`);
68
+ this.name = 'TraceRejected';
69
+ }
70
+ }
71
+
72
+ const BAD_NAME = /(^|[\\/])\.\.([\\/]|$)|^[\\/]|^[A-Za-z]:|\\|\0/;
73
+
74
+ /** Refuse an entry name that could ever be mistaken for a path outside the archive. */
75
+ export function assertSafeEntryName(name: string): void {
76
+ if (!name || BAD_NAME.test(name)) throw new TraceRejected('zip.entry-name', `refused entry name ${JSON.stringify(name.slice(0, 80))}`);
77
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * A synchronous, limit-enforcing zip reader for trace.zip files (DOS-14.7) on Node's own zlib —
3
+ * no dependency, and synchronous so the contract verdict (and the Claude Code guard that rebuilds
4
+ * it) stays a plain function.
5
+ *
6
+ * Only what a Playwright trace needs is accepted: STORE or DEFLATE entries, no encryption, no
7
+ * ZIP64, no duplicate names. Sizes come from the central directory and are checked against
8
+ * TRACE_ZIP_LIMITS before anything is inflated; inflation itself is capped at the declared size and
9
+ * the CRC is verified, so a header that lies is caught while reading, not after. Entry names are
10
+ * map keys — nothing here ever touches the filesystem.
11
+ */
12
+ import * as zlib from 'zlib';
13
+ import { assertSafeEntryName, TRACE_ZIP_LIMITS, TraceRejected, TraceZipLimits } from './trace-zip-limits';
14
+
15
+ interface Entry { name: string; method: number; compressed: number; size: number; crc: number; localOffset: number }
16
+
17
+ export interface ZipArchive {
18
+ names(): string[];
19
+ has(name: string): boolean;
20
+ readBuffer(name: string): Buffer;
21
+ readText(name: string): string;
22
+ }
23
+
24
+ const EOCD = 0x06054b50;
25
+ const CENTRAL = 0x02014b50;
26
+ const LOCAL = 0x04034b50;
27
+ /** Below this, a high ratio is just a small repetitive file; the per-entry and total caps still apply. */
28
+ const RATIO_FLOOR_BYTES = 64 * 1024;
29
+
30
+ const malformed = (why: string): TraceRejected => new TraceRejected('zip.malformed', why);
31
+
32
+ const CRC_TABLE = (() => {
33
+ const t = new Int32Array(256);
34
+ for (let n = 0; n < 256; n++) { let c = n; for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1; t[n] = c; }
35
+ return t;
36
+ })();
37
+ function crc32(buf: Buffer): number {
38
+ let c = -1;
39
+ for (let i = 0; i < buf.length; i++) c = CRC_TABLE[(c ^ buf[i]) & 0xff] ^ (c >>> 8);
40
+ return (c ^ -1) >>> 0;
41
+ }
42
+
43
+ function findEocd(buf: Buffer): number {
44
+ const stop = Math.max(0, buf.length - 22 - 0xffff);
45
+ for (let i = buf.length - 22; i >= stop; i--) if (buf.readUInt32LE(i) === EOCD) return i;
46
+ throw malformed('no end-of-central-directory record (not a zip)');
47
+ }
48
+
49
+ function readEntries(buf: Buffer, limits: TraceZipLimits): Map<string, Entry> {
50
+ const eocd = findEocd(buf);
51
+ const count = buf.readUInt16LE(eocd + 10);
52
+ const cdOffset = buf.readUInt32LE(eocd + 16);
53
+ if (count === 0xffff || cdOffset === 0xffffffff) throw new TraceRejected('zip.unsupported', 'ZIP64 archives are not read');
54
+ if (count > limits.maxEntries) throw new TraceRejected('zip.too-many-entries', `${count} entries > ${limits.maxEntries}`);
55
+ const entries = new Map<string, Entry>();
56
+ let at = cdOffset;
57
+ let total = 0;
58
+ for (let i = 0; i < count; i++) {
59
+ if (buf.readUInt32LE(at) !== CENTRAL) throw malformed(`central directory entry ${i} has a bad signature`);
60
+ const flags = buf.readUInt16LE(at + 8);
61
+ const method = buf.readUInt16LE(at + 10);
62
+ const crc = buf.readUInt32LE(at + 16);
63
+ const compressed = buf.readUInt32LE(at + 20);
64
+ const size = buf.readUInt32LE(at + 24);
65
+ const nameLen = buf.readUInt16LE(at + 28);
66
+ const name = buf.toString('utf8', at + 46, at + 46 + nameLen);
67
+ const localOffset = buf.readUInt32LE(at + 42);
68
+ at += 46 + nameLen + buf.readUInt16LE(at + 30) + buf.readUInt16LE(at + 32);
69
+ assertSafeEntryName(name.replace(/\/$/, '') || name);
70
+ if (flags & 1) throw new TraceRejected('zip.unsupported', `${name} is encrypted`);
71
+ if (method !== 0 && method !== 8) throw new TraceRejected('zip.unsupported', `${name} uses compression method ${method}`);
72
+ if (compressed === 0xffffffff || size === 0xffffffff) throw new TraceRejected('zip.unsupported', `${name} needs ZIP64`);
73
+ if (name.endsWith('/')) continue;
74
+ if (entries.has(name)) throw malformed(`duplicate entry ${name}`);
75
+ if (size > limits.maxEntryBytes) throw new TraceRejected('zip.entry-too-large', `${name}: ${size} B > ${limits.maxEntryBytes}`);
76
+ if (size >= RATIO_FLOOR_BYTES && compressed > 0 && size / compressed > limits.maxRatio) {
77
+ throw new TraceRejected('zip.ratio', `${name}: ratio ${(size / compressed).toFixed(0)}:1 > ${limits.maxRatio}:1`);
78
+ }
79
+ if (size >= RATIO_FLOOR_BYTES && compressed === 0) throw new TraceRejected('zip.ratio', `${name}: ${size} B from 0 compressed bytes`);
80
+ total += size;
81
+ if (total > limits.maxTotalBytes) throw new TraceRejected('zip.total-too-large', `more than ${limits.maxTotalBytes} B uncompressed`);
82
+ entries.set(name, { name, method, compressed, size, crc, localOffset });
83
+ }
84
+ return entries;
85
+ }
86
+
87
+ function inflate(buf: Buffer, e: Entry): Buffer {
88
+ if (buf.readUInt32LE(e.localOffset) !== LOCAL) throw malformed(`${e.name}: bad local header`);
89
+ const start = e.localOffset + 30 + buf.readUInt16LE(e.localOffset + 26) + buf.readUInt16LE(e.localOffset + 28);
90
+ const data = buf.subarray(start, start + e.compressed);
91
+ if (data.length !== e.compressed) throw malformed(`${e.name}: truncated data`);
92
+ let out: Buffer;
93
+ if (e.method === 0) out = data;
94
+ else {
95
+ try { out = zlib.inflateRawSync(data, { maxOutputLength: Math.max(1, e.size) }); } catch (err) {
96
+ throw malformed(`${e.name}: inflates past its declared ${e.size} B or is corrupt (${(err as Error).message.split('\n')[0]})`);
97
+ }
98
+ }
99
+ if (out.length !== e.size) throw malformed(`${e.name}: ${out.length} B, header says ${e.size} B`);
100
+ if (crc32(out) !== e.crc) throw malformed(`${e.name}: CRC mismatch`);
101
+ return out;
102
+ }
103
+
104
+ /** Open a zip held in memory. Throws TraceRejected for anything outside the limits or the format. */
105
+ export function openZip(buf: Buffer, limits: TraceZipLimits = TRACE_ZIP_LIMITS): ZipArchive {
106
+ if (buf.length > limits.maxZipBytes) throw new TraceRejected('zip.too-large', `${buf.length} B > ${limits.maxZipBytes}`);
107
+ if (buf.length < 22) throw malformed('too short to be a zip');
108
+ let entries: Map<string, Entry>;
109
+ try { entries = readEntries(buf, limits); } catch (e) {
110
+ if (e instanceof TraceRejected) throw e;
111
+ throw malformed(`unreadable zip structure (${(e as Error).message.split('\n')[0]})`);
112
+ }
113
+ const readBuffer = (name: string): Buffer => {
114
+ const e = entries.get(name);
115
+ if (!e) throw malformed(`no entry ${name}`);
116
+ try { return inflate(buf, e); } catch (err) {
117
+ if (err instanceof TraceRejected) throw err;
118
+ throw malformed(`${name}: ${(err as Error).message.split('\n')[0]}`);
119
+ }
120
+ };
121
+ return {
122
+ names: () => [...entries.keys()],
123
+ has: (name) => entries.has(name),
124
+ readBuffer,
125
+ readText: (name) => readBuffer(name).toString('utf8'),
126
+ };
127
+ }
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Every approved lock entry must be vouched for by its decision (DOS-13.2, DOS-14.4, review M1):
3
+ * `qa/<kind>/<unit>/decisions/<decisionId>.yaml`, COMMITTED in git HEAD (outside git: on disk),
4
+ * intact (schema, id = content, entry_hash = entry), of kind `contract-approval`, whose payload lists
5
+ * this scenario at this hash — with exactly the opaque steps the entry says QA accepted (#923) — and
6
+ * whose `valid_from` is the entry's `approvedAt`. A lock line copied from elsewhere, re-pointed at
7
+ * another decision, backdated, or given an acceptance nobody recorded fails here — `unverified`,
8
+ * reported under contract.lock-uncommitted (hard).
9
+ *
10
+ * Only entries that are otherwise identical to HEAD are checked: an entry already added, changed or
11
+ * tampered is a hard finding on its own.
12
+ */
13
+ import * as path from 'path';
14
+ import { computeDecisionId, computeEntryHash } from '../decisions/decision-identity';
15
+ import { DecisionEntry, storedEntryErrors } from '../decisions/decision-schema';
16
+ import { safeYamlParse } from '../utils/safe-yaml-parse';
17
+ import { HeadSnapshot, headFileText, posixRel, readTextOrNull } from './contract-git';
18
+ import { sameJson } from './contract-hash';
19
+ import { ContractLock, isHumanApproved, LockEntry } from './contract-schema';
20
+ import type { UncommittedEntry } from './lock-vs-git-head';
21
+
22
+ type Loaded = { entry: DecisionEntry } | { problem: string };
23
+
24
+ function loadDecision(projectRoot: string, unitDir: string, id: string, snap: HeadSnapshot): Loaded {
25
+ const file = path.join(unitDir, 'decisions', `${id}.yaml`);
26
+ const rel = posixRel(projectRoot, file);
27
+ const working = readTextOrNull(file);
28
+ const text = snap.blobs === null ? working : headFileText(snap, rel, working);
29
+ if (text === null) return { problem: snap.blobs === null ? `decision ${id} does not exist` : `decision ${id} is not in git HEAD (not committed through review)` };
30
+ let raw: unknown;
31
+ try { raw = safeYamlParse(text, rel); } catch (e) { return { problem: `decision ${id} is unreadable: ${e instanceof Error ? e.message : e}` }; }
32
+ const errors = storedEntryErrors(raw);
33
+ if (errors.length) return { problem: `decision ${id} is invalid: ${errors[0]}` };
34
+ const entry = raw as DecisionEntry;
35
+ const scope = posixRel(path.join(projectRoot, 'qa'), unitDir);
36
+ if (entry.id !== id || computeDecisionId(entry, scope) !== id) return { problem: `decision ${id} does not hash to its id in ${scope}` };
37
+ if (computeEntryHash(entry) !== entry.entry_hash) return { problem: `decision ${id} was altered (entry_hash)` };
38
+ return { entry };
39
+ }
40
+
41
+ function mismatch(scenario: string, lockEntry: LockEntry, d: DecisionEntry): string | null {
42
+ if (d.kind !== 'contract-approval') return `decision ${d.id} is a ${d.kind}, not a contract-approval`;
43
+ const listed = Array.isArray(d.payload?.scenarios) ? d.payload!.scenarios as Array<{ id?: unknown; hash?: unknown; acceptedOpaque?: unknown }> : [];
44
+ const item = listed.find((s) => s && s.id === scenario && s.hash === lockEntry.hash);
45
+ if (!item) return `decision ${d.id} does not approve ${scenario} at hash ${lockEntry.hash}`;
46
+ if (!sameJson(item.acceptedOpaque ?? [], lockEntry.acceptedOpaque ?? [])) return `decision ${d.id} does not accept the opaque step(s) the lock entry of ${scenario} lists (acceptedOpaque)`;
47
+ if (Date.parse(lockEntry.approvedAt) !== Date.parse(d.valid_from)) return `approvedAt ${lockEntry.approvedAt} is not decision ${d.id}'s valid_from ${d.valid_from}`;
48
+ return null;
49
+ }
50
+
51
+ export function unverifiedApprovals(
52
+ projectRoot: string, unitDir: string, lock: ContractLock | null, skip: ReadonlySet<string>, snap: HeadSnapshot,
53
+ ): UncommittedEntry[] {
54
+ const cache = new Map<string, Loaded>();
55
+ const out: UncommittedEntry[] = [];
56
+ for (const [id, entry] of Object.entries(lock?.scenarios ?? {})) {
57
+ if (!isHumanApproved(entry) || skip.has(id)) continue;
58
+ if (!cache.has(entry.decisionId)) cache.set(entry.decisionId, loadDecision(projectRoot, unitDir, entry.decisionId, snap));
59
+ const loaded = cache.get(entry.decisionId)!;
60
+ const problem = 'problem' in loaded ? loaded.problem : mismatch(id, entry, loaded.entry);
61
+ if (problem) out.push({ id, change: 'unverified', detail: problem });
62
+ }
63
+ return out;
64
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Append one decision: one file per entry, named by its content id, created exclusively
3
+ * (DOS-13.1, red-team #13). The file appears complete or not at all (createFileExclusive), so two
4
+ * writers can race freely: same content → same name → the second sees "already recorded"; different
5
+ * content → different names → both land. Nothing is sequential, so nothing can collide.
6
+ */
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ import { createFileExclusive } from './exclusive-file-create';
10
+ import { DecisionDraft, DecisionEntry, draftErrors } from './decision-schema';
11
+ import { sealDecision } from './decision-identity';
12
+ import { decisionsDirFor, serializeDecision, verifyDecisionFile } from './decision-file';
13
+
14
+ export interface AppendResult { status: 'created' | 'already-recorded'; entry: DecisionEntry; path: string }
15
+
16
+ export class DecisionConflictError extends Error {
17
+ constructor(public readonly path: string, detail: string) {
18
+ super(`${path} already exists but does not verify (${detail}). Restore it from git; record a new entry instead.`);
19
+ this.name = 'DecisionConflictError';
20
+ }
21
+ }
22
+
23
+ export function appendDecision(projectRoot: string, scope: string, draft: DecisionDraft): AppendResult {
24
+ const errors = draftErrors(draft as unknown as Record<string, unknown>);
25
+ if (errors.length) throw new Error(`invalid decision: ${errors.join('; ')}`);
26
+ const dir = decisionsDirFor(projectRoot, scope);
27
+ const entry = sealDecision(draft, scope);
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ const file = path.join(dir, `${entry.id}.yaml`);
30
+ if (createFileExclusive(file, serializeDecision(entry))) return { status: 'created', entry, path: file };
31
+
32
+ const existing = verifyDecisionFile(file, scope);
33
+ if (existing.entry) return { status: 'already-recorded', entry: existing.entry, path: file };
34
+ throw new DecisionConflictError(file, `${existing.problem?.code}: ${existing.problem?.message}`);
35
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * The journey CLI's human-gated actions (DOS-13.4), with the terminal passed in so the exact code the
3
+ * CLI runs on process.stdin/stderr is the code a test drives with a simulated TTY.
4
+ *
5
+ * waive `sungen journey --screen <u> --waive <OB> --reason …` phrase: the obligation id
6
+ * signoff `sungen journey --screen <u> --signoff [--by <name>]` phrase: SIGN-OFF (review W3)
7
+ * decide `sungen journey [--screen <u>] --decide <kind> --text … --reason … [--anchor …]` phrase: the kind
8
+ * migration a leftover write-ahead sentinel → REVERT or KEEP (takumi T6)
9
+ *
10
+ * Everything that can be validated is validated BEFORE the prompt, so a human never confirms
11
+ * something that is then rejected — for a gate-override that includes the override rules (OES-11.3:
12
+ * soft rule, warning|info|off, `off` only where allowed, one unit or a glob in one kind, reason ≥ 15).
13
+ * `humanAccepted: true` is added to a gate-override's payload only AFTER the typed confirmation
14
+ * (takumi T5: present means effective) and can never be supplied through --payload.
15
+ * Without a TTY each refuses and prints the exact command.
16
+ */
17
+ import * as path from 'path';
18
+ import { assertNoPendingMigration, pendingMigrationState, PendingMigration, readPendingMigration, resolvePendingMigration, sentinelPath } from '../basis/migration-sentinel';
19
+ import { parseAnchorId } from '../basis/anchor-grammar';
20
+ import { assertCanSignOff, assertWaivable, JourneyReport, runJourney, signoff, signoffSigner, waive } from '../harness/journey';
21
+ import { reportSlug } from '../harness/unit-paths';
22
+ import { appendDecision, AppendResult } from './append-decision';
23
+ import { PROJECT_SCOPE, unitDecisionScope } from './decision-file';
24
+ import { DecisionDraft, DecisionKind, draftErrors, JsonValue } from './decision-schema';
25
+ import { gitUserName } from './decision-source';
26
+ import { askMigrationChoice, ConfirmationIO, formatCommand, requireInteractive, requireTypedConfirmation } from './human-confirmation';
27
+ import { readDecisions } from './read-decisions';
28
+ import { overridePayloadErrors } from '../harness/gates/gate-override-validation';
29
+
30
+ export interface WaiveInput { projectRoot: string; unit: string; obligation: string; reason: string; io: ConfirmationIO }
31
+
32
+ export async function waiveWithConfirmation(i: WaiveInput): Promise<JourneyReport> {
33
+ if (!i.reason || !i.reason.trim()) throw new Error('A reason is required to waive (anti-amnesia: a waiver must record WHY). Use --reason "...".');
34
+ assertWaivable(runJourney(i.projectRoot, i.unit), i.unit, i.obligation);
35
+ await requireTypedConfirmation({
36
+ what: `waive ${i.obligation} for ${i.unit}`,
37
+ phrase: i.obligation,
38
+ command: formatCommand(['sungen', 'journey', '--screen', i.unit, '--waive', i.obligation, '--reason', i.reason]),
39
+ summary: [`reason: ${i.reason.trim()}`, `recorded by: ${gitUserName(i.projectRoot)}`, 'it stops counting as soon as the audit changes (re-decide then)'],
40
+ io: i.io,
41
+ });
42
+ return waive(i.projectRoot, i.unit, i.obligation, i.reason);
43
+ }
44
+
45
+ export interface SignoffInput { projectRoot: string; unit: string; by?: string; io: ConfirmationIO }
46
+
47
+ /**
48
+ * The single human gate (DOS §3.4, S5), typed by a person on a terminal: the gate suggests it, so an
49
+ * agent must not be able to give it. Refused before the prompt when the board cannot be signed off.
50
+ */
51
+ export async function signoffWithConfirmation(i: SignoffInput): Promise<JourneyReport> {
52
+ const what = `sign off ${i.unit} (the single human gate before delivery)`;
53
+ const command = formatCommand(['sungen', 'journey', '--screen', i.unit, '--signoff', ...(i.by ? ['--by', i.by] : [])]);
54
+ requireInteractive(i.io, what, command); // before the board is read: a refused sign-off writes nothing
55
+ const { signer, gitUser } = signoffSigner(i.projectRoot, i.unit, i.by); // nobody to name → refused, no prompt
56
+ const before = runJourney(i.projectRoot, i.unit);
57
+ assertCanSignOff(before);
58
+ await requireTypedConfirmation({
59
+ what, phrase: 'SIGN-OFF', command,
60
+ summary: [`by: ${signer}${signer !== gitUser ? ` (recorded by git user ${gitUser})` : ''}`, `${before.needsYou.length} item(s) in the review queue — you have reviewed them`, 'it goes stale as soon as the audit changes (sign off again then)'],
61
+ io: i.io,
62
+ });
63
+ return signoff(i.projectRoot, i.unit, i.by);
64
+ }
65
+
66
+ /** Kinds `--decide` records. The others have a command of their own that computes their payload. */
67
+ export const DECIDE_KINDS: readonly DecisionKind[] = ['gate-override', 'clarification'];
68
+ const OWN_COMMAND: Partial<Record<DecisionKind, string>> = {
69
+ waiver: 'use `sungen journey --screen <unit> --waive <OB-id> --reason "..."`',
70
+ 'contract-approval': 'it is recorded by `sungen contract approve`',
71
+ 'viewpoint-acceptance': 'it is recorded by `sungen audit --accept-viewpoint`',
72
+ };
73
+
74
+ export interface DecideInput {
75
+ projectRoot: string; unit?: string; kind: string; text?: string; reason?: string; anchors?: string[];
76
+ payload?: string; visibility?: string; supersedes?: string; io: ConfirmationIO;
77
+ }
78
+
79
+ function decideDraft(i: DecideInput): { scope: string; draft: DecisionDraft } {
80
+ const kind = i.kind as DecisionKind;
81
+ if (!DECIDE_KINDS.includes(kind)) {
82
+ throw new Error(`--decide ${i.kind}: ${OWN_COMMAND[kind] ?? `kind must be one of ${DECIDE_KINDS.join(', ')}`}.`);
83
+ }
84
+ const errors: string[] = [];
85
+ const anchors = i.anchors ?? [];
86
+ for (const a of anchors) if (!parseAnchorId(a)) errors.push(`--anchor "${a}" is not a spec anchor (SPEC-ID#A-2, SPEC-ID#A-2/val or sec-<slug>)`);
87
+ let payload: Record<string, JsonValue> | undefined;
88
+ if (i.payload !== undefined) {
89
+ try {
90
+ const p = JSON.parse(i.payload);
91
+ if (p && typeof p === 'object' && !Array.isArray(p)) payload = p; else errors.push('--payload must be a JSON object');
92
+ } catch { errors.push('--payload is not valid JSON'); }
93
+ }
94
+ const scope = i.unit ? unitDecisionScope(i.projectRoot, i.unit) : PROJECT_SCOPE;
95
+ if (!scope) errors.push(`--screen ${i.unit} does not name exactly one unit under qa/screens, qa/flows or qa/api`);
96
+ if (kind === 'gate-override') {
97
+ if (payload && 'humanAccepted' in payload) errors.push('--payload must not carry humanAccepted — the terminal confirmation sets it');
98
+ else if (!payload) errors.push('--payload is required for a gate-override: {"rule","severity","scope"}');
99
+ else if (scope) errors.push(...overridePayloadErrors(payload, i.reason ?? '', scope).map((e) => `gate-override: ${e}`));
100
+ }
101
+ if (scope && i.supersedes && !readDecisions(i.projectRoot, scope).entries.some((e) => e.id === i.supersedes)) {
102
+ errors.push(`--supersedes ${i.supersedes} names no decision in ${scope === PROJECT_SCOPE ? 'qa/decisions' : `qa/${scope}/decisions`}`);
103
+ }
104
+ const draft = {
105
+ kind, anchors, text: i.text ?? '', reason: i.reason ?? '', ...(payload ? { payload } : {}),
106
+ source: { by: gitUserName(i.projectRoot), where: 'cli' }, valid_from: new Date().toISOString(),
107
+ ...(i.supersedes ? { supersedes: i.supersedes } : {}), visibility: (i.visibility ?? 'internal') as DecisionDraft['visibility'],
108
+ };
109
+ errors.push(...draftErrors(draft as unknown as Record<string, unknown>).map((e) => e.replace(/^text /, '--text ').replace(/^reason /, '--reason ')));
110
+ if (errors.length) throw new Error(`Cannot record the decision:\n - ${errors.join('\n - ')}`);
111
+ return { scope, draft };
112
+ }
113
+
114
+ export async function decideWithConfirmation(i: DecideInput): Promise<AppendResult> {
115
+ const { scope, draft } = decideDraft(i);
116
+ const argv = ['sungen', 'journey', ...(i.unit ? ['--screen', i.unit] : []), '--decide', draft.kind, '--text', draft.text, '--reason', draft.reason,
117
+ ...draft.anchors.flatMap((a) => ['--anchor', a]), ...(i.payload !== undefined ? ['--payload', i.payload] : []),
118
+ ...(draft.visibility !== 'internal' ? ['--visibility', draft.visibility] : []), ...(draft.supersedes ? ['--supersedes', draft.supersedes] : [])];
119
+ await requireTypedConfirmation({
120
+ what: `record a ${draft.kind} decision in ${scope === PROJECT_SCOPE ? 'qa/decisions' : `qa/${scope}/decisions`}`,
121
+ phrase: draft.kind,
122
+ command: formatCommand(argv),
123
+ summary: [`text: ${draft.text}`, `reason: ${draft.reason}`, ...(draft.anchors.length ? [`anchors: ${draft.anchors.join(', ')}`] : []),
124
+ ...(draft.payload ? [`payload: ${JSON.stringify(draft.payload)}`] : []), `visibility: ${draft.visibility}`, `recorded by: ${draft.source.by}`],
125
+ io: i.io,
126
+ });
127
+ // Present means effective (T5): only now, after a human typed the phrase, is the override accepted.
128
+ const confirmed = draft.kind === 'gate-override' ? { ...draft, payload: { ...draft.payload, humanAccepted: true } } : draft;
129
+ return appendDecision(i.projectRoot, scope, confirmed);
130
+ }
131
+
132
+ function assertNotInProgress(projectRoot: string, slug: string, pending: PendingMigration & { readable: boolean }): void {
133
+ if (pendingMigrationState(pending) === 'in-progress') assertNoPendingMigration(projectRoot, slug); // throws MigrationInProgressError
134
+ }
135
+
136
+ /** A sentinel left by a killed migration: ask REVERT/KEEP on a TTY, refuse without one. null = none pending. */
137
+ export async function answerPendingMigration(projectRoot: string, unit: string, io: ConfirmationIO): Promise<string[] | null> {
138
+ const slug = reportSlug(unit);
139
+ const pending = readPendingMigration(projectRoot, slug);
140
+ if (!pending) return null;
141
+ assertNotInProgress(projectRoot, slug, pending); // another run migrating now: "retry", never a prompt
142
+ const files = pending.files.map((f) => ` ${f.existed ? 'restore' : 'remove '} ${f.path}`).join('\n');
143
+ const choice = await askMigrationChoice({
144
+ detail: `An interrupted migration left ${path.relative(projectRoot, sentinelPath(projectRoot, slug))} (started ${pending.startedAt}: ${pending.reason}).\n${files}`,
145
+ command: formatCommand(['sungen', 'journey', '--screen', unit]),
146
+ io,
147
+ });
148
+ return resolvePendingMigration(projectRoot, slug, choice);
149
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Where decisions live and how one file reads and writes (DOS-13.1, DOS-3.9).
3
+ *
4
+ * project scope qa/decisions/<id>.yaml
5
+ * unit scope qa/<kind>/<unit>/decisions/<id>.yaml scope = `<kind>/<unit>` (e.g. `screens/login`)
6
+ *
7
+ * The scope is not stored in the entry: it is where the file lives, and it is part of the id, so a
8
+ * file moved to another unit no longer matches its own id.
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import { stringify } from 'yaml';
13
+ import { resolveUnitCandidates } from '../cli/resolve-unit';
14
+ import { safeYamlParse } from '../utils/safe-yaml-parse';
15
+ import { DecisionEntry, storedEntryErrors } from './decision-schema';
16
+ import { computeDecisionId, computeEntryHash } from './decision-identity';
17
+
18
+ export const PROJECT_SCOPE = 'project';
19
+ /** A decision file's path (`/`-separated, relative to the project): `…/decisions/<name>.yaml`. One test for every reader. */
20
+ export const DECISION_FILE_PATH = /(^|\/)decisions\/[^/]+\.yaml$/;
21
+ const UNIT_SCOPE_RE = /^(?:(?:screens|flows|api)\/(?!\.\.?$)[^/\\]+|api\/flows\/(?!\.\.?$)[^/\\]+)$/;
22
+
23
+ export function isValidScope(scope: string): boolean {
24
+ return scope === PROJECT_SCOPE || UNIT_SCOPE_RE.test(scope);
25
+ }
26
+
27
+ export function decisionsDirFor(projectRoot: string, scope: string): string {
28
+ if (!isValidScope(scope)) throw new Error(`invalid decision scope "${scope}" (project, or <screens|flows|api>/<unit>)`);
29
+ return scope === PROJECT_SCOPE
30
+ ? path.join(projectRoot, 'qa', 'decisions')
31
+ : path.join(projectRoot, 'qa', ...scope.split('/'), 'decisions');
32
+ }
33
+
34
+ /** The unit scope for a unit name, or null when the name matches no unit or more than one. */
35
+ export function unitDecisionScope(projectRoot: string, unit: string): string | null {
36
+ const found = resolveUnitCandidates(unit, projectRoot);
37
+ if (found.length !== 1) return null;
38
+ const scope = path.relative(path.join(projectRoot, 'qa'), found[0].dir).split(path.sep).join('/');
39
+ return isValidScope(scope) ? scope : null;
40
+ }
41
+
42
+ /** Every decisions directory that exists, with its scope. */
43
+ export function listDecisionDirs(projectRoot: string): { scope: string; dir: string }[] {
44
+ const qa = path.join(projectRoot, 'qa');
45
+ const out: { scope: string; dir: string }[] = [];
46
+ const add = (scope: string): void => {
47
+ const dir = decisionsDirFor(projectRoot, scope);
48
+ if (fs.existsSync(dir)) out.push({ scope, dir });
49
+ };
50
+ add(PROJECT_SCOPE);
51
+ const units = (rel: string): string[] => {
52
+ try {
53
+ return fs.readdirSync(path.join(qa, rel), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
54
+ } catch { return []; }
55
+ };
56
+ for (const kind of ['screens', 'flows', 'api']) {
57
+ for (const u of units(kind)) if (!(kind === 'api' && u === 'flows')) add(`${kind}/${u}`);
58
+ }
59
+ for (const u of units('api/flows')) add(`api/flows/${u}`);
60
+ return out;
61
+ }
62
+
63
+ export function serializeDecision(entry: DecisionEntry): string {
64
+ const head = '# Sungen decision — append-only. To change it, record a new entry with `supersedes`.\n';
65
+ return head + stringify(entry, { schema: 'core', lineWidth: 0 });
66
+ }
67
+
68
+ /** `untrusted`: legacy approval state that differs from git HEAD (viewpoint-baseline adapter). */
69
+ export type DecisionProblemCode = 'unreadable' | 'invalid' | 'id-mismatch' | 'hash-mismatch' | 'untrusted';
70
+ export interface DecisionProblem { path: string; code: DecisionProblemCode; message: string }
71
+
72
+ /**
73
+ * Read one decision file and verify it against itself: schema, file name = id, id = content
74
+ * (else `id-mismatch` → decision.id-reuse), entry_hash = entry (else `hash-mismatch` → decision.mutated).
75
+ * Never throws — a bad file is a problem, and the caller decides what that means.
76
+ */
77
+ export function verifyDecisionFile(file: string, scope: string): { entry?: DecisionEntry; problem?: DecisionProblem } {
78
+ const fail = (code: DecisionProblemCode, message: string) => ({ problem: { path: file, code, message } });
79
+ let raw: unknown;
80
+ try {
81
+ raw = safeYamlParse(fs.readFileSync(file, 'utf8'), file);
82
+ } catch (err) {
83
+ return fail('unreadable', err instanceof Error ? err.message : String(err));
84
+ }
85
+ const errors = storedEntryErrors(raw);
86
+ if (errors.length) return fail('invalid', errors.join('; '));
87
+ const entry = raw as DecisionEntry;
88
+ if (path.basename(file) !== `${entry.id}.yaml`) return fail('id-mismatch', `file name does not match its id ${entry.id}`);
89
+ const id = computeDecisionId(entry, scope);
90
+ if (id !== entry.id) return fail('id-mismatch', `stored id ${entry.id} but the content (in scope ${scope}) hashes to ${id}`);
91
+ if (computeEntryHash(entry) !== entry.entry_hash) return fail('hash-mismatch', 'entry_hash no longer matches the entry');
92
+ return { entry };
93
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Decision identity (DOS-13.2). Two hashes answer two different questions:
3
+ *
4
+ * id = `D-` + first 16 hex of sha256(normalized content)
5
+ * content = {kind, scope, anchors (sorted), text, reason, payload, supersedes, visibility,
6
+ * evidence_hash}; excludes valid_from, source, id, entry_hash
7
+ * → "what was decided, where": re-recording it later, by anyone, yields the same id
8
+ * entry_hash = full sha256 of the whole stored entry in canonical form (id, valid_from, source included)
9
+ * → "was this file altered": changing any field, even the date, breaks it
10
+ *
11
+ * Canonical form: keys sorted, strings NFC with LF line ends and trimmed, absent fields omitted
12
+ * (`null` in the id content so its key set is fixed). The stored entry IS the normalized form, so a
13
+ * hash over the parsed file equals a hash over what was sealed.
14
+ */
15
+ import { createHash } from 'crypto';
16
+ import { DecisionDraft, DecisionEntry, JsonValue } from './decision-schema';
17
+
18
+ const normText = (s: string): string => s.normalize('NFC').replace(/\r\n?/g, '\n').trim();
19
+
20
+ export function canonicalize(v: unknown): unknown {
21
+ if (typeof v === 'string') return normText(v);
22
+ if (Array.isArray(v)) return v.map(canonicalize);
23
+ if (v && typeof v === 'object') {
24
+ const out: Record<string, unknown> = {};
25
+ for (const k of Object.keys(v).sort()) {
26
+ const x = (v as Record<string, unknown>)[k];
27
+ if (x !== undefined) out[k] = canonicalize(x);
28
+ }
29
+ return out;
30
+ }
31
+ return v;
32
+ }
33
+
34
+ export const canonicalJson = (v: unknown): string => JSON.stringify(canonicalize(v));
35
+ const sha256 = (s: string): string => createHash('sha256').update(s).digest('hex');
36
+
37
+ /** The draft as it is stored: normalized strings, sorted anchors, absent optionals dropped. */
38
+ export function normalizeDraft(d: DecisionDraft): DecisionDraft {
39
+ const out: DecisionDraft = {
40
+ kind: d.kind,
41
+ anchors: d.anchors.map(normText).sort(),
42
+ text: normText(d.text),
43
+ reason: normText(d.reason),
44
+ ...(d.payload !== undefined ? { payload: canonicalize(d.payload) as Record<string, JsonValue> } : {}),
45
+ source: { by: normText(d.source.by), where: normText(d.source.where) },
46
+ valid_from: normText(d.valid_from),
47
+ ...(d.supersedes !== undefined ? { supersedes: normText(d.supersedes) } : {}),
48
+ visibility: d.visibility,
49
+ ...(d.evidence_hash !== undefined ? { evidence_hash: normText(d.evidence_hash) } : {}),
50
+ };
51
+ return out;
52
+ }
53
+
54
+ export function computeDecisionId(d: DecisionDraft, scope: string): string {
55
+ const n = normalizeDraft(d);
56
+ const content = {
57
+ kind: n.kind, scope, anchors: n.anchors, text: n.text, reason: n.reason, payload: n.payload ?? null,
58
+ supersedes: n.supersedes ?? null, visibility: n.visibility, evidence_hash: n.evidence_hash ?? null,
59
+ };
60
+ return `D-${sha256(canonicalJson(content)).slice(0, 16)}`;
61
+ }
62
+
63
+ export function computeEntryHash(entry: Omit<DecisionEntry, 'entry_hash'> & { entry_hash?: string }): string {
64
+ const { entry_hash: _ignored, ...rest } = entry;
65
+ return sha256(canonicalJson(rest));
66
+ }
67
+
68
+ /** Normalize a draft and give it its id and entry_hash, fields in storage order. */
69
+ export function sealDecision(d: DecisionDraft, scope: string): DecisionEntry {
70
+ const n = normalizeDraft(d);
71
+ const withId = { id: computeDecisionId(n, scope), ...n };
72
+ return { ...withId, entry_hash: computeEntryHash(withId) };
73
+ }