@opengsd/gsd-path 1.5.0 → 1.6.0

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 (352) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/DOCS.md +4 -3
  3. package/FULL.md +64 -4
  4. package/HOOKS.md +63 -2
  5. package/MIGRATE.md +12 -0
  6. package/QUICK.md +4 -2
  7. package/README.md +67 -15
  8. package/RUNTIME.md +23 -5
  9. package/UPDATE.md +35 -0
  10. package/WORKFLOW.md +58 -3
  11. package/package.json +1 -1
  12. package/scripts/_common.py +107 -1
  13. package/scripts/build_recovery.py +62 -30
  14. package/scripts/build_state.py +195 -5
  15. package/scripts/check_handoffs.py +92 -30
  16. package/scripts/check_task_briefs.py +19 -14
  17. package/scripts/detect_project.py +17 -2
  18. package/scripts/discussion_records.py +9 -1
  19. package/scripts/discussion_validate.py +7 -6
  20. package/scripts/dispatch_driver.py +157 -31
  21. package/scripts/git_guard.py +24 -5
  22. package/scripts/guard_hook.py +1216 -47
  23. package/scripts/install.mjs +76 -3
  24. package/scripts/install.py +182 -37
  25. package/scripts/integration.py +98 -64
  26. package/scripts/isolation.py +148 -11
  27. package/scripts/members.py +68 -25
  28. package/scripts/migrate_core.py +2 -0
  29. package/scripts/model_policy.py +5 -1
  30. package/scripts/pipeline_diagnose.py +17 -2
  31. package/scripts/pipeline_git.py +68 -30
  32. package/scripts/pipeline_state.py +28 -6
  33. package/scripts/pipeline_undo.py +17 -8
  34. package/scripts/promote_lookahead.py +3 -3
  35. package/scripts/review_findings.py +180 -44
  36. package/scripts/roadmap.py +9 -1
  37. package/scripts/runtime_store.py +1 -0
  38. package/scripts/state_checkpoint.py +30 -9
  39. package/scripts/state_promote.py +15 -4
  40. package/scripts/task_context.py +2 -0
  41. package/scripts/workflow_run.py +9 -2
  42. package/skills/gsd-path/DEFINE.md +6 -2
  43. package/skills/gsd-path/PLAN.md +3 -0
  44. package/skills/gsd-path/ROADMAP.md +16 -6
  45. package/skills/gsd-path/SHIP.md +26 -4
  46. package/skills/gsd-path/SKILL.md +52 -24
  47. package/skills/gsd-path/references/build-native.md +96 -9
  48. package/skills/gsd-path/references/build-recovery.md +13 -0
  49. package/skills/gsd-path/references/coder.md +7 -3
  50. package/skills/gsd-path/references/operating-rules.md +11 -3
  51. package/skills/gsd-path/references/planner.md +13 -1
  52. package/skills/gsd-path/references/reviewer-final.md +5 -5
  53. package/skills/gsd-path/references/reviewer-wave.md +46 -13
  54. package/skills/gsd-path/references/runtime-selection.md +9 -0
  55. package/skills/gsd-path/scripts/_common.py +107 -1
  56. package/skills/gsd-path/scripts/build_recovery.py +62 -30
  57. package/skills/gsd-path/scripts/build_state.py +195 -5
  58. package/skills/gsd-path/scripts/check_handoffs.py +92 -30
  59. package/skills/gsd-path/scripts/check_task_briefs.py +19 -14
  60. package/skills/gsd-path/scripts/detect_project.py +17 -2
  61. package/skills/gsd-path/scripts/discussion_records.py +9 -1
  62. package/skills/gsd-path/scripts/discussion_validate.py +7 -6
  63. package/skills/gsd-path/scripts/dispatch_driver.py +157 -31
  64. package/skills/gsd-path/scripts/git_guard.py +24 -5
  65. package/skills/gsd-path/scripts/integration.py +98 -64
  66. package/skills/gsd-path/scripts/isolation.py +148 -11
  67. package/skills/gsd-path/scripts/members.py +68 -25
  68. package/skills/gsd-path/scripts/model_policy.py +5 -1
  69. package/skills/gsd-path/scripts/pipeline_git.py +68 -30
  70. package/skills/gsd-path/scripts/pipeline_state.py +28 -6
  71. package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
  72. package/skills/gsd-path/scripts/review_findings.py +180 -44
  73. package/skills/gsd-path/scripts/roadmap.py +9 -1
  74. package/skills/gsd-path/scripts/state_checkpoint.py +30 -9
  75. package/skills/gsd-path/scripts/state_promote.py +15 -4
  76. package/skills/gsd-path/scripts/task_context.py +2 -0
  77. package/skills/gsd-path/scripts/workflow_run.py +9 -2
  78. package/skills/gsd-path/templates/final-review.md +5 -5
  79. package/skills/gsd-path/templates/state.md +1 -0
  80. package/skills/gsd-path/templates/task.md +1 -0
  81. package/skills/gsd-path/templates/wave-review.md +18 -9
  82. package/skills/gsd-path-build/references/build-native.md +96 -9
  83. package/skills/gsd-path-build/references/build-recovery.md +13 -0
  84. package/skills/gsd-path-build/references/coder.md +7 -3
  85. package/skills/gsd-path-build/references/operating-rules.md +11 -3
  86. package/skills/gsd-path-build/references/reviewer-final.md +5 -5
  87. package/skills/gsd-path-build/references/reviewer-wave.md +46 -13
  88. package/skills/gsd-path-build/references/runtime-selection.md +9 -0
  89. package/skills/gsd-path-build/scripts/_common.py +107 -1
  90. package/skills/gsd-path-build/scripts/build_recovery.py +62 -30
  91. package/skills/gsd-path-build/scripts/build_state.py +195 -5
  92. package/skills/gsd-path-build/scripts/check_handoffs.py +92 -30
  93. package/skills/gsd-path-build/scripts/check_task_briefs.py +19 -14
  94. package/skills/gsd-path-build/scripts/detect_project.py +17 -2
  95. package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
  96. package/skills/gsd-path-build/scripts/discussion_validate.py +7 -6
  97. package/skills/gsd-path-build/scripts/dispatch_driver.py +157 -31
  98. package/skills/gsd-path-build/scripts/integration.py +98 -64
  99. package/skills/gsd-path-build/scripts/isolation.py +148 -11
  100. package/skills/gsd-path-build/scripts/members.py +68 -25
  101. package/skills/gsd-path-build/scripts/model_policy.py +5 -1
  102. package/skills/gsd-path-build/scripts/pipeline_git.py +68 -30
  103. package/skills/gsd-path-build/scripts/pipeline_state.py +28 -6
  104. package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
  105. package/skills/gsd-path-build/scripts/review_findings.py +180 -44
  106. package/skills/gsd-path-build/scripts/roadmap.py +9 -1
  107. package/skills/gsd-path-build/scripts/state_checkpoint.py +30 -9
  108. package/skills/gsd-path-build/scripts/state_promote.py +15 -4
  109. package/skills/gsd-path-build/scripts/task_context.py +2 -0
  110. package/skills/gsd-path-build/scripts/workflow_run.py +9 -2
  111. package/skills/gsd-path-build/templates/task.md +1 -0
  112. package/skills/gsd-path-build/templates/wave-review.md +18 -9
  113. package/skills/gsd-path-decide/references/operating-rules.md +11 -3
  114. package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
  115. package/skills/gsd-path-decide/scripts/_common.py +107 -1
  116. package/skills/gsd-path-decide/scripts/build_recovery.py +62 -30
  117. package/skills/gsd-path-decide/scripts/check_handoffs.py +92 -30
  118. package/skills/gsd-path-decide/scripts/check_task_briefs.py +19 -14
  119. package/skills/gsd-path-decide/scripts/detect_project.py +17 -2
  120. package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
  121. package/skills/gsd-path-decide/scripts/discussion_validate.py +7 -6
  122. package/skills/gsd-path-decide/scripts/integration.py +98 -64
  123. package/skills/gsd-path-decide/scripts/isolation.py +148 -11
  124. package/skills/gsd-path-decide/scripts/members.py +68 -25
  125. package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
  126. package/skills/gsd-path-decide/scripts/pipeline_git.py +68 -30
  127. package/skills/gsd-path-decide/scripts/pipeline_state.py +28 -6
  128. package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
  129. package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
  130. package/skills/gsd-path-decide/scripts/state_checkpoint.py +30 -9
  131. package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
  132. package/skills/gsd-path-define/SKILL.md +6 -2
  133. package/skills/gsd-path-define/references/build-recovery.md +13 -0
  134. package/skills/gsd-path-define/references/operating-rules.md +11 -3
  135. package/skills/gsd-path-define/references/runtime-selection.md +9 -0
  136. package/skills/gsd-path-define/scripts/_common.py +107 -1
  137. package/skills/gsd-path-define/scripts/build_recovery.py +62 -30
  138. package/skills/gsd-path-define/scripts/check_handoffs.py +92 -30
  139. package/skills/gsd-path-define/scripts/check_task_briefs.py +19 -14
  140. package/skills/gsd-path-define/scripts/detect_project.py +17 -2
  141. package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
  142. package/skills/gsd-path-define/scripts/discussion_validate.py +7 -6
  143. package/skills/gsd-path-define/scripts/integration.py +98 -64
  144. package/skills/gsd-path-define/scripts/isolation.py +148 -11
  145. package/skills/gsd-path-define/scripts/members.py +68 -25
  146. package/skills/gsd-path-define/scripts/model_policy.py +5 -1
  147. package/skills/gsd-path-define/scripts/pipeline_git.py +68 -30
  148. package/skills/gsd-path-define/scripts/pipeline_state.py +28 -6
  149. package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
  150. package/skills/gsd-path-define/scripts/roadmap.py +9 -1
  151. package/skills/gsd-path-define/scripts/state_checkpoint.py +30 -9
  152. package/skills/gsd-path-define/scripts/state_promote.py +15 -4
  153. package/skills/gsd-path-define/templates/state.md +1 -0
  154. package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
  155. package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
  156. package/skills/gsd-path-discuss/scripts/_common.py +107 -1
  157. package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
  158. package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
  159. package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
  160. package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
  161. package/skills/gsd-path-docs-audit/scripts/_common.py +107 -1
  162. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +62 -30
  163. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +92 -30
  164. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +19 -14
  165. package/skills/gsd-path-docs-audit/scripts/detect_project.py +17 -2
  166. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
  167. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +7 -6
  168. package/skills/gsd-path-docs-audit/scripts/integration.py +98 -64
  169. package/skills/gsd-path-docs-audit/scripts/isolation.py +148 -11
  170. package/skills/gsd-path-docs-audit/scripts/members.py +68 -25
  171. package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
  172. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +68 -30
  173. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +28 -6
  174. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
  175. package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
  176. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +30 -9
  177. package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
  178. package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
  179. package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
  180. package/skills/gsd-path-forensics/scripts/_common.py +107 -1
  181. package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
  182. package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
  183. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
  184. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +17 -8
  185. package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
  186. package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
  187. package/skills/gsd-path-inspect/scripts/_common.py +107 -1
  188. package/skills/gsd-path-inspect/scripts/build_recovery.py +62 -30
  189. package/skills/gsd-path-inspect/scripts/check_handoffs.py +92 -30
  190. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +19 -14
  191. package/skills/gsd-path-inspect/scripts/detect_project.py +17 -2
  192. package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
  193. package/skills/gsd-path-inspect/scripts/discussion_validate.py +7 -6
  194. package/skills/gsd-path-inspect/scripts/integration.py +98 -64
  195. package/skills/gsd-path-inspect/scripts/isolation.py +148 -11
  196. package/skills/gsd-path-inspect/scripts/members.py +68 -25
  197. package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
  198. package/skills/gsd-path-inspect/scripts/pipeline_git.py +68 -30
  199. package/skills/gsd-path-inspect/scripts/pipeline_state.py +28 -6
  200. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
  201. package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
  202. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +30 -9
  203. package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
  204. package/skills/gsd-path-inspect/scripts/workflow_run.py +9 -2
  205. package/skills/gsd-path-inspect/templates/state.md +1 -0
  206. package/skills/gsd-path-loop/references/operating-rules.md +11 -3
  207. package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
  208. package/skills/gsd-path-loop/scripts/_common.py +107 -1
  209. package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
  210. package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
  211. package/skills/gsd-path-migrate/SKILL.md +8 -0
  212. package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
  213. package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
  214. package/skills/gsd-path-migrate/scripts/_common.py +107 -1
  215. package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
  216. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
  217. package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
  218. package/skills/gsd-path-plan/SKILL.md +3 -0
  219. package/skills/gsd-path-plan/references/build-recovery.md +13 -0
  220. package/skills/gsd-path-plan/references/operating-rules.md +11 -3
  221. package/skills/gsd-path-plan/references/planner.md +13 -1
  222. package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
  223. package/skills/gsd-path-plan/scripts/_common.py +107 -1
  224. package/skills/gsd-path-plan/scripts/build_recovery.py +62 -30
  225. package/skills/gsd-path-plan/scripts/check_handoffs.py +92 -30
  226. package/skills/gsd-path-plan/scripts/check_task_briefs.py +19 -14
  227. package/skills/gsd-path-plan/scripts/detect_project.py +17 -2
  228. package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
  229. package/skills/gsd-path-plan/scripts/discussion_validate.py +7 -6
  230. package/skills/gsd-path-plan/scripts/integration.py +98 -64
  231. package/skills/gsd-path-plan/scripts/isolation.py +148 -11
  232. package/skills/gsd-path-plan/scripts/members.py +68 -25
  233. package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
  234. package/skills/gsd-path-plan/scripts/pipeline_git.py +68 -30
  235. package/skills/gsd-path-plan/scripts/pipeline_state.py +28 -6
  236. package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
  237. package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
  238. package/skills/gsd-path-plan/scripts/state_checkpoint.py +30 -9
  239. package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
  240. package/skills/gsd-path-plan/scripts/workflow_run.py +9 -2
  241. package/skills/gsd-path-plan/templates/task.md +1 -0
  242. package/skills/gsd-path-research/references/operating-rules.md +11 -3
  243. package/skills/gsd-path-research/references/runtime-selection.md +9 -0
  244. package/skills/gsd-path-research/scripts/_common.py +107 -1
  245. package/skills/gsd-path-research/scripts/build_recovery.py +62 -30
  246. package/skills/gsd-path-research/scripts/check_handoffs.py +92 -30
  247. package/skills/gsd-path-research/scripts/check_task_briefs.py +19 -14
  248. package/skills/gsd-path-research/scripts/detect_project.py +17 -2
  249. package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
  250. package/skills/gsd-path-research/scripts/discussion_validate.py +7 -6
  251. package/skills/gsd-path-research/scripts/integration.py +98 -64
  252. package/skills/gsd-path-research/scripts/isolation.py +148 -11
  253. package/skills/gsd-path-research/scripts/members.py +68 -25
  254. package/skills/gsd-path-research/scripts/model_policy.py +5 -1
  255. package/skills/gsd-path-research/scripts/pipeline_git.py +68 -30
  256. package/skills/gsd-path-research/scripts/pipeline_state.py +28 -6
  257. package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
  258. package/skills/gsd-path-research/scripts/roadmap.py +9 -1
  259. package/skills/gsd-path-research/scripts/state_checkpoint.py +30 -9
  260. package/skills/gsd-path-research/scripts/state_promote.py +15 -4
  261. package/skills/gsd-path-roadmap/SKILL.md +16 -6
  262. package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
  263. package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
  264. package/skills/gsd-path-roadmap/scripts/_common.py +107 -1
  265. package/skills/gsd-path-roadmap/scripts/build_recovery.py +62 -30
  266. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +92 -30
  267. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +19 -14
  268. package/skills/gsd-path-roadmap/scripts/detect_project.py +17 -2
  269. package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
  270. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +7 -6
  271. package/skills/gsd-path-roadmap/scripts/integration.py +98 -64
  272. package/skills/gsd-path-roadmap/scripts/isolation.py +148 -11
  273. package/skills/gsd-path-roadmap/scripts/members.py +68 -25
  274. package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
  275. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +68 -30
  276. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +28 -6
  277. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
  278. package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
  279. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +30 -9
  280. package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
  281. package/skills/gsd-path-ship/SKILL.md +26 -4
  282. package/skills/gsd-path-ship/references/operating-rules.md +11 -3
  283. package/skills/gsd-path-ship/references/reviewer-final.md +5 -5
  284. package/skills/gsd-path-ship/references/reviewer-wave.md +46 -13
  285. package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
  286. package/skills/gsd-path-ship/scripts/_common.py +107 -1
  287. package/skills/gsd-path-ship/scripts/build_recovery.py +62 -30
  288. package/skills/gsd-path-ship/scripts/build_state.py +195 -5
  289. package/skills/gsd-path-ship/scripts/check_handoffs.py +92 -30
  290. package/skills/gsd-path-ship/scripts/check_task_briefs.py +19 -14
  291. package/skills/gsd-path-ship/scripts/detect_project.py +17 -2
  292. package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
  293. package/skills/gsd-path-ship/scripts/discussion_validate.py +7 -6
  294. package/skills/gsd-path-ship/scripts/integration.py +98 -64
  295. package/skills/gsd-path-ship/scripts/isolation.py +148 -11
  296. package/skills/gsd-path-ship/scripts/members.py +68 -25
  297. package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
  298. package/skills/gsd-path-ship/scripts/pipeline_git.py +68 -30
  299. package/skills/gsd-path-ship/scripts/pipeline_state.py +28 -6
  300. package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
  301. package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
  302. package/skills/gsd-path-ship/scripts/state_checkpoint.py +30 -9
  303. package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
  304. package/skills/gsd-path-ship/scripts/workflow_run.py +9 -2
  305. package/skills/gsd-path-ship/templates/final-review.md +5 -5
  306. package/skills/gsd-path-ship/templates/wave-review.md +18 -9
  307. package/skills/gsd-path-undo/references/operating-rules.md +11 -3
  308. package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
  309. package/skills/gsd-path-undo/scripts/_common.py +107 -1
  310. package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
  311. package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
  312. package/skills/gsd-path-undo/scripts/pipeline_undo.py +17 -8
  313. package/skills/path/DEFINE.md +6 -2
  314. package/skills/path/PLAN.md +3 -0
  315. package/skills/path/ROADMAP.md +16 -6
  316. package/skills/path/SHIP.md +26 -4
  317. package/skills/path/SKILL.md +52 -24
  318. package/skills/path/references/build-native.md +96 -9
  319. package/skills/path/references/build-recovery.md +13 -0
  320. package/skills/path/references/coder.md +7 -3
  321. package/skills/path/references/operating-rules.md +11 -3
  322. package/skills/path/references/planner.md +13 -1
  323. package/skills/path/references/reviewer-final.md +5 -5
  324. package/skills/path/references/reviewer-wave.md +46 -13
  325. package/skills/path/references/runtime-selection.md +9 -0
  326. package/skills/path/scripts/_common.py +107 -1
  327. package/skills/path/scripts/build_recovery.py +62 -30
  328. package/skills/path/scripts/build_state.py +195 -5
  329. package/skills/path/scripts/check_handoffs.py +92 -30
  330. package/skills/path/scripts/check_task_briefs.py +19 -14
  331. package/skills/path/scripts/detect_project.py +17 -2
  332. package/skills/path/scripts/discussion_records.py +9 -1
  333. package/skills/path/scripts/discussion_validate.py +7 -6
  334. package/skills/path/scripts/dispatch_driver.py +157 -31
  335. package/skills/path/scripts/git_guard.py +24 -5
  336. package/skills/path/scripts/integration.py +98 -64
  337. package/skills/path/scripts/isolation.py +148 -11
  338. package/skills/path/scripts/members.py +68 -25
  339. package/skills/path/scripts/model_policy.py +5 -1
  340. package/skills/path/scripts/pipeline_git.py +68 -30
  341. package/skills/path/scripts/pipeline_state.py +28 -6
  342. package/skills/path/scripts/promote_lookahead.py +3 -3
  343. package/skills/path/scripts/review_findings.py +180 -44
  344. package/skills/path/scripts/roadmap.py +9 -1
  345. package/skills/path/scripts/state_checkpoint.py +30 -9
  346. package/skills/path/scripts/state_promote.py +15 -4
  347. package/skills/path/scripts/task_context.py +2 -0
  348. package/skills/path/scripts/workflow_run.py +9 -2
  349. package/skills/path/templates/final-review.md +5 -5
  350. package/skills/path/templates/state.md +1 -0
  351. package/skills/path/templates/task.md +1 -0
  352. package/skills/path/templates/wave-review.md +18 -9
