@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
@@ -5,27 +5,45 @@ import argparse
5
5
  import hashlib
6
6
  import json
7
7
  import os
8
+ import re
8
9
  import subprocess
9
10
  import sys
10
11
  import tempfile
11
12
  from pathlib import Path
12
13
 
13
14
  try:
14
- from scripts import _common
15
+ from scripts import _common, isolation
15
16
  except ImportError: # bundled copy inside a skill's scripts directory
16
17
  import _common
18
+ import isolation
17
19
 
18
20
 
19
21
  class StepFailed(RuntimeError):
20
22
  pass
21
23
 
24
+
25
+ def _table_rows(body):
26
+ """Cells of a Markdown table's data rows (header and separator skipped)."""
27
+ lines = [line.strip() for line in (body or "").splitlines() if line.strip().startswith("|")]
28
+ return [[cell.strip() for cell in re.split(r"(?<!\\)\|", line.strip("|"))] for line in lines[2:]]
29
+
22
30
  INSPECTION_SPECS = (("inspect_codebase", "codebase-mapper", "codebase", "evidence-codebase.md"),
23
31
  ("inspect_docs", "docs-auditor", "docs-audit", "DOCS-AUDIT.md"))
24
32
 
25
33
 
34
+ def _task_member(repo: Path, project_dir: str, task_id: str):
35
+ """The `repo:` member a task names, or None for a coordinator task."""
36
+ for path in sorted((repo / project_dir / "tasks").glob(f"{task_id}-*.md")):
37
+ fields, error = isolation.task_frontmatter(path.read_text(encoding="utf-8"))
38
+ if error:
39
+ raise StepFailed(error)
40
+ return fields.get("repo")
41
+ return None
42
+
43
+
26
44
  def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str = None,
27
45
  task_id: str = None, round_size: int = None, inspection: Path = None,
28
- mapper_reviewed: bool = False) -> dict:
46
+ mapper_reviewed: bool = False, kind: str = None) -> dict:
29
47
  steps = []
30
48
  outputs = {}
31
49
  scripts = Path(__file__).resolve().parent
@@ -33,7 +51,7 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
33
51
 
34
52
  def step(script, *arguments, raw=False):
35
53
  command = [sys.executable, "-B", str(helpers / script), *arguments]
36
- completed = subprocess.run(command, cwd=repo, capture_output=True, text=True)
54
+ completed = subprocess.run(command, cwd=repo, capture_output=True, encoding="utf-8", errors="replace")
37
55
  receipt = {"script": script, "command": command, "exit_code": completed.returncode,
38
56
  "stdout": completed.stdout, "stderr": completed.stderr}
39
57
  steps.append(receipt)
@@ -50,12 +68,29 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
50
68
  return receipt["result"]
51
69
 
52
70
  common = ["--repo", str(repo), "--project-dir", project_dir]
71
+ next_step = "$gsd-path-forensics"
72
+
73
+ def gate_plan():
74
+ if step("discussion_records.py", "pending", "--repo", str(repo))["pending"]:
75
+ raise StepFailed("pending discussion requires its owner disposition")
76
+ step("check_handoffs.py", "plan", *common)
77
+ head = subprocess.run(["git", "rev-parse", "--verify", "HEAD"],
78
+ cwd=repo, capture_output=True, encoding="utf-8", errors="replace", check=True).stdout.strip()
79
+ step("check_task_briefs.py", "--repo", str(repo), "--base", head,
80
+ "--tasks-dir", f"{project_dir}/tasks", "--project-dir", project_dir)
81
+ panel = ["validate-plan", "--plan", str(repo / project_dir / "plan/PLAN.md"),
82
+ "--intent", str(repo / project_dir / "intent/INTENT.md")]
83
+ charter = repo / ".project/CHARTER.md"
84
+ if charter.exists():
85
+ panel += ["--charter", str(charter)]
86
+ return step("review_panel.py", *panel)
87
+
53
88
  try:
54
89
  if os.path.lexists(repo / ".gsd-path/runtime.json"):
