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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (889) hide show
  1. package/dist/basis/anchor-grammar.d.ts +32 -0
  2. package/dist/basis/anchor-grammar.d.ts.map +1 -0
  3. package/dist/basis/anchor-grammar.js +82 -0
  4. package/dist/basis/anchor-grammar.js.map +1 -0
  5. package/dist/basis/anchor-hash.d.ts +6 -0
  6. package/dist/basis/anchor-hash.d.ts.map +1 -0
  7. package/dist/basis/anchor-hash.js +28 -0
  8. package/dist/basis/anchor-hash.js.map +1 -0
  9. package/dist/basis/bm51-tables.d.ts +20 -0
  10. package/dist/basis/bm51-tables.d.ts.map +1 -0
  11. package/dist/basis/bm51-tables.js +71 -0
  12. package/dist/basis/bm51-tables.js.map +1 -0
  13. package/dist/basis/extract-spec-anchors.d.ts +39 -0
  14. package/dist/basis/extract-spec-anchors.d.ts.map +1 -0
  15. package/dist/basis/extract-spec-anchors.js +81 -0
  16. package/dist/basis/extract-spec-anchors.js.map +1 -0
  17. package/dist/basis/migration-sentinel.d.ts +47 -0
  18. package/dist/basis/migration-sentinel.d.ts.map +1 -0
  19. package/dist/basis/migration-sentinel.js +219 -0
  20. package/dist/basis/migration-sentinel.js.map +1 -0
  21. package/dist/basis/spec-frontmatter.d.ts +18 -0
  22. package/dist/basis/spec-frontmatter.d.ts.map +1 -0
  23. package/dist/basis/spec-frontmatter.js +55 -0
  24. package/dist/basis/spec-frontmatter.js.map +1 -0
  25. package/dist/basis/spec-sections.d.ts +18 -0
  26. package/dist/basis/spec-sections.d.ts.map +1 -0
  27. package/dist/basis/spec-sections.js +27 -0
  28. package/dist/basis/spec-sections.js.map +1 -0
  29. package/dist/basis/test-basis-schema.d.ts +28 -0
  30. package/dist/basis/test-basis-schema.d.ts.map +1 -0
  31. package/dist/basis/test-basis-schema.js +141 -0
  32. package/dist/basis/test-basis-schema.js.map +1 -0
  33. package/dist/capabilities/discover.d.ts +4 -0
  34. package/dist/capabilities/discover.d.ts.map +1 -1
  35. package/dist/capabilities/discover.js +16 -2
  36. package/dist/capabilities/discover.js.map +1 -1
  37. package/dist/capabilities/registry.d.ts +15 -0
  38. package/dist/capabilities/registry.d.ts.map +1 -1
  39. package/dist/capabilities/registry.js.map +1 -1
  40. package/dist/cli/commands/audit.d.ts.map +1 -1
  41. package/dist/cli/commands/audit.js +10 -5
  42. package/dist/cli/commands/audit.js.map +1 -1
  43. package/dist/cli/commands/capability.d.ts.map +1 -1
  44. package/dist/cli/commands/capability.js +6 -2
  45. package/dist/cli/commands/capability.js.map +1 -1
  46. package/dist/cli/commands/contract-derive-command.d.ts +11 -0
  47. package/dist/cli/commands/contract-derive-command.d.ts.map +1 -0
  48. package/dist/cli/commands/contract-derive-command.js +99 -0
  49. package/dist/cli/commands/contract-derive-command.js.map +1 -0
  50. package/dist/cli/commands/contract.d.ts +17 -0
  51. package/dist/cli/commands/contract.d.ts.map +1 -0
  52. package/dist/cli/commands/contract.js +162 -0
  53. package/dist/cli/commands/contract.js.map +1 -0
  54. package/dist/cli/commands/defect.d.ts +7 -0
  55. package/dist/cli/commands/defect.d.ts.map +1 -0
  56. package/dist/cli/commands/defect.js +68 -0
  57. package/dist/cli/commands/defect.js.map +1 -0
  58. package/dist/cli/commands/delivery.d.ts.map +1 -1
  59. package/dist/cli/commands/delivery.js +96 -12
  60. package/dist/cli/commands/delivery.js.map +1 -1
  61. package/dist/cli/commands/generate.d.ts.map +1 -1
  62. package/dist/cli/commands/generate.js +3 -1
  63. package/dist/cli/commands/generate.js.map +1 -1
  64. package/dist/cli/commands/journey.d.ts.map +1 -1
  65. package/dist/cli/commands/journey.js +43 -15
  66. package/dist/cli/commands/journey.js.map +1 -1
  67. package/dist/cli/commands/next.d.ts +8 -0
  68. package/dist/cli/commands/next.d.ts.map +1 -1
  69. package/dist/cli/commands/next.js +68 -8
  70. package/dist/cli/commands/next.js.map +1 -1
  71. package/dist/cli/commands/triage.d.ts +7 -0
  72. package/dist/cli/commands/triage.d.ts.map +1 -0
  73. package/dist/cli/commands/triage.js +98 -0
  74. package/dist/cli/commands/triage.js.map +1 -0
  75. package/dist/cli/commands/update.d.ts +11 -0
  76. package/dist/cli/commands/update.d.ts.map +1 -1
  77. package/dist/cli/commands/update.js +31 -6
  78. package/dist/cli/commands/update.js.map +1 -1
  79. package/dist/cli/index.js +24 -33
  80. package/dist/cli/index.js.map +1 -1
  81. package/dist/cli/project-sungen-invocation.d.ts +7 -0
  82. package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
  83. package/dist/cli/project-sungen-invocation.js +76 -0
  84. package/dist/cli/project-sungen-invocation.js.map +1 -0
  85. package/dist/contract/approve-contract.d.ts +31 -0
  86. package/dist/contract/approve-contract.d.ts.map +1 -0
  87. package/dist/contract/approve-contract.js +87 -0
  88. package/dist/contract/approve-contract.js.map +1 -0
  89. package/dist/contract/assertion-matcher-vocabulary.d.ts +24 -0
  90. package/dist/contract/assertion-matcher-vocabulary.d.ts.map +1 -0
  91. package/dist/contract/assertion-matcher-vocabulary.js +100 -0
  92. package/dist/contract/assertion-matcher-vocabulary.js.map +1 -0
  93. package/dist/contract/build-contract-verdict.d.ts +32 -0
  94. package/dist/contract/build-contract-verdict.d.ts.map +1 -0
  95. package/dist/contract/build-contract-verdict.js +123 -0
  96. package/dist/contract/build-contract-verdict.js.map +1 -0
  97. package/dist/contract/build-trace-conformance.d.ts +18 -0
  98. package/dist/contract/build-trace-conformance.d.ts.map +1 -0
  99. package/dist/contract/build-trace-conformance.js +153 -0
  100. package/dist/contract/build-trace-conformance.js.map +1 -0
  101. package/dist/contract/classify-contract-change.d.ts +23 -0
  102. package/dist/contract/classify-contract-change.d.ts.map +1 -0
  103. package/dist/contract/classify-contract-change.js +98 -0
  104. package/dist/contract/classify-contract-change.js.map +1 -0
  105. package/dist/contract/classify-contract-unit.d.ts +18 -0
  106. package/dist/contract/classify-contract-unit.d.ts.map +1 -0
  107. package/dist/contract/classify-contract-unit.js +49 -0
  108. package/dist/contract/classify-contract-unit.js.map +1 -0
  109. package/dist/contract/classify-trace-conformance.d.ts +32 -0
  110. package/dist/contract/classify-trace-conformance.d.ts.map +1 -0
  111. package/dist/contract/classify-trace-conformance.js +117 -0
  112. package/dist/contract/classify-trace-conformance.js.map +1 -0
  113. package/dist/contract/contract-git.d.ts +24 -0
  114. package/dist/contract/contract-git.d.ts.map +1 -0
  115. package/dist/contract/contract-git.js +144 -0
  116. package/dist/contract/contract-git.js.map +1 -0
  117. package/dist/contract/contract-hash.d.ts +7 -0
  118. package/dist/contract/contract-hash.d.ts.map +1 -0
  119. package/dist/contract/contract-hash.js +38 -0
  120. package/dist/contract/contract-hash.js.map +1 -0
  121. package/dist/contract/contract-report-file.d.ts +4 -0
  122. package/dist/contract/contract-report-file.d.ts.map +1 -0
  123. package/dist/contract/contract-report-file.js +60 -0
  124. package/dist/contract/contract-report-file.js.map +1 -0
  125. package/dist/contract/contract-schema.d.ts +71 -0
  126. package/dist/contract/contract-schema.d.ts.map +1 -0
  127. package/dist/contract/contract-schema.js +102 -0
  128. package/dist/contract/contract-schema.js.map +1 -0
  129. package/dist/contract/contract-units.d.ts +12 -0
  130. package/dist/contract/contract-units.d.ts.map +1 -0
  131. package/dist/contract/contract-units.js +96 -0
  132. package/dist/contract/contract-units.js.map +1 -0
  133. package/dist/contract/contracts-lock-file.d.ts +24 -0
  134. package/dist/contract/contracts-lock-file.d.ts.map +1 -0
  135. package/dist/contract/contracts-lock-file.js +140 -0
  136. package/dist/contract/contracts-lock-file.js.map +1 -0
  137. package/dist/contract/data-normalize.d.ts +10 -0
  138. package/dist/contract/data-normalize.d.ts.map +1 -0
  139. package/dist/contract/data-normalize.js +110 -0
  140. package/dist/contract/data-normalize.js.map +1 -0
  141. package/dist/contract/derive-free-feature.d.ts +38 -0
  142. package/dist/contract/derive-free-feature.d.ts.map +1 -0
  143. package/dist/contract/derive-free-feature.js +154 -0
  144. package/dist/contract/derive-free-feature.js.map +1 -0
  145. package/dist/contract/field-semantic-redaction.d.ts +21 -0
  146. package/dist/contract/field-semantic-redaction.d.ts.map +1 -0
  147. package/dist/contract/field-semantic-redaction.js +118 -0
  148. package/dist/contract/field-semantic-redaction.js.map +1 -0
  149. package/dist/contract/free-feature-blocks.d.ts +10 -0
  150. package/dist/contract/free-feature-blocks.d.ts.map +1 -0
  151. package/dist/contract/free-feature-blocks.js +94 -0
  152. package/dist/contract/free-feature-blocks.js.map +1 -0
  153. package/dist/contract/lock-secret-guard.d.ts +22 -0
  154. package/dist/contract/lock-secret-guard.d.ts.map +1 -0
  155. package/dist/contract/lock-secret-guard.js +134 -0
  156. package/dist/contract/lock-secret-guard.js.map +1 -0
  157. package/dist/contract/lock-vs-git-head.d.ts +26 -0
  158. package/dist/contract/lock-vs-git-head.d.ts.map +1 -0
  159. package/dist/contract/lock-vs-git-head.js +28 -0
  160. package/dist/contract/lock-vs-git-head.js.map +1 -0
  161. package/dist/contract/normalize-contract-step.d.ts +21 -0
  162. package/dist/contract/normalize-contract-step.d.ts.map +1 -0
  163. package/dist/contract/normalize-contract-step.js +70 -0
  164. package/dist/contract/normalize-contract-step.js.map +1 -0
  165. package/dist/contract/normalize-feature-steps.d.ts +7 -0
  166. package/dist/contract/normalize-feature-steps.d.ts.map +1 -0
  167. package/dist/contract/normalize-feature-steps.js +127 -0
  168. package/dist/contract/normalize-feature-steps.js.map +1 -0
  169. package/dist/contract/oracle-strength.d.ts +12 -0
  170. package/dist/contract/oracle-strength.d.ts.map +1 -0
  171. package/dist/contract/oracle-strength.js +88 -0
  172. package/dist/contract/oracle-strength.js.map +1 -0
  173. package/dist/contract/project-contract-blockers.d.ts +10 -0
  174. package/dist/contract/project-contract-blockers.d.ts.map +1 -0
  175. package/dist/contract/project-contract-blockers.js +73 -0
  176. package/dist/contract/project-contract-blockers.js.map +1 -0
  177. package/dist/contract/record-contract-approval.d.ts +21 -0
  178. package/dist/contract/record-contract-approval.d.ts.map +1 -0
  179. package/dist/contract/record-contract-approval.js +98 -0
  180. package/dist/contract/record-contract-approval.js.map +1 -0
  181. package/dist/contract/render-free-gherkin.d.ts +40 -0
  182. package/dist/contract/render-free-gherkin.d.ts.map +1 -0
  183. package/dist/contract/render-free-gherkin.js +141 -0
  184. package/dist/contract/render-free-gherkin.js.map +1 -0
  185. package/dist/contract/render-trace-sentence.d.ts +20 -0
  186. package/dist/contract/render-trace-sentence.d.ts.map +1 -0
  187. package/dist/contract/render-trace-sentence.js +109 -0
  188. package/dist/contract/render-trace-sentence.js.map +1 -0
  189. package/dist/contract/render-trace-target.d.ts +14 -0
  190. package/dist/contract/render-trace-target.d.ts.map +1 -0
  191. package/dist/contract/render-trace-target.js +70 -0
  192. package/dist/contract/render-trace-target.js.map +1 -0
  193. package/dist/contract/resolve-unit-trace-identities.d.ts +8 -0
  194. package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -0
  195. package/dist/contract/resolve-unit-trace-identities.js +78 -0
  196. package/dist/contract/resolve-unit-trace-identities.js.map +1 -0
  197. package/dist/contract/trace/collect-trace-evidence.d.ts +33 -0
  198. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -0
  199. package/dist/contract/trace/collect-trace-evidence.js +161 -0
  200. package/dist/contract/trace/collect-trace-evidence.js.map +1 -0
  201. package/dist/contract/trace/identity-cache.d.ts +19 -0
  202. package/dist/contract/trace/identity-cache.d.ts.map +1 -0
  203. package/dist/contract/trace/identity-cache.js +104 -0
  204. package/dist/contract/trace/identity-cache.js.map +1 -0
  205. package/dist/contract/trace/select-final-attempt.d.ts +27 -0
  206. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -0
  207. package/dist/contract/trace/select-final-attempt.js +116 -0
  208. package/dist/contract/trace/select-final-attempt.js.map +1 -0
  209. package/dist/contract/trace/snapshot-html-renderer.d.ts +31 -0
  210. package/dist/contract/trace/snapshot-html-renderer.d.ts.map +1 -0
  211. package/dist/contract/trace/snapshot-html-renderer.js +172 -0
  212. package/dist/contract/trace/snapshot-html-renderer.js.map +1 -0
  213. package/dist/contract/trace/snapshot-resolver.d.ts +21 -0
  214. package/dist/contract/trace/snapshot-resolver.d.ts.map +1 -0
  215. package/dist/contract/trace/snapshot-resolver.js +65 -0
  216. package/dist/contract/trace/snapshot-resolver.js.map +1 -0
  217. package/dist/contract/trace/snapshot-store.d.ts +66 -0
  218. package/dist/contract/trace/snapshot-store.d.ts.map +1 -0
  219. package/dist/contract/trace/snapshot-store.js +173 -0
  220. package/dist/contract/trace/snapshot-store.js.map +1 -0
  221. package/dist/contract/trace/target-identity.d.ts +74 -0
  222. package/dist/contract/trace/target-identity.d.ts.map +1 -0
  223. package/dist/contract/trace/target-identity.js +68 -0
  224. package/dist/contract/trace/target-identity.js.map +1 -0
  225. package/dist/contract/trace/test-step-join.d.ts +65 -0
  226. package/dist/contract/trace/test-step-join.d.ts.map +1 -0
  227. package/dist/contract/trace/test-step-join.js +80 -0
  228. package/dist/contract/trace/test-step-join.js.map +1 -0
  229. package/dist/contract/trace/trace-binding.d.ts +21 -0
  230. package/dist/contract/trace/trace-binding.d.ts.map +1 -0
  231. package/dist/contract/trace/trace-binding.js +88 -0
  232. package/dist/contract/trace/trace-binding.js.map +1 -0
  233. package/dist/contract/trace/trace-file-reader.d.ts +41 -0
  234. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -0
  235. package/dist/contract/trace/trace-file-reader.js +161 -0
  236. package/dist/contract/trace/trace-file-reader.js.map +1 -0
  237. package/dist/contract/trace/trace-fingerprint.d.ts +22 -0
  238. package/dist/contract/trace/trace-fingerprint.d.ts.map +1 -0
  239. package/dist/contract/trace/trace-fingerprint.js +96 -0
  240. package/dist/contract/trace/trace-fingerprint.js.map +1 -0
  241. package/dist/contract/trace/trace-identity-resolution.d.ts +26 -0
  242. package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -0
  243. package/dist/contract/trace/trace-identity-resolution.js +84 -0
  244. package/dist/contract/trace/trace-identity-resolution.js.map +1 -0
  245. package/dist/contract/trace/trace-run-record.d.ts +30 -0
  246. package/dist/contract/trace/trace-run-record.d.ts.map +1 -0
  247. package/dist/contract/trace/trace-run-record.js +121 -0
  248. package/dist/contract/trace/trace-run-record.js.map +1 -0
  249. package/dist/contract/trace/trace-steps.d.ts +19 -0
  250. package/dist/contract/trace/trace-steps.d.ts.map +1 -0
  251. package/dist/contract/trace/trace-steps.js +79 -0
  252. package/dist/contract/trace/trace-steps.js.map +1 -0
  253. package/dist/contract/trace/trace-zip-limits.d.ts +45 -0
  254. package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -0
  255. package/dist/contract/trace/trace-zip-limits.js +52 -0
  256. package/dist/contract/trace/trace-zip-limits.js.map +1 -0
  257. package/dist/contract/trace/trace-zip-reader.d.ts +10 -0
  258. package/dist/contract/trace/trace-zip-reader.d.ts.map +1 -0
  259. package/dist/contract/trace/trace-zip-reader.js +186 -0
  260. package/dist/contract/trace/trace-zip-reader.js.map +1 -0
  261. package/dist/contract/verify-approval-decisions.d.ts +5 -0
  262. package/dist/contract/verify-approval-decisions.d.ts.map +1 -0
  263. package/dist/contract/verify-approval-decisions.js +104 -0
  264. package/dist/contract/verify-approval-decisions.js.map +1 -0
  265. package/dist/decisions/append-decision.d.ts +12 -0
  266. package/dist/decisions/append-decision.d.ts.map +1 -0
  267. package/dist/decisions/append-decision.js +73 -0
  268. package/dist/decisions/append-decision.js.map +1 -0
  269. package/dist/decisions/confirmed-decision-commands.d.ts +41 -0
  270. package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -0
  271. package/dist/decisions/confirmed-decision-commands.js +190 -0
  272. package/dist/decisions/confirmed-decision-commands.js.map +1 -0
  273. package/dist/decisions/decision-file.d.ts +31 -0
  274. package/dist/decisions/decision-file.d.ts.map +1 -0
  275. package/dist/decisions/decision-file.js +139 -0
  276. package/dist/decisions/decision-file.js.map +1 -0
  277. package/dist/decisions/decision-identity.d.ts +12 -0
  278. package/dist/decisions/decision-identity.d.ts.map +1 -0
  279. package/dist/decisions/decision-identity.js +78 -0
  280. package/dist/decisions/decision-identity.js.map +1 -0
  281. package/dist/decisions/decision-integrity-check.d.ts +12 -0
  282. package/dist/decisions/decision-integrity-check.d.ts.map +1 -0
  283. package/dist/decisions/decision-integrity-check.js +102 -0
  284. package/dist/decisions/decision-integrity-check.js.map +1 -0
  285. package/dist/decisions/decision-schema.d.ts +42 -0
  286. package/dist/decisions/decision-schema.d.ts.map +1 -0
  287. package/dist/decisions/decision-schema.js +75 -0
  288. package/dist/decisions/decision-schema.js.map +1 -0
  289. package/dist/decisions/decision-source.d.ts +2 -0
  290. package/dist/decisions/decision-source.d.ts.map +1 -0
  291. package/dist/decisions/decision-source.js +18 -0
  292. package/dist/decisions/decision-source.js.map +1 -0
  293. package/dist/decisions/exclusive-file-create.d.ts +3 -0
  294. package/dist/decisions/exclusive-file-create.d.ts.map +1 -0
  295. package/dist/decisions/exclusive-file-create.js +84 -0
  296. package/dist/decisions/exclusive-file-create.js.map +1 -0
  297. package/dist/decisions/git-head-trust.d.ts +7 -0
  298. package/dist/decisions/git-head-trust.d.ts.map +1 -0
  299. package/dist/decisions/git-head-trust.js +76 -0
  300. package/dist/decisions/git-head-trust.js.map +1 -0
  301. package/dist/decisions/human-confirmation.d.ts +35 -0
  302. package/dist/decisions/human-confirmation.d.ts.map +1 -0
  303. package/dist/decisions/human-confirmation.js +161 -0
  304. package/dist/decisions/human-confirmation.js.map +1 -0
  305. package/dist/decisions/legacy-waiver-migration.d.ts +31 -0
  306. package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -0
  307. package/dist/decisions/legacy-waiver-migration.js +170 -0
  308. package/dist/decisions/legacy-waiver-migration.js.map +1 -0
  309. package/dist/decisions/read-decisions.d.ts +19 -0
  310. package/dist/decisions/read-decisions.d.ts.map +1 -0
  311. package/dist/decisions/read-decisions.js +90 -0
  312. package/dist/decisions/read-decisions.js.map +1 -0
  313. package/dist/decisions/viewpoint-baseline-adapter.d.ts +7 -0
  314. package/dist/decisions/viewpoint-baseline-adapter.d.ts.map +1 -0
  315. package/dist/decisions/viewpoint-baseline-adapter.js +109 -0
  316. package/dist/decisions/viewpoint-baseline-adapter.js.map +1 -0
  317. package/dist/decisions/waiver-decisions.d.ts +24 -0
  318. package/dist/decisions/waiver-decisions.d.ts.map +1 -0
  319. package/dist/decisions/waiver-decisions.js +46 -0
  320. package/dist/decisions/waiver-decisions.js.map +1 -0
  321. package/dist/exporters/csv-exporter.d.ts +4 -0
  322. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  323. package/dist/exporters/csv-exporter.js +1 -1
  324. package/dist/exporters/csv-exporter.js.map +1 -1
  325. package/dist/exporters/feature-parser.d.ts +8 -0
  326. package/dist/exporters/feature-parser.d.ts.map +1 -1
  327. package/dist/exporters/feature-parser.js +12 -0
  328. package/dist/exporters/feature-parser.js.map +1 -1
  329. package/dist/exporters/matrix/build.d.ts +3 -0
  330. package/dist/exporters/matrix/build.d.ts.map +1 -1
  331. package/dist/exporters/matrix/build.js +59 -19
  332. package/dist/exporters/matrix/build.js.map +1 -1
  333. package/dist/exporters/matrix/carry-manual-results.d.ts +19 -0
  334. package/dist/exporters/matrix/carry-manual-results.d.ts.map +1 -1
  335. package/dist/exporters/matrix/carry-manual-results.js +76 -6
  336. package/dist/exporters/matrix/carry-manual-results.js.map +1 -1
  337. package/dist/exporters/matrix/export.d.ts +8 -2
  338. package/dist/exporters/matrix/export.d.ts.map +1 -1
  339. package/dist/exporters/matrix/export.js +16 -3
  340. package/dist/exporters/matrix/export.js.map +1 -1
  341. package/dist/exporters/matrix/gates.d.ts +6 -1
  342. package/dist/exporters/matrix/gates.d.ts.map +1 -1
  343. package/dist/exporters/matrix/gates.js +57 -128
  344. package/dist/exporters/matrix/gates.js.map +1 -1
  345. package/dist/exporters/matrix/render-csv.d.ts.map +1 -1
  346. package/dist/exporters/matrix/render-csv.js +4 -1
  347. package/dist/exporters/matrix/render-csv.js.map +1 -1
  348. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts +13 -0
  349. package/dist/exporters/matrix/render-gate-overrides-sheet.d.ts.map +1 -0
  350. package/dist/exporters/matrix/render-gate-overrides-sheet.js +44 -0
  351. package/dist/exporters/matrix/render-gate-overrides-sheet.js.map +1 -0
  352. package/dist/exporters/matrix/render-xlsx.d.ts +1 -0
  353. package/dist/exporters/matrix/render-xlsx.d.ts.map +1 -1
  354. package/dist/exporters/matrix/render-xlsx.js +6 -0
  355. package/dist/exporters/matrix/render-xlsx.js.map +1 -1
  356. package/dist/exporters/matrix/types.d.ts +9 -1
  357. package/dist/exporters/matrix/types.d.ts.map +1 -1
  358. package/dist/exporters/matrix/types.js.map +1 -1
  359. package/dist/exporters/matrix/xlsx-cells.js +1 -1
  360. package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
  361. package/dist/exporters/playwright-report-parser.d.ts.map +1 -1
  362. package/dist/exporters/playwright-report-parser.js +1 -0
  363. package/dist/exporters/playwright-report-parser.js.map +1 -1
  364. package/dist/exporters/scenario-merger.d.ts.map +1 -1
  365. package/dist/exporters/scenario-merger.js +2 -0
  366. package/dist/exporters/scenario-merger.js.map +1 -1
  367. package/dist/exporters/types.d.ts +5 -0
  368. package/dist/exporters/types.d.ts.map +1 -1
  369. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  370. package/dist/generators/test-generator/code-generator.js +13 -0
  371. package/dist/generators/test-generator/code-generator.js.map +1 -1
  372. package/dist/graph/evaluate-graph.d.ts +23 -0
  373. package/dist/graph/evaluate-graph.d.ts.map +1 -0
  374. package/dist/graph/evaluate-graph.js +52 -0
  375. package/dist/graph/evaluate-graph.js.map +1 -0
  376. package/dist/graph/locate-finding.d.ts +20 -0
  377. package/dist/graph/locate-finding.d.ts.map +1 -0
  378. package/dist/graph/locate-finding.js +137 -0
  379. package/dist/graph/locate-finding.js.map +1 -0
  380. package/dist/graph/node-decl.d.ts +66 -0
  381. package/dist/graph/node-decl.d.ts.map +1 -0
  382. package/dist/graph/node-decl.js +8 -0
  383. package/dist/graph/node-decl.js.map +1 -0
  384. package/dist/graph/nodes/core-node-catalog.d.ts +7 -0
  385. package/dist/graph/nodes/core-node-catalog.d.ts.map +1 -0
  386. package/dist/graph/nodes/core-node-catalog.js +13 -0
  387. package/dist/graph/nodes/core-node-catalog.js.map +1 -0
  388. package/dist/graph/nodes/test-case-contract-nodes.d.ts +21 -0
  389. package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -0
  390. package/dist/graph/nodes/test-case-contract-nodes.js +59 -0
  391. package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -0
  392. package/dist/graph/nodes/test-case-nodes.d.ts +26 -0
  393. package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -0
  394. package/dist/graph/nodes/test-case-nodes.js +66 -0
  395. package/dist/graph/nodes/test-case-nodes.js.map +1 -0
  396. package/dist/graph/nodes/unit-audit-nodes.d.ts +18 -0
  397. package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -0
  398. package/dist/graph/nodes/unit-audit-nodes.js +95 -0
  399. package/dist/graph/nodes/unit-audit-nodes.js.map +1 -0
  400. package/dist/graph/nodes/unit-contract-node.d.ts +21 -0
  401. package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -0
  402. package/dist/graph/nodes/unit-contract-node.js +88 -0
  403. package/dist/graph/nodes/unit-contract-node.js.map +1 -0
  404. package/dist/graph/nodes/unit-design-nodes.d.ts +14 -0
  405. package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -0
  406. package/dist/graph/nodes/unit-design-nodes.js +91 -0
  407. package/dist/graph/nodes/unit-design-nodes.js.map +1 -0
  408. package/dist/graph/nodes/unit-execution-nodes.d.ts +16 -0
  409. package/dist/graph/nodes/unit-execution-nodes.d.ts.map +1 -0
  410. package/dist/graph/nodes/unit-execution-nodes.js +79 -0
  411. package/dist/graph/nodes/unit-execution-nodes.js.map +1 -0
  412. package/dist/graph/test-case-identity.d.ts +13 -0
  413. package/dist/graph/test-case-identity.d.ts.map +1 -0
  414. package/dist/graph/test-case-identity.js +106 -0
  415. package/dist/graph/test-case-identity.js.map +1 -0
  416. package/dist/graph/test-case-results.d.ts +11 -0
  417. package/dist/graph/test-case-results.d.ts.map +1 -0
  418. package/dist/graph/test-case-results.js +137 -0
  419. package/dist/graph/test-case-results.js.map +1 -0
  420. package/dist/graph/test-case-satisfied.d.ts +25 -0
  421. package/dist/graph/test-case-satisfied.d.ts.map +1 -0
  422. package/dist/graph/test-case-satisfied.js +51 -0
  423. package/dist/graph/test-case-satisfied.js.map +1 -0
  424. package/dist/graph/test-case-state-shape.d.ts +67 -0
  425. package/dist/graph/test-case-state-shape.d.ts.map +1 -0
  426. package/dist/graph/test-case-state-shape.js +3 -0
  427. package/dist/graph/test-case-state-shape.js.map +1 -0
  428. package/dist/graph/test-case-states.d.ts +9 -0
  429. package/dist/graph/test-case-states.d.ts.map +1 -0
  430. package/dist/graph/test-case-states.js +116 -0
  431. package/dist/graph/test-case-states.js.map +1 -0
  432. package/dist/graph/unit-artifact-probes.d.ts +19 -0
  433. package/dist/graph/unit-artifact-probes.d.ts.map +1 -0
  434. package/dist/graph/unit-artifact-probes.js +133 -0
  435. package/dist/graph/unit-artifact-probes.js.map +1 -0
  436. package/dist/graph/unit-state-facts.d.ts +43 -0
  437. package/dist/graph/unit-state-facts.d.ts.map +1 -0
  438. package/dist/graph/unit-state-facts.js +87 -0
  439. package/dist/graph/unit-state-facts.js.map +1 -0
  440. package/dist/harness/audit.d.ts +11 -0
  441. package/dist/harness/audit.d.ts.map +1 -1
  442. package/dist/harness/audit.js +34 -9
  443. package/dist/harness/audit.js.map +1 -1
  444. package/dist/harness/catalog/gate-rules.yaml +647 -0
  445. package/dist/harness/counted-assertions.d.ts +2 -0
  446. package/dist/harness/counted-assertions.d.ts.map +1 -0
  447. package/dist/harness/counted-assertions.js +38 -0
  448. package/dist/harness/counted-assertions.js.map +1 -0
  449. package/dist/harness/defect-draft.d.ts +14 -0
  450. package/dist/harness/defect-draft.d.ts.map +1 -0
  451. package/dist/harness/defect-draft.js +143 -0
  452. package/dist/harness/defect-draft.js.map +1 -0
  453. package/dist/harness/defects.d.ts +24 -0
  454. package/dist/harness/defects.d.ts.map +1 -0
  455. package/dist/harness/defects.js +118 -0
  456. package/dist/harness/defects.js.map +1 -0
  457. package/dist/harness/gates/audit-gate-terms.d.ts +41 -0
  458. package/dist/harness/gates/audit-gate-terms.d.ts.map +1 -0
  459. package/dist/harness/gates/audit-gate-terms.js +72 -0
  460. package/dist/harness/gates/audit-gate-terms.js.map +1 -0
  461. package/dist/harness/gates/audit-gate-verdict.d.ts +31 -0
  462. package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -0
  463. package/dist/harness/gates/audit-gate-verdict.js +101 -0
  464. package/dist/harness/gates/audit-gate-verdict.js.map +1 -0
  465. package/dist/harness/gates/audit-input-hash.d.ts +4 -0
  466. package/dist/harness/gates/audit-input-hash.d.ts.map +1 -0
  467. package/dist/harness/gates/audit-input-hash.js +96 -0
  468. package/dist/harness/gates/audit-input-hash.js.map +1 -0
  469. package/dist/harness/gates/audit-report-verification.d.ts +41 -0
  470. package/dist/harness/gates/audit-report-verification.d.ts.map +1 -0
  471. package/dist/harness/gates/audit-report-verification.js +236 -0
  472. package/dist/harness/gates/audit-report-verification.js.map +1 -0
  473. package/dist/harness/gates/decisions-hash.d.ts +13 -0
  474. package/dist/harness/gates/decisions-hash.d.ts.map +1 -0
  475. package/dist/harness/gates/decisions-hash.js +72 -0
  476. package/dist/harness/gates/decisions-hash.js.map +1 -0
  477. package/dist/harness/gates/delivery-checklist.d.ts +21 -0
  478. package/dist/harness/gates/delivery-checklist.d.ts.map +1 -0
  479. package/dist/harness/gates/delivery-checklist.js +128 -0
  480. package/dist/harness/gates/delivery-checklist.js.map +1 -0
  481. package/dist/harness/gates/delivery-decision-gate.d.ts +33 -0
  482. package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -0
  483. package/dist/harness/gates/delivery-decision-gate.js +116 -0
  484. package/dist/harness/gates/delivery-decision-gate.js.map +1 -0
  485. package/dist/harness/gates/delivery-decision-step.d.ts +19 -0
  486. package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -0
  487. package/dist/harness/gates/delivery-decision-step.js +86 -0
  488. package/dist/harness/gates/delivery-decision-step.js.map +1 -0
  489. package/dist/harness/gates/gate-override-report.d.ts +59 -0
  490. package/dist/harness/gates/gate-override-report.d.ts.map +1 -0
  491. package/dist/harness/gates/gate-override-report.js +86 -0
  492. package/dist/harness/gates/gate-override-report.js.map +1 -0
  493. package/dist/harness/gates/gate-override-scope.d.ts +18 -0
  494. package/dist/harness/gates/gate-override-scope.d.ts.map +1 -0
  495. package/dist/harness/gates/gate-override-scope.js +98 -0
  496. package/dist/harness/gates/gate-override-scope.js.map +1 -0
  497. package/dist/harness/gates/gate-override-validation.d.ts +25 -0
  498. package/dist/harness/gates/gate-override-validation.d.ts.map +1 -0
  499. package/dist/harness/gates/gate-override-validation.js +81 -0
  500. package/dist/harness/gates/gate-override-validation.js.map +1 -0
  501. package/dist/harness/gates/gate-rule-catalog.d.ts +24 -0
  502. package/dist/harness/gates/gate-rule-catalog.d.ts.map +1 -0
  503. package/dist/harness/gates/gate-rule-catalog.js +112 -0
  504. package/dist/harness/gates/gate-rule-catalog.js.map +1 -0
  505. package/dist/harness/gates/gate-terms.d.ts +33 -0
  506. package/dist/harness/gates/gate-terms.d.ts.map +1 -0
  507. package/dist/harness/gates/gate-terms.js +41 -0
  508. package/dist/harness/gates/gate-terms.js.map +1 -0
  509. package/dist/harness/gates/in-run-decision-check.d.ts +21 -0
  510. package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -0
  511. package/dist/harness/gates/in-run-decision-check.js +138 -0
  512. package/dist/harness/gates/in-run-decision-check.js.map +1 -0
  513. package/dist/harness/gates/journey-gate-inputs.d.ts +37 -0
  514. package/dist/harness/gates/journey-gate-inputs.d.ts.map +1 -0
  515. package/dist/harness/gates/journey-gate-inputs.js +81 -0
  516. package/dist/harness/gates/journey-gate-inputs.js.map +1 -0
  517. package/dist/harness/gates/migrated-waiver-review.d.ts +6 -0
  518. package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -0
  519. package/dist/harness/gates/migrated-waiver-review.js +116 -0
  520. package/dist/harness/gates/migrated-waiver-review.js.map +1 -0
  521. package/dist/harness/gates/resolve-rule.d.ts +59 -0
  522. package/dist/harness/gates/resolve-rule.d.ts.map +1 -0
  523. package/dist/harness/gates/resolve-rule.js +41 -0
  524. package/dist/harness/gates/resolve-rule.js.map +1 -0
  525. package/dist/harness/gates/unit-gate-overrides.d.ts +25 -0
  526. package/dist/harness/gates/unit-gate-overrides.d.ts.map +1 -0
  527. package/dist/harness/gates/unit-gate-overrides.js +122 -0
  528. package/dist/harness/gates/unit-gate-overrides.js.map +1 -0
  529. package/dist/harness/journey.d.ts +43 -1
  530. package/dist/harness/journey.d.ts.map +1 -1
  531. package/dist/harness/journey.js +207 -33
  532. package/dist/harness/journey.js.map +1 -1
  533. package/dist/harness/manifest.d.ts +12 -0
  534. package/dist/harness/manifest.d.ts.map +1 -1
  535. package/dist/harness/manifest.js +73 -45
  536. package/dist/harness/manifest.js.map +1 -1
  537. package/dist/harness/next-step.d.ts +37 -6
  538. package/dist/harness/next-step.d.ts.map +1 -1
  539. package/dist/harness/next-step.js +34 -174
  540. package/dist/harness/next-step.js.map +1 -1
  541. package/dist/harness/parse.d.ts +25 -0
  542. package/dist/harness/parse.d.ts.map +1 -1
  543. package/dist/harness/parse.js +38 -13
  544. package/dist/harness/parse.js.map +1 -1
  545. package/dist/harness/provenance.d.ts +29 -0
  546. package/dist/harness/provenance.d.ts.map +1 -1
  547. package/dist/harness/provenance.js +109 -9
  548. package/dist/harness/provenance.js.map +1 -1
  549. package/dist/harness/script-check.d.ts.map +1 -1
  550. package/dist/harness/script-check.js +29 -6
  551. package/dist/harness/script-check.js.map +1 -1
  552. package/dist/harness/sensors.d.ts +14 -3
  553. package/dist/harness/sensors.d.ts.map +1 -1
  554. package/dist/harness/sensors.js +64 -44
  555. package/dist/harness/sensors.js.map +1 -1
  556. package/dist/harness/triage-signals.d.ts +20 -0
  557. package/dist/harness/triage-signals.d.ts.map +1 -0
  558. package/dist/harness/triage-signals.js +30 -0
  559. package/dist/harness/triage-signals.js.map +1 -0
  560. package/dist/harness/triage-unit.d.ts +23 -0
  561. package/dist/harness/triage-unit.d.ts.map +1 -0
  562. package/dist/harness/triage-unit.js +142 -0
  563. package/dist/harness/triage-unit.js.map +1 -0
  564. package/dist/harness/triage.d.ts +28 -0
  565. package/dist/harness/triage.d.ts.map +1 -0
  566. package/dist/harness/triage.js +99 -0
  567. package/dist/harness/triage.js.map +1 -0
  568. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  569. package/dist/harness/viewpoint-ledger.js +2 -1
  570. package/dist/harness/viewpoint-ledger.js.map +1 -1
  571. package/dist/hooks/bash-write-targets.d.ts +15 -0
  572. package/dist/hooks/bash-write-targets.d.ts.map +1 -0
  573. package/dist/hooks/bash-write-targets.js +173 -0
  574. package/dist/hooks/bash-write-targets.js.map +1 -0
  575. package/dist/hooks/claude-hook-entry.d.ts +11 -0
  576. package/dist/hooks/claude-hook-entry.d.ts.map +1 -0
  577. package/dist/hooks/claude-hook-entry.js +137 -0
  578. package/dist/hooks/claude-hook-entry.js.map +1 -0
  579. package/dist/hooks/claude-transcript-turn.d.ts +11 -0
  580. package/dist/hooks/claude-transcript-turn.d.ts.map +1 -0
  581. package/dist/hooks/claude-transcript-turn.js +143 -0
  582. package/dist/hooks/claude-transcript-turn.js.map +1 -0
  583. package/dist/hooks/guard-delivery-contract-rule.d.ts +10 -0
  584. package/dist/hooks/guard-delivery-contract-rule.d.ts.map +1 -0
  585. package/dist/hooks/guard-delivery-contract-rule.js +152 -0
  586. package/dist/hooks/guard-delivery-contract-rule.js.map +1 -0
  587. package/dist/hooks/guard-protected-paths.d.ts +9 -0
  588. package/dist/hooks/guard-protected-paths.d.ts.map +1 -0
  589. package/dist/hooks/guard-protected-paths.js +107 -0
  590. package/dist/hooks/guard-protected-paths.js.map +1 -0
  591. package/dist/hooks/guard-rules.d.ts +37 -0
  592. package/dist/hooks/guard-rules.d.ts.map +1 -0
  593. package/dist/hooks/guard-rules.js +61 -0
  594. package/dist/hooks/guard-rules.js.map +1 -0
  595. package/dist/hooks/guard-tty-spoof-rule.d.ts +15 -0
  596. package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -0
  597. package/dist/hooks/guard-tty-spoof-rule.js +21 -0
  598. package/dist/hooks/guard-tty-spoof-rule.js.map +1 -0
  599. package/dist/hooks/hand-back-core.d.ts +39 -0
  600. package/dist/hooks/hand-back-core.d.ts.map +1 -0
  601. package/dist/hooks/hand-back-core.js +122 -0
  602. package/dist/hooks/hand-back-core.js.map +1 -0
  603. package/dist/hooks/hook-cli-command.d.ts +9 -0
  604. package/dist/hooks/hook-cli-command.d.ts.map +1 -0
  605. package/dist/hooks/hook-cli-command.js +46 -0
  606. package/dist/hooks/hook-cli-command.js.map +1 -0
  607. package/dist/hooks/hook-registry.d.ts +10 -0
  608. package/dist/hooks/hook-registry.d.ts.map +1 -0
  609. package/dist/hooks/hook-registry.js +24 -0
  610. package/dist/hooks/hook-registry.js.map +1 -0
  611. package/dist/hooks/hook-result-contract.d.ts +50 -0
  612. package/dist/hooks/hook-result-contract.d.ts.map +1 -0
  613. package/dist/hooks/hook-result-contract.js +80 -0
  614. package/dist/hooks/hook-result-contract.js.map +1 -0
  615. package/dist/hooks/hook-toggles.d.ts +10 -0
  616. package/dist/hooks/hook-toggles.d.ts.map +1 -0
  617. package/dist/hooks/hook-toggles.js +107 -0
  618. package/dist/hooks/hook-toggles.js.map +1 -0
  619. package/dist/hooks/pre-tool-guard-hook.d.ts +10 -0
  620. package/dist/hooks/pre-tool-guard-hook.d.ts.map +1 -0
  621. package/dist/hooks/pre-tool-guard-hook.js +105 -0
  622. package/dist/hooks/pre-tool-guard-hook.js.map +1 -0
  623. package/dist/hooks/session-start-unit-state-hook.d.ts +13 -0
  624. package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -0
  625. package/dist/hooks/session-start-unit-state-hook.js +57 -0
  626. package/dist/hooks/session-start-unit-state-hook.js.map +1 -0
  627. package/dist/hooks/stop-next-step-hook.d.ts +16 -0
  628. package/dist/hooks/stop-next-step-hook.d.ts.map +1 -0
  629. package/dist/hooks/stop-next-step-hook.js +42 -0
  630. package/dist/hooks/stop-next-step-hook.js.map +1 -0
  631. package/dist/hooks/sungen-project-root.d.ts +19 -0
  632. package/dist/hooks/sungen-project-root.d.ts.map +1 -0
  633. package/dist/hooks/sungen-project-root.js +130 -0
  634. package/dist/hooks/sungen-project-root.js.map +1 -0
  635. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts +15 -0
  636. package/dist/orchestrator/ai-skills/command-partial-includes.d.ts.map +1 -0
  637. package/dist/orchestrator/ai-skills/command-partial-includes.js +106 -0
  638. package/dist/orchestrator/ai-skills/command-partial-includes.js.map +1 -0
  639. package/dist/orchestrator/ai-skills/commands.d.ts +5 -1
  640. package/dist/orchestrator/ai-skills/commands.d.ts.map +1 -1
  641. package/dist/orchestrator/ai-skills/commands.js +16 -6
  642. package/dist/orchestrator/ai-skills/commands.js.map +1 -1
  643. package/dist/orchestrator/ai-skills/golden-skills.test.js +29 -0
  644. package/dist/orchestrator/ai-skills/golden-skills.test.js.map +1 -1
  645. package/dist/orchestrator/assets-drift.d.ts +5 -0
  646. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  647. package/dist/orchestrator/assets-drift.js +12 -3
  648. package/dist/orchestrator/assets-drift.js.map +1 -1
  649. package/dist/orchestrator/claude-hooks-install.d.ts +27 -0
  650. package/dist/orchestrator/claude-hooks-install.d.ts.map +1 -0
  651. package/dist/orchestrator/claude-hooks-install.js +203 -0
  652. package/dist/orchestrator/claude-hooks-install.js.map +1 -0
  653. package/dist/orchestrator/lockstep-version.d.ts +15 -5
  654. package/dist/orchestrator/lockstep-version.d.ts.map +1 -1
  655. package/dist/orchestrator/lockstep-version.js +30 -17
  656. package/dist/orchestrator/lockstep-version.js.map +1 -1
  657. package/dist/orchestrator/project-initializer.d.ts +6 -0
  658. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  659. package/dist/orchestrator/project-initializer.js +24 -0
  660. package/dist/orchestrator/project-initializer.js.map +1 -1
  661. package/dist/orchestrator/screen-manager.d.ts.map +1 -1
  662. package/dist/orchestrator/screen-manager.js +4 -2
  663. package/dist/orchestrator/screen-manager.js.map +1 -1
  664. package/dist/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  665. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  666. package/dist/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  667. package/dist/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  668. package/dist/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  669. package/dist/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  670. package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  671. package/dist/orchestrator/templates/ai-src/commands/design.md +2 -0
  672. package/dist/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  673. package/dist/orchestrator/templates/ai-src/commands/locale.md +2 -0
  674. package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
  675. package/dist/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  676. package/dist/orchestrator/templates/ai-src/config/claude.md +20 -7
  677. package/dist/orchestrator/templates/ai-src/config/copilot.md +20 -7
  678. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  679. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  680. package/dist/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  681. package/dist/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  682. package/dist/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  683. package/dist/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  684. package/dist/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  685. package/dist/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  686. package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  687. package/dist/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  688. package/dist/utils/safe-yaml-parse.d.ts +8 -0
  689. package/dist/utils/safe-yaml-parse.d.ts.map +1 -0
  690. package/dist/utils/safe-yaml-parse.js +51 -0
  691. package/dist/utils/safe-yaml-parse.js.map +1 -0
  692. package/package.json +3 -3
  693. package/src/basis/anchor-grammar.ts +83 -0
  694. package/src/basis/anchor-hash.ts +27 -0
  695. package/src/basis/bm51-tables.ts +65 -0
  696. package/src/basis/extract-spec-anchors.ts +95 -0
  697. package/src/basis/migration-sentinel.ts +175 -0
  698. package/src/basis/spec-frontmatter.ts +68 -0
  699. package/src/basis/spec-sections.ts +35 -0
  700. package/src/basis/test-basis-schema.ts +81 -0
  701. package/src/capabilities/discover.ts +15 -2
  702. package/src/capabilities/registry.ts +16 -0
  703. package/src/cli/commands/audit.ts +10 -5
  704. package/src/cli/commands/capability.ts +4 -2
  705. package/src/cli/commands/contract-derive-command.ts +61 -0
  706. package/src/cli/commands/contract.ts +130 -0
  707. package/src/cli/commands/defect.ts +49 -0
  708. package/src/cli/commands/delivery.ts +92 -15
  709. package/src/cli/commands/generate.ts +3 -1
  710. package/src/cli/commands/journey.ts +41 -16
  711. package/src/cli/commands/next.ts +64 -10
  712. package/src/cli/commands/triage.ts +57 -0
  713. package/src/cli/commands/update.ts +35 -8
  714. package/src/cli/index.ts +24 -30
  715. package/src/cli/project-sungen-invocation.ts +39 -0
  716. package/src/contract/approve-contract.ts +94 -0
  717. package/src/contract/assertion-matcher-vocabulary.ts +93 -0
  718. package/src/contract/build-contract-verdict.ts +108 -0
  719. package/src/contract/build-trace-conformance.ts +100 -0
  720. package/src/contract/classify-contract-change.ts +92 -0
  721. package/src/contract/classify-contract-unit.ts +47 -0
  722. package/src/contract/classify-trace-conformance.ts +116 -0
  723. package/src/contract/contract-git.ts +106 -0
  724. package/src/contract/contract-hash.ts +34 -0
  725. package/src/contract/contract-report-file.ts +25 -0
  726. package/src/contract/contract-schema.ts +137 -0
  727. package/src/contract/contract-units.ts +52 -0
  728. package/src/contract/contracts-lock-file.ts +97 -0
  729. package/src/contract/data-normalize.ts +66 -0
  730. package/src/contract/derive-free-feature.ts +120 -0
  731. package/src/contract/field-semantic-redaction.ts +80 -0
  732. package/src/contract/free-feature-blocks.ts +56 -0
  733. package/src/contract/lock-secret-guard.ts +95 -0
  734. package/src/contract/lock-vs-git-head.ts +38 -0
  735. package/src/contract/normalize-contract-step.ts +74 -0
  736. package/src/contract/normalize-feature-steps.ts +93 -0
  737. package/src/contract/oracle-strength.ts +80 -0
  738. package/src/contract/project-contract-blockers.ts +36 -0
  739. package/src/contract/record-contract-approval.ts +70 -0
  740. package/src/contract/render-free-gherkin.ts +113 -0
  741. package/src/contract/render-trace-sentence.ts +98 -0
  742. package/src/contract/render-trace-target.ts +68 -0
  743. package/src/contract/resolve-unit-trace-identities.ts +35 -0
  744. package/src/contract/trace/collect-trace-evidence.ts +109 -0
  745. package/src/contract/trace/identity-cache.ts +61 -0
  746. package/src/contract/trace/select-final-attempt.ts +70 -0
  747. package/src/contract/trace/snapshot-html-renderer.ts +136 -0
  748. package/src/contract/trace/snapshot-resolver.ts +66 -0
  749. package/src/contract/trace/snapshot-store.ts +151 -0
  750. package/src/contract/trace/target-identity.ts +104 -0
  751. package/src/contract/trace/test-step-join.ts +104 -0
  752. package/src/contract/trace/trace-binding.ts +56 -0
  753. package/src/contract/trace/trace-file-reader.ts +133 -0
  754. package/src/contract/trace/trace-fingerprint.ts +68 -0
  755. package/src/contract/trace/trace-identity-resolution.ts +74 -0
  756. package/src/contract/trace/trace-run-record.ts +80 -0
  757. package/src/contract/trace/trace-steps.ts +88 -0
  758. package/src/contract/trace/trace-zip-limits.ts +77 -0
  759. package/src/contract/trace/trace-zip-reader.ts +127 -0
  760. package/src/contract/verify-approval-decisions.ts +60 -0
  761. package/src/decisions/append-decision.ts +35 -0
  762. package/src/decisions/confirmed-decision-commands.ts +149 -0
  763. package/src/decisions/decision-file.ts +93 -0
  764. package/src/decisions/decision-identity.ts +73 -0
  765. package/src/decisions/decision-integrity-check.ts +61 -0
  766. package/src/decisions/decision-schema.ts +76 -0
  767. package/src/decisions/decision-source.ts +14 -0
  768. package/src/decisions/exclusive-file-create.ts +42 -0
  769. package/src/decisions/git-head-trust.ts +32 -0
  770. package/src/decisions/human-confirmation.ts +119 -0
  771. package/src/decisions/legacy-waiver-migration.ts +135 -0
  772. package/src/decisions/read-decisions.ts +61 -0
  773. package/src/decisions/viewpoint-baseline-adapter.ts +74 -0
  774. package/src/decisions/waiver-decisions.ts +56 -0
  775. package/src/exporters/csv-exporter.ts +5 -1
  776. package/src/exporters/feature-parser.ts +12 -0
  777. package/src/exporters/matrix/build.ts +62 -18
  778. package/src/exporters/matrix/carry-manual-results.ts +70 -7
  779. package/src/exporters/matrix/export.ts +17 -2
  780. package/src/exporters/matrix/gates.ts +62 -129
  781. package/src/exporters/matrix/render-csv.ts +4 -1
  782. package/src/exporters/matrix/render-gate-overrides-sheet.ts +50 -0
  783. package/src/exporters/matrix/render-xlsx.ts +6 -0
  784. package/src/exporters/matrix/types.ts +9 -1
  785. package/src/exporters/matrix/xlsx-cells.ts +1 -1
  786. package/src/exporters/playwright-report-parser.ts +1 -0
  787. package/src/exporters/scenario-merger.ts +2 -1
  788. package/src/exporters/types.ts +5 -0
  789. package/src/generators/test-generator/code-generator.ts +13 -0
  790. package/src/graph/evaluate-graph.ts +66 -0
  791. package/src/graph/locate-finding.ts +93 -0
  792. package/src/graph/node-decl.ts +72 -0
  793. package/src/graph/nodes/core-node-catalog.ts +15 -0
  794. package/src/graph/nodes/test-case-contract-nodes.ts +74 -0
  795. package/src/graph/nodes/test-case-nodes.ts +68 -0
  796. package/src/graph/nodes/unit-audit-nodes.ts +95 -0
  797. package/src/graph/nodes/unit-contract-node.ts +89 -0
  798. package/src/graph/nodes/unit-design-nodes.ts +89 -0
  799. package/src/graph/nodes/unit-execution-nodes.ts +77 -0
  800. package/src/graph/test-case-identity.ts +75 -0
  801. package/src/graph/test-case-results.ts +90 -0
  802. package/src/graph/test-case-satisfied.ts +55 -0
  803. package/src/graph/test-case-state-shape.ts +62 -0
  804. package/src/graph/test-case-states.ts +84 -0
  805. package/src/graph/unit-artifact-probes.ts +77 -0
  806. package/src/graph/unit-state-facts.ts +112 -0
  807. package/src/harness/audit.ts +46 -11
  808. package/src/harness/catalog/gate-rules.yaml +647 -0
  809. package/src/harness/counted-assertions.ts +33 -0
  810. package/src/harness/defect-draft.ts +115 -0
  811. package/src/harness/defects.ts +94 -0
  812. package/src/harness/gates/audit-gate-terms.ts +80 -0
  813. package/src/harness/gates/audit-gate-verdict.ts +78 -0
  814. package/src/harness/gates/audit-input-hash.ts +55 -0
  815. package/src/harness/gates/audit-report-verification.ts +201 -0
  816. package/src/harness/gates/decisions-hash.ts +42 -0
  817. package/src/harness/gates/delivery-checklist.ts +120 -0
  818. package/src/harness/gates/delivery-decision-gate.ts +139 -0
  819. package/src/harness/gates/delivery-decision-step.ts +89 -0
  820. package/src/harness/gates/gate-override-report.ts +114 -0
  821. package/src/harness/gates/gate-override-scope.ts +66 -0
  822. package/src/harness/gates/gate-override-validation.ts +75 -0
  823. package/src/harness/gates/gate-rule-catalog.ts +82 -0
  824. package/src/harness/gates/gate-terms.ts +59 -0
  825. package/src/harness/gates/in-run-decision-check.ts +99 -0
  826. package/src/harness/gates/journey-gate-inputs.ts +89 -0
  827. package/src/harness/gates/migrated-waiver-review.ts +68 -0
  828. package/src/harness/gates/resolve-rule.ts +94 -0
  829. package/src/harness/gates/unit-gate-overrides.ts +99 -0
  830. package/src/harness/journey.ts +215 -38
  831. package/src/harness/manifest.ts +69 -45
  832. package/src/harness/next-step.ts +60 -170
  833. package/src/harness/parse.ts +40 -13
  834. package/src/harness/provenance.ts +99 -11
  835. package/src/harness/script-check.ts +27 -6
  836. package/src/harness/sensors.ts +73 -47
  837. package/src/harness/triage-signals.ts +46 -0
  838. package/src/harness/triage-unit.ts +113 -0
  839. package/src/harness/triage.ts +127 -0
  840. package/src/harness/viewpoint-ledger.ts +2 -2
  841. package/src/hooks/bash-write-targets.ts +109 -0
  842. package/src/hooks/claude-hook-entry.ts +85 -0
  843. package/src/hooks/claude-transcript-turn.ts +96 -0
  844. package/src/hooks/guard-delivery-contract-rule.ts +110 -0
  845. package/src/hooks/guard-protected-paths.ts +71 -0
  846. package/src/hooks/guard-rules.ts +98 -0
  847. package/src/hooks/guard-tty-spoof-rule.ts +31 -0
  848. package/src/hooks/hand-back-core.ts +112 -0
  849. package/src/hooks/hook-cli-command.ts +17 -0
  850. package/src/hooks/hook-registry.ts +24 -0
  851. package/src/hooks/hook-result-contract.ts +114 -0
  852. package/src/hooks/hook-toggles.ts +66 -0
  853. package/src/hooks/pre-tool-guard-hook.ts +67 -0
  854. package/src/hooks/session-start-unit-state-hook.ts +56 -0
  855. package/src/hooks/stop-next-step-hook.ts +37 -0
  856. package/src/hooks/sungen-project-root.ts +80 -0
  857. package/src/orchestrator/ai-skills/command-partial-includes.ts +72 -0
  858. package/src/orchestrator/ai-skills/commands.ts +22 -8
  859. package/src/orchestrator/ai-skills/golden-skills.test.ts +23 -0
  860. package/src/orchestrator/assets-drift.ts +12 -5
  861. package/src/orchestrator/claude-hooks-install.ts +168 -0
  862. package/src/orchestrator/lockstep-version.ts +28 -15
  863. package/src/orchestrator/project-initializer.ts +22 -0
  864. package/src/orchestrator/screen-manager.ts +3 -1
  865. package/src/orchestrator/templates/ai-src/commands/add-api.md +2 -0
  866. package/src/orchestrator/templates/ai-src/commands/add-flow.md +2 -0
  867. package/src/orchestrator/templates/ai-src/commands/add-screen.md +2 -0
  868. package/src/orchestrator/templates/ai-src/commands/create-data-test.md +1 -0
  869. package/src/orchestrator/templates/ai-src/commands/create-test.md +14 -16
  870. package/src/orchestrator/templates/ai-src/commands/dashboard.md +2 -0
  871. package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  872. package/src/orchestrator/templates/ai-src/commands/design.md +2 -0
  873. package/src/orchestrator/templates/ai-src/commands/feedback.md +2 -0
  874. package/src/orchestrator/templates/ai-src/commands/locale.md +2 -0
  875. package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
  876. package/src/orchestrator/templates/ai-src/commands/run-test.md +14 -10
  877. package/src/orchestrator/templates/ai-src/config/claude.md +20 -7
  878. package/src/orchestrator/templates/ai-src/config/copilot.md +20 -7
  879. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.claude.md +20 -0
  880. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.codex.md +20 -0
  881. package/src/orchestrator/templates/ai-src/partials/hand-back-rule.copilot.md +20 -0
  882. package/src/orchestrator/templates/ai-src/skills/sungen-api-coverage-model/SKILL.md +1 -1
  883. package/src/orchestrator/templates/ai-src/skills/sungen-capture-mobile/SKILL.md +3 -3
  884. package/src/orchestrator/templates/ai-src/skills/sungen-data-factory/SKILL.md +9 -0
  885. package/src/orchestrator/templates/ai-src/skills/sungen-error-mapping/SKILL.md +2 -0
  886. package/src/orchestrator/templates/ai-src/skills/sungen-gherkin-syntax/SKILL.md +1 -1
  887. package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +2 -0
  888. package/src/orchestrator/templates/claude-hooks/sungen-hook.cjs +64 -0
  889. package/src/utils/safe-yaml-parse.ts +44 -0
