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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/dist/capabilities/discover.d.ts +4 -0
  2. package/dist/capabilities/discover.d.ts.map +1 -1
  3. package/dist/capabilities/discover.js +16 -2
  4. package/dist/capabilities/discover.js.map +1 -1
  5. package/dist/cli/case-triage-hint.d.ts +14 -0
  6. package/dist/cli/case-triage-hint.d.ts.map +1 -0
  7. package/dist/cli/case-triage-hint.js +23 -0
  8. package/dist/cli/case-triage-hint.js.map +1 -0
  9. package/dist/cli/commands/audit.js +1 -1
  10. package/dist/cli/commands/audit.js.map +1 -1
  11. package/dist/cli/commands/contract-derive-command.d.ts +4 -2
  12. package/dist/cli/commands/contract-derive-command.d.ts.map +1 -1
  13. package/dist/cli/commands/contract-derive-command.js +19 -5
  14. package/dist/cli/commands/contract-derive-command.js.map +1 -1
  15. package/dist/cli/commands/contract.d.ts +3 -0
  16. package/dist/cli/commands/contract.d.ts.map +1 -1
  17. package/dist/cli/commands/contract.js +40 -7
  18. package/dist/cli/commands/contract.js.map +1 -1
  19. package/dist/cli/commands/delivery.d.ts.map +1 -1
  20. package/dist/cli/commands/delivery.js +59 -18
  21. package/dist/cli/commands/delivery.js.map +1 -1
  22. package/dist/cli/commands/gate.d.ts.map +1 -1
  23. package/dist/cli/commands/gate.js +2 -1
  24. package/dist/cli/commands/gate.js.map +1 -1
  25. package/dist/cli/commands/generate.d.ts.map +1 -1
  26. package/dist/cli/commands/generate.js +14 -2
  27. package/dist/cli/commands/generate.js.map +1 -1
  28. package/dist/cli/commands/journey.d.ts.map +1 -1
  29. package/dist/cli/commands/journey.js +6 -4
  30. package/dist/cli/commands/journey.js.map +1 -1
  31. package/dist/cli/commands/next.d.ts +7 -2
  32. package/dist/cli/commands/next.d.ts.map +1 -1
  33. package/dist/cli/commands/next.js +41 -10
  34. package/dist/cli/commands/next.js.map +1 -1
  35. package/dist/cli/commands/triage.d.ts +2 -1
  36. package/dist/cli/commands/triage.d.ts.map +1 -1
  37. package/dist/cli/commands/triage.js +45 -3
  38. package/dist/cli/commands/triage.js.map +1 -1
  39. package/dist/cli/commands/update.d.ts.map +1 -1
  40. package/dist/cli/commands/update.js +6 -2
  41. package/dist/cli/commands/update.js.map +1 -1
  42. package/dist/cli/index.js +5 -1
  43. package/dist/cli/index.js.map +1 -1
  44. package/dist/cli/json-error-on-exit.d.ts +34 -0
  45. package/dist/cli/json-error-on-exit.d.ts.map +1 -0
  46. package/dist/cli/json-error-on-exit.js +63 -0
  47. package/dist/cli/json-error-on-exit.js.map +1 -0
  48. package/dist/cli/project-sungen-invocation.d.ts +13 -0
  49. package/dist/cli/project-sungen-invocation.d.ts.map +1 -0
  50. package/dist/cli/project-sungen-invocation.js +95 -0
  51. package/dist/cli/project-sungen-invocation.js.map +1 -0
  52. package/dist/cli/run-command-hints.d.ts +9 -0
  53. package/dist/cli/run-command-hints.d.ts.map +1 -0
  54. package/dist/cli/run-command-hints.js +84 -0
  55. package/dist/cli/run-command-hints.js.map +1 -0
  56. package/dist/cli/waiting-for-you-block.d.ts +18 -0
  57. package/dist/cli/waiting-for-you-block.d.ts.map +1 -0
  58. package/dist/cli/waiting-for-you-block.js +22 -0
  59. package/dist/cli/waiting-for-you-block.js.map +1 -0
  60. package/dist/contract/accept-opaque-steps.d.ts +3 -0
  61. package/dist/contract/accept-opaque-steps.d.ts.map +1 -0
  62. package/dist/contract/accept-opaque-steps.js +114 -0
  63. package/dist/contract/accept-opaque-steps.js.map +1 -0
  64. package/dist/contract/approve-contract.d.ts +8 -1
  65. package/dist/contract/approve-contract.d.ts.map +1 -1
  66. package/dist/contract/approve-contract.js +6 -0
  67. package/dist/contract/approve-contract.js.map +1 -1
  68. package/dist/contract/build-contract-verdict.js +2 -2
  69. package/dist/contract/build-contract-verdict.js.map +1 -1
  70. package/dist/contract/build-trace-conformance.d.ts +5 -1
  71. package/dist/contract/build-trace-conformance.d.ts.map +1 -1
  72. package/dist/contract/build-trace-conformance.js +12 -14
  73. package/dist/contract/build-trace-conformance.js.map +1 -1
  74. package/dist/contract/classify-contract-change.d.ts +3 -2
  75. package/dist/contract/classify-contract-change.d.ts.map +1 -1
  76. package/dist/contract/classify-contract-change.js.map +1 -1
  77. package/dist/contract/classify-trace-conformance.d.ts +18 -3
  78. package/dist/contract/classify-trace-conformance.d.ts.map +1 -1
  79. package/dist/contract/classify-trace-conformance.js +64 -17
  80. package/dist/contract/classify-trace-conformance.js.map +1 -1
  81. package/dist/contract/contract-schema.d.ts +21 -0
  82. package/dist/contract/contract-schema.d.ts.map +1 -1
  83. package/dist/contract/contract-schema.js +25 -3
  84. package/dist/contract/contract-schema.js.map +1 -1
  85. package/dist/contract/contracts-lock-file.d.ts.map +1 -1
  86. package/dist/contract/contracts-lock-file.js +1 -0
  87. package/dist/contract/contracts-lock-file.js.map +1 -1
  88. package/dist/contract/derive-free-feature.d.ts +19 -0
  89. package/dist/contract/derive-free-feature.d.ts.map +1 -1
  90. package/dist/contract/derive-free-feature.js +40 -2
  91. package/dist/contract/derive-free-feature.js.map +1 -1
  92. package/dist/contract/project-contract-blockers.d.ts.map +1 -1
  93. package/dist/contract/project-contract-blockers.js +4 -2
  94. package/dist/contract/project-contract-blockers.js.map +1 -1
  95. package/dist/contract/record-contract-approval.d.ts +16 -1
  96. package/dist/contract/record-contract-approval.d.ts.map +1 -1
  97. package/dist/contract/record-contract-approval.js +29 -1
  98. package/dist/contract/record-contract-approval.js.map +1 -1
  99. package/dist/contract/render-free-gherkin.d.ts +2 -0
  100. package/dist/contract/render-free-gherkin.d.ts.map +1 -1
  101. package/dist/contract/render-free-gherkin.js +6 -0
  102. package/dist/contract/render-free-gherkin.js.map +1 -1
  103. package/dist/contract/resolve-unit-trace-identities.d.ts +12 -0
  104. package/dist/contract/resolve-unit-trace-identities.d.ts.map +1 -1
  105. package/dist/contract/resolve-unit-trace-identities.js +33 -49
  106. package/dist/contract/resolve-unit-trace-identities.js.map +1 -1
  107. package/dist/contract/trace/collect-trace-evidence.d.ts +16 -5
  108. package/dist/contract/trace/collect-trace-evidence.d.ts.map +1 -1
  109. package/dist/contract/trace/collect-trace-evidence.js +101 -43
  110. package/dist/contract/trace/collect-trace-evidence.js.map +1 -1
  111. package/dist/contract/trace/read-file-once.d.ts +20 -0
  112. package/dist/contract/trace/read-file-once.d.ts.map +1 -0
  113. package/dist/contract/trace/read-file-once.js +135 -0
  114. package/dist/contract/trace/read-file-once.js.map +1 -0
  115. package/dist/contract/trace/scenario-id-claims.d.ts +11 -0
  116. package/dist/contract/trace/scenario-id-claims.d.ts.map +1 -0
  117. package/dist/contract/trace/scenario-id-claims.js +89 -0
  118. package/dist/contract/trace/scenario-id-claims.js.map +1 -0
  119. package/dist/contract/trace/select-final-attempt.d.ts +4 -2
  120. package/dist/contract/trace/select-final-attempt.d.ts.map +1 -1
  121. package/dist/contract/trace/select-final-attempt.js +7 -4
  122. package/dist/contract/trace/select-final-attempt.js.map +1 -1
  123. package/dist/contract/trace/test-step-join.d.ts +3 -3
  124. package/dist/contract/trace/test-step-join.d.ts.map +1 -1
  125. package/dist/contract/trace/test-step-join.js +2 -2
  126. package/dist/contract/trace/test-step-join.js.map +1 -1
  127. package/dist/contract/trace/trace-binding.d.ts +3 -2
  128. package/dist/contract/trace/trace-binding.d.ts.map +1 -1
  129. package/dist/contract/trace/trace-binding.js +6 -3
  130. package/dist/contract/trace/trace-binding.js.map +1 -1
  131. package/dist/contract/trace/trace-file-reader.d.ts +14 -2
  132. package/dist/contract/trace/trace-file-reader.d.ts.map +1 -1
  133. package/dist/contract/trace/trace-file-reader.js +27 -45
  134. package/dist/contract/trace/trace-file-reader.js.map +1 -1
  135. package/dist/contract/trace/trace-freshness.d.ts +27 -0
  136. package/dist/contract/trace/trace-freshness.d.ts.map +1 -0
  137. package/dist/contract/trace/trace-freshness.js +146 -0
  138. package/dist/contract/trace/trace-freshness.js.map +1 -0
  139. package/dist/contract/trace/trace-identity-resolution.d.ts +2 -0
  140. package/dist/contract/trace/trace-identity-resolution.d.ts.map +1 -1
  141. package/dist/contract/trace/trace-identity-resolution.js +6 -3
  142. package/dist/contract/trace/trace-identity-resolution.js.map +1 -1
  143. package/dist/contract/trace/trace-run-record.d.ts +8 -3
  144. package/dist/contract/trace/trace-run-record.d.ts.map +1 -1
  145. package/dist/contract/trace/trace-run-record.js +42 -22
  146. package/dist/contract/trace/trace-run-record.js.map +1 -1
  147. package/dist/contract/trace/trace-steps.js +1 -1
  148. package/dist/contract/trace/trace-steps.js.map +1 -1
  149. package/dist/contract/trace/trace-zip-limits.d.ts +5 -1
  150. package/dist/contract/trace/trace-zip-limits.d.ts.map +1 -1
  151. package/dist/contract/trace/trace-zip-limits.js +6 -2
  152. package/dist/contract/trace/trace-zip-limits.js.map +1 -1
  153. package/dist/contract/verify-approval-decisions.d.ts.map +1 -1
  154. package/dist/contract/verify-approval-decisions.js +9 -4
  155. package/dist/contract/verify-approval-decisions.js.map +1 -1
  156. package/dist/decisions/confirmed-decision-commands.d.ts +11 -0
  157. package/dist/decisions/confirmed-decision-commands.d.ts.map +1 -1
  158. package/dist/decisions/confirmed-decision-commands.js +21 -3
  159. package/dist/decisions/confirmed-decision-commands.js.map +1 -1
  160. package/dist/decisions/decision-schema.d.ts +2 -1
  161. package/dist/decisions/decision-schema.d.ts.map +1 -1
  162. package/dist/decisions/decision-schema.js +2 -1
  163. package/dist/decisions/decision-schema.js.map +1 -1
  164. package/dist/decisions/git-head-trust.d.ts +12 -0
  165. package/dist/decisions/git-head-trust.d.ts.map +1 -1
  166. package/dist/decisions/git-head-trust.js +52 -0
  167. package/dist/decisions/git-head-trust.js.map +1 -1
  168. package/dist/decisions/human-confirmation.d.ts +2 -0
  169. package/dist/decisions/human-confirmation.d.ts.map +1 -1
  170. package/dist/decisions/human-confirmation.js +6 -0
  171. package/dist/decisions/human-confirmation.js.map +1 -1
  172. package/dist/decisions/legacy-waiver-migration.d.ts +8 -1
  173. package/dist/decisions/legacy-waiver-migration.d.ts.map +1 -1
  174. package/dist/decisions/legacy-waiver-migration.js +13 -4
  175. package/dist/decisions/legacy-waiver-migration.js.map +1 -1
  176. package/dist/exporters/csv-exporter.d.ts +11 -2
  177. package/dist/exporters/csv-exporter.d.ts.map +1 -1
  178. package/dist/exporters/csv-exporter.js +8 -4
  179. package/dist/exporters/csv-exporter.js.map +1 -1
  180. package/dist/exporters/matrix/export.d.ts +6 -1
  181. package/dist/exporters/matrix/export.d.ts.map +1 -1
  182. package/dist/exporters/matrix/export.js +11 -4
  183. package/dist/exporters/matrix/export.js.map +1 -1
  184. package/dist/exporters/matrix/xlsx-cells.js +1 -1
  185. package/dist/exporters/matrix/xlsx-cells.js.map +1 -1
  186. package/dist/exporters/xlsx-exporter.d.ts +3 -2
  187. package/dist/exporters/xlsx-exporter.d.ts.map +1 -1
  188. package/dist/exporters/xlsx-exporter.js +4 -4
  189. package/dist/exporters/xlsx-exporter.js.map +1 -1
  190. package/dist/graph/board-human-actions.d.ts +5 -0
  191. package/dist/graph/board-human-actions.d.ts.map +1 -0
  192. package/dist/graph/board-human-actions.js +83 -0
  193. package/dist/graph/board-human-actions.js.map +1 -0
  194. package/dist/graph/evaluate-graph.d.ts +21 -1
  195. package/dist/graph/evaluate-graph.d.ts.map +1 -1
  196. package/dist/graph/evaluate-graph.js +37 -9
  197. package/dist/graph/evaluate-graph.js.map +1 -1
  198. package/dist/graph/human-action.d.ts +21 -0
  199. package/dist/graph/human-action.d.ts.map +1 -0
  200. package/dist/graph/human-action.js +3 -0
  201. package/dist/graph/human-action.js.map +1 -0
  202. package/dist/graph/manual-triage-decisions.d.ts +19 -0
  203. package/dist/graph/manual-triage-decisions.d.ts.map +1 -0
  204. package/dist/graph/manual-triage-decisions.js +53 -0
  205. package/dist/graph/manual-triage-decisions.js.map +1 -0
  206. package/dist/graph/node-decl.d.ts +16 -0
  207. package/dist/graph/node-decl.d.ts.map +1 -1
  208. package/dist/graph/node-decl.js +4 -1
  209. package/dist/graph/node-decl.js.map +1 -1
  210. package/dist/graph/nodes/test-case-contract-nodes.d.ts +3 -1
  211. package/dist/graph/nodes/test-case-contract-nodes.d.ts.map +1 -1
  212. package/dist/graph/nodes/test-case-contract-nodes.js +22 -6
  213. package/dist/graph/nodes/test-case-contract-nodes.js.map +1 -1
  214. package/dist/graph/nodes/test-case-nodes.d.ts +3 -0
  215. package/dist/graph/nodes/test-case-nodes.d.ts.map +1 -1
  216. package/dist/graph/nodes/test-case-nodes.js +33 -4
  217. package/dist/graph/nodes/test-case-nodes.js.map +1 -1
  218. package/dist/graph/nodes/unit-audit-nodes.d.ts.map +1 -1
  219. package/dist/graph/nodes/unit-audit-nodes.js +1 -0
  220. package/dist/graph/nodes/unit-audit-nodes.js.map +1 -1
  221. package/dist/graph/nodes/unit-contract-node.d.ts +2 -1
  222. package/dist/graph/nodes/unit-contract-node.d.ts.map +1 -1
  223. package/dist/graph/nodes/unit-contract-node.js +16 -1
  224. package/dist/graph/nodes/unit-contract-node.js.map +1 -1
  225. package/dist/graph/nodes/unit-design-nodes.d.ts.map +1 -1
  226. package/dist/graph/nodes/unit-design-nodes.js +2 -1
  227. package/dist/graph/nodes/unit-design-nodes.js.map +1 -1
  228. package/dist/graph/test-case-results.d.ts +1 -0
  229. package/dist/graph/test-case-results.d.ts.map +1 -1
  230. package/dist/graph/test-case-results.js +27 -3
  231. package/dist/graph/test-case-results.js.map +1 -1
  232. package/dist/graph/test-case-satisfied.d.ts +5 -4
  233. package/dist/graph/test-case-satisfied.d.ts.map +1 -1
  234. package/dist/graph/test-case-satisfied.js +4 -0
  235. package/dist/graph/test-case-satisfied.js.map +1 -1
  236. package/dist/graph/test-case-state-shape.d.ts +7 -1
  237. package/dist/graph/test-case-state-shape.d.ts.map +1 -1
  238. package/dist/graph/unit-artifact-probes.d.ts.map +1 -1
  239. package/dist/graph/unit-artifact-probes.js +3 -1
  240. package/dist/graph/unit-artifact-probes.js.map +1 -1
  241. package/dist/graph/unit-results-freshness.d.ts +29 -0
  242. package/dist/graph/unit-results-freshness.d.ts.map +1 -0
  243. package/dist/graph/unit-results-freshness.js +213 -0
  244. package/dist/graph/unit-results-freshness.js.map +1 -0
  245. package/dist/harness/audit.d.ts +3 -2
  246. package/dist/harness/audit.d.ts.map +1 -1
  247. package/dist/harness/audit.js +4 -17
  248. package/dist/harness/audit.js.map +1 -1
  249. package/dist/harness/catalog/gate-rules.yaml +3 -3
  250. package/dist/harness/defect-draft.d.ts.map +1 -1
  251. package/dist/harness/defect-draft.js +12 -2
  252. package/dist/harness/defect-draft.js.map +1 -1
  253. package/dist/harness/defects.d.ts +14 -0
  254. package/dist/harness/defects.d.ts.map +1 -1
  255. package/dist/harness/defects.js +14 -10
  256. package/dist/harness/defects.js.map +1 -1
  257. package/dist/harness/flow-check.d.ts +9 -0
  258. package/dist/harness/flow-check.d.ts.map +1 -1
  259. package/dist/harness/flow-check.js +11 -0
  260. package/dist/harness/flow-check.js.map +1 -1
  261. package/dist/harness/gates/audit-gate-verdict.d.ts.map +1 -1
  262. package/dist/harness/gates/audit-gate-verdict.js +2 -1
  263. package/dist/harness/gates/audit-gate-verdict.js.map +1 -1
  264. package/dist/harness/gates/audit-input-hash.d.ts +2 -0
  265. package/dist/harness/gates/audit-input-hash.d.ts.map +1 -1
  266. package/dist/harness/gates/audit-input-hash.js +30 -2
  267. package/dist/harness/gates/audit-input-hash.js.map +1 -1
  268. package/dist/harness/gates/audit-report-verification.d.ts +17 -6
  269. package/dist/harness/gates/audit-report-verification.d.ts.map +1 -1
  270. package/dist/harness/gates/audit-report-verification.js +55 -21
  271. package/dist/harness/gates/audit-report-verification.js.map +1 -1
  272. package/dist/harness/gates/delivery-checklist.d.ts +3 -0
  273. package/dist/harness/gates/delivery-checklist.d.ts.map +1 -1
  274. package/dist/harness/gates/delivery-checklist.js +39 -6
  275. package/dist/harness/gates/delivery-checklist.js.map +1 -1
  276. package/dist/harness/gates/delivery-decision-gate.d.ts +4 -0
  277. package/dist/harness/gates/delivery-decision-gate.d.ts.map +1 -1
  278. package/dist/harness/gates/delivery-decision-gate.js +26 -1
  279. package/dist/harness/gates/delivery-decision-gate.js.map +1 -1
  280. package/dist/harness/gates/delivery-decision-step.d.ts +4 -1
  281. package/dist/harness/gates/delivery-decision-step.d.ts.map +1 -1
  282. package/dist/harness/gates/delivery-decision-step.js +17 -2
  283. package/dist/harness/gates/delivery-decision-step.js.map +1 -1
  284. package/dist/harness/gates/in-run-decision-check.d.ts.map +1 -1
  285. package/dist/harness/gates/in-run-decision-check.js +40 -12
  286. package/dist/harness/gates/in-run-decision-check.js.map +1 -1
  287. package/dist/harness/gates/migrated-waiver-import-bounds.d.ts +13 -0
  288. package/dist/harness/gates/migrated-waiver-import-bounds.d.ts.map +1 -0
  289. package/dist/harness/gates/migrated-waiver-import-bounds.js +141 -0
  290. package/dist/harness/gates/migrated-waiver-import-bounds.js.map +1 -0
  291. package/dist/harness/gates/migrated-waiver-review.d.ts +14 -4
  292. package/dist/harness/gates/migrated-waiver-review.d.ts.map +1 -1
  293. package/dist/harness/gates/migrated-waiver-review.js +78 -80
  294. package/dist/harness/gates/migrated-waiver-review.js.map +1 -1
  295. package/dist/harness/journey.d.ts +40 -0
  296. package/dist/harness/journey.d.ts.map +1 -1
  297. package/dist/harness/journey.js +155 -22
  298. package/dist/harness/journey.js.map +1 -1
  299. package/dist/harness/next-step.d.ts +19 -0
  300. package/dist/harness/next-step.d.ts.map +1 -1
  301. package/dist/harness/next-step.js +21 -0
  302. package/dist/harness/next-step.js.map +1 -1
  303. package/dist/harness/provenance.d.ts +29 -0
  304. package/dist/harness/provenance.d.ts.map +1 -1
  305. package/dist/harness/provenance.js +109 -9
  306. package/dist/harness/provenance.js.map +1 -1
  307. package/dist/harness/triage-manual-classification.d.ts +32 -0
  308. package/dist/harness/triage-manual-classification.d.ts.map +1 -0
  309. package/dist/harness/triage-manual-classification.js +56 -0
  310. package/dist/harness/triage-manual-classification.js.map +1 -0
  311. package/dist/harness/unit-paths.d.ts +8 -0
  312. package/dist/harness/unit-paths.d.ts.map +1 -1
  313. package/dist/harness/unit-paths.js +23 -1
  314. package/dist/harness/unit-paths.js.map +1 -1
  315. package/dist/hooks/bash-read-only-segment.d.ts +9 -0
  316. package/dist/hooks/bash-read-only-segment.d.ts.map +1 -0
  317. package/dist/hooks/bash-read-only-segment.js +168 -0
  318. package/dist/hooks/bash-read-only-segment.js.map +1 -0
  319. package/dist/hooks/bash-write-targets.d.ts +12 -2
  320. package/dist/hooks/bash-write-targets.d.ts.map +1 -1
  321. package/dist/hooks/bash-write-targets.js +122 -29
  322. package/dist/hooks/bash-write-targets.js.map +1 -1
  323. package/dist/hooks/guard-protected-paths.d.ts +4 -0
  324. package/dist/hooks/guard-protected-paths.d.ts.map +1 -1
  325. package/dist/hooks/guard-protected-paths.js +13 -3
  326. package/dist/hooks/guard-protected-paths.js.map +1 -1
  327. package/dist/hooks/guard-rules.d.ts +0 -17
  328. package/dist/hooks/guard-rules.d.ts.map +1 -1
  329. package/dist/hooks/guard-rules.js +79 -10
  330. package/dist/hooks/guard-rules.js.map +1 -1
  331. package/dist/hooks/guard-tty-spoof-rule.d.ts +3 -1
  332. package/dist/hooks/guard-tty-spoof-rule.d.ts.map +1 -1
  333. package/dist/hooks/guard-tty-spoof-rule.js +3 -2
  334. package/dist/hooks/guard-tty-spoof-rule.js.map +1 -1
  335. package/dist/hooks/hand-back-core.d.ts +9 -4
  336. package/dist/hooks/hand-back-core.d.ts.map +1 -1
  337. package/dist/hooks/hand-back-core.js +24 -11
  338. package/dist/hooks/hand-back-core.js.map +1 -1
  339. package/dist/hooks/session-start-unit-state-hook.d.ts +2 -1
  340. package/dist/hooks/session-start-unit-state-hook.d.ts.map +1 -1
  341. package/dist/hooks/session-start-unit-state-hook.js +9 -4
  342. package/dist/hooks/session-start-unit-state-hook.js.map +1 -1
  343. package/dist/hooks/stop-next-step-hook.d.ts.map +1 -1
  344. package/dist/hooks/stop-next-step-hook.js +1 -0
  345. package/dist/hooks/stop-next-step-hook.js.map +1 -1
  346. package/dist/orchestrator/assets-drift.d.ts +5 -0
  347. package/dist/orchestrator/assets-drift.d.ts.map +1 -1
  348. package/dist/orchestrator/assets-drift.js +12 -3
  349. package/dist/orchestrator/assets-drift.js.map +1 -1
  350. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  351. package/dist/orchestrator/project-initializer.js +1 -0
  352. package/dist/orchestrator/project-initializer.js.map +1 -1
  353. package/dist/orchestrator/templates/ai-src/commands/create-test.md +6 -3
  354. package/dist/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  355. package/dist/orchestrator/templates/ai-src/commands/review.md +2 -0
  356. package/dist/orchestrator/templates/ai-src/commands/run-test.md +1 -1
  357. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.claude.md +11 -0
  358. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
  359. package/dist/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
  360. package/package.json +3 -3
  361. package/src/capabilities/discover.ts +15 -2
  362. package/src/cli/case-triage-hint.ts +31 -0
  363. package/src/cli/commands/audit.ts +1 -1
  364. package/src/cli/commands/contract-derive-command.ts +20 -8
  365. package/src/cli/commands/contract.ts +41 -7
  366. package/src/cli/commands/delivery.ts +56 -18
  367. package/src/cli/commands/gate.ts +2 -1
  368. package/src/cli/commands/generate.ts +13 -2
  369. package/src/cli/commands/journey.ts +8 -6
  370. package/src/cli/commands/next.ts +41 -12
  371. package/src/cli/commands/triage.ts +41 -3
  372. package/src/cli/commands/update.ts +6 -2
  373. package/src/cli/index.ts +5 -1
  374. package/src/cli/json-error-on-exit.ts +72 -0
  375. package/src/cli/project-sungen-invocation.ts +59 -0
  376. package/src/cli/run-command-hints.ts +47 -0
  377. package/src/cli/waiting-for-you-block.ts +27 -0
  378. package/src/contract/accept-opaque-steps.ts +114 -0
  379. package/src/contract/approve-contract.ts +10 -3
  380. package/src/contract/build-contract-verdict.ts +2 -2
  381. package/src/contract/build-trace-conformance.ts +11 -8
  382. package/src/contract/classify-contract-change.ts +3 -3
  383. package/src/contract/classify-trace-conformance.ts +76 -22
  384. package/src/contract/contract-schema.ts +31 -2
  385. package/src/contract/contracts-lock-file.ts +1 -0
  386. package/src/contract/derive-free-feature.ts +46 -3
  387. package/src/contract/project-contract-blockers.ts +4 -2
  388. package/src/contract/record-contract-approval.ts +41 -1
  389. package/src/contract/render-free-gherkin.ts +5 -0
  390. package/src/contract/resolve-unit-trace-identities.ts +35 -12
  391. package/src/contract/trace/collect-trace-evidence.ts +105 -36
  392. package/src/contract/trace/read-file-once.ts +95 -0
  393. package/src/contract/trace/scenario-id-claims.ts +60 -0
  394. package/src/contract/trace/select-final-attempt.ts +12 -5
  395. package/src/contract/trace/test-step-join.ts +6 -5
  396. package/src/contract/trace/trace-binding.ts +7 -4
  397. package/src/contract/trace/trace-file-reader.ts +34 -13
  398. package/src/contract/trace/trace-freshness.ts +110 -0
  399. package/src/contract/trace/trace-identity-resolution.ts +7 -4
  400. package/src/contract/trace/trace-run-record.ts +37 -15
  401. package/src/contract/trace/trace-steps.ts +1 -1
  402. package/src/contract/trace/trace-zip-limits.ts +6 -2
  403. package/src/contract/verify-approval-decisions.ts +9 -5
  404. package/src/decisions/confirmed-decision-commands.ts +25 -4
  405. package/src/decisions/decision-schema.ts +2 -1
  406. package/src/decisions/git-head-trust.ts +44 -0
  407. package/src/decisions/human-confirmation.ts +5 -0
  408. package/src/decisions/legacy-waiver-migration.ts +14 -3
  409. package/src/exporters/csv-exporter.ts +12 -4
  410. package/src/exporters/matrix/export.ts +11 -4
  411. package/src/exporters/matrix/xlsx-cells.ts +1 -1
  412. package/src/exporters/xlsx-exporter.ts +5 -4
  413. package/src/graph/board-human-actions.ts +80 -0
  414. package/src/graph/evaluate-graph.ts +45 -10
  415. package/src/graph/human-action.ts +33 -0
  416. package/src/graph/manual-triage-decisions.ts +55 -0
  417. package/src/graph/node-decl.ts +18 -0
  418. package/src/graph/nodes/test-case-contract-nodes.ts +28 -7
  419. package/src/graph/nodes/test-case-nodes.ts +37 -5
  420. package/src/graph/nodes/unit-audit-nodes.ts +2 -1
  421. package/src/graph/nodes/unit-contract-node.ts +20 -2
  422. package/src/graph/nodes/unit-design-nodes.ts +2 -1
  423. package/src/graph/test-case-results.ts +25 -4
  424. package/src/graph/test-case-satisfied.ts +7 -4
  425. package/src/graph/test-case-state-shape.ts +7 -2
  426. package/src/graph/unit-artifact-probes.ts +3 -1
  427. package/src/graph/unit-results-freshness.ts +165 -0
  428. package/src/harness/audit.ts +4 -13
  429. package/src/harness/catalog/gate-rules.yaml +3 -3
  430. package/src/harness/defect-draft.ts +13 -2
  431. package/src/harness/defects.ts +22 -9
  432. package/src/harness/flow-check.ts +11 -0
  433. package/src/harness/gates/audit-gate-verdict.ts +2 -1
  434. package/src/harness/gates/audit-input-hash.ts +27 -3
  435. package/src/harness/gates/audit-report-verification.ts +57 -24
  436. package/src/harness/gates/delivery-checklist.ts +39 -7
  437. package/src/harness/gates/delivery-decision-gate.ts +29 -1
  438. package/src/harness/gates/delivery-decision-step.ts +19 -3
  439. package/src/harness/gates/in-run-decision-check.ts +38 -13
  440. package/src/harness/gates/migrated-waiver-import-bounds.ts +103 -0
  441. package/src/harness/gates/migrated-waiver-review.ts +90 -37
  442. package/src/harness/journey.ts +174 -21
  443. package/src/harness/next-step.ts +34 -1
  444. package/src/harness/provenance.ts +99 -11
  445. package/src/harness/triage-manual-classification.ts +76 -0
  446. package/src/harness/unit-paths.ts +19 -0
  447. package/src/hooks/bash-read-only-segment.ts +130 -0
  448. package/src/hooks/bash-write-targets.ts +109 -23
  449. package/src/hooks/guard-protected-paths.ts +13 -3
  450. package/src/hooks/guard-rules.ts +37 -18
  451. package/src/hooks/guard-tty-spoof-rule.ts +6 -3
  452. package/src/hooks/hand-back-core.ts +24 -12
  453. package/src/hooks/session-start-unit-state-hook.ts +9 -4
  454. package/src/hooks/stop-next-step-hook.ts +1 -0
  455. package/src/orchestrator/assets-drift.ts +12 -5
  456. package/src/orchestrator/project-initializer.ts +1 -0
  457. package/src/orchestrator/templates/ai-src/commands/create-test.md +6 -3
  458. package/src/orchestrator/templates/ai-src/commands/delivery.md +2 -0
  459. package/src/orchestrator/templates/ai-src/commands/review.md +2 -0
  460. package/src/orchestrator/templates/ai-src/commands/run-test.md +1 -1
  461. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.claude.md +11 -0
  462. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.codex.md +11 -0
  463. package/src/orchestrator/templates/ai-src/partials/waiting-for-you.copilot.md +11 -0