55
90
  resolved = subprocess.run(
56
91
  [sys.executable, "-B", str(repo / ".gsd-path/status_runtime.py"),
57
92
  "--repo", str(repo), "--runtime-path"],
58
- cwd=repo, capture_output=True, text=True)
93
+ cwd=repo, capture_output=True, encoding="utf-8", errors="replace")
59
94
  if resolved.returncode:
60
95
  sys.stderr.write(resolved.stderr)
61
96
  raise StepFailed(resolved.stderr.strip())
@@ -71,7 +106,7 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
71
106
  (repo / project_dir / "research" / spec[3]).is_symlink() for spec in specs):
72
107
  raise StepFailed("prior inspection evidence requires the re-inspection contract")
73
108
  branch = subprocess.run(["git", "branch", "--show-current"], cwd=repo,
74
- capture_output=True, text=True, check=True).stdout.strip()
109
+ capture_output=True, encoding="utf-8", errors="replace", check=True).stdout.strip()
75
110
  if branch != state["branch"]:
76
111
  raise StepFailed("current branch differs from the recorded inspection branch")
77
112
  pending = step("discussion_records.py", "pending", "--repo", str(repo))
@@ -87,7 +122,7 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
87
122
  raise StepFailed(f"missing inspection resource: {path}")
88
123
  staging = Path(tempfile.mkdtemp(prefix="gsd-path-inspect-"))
89
124
  inventory_file = staging / "inventory.txt"
90
- inventory_file.write_text(inventory, encoding="utf-8")
125
+ inventory_file.write_bytes(inventory.encode("utf-8"))
91
126
  assignments = []
92
127
  for task_name, role, template, filename in specs:
93
128
  isolated = step("isolation.py", "isolate-verify", "--repo", str(repo),
@@ -100,13 +135,14 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
100
135
  f"Template: {template_path}\nRepository and command cwd: {isolated['worktree']}\n"
101
136
  f"Recorded baseline and Audited HEAD: {isolated['base']}\n"
102
137
  f"Write only: {Path(isolated['worktree']) / output}\n"
138
+ f"Write header Repo root: {repo}\n"
103
139
  "Use only this supplied sidecar for project commands; do not create worktrees.\n"
104
140
  "The parent owns gates, collection, retirement, and phase state.\n"
105
141
  "Exclude .git, node_modules, .project/archive, and installed GSD Path and path skill bundles.\n")
106
142
  if task_name == "inspect_docs":
107
143
  brief += ("Alignment mode: false. No prior audit or changed set.\n"
108
144
  "Frozen inventory follows; use it exactly, without rediscovery:\n" + inventory)
109
- brief_file.write_text(brief, encoding="utf-8")
145
+ brief_file.write_bytes(brief.encode("utf-8"))
110
146
  assignments.append({**isolated, "task_name": task_name, "role": str(role_path),
111
147
  "template": str(template_path), "output": output,
112
148
  "brief_file": str(brief_file)})
@@ -136,16 +172,16 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
136
172
  if state["phase"] != "inspect" or state["status"] != "active":
137
173
  raise StepFailed("inspection completion requires inspect/active")
138
174
  branch = subprocess.run(["git", "branch", "--show-current"], cwd=repo,
139
- capture_output=True, text=True, check=True).stdout.strip()
175
+ capture_output=True, encoding="utf-8", errors="replace", check=True).stdout.strip()
140
176
  if state["branch"] != branch:
141
177
  raise StepFailed("current branch differs from the recorded inspection branch")
142
178
  pending = step("discussion_records.py", "pending", "--repo", str(repo))
143
179
  if pending["pending"]:
144
180
  raise StepFailed("pending discussion requires its owner disposition")
145
181
  docs = assignments["inspect_docs"]
146
- step("check_docs_audit.py", "--repo", docs["worktree"], "--audit", docs["output"],
147
- "--inventory", str(inventory_file))
148
- if f"Audited HEAD: {expected_head}" not in (Path(docs["worktree"]) / docs["output"]).read_text().splitlines():
182
+ step("check_docs_audit.py", "--repo", docs["worktree"], "--primary", str(repo),
183
+ "--audit", docs["output"], "--inventory", str(inventory_file))
184
+ if f"Audited HEAD: {expected_head}" not in (Path(docs["worktree"]) / docs["output"]).read_text(encoding="utf-8").splitlines():
149
185
  raise StepFailed("audit does not name the supplied inspection baseline")