@@ -128,6 +128,10 @@ dispatch contract and perform steps 1–5 by hand.
128
128
  rerun `recover`. The original lineage must stay reachable: keep a local
129
129
  branch on the old tip until the milestone ships. Adopted tasks report
130
130
  `attested` with `provenance: owner-authorized-rebase`.
131
+ - `block` with a `leftover` path: the task is landed, and that path is what
132
+ a failed removal left of its isolate; it holds nothing that Git does not
133
+ have. Do not set `build/blocked`. Stop with the returned reason; after
134
+ the path is removed, rerun `recover`.
131
135
  - `block` for any other reason: set `build/blocked` with the returned
132
136
  reason and stop.
133
137
  - `none`: take no recovery action for that task.
@@ -142,6 +146,13 @@ dispatch contract and perform steps 1–5 by hand.
142
146
  order, or overlap-check tasks in prose. Readiness is continuous, not
143
147
  layered: a task becomes selectable the moment its last dependency lands,
144
148
  even while unrelated tasks still run, so rerun `ready` after each landing.
149
+ Two tasks that each share a file with the same `done` task of an earlier
150
+ wave never run together: `ready` returns one and holds the other until the
151
+ first is `done`. The second then starts from a base that has the first
152
+ landing, and the step 5 rerun of the earlier Verify checks both edits. A
153
+ task with a retained isolate keeps its turn. A task that a `supersedes`
154
+ field retires still counts: the superseding task never runs together
155
+ with a task that shares a file with the superseded task.
145
156
  A `NEEDS-ORCHESTRATOR` block stays unselectable until its `Orchestrator
146
157
  answer` is recorded in the task Log and the task is back to `pending`.