@@ -17,8 +17,17 @@ import * as path from 'path';
17
17
  import * as crypto from 'crypto';
18
18
  import { reportSlug } from './unit-paths';
19
19
  import { readTextFile } from './read-text';
20
-
21
- export type ObStatus = 'satisfied' | 'needs-work' | 'pending' | 'waived';
20
+ import { assertNoPendingMigration } from '../basis/migration-sentinel';
21
+ import { commitWaiverSync, planWaiverSync, recordWaiver, untrustedWaiverText } from '../decisions/legacy-waiver-migration';
22
+ import { DecisionConflictError } from '../decisions/append-decision';
23
+ import { gitUserName } from '../decisions/decision-source';
24
+ import { resolveRule } from './gates/resolve-rule';
25
+ import { applyAuditOverrides, decisionFindingText, DecisionGateFinding, ignoredOverrideText, journeyDecisionFindings, OBLIGATION_RULE, readJourneyAudit, unitOverrides } from './gates/journey-gate-inputs';
26
+ import { IN_RUN_RULE, uncommittedReleaseDecisions } from './gates/in-run-decision-check';
27
+ import { PROJECT_SCOPE } from '../decisions/decision-file';
28
+
29
+ /** `overridden`: the audit recorded a gate-override on the obligation's rule (OES-11.2) — accepted like a waiver. */
30
+ export type ObStatus = 'satisfied' | 'needs-work' | 'pending' | 'waived' | 'overridden';
22
31
 