150
186
  for task_name, _, _, _ in INSPECTION_SPECS:
151
187
  assignment = assignments[task_name]
@@ -161,10 +197,14 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
161
197
  "--set-phase", "inspect", "--set-status", "done", "--event", "inspection artifacts passed")
162
198
  elif action == "lint-round":
163
199
  head = subprocess.run(["git", "rev-parse", "--verify", "HEAD"],
164
- cwd=repo, capture_output=True, text=True, check=True).stdout.strip()
200
+ cwd=repo, capture_output=True, encoding="utf-8", errors="replace", check=True).stdout.strip()
165
201
  step("check_task_briefs.py", "--repo", str(repo), "--base", head,
166
- "--tasks-dir", f"{project_dir}/tasks")
202
+ "--tasks-dir", f"{project_dir}/tasks", "--project-dir", project_dir)
167
203
  step("check_handoffs.py", "plan", *common)
204
+ elif action == "prepare-task" and _task_member(repo, project_dir, task_id):
205
+ # A member task works in a sidecar of its member; its Verify runs there at finish.
206
+ step("isolation.py", "isolate-member-task", "--repo", str(repo),
207
+ "--member", _task_member(repo, project_dir, task_id), "--task-id", task_id)
168
208
  elif action == "prepare-task":
169
209
  task = step("isolation.py", "isolate-task", "--repo", str(repo),
170
210
  "--base", expected_head, "--task-id", task_id,
@@ -186,33 +226,67 @@ def run_workflow(repo: Path, action: str, project_dir: str, expected_head: str =
186
226
  raise StepFailed("pending discussion requires its owner disposition")
187
227
  step("build_state.py", "verify-landed", *common, "--head", expected_head)
188
228
  step("lean_verification.py", "--repo", str(repo), "--expected-head", expected_head)
189
- else:
190
- pending = step("discussion_records.py", "pending", "--repo", str(repo))
191
- if pending["pending"]:
229
+ elif action == "preauthorize":
230
+ # A block here is not a failure: the gate asks its owner as usual.
231
+ next_step = "ask the owner at this gate"
232
+ if project_dir != ".project" or kind not in {"intent", "plan"}:
233
+ raise StepFailed("pre-approval covers only intent or plan on the active track")
234
+ routed = step("pipeline_state.py", "route", *common)
235
+ if routed["route"].get("action") != "run-phase" or "recovery" in routed:
236
+ raise StepFailed("pre-approval needs an ordinary phase route")
237
+ if step("discussion_records.py", "pending", "--repo", str(repo))["pending"]:
192
238
  raise StepFailed("pending discussion requires its owner disposition")
193
- step("check_handoffs.py", "plan", *common)
194
- head = subprocess.run(["git", "rev-parse", "--verify", "HEAD"],
195
- cwd=repo, capture_output=True, text=True, check=True).stdout.strip()
196
- step("check_task_briefs.py", "--repo", str(repo), "--base", head,
197
- "--tasks-dir", f"{project_dir}/tasks")
198
- panel = ["validate-plan", "--plan", str(repo / project_dir / "plan/PLAN.md"),
199
- "--intent", str(repo / project_dir / "intent/INTENT.md")]
200
- charter = repo / ".project/CHARTER.md"
201
- if charter.exists():
202
- panel += ["--charter", str(charter)]
203
- step("review_panel.py", *panel)
239
+ track = repo / project_dir
240
+ intent = (track / "intent/INTENT.md").read_text(encoding="utf-8")
241
+ lane = re.search(r"(?m)^Lane:\s*(.+)$", intent)
242
+ if not lane or lane.group(1).split("<!--", 1)[0].strip().strip("`") != "quick":
243
+ raise StepFailed("pre-approval covers only the quick lane")
244
+ intent = re.sub(r"(?s)<!--.*?-->", "", intent)
245
+ if re.search(r"(?m)^\s*-\s*\[(RESEARCH|NEEDS-USER)\]", _common.section_body(intent, "Open questions") or ""):
246
+ raise StepFailed("INTENT.md has open RESEARCH or NEEDS-USER questions")
247
+ audit_path = track / "research/DOCS-AUDIT.md"
248
+ if audit_path.exists():
249
+ audit = audit_path.read_text(encoding="utf-8")
250
+ queue = _table_rows(_common.section_body(audit, "Remediation queue"))
251
+ ruled = set()
252
+ for row in _table_rows(_common.section_body(audit, "User rulings")):
253
+ if len(row) != 4 or row[1] not in {"fix-code", "fix-doc", "accept-drift"}:
254
+ continue
255
+ words = row[2].strip().strip('`"').strip()
256
+ if words and words.casefold() != "none" and not re.fullmatch(r"<[^>]*>", words):
257
+ ruled.add(row[0])
258
+ if any(len(row) == 6 and row[4] == "NEEDS-USER" and row[0] not in ruled for row in queue):
259
+ raise StepFailed("DOCS-AUDIT.md has NEEDS-USER rows without a user ruling")
260
+ if kind == "intent":
261
+ # Malformed or incomplete spec-probe tables are not a pre-approvable draft.
262
+ step("check_handoffs.py", "intent", *common)
263
+ if kind == "plan":
264
+ if gate_plan()["mode"] != "off":
265
+ raise StepFailed("pre-approval requires review_panel off")
266
+ plan = re.sub(r"(?s)<!--.*?-->", "", (track / "plan/PLAN.md").read_text(encoding="utf-8"))
267
+ config = _common.section_body(plan, "Config") or ""
268
+ skeptics = re.search(r"(?m)^[ \t]*-[ \t]*finding_skeptics:[ \t]*(\S+)", config)
269
+ if skeptics and skeptics.group(1) != "off":
270
+ raise StepFailed("pre-approval requires finding_skeptics off")
271
+ # Quick-lane limit from project policy (gsd-path-plan Quick mode): one wave, at most two tasks.
272
+ if (len(re.findall(r"(?m)^## Wave \d+ — ", plan)) != 1
273
+ or len(list((track / "tasks").glob("T[0-9][0-9][0-9]-*.md"))) > 2):
274
+ raise StepFailed("pre-approval requires one wave and at most two tasks")
275
+ step("pipeline_state.py", "pre-approve", "--repo", str(repo), "--use", kind)
276
+ else:
277
+ gate_plan()
204
278
  if action == "approve-plan":
205
279
  step("pipeline_state.py", "approve", *common, "--kind", "plan",
206
280
  "--expected-head", expected_head)
207
281
  except (StepFailed, OSError, subprocess.CalledProcessError, ValueError, KeyError, TypeError) as error:
208
282
  return {"status": "blocked", "reason": str(error), "steps": steps,
209
- "next": "$gsd-path-forensics"}
283
+ "next": next_step}
210
284
  return {"status": "complete", "steps": steps, **outputs}
211
285
 
212
286
 
213
287
  def main(argv=None):
214
288
  parser = argparse.ArgumentParser(description=__doc__)
215
- parser.add_argument("action", choices=("route", "gate-plan", "approve-plan", "build-evidence", "lint-round", "prepare-task", "prepare-final", "prepare-inspect", "finish-inspect"))
289
+ parser.add_argument("action", choices=("route", "gate-plan", "approve-plan", "build-evidence", "lint-round", "prepare-task", "prepare-final", "prepare-inspect", "finish-inspect", "preauthorize"))
216
290
  parser.add_argument("--repo", type=Path, required=True)
217
291
  parser.add_argument("--project-dir", choices=(".project", ".project/next"), default=".project")
218
292
  parser.add_argument("--expected-head")
@@ -220,15 +294,18 @@ def main(argv=None):
220
294
  parser.add_argument("--round-size", type=int)
221
295
  parser.add_argument("--inspection", type=Path)
222
296
  parser.add_argument("--mapper-reviewed", action="store_true")
297
+ parser.add_argument("--kind", choices=("intent", "plan"))
223
298
  arguments = parser.parse_args(argv)
224
299
  if arguments.action in {"approve-plan", "build-evidence", "prepare-task", "prepare-final", "prepare-inspect", "finish-inspect"} and not arguments.expected_head:
225
300
  parser.error(f"{arguments.action} requires --expected-head")
226
301
  if arguments.action == "prepare-task" and (not arguments.task_id or arguments.round_size is None):
227
302
  parser.error("prepare-task requires --task-id and --round-size")
303
+ if arguments.action == "preauthorize" and not arguments.kind:
304
+ parser.error("preauthorize requires --kind")
228
305
  result = run_workflow(arguments.repo.resolve(), arguments.action,
229
306
  arguments.project_dir, arguments.expected_head,
230
307
  arguments.task_id, arguments.round_size, arguments.inspection,
231
- arguments.mapper_reviewed)
308
+ arguments.mapper_reviewed, arguments.kind)
232
309
  print(json.dumps(result, sort_keys=True))
