@opengsd/gsd-path 1.3.1 → 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 (481) hide show
  1. package/AGENTS.md +2 -207
  2. package/CHANGELOG.md +331 -69
  3. package/DOCS.md +25 -9
  4. package/FULL.md +12 -5
  5. package/GUIDE.md +1 -1
  6. package/HOOKS.md +104 -14
  7. package/QUICK.md +5 -2
  8. package/README.md +131 -111
  9. package/RUNTIME.md +2 -2
  10. package/UPDATE.md +61 -11
  11. package/WORKFLOW.md +44 -7
  12. package/package.json +13 -9
  13. package/platforms/shared-agents/dispatch.md +13 -0
  14. package/scripts/_common.py +619 -18
  15. package/scripts/archive_milestone.py +160 -86
  16. package/scripts/bootstrap_repository.py +8 -5
  17. package/scripts/build_recovery.py +100 -32
  18. package/scripts/build_state.py +143 -24
  19. package/scripts/check_docs_audit.py +91 -7
  20. package/scripts/check_handoffs.py +662 -50
  21. package/scripts/check_task_briefs.py +338 -30
  22. package/scripts/check_update.py +2 -2
  23. package/scripts/core_hook_gate.py +10 -1
  24. package/scripts/core_hook_settings.py +11 -4
  25. package/scripts/detect_project.py +587 -32
  26. package/scripts/discussion_records.py +19 -13
  27. package/scripts/discussion_validate.py +152 -50
  28. package/scripts/dispatch_driver.py +501 -46
  29. package/scripts/git_guard.py +118 -31
  30. package/scripts/guard_hook.py +1567 -194
  31. package/scripts/install.mjs +77 -46
  32. package/scripts/install.py +611 -50
  33. package/scripts/integration.py +580 -25
  34. package/scripts/isolation.py +1438 -57
  35. package/scripts/lean_verification.py +99 -19
  36. package/scripts/loop_run.py +31 -29
  37. package/scripts/members.py +706 -0
  38. package/scripts/migrate_core.py +2 -2
  39. package/scripts/path_config.py +5 -5
  40. package/scripts/pipeline_diagnose.py +82 -31
  41. package/scripts/pipeline_git.py +124 -34
  42. package/scripts/pipeline_state.py +287 -87
  43. package/scripts/pipeline_undo.py +218 -30
  44. package/scripts/promote_lookahead.py +1 -1
  45. package/scripts/review_panel.py +1 -1
  46. package/scripts/runtime_store.py +55 -11
  47. package/scripts/skill-resources.json +37 -5
  48. package/scripts/state_checkpoint.py +135 -44
  49. package/scripts/state_promote.py +2 -0
  50. package/scripts/status_runtime.py +58 -10
  51. package/scripts/sync_skill_resources.py +8 -7
  52. package/scripts/task_context.py +12 -3
  53. package/scripts/token_budget.py +12 -8
  54. package/scripts/wizard.mjs +1 -0
  55. package/scripts/workflow_run.py +107 -30
  56. package/scripts/worktree_paths.py +72 -10
  57. package/skills/gsd-path/BUILD.md +7 -1
  58. package/skills/gsd-path/DECIDE.md +11 -4
  59. package/skills/gsd-path/DEFINE.md +36 -4
  60. package/skills/gsd-path/DOCS-AUDIT.md +6 -4
  61. package/skills/gsd-path/INSPECT.md +5 -4
  62. package/skills/gsd-path/PLAN.md +18 -4
  63. package/skills/gsd-path/RESEARCH.md +13 -1
  64. package/skills/gsd-path/ROADMAP.md +2 -1
  65. package/skills/gsd-path/SHIP.md +33 -11
  66. package/skills/gsd-path/SKILL.md +45 -1
  67. package/skills/gsd-path/references/build-native.md +63 -15
  68. package/skills/gsd-path/references/codebase-mapper.md +2 -1
  69. package/skills/gsd-path/references/dispatch.md +13 -0
  70. package/skills/gsd-path/references/docs-auditor.md +7 -1
  71. package/skills/gsd-path/references/operating-rules.md +214 -0
  72. package/skills/gsd-path/references/planner.md +22 -4
  73. package/skills/gsd-path/references/reviewer-final.md +20 -2
  74. package/skills/gsd-path/references/reviewer-wave.md +18 -5
  75. package/skills/gsd-path/references/reviewer.md +3 -1
  76. package/skills/gsd-path/references/spec-probes.md +150 -0
  77. package/skills/gsd-path/scripts/_common.py +619 -18
  78. package/skills/gsd-path/scripts/archive_milestone.py +160 -86
  79. package/skills/gsd-path/scripts/bootstrap_repository.py +8 -5
  80. package/skills/gsd-path/scripts/build_recovery.py +100 -32
  81. package/skills/gsd-path/scripts/build_state.py +143 -24
  82. package/skills/gsd-path/scripts/check_docs_audit.py +91 -7
  83. package/skills/gsd-path/scripts/check_handoffs.py +662 -50
  84. package/skills/gsd-path/scripts/check_task_briefs.py +338 -30
  85. package/skills/gsd-path/scripts/check_update.py +2 -2
  86. package/skills/gsd-path/scripts/detect_project.py +587 -32
  87. package/skills/gsd-path/scripts/discussion_records.py +19 -13
  88. package/skills/gsd-path/scripts/discussion_validate.py +152 -50
  89. package/skills/gsd-path/scripts/dispatch_driver.py +501 -46
  90. package/skills/gsd-path/scripts/git_guard.py +118 -31
  91. package/skills/gsd-path/scripts/integration.py +580 -25
  92. package/skills/gsd-path/scripts/isolation.py +1438 -57
  93. package/skills/gsd-path/scripts/lean_verification.py +99 -19
  94. package/skills/gsd-path/scripts/loop_run.py +31 -29
  95. package/skills/gsd-path/scripts/members.py +706 -0
  96. package/skills/gsd-path/scripts/path_config.py +5 -5
  97. package/skills/gsd-path/scripts/pipeline_git.py +124 -34
  98. package/skills/gsd-path/scripts/pipeline_state.py +287 -87
  99. package/skills/gsd-path/scripts/promote_lookahead.py +1 -1
  100. package/skills/gsd-path/scripts/review_panel.py +1 -1
  101. package/skills/gsd-path/scripts/state_checkpoint.py +135 -44
  102. package/skills/gsd-path/scripts/state_promote.py +2 -0
  103. package/skills/gsd-path/scripts/status_runtime.py +58 -10
  104. package/skills/gsd-path/scripts/task_context.py +12 -3
  105. package/skills/gsd-path/scripts/token_budget.py +12 -8
  106. package/skills/gsd-path/scripts/workflow_run.py +107 -30
  107. package/skills/gsd-path/scripts/worktree_paths.py +72 -10
  108. package/skills/gsd-path/templates/codebase.md +1 -1
  109. package/skills/gsd-path/templates/docs-audit.md +6 -2
  110. package/skills/gsd-path/templates/final-review.md +16 -4
  111. package/skills/gsd-path/templates/gap-review.md +2 -1
  112. package/skills/gsd-path/templates/intent.md +30 -0
  113. package/skills/gsd-path/templates/patch-findings.md +3 -3
  114. package/skills/gsd-path/templates/plan.md +17 -2
  115. package/skills/gsd-path/templates/research-handoff.md +14 -3
  116. package/skills/gsd-path/templates/state.md +1 -1
  117. package/skills/gsd-path/templates/task.md +1 -0
  118. package/skills/gsd-path/templates/wave-review.md +16 -4
  119. package/skills/gsd-path-build/SKILL.md +7 -1
  120. package/skills/gsd-path-build/references/build-native.md +63 -15
  121. package/skills/gsd-path-build/references/dispatch.md +13 -0
  122. package/skills/gsd-path-build/references/operating-rules.md +214 -0
  123. package/skills/gsd-path-build/references/reviewer-final.md +20 -2
  124. package/skills/gsd-path-build/references/reviewer-wave.md +18 -5
  125. package/skills/gsd-path-build/references/reviewer.md +3 -1
  126. package/skills/gsd-path-build/references/spec-probes.md +150 -0
  127. package/skills/gsd-path-build/scripts/_common.py +619 -18
  128. package/skills/gsd-path-build/scripts/archive_milestone.py +160 -86
  129. package/skills/gsd-path-build/scripts/build_recovery.py +100 -32
  130. package/skills/gsd-path-build/scripts/build_state.py +143 -24
  131. package/skills/gsd-path-build/scripts/check_handoffs.py +662 -50
  132. package/skills/gsd-path-build/scripts/check_task_briefs.py +338 -30
  133. package/skills/gsd-path-build/scripts/detect_project.py +587 -32
  134. package/skills/gsd-path-build/scripts/discussion_records.py +19 -13
  135. package/skills/gsd-path-build/scripts/discussion_validate.py +152 -50
  136. package/skills/gsd-path-build/scripts/dispatch_driver.py +501 -46
  137. package/skills/gsd-path-build/scripts/integration.py +580 -25
  138. package/skills/gsd-path-build/scripts/isolation.py +1438 -57
  139. package/skills/gsd-path-build/scripts/loop_run.py +31 -29
  140. package/skills/gsd-path-build/scripts/members.py +706 -0
  141. package/skills/gsd-path-build/scripts/path_config.py +5 -5
  142. package/skills/gsd-path-build/scripts/pipeline_git.py +124 -34
  143. package/skills/gsd-path-build/scripts/pipeline_state.py +287 -87
  144. package/skills/gsd-path-build/scripts/promote_lookahead.py +1 -1
  145. package/skills/gsd-path-build/scripts/review_panel.py +1 -1
  146. package/skills/gsd-path-build/scripts/state_checkpoint.py +135 -44
  147. package/skills/gsd-path-build/scripts/state_promote.py +2 -0
  148. package/skills/gsd-path-build/scripts/task_context.py +12 -3
  149. package/skills/gsd-path-build/scripts/token_budget.py +12 -8
  150. package/skills/gsd-path-build/scripts/workflow_run.py +107 -30
  151. package/skills/gsd-path-build/scripts/worktree_paths.py +72 -10
  152. package/skills/gsd-path-build/templates/task.md +1 -0
  153. package/skills/gsd-path-build/templates/wave-review.md +16 -4
  154. package/skills/gsd-path-decide/SKILL.md +11 -4
  155. package/skills/gsd-path-decide/references/dispatch.md +13 -0
  156. package/skills/gsd-path-decide/references/operating-rules.md +214 -0
  157. package/skills/gsd-path-decide/scripts/_common.py +619 -18
  158. package/skills/gsd-path-decide/scripts/archive_milestone.py +160 -86
  159. package/skills/gsd-path-decide/scripts/build_recovery.py +100 -32
  160. package/skills/gsd-path-decide/scripts/check_handoffs.py +662 -50
  161. package/skills/gsd-path-decide/scripts/check_task_briefs.py +338 -30
  162. package/skills/gsd-path-decide/scripts/detect_project.py +587 -32
  163. package/skills/gsd-path-decide/scripts/discussion_records.py +19 -13
  164. package/skills/gsd-path-decide/scripts/discussion_validate.py +152 -50
  165. package/skills/gsd-path-decide/scripts/integration.py +580 -25
  166. package/skills/gsd-path-decide/scripts/isolation.py +1438 -57
  167. package/skills/gsd-path-decide/scripts/loop_run.py +31 -29
  168. package/skills/gsd-path-decide/scripts/members.py +706 -0
  169. package/skills/gsd-path-decide/scripts/path_config.py +5 -5
  170. package/skills/gsd-path-decide/scripts/pipeline_git.py +124 -34
  171. package/skills/gsd-path-decide/scripts/pipeline_state.py +287 -87
  172. package/skills/gsd-path-decide/scripts/promote_lookahead.py +1 -1
  173. package/skills/gsd-path-decide/scripts/review_panel.py +1 -1
  174. package/skills/gsd-path-decide/scripts/state_checkpoint.py +135 -44
  175. package/skills/gsd-path-decide/scripts/state_promote.py +2 -0
  176. package/skills/gsd-path-decide/scripts/worktree_paths.py +72 -10
  177. package/skills/gsd-path-define/SKILL.md +36 -4
  178. package/skills/gsd-path-define/references/operating-rules.md +214 -0
  179. package/skills/gsd-path-define/references/spec-probes.md +150 -0
  180. package/skills/gsd-path-define/scripts/_common.py +619 -18
  181. package/skills/gsd-path-define/scripts/archive_milestone.py +160 -86
  182. package/skills/gsd-path-define/scripts/build_recovery.py +100 -32
  183. package/skills/gsd-path-define/scripts/check_handoffs.py +662 -50
  184. package/skills/gsd-path-define/scripts/check_task_briefs.py +338 -30
  185. package/skills/gsd-path-define/scripts/detect_project.py +587 -32
  186. package/skills/gsd-path-define/scripts/discussion_records.py +19 -13
  187. package/skills/gsd-path-define/scripts/discussion_validate.py +152 -50
  188. package/skills/gsd-path-define/scripts/integration.py +580 -25
  189. package/skills/gsd-path-define/scripts/isolation.py +1438 -57
  190. package/skills/gsd-path-define/scripts/loop_run.py +31 -29
  191. package/skills/gsd-path-define/scripts/members.py +706 -0
  192. package/skills/gsd-path-define/scripts/path_config.py +5 -5
  193. package/skills/gsd-path-define/scripts/pipeline_git.py +124 -34
  194. package/skills/gsd-path-define/scripts/pipeline_state.py +287 -87
  195. package/skills/gsd-path-define/scripts/promote_lookahead.py +1 -1
  196. package/skills/gsd-path-define/scripts/review_panel.py +1 -1
  197. package/skills/gsd-path-define/scripts/state_checkpoint.py +135 -44
  198. package/skills/gsd-path-define/scripts/state_promote.py +2 -0
  199. package/skills/gsd-path-define/scripts/worktree_paths.py +72 -10
  200. package/skills/gsd-path-define/templates/intent.md +30 -0
  201. package/skills/gsd-path-define/templates/state.md +1 -1
  202. package/skills/gsd-path-discuss/SKILL.md +2 -1
  203. package/skills/gsd-path-discuss/references/operating-rules.md +214 -0
  204. package/skills/gsd-path-discuss/scripts/_common.py +619 -18
  205. package/skills/gsd-path-discuss/scripts/discussion_records.py +19 -13
  206. package/skills/gsd-path-discuss/scripts/loop_run.py +31 -29
  207. package/skills/gsd-path-discuss/scripts/path_config.py +5 -5
  208. package/skills/gsd-path-discuss/scripts/review_panel.py +1 -1
  209. package/skills/gsd-path-discuss/scripts/worktree_paths.py +72 -10
  210. package/skills/gsd-path-docs-audit/SKILL.md +6 -4
  211. package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
  212. package/skills/gsd-path-docs-audit/references/docs-auditor.md +7 -1
  213. package/skills/gsd-path-docs-audit/references/operating-rules.md +214 -0
  214. package/skills/gsd-path-docs-audit/scripts/_common.py +619 -18
  215. package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +160 -86
  216. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +100 -32
  217. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +91 -7
  218. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +662 -50
  219. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +338 -30
  220. package/skills/gsd-path-docs-audit/scripts/detect_project.py +587 -32
  221. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +19 -13
  222. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +152 -50
  223. package/skills/gsd-path-docs-audit/scripts/integration.py +580 -25
  224. package/skills/gsd-path-docs-audit/scripts/isolation.py +1438 -57
  225. package/skills/gsd-path-docs-audit/scripts/loop_run.py +31 -29
  226. package/skills/gsd-path-docs-audit/scripts/members.py +706 -0
  227. package/skills/gsd-path-docs-audit/scripts/path_config.py +5 -5
  228. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +124 -34
  229. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +287 -87
  230. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +1 -1
  231. package/skills/gsd-path-docs-audit/scripts/review_panel.py +1 -1
  232. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +135 -44
  233. package/skills/gsd-path-docs-audit/scripts/state_promote.py +2 -0
  234. package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +72 -10
  235. package/skills/gsd-path-docs-audit/templates/docs-audit.md +6 -2
  236. package/skills/gsd-path-forensics/SKILL.md +2 -1
  237. package/skills/gsd-path-forensics/references/operating-rules.md +214 -0
  238. package/skills/gsd-path-forensics/scripts/_common.py +619 -18
  239. package/skills/gsd-path-forensics/scripts/discussion_records.py +19 -13
  240. package/skills/gsd-path-forensics/scripts/loop_run.py +31 -29
  241. package/skills/gsd-path-forensics/scripts/path_config.py +5 -5
  242. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +82 -31
  243. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +218 -30
  244. package/skills/gsd-path-forensics/scripts/review_panel.py +1 -1
  245. package/skills/gsd-path-forensics/scripts/worktree_paths.py +72 -10
  246. package/skills/gsd-path-inspect/SKILL.md +5 -4
  247. package/skills/gsd-path-inspect/references/codebase-mapper.md +2 -1
  248. package/skills/gsd-path-inspect/references/dispatch.md +13 -0
  249. package/skills/gsd-path-inspect/references/docs-auditor.md +7 -1
  250. package/skills/gsd-path-inspect/references/operating-rules.md +214 -0
  251. package/skills/gsd-path-inspect/scripts/_common.py +619 -18
  252. package/skills/gsd-path-inspect/scripts/archive_milestone.py +160 -86
  253. package/skills/gsd-path-inspect/scripts/build_recovery.py +100 -32
  254. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +91 -7
  255. package/skills/gsd-path-inspect/scripts/check_handoffs.py +662 -50
  256. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +338 -30
  257. package/skills/gsd-path-inspect/scripts/detect_project.py +587 -32
  258. package/skills/gsd-path-inspect/scripts/discussion_records.py +19 -13
  259. package/skills/gsd-path-inspect/scripts/discussion_validate.py +152 -50
  260. package/skills/gsd-path-inspect/scripts/integration.py +580 -25
  261. package/skills/gsd-path-inspect/scripts/isolation.py +1438 -57
  262. package/skills/gsd-path-inspect/scripts/loop_run.py +31 -29
  263. package/skills/gsd-path-inspect/scripts/members.py +706 -0
  264. package/skills/gsd-path-inspect/scripts/path_config.py +5 -5
  265. package/skills/gsd-path-inspect/scripts/pipeline_git.py +124 -34
  266. package/skills/gsd-path-inspect/scripts/pipeline_state.py +287 -87
  267. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +1 -1
  268. package/skills/gsd-path-inspect/scripts/review_panel.py +1 -1
  269. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +135 -44
  270. package/skills/gsd-path-inspect/scripts/state_promote.py +2 -0
  271. package/skills/gsd-path-inspect/scripts/workflow_run.py +107 -30
  272. package/skills/gsd-path-inspect/scripts/worktree_paths.py +72 -10
  273. package/skills/gsd-path-inspect/templates/codebase.md +1 -1
  274. package/skills/gsd-path-inspect/templates/docs-audit.md +6 -2
  275. package/skills/gsd-path-inspect/templates/state.md +1 -1
  276. package/skills/gsd-path-loop/SKILL.md +2 -1
  277. package/skills/gsd-path-loop/references/operating-rules.md +214 -0
  278. package/skills/gsd-path-loop/scripts/_common.py +619 -18
  279. package/skills/gsd-path-loop/scripts/discussion_records.py +19 -13
  280. package/skills/gsd-path-loop/scripts/loop_run.py +31 -29
  281. package/skills/gsd-path-loop/scripts/path_config.py +5 -5
  282. package/skills/gsd-path-loop/scripts/review_panel.py +1 -1
  283. package/skills/gsd-path-loop/scripts/worktree_paths.py +72 -10
  284. package/skills/gsd-path-migrate/SKILL.md +2 -1
  285. package/skills/gsd-path-migrate/references/operating-rules.md +214 -0
  286. package/skills/gsd-path-migrate/scripts/_common.py +619 -18
  287. package/skills/gsd-path-migrate/scripts/core_hook_gate.py +10 -1
  288. package/skills/gsd-path-migrate/scripts/core_hook_settings.py +11 -4
  289. package/skills/gsd-path-migrate/scripts/discussion_records.py +19 -13
  290. package/skills/gsd-path-migrate/scripts/loop_run.py +31 -29
  291. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -2
  292. package/skills/gsd-path-migrate/scripts/path_config.py +5 -5
  293. package/skills/gsd-path-migrate/scripts/review_panel.py +1 -1
  294. package/skills/gsd-path-plan/SKILL.md +18 -4
  295. package/skills/gsd-path-plan/references/dispatch.md +13 -0
  296. package/skills/gsd-path-plan/references/operating-rules.md +214 -0
  297. package/skills/gsd-path-plan/references/planner.md +22 -4
  298. package/skills/gsd-path-plan/references/spec-probes.md +150 -0
  299. package/skills/gsd-path-plan/scripts/_common.py +619 -18
  300. package/skills/gsd-path-plan/scripts/archive_milestone.py +160 -86
  301. package/skills/gsd-path-plan/scripts/build_recovery.py +100 -32
  302. package/skills/gsd-path-plan/scripts/check_handoffs.py +662 -50
  303. package/skills/gsd-path-plan/scripts/check_task_briefs.py +338 -30
  304. package/skills/gsd-path-plan/scripts/detect_project.py +587 -32
  305. package/skills/gsd-path-plan/scripts/discussion_records.py +19 -13
  306. package/skills/gsd-path-plan/scripts/discussion_validate.py +152 -50
  307. package/skills/gsd-path-plan/scripts/integration.py +580 -25
  308. package/skills/gsd-path-plan/scripts/isolation.py +1438 -57
  309. package/skills/gsd-path-plan/scripts/loop_run.py +31 -29
  310. package/skills/gsd-path-plan/scripts/members.py +706 -0
  311. package/skills/gsd-path-plan/scripts/path_config.py +5 -5
  312. package/skills/gsd-path-plan/scripts/pipeline_git.py +124 -34
  313. package/skills/gsd-path-plan/scripts/pipeline_state.py +287 -87
  314. package/skills/gsd-path-plan/scripts/promote_lookahead.py +1 -1
  315. package/skills/gsd-path-plan/scripts/review_panel.py +1 -1
  316. package/skills/gsd-path-plan/scripts/state_checkpoint.py +135 -44
  317. package/skills/gsd-path-plan/scripts/state_promote.py +2 -0
  318. package/skills/gsd-path-plan/scripts/workflow_run.py +107 -30
  319. package/skills/gsd-path-plan/scripts/worktree_paths.py +72 -10
  320. package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
  321. package/skills/gsd-path-plan/templates/plan.md +17 -2
  322. package/skills/gsd-path-plan/templates/task.md +1 -0
  323. package/skills/gsd-path-research/SKILL.md +13 -1
  324. package/skills/gsd-path-research/references/dispatch.md +13 -0
  325. package/skills/gsd-path-research/references/operating-rules.md +214 -0
  326. package/skills/gsd-path-research/scripts/_common.py +619 -18
  327. package/skills/gsd-path-research/scripts/archive_milestone.py +160 -86
  328. package/skills/gsd-path-research/scripts/build_recovery.py +100 -32
  329. package/skills/gsd-path-research/scripts/check_handoffs.py +662 -50
  330. package/skills/gsd-path-research/scripts/check_task_briefs.py +338 -30
  331. package/skills/gsd-path-research/scripts/detect_project.py +587 -32
  332. package/skills/gsd-path-research/scripts/discussion_records.py +19 -13
  333. package/skills/gsd-path-research/scripts/discussion_validate.py +152 -50
  334. package/skills/gsd-path-research/scripts/integration.py +580 -25
  335. package/skills/gsd-path-research/scripts/isolation.py +1438 -57
  336. package/skills/gsd-path-research/scripts/loop_run.py +31 -29
  337. package/skills/gsd-path-research/scripts/members.py +706 -0
  338. package/skills/gsd-path-research/scripts/path_config.py +5 -5
  339. package/skills/gsd-path-research/scripts/pipeline_git.py +124 -34
  340. package/skills/gsd-path-research/scripts/pipeline_state.py +287 -87
  341. package/skills/gsd-path-research/scripts/promote_lookahead.py +1 -1
  342. package/skills/gsd-path-research/scripts/review_panel.py +1 -1
  343. package/skills/gsd-path-research/scripts/state_checkpoint.py +135 -44
  344. package/skills/gsd-path-research/scripts/state_promote.py +2 -0
  345. package/skills/gsd-path-research/scripts/worktree_paths.py +72 -10
  346. package/skills/gsd-path-research/templates/research-handoff.md +14 -3
  347. package/skills/gsd-path-roadmap/SKILL.md +2 -1
  348. package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
  349. package/skills/gsd-path-roadmap/references/operating-rules.md +214 -0
  350. package/skills/gsd-path-roadmap/scripts/_common.py +619 -18
  351. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +160 -86
  352. package/skills/gsd-path-roadmap/scripts/build_recovery.py +100 -32
  353. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +662 -50
  354. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +338 -30
  355. package/skills/gsd-path-roadmap/scripts/detect_project.py +587 -32
  356. package/skills/gsd-path-roadmap/scripts/discussion_records.py +19 -13
  357. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +152 -50
  358. package/skills/gsd-path-roadmap/scripts/integration.py +580 -25
  359. package/skills/gsd-path-roadmap/scripts/isolation.py +1438 -57
  360. package/skills/gsd-path-roadmap/scripts/loop_run.py +31 -29
  361. package/skills/gsd-path-roadmap/scripts/members.py +706 -0
  362. package/skills/gsd-path-roadmap/scripts/path_config.py +5 -5
  363. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +124 -34
  364. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +287 -87
  365. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +1 -1
  366. package/skills/gsd-path-roadmap/scripts/review_panel.py +1 -1
  367. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +135 -44
  368. package/skills/gsd-path-roadmap/scripts/state_promote.py +2 -0
  369. package/skills/gsd-path-roadmap/scripts/worktree_paths.py +72 -10
  370. package/skills/gsd-path-ship/SKILL.md +33 -11
  371. package/skills/gsd-path-ship/references/dispatch.md +13 -0
  372. package/skills/gsd-path-ship/references/operating-rules.md +214 -0
  373. package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
  374. package/skills/gsd-path-ship/references/reviewer-wave.md +18 -5
  375. package/skills/gsd-path-ship/references/reviewer.md +3 -1
  376. package/skills/gsd-path-ship/references/spec-probes.md +150 -0
  377. package/skills/gsd-path-ship/scripts/_common.py +619 -18
  378. package/skills/gsd-path-ship/scripts/archive_milestone.py +160 -86
  379. package/skills/gsd-path-ship/scripts/build_recovery.py +100 -32
  380. package/skills/gsd-path-ship/scripts/build_state.py +143 -24
  381. package/skills/gsd-path-ship/scripts/check_handoffs.py +662 -50
  382. package/skills/gsd-path-ship/scripts/check_task_briefs.py +338 -30
  383. package/skills/gsd-path-ship/scripts/detect_project.py +587 -32
  384. package/skills/gsd-path-ship/scripts/discussion_records.py +19 -13
  385. package/skills/gsd-path-ship/scripts/discussion_validate.py +152 -50
  386. package/skills/gsd-path-ship/scripts/integration.py +580 -25
  387. package/skills/gsd-path-ship/scripts/isolation.py +1438 -57
  388. package/skills/gsd-path-ship/scripts/lean_verification.py +99 -19
  389. package/skills/gsd-path-ship/scripts/loop_run.py +31 -29
  390. package/skills/gsd-path-ship/scripts/members.py +706 -0
  391. package/skills/gsd-path-ship/scripts/path_config.py +5 -5
  392. package/skills/gsd-path-ship/scripts/pipeline_git.py +124 -34
  393. package/skills/gsd-path-ship/scripts/pipeline_state.py +287 -87
  394. package/skills/gsd-path-ship/scripts/promote_lookahead.py +1 -1
  395. package/skills/gsd-path-ship/scripts/review_panel.py +1 -1
  396. package/skills/gsd-path-ship/scripts/state_checkpoint.py +135 -44
  397. package/skills/gsd-path-ship/scripts/state_promote.py +2 -0
  398. package/skills/gsd-path-ship/scripts/workflow_run.py +107 -30
  399. package/skills/gsd-path-ship/scripts/worktree_paths.py +72 -10
  400. package/skills/gsd-path-ship/templates/final-review.md +16 -4
  401. package/skills/gsd-path-ship/templates/gap-review.md +2 -1
  402. package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
  403. package/skills/gsd-path-ship/templates/wave-review.md +16 -4
  404. package/skills/gsd-path-undo/SKILL.md +2 -1
  405. package/skills/gsd-path-undo/references/operating-rules.md +214 -0
  406. package/skills/gsd-path-undo/scripts/_common.py +619 -18
  407. package/skills/gsd-path-undo/scripts/discussion_records.py +19 -13
  408. package/skills/gsd-path-undo/scripts/loop_run.py +31 -29
  409. package/skills/gsd-path-undo/scripts/path_config.py +5 -5
  410. package/skills/gsd-path-undo/scripts/pipeline_undo.py +218 -30
  411. package/skills/gsd-path-undo/scripts/review_panel.py +1 -1
  412. package/skills/gsd-path-undo/scripts/worktree_paths.py +72 -10
  413. package/skills/path/BUILD.md +7 -1
  414. package/skills/path/DECIDE.md +11 -4
  415. package/skills/path/DEFINE.md +36 -4
  416. package/skills/path/DOCS-AUDIT.md +6 -4
  417. package/skills/path/INSPECT.md +5 -4
  418. package/skills/path/PLAN.md +18 -4
  419. package/skills/path/RESEARCH.md +13 -1
  420. package/skills/path/ROADMAP.md +2 -1
  421. package/skills/path/SHIP.md +33 -11
  422. package/skills/path/SKILL.md +45 -1
  423. package/skills/path/references/build-native.md +63 -15
  424. package/skills/path/references/codebase-mapper.md +2 -1
  425. package/skills/path/references/dispatch.md +13 -0
  426. package/skills/path/references/docs-auditor.md +7 -1
  427. package/skills/path/references/operating-rules.md +214 -0
  428. package/skills/path/references/planner.md +22 -4
  429. package/skills/path/references/reviewer-final.md +20 -2
  430. package/skills/path/references/reviewer-wave.md +18 -5
  431. package/skills/path/references/reviewer.md +3 -1
  432. package/skills/path/references/spec-probes.md +150 -0
  433. package/skills/path/scripts/_common.py +619 -18
  434. package/skills/path/scripts/archive_milestone.py +160 -86
  435. package/skills/path/scripts/bootstrap_repository.py +8 -5
  436. package/skills/path/scripts/build_recovery.py +100 -32
  437. package/skills/path/scripts/build_state.py +143 -24
  438. package/skills/path/scripts/check_docs_audit.py +91 -7
  439. package/skills/path/scripts/check_handoffs.py +662 -50
  440. package/skills/path/scripts/check_task_briefs.py +338 -30
  441. package/skills/path/scripts/check_update.py +2 -2
  442. package/skills/path/scripts/detect_project.py +587 -32
  443. package/skills/path/scripts/discussion_records.py +19 -13
  444. package/skills/path/scripts/discussion_validate.py +152 -50
  445. package/skills/path/scripts/dispatch_driver.py +501 -46
  446. package/skills/path/scripts/git_guard.py +118 -31
  447. package/skills/path/scripts/integration.py +580 -25
  448. package/skills/path/scripts/isolation.py +1438 -57
  449. package/skills/path/scripts/lean_verification.py +99 -19
  450. package/skills/path/scripts/loop_run.py +31 -29
  451. package/skills/path/scripts/members.py +706 -0
  452. package/skills/path/scripts/path_config.py +5 -5
  453. package/skills/path/scripts/pipeline_git.py +124 -34
  454. package/skills/path/scripts/pipeline_state.py +287 -87
  455. package/skills/path/scripts/promote_lookahead.py +1 -1
  456. package/skills/path/scripts/review_panel.py +1 -1
  457. package/skills/path/scripts/state_checkpoint.py +135 -44
  458. package/skills/path/scripts/state_promote.py +2 -0
  459. package/skills/path/scripts/status_runtime.py +58 -10
  460. package/skills/path/scripts/task_context.py +12 -3
  461. package/skills/path/scripts/token_budget.py +12 -8
  462. package/skills/path/scripts/workflow_run.py +107 -30
  463. package/skills/path/scripts/worktree_paths.py +72 -10
  464. package/skills/path/templates/codebase.md +1 -1
  465. package/skills/path/templates/docs-audit.md +6 -2
  466. package/skills/path/templates/final-review.md +16 -4
  467. package/skills/path/templates/gap-review.md +2 -1
  468. package/skills/path/templates/intent.md +30 -0
  469. package/skills/path/templates/patch-findings.md +3 -3
  470. package/skills/path/templates/plan.md +17 -2
  471. package/skills/path/templates/research-handoff.md +14 -3
  472. package/skills/path/templates/state.md +1 -1
  473. package/skills/path/templates/task.md +1 -0
  474. package/skills/path/templates/wave-review.md +16 -4
  475. package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  476. package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  477. package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  478. package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  479. package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  480. package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  481. package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