147
158
  An all-done wave whose latest canonical review cycle has any blocked lens
@@ -151,6 +162,11 @@ dispatch contract and perform steps 1–5 by hand.
151
162
  repair remains, `ready` returns no tasks and adds `blocked_review` (`wave`,
152
163
  `cycle`, `waiting_waves`); a later passing canonical review cycle releases
153
164
  the waiting waves.
165
+ `unreviewed_waves`, when present, lists earlier waves whose tasks are all
166
+ `done` and that have no canonical review file. A repair wave is not
167
+ listed: the next review cycle of its source wave judges it. `ready` reports
168
+ the listed waves and does not hold the returned tasks: run step 6 for each
169
+ listed wave before you dispatch.
154
170
  Its typed errors are the recovery rule:
155
171
  - `task-recovery-required`: for each listed failed or blocked task run
156
172
  `python3 <absolute build_state.py> reconcile --repo <absolute primary>
@@ -263,7 +279,8 @@ dispatch contract and perform steps 1–5 by hand.
263
279
  defective task contract before establishing the round base. Run ready work
264
280
  up to capacity. Verify commands marked `Heavy: yes` (`verify_heavy` in the
265
281
  ready set) run one at a time across every concurrent task, including the
266
- step 5 rerun; light ones are unconstrained. Do not wait for the whole
282
+ step 5 rerun; light ones are unconstrained. `verify_heavy` is also true
283
+ when step 5 reruns a heavy Verify of an earlier task. Do not wait for the whole
267
284
  round before unlocking dependents: each task landing in step 5 re-opens
268
285
  step 2, and a newly ready
269
286
  task dispatches in a fresh round at the current clean HEAD while unrelated
@@ -289,8 +306,35 @@ dispatch contract and perform steps 1–5 by hand.
289
306
  native child tools; no child command is needed. It reproduces serial work
290
307
  in its prepared sidecar, runs authoritative Verify, records exact output,
291
308
  lands through `isolation.py`, records eligible ledger evidence, and retires
292
- the isolate. A `landed` receipt proves those steps; do not run them again
293
- or author another implementation narrative. A blocked receipt preserves
309
+ the isolate. Authoritative Verify is the task's own Verify, then the
310
+ Verify of each `done` task of an earlier wave, in the same repo, that
311
+ shares a declared file with this task. `finish` selects those commands;
312
+ never select them by hand. An earlier command does not run again in two
313
+ cases only: it is identical to the own Verify, or the own Verify is the
314
+ unchanged Verify that `fix-tasks` wrote from the task's `deps` and the
315
+ command belongs to one of them. A Verify that only contains the command
316
+ text does not replace the rerun. A failed earlier-task Verify blocks the landing as a
317
+ failed own Verify does. The receipt (`regressions`) and the task Log
318
+ entry `orchestrator regression Verify of <task id>` name the earlier
319
+ task. The ledger records only the own command.
320
+ A plan-approved `supersedes` field retires the Verify of each earlier
321
+ task that it names: `finish` does not run that Verify for the task, or
322
+ for a task that lands after the task is `done`. The receipt (`retired`)
323
+ and the task Log entry `orchestrator regression Verify of <task id>
324
+ retired: superseded by <task id>` name both tasks. When the generated
325
+ Verify of a fix task loses only the copy of a retired Verify, the
326
+ `retired` entry has the key `part` and the Log entry is `orchestrator
327
+ regression Verify of <fix task id>: part of <task id> retired:
328
+ superseded by <task id>`. The superseding
329
+ task inherits the role of each task that it names, also through a
330
+ chain: after it is `done`, its Verify runs in the place of the retired
331
+ Verify for each later landing that shares a file with a superseded
332
+ task, also in its own wave. The Log entry is `orchestrator regression
333
+ Verify of <task id> (supersedes <task id>)`.
334
+ A `landed` receipt proves those steps; do not run them again
335
+ or author another implementation narrative. A `cleanup_warning` on a
336
+ landing means only that the isolate was not removed: the task is landed,
337
+ and the next `round` or `finish` checks the isolate again. A blocked receipt preserves
294
338
  its failure evidence and follows the recovery rule, never a manual bypass.
295
339
  Keep the pre-finish declared-path check above. Each landing re-opens step 2
296
340
  so ready dependents can run while unrelated children remain in flight.
@@ -503,26 +547,69 @@ dispatch contract and perform steps 1–5 by hand.
503
547
  again.
504
548
  - Otherwise batch `fix_batches` into complete fix tasks from the task
505
549
  template — one task per batch, never one per finding — each carrying
506
- its groups' failed criteria and observed evidence verbatim. A group
550
+ its groups' failed criteria and observed evidence verbatim. Each batch
551
+ is in one repo: a batch with `repo` is for that member and its fix task
552
+ has `repo: <member>`; a batch without `repo` is for the coordinator. A
553
+ finding whose source tasks are in two repos gives one batch for each
554
+ repo. A group
507
555
  with `repeat` true is evidence its earlier fix failed, never a new
508
556
  finding; a re-review never spawns a duplicate fix task for a finding
509
- already carried. Write each fix task to `.project/tasks/` with `wave`
557
+ that a fix task not yet `done` already carries in the same repo. A
558
+ repeat after its fix
559
+ landed gets the next fix task. After a build recovery, a changed wave
560
+ is reviewed again from cycle 1; the fix tasks and PLAN.md repair wave
561
+ of the review that recovery set aside do not count for the new one.
562
+ Write each fix task to `.project/tasks/` with `wave`
510
563
  set to the current wave or a newly appended `## Wave N` heading in
