@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,6 +17,7 @@ import os
17
17
  import re
18
18
  import shutil
19
19
  import sys
20
+ from datetime import date
20
21
 
21
22
  # Runtime helpers must not modify their immutable installation.
22
23
  sys.dont_write_bytecode = True
@@ -25,22 +26,30 @@ from pathlib import Path, PurePosixPath
25
26
  from typing import Optional, Sequence
26
27
 
27
28
  def _load_pipeline_modules():
28
- try:
29
- import archive_milestone
30
- import isolation
31
- import pipeline_git
32
- import pipeline_state
33
- import state_checkpoint
29
+ if __package__:
30
+ from . import archive_milestone
31
+ from . import isolation
32
+ from . import pipeline_git
33
+ from . import pipeline_state
34
+ from . import state_checkpoint
34
35
  return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
35
- except ModuleNotFoundError as error:
36
- if error.name not in {
37
- "archive_milestone",
38
- "isolation",
39
- "pipeline_git",
40
- "pipeline_state",
41
- "state_checkpoint",
42
- }:
43
- raise
36
+ else:
37
+ try:
38
+ import archive_milestone
39
+ import isolation
40
+ import pipeline_git
41
+ import pipeline_state
42
+ import state_checkpoint
43
+ return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
44
+ except ModuleNotFoundError as error:
45
+ if error.name not in {
46
+ "archive_milestone",
47
+ "isolation",
48
+ "pipeline_git",
49
+ "pipeline_state",
50
+ "state_checkpoint",
51
+ }:
52
+ raise
44
53
  try:
45
54
  from scripts import archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
46
55
  return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
@@ -94,10 +103,20 @@ UNDO_TRANSACTION_SCHEMA = pipeline_state.UNDO_TRANSACTION_SCHEMA
94
103
  UNDO_TRANSACTION_NAME = pipeline_state.UNDO_TRANSACTION_NAME
95
104
  ROADMAP_APPROVAL_SUBJECT = "roadmap: program roadmap approved"
96
105
  TASK_SUBJECT_RE = re.compile(r"^(T\d{3,}): .+")
97
- KINDS = ("checkpoint", "task", "uncommitted-archive", "lookahead")
106
+ KINDS = ("checkpoint", "task", "member-task", "uncommitted-archive", "lookahead")
98
107
  PROMOTION_PREFIX = "router: promote lookahead milestone "
99
108
  ABANDON_PREFIX = "build: abandon milestone "
100
109
  INTEGRATE_PREFIX = "integrate: "
110
+ SHIP_LOG_ONLY_LINE = re.compile(
111
+ r"- (?P<date>\d{4}-\d{2}-\d{2}) — ship — (?P<event>[^\r\n]+)\n\Z"
112
+ )
113
+ SHIPMENT_RECORD_LINE = re.compile(
114
+ r"- (?P<date>\d{4}-\d{2}-\d{2}) — shipped — (?P<event>[^\r\n]+)\n\Z"
115
+ )
116
+ SHIPMENT_EVENTS = {
117
+ "archive preflight passed; shipment recorded",
118
+ "archive preflight passed; shipment recorded; program complete",
119
+ }
101
120
 
102
121
 
103
122
  class UndoError(RuntimeError):
@@ -367,6 +386,80 @@ def pending_transaction(repo: Path) -> Optional[dict[str, object]]:
367
386
  raise UndoError(str(error)) from error
368
387
 
369
388
 