233
310
  return 0 if result["status"] == "complete" else 1
234
311
 
@@ -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-build
3
3
  description: Execute or resume an approved GSD Path plan with isolated task worktrees, deterministic commits, and independent wave review. Use only when the user explicitly invokes $gsd-path-build 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 Build Orchestrator
9
10
 
@@ -100,6 +101,11 @@ rule; never invoke an explicit-only sibling skill yourself.
100
101
  checkpoint `.project/` records uses this helper. Record the exact full HEAD
101
102
  before the first metadata change in that checkpoint, then run:
102
103
 
104
+ Before dispatch, also checkpoint a pre-existing `.project/build/verify-ledger.jsonl`
105
+ when it is an ignored regular file absent from HEAD, even if Git reports no
106
+ other pending paths. The `build:` checkpoint validates and force-adds only
107
+ that ledger; a malformed ledger blocks the checkpoint.
108
+
103
109
  Explicit configuration edits in `.project/config.json` and
104
110
  `.project/model-policy.json` are expected bookkeeping. Include them in the next
105
111
  normal checkpoint before a clean dispatch base; they may remain pending while
@@ -3,7 +3,8 @@ name: gsd-path-decide
3
3
  description: Decide implementation direction from approved intent and complete research evidence, recording settled choices in SYNTHESIS.md. Use only when the user explicitly invokes $gsd-path-decide 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 Decide Phase