23
32
  export interface Obligation {
24
33
  id: string;
@@ -26,6 +35,7 @@ export interface Obligation {
26
35
  status: ObStatus;
27
36
  detail: string;
28
37
  waivedReason?: string; // S2 — set when the QA explicitly waived this obligation
38
+ overriddenBy?: string; // P0 — the gate-override decision the audit applied to this obligation's rule
29
39
  }
30
40
 
31
41
  /** S5 — a parsed anchor so an IDE can jump straight to what needs review. */
@@ -42,6 +52,10 @@ export interface JourneyReport {
42
52
  obligations: Obligation[];
43
53
  needsYou: ReviewItem[]; // S5 — the review queue: human-judgment findings, each with an anchor
44
54
  nextSuggested: string;
55
+ /** T3 — set when an audit report exists but does not count (stale or untrusted). */
56
+ auditNotCounted?: string;
57
+ /** Decision files that do not verify, edited committed entries, rejected overrides — hard, block the gate. */
58
+ decisionFindings?: DecisionGateFinding[];
45
59
  }
46
60
 
47
61
  function readJSON(p: string): any {
@@ -72,9 +86,33 @@ function extractAnchor(text: string): Anchor {
72
86
 
73
87
  const SAT = 0.8; // axis at/above this = satisfied (below = needs-work)
74
88
 
89
+ /**
90
+ * OB-coverage IS the audit's viewpoint gate (#934): the registry maps it to `audit.viewpoint-coverage`,
91
+ * whose condition is "no critical theme missing or shallow" (audit-gate-terms.ts). The coverage
92
+ * percentage alone can read 83% with a critical theme missing, so a gap the rule blocks on keeps the
93
+ * obligation open and names the themes. An override the audit applied is credited later by
94
+ * applyAuditOverrides — journey never re-applies one, so the rule is resolved from the catalog here.
95
+ */
96
+ function coverageObligation(coverage: number | undefined, audit: any): Obligation {
97
+ const id = 'OB-coverage';
98
+ const title = 'Viewpoint coverage';
99
+ const pct = coverage === undefined ? '' : `${Math.round(coverage * 100)}% (need ${Math.round(SAT * 100)}%) — `;
100
+ const gaps: Array<{ theme?: unknown; status?: unknown }> = Array.isArray(audit.gate?.gaps) ? audit.gate.gaps : [];
101
+ if (gaps.length && resolveRule(OBLIGATION_RULE[id]).blocking) {
102
+ const themes = gaps.map((g) => `${String(g.theme)} (${g.status === 'shallow' ? 'shallow' : 'missing'})`).join(', ');
103
+ return { id, title, status: 'needs-work', detail: `${pct}critical theme(s) not covered: ${themes} — the audit's viewpoint gate fails on them` };
104
+ }
105
+ const status: ObStatus = coverage === undefined ? 'pending' : coverage >= SAT ? 'satisfied' : 'needs-work';
106
+ return { id, title, status, detail: `${pct}critical themes covered` };
107
+ }
108
+
75
109
  function computeFresh(projectRoot: string, unit: string): JourneyReport {
76
110
  const slug = reportSlug(unit);
77
- const audit = readJSON(path.join(projectRoot, '.sungen', 'reports', `${slug}-audit.json`));
111
+ // T3: the report is an output — read through the checks; stale or untrusted counts as never audited.
112
+ const read = readJourneyAudit(projectRoot, unit);
113
+ const notCountedReason = read.notCountedReason;
114
+ // The verifier checked the top-level keys and types; nested fields are read defensively below, as before.
115
+ const audit = read.audit as any;
78
116
  const phases = readLedgerPhases(path.join(projectRoot, '.sungen', 'ledger', `${slug}.jsonl`));
79
117
 
80
118
  const from: string[] = [];
@@ -89,10 +127,11 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
89
127
 
90
128
  if (!audit) {
91
129
  // Nothing measured yet — the journey hasn't really begun.
92
- obligations.push({ id: 'OB-create', title: 'Generate test cases', status: 'pending', detail: 'No audit report yet — run /sungen:create-test.' });
130
+ obligations.push({ id: 'OB-create', title: 'Generate test cases', status: 'pending', detail: notCountedReason ?? 'No audit report yet — run /sungen:create-test.' });
93
131
  return {
94
- unit, generatedFrom: from, youAreHere, phasesDone: phases, gateStatus: null, score: null,
95
- obligations, needsYou, nextSuggested: 'Run `/sungen:create-test ' + unit + '` to begin.',
132
+ unit, generatedFrom: from, youAreHere, phasesDone: phases, gateStatus: null, score: null, obligations, needsYou,
133
+ nextSuggested: notCountedReason ?? 'Run `/sungen:create-test ' + unit + '` to begin.',
134
+ ...(notCountedReason ? { auditNotCounted: notCountedReason } : {}),
96
135
  };
97
136
  }
98
137
 
@@ -105,7 +144,7 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
105
144
  });
106
145
 
107
146
  obligations.push(ob('OB-spec', 'Spec readiness', ax.specFR, 1, 'FR/sections sufficient to design from'));
108
- obligations.push(ob('OB-coverage', 'Viewpoint coverage', ax.coverage, SAT, 'critical themes covered'));
147
+ obligations.push(coverageObligation(ax.coverage, audit));
109
148
  obligations.push(ob('OB-depth', 'Assertion depth', ax.businessDepth, depthThreshold, 'business-critical scenarios assert data'));
110
149
  obligations.push(ob('OB-trace', 'Traceability', ax.taxonomy ?? ax.traceability, SAT, 'scenarios trace to viewpoints'));
111
150
 
@@ -116,6 +155,8 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
116
155
  status: autoPending ? 'needs-work' : 'satisfied',
117
156
  detail: autoPending ? `${audit.automatableManual.automatable} @manual scenario(s) a driver could automate` : 'no capability-pending automatable cases',
118
157
  });