@@ -17,12 +17,15 @@ from datetime import date
17
17
  from pathlib import Path, PurePosixPath
18
18
  from typing import Mapping, Optional, Sequence
19
19
 
20
- try:
21
- from isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
22
- except ModuleNotFoundError as error: # pragma: no cover - package imports used by tests
23
- if error.name != "isolation":
24
- raise
25
- from scripts.isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
20
+ if __package__:
21
+ from .isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
22
+ else:
23
+ try:
24
+ from isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
25
+ except ModuleNotFoundError as error: # pragma: no cover - package imports used by tests
26
+ if error.name != "isolation":
27
+ raise
28
+ from scripts.isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
26
29
 
27
30
 
28
31
  if __package__:
@@ -66,6 +69,11 @@ def _sha256(content: str) -> str:
66
69
  return hashlib.sha256(content.encode("utf-8")).hexdigest()
67
70
 
68
71
 
72
+ def _is_junk_file(path: Path) -> bool:
73
+ # Drift digests skip OS junk by name: Finder rewrites it whatever its ignore status.
74
+ return path.name in pipeline_state._common.OS_JUNK_NAMES and path.is_file() and not path.is_symlink()
75
+
76
+
69
77
  def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
70
78
  if path.is_symlink() or not path.is_dir():
71
79
  raise PipelineStateError(f"promotion path must be a real directory: {path}")
