@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):
@@ -4,7 +4,7 @@
4
4
  (brownfield mode), researchers (fifth standard dimension), the planner
5
5
  (conventions are binding), and reviewers. -->
6
6
 
7
- Repo root: <absolute path>
7
+ Repo root: <absolute primary repo root, never a sidecar>
8
8
  Scanned: <date>
9
9
  Checks run: <exact commands run and their results, e.g. `npm test` → 37/40 pass>
10
10
 
@@ -3,7 +3,7 @@
3
3
  <!-- Written by the docs auditor ($gsd-path-docs-audit or $gsd-path-inspect).
4
4
  Every verdict carries evidence; a verdict without evidence is a defect. -->
5
5
 
6
- Repo root: <absolute path>
6
+ Repo root: <absolute primary repo root, never a sidecar>
7
7
  Audited: <date>
8
8
  Audited HEAD: <40-hex commit the claims were checked at, or none>
9
9
  Alignment mode: <yes | no — yes when .project/ artifacts were also audited>
@@ -62,7 +62,11 @@ Worst drift: <one sentence — the most misleading claim found>
62
62
  ## Remediation queue
63
63
 
64
64
  <!-- Every non-verified claim, classified. The user rules on this queue;
65
- the auditor never fixes anything. -->
65
+ the auditor never fixes anything.
66
+ Numbers are unique and strictly increasing, not necessarily contiguous.
67
+ A persisting row keeps its number; a new row takes a number above every
68
+ prior queue number and every User rulings Queue #. Never reuse a retired
69
+ number: a ruling stays bound to the item it was made for. -->
66
70
 
67
71
  | # | Doc | Claim | Verdict | Class | Suggested action |
68
72
  |---|-----|-------|---------|-------|------------------|
@@ -4,20 +4,32 @@
4
4
  criterion appears exactly once and carries checked evidence. A criterion
5
5
  listed in PLAN.md's Surface contract also names its Surface, and its
6
6
  Check is the walkthrough performed — never internal test output. Embedded
7
- angle brackets are valid in concrete Check and Observed values. -->
7
+ angle brackets are valid in concrete Check and Observed values.
8
+ When .project/build/members.json locks members, add one line per locked
9
+ member after Reviewed HEAD: `Member reviewed HEAD: <member> <full SHA>`,
10
+ naming that member's bound branch tip. -->
8
11
 
9
12
  Reviewed HEAD: <full SHA>
10
13
  Overall verdict: <pass | blocked>
11
14
 
12
15
  <!-- pass only when every criterion is met; blocked when any criterion is