9
10
 
@@ -24,7 +25,11 @@ checking. Legal entry is `research/done` or `decide/active|blocked`. On
24
25
  `research/done`, enter with `pipeline_state.py transition`, expected
25
26
  phase/status `research/done`, exact branch and archive values, event `decision
26
27
  synthesis started`, and set phase/status `decide/active` (plus the same
27
- lookahead project dir); never edit STATE directly. `decide/done` or any later phase blocks rather
28
+ lookahead project dir). Resume `decide/blocked` through the same helper with
29
+ the complete current state as expected, `--set-phase decide --set-status
30
+ active`, event `decision synthesis resumed`, and the same lookahead project
31
+ dir when supplied. Require the returned track state to be `decide/active`;
32
+ never edit STATE directly. `decide/done` or any later phase blocks rather
28
33
  than replacing decisions beneath an existing plan. When an active router
29
34
  supplies the lookahead track root `.project/next/`, evaluate these
30
35
  preconditions against the track instead; see Lookahead mode. Require
@@ -60,8 +65,10 @@ rules are unchanged; never write an active-path artifact.
60
65
 
61
66
  1. Read the local [synthesis template](templates/synthesis.md),
62
67
  `.project/research/RESEARCH.md`, and the bundled `scripts/check_handoffs.py`;
63
- resolve each to an absolute path. Run the research hand-off validator before
64
- dispatch so decide receives a complete, intentional evidence set.
68
+ resolve each to an absolute path. At `decide/active`, before dispatch, run
69
+ `python3 <absolute check_handoffs.py> research --repo <absolute root>
70
+ [--project-dir .project/next]` so decide receives a complete, intentional
71
+ evidence set.
65
72
  2. Read the local [decider role](references/decider.md), then follow