511
- PLAN.md before dispatch. Its dependencies include every source task in
512
- the batch; its files match the batch. In `## Review findings`, use one
564
+ PLAN.md before dispatch. Its dependencies include every source task of
565
+ the batch that is in the same repo, and every landed fix task of the
566
+ same source wave and repo that carried one of its findings; its Verify
567
+ runs the Verify of those source tasks; its files are the batch files or a subset of them, never
568
+ none. When a finding names a fix site outside the batch files, follow
569
+ [build recovery](build-recovery.md) to plan, which adds a repair task
570
+ with those files, the batch's `## Review findings` and the same
571
+ dependencies; `repair-evidence` accepts that task. In
572
+ `## Review findings`, use one
513
573
  `### <locator>` block per group, `Criterion: <verbatim criterion>`, and
514
574
  every observation verbatim. Run the repair through the same isolated
515
575
  layer loop, even when its appended wave repairs an earlier blocked wave.
576
+ An appended repair wave has the highest wave number and still runs before
577
+ the pending waves, because `ready` gates them on the blocked wave (step
578
+ 2). Do not renumber waves or move the repair wave.
516
579
  After landing, call `review_findings.py repair-evidence --repo <primary>
517
580
  --wave <source wave> --cycle <source cycle> --task <repair id>` and save