@@ -4,20 +4,29 @@
4
4
  *
5
5
  * protected-approval-paths DENY a precise write (Edit/Write/MultiEdit, or Bash `>`, `tee`,
6
6
  * `sed -i`) to a contract lock, a decision record, approval state or
7
- * trace evidence (.sungen/trace-identity, test-results/sungen-run-record*)
7
+ * trace evidence (.sungen/trace-identity, test-results[-free]/sungen-run-record*)
8
8
  * protected-hook-control ASK the same writes to the files that control the hooks, so the
9
9
  * agent cannot switch its own guard off unasked
10
- * bash-protected-mention ASK any other Bash segment that names a protected path and does not
11
- * start with a read-only command (cp, mv, ln, install, rm,
12
- * bash -c, python -c, perl -i…)
10
+ * bash-protected-mention ASK any other Bash segment that names a protected path and is not
11
+ * read-only (cp, mv, ln, install, rm, bash -c, python -c, perl -i…);
12
+ * a read-only one too when its output is piped into a non-read-only
13
+ * command, or the line has command substitution or sets shell state
14
+ * (`X=…`, export, alias, a function…); a heredoc / here-string
15
+ * that names one; and a write target with a glob or brace (#968 — bash-read-only-segment.ts lists what counts
16
+ * as read-only, and the accepted floor)
13
17
  *