66
73
  the local [runtime dispatch contract](references/dispatch.md) with
67
74
  deterministic logical task name `decide`. Give it absolute paths to the role,
@@ -3,7 +3,8 @@ name: gsd-path-define
3
3
  description: Define and approve project or milestone intent through an interview or milestone confirmation, writing .project/CHARTER.md or .project/intent/INTENT.md. Use only when the user explicitly invokes $gsd-path-define 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 Define Phase
9
10
 
@@ -99,6 +100,10 @@ Obtain a confident answer in every area before finishing:
99
100
  give every named surface at least one success criterion observable
100
101
  there. A criterion satisfied by a passing test alone does not cover a
101
102
  surface.
103
+ 9. **Edges and prohibitions** — once the success criteria are drafted, run
104
+ the [spec-reach probes](references/spec-probes.md): every applicable edge
105
+ and every kept prohibition gets the user's ruling in INTENT.md
106
+ `## Edge coverage` and `## Prohibitions`.
102
107
 
103
108
  ## Program mode
104
109
 
@@ -148,7 +153,10 @@ State ownership. There is no re-interview of charter or roadmap scope:
148
153
  `Lane: milestone`, `Surfaces:` copied verbatim from the entry, and
149
154
  `Review panel:` copied from CHARTER.md (default
150
155
  the configured preference when CHARTER omits it). The confirmation may override the copied
151
- panel value; do not invent `detected` or a named list. When brownfield,
156
+ panel value; do not invent `detected` or a named list. Run the
157
+ [spec-reach probes](references/spec-probes.md) over the derived criteria
158
+ and draft `## Edge coverage` and `## Prohibitions` with recommended
159
+ rulings. When brownfield,
152
160
  fill `## Current state` from the map, record doc-vs-code rulings as in
153
161
  Brownfield mode, and add protected existing behavior under Scope out.
154
162
  Write Ground truth paths from the track root: `.project` normally, or
@@ -156,7 +164,9 @@ State ownership. There is no re-interview of charter or roadmap scope:
156
164
  active `research/` paths.
157
165
  3. Present one confirmation, not an interview: playback the derivation (and
158
166
  brownfield ground truth when present), link the resolved absolute INTENT.md
159
- path, and ask approve or adjust. A requested change that contradicts the
167
+ path, and ask approve or adjust. The confirmation lists each proposed edge
168
+ and prohibition ruling for the user to accept or change; it never rules on
169
+ them silently. A requested change that contradicts the
160
170
  charter or the resolved roadmap entry is a scope change — this phase never
161
171
  edits the roadmap; surface it to the user for a `$gsd-path-roadmap` re-slice
162
172
  at the next milestone boundary.
@@ -253,7 +263,15 @@ question. The rules change for every primary mode:
253
263
  the brownfield map already established. Milestone mode skips this step.
254
264
  5. Stop when coverage is complete or the user says `enough`. Record remaining
255
265
  uncertainty under `## Open questions` with `RESEARCH` or `NEEDS-USER`.
256
- 6. Classify the proposed milestone lane before writing the approval draft.
266
+ `enough` does not skip the next step.
267
+ 6. In standard mode, run the [spec-reach probes](references/spec-probes.md)
268
+ over the drafted success criteria: one question round for edges, then one
269
+ for kept prohibitions, each with a recommended ruling first. A ruling
270
+ observable where the user sees the work becomes or amends a success
271
+ criterion; write every ruling into `## Edge coverage` and
272
+ `## Prohibitions`. Program mode skips this step (each milestone runs it
273
+ in milestone mode); milestone mode runs it inside its confirmation.
274
+ 7. Classify the proposed milestone lane before writing the approval draft.
257
275
  Milestone mode keeps `Lane: milestone` and skips this classification.
258
276
  Program mode writes CHARTER.md instead of INTENT.md. Otherwise choose