518
- its JSON as the repair evidence for the next review. The helper validates
581
+ its JSON as the repair evidence for the next review. The helper selects
582
+ the batch by the repair's locators and repo, then validates
519
583
  the carried batch, original and repair landings, isolated product scope,
520
- unchanged source reports and reusable Verify. On success, brief the next
584
+ unchanged source reports and reusable Verify. For a member repair it
585
+ checks the product in the member repository, against the member commits
586
+ and the member Verify record, and the receipt adds `member`,
587
+ `member_base` and `member_commit`. Another change to the checked files
588
+ is accepted only when it is the landing of a linked repair: a `done`
589
+ task of the same repo that carries one of the repair's findings in
590
+ `## Review findings`, with the same locator and criterion, and is
591
+ joined to the repair by `deps`. A finding on an acceptance criterion of
592
+ a fix task counts as the finding that this fix task carries with the
593
+ same criterion; the same criterion text under another locator is
594
+ another finding. Linked
595
+ repairs in the repair base are in `earlier_repairs`. Linked repairs
596
+ after the repair are in `later_repairs`; then the landing and the
597
+ recorded Verify of the last one are the evidence, and `chain_files`
598
+ lists the files checked from the repair base to the tip: those of the
599
+ repair and of every later linked repair. From the repair base to the
600
+ parent of the repair landing, no landing can change these files, also
601
+ not a linked one. On success, brief the next
521
602
  original-wave review with this receipt and the reviewer role's
522
603
  **Re-review after a proven repair** contract. Reuse command evidence;
523
604
  the new review judges the repaired product against the original criteria.
524
605
  Preserve prior verdicts and source tasks. On helper rejection, resolve
525
606
  the evidence blocker rather than redispatching an already proven fix.
607
+ When the blocker cannot be resolved, for example `repair base contains
608
+ unlinked changes to original product` or `product changed after the
609
+ repair landing` because a task that is not a linked repair changed the
610
+ same files, run the next review cycle of the source wave in full at the
611
+ current HEAD, without the receipt. This is the supported fallback: it
612
+ needs no ruling and no plan change.
526
613
  At the cap, record all attempts in the STATE.md log and ask the user —
527
614
  through an interactive user-input tool when available — after linking
528
615
  the resolved absolute blocking wave review, every deep lens file for the
@@ -69,6 +69,19 @@ checks landed-task preservation and restored intent ownership, restores review
69
69
  evidence only for unchanged contracts, and creates the normal journaled plan
70
70
  checkpoint. A failed approval leaves recovery open.
71
71
 
72
+ A wave keeps its review evidence when INTENT.md, its own `## Wave N` section,
73
+ its task files, and every other non-wave PLAN.md section are byte-identical to
74
+ the recovery base. Two edits are exempt: the value of the `max_review_cycles`
75
+ and `wave_budget` lines in `## Config`, and all of `## Dependency notes`. In
76
+ `## Config` only those two values may change; any other edit there, a comment
77
+ edit included, drops the evidence of every wave, as does any other non-wave
78
+ edit. A `- review_panel:` line that is added, removed, or changed anywhere in
79
+ PLAN.md also drops the evidence of every wave. The approval result reports
80
+ this in `recovery_reviews`: `restored` lists the waves that kept their evidence, and
81
+ `review_again` lists each wave that lost it, with the reason. Review every
82
+ `review_again` wave again after build resumes; completion refuses a wave
83
+ without a passing review.
84
+
72
85
  Return through `plan/done → build/active` with event `build started`. The dispatch
73
86
  driver uses a separate record directory for this recovery base, while retaining
74
87
  the milestone budget ledger. Resume only from the new approved task inventory.
