@opengsd/gsd-path 1.4.0 → 1.5.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 (347) hide show
  1. package/CHANGELOG.md +325 -344
  2. package/DOCS.md +12 -2
  3. package/FULL.md +3 -2
  4. package/HOOKS.md +95 -8
  5. package/QUICK.md +1 -1
  6. package/README.md +78 -110
  7. package/RUNTIME.md +1 -1
  8. package/UPDATE.md +4 -3
  9. package/WORKFLOW.md +22 -1
  10. package/package.json +5 -2
  11. package/platforms/shared-agents/dispatch.md +13 -0
  12. package/scripts/_common.py +149 -1
  13. package/scripts/archive_milestone.py +14 -13
  14. package/scripts/build_recovery.py +96 -31
  15. package/scripts/build_state.py +79 -3
  16. package/scripts/check_docs_audit.py +77 -4
  17. package/scripts/check_handoffs.py +546 -30
  18. package/scripts/check_task_briefs.py +279 -23
  19. package/scripts/detect_project.py +243 -18
  20. package/scripts/discussion_validate.py +86 -29
  21. package/scripts/dispatch_driver.py +392 -22
  22. package/scripts/git_guard.py +3 -3
  23. package/scripts/guard_hook.py +1416 -165
  24. package/scripts/install.mjs +23 -8
  25. package/scripts/install.py +49 -9
  26. package/scripts/integration.py +146 -1
  27. package/scripts/isolation.py +392 -60
  28. package/scripts/loop_run.py +16 -4
  29. package/scripts/members.py +11 -9
  30. package/scripts/path_config.py +3 -3
  31. package/scripts/pipeline_git.py +63 -12
  32. package/scripts/pipeline_state.py +111 -33
  33. package/scripts/pipeline_undo.py +101 -8
  34. package/scripts/runtime_store.py +20 -2
  35. package/scripts/skill-resources.json +9 -2
  36. package/scripts/state_checkpoint.py +9 -27
  37. package/scripts/status_runtime.py +22 -4
  38. package/scripts/task_context.py +12 -3
  39. package/scripts/wizard.mjs +1 -0
  40. package/scripts/workflow_run.py +5 -2
  41. package/scripts/worktree_paths.py +54 -2
  42. package/skills/gsd-path/DEFINE.md +28 -3
  43. package/skills/gsd-path/PLAN.md +11 -3
  44. package/skills/gsd-path/RESEARCH.md +11 -0
  45. package/skills/gsd-path/SHIP.md +6 -1
  46. package/skills/gsd-path/references/build-native.md +16 -1
  47. package/skills/gsd-path/references/dispatch.md +13 -0
  48. package/skills/gsd-path/references/docs-auditor.md +5 -0
  49. package/skills/gsd-path/references/planner.md +14 -4
  50. package/skills/gsd-path/references/reviewer-final.md +20 -2
  51. package/skills/gsd-path/references/reviewer-wave.md +15 -4
  52. package/skills/gsd-path/references/reviewer.md +3 -1
  53. package/skills/gsd-path/references/spec-probes.md +150 -0
  54. package/skills/gsd-path/scripts/_common.py +149 -1
  55. package/skills/gsd-path/scripts/archive_milestone.py +14 -13
  56. package/skills/gsd-path/scripts/build_recovery.py +96 -31
  57. package/skills/gsd-path/scripts/build_state.py +79 -3
  58. package/skills/gsd-path/scripts/check_docs_audit.py +77 -4
  59. package/skills/gsd-path/scripts/check_handoffs.py +546 -30
  60. package/skills/gsd-path/scripts/check_task_briefs.py +279 -23
  61. package/skills/gsd-path/scripts/detect_project.py +243 -18
  62. package/skills/gsd-path/scripts/discussion_validate.py +86 -29
  63. package/skills/gsd-path/scripts/dispatch_driver.py +392 -22
  64. package/skills/gsd-path/scripts/git_guard.py +3 -3
  65. package/skills/gsd-path/scripts/integration.py +146 -1
  66. package/skills/gsd-path/scripts/isolation.py +392 -60
  67. package/skills/gsd-path/scripts/loop_run.py +16 -4
  68. package/skills/gsd-path/scripts/members.py +11 -9
  69. package/skills/gsd-path/scripts/path_config.py +3 -3
  70. package/skills/gsd-path/scripts/pipeline_git.py +63 -12
  71. package/skills/gsd-path/scripts/pipeline_state.py +111 -33
  72. package/skills/gsd-path/scripts/state_checkpoint.py +9 -27
  73. package/skills/gsd-path/scripts/status_runtime.py +22 -4
  74. package/skills/gsd-path/scripts/task_context.py +12 -3
  75. package/skills/gsd-path/scripts/workflow_run.py +5 -2
  76. package/skills/gsd-path/scripts/worktree_paths.py +54 -2
  77. package/skills/gsd-path/templates/docs-audit.md +5 -1
  78. package/skills/gsd-path/templates/final-review.md +11 -2
  79. package/skills/gsd-path/templates/intent.md +30 -0
  80. package/skills/gsd-path/templates/patch-findings.md +3 -3
  81. package/skills/gsd-path/templates/plan.md +17 -2
  82. package/skills/gsd-path/templates/research-handoff.md +14 -3
  83. package/skills/gsd-path/templates/state.md +1 -1
  84. package/skills/gsd-path/templates/wave-review.md +16 -6
  85. package/skills/gsd-path-build/references/build-native.md +16 -1
  86. package/skills/gsd-path-build/references/dispatch.md +13 -0
  87. package/skills/gsd-path-build/references/reviewer-final.md +20 -2
  88. package/skills/gsd-path-build/references/reviewer-wave.md +15 -4
  89. package/skills/gsd-path-build/references/reviewer.md +3 -1
  90. package/skills/gsd-path-build/references/spec-probes.md +150 -0
  91. package/skills/gsd-path-build/scripts/_common.py +149 -1
  92. package/skills/gsd-path-build/scripts/archive_milestone.py +14 -13
  93. package/skills/gsd-path-build/scripts/build_recovery.py +96 -31
  94. package/skills/gsd-path-build/scripts/build_state.py +79 -3
  95. package/skills/gsd-path-build/scripts/check_handoffs.py +546 -30
  96. package/skills/gsd-path-build/scripts/check_task_briefs.py +279 -23
  97. package/skills/gsd-path-build/scripts/detect_project.py +243 -18
  98. package/skills/gsd-path-build/scripts/discussion_validate.py +86 -29
  99. package/skills/gsd-path-build/scripts/dispatch_driver.py +392 -22
  100. package/skills/gsd-path-build/scripts/integration.py +146 -1
  101. package/skills/gsd-path-build/scripts/isolation.py +392 -60
  102. package/skills/gsd-path-build/scripts/loop_run.py +16 -4
  103. package/skills/gsd-path-build/scripts/members.py +11 -9
  104. package/skills/gsd-path-build/scripts/path_config.py +3 -3
  105. package/skills/gsd-path-build/scripts/pipeline_git.py +63 -12
  106. package/skills/gsd-path-build/scripts/pipeline_state.py +111 -33
  107. package/skills/gsd-path-build/scripts/state_checkpoint.py +9 -27
  108. package/skills/gsd-path-build/scripts/task_context.py +12 -3
  109. package/skills/gsd-path-build/scripts/workflow_run.py +5 -2
  110. package/skills/gsd-path-build/scripts/worktree_paths.py +54 -2
  111. package/skills/gsd-path-build/templates/wave-review.md +16 -6
  112. package/skills/gsd-path-decide/references/dispatch.md +13 -0
  113. package/skills/gsd-path-decide/scripts/_common.py +149 -1
  114. package/skills/gsd-path-decide/scripts/archive_milestone.py +14 -13
  115. package/skills/gsd-path-decide/scripts/build_recovery.py +96 -31
  116. package/skills/gsd-path-decide/scripts/check_handoffs.py +546 -30
  117. package/skills/gsd-path-decide/scripts/check_task_briefs.py +279 -23
  118. package/skills/gsd-path-decide/scripts/detect_project.py +243 -18
  119. package/skills/gsd-path-decide/scripts/discussion_validate.py +86 -29
  120. package/skills/gsd-path-decide/scripts/integration.py +146 -1
  121. package/skills/gsd-path-decide/scripts/isolation.py +392 -60
  122. package/skills/gsd-path-decide/scripts/loop_run.py +16 -4
  123. package/skills/gsd-path-decide/scripts/members.py +11 -9
  124. package/skills/gsd-path-decide/scripts/path_config.py +3 -3
  125. package/skills/gsd-path-decide/scripts/pipeline_git.py +63 -12
  126. package/skills/gsd-path-decide/scripts/pipeline_state.py +111 -33
  127. package/skills/gsd-path-decide/scripts/state_checkpoint.py +9 -27
  128. package/skills/gsd-path-decide/scripts/worktree_paths.py +54 -2
  129. package/skills/gsd-path-define/SKILL.md +28 -3
  130. package/skills/gsd-path-define/references/spec-probes.md +150 -0
  131. package/skills/gsd-path-define/scripts/_common.py +149 -1
  132. package/skills/gsd-path-define/scripts/archive_milestone.py +14 -13
  133. package/skills/gsd-path-define/scripts/build_recovery.py +96 -31
  134. package/skills/gsd-path-define/scripts/check_handoffs.py +546 -30
  135. package/skills/gsd-path-define/scripts/check_task_briefs.py +279 -23
  136. package/skills/gsd-path-define/scripts/detect_project.py +243 -18
  137. package/skills/gsd-path-define/scripts/discussion_validate.py +86 -29
  138. package/skills/gsd-path-define/scripts/integration.py +146 -1
  139. package/skills/gsd-path-define/scripts/isolation.py +392 -60
  140. package/skills/gsd-path-define/scripts/loop_run.py +16 -4
  141. package/skills/gsd-path-define/scripts/members.py +11 -9
  142. package/skills/gsd-path-define/scripts/path_config.py +3 -3
  143. package/skills/gsd-path-define/scripts/pipeline_git.py +63 -12
  144. package/skills/gsd-path-define/scripts/pipeline_state.py +111 -33
  145. package/skills/gsd-path-define/scripts/state_checkpoint.py +9 -27
  146. package/skills/gsd-path-define/scripts/worktree_paths.py +54 -2
  147. package/skills/gsd-path-define/templates/intent.md +30 -0
  148. package/skills/gsd-path-define/templates/state.md +1 -1
  149. package/skills/gsd-path-discuss/scripts/_common.py +149 -1
  150. package/skills/gsd-path-discuss/scripts/loop_run.py +16 -4
  151. package/skills/gsd-path-discuss/scripts/path_config.py +3 -3
  152. package/skills/gsd-path-discuss/scripts/worktree_paths.py +54 -2
  153. package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
  154. package/skills/gsd-path-docs-audit/references/docs-auditor.md +5 -0
  155. package/skills/gsd-path-docs-audit/scripts/_common.py +149 -1
  156. package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +14 -13
  157. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +96 -31
  158. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +77 -4
  159. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +546 -30
  160. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +279 -23
  161. package/skills/gsd-path-docs-audit/scripts/detect_project.py +243 -18
  162. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +86 -29
  163. package/skills/gsd-path-docs-audit/scripts/integration.py +146 -1
  164. package/skills/gsd-path-docs-audit/scripts/isolation.py +392 -60
  165. package/skills/gsd-path-docs-audit/scripts/loop_run.py +16 -4
  166. package/skills/gsd-path-docs-audit/scripts/members.py +11 -9
  167. package/skills/gsd-path-docs-audit/scripts/path_config.py +3 -3
  168. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +63 -12
  169. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +111 -33
  170. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +9 -27
  171. package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +54 -2
  172. package/skills/gsd-path-docs-audit/templates/docs-audit.md +5 -1
  173. package/skills/gsd-path-forensics/scripts/_common.py +149 -1
  174. package/skills/gsd-path-forensics/scripts/loop_run.py +16 -4
  175. package/skills/gsd-path-forensics/scripts/path_config.py +3 -3
  176. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +101 -8
  177. package/skills/gsd-path-forensics/scripts/worktree_paths.py +54 -2
  178. package/skills/gsd-path-inspect/references/dispatch.md +13 -0
  179. package/skills/gsd-path-inspect/references/docs-auditor.md +5 -0
  180. package/skills/gsd-path-inspect/scripts/_common.py +149 -1
  181. package/skills/gsd-path-inspect/scripts/archive_milestone.py +14 -13
  182. package/skills/gsd-path-inspect/scripts/build_recovery.py +96 -31
  183. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +77 -4
  184. package/skills/gsd-path-inspect/scripts/check_handoffs.py +546 -30
  185. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +279 -23
  186. package/skills/gsd-path-inspect/scripts/detect_project.py +243 -18
  187. package/skills/gsd-path-inspect/scripts/discussion_validate.py +86 -29
  188. package/skills/gsd-path-inspect/scripts/integration.py +146 -1
  189. package/skills/gsd-path-inspect/scripts/isolation.py +392 -60
  190. package/skills/gsd-path-inspect/scripts/loop_run.py +16 -4
  191. package/skills/gsd-path-inspect/scripts/members.py +11 -9
  192. package/skills/gsd-path-inspect/scripts/path_config.py +3 -3
  193. package/skills/gsd-path-inspect/scripts/pipeline_git.py +63 -12
  194. package/skills/gsd-path-inspect/scripts/pipeline_state.py +111 -33
  195. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +9 -27
  196. package/skills/gsd-path-inspect/scripts/workflow_run.py +5 -2
  197. package/skills/gsd-path-inspect/scripts/worktree_paths.py +54 -2
  198. package/skills/gsd-path-inspect/templates/docs-audit.md +5 -1
  199. package/skills/gsd-path-inspect/templates/state.md +1 -1
  200. package/skills/gsd-path-loop/scripts/_common.py +149 -1
  201. package/skills/gsd-path-loop/scripts/loop_run.py +16 -4
  202. package/skills/gsd-path-loop/scripts/path_config.py +3 -3
  203. package/skills/gsd-path-loop/scripts/worktree_paths.py +54 -2
  204. package/skills/gsd-path-migrate/scripts/_common.py +149 -1
  205. package/skills/gsd-path-migrate/scripts/loop_run.py +16 -4
  206. package/skills/gsd-path-migrate/scripts/path_config.py +3 -3
  207. package/skills/gsd-path-plan/SKILL.md +11 -3
  208. package/skills/gsd-path-plan/references/dispatch.md +13 -0
  209. package/skills/gsd-path-plan/references/planner.md +14 -4
  210. package/skills/gsd-path-plan/references/spec-probes.md +150 -0
  211. package/skills/gsd-path-plan/scripts/_common.py +149 -1
  212. package/skills/gsd-path-plan/scripts/archive_milestone.py +14 -13
  213. package/skills/gsd-path-plan/scripts/build_recovery.py +96 -31
  214. package/skills/gsd-path-plan/scripts/check_handoffs.py +546 -30
  215. package/skills/gsd-path-plan/scripts/check_task_briefs.py +279 -23
  216. package/skills/gsd-path-plan/scripts/detect_project.py +243 -18
  217. package/skills/gsd-path-plan/scripts/discussion_validate.py +86 -29
  218. package/skills/gsd-path-plan/scripts/integration.py +146 -1
  219. package/skills/gsd-path-plan/scripts/isolation.py +392 -60
  220. package/skills/gsd-path-plan/scripts/loop_run.py +16 -4
  221. package/skills/gsd-path-plan/scripts/members.py +11 -9
  222. package/skills/gsd-path-plan/scripts/path_config.py +3 -3
  223. package/skills/gsd-path-plan/scripts/pipeline_git.py +63 -12
  224. package/skills/gsd-path-plan/scripts/pipeline_state.py +111 -33
  225. package/skills/gsd-path-plan/scripts/state_checkpoint.py +9 -27
  226. package/skills/gsd-path-plan/scripts/workflow_run.py +5 -2
  227. package/skills/gsd-path-plan/scripts/worktree_paths.py +54 -2
  228. package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
  229. package/skills/gsd-path-plan/templates/plan.md +17 -2
  230. package/skills/gsd-path-research/SKILL.md +11 -0
  231. package/skills/gsd-path-research/references/dispatch.md +13 -0
  232. package/skills/gsd-path-research/scripts/_common.py +149 -1
  233. package/skills/gsd-path-research/scripts/archive_milestone.py +14 -13
  234. package/skills/gsd-path-research/scripts/build_recovery.py +96 -31
  235. package/skills/gsd-path-research/scripts/check_handoffs.py +546 -30
  236. package/skills/gsd-path-research/scripts/check_task_briefs.py +279 -23
  237. package/skills/gsd-path-research/scripts/detect_project.py +243 -18
  238. package/skills/gsd-path-research/scripts/discussion_validate.py +86 -29
  239. package/skills/gsd-path-research/scripts/integration.py +146 -1
  240. package/skills/gsd-path-research/scripts/isolation.py +392 -60
  241. package/skills/gsd-path-research/scripts/loop_run.py +16 -4
  242. package/skills/gsd-path-research/scripts/members.py +11 -9
  243. package/skills/gsd-path-research/scripts/path_config.py +3 -3
  244. package/skills/gsd-path-research/scripts/pipeline_git.py +63 -12
  245. package/skills/gsd-path-research/scripts/pipeline_state.py +111 -33
  246. package/skills/gsd-path-research/scripts/state_checkpoint.py +9 -27
  247. package/skills/gsd-path-research/scripts/worktree_paths.py +54 -2
  248. package/skills/gsd-path-research/templates/research-handoff.md +14 -3
  249. package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
  250. package/skills/gsd-path-roadmap/scripts/_common.py +149 -1
  251. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +14 -13
  252. package/skills/gsd-path-roadmap/scripts/build_recovery.py +96 -31
  253. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +546 -30
  254. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +279 -23
  255. package/skills/gsd-path-roadmap/scripts/detect_project.py +243 -18
  256. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +86 -29
  257. package/skills/gsd-path-roadmap/scripts/integration.py +146 -1
  258. package/skills/gsd-path-roadmap/scripts/isolation.py +392 -60
  259. package/skills/gsd-path-roadmap/scripts/loop_run.py +16 -4
  260. package/skills/gsd-path-roadmap/scripts/members.py +11 -9
  261. package/skills/gsd-path-roadmap/scripts/path_config.py +3 -3
  262. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +63 -12
  263. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +111 -33
  264. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +9 -27
  265. package/skills/gsd-path-roadmap/scripts/worktree_paths.py +54 -2
  266. package/skills/gsd-path-ship/SKILL.md +6 -1
  267. package/skills/gsd-path-ship/references/dispatch.md +13 -0
  268. package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
  269. package/skills/gsd-path-ship/references/reviewer-wave.md +15 -4
  270. package/skills/gsd-path-ship/references/reviewer.md +3 -1
  271. package/skills/gsd-path-ship/references/spec-probes.md +150 -0
  272. package/skills/gsd-path-ship/scripts/_common.py +149 -1
  273. package/skills/gsd-path-ship/scripts/archive_milestone.py +14 -13
  274. package/skills/gsd-path-ship/scripts/build_recovery.py +96 -31
  275. package/skills/gsd-path-ship/scripts/build_state.py +79 -3
  276. package/skills/gsd-path-ship/scripts/check_handoffs.py +546 -30
  277. package/skills/gsd-path-ship/scripts/check_task_briefs.py +279 -23
  278. package/skills/gsd-path-ship/scripts/detect_project.py +243 -18
  279. package/skills/gsd-path-ship/scripts/discussion_validate.py +86 -29
  280. package/skills/gsd-path-ship/scripts/integration.py +146 -1
  281. package/skills/gsd-path-ship/scripts/isolation.py +392 -60
  282. package/skills/gsd-path-ship/scripts/loop_run.py +16 -4
  283. package/skills/gsd-path-ship/scripts/members.py +11 -9
  284. package/skills/gsd-path-ship/scripts/path_config.py +3 -3
  285. package/skills/gsd-path-ship/scripts/pipeline_git.py +63 -12
  286. package/skills/gsd-path-ship/scripts/pipeline_state.py +111 -33
  287. package/skills/gsd-path-ship/scripts/state_checkpoint.py +9 -27
  288. package/skills/gsd-path-ship/scripts/workflow_run.py +5 -2
  289. package/skills/gsd-path-ship/scripts/worktree_paths.py +54 -2
  290. package/skills/gsd-path-ship/templates/final-review.md +11 -2
  291. package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
  292. package/skills/gsd-path-ship/templates/wave-review.md +16 -6
  293. package/skills/gsd-path-undo/scripts/_common.py +149 -1
  294. package/skills/gsd-path-undo/scripts/loop_run.py +16 -4
  295. package/skills/gsd-path-undo/scripts/path_config.py +3 -3
  296. package/skills/gsd-path-undo/scripts/pipeline_undo.py +101 -8
  297. package/skills/gsd-path-undo/scripts/worktree_paths.py +54 -2
  298. package/skills/path/DEFINE.md +28 -3
  299. package/skills/path/PLAN.md +11 -3
  300. package/skills/path/RESEARCH.md +11 -0
  301. package/skills/path/SHIP.md +6 -1
  302. package/skills/path/references/build-native.md +16 -1
  303. package/skills/path/references/dispatch.md +13 -0
  304. package/skills/path/references/docs-auditor.md +5 -0
  305. package/skills/path/references/planner.md +14 -4
  306. package/skills/path/references/reviewer-final.md +20 -2
  307. package/skills/path/references/reviewer-wave.md +15 -4
  308. package/skills/path/references/reviewer.md +3 -1
  309. package/skills/path/references/spec-probes.md +150 -0
  310. package/skills/path/scripts/_common.py +149 -1
  311. package/skills/path/scripts/archive_milestone.py +14 -13
  312. package/skills/path/scripts/build_recovery.py +96 -31
  313. package/skills/path/scripts/build_state.py +79 -3
  314. package/skills/path/scripts/check_docs_audit.py +77 -4
  315. package/skills/path/scripts/check_handoffs.py +546 -30
  316. package/skills/path/scripts/check_task_briefs.py +279 -23
  317. package/skills/path/scripts/detect_project.py +243 -18
  318. package/skills/path/scripts/discussion_validate.py +86 -29
  319. package/skills/path/scripts/dispatch_driver.py +392 -22
  320. package/skills/path/scripts/git_guard.py +3 -3
  321. package/skills/path/scripts/integration.py +146 -1
  322. package/skills/path/scripts/isolation.py +392 -60
  323. package/skills/path/scripts/loop_run.py +16 -4
  324. package/skills/path/scripts/members.py +11 -9
  325. package/skills/path/scripts/path_config.py +3 -3
  326. package/skills/path/scripts/pipeline_git.py +63 -12
  327. package/skills/path/scripts/pipeline_state.py +111 -33
  328. package/skills/path/scripts/state_checkpoint.py +9 -27
  329. package/skills/path/scripts/status_runtime.py +22 -4
  330. package/skills/path/scripts/task_context.py +12 -3
  331. package/skills/path/scripts/workflow_run.py +5 -2
  332. package/skills/path/scripts/worktree_paths.py +54 -2
  333. package/skills/path/templates/docs-audit.md +5 -1
  334. package/skills/path/templates/final-review.md +11 -2
  335. package/skills/path/templates/intent.md +30 -0
  336. package/skills/path/templates/patch-findings.md +3 -3
  337. package/skills/path/templates/plan.md +17 -2
  338. package/skills/path/templates/research-handoff.md +14 -3
  339. package/skills/path/templates/state.md +1 -1
  340. package/skills/path/templates/wave-review.md +16 -6
  341. package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  342. package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  343. package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  344. package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  345. package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  346. package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  347. package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