14
18
  * A floor, not a sandbox: a path built at runtime, a symlink, or a script file that writes without
15
- * naming the path on the command line is out of reach by design. Each rule only matches strings,
19
+ * naming the path on the command line is out of reach by design (the full list of what the floor
20
+ * does not catch is in bash-read-only-segment.ts; release-time decision integrity is the backstop). Each rule only matches strings,
16
21
  * so each fails open (`onError: 'no-op'`); a rule that READS project state must declare `'ask'`.
17
22
  */
23
+ import * as path from 'path';
18
24
  import type { HookContext, HookResult } from './hook-result-contract';
19
- import { bashSegments } from './bash-write-targets';
20
- import { approvalRecordPath, hookControlPath, mentionsProtectedPath, traceEvidencePath } from './guard-protected-paths';
25
+ import { BashSegment, bashSegments } from './bash-write-targets';
26
+ import { isReadOnlySegment, lineKeepsReadOnlyExemption, pipelineStaysReadOnly } from './bash-read-only-segment';
27
+ import {
28
+ approvalRecordPath, hookControlPath, mentionsProtectedPath, mentionsProtectedText, opaqueNearProtected, traceEvidencePath,
29
+ } from './guard-protected-paths';
21
30
 
22
31
  /** One tool call, normalized from the untrusted payload. */