389
+ def _valid_state_event_line(line: str, phase: str) -> bool:
390
+ pattern = SHIP_LOG_ONLY_LINE if phase == "ship" else SHIPMENT_RECORD_LINE
391
+ match = pattern.fullmatch(line)
392
+ if match is None:
393
+ return False
394
+ try:
395
+ event_date = date.fromisoformat(match.group("date"))
396
+ except ValueError:
397
+ return False
398
+ event = match.group("event")
399
+ return event_date.isoformat() == match.group("date") and event == " ".join(event.split())
400
+
401
+
402
+ def _owned_ship_log_events(
403
+ prepared_state: str,
404
+ current_state: str,
405
+ phase: object,
406
+ status: object,
407
+ ) -> Optional[str]:
408
+ """Return only ship log lines appended around a helper-owned archive event.
409
+
410
+ The prepared text must remain byte-for-byte unchanged. For shipped/done,
411
+ record-shipment changes only phase and status before appending its one
412
+ generated shipment event, so validate that exact prefix and event shape.
413
+ """
414
+ if (phase, status) == ("ship", "active"):
415
+ if current_state == prepared_state:
416
+ return ""
417
+ if not current_state.startswith(prepared_state):
418
+ return None
419
+ suffix = current_state[len(prepared_state):]
420
+ separator = "" if prepared_state.endswith("\n") else "\n"
421
+ if separator:
422
+ if not suffix.startswith(separator):
423
+ return None
424
+ suffix = suffix[len(separator):]
425
+ lines = suffix.splitlines(keepends=True)
426
+ if not lines or "".join(lines) != suffix:
427
+ return None
428
+ if not all(_valid_state_event_line(line, "ship") for line in lines):
429
+ return None
430
+ return separator + suffix
431
+
432
+ if (phase, status) != ("shipped", "done"):
433
+ return None
434
+ try:
435
+ shipped_prefix = pipeline_state._set_frontmatter(
436
+ prepared_state,
437
+ {"phase": "shipped", "status": "done"},
438
+ )
439
+ except PipelineStateError:
440
+ return None
441
+ if not current_state.startswith(shipped_prefix):
442
+ return None
443
+ suffix = current_state[len(shipped_prefix):]
444
+ separator = "" if shipped_prefix.endswith("\n") else "\n"
445
+ if separator:
446
+ if not suffix.startswith(separator):
447
+ return None
448
+ suffix = suffix[len(separator):]
449
+ lines = suffix.splitlines(keepends=True)
450
+ if not lines or "".join(lines) != suffix:
451
+ return None
452
+ shipment_event = lines[-1]
453
+ if not _valid_state_event_line(shipment_event, "shipped"):
454
+ return None
455
+ if SHIPMENT_RECORD_LINE.fullmatch(shipment_event).group("event") not in SHIPMENT_EVENTS:
456
+ return None
457
+ ship_events = lines[:-1]
458
+ if not all(_valid_state_event_line(line, "ship") for line in ship_events):
459
+ return None
460
+ return separator + "".join(ship_events) if ship_events else ""
461
+
462
+
370
463
  def _archive_metadata_error(
371
464
  repo: Path,
372
465
  state_fields: dict[str, object],
@@ -412,8 +505,13 @@ def _archive_metadata_error(
412
505
  if final_review.exists() or gap_reviews:
413
506
  reviewed_head, _ = archive_milestone.parse_final_review(archive_path)
414
507
  archive_milestone.validate_gap_reviews(archive_path, reviewed_head)
415
- if reviewed_head != _optional_rev(repo, "HEAD"):
416
- return "archive undo final review does not match current HEAD"
508
+ if not archive_milestone.reviewed_head_covers(
509
+ repo, reviewed_head, _optional_rev(repo, "HEAD")
510
+ ):
511
+ return (
512
+ "archive undo final review does not match current HEAD; "
513
+ f"{archive_milestone._common.RUNTIME_PIN_ALLOWANCE}"
514
+ )
417
515
  expected_inventory.add("review/FINAL.md")
418
516
  expected_inventory.update(
419
517
  path.relative_to(archive_path).as_posix() for path in gap_reviews
@@ -468,10 +566,14 @@ def _archive_metadata_error(
468
566
  "archive",
469
567
  configured,
470
568
  )
471
- current_state = (repo / ".project" / "STATE.md").read_text(encoding="utf-8")
569
+ current_state = (repo / ".project" / "STATE.md").read_bytes().decode("utf-8")
472
570
  phase = state_fields.get("phase")
473
571
  status = state_fields.get("status")
572
+ ship_events = _owned_ship_log_events(prepared_state, current_state, phase, status)
474
573
  if (phase, status) == ("ship", "active"):
574
+ if ship_events is None:
575
+ return "archive undo found unowned STATE.md changes"
576
+ prepared_state += ship_events
475
577
  if current_state != prepared_state:
476
578
  return "archive undo found unowned STATE.md changes"
477
579
  if ".project/ROADMAP.md" in dirty:
@@ -479,14 +581,13 @@ def _archive_metadata_error(
479
581
  return None
480
582
  if (phase, status) != ("shipped", "done"):
481
583
  return "archive undo requires ship/active or shipped/done"
584
+ if ship_events is None:
585
+ return "archive undo found unowned shipment STATE.md changes"
586
+ prepared_state += ship_events
482
587
 
483
588
  prepared = _state_from_text(prepared_state, "prepared archive STATE.md")
484
- events = (
485
- "archive preflight passed; shipment recorded",
486
- "archive preflight passed; shipment recorded; program complete",
487
- )
488
589
  rendered_states = []
489
- for event in events:
590
+ for event in SHIPMENT_EVENTS:
490
591
  try:
491
592
  _, _, rendered = _render_transition(
492
593
  prepared,
@@ -528,6 +629,7 @@ def _prepare_transaction(
528
629
  branch: str,
529
630
  archive: Optional[str],
530
631
  discussion: Optional[dict[str, bytes]],
632
+ member_fields: Optional[dict[str, str]] = None,
531
633
  ) -> dict[str, object]:
532
634
  transaction = {
533
635
  "schema": UNDO_TRANSACTION_SCHEMA,
@@ -545,6 +647,8 @@ def _prepare_transaction(
545
647
  ),
546
648
  "discussion": _encode_discussion(discussion),
547
649
  }
650
+ if member_fields is not None:
651
+ transaction.update(member_fields)
548
652
  _write_json(_git_path(repo, UNDO_TRANSACTION_NAME), transaction)
549
653
  return transaction
550
654
 
@@ -641,7 +745,7 @@ def _transaction_recovery_stage(
641
745
  expected_head = str(transaction["expected_head"])
642
746
  parent = str(transaction["parent"])
643
747
  current = _optional_rev(repo, "HEAD")
644
- if transaction["kind"] == "checkpoint":
748
+ if transaction["kind"] in {"checkpoint", "member-task"}:
645
749
  allowed = {expected_head, parent}
646
750
  else:
647
751
  allowed = {expected_head}
@@ -662,8 +766,60 @@ def _transaction_recovery_stage(
662
766
  return "reset"
663
767
 
664
768
 
769
+ def _member_undo_parent(repo: Path, member: str, landing: str) -> str:
770
+ """The member landing's parent, while that landing is the unpublished bound tip."""
771
+ checkout, _, entry = isolation._member_context(repo, member)
772
+ bound = entry["branch"]
773
+ if _run_git(checkout, "rev-parse", f"refs/heads/{bound}").stdout.strip() != landing:
774
+ raise UndoError(f"member {member} {bound} moved past this landing")
775
+ _require_member_unpublished(checkout, member, landing, bound)
776
+ return _run_git(checkout, "rev-parse", f"{landing}^").stdout.strip()
777
+
778
+
779
+ def _require_member_unpublished(checkout: Path, member: str, landing: str, bound: str) -> None:
780
+ for ref, where in (("refs/remotes/origin/main", "origin/main"), (f"refs/remotes/origin/{bound}", f"origin/{bound}")):
781
+ if _run_git(checkout, "merge-base", "--is-ancestor", landing, ref, check=False).returncode == 0:
782
+ raise UndoError(f"member {member} landing is already on {where}")
783
+
784
+
785
+ def _require_no_member_landing_journal(repo: Path) -> None:
786
+ directory = isolation.common_git_dir(repo).joinpath(*isolation.MEMBER_LANDING_DIR)
787
+ if any(directory.glob("*.json")):
788
+ raise UndoError("member landing journal is pending; recover member landing first")
789
+
790
+
791
+ def _undo_member_landing(repo: Path, transaction: dict[str, object]) -> None:
792
+ """Reset the member bound branch first; a resumed undo finds it already reset."""
793
+ member = str(transaction["member"])
794
+ checkout, _, entry = isolation._member_context(repo, member)
795
+ tip = _run_git(checkout, "rev-parse", f"refs/heads/{entry['branch']}").stdout.strip()
796
+ if tip == transaction["member_parent"]:
797
+ _require_member_unpublished(checkout, member, str(transaction["landing"]), entry["branch"])
798
+ return
799
+ if tip != transaction["landing"]:
800
+ raise UndoError(f"member {member} bound branch moved during undo")
801
+ if _member_undo_parent(repo, member, str(transaction["landing"])) != transaction["member_parent"]:
802
+ raise UndoError(f"member {member} landing parent changed during undo")
803
+ bound = Path(isolation.member_bound_checkout(repo, member)["checkout"])
804
+ if _run_git(bound, "status", "--porcelain", "--untracked-files=all").stdout:
805
+ raise UndoError(f"member {member} bound checkout is dirty")
806
+ _run_git(bound, "reset", "--hard", str(transaction["member_parent"]))
807
+
808
+
665
809
  def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
810
+ if transaction["kind"] == "member-task":
811
+ with isolation._member_landing_lock(repo):
812
+ _finish_transaction_locked(repo, transaction)
813
+ return
814
+ _finish_transaction_locked(repo, transaction)
815
+
816
+
817
+ def _finish_transaction_locked(repo: Path, transaction: dict[str, object]) -> None:
818
+ if transaction["kind"] == "member-task":
819
+ _require_no_member_landing_journal(repo)
666
820
  stage = _transaction_recovery_stage(repo, transaction)
821
+ if transaction["kind"] == "member-task":
822
+ _undo_member_landing(repo, transaction)
667
823
  if stage == "prepared":
668
824
  _require_unpublished_reset(repo, str(transaction["branch"]))
669
825
  _reset_to(repo, str(transaction["parent"]))
@@ -675,11 +831,7 @@ def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
675
831
  _remove_untracked_tree(repo, archive)
676
832
  path = _git_path(repo, UNDO_TRANSACTION_NAME)
677
833
  path.unlink()
678
- descriptor = os.open(path.parent, os.O_RDONLY)
679
- try:
680
- os.fsync(descriptor)
681
- finally:
682
- os.close(descriptor)
834
+ pipeline_state._common.fsync_directory(path.parent)
683
835
 
684
836
 
685
837
  def classify_undo(repo: Path) -> dict[str, object]:
@@ -821,6 +973,28 @@ def classify_undo(repo: Path) -> dict[str, object]:
821
973
  proof_error = _task_proof_error(resolved, head)
822
974
  if proof_error:
823
975
  return _blocked([f"task landing ownership is unproven: {proof_error}"])
976
+ record = isolation.MEMBER_RECORD_RE.search(body)
977
+ if record is not None:
978
+ try:
979
+ _require_no_member_landing_journal(resolved)
980
+ member_parent = _member_undo_parent(resolved, record["member"], record["landing"])
981
+ except (IsolationError, UndoError, PipelineStateError) as error:
982
+ return _blocked([f"member landing undo is unsafe: {error}"])
983
+ return {
984
+ "kind": "member-task",
985
+ "branch": recorded_branch,
986
+ "head": head,
987
+ "parent": parent,
988
+ "subject": subject,
989
+ "member": record["member"],
990
+ "landing": record["landing"],
991
+ "member_parent": member_parent,
992
+ "effects": [
993
+ f"reset member {record['member']} bound branch to {member_parent}",
994
+ f"reset {recorded_branch} to {parent}",
995
+ ],
996
+ "blocked": [],
997
+ }
824
998
  return {
825
999
  "kind": "task",
826
1000
  "branch": recorded_branch,
@@ -978,6 +1152,20 @@ def apply_undo(repo: Path, kind: str, expected_head: str) -> dict[str, object]:
978
1152
  discussion,
979
1153
  )
980
1154
  _finish_transaction(resolved, transaction)
1155
+ elif kind == "member-task":
1156
+ with isolation._member_landing_lock(resolved):
1157
+ _require_no_member_landing_journal(resolved)
1158
+ if preview(resolved)["target"] != target:
1159
+ raise UndoError("member task undo target changed after preview")
1160
+ if _worktree_changes(resolved):
1161
+ raise UndoError("worktree changed after member task undo preview")
1162
+ _require_unpublished_reset(resolved, str(target["branch"]))
1163
+ transaction = _prepare_transaction(
1164
+ resolved, kind, expected_head, str(target["parent"]), str(target["branch"]), None, None,
1165
+ {"member": str(target["member"]), "landing": str(target["landing"]),
1166
+ "member_parent": str(target["member_parent"])},
1167
+ )
1168
+ _finish_transaction_locked(resolved, transaction)
981
1169
  elif kind == "task":
982
1170
  parent = target["parent"]
983
1171
  if not parent:
@@ -470,7 +470,7 @@ def merge_artifacts(
470
470
  lines.append(artifact["text"].rstrip())
471
471
  lines.append("")
472
472
  output.parent.mkdir(parents=True, exist_ok=True)
473
- output.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
473
+ output.write_bytes(("\n".join(lines).rstrip() + "\n").encode("utf-8"))
474
474
  return {
475
475
  "output": str(output.resolve()),
476
476
  "families": families,
@@ -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-inspect
3
3
  description: Inspect an existing codebase and its documentation to establish brownfield ground truth before intent is defined. Use only when the user explicitly invokes $gsd-path-inspect or an active $gsd-path router 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 Inspect Phase
9
10
 
@@ -112,15 +113,15 @@ Preparation never changes phase state; neither command dispatches agents.
112
113
  includes its path and revision for project commands; expected new pipeline
113
114
  artifacts do not make product code dirty. Each agent writes only its
114
115
  assigned output under that sidecar and keeps it there for the gates in step
115
- 3. Otherwise no
116
+ 3; its `Repo root` header still names the absolute primary. Otherwise no
116
117
  project command may run. The docs-auditor brief carries current HEAD as the
117
118
  audit baseline only when its verify sidecar was created at HEAD; otherwise
118
119
  it carries `none`. The auditor writes that baseline as `Audited HEAD`.
119
120
  3. Gate both artifacts against their templates: the codebase evidence needs
120
121
  a filled `## Map` plus findings as observed — no quota, but an empty
121
122
  findings section must say why; the docs audit must pass the bundled
122
- `python3 <absolute check_docs_audit.py> --repo <docs sidecar> --audit
123
- <track-relative DOCS-AUDIT.md> --inventory <frozen inventory file>`, where
123
+ `python3 <absolute check_docs_audit.py> --repo <docs sidecar> --primary
124
+ <absolute primary> --audit <track-relative DOCS-AUDIT.md> --inventory <frozen inventory file>`, where
124
125
  the audit path is `.project/research/DOCS-AUDIT.md` normally and
125
126
  `.project/next/research/DOCS-AUDIT.md` in Lookahead mode; add
126
127
  `--prior-audit <temporary prior-audit file>` when one was preserved and
@@ -10,7 +10,8 @@ change nothing outside your single output file.
10
10
  - Read AGENTS.md and the template before scanning. Stop on a missing path.
11
11
  - Write only the assigned output using the template. When the brief supplies a
12
12
  disposable root, write the output under that root at the relative handoff
13
- path; the orchestrator transfers it after validation. Do not ask the user
13
+ path; the orchestrator transfers it after validation. `Repo root` still names
14
+ the primary repo root, never the disposable root. Do not ask the user
14
15
  questions.
15
16
 
16
17
  ## What to establish
@@ -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
 
@@ -11,7 +11,8 @@ actually does. Read-only: change nothing outside your single output file.
11
11
  - Read AGENTS.md and the template before auditing. Stop on a missing path.
12
12
  - Write only the assigned output using the template. When the brief supplies a
13
13
  disposable root, write the output under that root at the relative handoff
14
- path; the orchestrator transfers it after validation. Do not ask the user
14
+ path; the orchestrator transfers it after validation. `Repo root` still names
15
+ the primary repo root, never the disposable root. Do not ask the user
15
16
  questions.
16
17
 
17
18
  ## Method
@@ -58,6 +59,11 @@ actually does. Read-only: change nothing outside your single output file.
58
59
  5. **Classify remediation** for every non-verified claim: `fix-doc`,
59
60
  `fix-code`, or `NEEDS-USER` when the right side of the conflict is not
60
61
  yours to decide.
62
+ Number queue rows with unique, strictly increasing positive integers; they
63
+ need not be contiguous. A row that persists from the prior audit keeps its
64
+ number. A new row takes a number greater than every prior queue number and
65
+ every `## User rulings` Queue #. Never reuse a retired number: a ruling
66
+ stays bound to the item it was made for.
61
67
 
62
68
  ## Rules
63
69