158
+ // What the audit already applied — never re-applied here, and only while that override is in force.
159
+ const ignored = applyAuditOverrides(obligations, audit, unitOverrides(projectRoot, unit).inForce);
119
160
 
120
161
  // Needs-you: the review queue. Prefer PRECISE per-scenario anchors from audit's structured
121
162
  // depth data — each shallow business-critical scenario carries its own VP id — over regex-parsing
@@ -128,6 +169,7 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
128
169
  anchor: extractAnchor(s.name),
129
170
  });
130
171
  }
172
+ for (const g of ignored) needsYou.push({ text: ignoredOverrideText(g), anchor: {} });
131
173
  const haveStructuredDepth = shallowBC.length > 0;
132
174
  for (const f of (audit.findings || [])) {
133
175
  if (!isHumanFinding(f)) continue;
@@ -143,7 +185,7 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
143
185
  });
144
186
 
145
187
  // Next suggested = first non-satisfied obligation; if all satisfied but run-test not done → run.
146
- const firstGap = obligations.find((o) => o.status !== 'satisfied' && o.id !== 'OB-signoff');
188
+ const firstGap = obligations.find((o) => o.status !== 'satisfied' && o.status !== 'overridden' && o.id !== 'OB-signoff');
147
189
  let nextSuggested: string;