23
32
  export interface GuardedCall {
@@ -76,23 +85,33 @@ export const protectedHookControl: GuardRule = {
76
85
  },
77
86
  };
78
87
 
79
- /** Segments that only read: they may name a protected path freely. */
80
- const READ_ONLY = new Set(['cat', 'ls', 'head', 'tail', 'grep', 'rg', 'wc', 'diff', 'sungen', 'sungen.js']);
81
- const GIT_READ_ONLY = new Set(['diff', 'log', 'show', 'status']);
82
- const isReadOnly = (cmd: string, words: string[]): boolean =>
83
- READ_ONLY.has(cmd) || (cmd === 'git' && GIT_READ_ONLY.has(words.find((w) => !w.startsWith('-')) ?? ''));
88
+ /** A heredoc or here-string: its body is another program's input, which the segments do not see. */
89
+ const HEREDOC = /<</;
84
90
 
85
91
  export const bashProtectedMention: GuardRule = {
86
92
  id: 'bash-protected-mention',
87
93
  onError: 'no-op',
88
94
  check(call) {
89
- if (call.tool !== 'Bash' || !call.bashCommand) return null;
90
- const seg = bashSegments(call.bashCommand, call.cwd)
91
- .find((s) => s.cmd && !isReadOnly(s.cmd, s.words) && s.words.some((w) => mentionsProtectedPath(w, s.dir)));
92
- return seg ? {
95
+ const command = call.tool === 'Bash' ? call.bashCommand : undefined;
96
+ if (!command) return null;
97
+ const segs = bashSegments(command, call.cwd);
98
+ const lineExempt = lineKeepsReadOnlyExemption(command, segs);
99
+ // the command word too: zsh `for f (qa/decisions/*) …` puts the list where a command name goes
100
+ const names = (s: BashSegment): boolean => [s.cmdPath, ...s.words, ...s.assigns.map((a) => a.slice(a.indexOf('=') + 1))]
101
+ .some((w) => w !== '' && (mentionsProtectedPath(w, s.dir) || opaqueNearProtected(w)));
102
+ const seg = segs.find((s, i) => names(s) && !(lineExempt && isReadOnlySegment(s) && pipelineStaysReadOnly(segs, i)));
103
+ // a write target the shell expands (`> q*/decisions/x`, `--output=qa/{a,b}`, `> $Q/decisions/x`, a literal `\`),
104
+ // or a relative one after a `cd` the guard could not follow, cannot be judged by its text
105
+ const opaqueWrite = segs.some((s) => s.writesInUnknownDir || s.writes.some((w) => {
106
+ const rel = path.relative(s.dir, w);
107
+ return /[*?[{\\]/.test(rel) || opaqueNearProtected(rel);
108
+ }));
109
+ if (!seg && !opaqueWrite && !(HEREDOC.test(command) && mentionsProtectedText(command))) return null;
110
+ const what = seg ? (seg.cmd ? `\`${seg.cmd}\` command` : 'variable') : opaqueWrite ? 'write target the guard cannot resolve' : 'heredoc';
111
+ return {
93
112
  status: 'ask',
94
- askReason: `sungen: this \`${seg.cmd}\` command names a contract lock, a decision record, approval state or a hook-control file, `
113
+ askReason: `sungen: this ${what} names a contract lock, a decision record, approval state or a hook-control file, `
95
114
  + 'and the guard cannot tell whether it writes it. Allow only if you asked for exactly this.',
96
- } : null;
115
+ };
97
116
  },
98
117
  };
@@ -2,7 +2,9 @@
2
2
  * Guard rule `tty-spoof` (phase 06, M5): ASK before an agent runs a human-confirmed sungen command
3
3
  * through a terminal emulator.
4
4
  *
5
- * `contract approve`, `journey --waive` and `journey --decide` refuse without a TTY (DOS-13.4), and
5
+ * `contract approve`, `journey --waive`, `journey --decide`, `journey --signoff`, `triage --as test-defect|environment`
6
+ * (#928: a red classified away from the product-defect path) and `delivery --accept-in-run` (delivering past
7
+ * decisions recorded during the run) refuse without a TTY (DOS-13.4), and
6
8
  * an agent's Bash has none — unless it borrows one: `script`, `expect`, `unbuffer`, or a pty from
7
9
  * Python/Perl/zsh. Then the prompt sees a "terminal" and a piped phrase reads as a human typing it.
8
10
  * This rule spots the pair in the raw command (quotes included, so `bash -c "…"` and `expect -c '…'`
@@ -13,7 +15,7 @@
13
15
  import type { GuardRule } from './guard-rules';
14
16
 
15
17
  const TTY_EMULATOR = /\b(?:script|unbuffer|expect|pty|zpty|openpty|forkpty|ptyprocess)\b/i;
16
- const HUMAN_GATED = /\bsungen\b[\s\S]*?\b(?:contract['",\s]+approve\b|journey\b[\s\S]*?--(?:waive|decide)\b)/i;
18
+ const HUMAN_GATED = /\bsungen\b[\s\S]*?\b(?:contract['",\s]+approve\b|journey\b[\s\S]*?--(?:waive|decide|signoff)\b|triage\b[\s\S]*?--as[\s='",]+(?:test-defect|environment)\b|delivery\b[\s\S]*?--accept-in-run\b)/i;
17
19
 
18
20
  export const ttySpoof: GuardRule = {
19
21
  id: 'tty-spoof',
@@ -23,7 +25,8 @@ export const ttySpoof: GuardRule = {
23
25
  if (!cmd || !TTY_EMULATOR.test(cmd) || !HUMAN_GATED.test(cmd)) return null;
24
26
  return {
25
27
  status: 'ask',
26
- askReason: 'sungen: this runs a human-confirmed sungen action (`contract approve` / `journey --waive|--decide`) through a terminal '
28
+ askReason: 'sungen: this runs a human-confirmed sungen action (`contract approve` / `journey --waive|--decide|--signoff` / '
29
+ + '`triage --as test-defect|environment` / `delivery --accept-in-run`) through a terminal '
27
30
  + 'emulator (script / expect / unbuffer / pty). Those confirmations exist so a PERSON at a terminal decides — allow only if you '
28
31
  + 'are that person and asked for exactly this; otherwise run the command yourself in your own terminal.',
29
32
  };
@@ -10,23 +10,28 @@
10
10
  * commander's preAction, so a usage error — which never reaches an action — and `main().catch`
11
11
  * ended in silence. The state now starts the moment parsing does; the action only refines it.
12
12
  */
13
+ import { sungenInvocation, withProjectInvocationInText } from '../cli/project-sungen-invocation';
14
+ import { waitingForYouLines } from '../cli/waiting-for-you-block';
13
15
  import { resolveUnitCandidates } from '../cli/resolve-unit';
14
16
  import { readUnitState, NextStep, UnitState } from '../harness/next-step';
15
17
  import { NO_OP, HookContext, HookInput, HookResult } from './hook-result-contract';
16
18
  import { findSungenRoot, findUnit, nearestUnit, UnitRef } from './sungen-project-root';
17
19
 
18
- /** `next` IS the answer; `hook` speaks JSON to Claude Code on stdout. Neither prints a hand-back. */
19
- const SILENT_COMMANDS = new Set(['next', 'hook']);
20
+ /** `hook` speaks JSON to Claude Code on stdout: it never prints a hand-back. */
21
+ const SILENT_COMMANDS = new Set(['hook']);
22
+ /** `next` IS the answer when it succeeds; a failed `next` answered nothing and hands back like any failure (#937). */
23
+ const ANSWER_COMMANDS = new Set(['next']);
20
24
  const UNIT_FLAG = /^(?:--screen|-s|--flow|--area|--api)$/;
21
25
  const UNIT_FLAG_EQ = /^--(?:screen|flow|area|api)=(.+)$/;
22
26
  /** A unit id is a name or `flows/<name>` — anything else is not offered back to the operator. */
23
27
  const SAFE_UNIT = /^[\w.-]+(?:\/[\w.-]+)?$/;
24
28
 
25
- export function handBackLine(unit?: string): string {
26
- return `Next: sungen next${unit ? ` ${unit}` : ''}`;
29
+ /** `invocation`: how the project runs sungen (`npx sungen` with a local install, #939). */
30
+ export function handBackLine(unit?: string, invocation = 'sungen'): string {
31
+ return `Next: ${invocation} next${unit ? ` ${unit}` : ''}`;
27
32
  }
28
33
 
29
- export interface CliHandBackState { unit?: string; machine: boolean; silent: boolean; actionRan: boolean }
34
+ export interface CliHandBackState { unit?: string; machine: boolean; silent: boolean; answer: boolean; actionRan: boolean }
30
35
 
31
36
  /** The default, set before commander parses — what a usage error or a fatal error hands back. */
32
37
  export function initialHandBackState(argv: string[]): CliHandBackState {
@@ -38,13 +43,14 @@ export function initialHandBackState(argv: string[]): CliHandBackState {
38
43
  else if (UNIT_FLAG.test(args[i]) && args[i + 1] && !args[i + 1].startsWith('-')) unit ??= args[++i];
39
44
  }
40
45
  const command = args.find((a) => !a.startsWith('-')) ?? '';
41
- return { unit, machine: args.includes('--json') || args.includes('--grep'), silent: SILENT_COMMANDS.has(command), actionRan: false };
46
+ return { unit, machine: args.includes('--json') || args.includes('--grep'), silent: SILENT_COMMANDS.has(command), answer: ANSWER_COMMANDS.has(command), actionRan: false };
42
47
  }
43
48
 
44
49
  /** commander's preAction: the action now KNOWS its unit and output mode. */
45
50
  export function onCliAction(state: CliHandBackState, name: string, opts: Record<string, unknown>, args: unknown[]): void {
46
51
  state.actionRan = true;
47
52
  if (SILENT_COMMANDS.has(name)) { state.silent = true; return; }
53
+ state.answer = ANSWER_COMMANDS.has(name);
48
54
  const flagged = [opts.screen, opts.flow, opts.area, opts.api].find((v) => typeof v === 'string' && v) as string | undefined;
49
55
  state.unit = flagged ?? (typeof args?.[0] === 'string' ? args[0] : undefined);
50
56
  // `--grep` is machine output too: callers capture it with `$(…)` (#836).
@@ -57,10 +63,11 @@ export function onCliAction(state: CliHandBackState, name: string, opts: Record<
57
63
  */
58
64
  export function exitHandBack(state: CliHandBackState, code: number, cwd: string): { stream: 'stdout' | 'stderr'; text: string } | null {
59
65
  if (state.silent) return null;
66
+ if (state.answer && code === 0) return null; // a successful `next` is the hand-back itself
60
67
  if (!state.actionRan && code === 0) return null; // --help / --version printed what was asked
61
68
  const unit = state.unit && SAFE_UNIT.test(state.unit) && !state.unit.split('/').includes('..')
62
69
  && resolveUnitCandidates(state.unit, cwd).length > 0 ? state.unit : undefined;
63
- const line = handBackLine(unit);
70
+ const line = handBackLine(unit, sungenInvocation(findSungenRoot(cwd) ?? cwd));
64
71
  if (code === 1) return { stream: 'stderr', text: `${line}\n` }; // after the error, one line
65
72
  return { stream: state.machine ? 'stderr' : 'stdout', text: `\n${line}\n` };
66
73
  }
@@ -81,10 +88,14 @@ export function attachCliHandBack(argv: string[], cwd: string): { onAction: (nam
81
88
 
82
89
  const MARK: Record<NextStep['kind'], string> = { do: '→', blocked: '⛔', optional: '○', decide: '⚖' };
83
90
 
84
- /** `sungen next` rendered compactly for an agent's context. */
85
- export function formatSteps(steps: NextStep[], max = 4): string[] {
91
+ /**
92
+ * `sungen next` rendered compactly for an agent's context; commands — the step's own and those quoted in
93
+ * its reason (#966) — as `root` runs sungen, the way `sungen next` prints them.
94
+ */
95
+ export function formatSteps(steps: NextStep[], max = 4, root?: string): string[] {
96
+ const asRun = (text: string): string => (root ? withProjectInvocationInText(text, root) : text);
86
97
  return steps.slice(0, max).map((st) =>
87
- ` ${MARK[st.kind]} ${st.command}${st.kind === 'decide' ? ' (a QA decision — ask, do not run)' : ''}\n ${st.because}`);
98
+ ` ${MARK[st.kind]} ${asRun(st.command)}${st.kind === 'decide' ? ' (a QA decision — ask, do not run)' : ''}\n ${asRun(st.because)}`);
88
99
  }
89
100
 
90
101
  /** The unit a session is on (a named one when it exists, else the nearest) and its derived state. */
@@ -95,12 +106,13 @@ export function locateUnitState(ctx: HookContext, preferred?: string): { root: s
95
106
  return unit ? { root, unit, state: readUnitState(root, unit.dir, unit.name, unit.kind) } : null;
96
107
  }
97
108
 
98
- /** Hook core: the next steps for the session's unit (input.unit, else the nearest) as context. */
109
+ /** Hook core: the next steps for the session's unit (input.unit, else the nearest) as context, then what waits for a human (#954). */
99
110
  export function run(input: HookInput, ctx: HookContext): HookResult {
100
111
  const found = locateUnitState(ctx, typeof input.unit === 'string' ? input.unit : undefined);
101
112
  if (!found || found.state.steps.length === 0) return NO_OP;
102
113
  return {
103
114
  status: 'context',
104
- output: [`${handBackLine(found.unit.name)} — derived from what the project holds now:`, ...formatSteps(found.state.steps)].join('\n'),
115
+ output: [`${handBackLine(found.unit.name, sungenInvocation(found.root))} — derived from what the project holds now:`, ...formatSteps(found.state.steps, 4, found.root),
116
+ ...waitingForYouLines(found.state.humanActions, found.root, found.state.humanActionsHeldBy, found.state.humanActionsHeldByCommand)].join('\n'),
105
117
  };
106
118
  }
@@ -5,10 +5,13 @@
5
5
  * After `/clear` or a context compaction the agent has lost the thread: it re-derives the state
6
6
  * from memory, or worse, re-runs work that is already done. This injects what `sungen next`
7
7
  * derives for the session's unit (the one cwd sits in, else the most recently active): what the
8
- * project already holds — stated as "do not redo" — the audit verdict, and the next steps.
8
+ * project already holds — stated as "do not redo" — the audit verdict, the next steps, and what waits
9
+ * for a human (#954).
9
10
  */
10
11
  import { NO_OP, HookMeta, SungenHook } from './hook-result-contract';
11
12
  import { formatSteps, locateUnitState } from './hand-back-core';
13
+ import { sungenInvocation } from '../cli/project-sungen-invocation';
14
+ import { waitingForYouLines } from '../cli/waiting-for-you-block';
12
15
  import { listUnits } from './sungen-project-root';
13
16
  import type { UnitState } from '../harness/next-step';
14
17
 
@@ -40,14 +43,16 @@ export const sessionStartUnitStateHook: SungenHook = {
40
43
  if (!found) return NO_OP;
41
44
  const { root, unit, state } = found;
42
45
  const others = listUnits(root).length - 1;
46
+ const sungen = sungenInvocation(root);
43
47
  const lines = [
44
48
  `[sungen] Unit in progress: ${unit.name} (${unit.kind})${others > 0 ? ` — the project holds ${others} other unit(s)` : ''}.`,
45
49
  `Already done — do not redo: ${held(state)}.`,
46
50
  state.audit ? `Audit: ${state.audit.overall}/10 [${state.audit.gateStatus}] · ${state.audit.findings.length} finding(s).` : '',
47
- `Next (\`sungen next ${unit.name}\`, derived from the project state):`,
48
- ...formatSteps(state.steps),
51
+ `Next (\`${sungen} next ${unit.name}\`, derived from the project state):`,
52
+ ...formatSteps(state.steps, 4, root),
53
+ ...waitingForYouLines(state.humanActions, root, state.humanActionsHeldBy, state.humanActionsHeldByCommand),
49
54
  input.source === 'compact' ? 'Context was compacted: re-read the unit\'s files before acting on them.' : '',
50
- others > 0 ? 'Working on another unit? Ask `sungen next <unit>` (or `sungen next` for all).' : '',
55
+ others > 0 ? `Working on another unit? Ask \`${sungen} next <unit>\` (or \`${sungen} next\` for all).` : '',
51
56
  ];
52
57
  return { status: 'context', output: lines.filter(Boolean).join('\n') };
53
58
  },
@@ -30,6 +30,7 @@ export const stopNextStepHook: SungenHook = {
30
30
  output: [
31
31
  '[sungen] This turn ran sungen work but ended without the next-step hand-back.',
32
32
  'Hand back now: present these steps to the user with AskUserQuestion and stop — do not run them yourself.',
33
+ ...(/Waiting for you/.test(core.output) ? ['Quote the "Waiting for you" block verbatim: the user runs those commands in their own terminal (`! <command>`); never run them.'] : []),
33
34
  core.output,
34
35
  ].join('\n'),
35
36
  };
@@ -2,6 +2,7 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { getPackageVersion } from '../exporters/package-info';
4
4
  import { readJsonConfig, warnUnreadableConfig } from '../harness/config-file';
5
+ import { updateCommand } from '../cli/project-sungen-invocation';
5
6
 
6
7
  /**
7
8
  * Are this project's AI assets (commands + skills under `.claude/` etc.) the ones
@@ -54,6 +55,16 @@ export function checkAssetsDrift(cwd: string): AssetsDrift | null {
54
55
  return { recordedVersion, runningVersion, changed, total };
55
56
  }
56
57
 
58
+ /**
59
+ * The note's text. The update command is the one this project runs (`npx sungen` with a local install)
60
+ * on the channel it runs (`--alpha` / `--beta`): a plain `sungen update` would switch to stable (#939).
61
+ */
62
+ export function assetsDriftNote(drift: AssetsDrift, cwd: string, paint: (cmd: string) => string = (c) => c): string {
63
+ return `note: this project's AI commands/skills were written by sungen ${drift.recordedVersion}, ` +
64
+ `you are running ${drift.runningVersion} — run ${paint(updateCommand(cwd, drift.runningVersion))} to refresh them ` +
65
+ '(upgrading the package alone does not).';
66
+ }
67
+
57
68
  /** One line, on stderr so `--json` output stays machine-readable. */
58
69
  export function warnAssetsDrift(cwd: string): void {
59
70
  const drift = checkAssetsDrift(cwd);
@@ -61,9 +72,5 @@ export function warnAssetsDrift(cwd: string): void {
61
72
  const gray = '\x1b[90m';
62
73
  const cyan = '\x1b[36m';
63
74
  const reset = '\x1b[0m';
64
- process.stderr.write(
65
- `${gray}note: this project's AI commands/skills were written by sungen ${drift.recordedVersion}, ` +
66
- `you are running ${drift.runningVersion} — run ${cyan}sungen update${reset}${gray} to refresh them ` +
67
- `(upgrading the package alone does not).${reset}\n`,
68
- );
75
+ process.stderr.write(`${gray}${assetsDriftNote(drift, cwd, (c) => `${cyan}${c}${reset}${gray}`)}${reset}\n`);
69
76
  }
@@ -294,6 +294,7 @@ export class ProjectInitializer {
294
294
  'specs/.auth-mobile/', // mobile auth contract = credentials (sensitive)
295
295
  '.env.appium', // local mobile-test env = machine paths + device/team ids (.example IS committed)
296
296
  'test-results/',
297
+ 'test-results-free/', // free / @impl:code runs: their own outputDir, so a compiled run cannot clear their traces (#941)
297
298
  'playwright-report/',
298
299
  '.playwright-mcp/',
299
300
  '.sungen/figma-cache/', // raw Figma node JSON (design IP)
@@ -102,8 +102,8 @@ declaration instead of leaving both on record.
102
102
 
103
103
  ## ⛔ HARD RULE — approvals and waivers are a human's, on a terminal
104
104
 
105
- `sungen contract approve`, `sungen journey --waive` and `sungen journey --decide` record a QA
106
- decision and ask for a typed confirmation on a real terminal (TTY). Never run them, never fake the
105
+ `sungen contract approve`, `sungen journey --waive`, `sungen journey --decide` and `sungen journey --signoff` record a QA
106
+ decision (the sign-off is the single human gate before delivery) and ask for a typed confirmation on a real terminal (TTY). Never run them, never fake the
107
107
  terminal (`script`, `expect`, a pty wrapper), and never edit `contracts.lock.yaml` or
108
108
  `qa/**/decisions/` by hand. When one is due, show the exact command and stop for the human.
109
109
 
@@ -111,7 +111,10 @@ terminal (`script`, `expect`, a pty wrapper), and never edit `contracts.lock.yam
111
111
  traces, write their Gherkin with `sungen contract derive --screen <name>` — deterministic, it writes
112
112
  `features/<name>.free.feature` with every scenario tagged `@free @proposed`. Do not author those
113
113
  steps yourself; you may name the scenarios and suggest VP-ids. A `@proposed` scenario is not
114
- counted by the audit until a QA approves it (`sungen contract approve --screen <name>`).
114
+ counted by the audit until a QA approves it (`sungen contract approve --screen <name>`). When
115
+ two recorded tests claim one ID, `sungen contract derive` exits `1`, names both tests and writes
116
+ nothing: stop and ask the QA to give each test its own ID (its title's leading ID, or its `@tag`).
117
+ Never rename a test's ID — or a scenario's — yourself to get past it.
115
118
 
116
119
  ## Platform detection (do this FIRST)
117
120
 
@@ -237,3 +237,5 @@ sungen delivery [names...] # matrix (default; needs the map) → XLSX onl
237
237
  Outputs: `qa/deliverables/<unit>-testcases.xlsx` (Overview + Auto + Manual + Coverage sheets) by default;
238
238
  `--format csv` writes `<unit>-testcases.csv` instead (flat, `Level` column `item|variant`),
239
239
  `--format both` writes both. Legacy mode writes the classic files instead.
240
+
241
+ <!-- include: waiting-for-you -->
@@ -97,3 +97,5 @@ You are an **independent QA Reviewer** — you did not author these tests. You d
97
97
  5. **Trace + next** — `sungen trace --screen ${input:name}` (human-loop focus), then offer:
98
98
  - **`/sungen-run-test ${input:name}`** (Recommended) · **`/sungen-delivery ${input:name}`** · **`/sungen-create-test ${input:name}`** · Done.
99
99
  {{/cap}}
100
+
101
+ <!-- include: waiting-for-you -->
@@ -268,7 +268,7 @@ question already.
268
268
  7. **Phase 3 — Full Run**: Run all tests. Fix only **new** failures (elements unique to `@normal`/`@low`). Max 1 attempt. Don't loop on low-priority failures.
269
269
  8. **Phase 4 — Regression**: One final full run. No more fix loops. Then run `sungen triage --screen <name>` and render its table as the results summary: every red or flaky scenario already sits in one class (`product-candidate`, `unclassified`, `test-defect`, `environment`, `blocked-capability`, `known-defect`, `flaky`) with the rule and one evidence line. You may move an `unclassified` row into a class only with a written evidence line of your own. You may never turn a `product-candidate` into a `test-defect` by editing the `.feature` or the expected value — the Gherkin is frozen; report it as a candidate bug. For each `product-candidate` you judge to be a product bug, run `sungen defect draft --screen <name> --scenario "<title>"`, fill the record's Summary, check its Expected against `spec.md`, then add `@known-defect:DEF-NNN` to that scenario's tag line (the tag-only exception above). The severity in the draft is `proposed` — confirm it with QA (`AskUserQuestion`) before the hand-back and set `severity_source: qa`. A row you judge is not a product bug stays in the summary with your reason, and gets no record. A `bare-timeout` row (`unclassified`) is never re-run inside this command — Phase 4 was the final run; offer the re-run in Next steps.
270
270
  8a. **Test Contract — every unit with a lock.** When `qa/<screens|flows|api>/<name>/contracts.lock.yaml` exists, check the suite still does what QA approved:
271
- - **`@free` / `@impl:code` scenarios** (hand-written specs, not compiled): in the Phase 4 final run, run their specs with `--trace on` (`npx playwright test <their spec> --trace on`) — their trace is the only proof. The project's config needs the sungen run-record reporter; if it is missing, no trace is admissible: tell the QA, do not edit the config yourself. Then `sungen contract check --screen <name> --trace`.
271
+ - **`@free` / `@impl:code` scenarios** (hand-written specs, not compiled): after the Phase 4 final run, run their specs with the project's free-test config and `--trace on` (`npx playwright test -c <free-test config> --trace on`) — their trace is the only proof. That config writes to its own `outputDir: 'test-results-free'` with `trace: 'on'` and the sungen run-record reporter; never run them into `test-results/`, which the next compiled run clears (the trace is then gone and the scenario is `unproven`). If the project has no such config, no trace is admissible: tell the QA, do not write or edit the config yourself. Then `sungen contract check --screen <name> --trace`.
272
272
  - **No free tests**: `sungen contract check --screen <name>`.
273
273
  - **Exit 2 (hard)** — `oracle-weakened`, `target-changed`, `assertion-lost`, `lock-uncommitted`, `unproven` → report each finding to the QA in the results summary, with its rule. **Never** edit the `.feature`, an expected value, the lock or a decision to turn it green, and **never** run `sungen contract approve` — approving is a QA's decision, on a terminal. **Exit 0 with `review`** → list it for the QA: review blocks `sungen delivery` until QA re-approves. **Exit 1** → report the error. No lock → skip: every scenario is `proposed`, which never blocks.
274
274
  9. **Phase 8 — Serial-cascade risk check** (#414): If any scenario has many steps, a skipped test may cause downstream steps to be incorrectly skipped due to the serial-cascade sensor detecting false "not reached" conditions. When you see "test skipped" messages during Phase 3–4 runs, check if the skipped scenario is a **blockers-exist** dependency in the test ledger (`sungen ledger query --screen <name>`). If the scenario had high step count and cascade fired, offer: *"Scenarios with deep steps can trigger serial-cascade skipping. Consider parallelizing this spec with `@concurrent` tags or breaking into smaller scenarios."* Let the user decide whether to refactor (do not auto-apply parallelization).
@@ -0,0 +1,11 @@
1
+ <!-- sungen:waiting-for-you v1 -->
2
+ ## Waiting for you — the commands only the QA runs
3
+
4
+ Right before the hand-back question, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
5
+ block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
6
+ sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
7
+ the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one in
8
+ their own terminal — in Claude Code, type `! <command>` in the prompt (a `/sungen:…` command is typed
9
+ as is). **Never run them yourself**, and never pipe or type a confirmation into them. When `sungen next`
10
+ prints no such block, say that nothing is waiting for the QA.
11
+ <!-- /sungen:waiting-for-you -->
@@ -0,0 +1,11 @@
1
+ <!-- sungen:waiting-for-you v1 -->
2
+ ## Waiting for you — the commands only the QA runs
3
+
4
+ Right before the hand-back list, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
5
+ block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
6
+ sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
7
+ the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one
8
+ themselves, in their own terminal (a slash command is typed as is). **Never run them yourself**, and
9
+ never pipe or type a confirmation into them. When `sungen next` prints no such block, say that nothing
10
+ is waiting for the QA.
11
+ <!-- /sungen:waiting-for-you -->
@@ -0,0 +1,11 @@
1
+ <!-- sungen:waiting-for-you v1 -->
2
+ ## Waiting for you — the commands only the QA runs
3
+
4
+ Right before the hand-back list, run `sungen next {{unitArg}}` and quote its **⏳ Waiting for you**
5
+ block **verbatim** — every command exactly as printed, each with its reason. Those commands approve,
6
+ sign off, waive, classify a red, accept in-run decisions or re-run once the environment is up: they are
7
+ the QA's alone, and most refuse without a person typing a confirmation. Tell the QA to run each one
8
+ themselves, in their own terminal (a slash command is typed as is). **Never run them yourself**, and
9
+ never pipe or type a confirmation into them. When `sungen next` prints no such block, say that nothing
10
+ is waiting for the QA.
11
+ <!-- /sungen:waiting-for-you -->