@@ -51,9 +51,13 @@ costs the run.
51
51
  2. Satisfy every acceptance criterion and every owned INTENT success
52
52
  criterion within the Approach constraints, matching conventions in the
53
53
  listed files.
54
- 3. Edit only exact paths in `files`, plus the task file's Log. There is no
55
- exception for imports, routes, generated files, or wiring.
56
- 4. Run Verify. Fix failures only within the allowed paths.
54
+ 3. Edit only paths in `files`, plus the task file's Log. A declared
55
+ directory covers the files below it; a declared file covers only itself.
56
+ There is no exception for imports, routes, generated files, or wiring.
57
+ 4. Run Verify. Fix failures only within the allowed paths. The orchestrator
58
+ also runs the Verify of each earlier-wave task that shares a file with
59
+ yours. A Log entry `orchestrator regression Verify of <task id>` with
60
+ `fail` names a task you broke; make its Verify pass too.
57
61
  5. Append the implementation and Verify result to Log. On a block, append the
58
62
  specific reason. Do not edit frontmatter state.
59
63
 
@@ -38,8 +38,8 @@ bundles this file; spawned agents follow their role brief instead.
38
38
  the lookahead planning track for the next milestone; it follows the same
39
39
  marker rule, owns no task frontmatter, and never binds a branch.
40
40
  - STATE.integration_default is the project closeout choice and
41
- STATE.integration is the current milestone choice. Both are `direct` or
42
- `pull-request`; STATE.integration_source is `default` or `milestone` and
41
+ STATE.integration is the current milestone choice. Both are `direct`,
42
+ `pull-request`, or `external-landing`; STATE.integration_source is `default` or `milestone` and
43
43
  preserves explicit override provenance. Older v2 state defaults to `direct`,
44
44
  and modes may be changed only through `pipeline_state.py
45
45
  configure-integration` before build. A next milestone resets its current
@@ -82,7 +82,9 @@ bundles this file; spawned agents follow their role brief instead.
82
82
  `isolation.py attest` may stand in for it: one `.project/`-only commit that
83
83
  names the base, the attested HEAD, the declared files that changed, the
84
84
  task Verify recorded as passing at that HEAD, and the ruling verbatim.
85
- `recover` reports it as `attested`, never as a proven landing.
85
+ `recover` reports it as `attested`, never as a proven landing. Attestation
86
+ matches the declared files literally: work that is only below a declared
87
+ directory can land but cannot be attested.
86
88
  - All pipeline work for a milestone lives on `gsd-path/M00N` (M001, M002,
87
89
  …) bound in STATE.branch. The next milestone binds a new unused
88
90
  `gsd-path/M00N` at the remote default after the previous ship integrates.
@@ -90,6 +92,12 @@ bundles this file; spawned agents follow their role brief instead.
90
92
  branch — either Path's direct merge or a Path-owned PR merged by the user.
91
93
  The bound branch never receives merges or back-merges and is never the
92
94
  GitHub default.
95
+ - The default branch is the one that STATE `default_branch` records at
96
+ initialization; a STATE file without the field means `main`. `main` and
97
+ `origin/main` in these rules mean that branch. Never change the record and
98
+ never take the name from a later `origin/HEAD` lookup. For a member
99
+ repository, the branch is the one that its `.project/MEMBERS.md` section
100
+ records as `Default branch`; a section without the field means `main`.
93
101
  - After initialization writes STATE.md, and before entering the first pipeline
94
102
  phase in an existing Git repository, the router calls
95
103
  `scripts/pipeline_git.py bind-initial` with the selected M00N and exact
@@ -83,7 +83,7 @@ plan order above, which still keeps plan-invalidating risk in wave 1.
83
83
  owning task's Approach.
84
84
  - Make `files` exhaustive, including imports, routes, generated artifacts,
85
85
  tests, and wiring. Require disjoint files for same-wave tasks that are not
86
- dependency-ordered.
86
+ dependency-ordered. A declared directory overlaps every path below it.
87
87
  - Write an Interface contract in every task: `None` for independent tasks;
88
88
  for any tasks that exchange a symbol, signature, schema, endpoint, file
89
89
  format, or path, the exact shapes both sides code against — identical text
@@ -96,6 +96,18 @@ plan order above, which still keeps plan-invalidating risk in wave 1.
96
96
  this task's work is skipped. That command must name a path from `files`,
97
97
  and must not be PLAN.md's project Verify unless an SC this task owns names
98
98
  that command. Criteria and Verify are the contract; Approach is guidance.
99
+ A task that lists a file of an earlier-wave task must also pass that
100
+ task's Verify to land. When it changes that behavior on purpose, list the
101
+ tests that Verify runs in its `files`.
102
+ - Add `supersedes: [<task id>]` only when INTENT.md requires this task to
103
+ remove or replace behavior of an earlier-wave task, and that task's Verify
104
+ cannot pass after the change. The named task must be in an earlier wave,
105
+ in the same repo, and share a file with this task. Its Verify is then
106
+ retired: it does not run at this landing or at a later landing. State the
107
+ replacement in this task's acceptance criteria. This task's Verify then
108
+ runs in its place for each later task that shares a file with the named
109
+ task, so it must check the replacement behavior for all files of that
110
+ task.
99
111
  - In a multi-repo milestone (`.project/MEMBERS.md` lists members), each task
100
112
  changes exactly one repo. Give a member task `repo: <member>`; its `files`
101
113
  and Verify are relative to that member's root, and its Verify runs there.
@@ -1,11 +1,11 @@
1
1
  ## Final integration mode
2
2
 
3
3
  Use only final-review.md. Treat INTENT.md success criteria as the rubric.
4
- Each `### SCn —` heading must match the criterion text as
5
- `check_handoffs._success_criteria` stores it from INTENT.md `## Success
6
- criteria`: indented continuation lines join with a single space and keep
7
- their `- ` list markers; the gate compares titles with `_normalize_ws`
8
- only. Exercise the running system and record `met`, `not-met`, or
4
+ Each `### SCn —` heading must have every word of the criterion in INTENT.md
5
+ `## Success criteria`: join indented continuation lines and sub-bullets
6
+ with a single space. You can keep or remove the `- ` markers of the
7
+ sub-bullets; the gate compares every other word. Exercise the running
8
+ system and record `met`, `not-met`, or
9
9
  `unverifiable` with checked command output or a precise file reference.
10
10
  When PLAN.md carries
11
11
  a `## Surface contract`, every criterion it lists under a surface is checked
@@ -17,19 +17,21 @@ tasks in this wave as the rubric. For each task:
17
17
  criterion. Never use the primary worktree or branch tip as task