@@ -74,7 +82,7 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
74
82
  if child.is_symlink():
75
83
  raise PipelineStateError(f"promotion path contains a symlink: {child}")
76
84
  relative = child.relative_to(path).as_posix()
77
- if PurePosixPath(relative).parts[0] in excluded:
85
+ if PurePosixPath(relative).parts[0] in excluded or _is_junk_file(child):
78
86
  continue
79
87
  if child.is_dir():
80
88
  digest.update(f"d\0{relative}\0".encode())
@@ -87,15 +95,15 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
87
95
 
88
96
 
89
97
  def _checkpoint_artifact_digest(project: Path, mutable_paths: set[str]) -> str:
90
- """Hash every approval artifact except the helper-owned metadata files."""
98
+ """Hash approval artifacts except helper-owned metadata and OS junk."""
91
99
  digest = hashlib.sha256()
92
100
  for child in sorted(project.rglob("*")):
93
101
  if child.is_symlink():
94
102
  raise PipelineStateError(f"checkpoint path contains a symlink: {child}")
95
103
  relative = child.relative_to(project).as_posix()
96
- # Unsupported entries (OS junk) are refused by the checkpoint itself; leaving them
97
- # out lets a refused approval resume after the owner removes them.
98
- if relative in mutable_paths or relative.split("/", 1)[0] not in PROJECT_ENTRIES:
104
+ # Finder can rewrite OS junk during approval; it must not cause artifact drift.
105
+ if (relative in mutable_paths or relative.split("/", 1)[0] not in PROJECT_ENTRIES
106
+ or _is_junk_file(child)):
99
107
  continue