13
- not-met or unverifiable. -->
16
+ not-met or unverifiable.
17
+ A criterion with a held-out edge (E#) or judgment prohibition (N#) in
18
+ INTENT.md is met only when Check, Observed, or Reference cites every such
19
+ id with its evidence; otherwise it is unverifiable with
20
+ `Finding: insufficient spec evidence: <id> ...`. -->
14
21
 
15
22
  ## Success criteria
16
23
 
17
- ### SC1 — <criterion copied verbatim from INTENT.md>
24
+ <!-- Each `### SCn —` title must match INTENT.md `## Success criteria` as
25
+ `_success_criteria` stores it: continuation lines join with a single
26
+ space and keep `- ` sub-bullet markers; comparison uses `_normalize_ws`
27
+ only. -->
28
+
29
+ ### SC1 — <criterion as stored by the gate>
18
30
 
19
31
  - **Verdict**: <met | not-met | unverifiable>
20
- - **Surface**: <the surface PLAN.md's Surface contract lists this criterion under; omit the whole field for any other criterion>
32
+ - **Surface**: <exactly the surface name PLAN.md's Surface contract lists this criterion under, with no detail after it; omit the whole field for any other criterion>
21
33
  - **Check**: `<command actually run, or "none">`
22
34
  - **Observed**: <relevant output or observed behavior>
23
35
  - **Reference**: <file:line, artifact path, or "none">
@@ -1,7 +1,8 @@
1
1
  # Gap Review — <N>: <risk identity>
2
2
 
3
3
  <!-- Written by one final gap reviewer. This file covers exactly one
4
- cross-wave integration risk named in the review brief. -->
4
+ cross-wave integration risk named in the review brief. Repeat FINAL.md's
5
+ `Member reviewed HEAD: <member> <full SHA>` lines after Reviewed HEAD. -->
5
6
 
6
7
  Reviewed HEAD: <full SHA>
7
8
  Gap verdict: <pass | blocked>
@@ -57,6 +57,36 @@ paragraph the user signed off on — do not edit without a new sign-off.>
57
57
  1. <criterion — a thing you can run/measure/see>
58
58
  2. ...
59
59
 
60
+ ## Edge coverage
61
+
62
+ <!-- Written by define's edge probe (references/spec-probes.md). Walk every
63
+ success criterion; each applicable edge gets one row ruled by the user.
64
+ Disposition: criterion SCn (stated in that criterion) | held-out (a named
65
+ test pins the ruling written in Detail) | dismissed (Detail says why the
66
+ edge cannot occur). Every SCn appears at least once; a criterion with no
67
+ data shape gets category none, dismissed. Categories: boundary,
68
+ adjacency, empty, encoding, ordering, precision, idempotency,
69
+ concurrency, none. `check_handoffs.py intent` gates this table. -->
70
+
71
+ | Edge | Criterion | Category | Disposition | Detail |
72
+ |------|-----------|----------|-------------|--------|
73
+ | E1 | SC1 | <category> | <disposition> | <ruling, examples, or dismissal reason> |
74
+
75
+ ## Prohibitions
76
+
77
+ <!-- Written by define's prohibition probe. What each criterion must never
78
+ silently become: values, safety, privacy, fairness, transparency. Not
79
+ routine engineering, not generic security canon.
80
+ Disposition: criterion SCn (checkable; stated in that criterion) |
81
+ judgment (final reviewer judges it; Detail says what to look for) |
82
+ dismissed. A single row with Criterion `all`, Must not `none`, and
83
+ disposition dismissed, and no other row, records work that affects no
84
+ person directly. -->
85
+
86
+ | Prohibition | Criterion | Must not | Disposition | Detail |
87
+ |-------------|-----------|----------|-------------|--------|
88
+ | N1 | SC1 | <what it must never become> | <disposition> | <what the reviewer looks for, or why dismissed> |
89
+
60
90
  ## Scope: in
61
91
 
62
92
  <The smallest version that hits the success criteria. Bullet list.>
@@ -11,6 +11,6 @@ State: ship/blocked
11
11
  ### P001 — <short finding title>
12
12
 
13
13
  - **Source**: `.project/review/FINAL.md`
14
- - **Locator**: `<SC number or gap risk row>`
15
- - **Evidence**: <observed result copied from the source review>
16
- - **Fix direction**: <concrete direction for the patch task>
14
+ - **Locator**: <copy the full `Risk: ...` line from a gap review, or the `SC<n>` id from `FINAL.md`>
15
+ - **Evidence**: <copy the gap review's `Found` or `FINAL.md`'s `Finding` field verbatim>
16
+ - **Fix direction**: <copy the source's `Fix direction` field verbatim>
@@ -47,8 +47,8 @@ Goal: <the end-to-end slice that runs>
47
47
  Review depth: <full | deep | verify-only>
48
48
 
49
49
  <!-- More waves: features by dependency, then polish. Rules:
50
- - deps only in earlier waves, or same wave with no file overlap
51
- - no two same-wave tasks share files
50
+ - deps only in earlier waves or the same wave
51
+ - same-wave tasks share files only when one transitively depends on the other
52
52
  - nothing from INTENT.md scope-out appears anywhere -->
53
53
 
54
54
  ## Surface contract
@@ -83,6 +83,21 @@ Walkthrough:
83
83
  |-----------|------|------------|
84
84
  | SC1 | T001 | AC1 |
85
85
 
86
+ ## Held-out checks
87
+
88
+ <!-- Required when INTENT.md Edge coverage has a held-out edge; omit the
89
+ section entirely when it has none. One row per held-out edge, given to
90
+ the task that owns the edge's criterion. Test is a file listed in that
91
+ task's files (optionally `path::test_name`); the task's Verify runs it
92
+ and its Acceptance
93
+ criteria state the edge id and the ruling from INTENT.md Detail. Final
94
+ review cites this test's recorded result for the edge.
95
+ `scripts/check_handoffs.py plan` gates this table. -->
96
+
97
+ | Edge | Task | Test |
98
+ |------|------|------|
99
+ | E1 | T001 | <test path from T001 files> |
100
+
86
101
  ## Dependency notes
87
102
 
88
103
  <Per non-obvious edge: the exact data or landed effect that makes X precede Y,
@@ -14,12 +14,23 @@ Intent: `.project/intent/INTENT.md`
14
14
  <!-- Include every standard dimension exactly once. A custom dimension may
15
15
  supplement these rows, never replace a standard row. -->
16
16
  - `domain` — dispatched → `.project/research/evidence-domain.md` — <why this dimension ran>
17
- - `stack` — skipped → none — <why this dimension was skipped>
17
+ - `stack` — dispatched → `.project/research/evidence-stack.md` — <why this dimension ran>
18
18
  - `pitfalls` — skipped → none — <why this dimension was skipped>
19
19
  - `similar` — skipped → none — <why this dimension was skipped>
20
20
 
21
21
  ## Question assignments
22
22
 
23
23
  <!-- Copy every [RESEARCH] question from INTENT.md exactly once. Use `- none`
24
- only when INTENT.md has no [RESEARCH] questions. -->
25
- - `[RESEARCH] <question copied from INTENT.md>` → `domain`
24
+ only when INTENT.md has no [RESEARCH] questions. The question is a
25
+ CommonMark code span: choose a fence length not used by a backtick run in
26
+ the question (a longer fence is usually easiest), with one space of
27
+ padding on each side. Each row may target one or more dispatched
28
+ dimensions, each in its own code span and separated by commas. Every
29
+ dispatched dimension must receive a question and answer all its assigned
30
+ questions in its evidence file. For example:
31
+ - `` [RESEARCH] Does `Widget` match `sample.json`? `` → `domain`, `stack`
32
+ A question that ends in a backtick also needs padding, as in:
33
+ - `` [RESEARCH] Does the label end with `Widget`?` `` → `domain`
34
+ After removing the fence and CommonMark padding, the text must equal the
35
+ INTENT question exactly. -->
36
+ - `` [RESEARCH] <question copied from INTENT.md> `` → `domain`, `stack`
@@ -10,7 +10,7 @@ branch: null # bound per milestone as gsd-path/M00N; after integration
10
10
  # the router rebinds before any next-milestone file change
11
11
  # the bound branch is never main; ship integrates it there
12
12
  archive: null # persisted archive transaction path; never recomputed
13
- integration_default: direct # direct | pull-request; project setting
13
+ integration_default: direct # direct | pull-request | external-landing; project setting
14
14
  integration: direct # current milestone; may override the default before build
15
15
  integration_source: default # default | milestone; preserves override provenance
16
16
  ---
@@ -10,6 +10,7 @@ worktree: null # orchestrator-owned: isolated task worktree while active
10
10
  task_branch: null # orchestrator-owned: gsd-path-task/<id> while parallel; null when serial
11
11
  # Optional explicit dispatch overrides: model: <advertised slug|inherit>
12
12
  # effort: <advertised effort|inherit>
13
+ # repo: <member> # multi-repo only: the MEMBERS.md member this task changes; omit for the coordinator
13
14
  files: # every file this task may touch — dispatch checks overlap
14
15
  - <path>
15
16
  ---
@@ -10,8 +10,11 @@
10
10
  with actual values, otherwise omit them:
11
11
  Reviewed HEAD: <full review commit SHA>
12
12
  Review scope: final
13
- In each surface SC block also include Surface, Check, and Observed fields
14
- using the final-review format. Record the actual walkthrough evidence once. -->
13
+ In each surface SC block keep the mandatory `- ✅` / `- ❌` evidence line
14
+ (the wave gate requires it). Also include Surface, Check, and Observed
15
+ fields using the final-review format. Surface holds exactly the surface name
16
+ from PLAN.md's Surface contract; put walkthrough detail in Check and Observed.
17
+ The `- ✅` line may summarize Observed; do not omit it. -->
15
18
 
16
19
  Wave verdict: <pass | blocked — blocked if any task fails>
17
20
  Cycle: <C>
@@ -43,12 +46,21 @@ Contract violations (blocking):
43
46
  <!-- One heading per INTENT.md success criterion owned by a task in this
44
47
  wave, ending `: pass` or `: fail`. `scripts/check_handoffs.py wave
45
48
  --review <this file>` gates the SC id set and verdicts. Omit this
46
- section when no task in the wave owns an SC. -->
49
+ section when no task in the wave owns an SC.
50
+ Copy the criterion text from INTENT.md `## Success criteria` exactly as
51
+ `_success_criteria` stores it: indented continuation lines join with a
52
+ single space and keep their leading `- ` markers; the gate compares
53
+ heading text with `_normalize_ws` only (no paraphrase or stripped
54
+ sub-bullets). -->
47
55
 
48
- ### SC1 — <criterion>: <pass | fail>
56
+ ### SC1 — <criterion as stored by the gate>: <pass | fail>
49
57
  - ✅ <evidence: verify output / file:line checked>
50
58
  - ❌ <criterion> — found: <what exists instead, file:line>
51
59
  fix: <concrete direction a coder can execute without re-investigating>
60
+ <!-- Quick-lane final scope (Review scope: final): add after the evidence line:
61
+ - **Surface**: <surface name from PLAN.md>
62
+ - **Check**: `<walkthrough command>`
63
+ - **Observed**: <what was seen> -->
52
64
 
53
65
  ## Fixed since last cycle
54
66