18
18
  evidence. Do not create or remove Git worktrees yourself.
19
19
  4. Mark `pass` or `fail`. Before the evidence separator (` — `), copy the
20
- complete task acceptance or interface criterion verbatim, joining wrapped
21
- lines with spaces. Do not substitute an AC id or summary: finding grouping
22
- binds this text to the task. Give the observed result, `file:line`, and
20
+ complete task acceptance or interface criterion (see Review file format
21
+ below). Do not substitute an AC id or summary: finding grouping binds
22
+ this text to the task. Give the observed result, `file:line`, and
23
23
  concrete fix direction for each failure.
24
24
 
25
+ A Log entry `orchestrator regression Verify of <task id> retired: superseded
26
+ by <task id>` is not evidence: judge the superseding task's acceptance
27
+ criteria. The same applies to the entry `orchestrator regression Verify of
28
+ <fix task id>: part of <task id> retired: superseded by <task id>`.
29
+
25
30
  Then check each INTENT.md success criterion owned by a task in this wave
26
31
  against that same isolated product. In each `### SCn —` heading, copy the
27
- criterion text exactly as `check_handoffs._success_criteria` stores it from
28
- INTENT.md `## Success criteria`: indented continuation lines are joined
29
- with a single space and keep their `- ` list markers in the compared text;
30
- only whitespace is normalized at the gate. Do not paraphrase or drop
31
- sub-bullets. Mark `pass` or `fail` with evidence; a failed owned SC blocks
32
- the wave. Omit the Intent coverage section when no task in the wave owns
32
+ complete criterion text from INTENT.md `## Success criteria` (see Review
33
+ file format below). Mark `pass` or `fail` with evidence; a failed owned SC
34
+ blocks the wave. Omit the Intent coverage section when no task in the wave owns
33
35
  an SC. When INTENT.md `## Edge coverage` or `## Prohibitions` has rows for
34
36
  an owned SC, judge it against those rulings too: cite each `held-out` edge
35
37
  id with its held-out test's recorded output and each `judgment` prohibition
@@ -48,6 +50,30 @@ For cycle greater than 1, read the previous review, re-check every failure,
48
50
  and regression-check affected passes. State when the same criterion fails for
49
51
  a different reason. Use only the wave-review template.
50
52
 
53
+ ### Review file format
54
+
55
+ `scripts/check_handoffs.py wave` rejects a review file that breaks one of
56
+ these rules, and `scripts/review_findings.py` cannot group a failure whose
57
+ criterion text does not match. Apply the rules before you write the file.
58
+
59
+ - **Section order.** Put the `## T### —` sections in task id order (T001
60
+ before T002). The order of the PLAN.md wave table does not apply. A `pass`
61
+ review has one section for each task of the wave.
62
+ - **Section heading.** Write `## T### — <title>: pass` or `: fail`, where
63
+ `<title>` is the exact `title:` value of the task file.
64
+ - **Evidence lines.** An evidence line starts with `- ✅ ` for pass or
65
+ `- ❌ ` for fail. Each task section and each `### SCn —` block needs one
66
+ or more lines with the marker of its own verdict. A failed task needs a
67
+ `- ❌ ` criterion line, also when other text describes the failure.
68
+ - **Criterion text.** In a task evidence line and in a `### SCn —` heading,
69
+ copy every word of the criterion. Join wrapped lines and sub-bullets with
70
+ one space. You can keep or remove the `- ` markers of the sub-bullets.
71
+ A changed, added, removed or moved word does not match.
72
+ - **Angle brackets.** Text such as `<b>` or `<path>` outside backticks reads
73
+ as an unfilled template placeholder and is rejected. Write literal markup
74
+ and code in backticks inside a sentence, for example: the output has
75
+ `<b>hello</b>`.
76
+
51
77
  ### Re-review after a proven repair
52
78
 
53
79
  When the brief supplies a `review_findings.py repair-evidence` receipt, use
@@ -55,14 +81,21 @@ its isolated repair product for the linked original criteria, including owned
55
81
  INTENT criteria. The original faulty landing and earlier verdicts remain
56
82
  historical evidence; they do not force the later verdict to remain failed.
57
83
  Reconstruct the receipt's repair `base` plus only its `commit^..commit` patch
58
- for `files` inside the supplied sidecar. Read the repair task's recorded
59
- Verify, inspect the patch against the original unchanged contract, and reuse
84
+ for `files` inside the supplied sidecar. For a member repair (the receipt
85
+ names `member`), use `member_base` and `member_commit` in that member's
86
+ repository. `earlier_repairs` are linked repairs of the same findings that
87
+ are already in the repair base. When the receipt has `later_repairs`, linked
88
+ repairs changed the same files after this repair: apply their patches in
89
+ order too. Read the repair task's recorded
90
+ Verify, or with `later_repairs` that of the last one, which is the receipt's
91
+ `verification`; inspect the patch against the original unchanged contract, and reuse
60
92
  settled checks. Check unaffected criteria from their prior evidence plus the
61
93
  repair diff for regressions. Cite the receipt, repair landing and task Log in
62
94
  the new review. A receipt proves provenance, not acceptance: judge whether the
63
95
  repair actually satisfies the criterion. A missing or rejected receipt blocks
64
- using that repair; the parent resolves it rather than creating another product
65
- fix for the unchanged historical failure.
96
+ using that repair; the parent resolves it, or briefs this review in full at
97
+ the current HEAD without a receipt, rather than creating another product fix
98
+ for the unchanged historical failure.
66
99
 
67
100
  ## Final scope in a quick full wave
68
101
 
@@ -20,6 +20,15 @@ references to bundled copies of those helpers. Other skill helpers, templates,
20
20
  and role briefs remain in the installed skill bundle. Pass `-B` to Python helper
21
21
  invocations so execution does not create bytecode in the runtime store.
22
22
 
23
+ The selected runtime is authoritative for each helper in its `manifest.json`;
24
+ this includes `review_findings.py` and `task_context.py`. A selected runtime
25
+ that was published before a helper became a runtime file does not list that
26
+ helper: run the bundled copy until the project runtime is upgraded.
27
+ `dispatch_driver.py` and `workflow_run.py` always run from the installed skill
28
+ bundle, because they read role briefs and templates from it; a skill update
29
+ replaces them, a runtime upgrade does not. The driver reloads the helper modules
30
+ that it imports from the selected runtime.
31
+
23
32
  With no declaration, retain the legacy helper lookup. An existing
24
33
  `.gsd-path/runtime/` requires the explicit `--runtime-migrate --project PATH`
25
34
  operation before adopting external storage; review the resulting Git diff.