100
108
  if child.is_dir():
101
109
  digest.update(f"d\0{relative}\0".encode())
@@ -333,11 +341,7 @@ def _converge_checkpoint_file(path: Path, before: str, after: str, label: str) -
333
341
 
334
342
  def _unlink_checkpoint_journal(path: Path) -> None:
335
343
  path.unlink()
336
- descriptor = os.open(path.parent, os.O_RDONLY)
337
- try:
338
- os.fsync(descriptor)
339
- finally:
340
- os.close(descriptor)
344
+ pipeline_state._common.fsync_directory(path.parent)
341
345
 
342
346
 
343
347
  def _resume_checkpoint_locked(
@@ -439,41 +443,85 @@ def _validate_plan_briefs(repo: Path, kind: str, project_dir: str) -> None:
439
443
  if head.returncode != 0:
440
444
  # Pre-Git approval defers base-dependent checks to build.
441
445
  return
446
+ if __package__:
447
+ from .check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
448
+ else:
449
+ try:
450
+ from check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
451
+ except ModuleNotFoundError as error: # pragma: no cover - package imports
452
+ if error.name != "check_task_briefs":
453
+ raise
454
+ from scripts.check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
455
+ if __package__:
456
+ from . import check_handoffs
457
+ else:
458
+ try:
459
+ import check_handoffs
460
+ except ModuleNotFoundError as error:
461
+ if error.name != "check_handoffs":
462
+ raise
463
+ from scripts import check_handoffs
442
464
  try:
443
- from check_task_briefs import BriefError, validate_task_briefs
444
- except ModuleNotFoundError as error: # pragma: no cover - package imports
445
- if error.name != "check_task_briefs":
446
- raise
447
- from scripts.check_task_briefs import BriefError, validate_task_briefs
448
- try:
449
- import check_handoffs
450
- except ModuleNotFoundError as error:
451
- if error.name != "check_handoffs":
452
- raise
453
- from scripts import check_handoffs
454
- try:
455
- tasks, dependency_files = check_handoffs.plan_brief_inputs(repo, project_dir)
456
- landed_bases = {}
457
- for task_id, text in tasks.items():
458
- if check_handoffs._task_scalar(text, task_id, "status") != "done":
459
- continue
460
- agent = check_handoffs._task_scalar(text, task_id, "agent")
461
- if agent in {"", "null"}:
462
- raise BriefError(f"{task_id} landed task has no recorded agent")
463
- recorded_base = check_handoffs._task_scalar(text, task_id, "base")
464
- try:
465
- landed_bases[task_id] = require_commit(repo, require_full_sha(recorded_base))
466
- except IsolationError as error:
467
- raise BriefError(f"{task_id} landed task has invalid historical base: {error}") from error
468
- dependency_files[task_id] = set()
465
+ member_base = _member_bases(repo)
466
+ tasks, dependency_files, landed_bases = plan_validation_bases(
467
+ repo, project_dir, member_base, initial=True
468
+ )
469
469
  validate_task_briefs(
470
470
  repo, head.stdout.strip(), f"{project_dir}/tasks",
471
471
  dependency_files=dependency_files, landed_bases=landed_bases,
472
+ member_base=member_base,
472
473
  )
474
+ if project_dir == ".project/next":
475
+ # Promotion checks lookahead member tasks from the bases their briefs were checked at.
476
+ named = {
477
+ str(check_handoffs._strict_frontmatter(text, task_id).get("repo"))
478
+ for task_id, text in tasks.items()
479
+ if check_handoffs._strict_frontmatter(text, task_id).get("repo")
480
+ and check_handoffs._task_scalar(text, task_id, "status") != "done"
481
+ }
482
+ if named:
483
+ bases = {name: member_base(name)[1] for name in sorted(named)}
484
+ milestone = pipeline_state.load_state(repo, project_dir)[0].milestone
485
+ path = _lookahead_member_bases_path(repo, str(milestone))
486
+ path.parent.mkdir(parents=True, exist_ok=True)
487
+ pipeline_state._common.atomic_write(path, json.dumps(
488
+ {"schema": LOOKAHEAD_MEMBER_BASES_SCHEMA, "milestone": milestone, "bases": bases},
489
+ indent=2, sort_keys=True) + "\n")
473
490
  except (BriefError, check_handoffs.HandoffError) as error:
474
491
  raise PipelineStateError(f"task brief validation failed: {error}") from error
475
492
 
476
493
 
494
+ LOOKAHEAD_MEMBER_BASES_SCHEMA = "gsd-path/lookahead-member-bases/v1"
495
+
496
+
497
+ def _lookahead_member_bases_path(repo: Path, milestone: str) -> Path:
498
+ common = pipeline_state._run_git(repo, "rev-parse", "--path-format=absolute", "--git-common-dir").stdout.strip()
499
+ return Path(common) / "gsd-path" / "lookahead-member-bases" / f"{milestone}.json"
500
+
501
+
502
+ def _lookahead_member_bases(repo: Path, milestone: str) -> Optional[dict]:
503
+ path = _lookahead_member_bases_path(repo, milestone)
504
+ if not path.is_file():
505
+ return None
506
+ value = json.loads(path.read_text(encoding="utf-8"))
507
+ if value.get("schema") != LOOKAHEAD_MEMBER_BASES_SCHEMA or value.get("milestone") != milestone:
508
+ return None
509
+ return value.get("bases")
510
+
511
+
512
+ def _shipped_member_merges(repo: Path, landing: str) -> dict:
513
+ """Member merges named by the ship commit the integration landing merged."""
514
+ if __package__:
515
+ from .pipeline_git import ship_member_rows
516
+ else:
517
+ from pipeline_git import ship_member_rows
518
+ ship = pipeline_state._run_git(repo, "rev-parse", "--verify", "--quiet", f"{landing}^2", check=False)
519
+ if ship.returncode != 0:
520
+ return {}
521
+ message = pipeline_state._run_git(repo, "show", "-s", "--format=%B", ship.stdout.strip()).stdout
522
+ return {row["name"]: row["merge"] for row in ship_member_rows(message)}
523
+
524
+
477
525
  def checkpoint_approval(
478
526
  repo: Path,
479
527
  kind: str,
@@ -1027,6 +1075,46 @@ def _classify_plan_drift(
1027
1075
  }
1028
1076
  approved = _approved_task_contracts(repo, checkpoint)
1029
1077
  current = _task_contracts_at(repo, revision)
1078
+ if __package__:
1079
+ from . import check_handoffs
1080
+ else:
1081
+ import check_handoffs
1082
+ # Member task paths live in member repos: compare each member from the base its brief
1083
+ # was checked at to the member merge the shipped milestone made (both fixed commits).
1084
+ task_repos = {
1085
+ task_id: str(check_handoffs._strict_frontmatter(contract.text, contract.path).get("repo") or "")
1086
+ for task_id, contract in approved.items()
1087
+ }
1088
+ active_member_tasks = {
1089
+ task_id for task_id, name in task_repos.items()
1090
+ if name and check_handoffs._task_scalar(approved[task_id].text, task_id, "status") != "done"
1091
+ }
1092
+ active_members = {task_repos[task_id] for task_id in active_member_tasks}
1093
+ member_changes: dict[str, list] = {}
1094
+ if active_members:
1095
+ bases = _lookahead_member_bases(repo, str(state.milestone)) or {}
1096
+ if any(name not in bases for name in active_members):
1097
+ return {
1098
+ "class": "unverifiable",
1099
+ "checkpoint": checkpoint,
1100
+ "task_ids": [],
1101
+ "changed_paths": [],
1102
+ "contract_paths": [],
1103
+ "member_tasks": True,
1104
+ "reason": "member bases were not recorded at plan approval",
1105
+ }
1106
+ if __package__:
1107
+ from . import members
1108
+ else:
1109
+ import members
1110
+ checkouts = {item["name"]: Path(item["checkout"]) for item in members.read_members(repo)}
1111
+ merges = _shipped_member_merges(repo, landing or revision)
1112
+ for name in active_members:
1113
+ member_changes[name] = [
1114
+ item for item in pipeline_state._run_git(
1115
+ checkouts[name], "diff", "--no-renames", "--name-only", "-z", bases[name], merges[name]
1116
+ ).stdout.split("\0") if item
1117
+ ] if name in merges else []
1030
1118
 
1031
1119
  contract_paths: set[str] = set()
1032
1120
  flagged_ids: set[str] = set()
@@ -1050,9 +1138,12 @@ def _classify_plan_drift(
1050
1138
 
1051
1139
  product_paths: set[str] = set()
1052
1140
  for task_id, contract in approved.items():
1141
+ member = task_repos.get(task_id)
1142
+ if member and task_id not in active_member_tasks:
1143
+ continue
1053
1144
  matches = sorted(
1054
- changed_path
1055
- for changed_path in changed
1145
+ (f"{member}:{changed_path}" if member else changed_path)
1146
+ for changed_path in (member_changes[member] if member else changed)
1056
1147
  if any(
1057
1148
  changed_path == path
1058
1149
  or changed_path.startswith(f"{path.rstrip('/')}/")
@@ -82,6 +82,8 @@ def _promotion_event(
82
82
  if isinstance(task_ids, list) and task_ids:
83
83
  return f"{prefix}; plan drift flagged tasks {', '.join(task_ids)}"
84
84
  return f"{prefix}; plan contract changed after approval"
85
+ if drift_class == "unverifiable" and drift.get("member_tasks"):
86
+ return f"{prefix}; plan drift unverifiable because member bases were not recorded at plan approval"
85
87
  if drift_class == "unverifiable":
86
88
  return f"{prefix}; plan drift unverifiable because approval checkpoint is missing"
87
89
  return prefix
@@ -13,10 +13,34 @@ import os
13
13
  import tempfile
14
14
  from pathlib import Path
15
15
 
16
- try:
17
- import _common
18
- except ImportError:
19
- from scripts import _common
16
+ if __package__:
17
+ from . import _common
18
+ else:
19
+ try:
20
+ import _common
21
+ except ImportError:
22
+ from scripts import _common
23
+
24
+
25
+ def _worktree_list_porcelain(primary: Path) -> tuple[str, bool]:
26
+ try:
27
+ if __package__:
28
+ from . import pipeline_git as pg
29
+ else:
30
+ from scripts import pipeline_git as pg
31
+ except ImportError:
32
+ try:
33
+ import pipeline_git as pg
34
+ except ImportError:
35
+ pg = None
36
+ if pg is not None:
37
+ return pg.worktree_list_porcelain(primary)
38
+ try:
39
+ output = _git(primary, "worktree", "list", "--porcelain", "-z")
40
+ return output, True
41
+ except ValueError:
42
+ output = _git(primary, "worktree", "list", "--porcelain")
43
+ return output, False
20
44
 
21
45
 
22
46
  def _git(primary: Path, *args: str) -> str:
@@ -27,7 +51,10 @@ def _git(primary: Path, *args: str) -> str:
27
51
 
28
52
 
29
53
  def _identity(path: Path) -> str:
30
- return hashlib.sha256(os.fsencode(path)).hexdigest()
54
+ digest = hashlib.sha256(os.fsencode(path)).hexdigest()
55
+ # Two identities nest in every managed path; full digests would use about
56
+ # 130 of Windows' 260-character MAX_PATH before any repository content.
57
+ return digest[:16] if os.name == "nt" else digest
31
58
 
32
59
 
33
60
  def _workspace(primary: Path, pin: bool) -> Path:
@@ -65,7 +92,7 @@ def _workspace(primary: Path, pin: bool) -> Path:
65
92
  receipt.parent.mkdir(parents=True, exist_ok=True)
66
93
  fd, temporary = tempfile.mkstemp(dir=receipt.parent)
67
94
  try:
68
- with os.fdopen(fd, "w", encoding="utf-8") as handle:
95
+ with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as handle:
69
96
  json.dump({"primary": str(primary), "root": str(workspace)}, handle)
70
97
  try:
71
98
  os.link(temporary, receipt)
@@ -76,17 +103,52 @@ def _workspace(primary: Path, pin: bool) -> Path:
76
103
  return workspace
77
104
 
78
105
 
106
+ def release_workspace(primary: Path) -> bool:
107
+ """Forget the pinned placement receipt once no linked worktrees remain.
108
+
109
+ Lets GSD_PATH_WORKTREE_ROOT (or a new default) apply again at the next
110
+ milestone's first allocation. Returns True when a receipt was removed;
111
+ any remaining linked worktree (including one only still registered) keeps
112
+ the pin.
113
+ """
114
+ primary = primary.resolve()
115
+ common = Path(_git(primary, "rev-parse", "--git-common-dir"))
116
+ common = (primary / common).resolve()
117
+ receipt = common / "gsd-path" / "workspaces" / f"{_identity(primary)}.json"
118
+ if not receipt.is_file():
119
+ return False
120
+ output, nul_separated = _worktree_list_porcelain(primary)
121
+ records = output.split("\0\0") if nul_separated else [
122
+ block for block in output.strip().split("\n\n") if block.strip()
123
+ ]
124
+ for record in records:
125
+ fields = record.split("\0") if nul_separated else record.splitlines()
126
+ for field in fields:
127
+ if field.startswith("worktree ") and Path(field[len("worktree "):]).resolve() != primary:
128
+ return False
129
+ receipt.unlink()
130
+ return True
131
+
132
+
79
133
  def worktree_path(primary: Path, kind: str, name: str, *, pin: bool = False) -> Path:
80
134
  primary = primary.resolve()
81
- if kind not in {"task", "verify", "integrate"} or not name or Path(name).name != name or name in {".", ".."}:
135
+ if kind not in {"task", "verify", "integrate", "bound"} or not name or Path(name).name != name or name in {".", ".."}:
82
136
  raise ValueError("invalid managed worktree kind or name")
137
+ if kind == "bound":
138
+ return _workspace(primary, pin) / kind / name
83
139
  legacy = (primary.parent / f".{primary.name}-gsd-path-integrate-{name}"
84
140
  if kind == "integrate" else primary.parent / f"{primary.name}.gsd-path" / kind / name)
85
141
  branch = f"refs/heads/gsd-path-{kind}/{name}"
86
- records = _git(primary, "worktree", "list", "--porcelain", "-z").split("\0\0")
142
+ output, nul_separated = _worktree_list_porcelain(primary)
143
+ if nul_separated:
144
+ records = output.split("\0\0")
145
+ else:
146
+ records = [block for block in output.strip().split("\n\n") if block.strip()]
87
147
  for record in records:
88
- fields = record.split("\0")
89
- if f"worktree {legacy}" in fields and f"branch {branch}" in fields:
148
+ fields = record.split("\0") if nul_separated else record.splitlines()
149
+ # Compare as paths: git prints forward slashes on Windows.
150
+ worktrees = [Path(field[len("worktree "):]) for field in fields if field.startswith("worktree ")]
151
+ if legacy in worktrees and f"branch {branch}" in fields:
90
152
  return legacy
91
153
  # Keep collision checks and missing-directory recovery at the old location.
92
154
  if os.path.lexists(legacy):
@@ -3,7 +3,8 @@ name: gsd-path-ship
3
3
  description: Verify a completed GSD Path milestone, manage evidence-backed patch decisions, request final shipping approval, and archive the validated result. Use only when the user explicitly invokes $gsd-path-ship or an active $gsd-path router or build orchestrator explicitly routes to this phase.
4
4
  ---
5
5
 
6
- Before executing project helpers, read [runtime selection](references/runtime-selection.md).
6
+ Before executing project helpers, read [runtime selection](references/runtime-selection.md)
7
+ and [operating rules](references/operating-rules.md).
7
8
 
8
9
  # GSD Path Ship Phase
9
10
 
@@ -82,10 +83,13 @@ so the position is unchanged. Then:
82
83
  This owns pending-discussion and landing checks, project Verify isolation,
83
84
  execution, output recording, collection, cleanup, and final-review reuse.
84
85
  Keep its JSON receipt; do not reconstruct those operations in shell calls.
85
- Exact stdout/stderr live once in `.project/build/verify-ledger.jsonl`;
86
- `final-gap-1.md` is the generated view referencing that entry. Re-entry at
87
- the same command and commit reuses the execution, including a failed one,
88
- and finishes interrupted collection without running the command again.
86
+ For a single-repo milestone, exact stdout/stderr live once in
87
+ `.project/build/verify-ledger.jsonl`; `final-gap-1.md` is the generated view
88
+ referencing that entry. For a member milestone, the gap records each member
89
+ head and holds the exact output; there is no reusable ledger entry.
90
+ Single-repo re-entry at the same command and commit reuses the execution,
91
+ including a failed one, and finishes interrupted collection without running
92
+ the command again.
89
93
  Missing legacy output requires evidence reconciliation, not a blind rerun.
90
94
  Any non-zero result stops this step; preserve its stderr and diagnose through
91
95
  the bundled forensics contract. Do not launch reviewers while project Verify
@@ -121,9 +125,10 @@ so the position is unchanged. Then:
121
125
  step 3 or create a fresh sidecar with `isolate-verify --name review-final`
122
126
  and dispatch the integration reviewer under logical task name
123
127
  `review_final`, assigning only
124
- `.project/review/FINAL.md`. Its complete brief includes the exact recorded
125
- project Verify ledger entry, every collected gap verdict so Overall verdict is
126
- consistent with them, and PLAN.md's `## Surface contract` when INTENT.md
128
+ `.project/review/FINAL.md`. Its complete brief includes the project Verify
129
+ evidence from the ledger or the member milestone's gap output, every
130
+ collected gap verdict so Overall verdict is consistent with them, and
131
+ PLAN.md's `## Surface contract` when INTENT.md
127
132
  names surfaces — that reviewer performs each Walkthrough and records the
128
133
  surface and what it showed on every criterion the contract lists. Collect FINAL.md and retire its sidecar through the
129
134
  same helper flow.
@@ -154,7 +159,12 @@ so the position is unchanged. Then:
154
159
  then stop and do not invent a patch finding. A `not-met`,
155
160
  `unverifiable`, or blocked gap with valid evidence sets `ship/blocked`,
156
161
  writes `.project/review/PATCH-FINDINGS.md` from the patch-findings template,
157
- and runs `python3 <absolute check_handoffs.py> patch --repo <absolute repo
162
+ copying the full `Risk: ...` line into each gap finding's Locator, its
163
+ `Found` field into Evidence, and its `Fix direction` field verbatim. For a
164
+ `FINAL.md` finding, use its `SC<n>` id as Locator and copy its `Finding` and
165
+ `Fix direction` fields verbatim. The patch validator requires these source
166
+ field values to match exactly; do not shorten or paraphrase them. Run
167
+ `python3 <absolute check_handoffs.py> patch --repo <absolute repo
158
168
  root>`. Present the blocked outcome, link the resolved absolute
159
169
  PATCH-FINDINGS.md path, and state that patch planning is next. The manifest
160
170
  contains exactly those FINAL.md and gap rows. When routed by an active
@@ -253,6 +263,14 @@ The persisted `STATE.archive` field is the transaction identity.
253
263
  at the current HEAD is the only artifact-producing remedy. The archive helper independently binds every FINAL.md
254
264
  `SCn` heading id and normalized text to the archived INTENT.md; a renamed or
255
265
  easier criterion blocks even if the earlier handoff gate was bypassed.
266
+ For a multi-repo milestone (the archive holds `build/members.json`), run
267
+ `python3 <absolute archive_milestone.py> close-members --repo <root>`
268
+ after preflight passes and before recording shipment. It closes each
269
+ locked member in lock order in that member's integration mode and
270
+ journals each one. When it returns `awaiting-merge`, report the member PR
271
+ link, stop, and rerun the same command after the user merges it; never
272
+ merge a member PR yourself. When it returns `integrated`, keep its `body`
273
+ for the ship commit below.
256
274
  5. Only after preflight passes, record shipment through the journaled helper;
257
275
  for a program it atomically replaces both ROADMAP.md and STATE.md, setting
258
276
  the current entry to `Status: shipped` with the exact `Archive:` pointer:
@@ -270,10 +288,14 @@ The persisted `STATE.archive` field is the transaction identity.
270
288
  idempotent after completion. Stage only
271
289
  `.project/` paths, inspect the staged path list against the transaction and
272
290
  create the ship phase's one commit with exact subject
273
- `ship: M00N — <milestone-slug>` and a body of exactly two consecutive lines,
291
+ `ship: M00N — <milestone-slug>`. For a single-repo milestone, its body has
292
+ exactly two consecutive lines,
274
293
  `Archive: .project/archive/<NNN>-<slug>` then
275
294
  `Reviewed-HEAD: <reviewed SHA>`, with no comment lines or blank line between them.
276
- Write the subject, a blank line, and the two body lines to a message file,
295
+ A multi-repo milestone's body is exactly the `body` that `close-members`
296
+ returned: those two lines, then one `Member-Reviewed-HEAD:` and one
297
+ `Member:` line per member.
298
+ Write the subject, a blank line, and the body lines to a message file,
277
299
  then use `git commit -F <message-file>`. M00N and NNN come from STATE.archive.
278
300
  There is no untracked-project exception and no product or older-archive
279
301
  path may enter this commit.
@@ -44,6 +44,19 @@ use exactly one matching branch:
44
44
  create another worktree. Encode task dependencies explicitly; launch
45
45
  independent children concurrently up to the host's advertised
46
46
  concurrent-subagent capacity.
47
+ - A `muse.subagent_spawn` tool (with `muse.subagent_wait`,
48
+ `muse.subagent_read_result`, and `muse.subagent_send_message` siblings) is
49
+ Muse Code. Omit `subagent_type` (general-purpose, full capability), pass the
50
+ logical task name as `task_name` and `role`, and the complete brief as
51
+ `objective`. Never set `worktree_isolation`. Keep the returned
52
+ `subagent_id`; send a correction to a still-live child with
53
+ `muse.subagent_send_message` mode `followup` and the complete new prompt,
54
+ otherwise start a fresh child. Collect with `muse.subagent_wait`
55
+ (`wait_for: task_terminal`) then `muse.subagent_read_result`; on
56
+ `root_capacity_exhausted`, wait for a child to finish and retry. Spawn has no
57
+ model or effort argument, so record no such capability. If only
58
+ `muse.workflow` is exposed (untrusted workspace), do not script or inline
59
+ the work; stop and report that the workspace must be trusted.
47
60
 
48
61
  For every branch:
49
62