259
277
  `quick` when scope fits at most two deliverable-sized tasks (project
@@ -274,6 +292,11 @@ question. The rules change for every primary mode:
274
292
  ## Output contract
275
293
 
276
294
  At approval, retain the already reviewed `Lane:` value and its one-line reason.
295
+ Before every approval question on INTENT.md, run the bundled `python3
296
+ <absolute-bundled-script> intent --repo <absolute-root>` helper
297
+ (`scripts/check_handoffs.py`, plus `--project-dir .project/next` in
298
+ lookahead). It checks the success criteria, Surfaces, and both probe tables;
299
+ fix a failure in the draft before asking. It approves nothing.
277
300
  Before presenting an approval draft without a CHARTER or explicit panel choice,
278
301
  read `settings.review_panel.value` from the selected runtime's `path_config.py
279
302
  show --repo <absolute-root>` (bundle for legacy projects; off for older selected
@@ -281,6 +304,12 @@ runtimes without config support). Include that preference in the draft.
281
304
  Retain `Review panel:` as reviewed: the CHARTER copy, the explicit user choice,
282
305
  or the configured future preference. Quick lane keeps the panel off.
283
306
 
307
+ When the active router recorded an `intent` pre-approval grant and the draft
308
+ needs no answer from the user, run the router's `workflow_run.py preauthorize
309
+ --kind intent` before asking. On `complete`, present Outcome and Review, say
310
+ the owner's pre-approval passed this gate, and continue as approved. On
311
+ `blocked`, ask as usual.
312
+
284
313
  After approval, finalize `.project/intent/INTENT.md` and run
285
314
  `pipeline_state.py transition` with expected `define/active`, the exact
286
315
  current milestone/branch/archive values, event `milestone intent approved`,
@@ -295,5 +324,8 @@ Use the executable phase handoff in AGENTS.md for the next action.
295
324
  - In brownfield mode, state mapped facts for correction; never re-ask them.
296
325
  - Treat solution-shaped problems as hypotheses and uncover the underlying pain.
297
326
  - Preserve vetoes and corrections verbatim.
327
+ - Never rule on an edge's behavior or a prohibition yourself; recommend,
328
+ then record the user's ruling. An edge the user has not ruled on is a
329
+ required answer, including under pre-approval.
298
330
  - Wrap up when every coverage-checklist area is answered or the user signals
299
331
  done, and tag remaining gaps.
@@ -3,7 +3,8 @@ name: gsd-path-docs-audit
3
3
  description: Verify Markdown claims against the actual code, commands, and GSD Path artifacts. Use only when the user explicitly invokes $gsd-path-docs-audit 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 Docs Audit
9
10
 
@@ -59,7 +60,8 @@ would dirty execution, invalidate review, or mutate shipped history.
59
60
  non-`.project` worktree changes, the orchestrator creates a verify sidecar
60
61
  with `python3 <absolute isolation.py> isolate-verify --repo <absolute
61
62
  primary> --base <HEAD> --name docs-audit` for project commands. The auditor
62
- writes only its assigned output under that sidecar. Gate it there before
63
+ writes only its assigned output under that sidecar; its `Repo root` header
64
+ still names the absolute primary. Gate it there before
63
65
  collection. Then run `python3 <absolute isolation.py> collect-artifact
64
66
  --repo <absolute primary> --source <returned worktree> --base <recorded
65
67
  HEAD> --branch <returned branch> --source-path
@@ -74,8 +76,8 @@ would dirty execution, invalidate review, or mutate shipped history.
74
76
  it carries `none`. The auditor writes that baseline as `Audited HEAD`.
75
77
  2. Gate the artifact with the bundled helper: write the frozen inventory to
76
78
  a temporary file (one path per line) and run
77
- `python3 <absolute check_docs_audit.py> --repo <docs sidecar> --inventory
78
- <file> [--prior-audit <temporary prior-audit file>] [--changed <temporary
79
+ `python3 <absolute check_docs_audit.py> --repo <docs sidecar> --primary
80
+ <absolute primary> --inventory <file> [--prior-audit <temporary prior-audit file>] [--changed <temporary
79
81
  changed-set file>]`.
80
82
  It enforces the contract — every doc with at least one testable claim has
81
83
  a claims table, every claim a valid type and verdict with evidence, every
@@ -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