148
190
  if (firstGap) nextSuggested = `Repair "${firstGap.title}" (${firstGap.detail}).`;
149
191
  else if (!ran('run')) nextSuggested = `Quality satisfied — run \`/sungen:run-test ${unit}\`.`;
@@ -158,9 +200,10 @@ function computeFresh(projectRoot: string, unit: string): JourneyReport {
158
200
 
159
201
  // ---------------- S2: writable lifecycle — persisted waivers + reconcile ----------------
160
202
 
161
- interface Waiver { reason: string; at: string; auditHashAtWaive: string; }
162
- interface Signoff { by?: string; at: string; auditHashAtSignoff: string; } // S5
163
- interface JourneyState { unit: string; auditHash: string; waivers: Record<string, Waiver>; signoff?: Signoff; }
203
+ // Waivers live in the decision layer (DOS-13.5); this file keeps a dual-written copy for one release.
204
+ /** S5 — stays here in P0. `by` is who signs (--by, else the git user); `recordedBy` the git user when --by differs. */
205
+ interface Signoff { by?: string; recordedBy?: string; at: string; auditHashAtSignoff: string; }
206
+ interface JourneyState { unit: string; auditHash: string; waivers: Record<string, unknown>; signoff?: Signoff; }
164
207
 
165
208
  function statePath(projectRoot: string, slug: string): string {
166
209
  return path.join(projectRoot, '.sungen', 'journey', `${slug}.state.json`);
@@ -176,9 +219,14 @@ function saveState(p: string, s: JourneyState): void {
176
219
  fs.writeFileSync(p, JSON.stringify(s, null, 2), 'utf-8');
177
220
  }
178
221
 
222
+ /** An obligation that does not block: met, waived by a human, or overridden by the audit's gate-override. */
223
+ const accepted = (s: ObStatus): boolean => s === 'satisfied' || s === 'waived' || s === 'overridden';
224
+
179
225
  /** Recompute nextSuggested AFTER waivers are applied (a waived obligation is not a gap). */
180
226
  function computeNext(r: JourneyReport, unit: string): string {
181
- const gap = r.obligations.find((o) => o.status !== 'satisfied' && o.status !== 'waived' && o.id !== 'OB-signoff');
227
+ const bad = r.decisionFindings?.[0];
228
+ if (bad) return `Resolve ${r.decisionFindings!.length} decision problem(s) first — ${bad.rule} on ${bad.path}.`;
229
+ const gap = r.obligations.find((o) => !accepted(o.status) && o.id !== 'OB-signoff');
182
230
  if (gap) return `Repair "${gap.title}" (${gap.detail}).`;
183
231
  if (!r.phasesDone.some((s) => s === 'run' || s.startsWith('run'))) return `Quality satisfied — run \`/sungen:run-test ${unit}\`.`;
184
232
  return `All obligations satisfied/waived — review the ${r.needsYou.length} queued item(s), then sign off & deliver.`;
@@ -190,17 +238,30 @@ function computeNext(r: JourneyReport, unit: string): string {
190
238
  * - an active waiver (evidence unchanged) sets status='waived' (carries the reason);
191
239
  * - a STALE waiver (audit changed since it was waived) is re-surfaced for re-decision (anti-amnesia).
192
240
  * Then persist the current evidence cursor.
241
+ * Waivers in force come from the decision layer; legacy waivers that match git HEAD are imported once,
242
+ * others are UNTRUSTED (not counted, listed for a human), and the result is dual-written back.
243
+ * A read-only checkout gets the same board without throwing.
193
244
  */
194
245
  export function runJourney(projectRoot: string, unit: string): JourneyReport {
195
246
  const slug = reportSlug(unit);
247
+ assertNoPendingMigration(projectRoot, slug);
196
248
  const report = computeFresh(projectRoot, unit);
197
249
  const sp = statePath(projectRoot, slug);
198
250
  const state = loadState(sp) || { unit, auditHash: '', waivers: {} };
199
251
  const curHash = auditHashOf(projectRoot, slug);
252
+ const sync = planWaiverSync(projectRoot, unit, slug, sp, state.waivers);
253
+ for (const u of sync.untrusted) {
254
+ const title = report.obligations.find((o) => o.id === u.obligation)?.title ?? u.obligation;
255
+ const ignored = unwaivableWhy(u.obligation, unit);
256
+ report.needsYou.unshift({ text: ignored ? ignoredWaiverText(u.obligation, ignored, u.waiver.reason) : untrustedWaiverText(unit, slug, title, u), anchor: { vpId: u.obligation } });
257
+ }
200
258
 
201
259
  for (const ob of report.obligations) {
202
- const w = state.waivers[ob.id];
260
+ const w = sync.waivers[ob.id];
203
261
  if (!w) continue;
262
+ // A waiver recorded before `--waive` refused this obligation never opens it (review W1).
263
+ const ignored = unwaivableWhy(ob.id, unit);
264
+ if (ignored) { report.needsYou.unshift({ text: ignoredWaiverText(ob.id, ignored, w.reason), anchor: { vpId: ob.id } }); continue; }
204
265
  if (w.auditHashAtWaive === curHash) {
205
266
  ob.status = 'waived';
206
267
  ob.waivedReason = w.reason;
@@ -215,16 +276,65 @@ export function runJourney(projectRoot: string, unit: string): JourneyReport {
215
276
  if (signoffOb && state.signoff) {
216
277
  if (state.signoff.auditHashAtSignoff === curHash) {
217
278
  signoffOb.status = 'satisfied';
218
- signoffOb.detail = `signed off${state.signoff.by ? ' by ' + state.signoff.by : ''} at ${state.signoff.at}`;
279
+ signoffOb.detail = `signed off${state.signoff.by ? ' by ' + state.signoff.by : ''}${state.signoff.recordedBy ? ` (recorded by ${state.signoff.recordedBy})` : ''} at ${state.signoff.at}`;
219
280
  } else {
220
281
  report.needsYou.unshift({ text: `⚠️ Sign-off is STALE (suite changed since ${state.signoff.at}) — re-review and sign off again.`, anchor: { vpId: 'OB-signoff' } });
221
282
  }
222
283
  }
284
+ // Phase-03 carry-over: a decision that does not verify is a FINDING the gate blocks on, not a crash.
285
+ const decisionFindings = journeyDecisionFindings(projectRoot, unitOverrides(projectRoot, unit));
286
+ const next: JourneyState = { unit, auditHash: curHash, waivers: sync.stateWaivers, signoff: state.signoff };
287
+ try {
288
+ commitWaiverSync(projectRoot, unit, slug, sync, sp, JSON.stringify(next, null, 2));
289
+ } catch (err) {
290
+ if (!(err instanceof DecisionConflictError)) throw err;
291
+ const rel = path.relative(projectRoot, err.path).split(path.sep).join('/');
292
+ if (!decisionFindings.some((f) => f.path === rel)) decisionFindings.push({ rule: 'decision.mutated', path: rel, message: err.message });
293
+ }
294
+ if (decisionFindings.length) {
295
+ report.decisionFindings = decisionFindings;
296
+ for (const f of [...decisionFindings].reverse()) report.needsYou.unshift({ text: decisionFindingText(f), anchor: { file: f.path } });
297
+ }
223
298
  report.nextSuggested = computeNext(report, unit);
224
- saveState(sp, { unit, auditHash: curHash, waivers: state.waivers, signoff: state.signoff });
225
299
  return report;
226
300
  }
227
301
 
302
+ /** The single human gate (DOS §3.4, S5): given with `--signoff`, never waived (#936). */
303
+ export const SIGNOFF_OBLIGATION = 'OB-signoff';
304
+ export const signoffCommand = (unit: string): string => `sungen journey --screen ${unit} --signoff --by "<name>"`;
305
+
306
+ /** "Never audited" (T3): a unit is measured by `sungen audit`, never waived through (review W2). */
307
+ export const CREATE_OBLIGATION = 'OB-create';
308
+
309
+ /** Why a waiver can never accept `obId` (and what does instead), or null when it can. */
310
+ function unwaivableWhy(obId: string, unit: string): string | null {
311
+ if (obId === SIGNOFF_OBLIGATION) return `sign-off is given with --signoff, never waived (${signoffCommand(unit)})`;
312
+ if (obId === CREATE_OBLIGATION) return `an unaudited unit cannot be waived through — re-run \`sungen audit --screen ${unit}\``;
313
+ return null;
314
+ }
315
+
316
+ /** The review-queue line for a recorded waiver the board does not honour. */
317
+ const ignoredWaiverText = (obId: string, why: string, reason: string): string => `⚠️ waiver on ${obId} ignored: ${why}. Was: ${reason}`;
318
+
319
+ /**
320
+ * Throws unless `obId` is an obligation of the board that a waiver can accept. Refused in every state,
321
+ * each with what does it instead: OB-signoff (before any audit it is not on the board, after one a
322
+ * waiver would let the human gate be waived away) and OB-create (an unaudited unit would pass every
323
+ * gate on a waiver; the audit measures it).
324
+ */
325
+ export function assertWaivable(report: JourneyReport, unit: string, obId: string): void {
326
+ if (obId === SIGNOFF_OBLIGATION) {
327
+ throw new Error(`${SIGNOFF_OBLIGATION} is the human sign-off — it is given, not waived. Once every other obligation is satisfied or waived, a human runs: ${signoffCommand(unit)}`);
328
+ }
329
+ if (obId === CREATE_OBLIGATION) {
330
+ throw new Error(`${CREATE_OBLIGATION} means the unit has no audit that counts — an unaudited unit cannot be waived through. Run: sungen audit --screen ${unit}`);
331
+ }
332
+ const valid = report.obligations.map((o) => o.id).filter((id) => id !== SIGNOFF_OBLIGATION && id !== CREATE_OBLIGATION);
333
+ if (!valid.includes(obId)) {
334
+ throw new Error(`Unknown obligation "${obId}". Valid: ${valid.join(', ') || `none — the unit has no audit that counts; run sungen audit --screen ${unit}`}`);
335
+ }
336
+ }
337
+
228
338
  /**
229
339
  * Waive an obligation — REQUIRES a reason (anti-amnesia: a waiver leaves a recorded "why").
230
340
  * Records the current evidence cursor so reconcile can invalidate it if the audit changes.
@@ -234,16 +344,11 @@ export function waive(projectRoot: string, unit: string, obId: string, reason: s
234
344
  throw new Error('A reason is required to waive (anti-amnesia: a waiver must record WHY). Use --reason "...".');
235
345
  }
236
346
  const slug = reportSlug(unit);
237
- const fresh = computeFresh(projectRoot, unit);
238
- const valid = fresh.obligations.map((o) => o.id);
239
- if (!valid.includes(obId)) {
240
- throw new Error(`Unknown obligation "${obId}". Valid: ${valid.join(', ')}`);
241
- }
242
- const sp = statePath(projectRoot, slug);
243
- const state = loadState(sp) || { unit, auditHash: '', waivers: {} };
244
- state.waivers[obId] = { reason: reason.trim(), at: new Date().toISOString(), auditHashAtWaive: auditHashOf(projectRoot, slug) };
245
- saveState(sp, state);
246
- return runJourney(projectRoot, unit);
347
+ const fresh = runJourney(projectRoot, unit); // stops on a pending migration; imports legacy waivers first
348
+ assertWaivable(fresh, unit, obId);
349
+ const given = { reason: reason.trim(), at: new Date().toISOString(), auditHashAtWaive: auditHashOf(projectRoot, slug) };
350
+ recordWaiver(projectRoot, unit, obId, given); // DOS-13.5: the decision layer is the record …
351
+ return runJourney(projectRoot, unit); // … and runJourney dual-writes it to the legacy file
247
352
  }
248
353
 
249
354
  /**
@@ -251,21 +356,57 @@ export function waive(projectRoot: string, unit: string, obId: string, reason: s
251
356
  * obligation is satisfied or waived (you cannot sign off an unclean suite). Records who/when +
252
357
  * the evidence cursor; reconcile invalidates it (stale → re-review) if the suite later changes.
253
358
  */
254
- export function signoff(projectRoot: string, unit: string, by?: string): JourneyReport {
255
- const before = runJourney(projectRoot, unit);
256
- const blockers = before.obligations.filter((o) => o.id !== 'OB-signoff' && o.status !== 'satisfied' && o.status !== 'waived');
359
+ /** Throws unless the board may be signed off: no decision problem, every other obligation accepted. */
360
+ export function assertCanSignOff(before: JourneyReport): void {
361
+ const blockers = before.obligations.filter((o) => o.id !== 'OB-signoff' && !accepted(o.status));
362
+ if (before.decisionFindings?.length) {
363
+ throw new Error(`Cannot sign off — ${before.decisionFindings.length} decision problem(s): ${before.decisionFindings.map((f) => `${f.rule} ${f.path}`).join(', ')}.`);
364
+ }
257
365
  if (blockers.length) {
258
366
  throw new Error(`Cannot sign off — still open: ${blockers.map((b) => b.id).join(', ')}. Fix, or waive each with a reason, first.`);
259
367
  }
368
+ }
369
+
370
+ /** Who signs off: `--by`, else the git user; throws when neither names anyone (never `by: unknown`). */
371
+ export function signoffSigner(projectRoot: string, unit: string, by?: string): { signer: string; gitUser: string } {
372
+ const gitUser = gitUserName(projectRoot);
373
+ const signer = by?.trim() || gitUser;
374
+ if (signer === 'unknown') {
375
+ throw new Error(`Cannot sign off — no git user.name is set and no --by was given, so the sign-off would name nobody. Say who signs: ${signoffCommand(unit)}`);
376
+ }
377
+ return { signer, gitUser };
378
+ }
379
+
380
+ export function signoff(projectRoot: string, unit: string, by?: string): JourneyReport {
381
+ // Attribution is not self-declared (review item 4): the git user is always on the record.
382
+ const { signer, gitUser } = signoffSigner(projectRoot, unit, by);
383
+ assertCanSignOff(runJourney(projectRoot, unit));
260
384
  const slug = reportSlug(unit);
261
385
  const sp = statePath(projectRoot, slug);
262
386
  const state = loadState(sp) || { unit, auditHash: '', waivers: {} };
263
- state.signoff = { by, at: new Date().toISOString(), auditHashAtSignoff: auditHashOf(projectRoot, slug) };
387
+ state.signoff = { by: signer, ...(signer !== gitUser ? { recordedBy: gitUser } : {}), at: new Date().toISOString(), auditHashAtSignoff: auditHashOf(projectRoot, slug) };
264
388
  saveState(sp, state);
265
389
  return runJourney(projectRoot, unit);
266
390
  }
267
391
 
268
- const ICON: Record<ObStatus, string> = { satisfied: '✅', 'needs-work': '⚠️ ', pending: '⏳', waived: '🚫' };
392
+ const UNWRITABLE = new Set(['EACCES', 'EROFS', 'ENOSPC', 'EPERM']);
393
+
394
+ /**
395
+ * Write a DERIVED journey file (board, report, roll-up). Best-effort by contract (DOS-13.3): a read-only
396
+ * or full checkout still shows the board — the file is skipped and null returned; any other error throws.
397
+ */
398
+ export function writeJourneyFileBestEffort(file: string, text: string): string | null {
399
+ try {
400
+ fs.mkdirSync(path.dirname(file), { recursive: true });
401
+ fs.writeFileSync(file, text, 'utf-8');
402
+ return file;
403
+ } catch (err) {
404
+ if (UNWRITABLE.has((err as NodeJS.ErrnoException)?.code ?? '')) return null;
405
+ throw err;
406
+ }
407
+ }
408
+
409
+ const ICON: Record<ObStatus, string> = { satisfied: '✅', 'needs-work': '⚠️ ', pending: '⏳', waived: '🚫', overridden: '🔓' };
269
410
 
270
411
  export function renderJourneyBoard(r: JourneyReport): string {
271
412
  const L: string[] = [];
@@ -308,6 +449,10 @@ export interface GateVerdict {
308
449
  required: string[];
309
450
  blockers: { id: string; title: string; detail: string }[];
310
451
  waivedCredit: { id: string; title: string }[]; // required obligations accepted via an explicit waiver
452
+ /** Required obligations accepted because the audit applied a gate-override to their rule. */
453
+ overriddenCredit?: { id: string; title: string; by: string }[];
454
+ /** The phase rule itself was lowered by this gate-override: the open obligations do not halt. */
455
+ phaseOverriddenBy?: string;
311
456
  }
312
457
 
313
458
  const PHASE_REQUIRED: Record<GatePhase, string[]> = {
@@ -319,25 +464,57 @@ const PHASE_REQUIRED: Record<GatePhase, string[]> = {
319
464
  deliver: ['OB-spec', 'OB-coverage', 'OB-depth', 'OB-trace', 'OB-automation', 'OB-signoff'],
320
465
  };
321
466
 
467
+ /** The catalog rule each phase boundary halts by (OES-11.2): soft, so a reasoned override may lower it. */
468
+ const PHASE_RULE: Record<GatePhase, string> = { create: 'journey.phase-create', run: 'journey.phase-run', deliver: 'journey.phase-deliver' };
469
+
322
470
  export function runGate(projectRoot: string, unit: string, phase: GatePhase): GateVerdict {
323
471
  const r = runJourney(projectRoot, unit);
324
472
  const required = PHASE_REQUIRED[phase];
325
- const reqObs = r.obligations.filter((o) => required.includes(o.id));
326
- const blockers = reqObs
327
- .filter((o) => o.status !== 'satisfied' && o.status !== 'waived')
328
- .map((o) => ({ id: o.id, title: o.title, detail: o.detail }));
473
+ // T3: a unit never audited (or whose report does not count) is never clean — OB-create blocks every phase.
474
+ const reqObs = r.obligations.filter((o) => required.includes(o.id) || o.id === 'OB-create');
475
+ const asBlocker = (o: Obligation) => ({ id: o.id, title: o.title, detail: o.detail });
476
+ // Never audited is not something a lowered phase rule may wave through (review M4).
477
+ const neverAudited = reqObs.filter((o) => o.id === 'OB-create' && !accepted(o.status)).map(asBlocker);
478
+ const open = reqObs.filter((o) => o.id !== 'OB-create' && !accepted(o.status)).map(asBlocker);
479
+ const overrides = unitOverrides(projectRoot, unit);
480
+ // Decision problems are hard rules: no phase override lowers them. At the release boundary an
481
+ // override, waiver or approval git HEAD does not hold is refused too (decision.in-run, review H1).
482
+ const scopes = [PROJECT_SCOPE, ...(overrides.unitScope ? [overrides.unitScope] : [])];
483
+ const hard = [
484
+ ...(r.decisionFindings ?? []).filter((f) => resolveRule(f.rule).blocking)
485
+ .map((f) => ({ id: f.rule, title: 'Decision integrity', detail: `${f.path} — ${f.message}` })),
486
+ ...(phase === 'deliver' && resolveRule(IN_RUN_RULE).blocking ? uncommittedReleaseDecisions(projectRoot, scopes) : [])
487
+ .map((d) => ({ id: IN_RUN_RULE, title: 'Decision not reviewed', detail: `${d.kind} ${d.id} (${d.path}) — ${d.why.join('; ')}` })),
488
+ ...neverAudited,
489
+ ];
490
+ const phaseRule = resolveRule(PHASE_RULE[phase], overrides.context);
491
+ const blockers = [...hard, ...open];
492
+ const halt = hard.length > 0 || (open.length > 0 && phaseRule.blocking);
329
493
  const waivedCredit = reqObs.filter((o) => o.status === 'waived').map((o) => ({ id: o.id, title: o.title }));
330
- return { unit, phase, status: blockers.length ? 'halt' : 'pass', required, blockers, waivedCredit };
494
+ const overriddenCredit = reqObs.filter((o) => o.status === 'overridden').map((o) => ({ id: o.id, title: o.title, by: o.overriddenBy ?? '' }));
495
+ return {
496
+ unit, phase, status: halt ? 'halt' : 'pass', required, blockers, waivedCredit,
497
+ ...(overriddenCredit.length ? { overriddenCredit } : {}),
498
+ ...(open.length && phaseRule.overriddenBy ? { phaseOverriddenBy: phaseRule.overriddenBy } : {}),
499
+ };
331
500
  }
332
501
 
333
502
  export function renderGate(v: GateVerdict): string {
334
503
  const L: string[] = [];
335
504
  L.push('');
336
505
  L.push(`━━━ Gate: ${v.unit} @ phase "${v.phase}" → ${v.status === 'pass' ? '✅ PASS' : '⛔ HALT'} ━━━`);
506
+ if (v.phaseOverriddenBy) L.push(` Phase rule lowered by ${v.phaseOverriddenBy}: open obligations are advisory (decision problems still block).`);
337
507
  if (v.blockers.length) {
338
- L.push(' Blocking obligations (must be satisfied or explicitly waived):');
508
+ L.push(v.phaseOverriddenBy ? ' Open obligations:' : ' Blocking obligations (must be satisfied or explicitly waived):');
339
509
  for (const b of v.blockers) L.push(` • ${b.id} ${b.title} — ${b.detail}`);
340
- L.push(' → Self-correct (repair / run-test), or `sungen journey --screen ' + v.unit + ' --waive <OB> --reason "..."` if accepted.');
510
+ // Name what each kind of blocker takes (#936): never offer to waive the sign-off or "never audited".
511
+ const waivable = v.blockers.map((b) => b.id).filter((id) => id.startsWith('OB-') && id !== SIGNOFF_OBLIGATION && id !== 'OB-create');
512
+ if (waivable.length) {
513
+ L.push(` → Self-correct (repair / run-test), or, if accepted, waive with a reason: \`sungen journey --screen ${v.unit} --waive ${waivable.length === 1 ? waivable[0] : `<${waivable.join('|')}>`} --reason "..."\`.`);
514
+ }
515
+ if (v.blockers.some((b) => b.id === SIGNOFF_OBLIGATION)) {
516
+ L.push(` → Human sign-off: once everything else is satisfied or waived, a human runs \`${signoffCommand(v.unit)}\`.`);
517
+ }
341
518
  } else {
342
519
  L.push(' All required obligations satisfied' + (v.waivedCredit.length ? ` (${v.waivedCredit.length} accepted via waiver)` : '') + '.');
343
520
  }
@@ -388,7 +565,7 @@ export function rollupJourney(projectRoot: string): UnitSummary[] {
388
565
  const r = runJourney(projectRoot, unit);
389
566
  const signedOff = r.obligations.find((o) => o.id === 'OB-signoff')?.status === 'satisfied';
390
567
  const obligationsOpen = r.obligations.filter(
391
- (o) => o.id !== 'OB-signoff' && o.status !== 'satisfied' && o.status !== 'waived',
568
+ (o) => o.id !== 'OB-signoff' && !accepted(o.status),
392
569
  ).length;
393
570
  return {
394
571
  unit, kind, score: r.score, gateStatus: r.gateStatus, youAreHere: r.youAreHere,
@@ -6,20 +6,33 @@
6
6
  * scenario: keep / regenerate / retire — so the orchestrator regenerates only the
7
7
  * parts whose spec changed (stable + cheap), and never silently drifts.
8
8
  *
9
+ * Schema 2 (DOS-12.3, red-team #1): each entry names its `hashAlgo`. Section entries keep `sha1-12`
10
+ * and the fuzzy `matchSection` — changing either would make every manifest on disk read "changed".
11
+ * Only item anchors (`<docId>#<itemId>` in a `# --- Section: … ---` comment) use `sha256-12` + exact
12
+ * ids. A manifest WITHOUT `schema` is compared as is (its sections are sha1-12) and upgraded on save.
9
13
  * Deterministic. Manifest lives at .sungen/manifest/<screen>.json.
10
14
  */
11
15
  import * as fs from 'fs';
12
16
  import * as path from 'path';
13
- import { createHash } from 'crypto';
14
17
  import { featureFilesFor, reportSlug } from './unit-paths';
15
18
  import { readTextFile } from './read-text';
19
+ import { vpCodeOf } from './parse';
20
+ import { HashAlgo, sectionHash } from '../basis/anchor-hash';
21
+ import { isItemAnchorId } from '../basis/anchor-grammar';
22
+ import { extractSpecAnchors } from '../basis/extract-spec-anchors';
23
+ import { normalizeSectionName as norm, readSpecSectionBlocks } from '../basis/spec-sections';
24
+ import { assertNoPendingMigration, withMigrationSentinel } from '../basis/migration-sentinel';
25
+
26
+ export const MANIFEST_SCHEMA = 2;
16
27
 
17
28
  export interface SpecSection { name: string; hash: string }
18
- export interface ManifestEntry { scenario: string; vpCode?: string; section: string; specHash: string }
29
+ export interface ManifestEntry { scenario: string; vpCode?: string; section: string; specHash: string; hashAlgo?: HashAlgo }
19
30
  export interface Manifest {
31
+ schema?: number; // absent = written before schema 2 → silent re-baseline
20
32
  screen: string;
21
33
  builtAt: string;
22
- specSections: Record<string, string>; // section name → hash (snapshot at build time)
34
+ specSections: Record<string, string>; // section name → sha1-12 (snapshot at build time)
35
+ specItems?: Record<string, string>; // item anchor → sha256-12 (schema 2, BM-51 specs with a docId)
23
36
  entries: ManifestEntry[]; // scenario ↔ section ↔ hash
24
37
  }
25
38
 
@@ -32,13 +45,6 @@ export interface ChangePlan {
32
45
  summary: { keep: number; regenerate: number; retire: number; newSections: number };
33
46
  }
34
47
 
35
- function norm(s: string): string {
36
- return s.replace(/\(Tier[^)]*\)/i, '').replace(/[#*-]/g, '').trim().toLowerCase().replace(/\s+/g, ' ');
37
- }
38
- function shortHash(s: string): string {
39
- return createHash('sha1').update(s).digest('hex').slice(0, 12);
40
- }
41
-
42
48
  const NO_SPEC = '(no-spec-link)';
43
49
 
44
50
  /**
@@ -60,21 +66,17 @@ function matchSection(featureSection: string, specNames: string[]): string | nul
60
66
  /** Parse spec.md into hashable sections (## and ### headings; "Section:" prefix stripped). */
61
67
  export function parseSpecSections(specPath: string): SpecSection[] {
62
68
  if (!fs.existsSync(specPath)) return [];
63
- const lines = readTextFile(specPath).split('\n');
64
- const sections: { name: string; body: string[] }[] = [];
65
- let cur: { name: string; body: string[] } | null = null;
66
- for (const line of lines) {
67
- const h = line.match(/^#{2,3}\s+(.*)$/);
68
- if (h) {
69
- if (cur) sections.push(cur);
70
- const name = h[1].replace(/^Section:\s*/i, '').trim();
71
- cur = { name, body: [] };
72
- } else if (cur) {
73
- cur.body.push(line);
74
- }
69
+ return readSpecSectionBlocks(readTextFile(specPath).split('\n')).map((s) => ({ name: norm(s.name), hash: sectionHash(s.body) }));
70
+ }
71
+
72
+ /** Item anchors a scenario can be linked to exactly: unambiguous §4.1 items and their §4.2 rows. */
73
+ function parseSpecItems(specPath: string): Record<string, string> {
74
+ if (!fs.existsSync(specPath)) return {};
75
+ const out: Record<string, string> = {};
76
+ for (const a of extractSpecAnchors(readTextFile(specPath), { repo: '.', sha: 'WORKTREE', path: 'spec.md' }).anchors) {
77
+ if (a.kind !== 'section' && a.confidence === 'EXTRACTED') out[a.id] = a.hash;
75
78
  }
76
- if (cur) sections.push(cur);
77
- return sections.map((s) => ({ name: norm(s.name), hash: shortHash(s.body.join('\n').trim()) }));
79
+ return out;
78
80
  }
79
81
 
80
82
  /** Parse feature into scenario → section mapping using `# --- Section: X ---` comments. */
@@ -86,12 +88,11 @@ function parseFeatureSections(featurePath: string): { scenario: string; vpCode?:
86
88
  for (const raw of lines) {
87
89
  const line = raw.trim();
88
90
  const sc = line.match(/^#\s*-{2,}\s*Section:\s*(.*?)\s*-{2,}\s*$/i);
89
- if (sc) { section = norm(sc[1]); continue; }
91
+ if (sc) { section = isItemAnchorId(sc[1].trim()) ? sc[1].trim() : norm(sc[1]); continue; }
90
92
  const s = line.match(/^Scenario:\s*(.*)$/);
91
93
  if (s) {
92
94
  const name = s[1].trim();
93
- const code = name.match(/\bVP-[A-Z]+-\d+/i)?.[0];
94
- out.push({ scenario: name, vpCode: code, section });
95
+ out.push({ scenario: name, vpCode: vpCodeOf(name).vpCode, section });
95
96
  }
96
97
  }
97
98
  return out;
@@ -100,44 +101,55 @@ function parseFeatureSections(featurePath: string): { scenario: string; vpCode?:
100
101
  export function buildManifest(screenDir: string, screenName: string): Manifest {
101
102
  const specPath = path.join(screenDir, 'requirements', 'spec.md');
102
103
  const featureFiles = featureFilesFor(screenDir, screenName);
103
- const specSections = parseSpecSections(specPath);
104
104
  const specMap: Record<string, string> = {};
105
- for (const s of specSections) specMap[s.name] = s.hash;
105
+ for (const s of parseSpecSections(specPath)) specMap[s.name] = s.hash;
106
+ const specItems = parseSpecItems(specPath);
106
107
 
107
108
  const specNames = Object.keys(specMap);
108
- const featScenarios = featureFiles.flatMap(parseFeatureSections);
109
- const entries: ManifestEntry[] = featScenarios.map((f) => {
109
+ const entries: ManifestEntry[] = featureFiles.flatMap(parseFeatureSections).map((f) => {
110
+ const base = { scenario: f.scenario, vpCode: f.vpCode };
111
+ if (isItemAnchorId(f.section)) {
112
+ const hash = specItems[f.section];
113
+ return hash ? { ...base, section: f.section, specHash: hash, hashAlgo: 'sha256-12' as HashAlgo } : { ...base, section: f.section, specHash: NO_SPEC };
114
+ }
110
115
  const matched = matchSection(f.section, specNames);
111
- return {
112
- scenario: f.scenario,
113
- vpCode: f.vpCode,
114
- section: matched ?? f.section, // canonical spec section when matched
115
- specHash: matched ? specMap[matched] : NO_SPEC,
116
- };
116
+ return matched
117
+ ? { ...base, section: matched, specHash: specMap[matched], hashAlgo: 'sha1-12' as HashAlgo } // canonical spec section when matched
118
+ : { ...base, section: f.section, specHash: NO_SPEC };
117
119
  });
118
120
 
119
121
  return {
122
+ schema: MANIFEST_SCHEMA,
120
123
  screen: screenName,
121
124
  builtAt: new Date().toISOString(),
122
125
  specSections: specMap,
126
+ ...(Object.keys(specItems).length ? { specItems } : {}),
123
127
  entries,
124
128
  };
125
129
  }
126
130
 
131
+ /**
132
+ * Compare a stored manifest — legacy or schema 2 — with the spec now. Read-only: it never rewrites
133
+ * the manifest. A legacy entry has no `hashAlgo` and is a section entry hashed sha1-12, exactly what
134
+ * the current code computes, so real drift since the legacy build reads `regenerate` and nothing reads
135
+ * "changed" merely because the format moved on.
136
+ */
127
137
  export function diffManifest(screenDir: string, screenName: string, manifest: Manifest): ChangePlan {
138
+ assertNoPendingMigration(process.cwd(), reportSlug(screenName));
128
139
  const specPath = path.join(screenDir, 'requirements', 'spec.md');
129
- const current = parseSpecSections(specPath);
130
140
  const currentMap: Record<string, string> = {};
131
- for (const s of current) currentMap[s.name] = s.hash;
141
+ for (const s of parseSpecSections(specPath)) currentMap[s.name] = s.hash;
142
+ const currentItems = manifest.entries.some((e) => e.hashAlgo === 'sha256-12') ? parseSpecItems(specPath) : {};
132
143
 
133
144
  const scenarios = manifest.entries.map((e) => {
134
145
  let change: ChangeKind; let reason: string;
146
+ const what = e.hashAlgo === 'sha256-12' ? 'spec item' : 'spec section';
135
147
  if (e.specHash === NO_SPEC) { change = 'keep'; reason = 'not linked to a spec section (manual/cross-cutting)'; }
136
148
  else {
137
- const now = currentMap[e.section];
138
- if (now === undefined) { change = 'retire'; reason = `spec section "${e.section}" no longer exists`; }
139
- else if (now !== e.specHash) { change = 'regenerate'; reason = `spec section "${e.section}" changed (${e.specHash} → ${now})`; }
140
- else { change = 'keep'; reason = 'spec section unchanged'; }
149
+ const now = e.hashAlgo === 'sha256-12' ? currentItems[e.section] : currentMap[e.section];
150
+ if (now === undefined) { change = 'retire'; reason = `${what} "${e.section}" no longer exists`; }
151
+ else if (now !== e.specHash) { change = 'regenerate'; reason = `${what} "${e.section}" changed (${e.specHash} → ${now})`; }
152
+ else { change = 'keep'; reason = `${what} unchanged`; }
141
153
  }
142
154
  return { scenario: e.scenario, section: e.section, change, reason };
143
155
  });
@@ -167,9 +179,21 @@ export function loadManifest(screenName: string): Manifest | null {
167
179
  const p = manifestPath(screenName);
168
180
  return fs.existsSync(p) ? JSON.parse(readTextFile(p)) : null;
169
181
  }
170
- export function saveManifest(m: Manifest): string {
171
- const p = manifestPath(m.screen);
182
+ /** The manifest on disk at `p`, or null when absent or unreadable (then a save is a plain write). */
183
+ function loadManifestFile(p: string): Manifest | null {
184
+ try { return fs.existsSync(p) ? JSON.parse(readTextFile(p)) : null; } catch { return null; }
185
+ }
186
+ function writeManifest(p: string, m: Manifest): void {
172
187
  fs.mkdirSync(path.dirname(p), { recursive: true });
173
188
  fs.writeFileSync(p, JSON.stringify(m, null, 2), 'utf-8');
189
+ }
190
+ /** Write a built manifest. Replacing a legacy (schema-less) file is the upgrade to schema 2, done under the sentinel. */
191
+ export function saveManifest(m: Manifest): string {
192
+ const slug = reportSlug(m.screen);
193
+ assertNoPendingMigration(process.cwd(), slug);
194
+ const p = manifestPath(m.screen);
195
+ const upgrading = m.schema === MANIFEST_SCHEMA && (loadManifestFile(p)?.schema ?? MANIFEST_SCHEMA) !== MANIFEST_SCHEMA;
196
+ if (upgrading) withMigrationSentinel(process.cwd(), m.screen, slug, 'manifest upgrade to schema 2', [p], () => writeManifest(p, m));
197
+ else writeManifest(p, m);
174
198
  return p;
175
199
  }