@@ -25,7 +25,8 @@ import signal
25
25
  import subprocess
26
26
  import time
27
27
  from pathlib import Path
28
- from typing import BinaryIO, Iterator, List, Optional, Sequence
28
+ from typing import BinaryIO, Iterable, Iterator, List, Optional, Sequence, Tuple
29
+
29
30
 
30
31
  # Chosen by what imports, not os.name, so tests can emulate Windows on POSIX.
31
32
  try:
@@ -161,6 +162,33 @@ def project_ignore_error(repo: Path) -> Optional[str]:
161
162
  + ". Anchor the product rule (for example `/build/`) in a task that owns it.")
162
163
 
163
164
 
165
+ _DEFAULT_BRANCH_RE = re.compile(
166
+ r"[^\s#\"'\\~^:?*\[\x00-\x1f\x7f-][^\s#\"'\\~^:?*\[\x00-\x1f\x7f]*"
167
+ )
168
+ _RESERVED_BRANCH_PREFIXES = ("gsd-path/", "gsd-path-integrate/", "gsd-path-task/")
169
+
170
+
171
+ def valid_default_branch(name: str) -> bool:
172
+ """A git branch name that STATE frontmatter can hold and Path does not reserve."""
173
+ return (
174
+ bool(_DEFAULT_BRANCH_RE.fullmatch(name))
175
+ and name != "null"
176
+ and not name.startswith(_RESERVED_BRANCH_PREFIXES)
177
+ and not name.endswith(("/", ".", ".lock"))
178
+ and not any(part in name for part in ("..", "//", "/.", "@{"))
179
+ )
180
+
181
+
182
+ def origin_default_branch(repo: Path) -> str:
183
+ """The origin default branch that initialization records; an unset origin/HEAD means main."""
184
+ result = run_git(repo, "symbolic-ref", "--quiet", "refs/remotes/origin/HEAD")
185
+ prefix = "refs/remotes/origin/"
186
+ remote_ref = result.stdout.strip()
187
+ if result.returncode != 0 or not remote_ref.startswith(prefix):
188
+ return "main"
189
+ return remote_ref.removeprefix(prefix)
190
+
191
+
164
192
  def section_body(text: str, heading: str) -> Optional[str]:
165
193
  """The text under `## <heading>` up to the next `## `, or None when absent."""
166
194
  match = re.search(
@@ -169,6 +197,79 @@ def section_body(text: str, heading: str) -> Optional[str]:
169
197
  return match.group("body") if match else None
170
198
 
171
199
 
200
+ def overlapping_paths(left: Sequence[str], right: Sequence[str]) -> List[str]:
201
+ """Return the sorted paths that two task `files` lists both cover.
202
+
203
+ An entry covers itself and the paths below it. For a declared directory
204
+ and a path below it, the result names the lower path. The callers have no
205
+ task base, so this does not ask if an entry is a file: the task-brief
206
+ lint rejects a path below a file at the base.
207
+ """
208
+ return sorted(
209
+ {
210
+ max(one, other, key=len)
211
+ for one in left
212
+ for other in right
213
+ if one == other or one.startswith(other + "/") or other.startswith(one + "/")
214
+ }
215
+ )
216
+
217
+
218
+ # The `- ` of an indented sub-bullet line. A line that would then read as a
219
+ # numbered item (`- 2. text`) keeps its marker, so both readings of a source
220
+ # have the same criteria.
221
+ SUB_BULLET_MARKER = re.compile(r"(?m)^([ \t]+)-[ \t]+(?![ \t]*\d+\.\s)")
222
+
223
+
224
+ def without_sub_bullet_markers(source: str) -> str:
225
+ """`source` with the `- ` marker of each indented sub-bullet line removed."""
226
+ return SUB_BULLET_MARKER.sub(r"\1", source)
227
+
228
+
229
+ class Criterion(str):
230
+ """A criterion as its parser joins it, with the `- ` markers of its sub-bullet lines.
231
+
232
+ `bare` is the same criterion parsed from `without_sub_bullet_markers(source)`.
233
+ The joined text cannot tell a marker from a minus sign; the source lines can.
234
+ """
235
+
236
+ bare: str
237
+
238
+ def __new__(cls, text: str, bare: str) -> "Criterion":
239
+ criterion = super().__new__(cls, text)
240
+ criterion.bare = bare
241
+ return criterion
242
+
243
+
244
+ def quotes_criterion(quote: str, criterion: str) -> bool:
245
+ """Whether a review quote is `criterion`, for every reader.
246
+
247
+ Only whitespace is collapsed. The quote must equal the criterion with all
248
+ the markers of its sub-bullet lines or with none of them; every other
249
+ character, a hyphen inside a line too, is compared.
250
+ """
251
+ forms = (criterion, getattr(criterion, "bare", criterion))
252
+ return " ".join(quote.split()) in {" ".join(form.split()) for form in forms}
253
+
254
+
255
+ def quoted_criterion(item: str, criteria: Sequence[str]) -> Optional[Tuple[int, int]]:
256
+ """Index of the criterion quoted at the start of `item`, and where the quote ends.
257
+
258
+ A criterion can contain ` — ` itself, so each separator and the end of
259
+ `item` is a candidate, the longest quote first. A criterion as written
260
+ wins over any criterion read without its sub-bullet markers.
261
+ """
262
+ ends = [match.start() for match in re.finditer("(?= —(?: |$))|$", item)][::-1]
263
+ for bare in (False, True):
264
+ for end in ends:
265
+ quote = " ".join(item[:end].split())
266
+ for index, criterion in enumerate(criteria):
267
+ form = getattr(criterion, "bare", criterion) if bare else criterion
268
+ if quote == " ".join(form.split()):
269
+ return index, end
270
+ return None
271
+
272
+
172
273
  def task_verify_command(task_text: str) -> str:
173
274
  """The Verify shell text, excluding the closing fence's separator newline."""
174
275
  body = section_body(task_text, "Verify")
@@ -176,6 +277,11 @@ def task_verify_command(task_text: str) -> str:
176
277
  return block.group("block").removesuffix("\n") if block else ""
177
278
 
178
279
 
280
+ def fix_verify(commands: Iterable[str]) -> str:
281
+ """The Verify of a fix task: each distinct source Verify in its own subshell, under `set -e`."""
282
+ return "set -e\n" + "\n".join(f"(\n{command}\n)" for command in dict.fromkeys(commands))
283
+
284
+
179
285
  def latest_verify_entry(entries: list, command: str, commit: str,
180
286
  repo: Optional[str] = None) -> Optional[dict]:
181
287
  """Rows are keyed by (command, repo, commit); a row without `repo` is a coordinator row."""