@@ -426,10 +426,10 @@ def frontmatter_value(content: str, key: str) -> Optional[str]:
426
426
  for line in lines[1:]:
427
427
  if line == "---":
428
428
  break
429
- match = re.match(rf"^{re.escape(key)}:\s*([^#]*?)\s*(?:#.*)?$", line)
429
+ match = re.match(rf"^{re.escape(key)}:(.*)$", line)
430
430
  if match:
431
- value = match.group(1).strip().strip('"').strip("'")
432
- return value
431
+ value = _common.strip_yaml_comment(match.group(1))
432
+ return value.strip().strip('"').strip("'")
433
433
  return None
434
434
 
435
435
 
@@ -586,14 +586,11 @@ def resolved_archive_target(
586
586
  expected_number = milestone_number(branch)
587
587
  configured = parsed_state.archive
588
588
  entries = archive_sequence_entries(project)
589
- missing_prior = [
590
- number for number in range(1, expected_number) if number not in entries
591
- ]
592
589
  later = sorted(number for number in entries if number > expected_number)
593
- if missing_prior or later:
590
+ if later:
594
591
  raise ArchiveError(
595
592
  f"archive sequence does not match bound branch {branch}: "
596
- f"missing={missing_prior}, later={later}"
593
+ f"later={later}"
597
594
  )
598
595
 
599
596
  if configured is not None:
@@ -1065,9 +1062,10 @@ def prepare_locked(project: Path, active_root: Path, slug: str) -> dict:
1065
1062
  final = active_root / "review" / "FINAL.md"
1066
1063
  reviewed = re.search(r"(?m)^Reviewed HEAD:\s*(\S+)", final.read_text(encoding="utf-8")) if final.is_file() else None
1067
1064
  head = require_git_success(run_git(project, "rev-parse", "HEAD"), "resolve HEAD").strip()
1068
- if reviewed and reviewed.group(1) != head:
1065
+ if reviewed and not _common.reviewed_head_covers(project, reviewed.group(1), head):
1069
1066
  raise ArchiveError(
1070
1067
  f"FINAL.md Reviewed HEAD {reviewed.group(1)} does not match current HEAD {head}; "
1068
+ f"{_common.RUNTIME_PIN_ALLOWANCE}; "
1071
1069
  "re-run the final review on the current commit before archiving"
1072
1070
  )
1073
1071
  target = resolved_archive_target(project, slug, parsed_state)
@@ -1680,6 +1678,7 @@ def abandon_locked(
1680
1678
 
1681
1679
 
1682
1680
  run_git = _common.run_git
1681
+ reviewed_head_covers = _common.reviewed_head_covers
1683
1682
  run_command = _common.run_command
1684
1683
 
1685
1684
 
@@ -1899,9 +1898,10 @@ def preflight(repo: Path) -> dict:
1899
1898
  require_stageable_carry_forward(project, archive)
1900
1899
  require_clean_older_archives(project, configured)
1901
1900
  head = require_git_success(run_git(project, "rev-parse", "HEAD"), "resolve preflight HEAD")
1902
- if reviewed_head != head:
1901
+ if not reviewed_head_covers(project, reviewed_head, head):
1903
1902
  raise ArchiveError(
1904
- f"FINAL.md Reviewed HEAD {reviewed_head} does not match current HEAD {head}"
1903
+ f"FINAL.md Reviewed HEAD {reviewed_head} does not match current HEAD {head}; "
1904
+ f"{_common.RUNTIME_PIN_ALLOWANCE}"
1905
1905
  )
1906
1906
  return {
1907
1907
  "archive": configured,
@@ -2093,9 +2093,10 @@ def validate(repo: Path, *, historical: bool = False) -> dict:
2093
2093
 
2094
2094
  members = member_ship_rows(project, archive, ship_commit)
2095
2095
  ship_parent = require_git_success(run_git(project, "rev-parse", f"{ship_commit}^"), "resolve ship parent")
2096
- if reviewed_head != ship_parent:
2096
+ if not reviewed_head_covers(project, reviewed_head, ship_parent):
2097
2097
  raise ArchiveError(
2098
- f"FINAL.md Reviewed HEAD {reviewed_head} does not match ship parent {ship_parent}"
2098
+ f"FINAL.md Reviewed HEAD {reviewed_head} does not match ship parent {ship_parent}; "
2099
+ f"{_common.RUNTIME_PIN_ALLOWANCE}"
2099
2100
  )
2100
2101
  require_canonical_commit_body(
2101
2102
  project,
@@ -1,5 +1,5 @@
1
1
  # gsd-path project runtime
2
- """Guard a blocked build's return to Define or Plan using its committed base."""
2
+ """Guard return to Define or Plan using a committed recovery base."""
3
3
 
4
4
  from __future__ import annotations
5
5
 
@@ -17,7 +17,9 @@ EVENTS = {
17
17
  "define": "build intent corrections requested",
18
18
  "plan": "build plan repair requested",
19
19
  }
20
+ PLAN_INTENT_EVENT = "plan intent corrections requested"
20
21
  MARKER = "build recovery: "
22
+ RECOVERY_KEYS = frozenset({"base", "branch", "kind", "source"})
21
23
 
22
24
 
23
25
  def runtime():
@@ -36,9 +38,42 @@ def checkpoint_runtime():
36
38
  return state_checkpoint
37
39
 
38
40
 
41
+ def _parse_recovery_record(value: object) -> dict:
42
+ if (
43
+ not isinstance(value, dict)
44
+ or not {"base", "branch", "kind"}.issubset(value)
45
+ or not set(value).issubset(RECOVERY_KEYS)
46
+ or not isinstance(value["base"], str)
47
+ or not re.fullmatch(r"[0-9a-f]{40}", value["base"])
48
+ ):
49
+ raise runtime().PipelineStateError("invalid build recovery record")
50
+ source = value.get("source", "build")
51
+ if source not in {"build", "plan"}:
52
+ raise runtime().PipelineStateError("invalid build recovery record")
53
+ if source == "plan":
54
+ if value["kind"] != "define":
55
+ raise runtime().PipelineStateError("invalid build recovery record")
56
+ elif value["kind"] not in EVENTS:
57
+ raise runtime().PipelineStateError("invalid build recovery record")
58
+ return {**value, "source": source}
59
+
60
+
61
+ def _recovery_base_proves_milestone(before, current, source: str) -> bool:
62
+ if before.branch != current.branch or before.milestone != current.milestone:
63
+ return False
64
+ if source == "plan":
65
+ return (before.phase, before.status) in {("plan", "active"), ("plan", "blocked")}
66
+ return (before.phase, before.status) == ("build", "blocked")
67
+
68
+
39
69
  def context(repo: Path, text: str | None = None) -> dict | None:
40
70
  state = runtime()
41
- current, loaded, _ = state.load_state(repo)
71
+ try:
72
+ current, loaded, _ = state.load_state(repo)
73
+ except state.PipelineStateError as error:
74
+ if "STATE.md must be a real file" not in str(error):
75
+ raise
76
+ return None
42
77
  text = loaded if text is None else text
43
78
  recovery = None
44
79
  for line in text.splitlines():
@@ -47,26 +82,24 @@ def context(repo: Path, text: str | None = None) -> dict | None:
47
82
  event = line.split(" — ", 2)[-1]
48
83
  if event.startswith(MARKER):
49
84
  try:
50
- value = json.loads(event[len(MARKER):])
85
+ value = _parse_recovery_record(json.loads(event[len(MARKER):]))
51
86
  except ValueError as error:
52
87
  raise state.PipelineStateError("invalid build recovery record") from error
53
- if (not isinstance(value, dict) or set(value) != {"base", "branch", "kind"}
54
- or value["kind"] not in EVENTS
55
- or not isinstance(value["base"], str)
56
- or not re.fullmatch(r"[0-9a-f]{40}", value["base"])):
57
- raise state.PipelineStateError("invalid build recovery record")
58
88
  recovery = {**value, "active": True} if value["branch"] == current.branch else None
59
- elif event == "build started" and recovery:
60
- recovery["active"] = False
89
+ elif recovery and recovery.get("active"):
90
+ source = recovery.get("source", "build")
91
+ if source == "build" and event == "build started":
92
+ recovery["active"] = False
93
+ elif source == "plan" and event == "plan approved":
94
+ recovery["active"] = False
61
95
  if recovery:
62
96
  if not state._is_ancestor(repo, recovery["base"], "HEAD"):
63
97
  raise state.PipelineStateError("build recovery base is not an ancestor of HEAD")
64
- source = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/STATE.md")
65
- if source is None:
98
+ base_text = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/STATE.md")
99
+ if base_text is None:
66
100
  raise state.PipelineStateError("build recovery base has no STATE.md")
67
- before = state._state_from_text(source)
68
- if ((before.phase, before.status) != ("build", "blocked")
69
- or before.branch != current.branch or before.milestone != current.milestone):
101
+ before = state._state_from_text(base_text)
102
+ if not _recovery_base_proves_milestone(before, current, recovery.get("source", "build")):
70
103
  raise state.PipelineStateError("build recovery base does not prove this blocked milestone")
71
104
  return recovery
72
105
 
@@ -108,18 +141,20 @@ def settled_tasks(repo: Path) -> dict[str, tuple[str, dict]]:
108
141
  return tasks
109
142
 
110
143
 
111
- def begin(repo: Path, before, after, event: str) -> dict:
144
+ def _begin_common(repo: Path, before, event: str) -> str:
112
145
  state = runtime()
113
- if (before.phase, before.status) != ("build", "blocked") or after.phase not in EVENTS:
114
- raise state.PipelineStateError("build recovery requires build/blocked")
115
- if event != EVENTS[after.phase]:
116
- raise state.PipelineStateError(f"state transition requires event: {EVENTS[after.phase]}")
117
146
  if before.archive is not None or before.branch != state._current_branch(repo):
118
147
  raise state.PipelineStateError("build recovery requires the active bound branch")
119
148
  if state._worktree_changes(repo):
120
149
  raise state.PipelineStateError("checkpoint the blocked build before recovery")
121
150
  if any(state.transaction_journals(repo).values()):
122
151
  raise state.PipelineStateError("finish pending transactions before build recovery")
152
+ state._read_real_file(repo / ".project/intent/INTENT.md", "INTENT.md")
153
+ return state._run_git(repo, "rev-parse", "HEAD").stdout.strip()
154
+
155
+
156
+ def _settle_build_dispatch(repo: Path) -> None:
157
+ state = runtime()
123
158
  records = records_root(repo)
124
159
  for directory in {path.parent.parent for path in records.rglob("attempt-*/state.json")}:
125
160
  latest = max(directory.glob("attempt-*/state.json"), key=lambda path: int(path.parent.name.split("-")[1]))
@@ -128,19 +163,49 @@ def begin(repo: Path, before, after, event: str) -> dict:
128
163
  or (record.get("worktree") and record.get("branch") and not record.get("cleanup_complete"))
129
164
  or record.get("outcome") not in {"landed", "collected", "blocked", "resolved", "redispatched"}):
130
165
  raise state.PipelineStateError(f"settle dispatch records before recovery: {latest}")
131
- tasks = settled_tasks(repo)
132
- state._read_real_file(repo / ".project/plan/PLAN.md", "PLAN.md")
133
- state._read_real_file(repo / ".project/intent/INTENT.md", "INTENT.md")
134
- base = state._run_git(repo, "rev-parse", "HEAD").stdout.strip()
166
+
167
+
168
+ def _verify_done_tasks(repo: Path, tasks: dict[str, tuple[str, dict]], base: str) -> None:
169
+ state = runtime()
135
170
  done = [repo / ".project/tasks" / name for name, (_, fields) in tasks.items()
136
171
  if fields["status"] == "done"]
137
- if done:
138
- if __package__:
139
- from scripts.isolation import verify_landed_task_files
140
- else:
141
- from isolation import verify_landed_task_files
142
- verify_landed_task_files(repo, done, ".project/tasks", base)
143
- return {"kind": after.phase, "base": base, "branch": before.branch}
172
+ if not done:
173
+ return
174
+ if __package__:
175
+ from scripts.isolation import verify_landed_task_files
176
+ else:
177
+ from isolation import verify_landed_task_files
178
+ verify_landed_task_files(repo, done, ".project/tasks", base)
179
+
180
+
181
+ def begin(repo: Path, before, after, event: str) -> dict:
182
+ state = runtime()
183
+ if (before.phase, before.status) == ("build", "blocked") and after.phase in EVENTS:
184
+ if event != EVENTS[after.phase]:
185
+ raise state.PipelineStateError(f"state transition requires event: {EVENTS[after.phase]}")
186
+ _settle_build_dispatch(repo)
187
+ tasks = settled_tasks(repo)
188
+ state._read_real_file(repo / ".project/plan/PLAN.md", "PLAN.md")
189
+ base = _begin_common(repo, before, event)
190
+ _verify_done_tasks(repo, tasks, base)
191
+ return {"kind": after.phase, "base": base, "branch": before.branch, "source": "build"}
192
+ if (
193
+ before.phase == "plan"
194
+ and before.status in {"active", "blocked"}
195
+ and (after.phase, after.status) == ("define", "active")
196
+ ):
197
+ if event != PLAN_INTENT_EVENT:
198
+ raise state.PipelineStateError(f"state transition requires event: {PLAN_INTENT_EVENT}")
199
+ state._read_real_file(repo / ".project/plan/PLAN.md", "PLAN.md")
200
+ tasks_dir = repo / ".project/tasks"
201
+ tasks = settled_tasks(repo) if tasks_dir.is_dir() and any(
202
+ path.is_file() and not state._common.is_ignored_junk(path)
203
+ for path in tasks_dir.iterdir()
204
+ ) else {}
205
+ base = _begin_common(repo, before, event)
206
+ _verify_done_tasks(repo, tasks, base)
207
+ return {"kind": "define", "base": base, "branch": before.branch, "source": "plan"}
208
+ raise state.PipelineStateError("build recovery requires build/blocked")
144
209
 
145
210
 
146
211
  def records_root(repo: Path) -> Path:
@@ -8,6 +8,10 @@ with testable claims where every claim row carries a valid type, a valid
8
8
  verdict, and real evidence, a `## Descriptive docs` list for claimless docs,
9
9
  the two sets disjoint and together equal to the frozen inventory, and a
10
10
  remediation queue with one classified row per non-verified claim.
11
+ Queue numbers are unique, positive and strictly increasing, not necessarily
12
+ contiguous. With `--prior-audit`, persisting rows keep their number and new
13
+ rows use a number above every prior queue number and User rulings Queue #.
14
+ Numbers stay bound to their original (doc, claim); never reuse a retired one.
11
15
  `## User rulings` is fixed-format durable memory. Pass the pre-rewrite audit
12
16
  with `--prior-audit FILE`; every prior row, including its Planned value, must
13
17
  remain an exact ordered prefix.
@@ -96,6 +100,12 @@ def _table_rows(body: str, width: int, label: str) -> List[List[str]]:
96
100
  return rows
97
101
 
98
102
 
103
+ def _remediation_queue_rows(body: str, label: str, required: bool = False) -> List[List[str]]:
104
+ if not required and "|" not in body:
105
+ return []
106
+ return _table_rows(body, 6, label)
107
+
108
+
99
109
  def _not_placeholder(value: str, label: str) -> None:
100
110
  normalized = value.strip().strip("`\"").strip()
101
111
  if (
@@ -247,6 +257,63 @@ def _check_carried(
247
257
  raise AuditError(f"{label}: doc or evidence changed since the prior audit: {', '.join(moved)}")
248
258
 
249
259
 
260
+ def _queue_number(number: str, label: str) -> int:
261
+ if not re.fullmatch(r"[1-9][0-9]*", number):
262
+ raise AuditError(f"{label}: queue numbers must be positive integers")
263
+ return int(number)
264
+
265
+
266
+ def _check_queue_number_history(
267
+ queue: Sequence[Sequence[str]],
268
+ prior_sections: Dict[str, str],
269
+ ) -> None:
270
+ if "Remediation queue" not in prior_sections:
271
+ raise AuditError("prior audit is missing section: ## Remediation queue")
272
+ if "User rulings" not in prior_sections:
273
+ raise AuditError("prior audit is missing section: ## User rulings")
274
+
275
+ prior_queue = _remediation_queue_rows(
276
+ prior_sections["Remediation queue"], "Prior remediation queue"
277
+ )
278
+ prior_items_by_number: Dict[int, tuple] = {}
279
+ prior_numbers_by_item: Dict[tuple, int] = {}
280
+ for number, doc, claim, *_ in prior_queue:
281
+ numeric_number = _queue_number(number, "Prior remediation queue")
282
+ identity = (doc, claim)
283
+ prior_items_by_number[numeric_number] = identity
284
+ prior_numbers_by_item[identity] = numeric_number
285
+
286
+ prior_rulings = _user_rulings(
287
+ prior_sections["User rulings"], "Prior user rulings"
288
+ )
289
+ prior_ruling_numbers = {int(row[0]) for row in prior_rulings}
290
+ prior_max = max(
291
+ [*prior_items_by_number, *prior_ruling_numbers],
292
+ default=0,
293
+ )
294
+
295
+ for number, doc, claim, *_ in queue:
296
+ numeric_number = _queue_number(number, "Remediation queue")
297
+ identity = (doc, claim)
298
+ prior_number = prior_numbers_by_item.get(identity)
299
+ if numeric_number in prior_ruling_numbers and prior_items_by_number.get(numeric_number) != identity:
300
+ raise AuditError(
301
+ f"Remediation queue #{number}: Queue # {number} is already retired by a prior "
302
+ "User rulings row for a different item; give new items a number above every "
303
+ "prior queue number and User rulings Queue #"
304
+ )
305
+ if prior_number is not None and numeric_number != prior_number:
306
+ raise AuditError(
307
+ f"Remediation queue #{number}: persisting item must keep its prior queue "
308
+ f"number #{prior_number}"
309
+ )
310
+ if prior_number is None and numeric_number <= prior_max:
311
+ raise AuditError(
312
+ f"Remediation queue #{number}: new items must use a number above every prior "
313
+ f"queue number and User rulings Queue # (maximum {prior_max})"
314
+ )
315
+
316
+
250
317
  def validate(
251
318
  repo: Path,
252
319
  audit_relative: str,
@@ -354,7 +421,9 @@ def validate(
354
421
 
355
422
  queue_body = sections["Remediation queue"]
356
423
  non_verified = sum(tallies[verdict] for verdict in VERDICTS if verdict != "verified")
357
- queue = _table_rows(queue_body, 6, "Remediation queue") if non_verified or "|" in queue_body else []
424
+ queue = _remediation_queue_rows(
425
+ queue_body, "Remediation queue", required=bool(non_verified)
426
+ )
358
427
  expected_queue = sorted(
359
428
  (doc, claim["claim"], claim["verdict"])
360
429
  for doc, claims in docs.items()
@@ -371,9 +440,13 @@ def validate(
371
440
  _not_placeholder(action, f"Remediation queue #{number}: action")
372
441
  if len(queue) != non_verified:
373
442
  raise AuditError(f"Remediation queue has {len(queue)} rows for {non_verified} non-verified claims")
374
- numbers = [row[0] for row in queue]
375
- if numbers != [str(number) for number in range(1, len(queue) + 1)]:
376
- raise AuditError("Remediation queue numbers must be contiguous and ordered from 1")
443
+ numbers = [_queue_number(row[0], "Remediation queue") for row in queue]
444
+ if any(later <= earlier for earlier, later in zip(numbers, numbers[1:])):
445
+ raise AuditError(
446
+ "Remediation queue numbers must be unique and strictly increasing"
447
+ )
448
+ if prior_sections is not None:
449
+ _check_queue_number_history(queue, prior_sections)
377
450
  actual_queue = sorted((doc, claim, verdict) for _, doc, claim, verdict, _, _ in queue)
378
451
  if actual_queue != expected_queue:
379
452
  raise AuditError(