@opengsd/gsd-path 1.5.0 → 1.6.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 (352) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/DOCS.md +4 -3
  3. package/FULL.md +64 -4
  4. package/HOOKS.md +63 -2
  5. package/MIGRATE.md +12 -0
  6. package/QUICK.md +4 -2
  7. package/README.md +67 -15
  8. package/RUNTIME.md +23 -5
  9. package/UPDATE.md +35 -0
  10. package/WORKFLOW.md +58 -3
  11. package/package.json +1 -1
  12. package/scripts/_common.py +107 -1
  13. package/scripts/build_recovery.py +62 -30
  14. package/scripts/build_state.py +195 -5
  15. package/scripts/check_handoffs.py +92 -30
  16. package/scripts/check_task_briefs.py +19 -14
  17. package/scripts/detect_project.py +17 -2
  18. package/scripts/discussion_records.py +9 -1
  19. package/scripts/discussion_validate.py +7 -6
  20. package/scripts/dispatch_driver.py +157 -31
  21. package/scripts/git_guard.py +24 -5
  22. package/scripts/guard_hook.py +1216 -47
  23. package/scripts/install.mjs +76 -3
  24. package/scripts/install.py +182 -37
  25. package/scripts/integration.py +98 -64
  26. package/scripts/isolation.py +148 -11
  27. package/scripts/members.py +68 -25
  28. package/scripts/migrate_core.py +2 -0
  29. package/scripts/model_policy.py +5 -1
  30. package/scripts/pipeline_diagnose.py +17 -2
  31. package/scripts/pipeline_git.py +68 -30
  32. package/scripts/pipeline_state.py +28 -6
  33. package/scripts/pipeline_undo.py +17 -8
  34. package/scripts/promote_lookahead.py +3 -3
  35. package/scripts/review_findings.py +180 -44
  36. package/scripts/roadmap.py +9 -1
  37. package/scripts/runtime_store.py +1 -0
  38. package/scripts/state_checkpoint.py +30 -9
  39. package/scripts/state_promote.py +15 -4
  40. package/scripts/task_context.py +2 -0
  41. package/scripts/workflow_run.py +9 -2
  42. package/skills/gsd-path/DEFINE.md +6 -2
  43. package/skills/gsd-path/PLAN.md +3 -0
  44. package/skills/gsd-path/ROADMAP.md +16 -6
  45. package/skills/gsd-path/SHIP.md +26 -4
  46. package/skills/gsd-path/SKILL.md +52 -24
  47. package/skills/gsd-path/references/build-native.md +96 -9
  48. package/skills/gsd-path/references/build-recovery.md +13 -0
  49. package/skills/gsd-path/references/coder.md +7 -3
  50. package/skills/gsd-path/references/operating-rules.md +11 -3
  51. package/skills/gsd-path/references/planner.md +13 -1
  52. package/skills/gsd-path/references/reviewer-final.md +5 -5
  53. package/skills/gsd-path/references/reviewer-wave.md +46 -13
  54. package/skills/gsd-path/references/runtime-selection.md +9 -0
  55. package/skills/gsd-path/scripts/_common.py +107 -1
  56. package/skills/gsd-path/scripts/build_recovery.py +62 -30
  57. package/skills/gsd-path/scripts/build_state.py +195 -5
  58. package/skills/gsd-path/scripts/check_handoffs.py +92 -30
  59. package/skills/gsd-path/scripts/check_task_briefs.py +19 -14
  60. package/skills/gsd-path/scripts/detect_project.py +17 -2
  61. package/skills/gsd-path/scripts/discussion_records.py +9 -1
  62. package/skills/gsd-path/scripts/discussion_validate.py +7 -6
  63. package/skills/gsd-path/scripts/dispatch_driver.py +157 -31
  64. package/skills/gsd-path/scripts/git_guard.py +24 -5
  65. package/skills/gsd-path/scripts/integration.py +98 -64
  66. package/skills/gsd-path/scripts/isolation.py +148 -11
  67. package/skills/gsd-path/scripts/members.py +68 -25
  68. package/skills/gsd-path/scripts/model_policy.py +5 -1
  69. package/skills/gsd-path/scripts/pipeline_git.py +68 -30
  70. package/skills/gsd-path/scripts/pipeline_state.py +28 -6
  71. package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
  72. package/skills/gsd-path/scripts/review_findings.py +180 -44
  73. package/skills/gsd-path/scripts/roadmap.py +9 -1
  74. package/skills/gsd-path/scripts/state_checkpoint.py +30 -9
  75. package/skills/gsd-path/scripts/state_promote.py +15 -4
  76. package/skills/gsd-path/scripts/task_context.py +2 -0
  77. package/skills/gsd-path/scripts/workflow_run.py +9 -2
  78. package/skills/gsd-path/templates/final-review.md +5 -5
  79. package/skills/gsd-path/templates/state.md +1 -0
  80. package/skills/gsd-path/templates/task.md +1 -0
  81. package/skills/gsd-path/templates/wave-review.md +18 -9
  82. package/skills/gsd-path-build/references/build-native.md +96 -9
  83. package/skills/gsd-path-build/references/build-recovery.md +13 -0
  84. package/skills/gsd-path-build/references/coder.md +7 -3
  85. package/skills/gsd-path-build/references/operating-rules.md +11 -3
  86. package/skills/gsd-path-build/references/reviewer-final.md +5 -5
  87. package/skills/gsd-path-build/references/reviewer-wave.md +46 -13
  88. package/skills/gsd-path-build/references/runtime-selection.md +9 -0
  89. package/skills/gsd-path-build/scripts/_common.py +107 -1
  90. package/skills/gsd-path-build/scripts/build_recovery.py +62 -30
  91. package/skills/gsd-path-build/scripts/build_state.py +195 -5
  92. package/skills/gsd-path-build/scripts/check_handoffs.py +92 -30
  93. package/skills/gsd-path-build/scripts/check_task_briefs.py +19 -14
  94. package/skills/gsd-path-build/scripts/detect_project.py +17 -2
  95. package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
  96. package/skills/gsd-path-build/scripts/discussion_validate.py +7 -6
  97. package/skills/gsd-path-build/scripts/dispatch_driver.py +157 -31
  98. package/skills/gsd-path-build/scripts/integration.py +98 -64
  99. package/skills/gsd-path-build/scripts/isolation.py +148 -11
  100. package/skills/gsd-path-build/scripts/members.py +68 -25
  101. package/skills/gsd-path-build/scripts/model_policy.py +5 -1
  102. package/skills/gsd-path-build/scripts/pipeline_git.py +68 -30
  103. package/skills/gsd-path-build/scripts/pipeline_state.py +28 -6
  104. package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
  105. package/skills/gsd-path-build/scripts/review_findings.py +180 -44
  106. package/skills/gsd-path-build/scripts/roadmap.py +9 -1
  107. package/skills/gsd-path-build/scripts/state_checkpoint.py +30 -9
  108. package/skills/gsd-path-build/scripts/state_promote.py +15 -4
  109. package/skills/gsd-path-build/scripts/task_context.py +2 -0
  110. package/skills/gsd-path-build/scripts/workflow_run.py +9 -2
  111. package/skills/gsd-path-build/templates/task.md +1 -0
  112. package/skills/gsd-path-build/templates/wave-review.md +18 -9
  113. package/skills/gsd-path-decide/references/operating-rules.md +11 -3
  114. package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
  115. package/skills/gsd-path-decide/scripts/_common.py +107 -1
  116. package/skills/gsd-path-decide/scripts/build_recovery.py +62 -30
  117. package/skills/gsd-path-decide/scripts/check_handoffs.py +92 -30
  118. package/skills/gsd-path-decide/scripts/check_task_briefs.py +19 -14
  119. package/skills/gsd-path-decide/scripts/detect_project.py +17 -2
  120. package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
  121. package/skills/gsd-path-decide/scripts/discussion_validate.py +7 -6
  122. package/skills/gsd-path-decide/scripts/integration.py +98 -64
  123. package/skills/gsd-path-decide/scripts/isolation.py +148 -11
  124. package/skills/gsd-path-decide/scripts/members.py +68 -25
  125. package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
  126. package/skills/gsd-path-decide/scripts/pipeline_git.py +68 -30
  127. package/skills/gsd-path-decide/scripts/pipeline_state.py +28 -6
  128. package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
  129. package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
  130. package/skills/gsd-path-decide/scripts/state_checkpoint.py +30 -9
  131. package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
  132. package/skills/gsd-path-define/SKILL.md +6 -2
  133. package/skills/gsd-path-define/references/build-recovery.md +13 -0
  134. package/skills/gsd-path-define/references/operating-rules.md +11 -3
  135. package/skills/gsd-path-define/references/runtime-selection.md +9 -0
  136. package/skills/gsd-path-define/scripts/_common.py +107 -1
  137. package/skills/gsd-path-define/scripts/build_recovery.py +62 -30
  138. package/skills/gsd-path-define/scripts/check_handoffs.py +92 -30
  139. package/skills/gsd-path-define/scripts/check_task_briefs.py +19 -14
  140. package/skills/gsd-path-define/scripts/detect_project.py +17 -2
  141. package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
  142. package/skills/gsd-path-define/scripts/discussion_validate.py +7 -6
  143. package/skills/gsd-path-define/scripts/integration.py +98 -64
  144. package/skills/gsd-path-define/scripts/isolation.py +148 -11
  145. package/skills/gsd-path-define/scripts/members.py +68 -25
  146. package/skills/gsd-path-define/scripts/model_policy.py +5 -1
  147. package/skills/gsd-path-define/scripts/pipeline_git.py +68 -30
  148. package/skills/gsd-path-define/scripts/pipeline_state.py +28 -6
  149. package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
  150. package/skills/gsd-path-define/scripts/roadmap.py +9 -1
  151. package/skills/gsd-path-define/scripts/state_checkpoint.py +30 -9
  152. package/skills/gsd-path-define/scripts/state_promote.py +15 -4
  153. package/skills/gsd-path-define/templates/state.md +1 -0
  154. package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
  155. package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
  156. package/skills/gsd-path-discuss/scripts/_common.py +107 -1
  157. package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
  158. package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
  159. package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
  160. package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
  161. package/skills/gsd-path-docs-audit/scripts/_common.py +107 -1
  162. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +62 -30
  163. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +92 -30
  164. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +19 -14
  165. package/skills/gsd-path-docs-audit/scripts/detect_project.py +17 -2
  166. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
  167. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +7 -6
  168. package/skills/gsd-path-docs-audit/scripts/integration.py +98 -64
  169. package/skills/gsd-path-docs-audit/scripts/isolation.py +148 -11
  170. package/skills/gsd-path-docs-audit/scripts/members.py +68 -25
  171. package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
  172. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +68 -30
  173. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +28 -6
  174. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
  175. package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
  176. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +30 -9
  177. package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
  178. package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
  179. package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
  180. package/skills/gsd-path-forensics/scripts/_common.py +107 -1
  181. package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
  182. package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
  183. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
  184. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +17 -8
  185. package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
  186. package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
  187. package/skills/gsd-path-inspect/scripts/_common.py +107 -1
  188. package/skills/gsd-path-inspect/scripts/build_recovery.py +62 -30
  189. package/skills/gsd-path-inspect/scripts/check_handoffs.py +92 -30
  190. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +19 -14
  191. package/skills/gsd-path-inspect/scripts/detect_project.py +17 -2
  192. package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
  193. package/skills/gsd-path-inspect/scripts/discussion_validate.py +7 -6
  194. package/skills/gsd-path-inspect/scripts/integration.py +98 -64
  195. package/skills/gsd-path-inspect/scripts/isolation.py +148 -11
  196. package/skills/gsd-path-inspect/scripts/members.py +68 -25
  197. package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
  198. package/skills/gsd-path-inspect/scripts/pipeline_git.py +68 -30
  199. package/skills/gsd-path-inspect/scripts/pipeline_state.py +28 -6
  200. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
  201. package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
  202. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +30 -9
  203. package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
  204. package/skills/gsd-path-inspect/scripts/workflow_run.py +9 -2
  205. package/skills/gsd-path-inspect/templates/state.md +1 -0
  206. package/skills/gsd-path-loop/references/operating-rules.md +11 -3
  207. package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
  208. package/skills/gsd-path-loop/scripts/_common.py +107 -1
  209. package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
  210. package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
  211. package/skills/gsd-path-migrate/SKILL.md +8 -0
  212. package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
  213. package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
  214. package/skills/gsd-path-migrate/scripts/_common.py +107 -1
  215. package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
  216. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
  217. package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
  218. package/skills/gsd-path-plan/SKILL.md +3 -0
  219. package/skills/gsd-path-plan/references/build-recovery.md +13 -0
  220. package/skills/gsd-path-plan/references/operating-rules.md +11 -3
  221. package/skills/gsd-path-plan/references/planner.md +13 -1
  222. package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
  223. package/skills/gsd-path-plan/scripts/_common.py +107 -1
  224. package/skills/gsd-path-plan/scripts/build_recovery.py +62 -30
  225. package/skills/gsd-path-plan/scripts/check_handoffs.py +92 -30
  226. package/skills/gsd-path-plan/scripts/check_task_briefs.py +19 -14
  227. package/skills/gsd-path-plan/scripts/detect_project.py +17 -2
  228. package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
  229. package/skills/gsd-path-plan/scripts/discussion_validate.py +7 -6
  230. package/skills/gsd-path-plan/scripts/integration.py +98 -64
  231. package/skills/gsd-path-plan/scripts/isolation.py +148 -11
  232. package/skills/gsd-path-plan/scripts/members.py +68 -25
  233. package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
  234. package/skills/gsd-path-plan/scripts/pipeline_git.py +68 -30
  235. package/skills/gsd-path-plan/scripts/pipeline_state.py +28 -6
  236. package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
  237. package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
  238. package/skills/gsd-path-plan/scripts/state_checkpoint.py +30 -9
  239. package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
  240. package/skills/gsd-path-plan/scripts/workflow_run.py +9 -2
  241. package/skills/gsd-path-plan/templates/task.md +1 -0
  242. package/skills/gsd-path-research/references/operating-rules.md +11 -3
  243. package/skills/gsd-path-research/references/runtime-selection.md +9 -0
  244. package/skills/gsd-path-research/scripts/_common.py +107 -1
  245. package/skills/gsd-path-research/scripts/build_recovery.py +62 -30
  246. package/skills/gsd-path-research/scripts/check_handoffs.py +92 -30
  247. package/skills/gsd-path-research/scripts/check_task_briefs.py +19 -14
  248. package/skills/gsd-path-research/scripts/detect_project.py +17 -2
  249. package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
  250. package/skills/gsd-path-research/scripts/discussion_validate.py +7 -6
  251. package/skills/gsd-path-research/scripts/integration.py +98 -64
  252. package/skills/gsd-path-research/scripts/isolation.py +148 -11
  253. package/skills/gsd-path-research/scripts/members.py +68 -25
  254. package/skills/gsd-path-research/scripts/model_policy.py +5 -1
  255. package/skills/gsd-path-research/scripts/pipeline_git.py +68 -30
  256. package/skills/gsd-path-research/scripts/pipeline_state.py +28 -6
  257. package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
  258. package/skills/gsd-path-research/scripts/roadmap.py +9 -1
  259. package/skills/gsd-path-research/scripts/state_checkpoint.py +30 -9
  260. package/skills/gsd-path-research/scripts/state_promote.py +15 -4
  261. package/skills/gsd-path-roadmap/SKILL.md +16 -6
  262. package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
  263. package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
  264. package/skills/gsd-path-roadmap/scripts/_common.py +107 -1
  265. package/skills/gsd-path-roadmap/scripts/build_recovery.py +62 -30
  266. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +92 -30
  267. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +19 -14
  268. package/skills/gsd-path-roadmap/scripts/detect_project.py +17 -2
  269. package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
  270. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +7 -6
  271. package/skills/gsd-path-roadmap/scripts/integration.py +98 -64
  272. package/skills/gsd-path-roadmap/scripts/isolation.py +148 -11
  273. package/skills/gsd-path-roadmap/scripts/members.py +68 -25
  274. package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
  275. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +68 -30
  276. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +28 -6
  277. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
  278. package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
  279. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +30 -9
  280. package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
  281. package/skills/gsd-path-ship/SKILL.md +26 -4
  282. package/skills/gsd-path-ship/references/operating-rules.md +11 -3
  283. package/skills/gsd-path-ship/references/reviewer-final.md +5 -5
  284. package/skills/gsd-path-ship/references/reviewer-wave.md +46 -13
  285. package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
  286. package/skills/gsd-path-ship/scripts/_common.py +107 -1
  287. package/skills/gsd-path-ship/scripts/build_recovery.py +62 -30
  288. package/skills/gsd-path-ship/scripts/build_state.py +195 -5
  289. package/skills/gsd-path-ship/scripts/check_handoffs.py +92 -30
  290. package/skills/gsd-path-ship/scripts/check_task_briefs.py +19 -14
  291. package/skills/gsd-path-ship/scripts/detect_project.py +17 -2
  292. package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
  293. package/skills/gsd-path-ship/scripts/discussion_validate.py +7 -6
  294. package/skills/gsd-path-ship/scripts/integration.py +98 -64
  295. package/skills/gsd-path-ship/scripts/isolation.py +148 -11
  296. package/skills/gsd-path-ship/scripts/members.py +68 -25
  297. package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
  298. package/skills/gsd-path-ship/scripts/pipeline_git.py +68 -30
  299. package/skills/gsd-path-ship/scripts/pipeline_state.py +28 -6
  300. package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
  301. package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
  302. package/skills/gsd-path-ship/scripts/state_checkpoint.py +30 -9
  303. package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
  304. package/skills/gsd-path-ship/scripts/workflow_run.py +9 -2
  305. package/skills/gsd-path-ship/templates/final-review.md +5 -5
  306. package/skills/gsd-path-ship/templates/wave-review.md +18 -9
  307. package/skills/gsd-path-undo/references/operating-rules.md +11 -3
  308. package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
  309. package/skills/gsd-path-undo/scripts/_common.py +107 -1
  310. package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
  311. package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
  312. package/skills/gsd-path-undo/scripts/pipeline_undo.py +17 -8
  313. package/skills/path/DEFINE.md +6 -2
  314. package/skills/path/PLAN.md +3 -0
  315. package/skills/path/ROADMAP.md +16 -6
  316. package/skills/path/SHIP.md +26 -4
  317. package/skills/path/SKILL.md +52 -24
  318. package/skills/path/references/build-native.md +96 -9
  319. package/skills/path/references/build-recovery.md +13 -0
  320. package/skills/path/references/coder.md +7 -3
  321. package/skills/path/references/operating-rules.md +11 -3
  322. package/skills/path/references/planner.md +13 -1
  323. package/skills/path/references/reviewer-final.md +5 -5
  324. package/skills/path/references/reviewer-wave.md +46 -13
  325. package/skills/path/references/runtime-selection.md +9 -0
  326. package/skills/path/scripts/_common.py +107 -1
  327. package/skills/path/scripts/build_recovery.py +62 -30
  328. package/skills/path/scripts/build_state.py +195 -5
  329. package/skills/path/scripts/check_handoffs.py +92 -30
  330. package/skills/path/scripts/check_task_briefs.py +19 -14
  331. package/skills/path/scripts/detect_project.py +17 -2
  332. package/skills/path/scripts/discussion_records.py +9 -1
  333. package/skills/path/scripts/discussion_validate.py +7 -6
  334. package/skills/path/scripts/dispatch_driver.py +157 -31
  335. package/skills/path/scripts/git_guard.py +24 -5
  336. package/skills/path/scripts/integration.py +98 -64
  337. package/skills/path/scripts/isolation.py +148 -11
  338. package/skills/path/scripts/members.py +68 -25
  339. package/skills/path/scripts/model_policy.py +5 -1
  340. package/skills/path/scripts/pipeline_git.py +68 -30
  341. package/skills/path/scripts/pipeline_state.py +28 -6
  342. package/skills/path/scripts/promote_lookahead.py +3 -3
  343. package/skills/path/scripts/review_findings.py +180 -44
  344. package/skills/path/scripts/roadmap.py +9 -1
  345. package/skills/path/scripts/state_checkpoint.py +30 -9
  346. package/skills/path/scripts/state_promote.py +15 -4
  347. package/skills/path/scripts/task_context.py +2 -0
  348. package/skills/path/scripts/workflow_run.py +9 -2
  349. package/skills/path/templates/final-review.md +5 -5
  350. package/skills/path/templates/state.md +1 -0
  351. package/skills/path/templates/task.md +1 -0
  352. package/skills/path/templates/wave-review.md +18 -9
@@ -20,6 +20,15 @@ references to bundled copies of those helpers. Other skill helpers, templates,
20
20
  and role briefs remain in the installed skill bundle. Pass `-B` to Python helper
21
21
  invocations so execution does not create bytecode in the runtime store.
22
22
 
23
+ The selected runtime is authoritative for each helper in its `manifest.json`;
24
+ this includes `review_findings.py` and `task_context.py`. A selected runtime
25
+ that was published before a helper became a runtime file does not list that
26
+ helper: run the bundled copy until the project runtime is upgraded.
27
+ `dispatch_driver.py` and `workflow_run.py` always run from the installed skill
28
+ bundle, because they read role briefs and templates from it; a skill update
29
+ replaces them, a runtime upgrade does not. The driver reloads the helper modules
30
+ that it imports from the selected runtime.
31
+
23
32
  With no declaration, retain the legacy helper lookup. An existing
24
33
  `.gsd-path/runtime/` requires the explicit `--runtime-migrate --project PATH`
25
34
  operation before adopting external storage; review the resulting Git diff.
@@ -25,7 +25,8 @@ import signal
25
25
  import subprocess
26
26
  import time
27
27
  from pathlib import Path
28
- from typing import BinaryIO, Iterator, List, Optional, Sequence
28
+ from typing import BinaryIO, Iterable, Iterator, List, Optional, Sequence, Tuple
29
+
29
30
 
30
31
  # Chosen by what imports, not os.name, so tests can emulate Windows on POSIX.
31
32
  try:
@@ -161,6 +162,33 @@ def project_ignore_error(repo: Path) -> Optional[str]:
161
162
  + ". Anchor the product rule (for example `/build/`) in a task that owns it.")
162
163
 
163
164
 
165
+ _DEFAULT_BRANCH_RE = re.compile(
166
+ r"[^\s#\"'\\~^:?*\[\x00-\x1f\x7f-][^\s#\"'\\~^:?*\[\x00-\x1f\x7f]*"
167
+ )
168
+ _RESERVED_BRANCH_PREFIXES = ("gsd-path/", "gsd-path-integrate/", "gsd-path-task/")
169
+
170
+
171
+ def valid_default_branch(name: str) -> bool:
172
+ """A git branch name that STATE frontmatter can hold and Path does not reserve."""
173
+ return (
174
+ bool(_DEFAULT_BRANCH_RE.fullmatch(name))
175
+ and name != "null"
176
+ and not name.startswith(_RESERVED_BRANCH_PREFIXES)
177
+ and not name.endswith(("/", ".", ".lock"))
178
+ and not any(part in name for part in ("..", "//", "/.", "@{"))
179
+ )
180
+
181
+
182
+ def origin_default_branch(repo: Path) -> str:
183
+ """The origin default branch that initialization records; an unset origin/HEAD means main."""
184
+ result = run_git(repo, "symbolic-ref", "--quiet", "refs/remotes/origin/HEAD")
185
+ prefix = "refs/remotes/origin/"
186
+ remote_ref = result.stdout.strip()
187
+ if result.returncode != 0 or not remote_ref.startswith(prefix):
188
+ return "main"
189
+ return remote_ref.removeprefix(prefix)
190
+
191
+
164
192
  def section_body(text: str, heading: str) -> Optional[str]:
165
193
  """The text under `## <heading>` up to the next `## `, or None when absent."""
166
194
  match = re.search(
@@ -169,6 +197,79 @@ def section_body(text: str, heading: str) -> Optional[str]:
169
197
  return match.group("body") if match else None
170
198
 
171
199
 
200
+ def overlapping_paths(left: Sequence[str], right: Sequence[str]) -> List[str]:
201
+ """Return the sorted paths that two task `files` lists both cover.
202
+
203
+ An entry covers itself and the paths below it. For a declared directory
204
+ and a path below it, the result names the lower path. The callers have no
205
+ task base, so this does not ask if an entry is a file: the task-brief
206
+ lint rejects a path below a file at the base.
207
+ """
208
+ return sorted(
209
+ {
210
+ max(one, other, key=len)
211
+ for one in left
212
+ for other in right
213
+ if one == other or one.startswith(other + "/") or other.startswith(one + "/")
214
+ }
215
+ )
216
+
217
+
218
+ # The `- ` of an indented sub-bullet line. A line that would then read as a
219
+ # numbered item (`- 2. text`) keeps its marker, so both readings of a source
220
+ # have the same criteria.
221
+ SUB_BULLET_MARKER = re.compile(r"(?m)^([ \t]+)-[ \t]+(?![ \t]*\d+\.\s)")
222
+
223
+
224
+ def without_sub_bullet_markers(source: str) -> str:
225
+ """`source` with the `- ` marker of each indented sub-bullet line removed."""
226
+ return SUB_BULLET_MARKER.sub(r"\1", source)
227
+
228
+
229
+ class Criterion(str):
230
+ """A criterion as its parser joins it, with the `- ` markers of its sub-bullet lines.
231
+
232
+ `bare` is the same criterion parsed from `without_sub_bullet_markers(source)`.
233
+ The joined text cannot tell a marker from a minus sign; the source lines can.
234
+ """
235
+
236
+ bare: str
237
+
238
+ def __new__(cls, text: str, bare: str) -> "Criterion":
239
+ criterion = super().__new__(cls, text)
240
+ criterion.bare = bare
241
+ return criterion
242
+
243
+
244
+ def quotes_criterion(quote: str, criterion: str) -> bool:
245
+ """Whether a review quote is `criterion`, for every reader.
246
+
247
+ Only whitespace is collapsed. The quote must equal the criterion with all
248
+ the markers of its sub-bullet lines or with none of them; every other
249
+ character, a hyphen inside a line too, is compared.
250
+ """
251
+ forms = (criterion, getattr(criterion, "bare", criterion))
252
+ return " ".join(quote.split()) in {" ".join(form.split()) for form in forms}
253
+
254
+
255
+ def quoted_criterion(item: str, criteria: Sequence[str]) -> Optional[Tuple[int, int]]:
256
+ """Index of the criterion quoted at the start of `item`, and where the quote ends.
257
+
258
+ A criterion can contain ` — ` itself, so each separator and the end of
259
+ `item` is a candidate, the longest quote first. A criterion as written
260
+ wins over any criterion read without its sub-bullet markers.
261
+ """
262
+ ends = [match.start() for match in re.finditer("(?= —(?: |$))|$", item)][::-1]
263
+ for bare in (False, True):
264
+ for end in ends:
265
+ quote = " ".join(item[:end].split())
266
+ for index, criterion in enumerate(criteria):
267
+ form = getattr(criterion, "bare", criterion) if bare else criterion
268
+ if quote == " ".join(form.split()):
269
+ return index, end
270
+ return None
271
+
272
+
172
273
  def task_verify_command(task_text: str) -> str:
173
274
  """The Verify shell text, excluding the closing fence's separator newline."""
174
275
  body = section_body(task_text, "Verify")
@@ -176,6 +277,11 @@ def task_verify_command(task_text: str) -> str:
176
277
  return block.group("block").removesuffix("\n") if block else ""
177
278
 
178
279
 
280
+ def fix_verify(commands: Iterable[str]) -> str:
281
+ """The Verify of a fix task: each distinct source Verify in its own subshell, under `set -e`."""
282
+ return "set -e\n" + "\n".join(f"(\n{command}\n)" for command in dict.fromkeys(commands))
283
+
284
+
179
285
  def latest_verify_entry(entries: list, command: str, commit: str,
180
286
  repo: Optional[str] = None) -> Optional[dict]:
181
287
  """Rows are keyed by (command, repo, commit); a row without `repo` is a coordinator row."""
@@ -7,6 +7,7 @@ import json
7
7
  import os
8
8
  import shutil
9
9
  import sys
10
+ import traceback
10
11
 
11
12
  # Runtime helpers must not modify their immutable installation.
12
13
  sys.dont_write_bytecode = True
@@ -33,7 +34,7 @@ def _load_pipeline_modules():
33
34
  try:
34
35
  from scripts import archive_milestone, pipeline_state, _common
35
36
  return _common, archive_milestone, pipeline_state
36
- except ModuleNotFoundError as error:
37
+ except ImportError as error: # a foreign `scripts` package
37
38
  if error.name not in {
38
39
  "scripts",
39
40
  "scripts.archive_milestone",
@@ -41,6 +42,13 @@ def _load_pipeline_modules():
41
42
  "scripts._common",
42
43
  }:
43
44
  raise
45
+ # A plain ImportError raised while a `scripts` module loaded is not a
46
+ # foreign package. A missing module falls back, as before.
47
+ if not isinstance(error, ModuleNotFoundError) and any(
48
+ frame.f_globals.get("__name__", "").startswith("scripts.")
49
+ for frame, _ in traceback.walk_tb(error.__traceback__)
50
+ ):
51
+ raise
44
52
  shared_scripts = Path(__file__).resolve().parents[2] / "gsd-path" / "scripts"
45
53
  sys.path.insert(0, str(shared_scripts))
46
54
  import archive_milestone
@@ -202,7 +202,11 @@ def native_record(args):
202
202
  identity = {'repo': str(args.repo.resolve()), 'project_dir': args.project_dir,
203
203
  'scope': args.scope, 'assignment': args.assignment, 'role': args.role}
204
204
  if data is not None and data.get('identity') != identity:
205
- raise PolicyError('record belongs to another assignment or milestone/track/cycle')
205
+ recorded = data.get('identity')
206
+ recorded = recorded if isinstance(recorded, dict) else {}
207
+ differing = ', '.join(f'{field}: {value}, record has {recorded.get(field)}'
208
+ for field, value in identity.items() if recorded.get(field) != value)
209
+ raise PolicyError(f'record belongs to another assignment or milestone/track/cycle ({differing})')
206
210
  if args.action == 'release':
207
211
  if data is None or not args.terminal_result:
208
212
  raise PolicyError('release requires an existing record and terminal-result evidence')
@@ -22,6 +22,7 @@ from datetime import date
22
22
  # Runtime helpers must not modify their immutable installation.
23
23
  sys.dont_write_bytecode = True
24
24
  import tempfile
25
+ import traceback
25
26
  from pathlib import Path, PurePosixPath
26
27
  from typing import Optional, Sequence
27
28
 
@@ -53,7 +54,7 @@ def _load_pipeline_modules():
53
54
  try:
54
55
  from scripts import archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
55
56
  return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
56
- except ModuleNotFoundError as error:
57
+ except ImportError as error: # a foreign `scripts` package
57
58
  if error.name not in {
58
59
  "scripts",
59
60
  "scripts.archive_milestone",
@@ -63,6 +64,13 @@ def _load_pipeline_modules():
63
64
  "scripts.state_checkpoint",
64
65
  }:
65
66
  raise
67
+ # A plain ImportError raised while a `scripts` module loaded is not a
68
+ # foreign package. A missing module falls back, as before.
69
+ if not isinstance(error, ModuleNotFoundError) and any(
70
+ frame.f_globals.get("__name__", "").startswith("scripts.")
71
+ for frame, _ in traceback.walk_tb(error.__traceback__)
72
+ ):
73
+ raise
66
74
  shared = Path(__file__).resolve().parents[2] / "gsd-path" / "scripts"
67
75
  sys.path.insert(0, str(shared))
68
76
  import archive_milestone
@@ -772,14 +780,15 @@ def _member_undo_parent(repo: Path, member: str, landing: str) -> str:
772
780
  bound = entry["branch"]
773
781
  if _run_git(checkout, "rev-parse", f"refs/heads/{bound}").stdout.strip() != landing:
774
782
  raise UndoError(f"member {member} {bound} moved past this landing")
775
- _require_member_unpublished(checkout, member, landing, bound)
783
+ _require_member_unpublished(repo, checkout, member, landing, bound)
776
784
  return _run_git(checkout, "rev-parse", f"{landing}^").stdout.strip()
777
785
 
778
786
 
779
- def _require_member_unpublished(checkout: Path, member: str, landing: str, bound: str) -> None:
780
- for ref, where in (("refs/remotes/origin/main", "origin/main"), (f"refs/remotes/origin/{bound}", f"origin/{bound}")):
787
+ def _require_member_unpublished(repo: Path, checkout: Path, member: str, landing: str, bound: str) -> None:
788
+ for branch in (isolation.member_default_branch(repo, member), bound):
789
+ ref = f"refs/remotes/origin/{branch}"
781
790
  if _run_git(checkout, "merge-base", "--is-ancestor", landing, ref, check=False).returncode == 0:
782
- raise UndoError(f"member {member} landing is already on {where}")
791
+ raise UndoError(f"member {member} landing is already on origin/{branch}")
783
792
 
784
793
 
785
794
  def _require_no_member_landing_journal(repo: Path) -> None:
@@ -794,7 +803,7 @@ def _undo_member_landing(repo: Path, transaction: dict[str, object]) -> None:
794
803
  checkout, _, entry = isolation._member_context(repo, member)
795
804
  tip = _run_git(checkout, "rev-parse", f"refs/heads/{entry['branch']}").stdout.strip()
796
805
  if tip == transaction["member_parent"]:
797
- _require_member_unpublished(checkout, member, str(transaction["landing"]), entry["branch"])
806
+ _require_member_unpublished(repo, checkout, member, str(transaction["landing"]), entry["branch"])
798
807
  return
799
808
  if tip != transaction["landing"]:
800
809
  raise UndoError(f"member {member} bound branch moved during undo")
@@ -861,7 +870,7 @@ def classify_undo(repo: Path) -> dict[str, object]:
861
870
  [f"an in-progress helper journal exists ({names}); resume that transaction first"]
862
871
  )
863
872
  if git.get("ancestor_of_origin_main"):
864
- return _blocked(["HEAD is an ancestor of origin/main; undo would rewrite shipped history"])
873
+ return _blocked(["HEAD is an ancestor of the origin default branch; undo would rewrite shipped history"])
865
874
 
866
875
  product = _product_dirty(dirty)
867
876
  if product:
@@ -1081,7 +1090,7 @@ def _require_unpublished_reset(repo: Path, expected_branch: str) -> None:
1081
1090
  if git.get("published"):
1082
1091
  raise UndoError("HEAD became published on its recorded remote branch")
1083
1092
  if git.get("ancestor_of_origin_main"):
1084
- raise UndoError("HEAD became published through origin/main")
1093
+ raise UndoError("HEAD became published through the origin default branch")
1085
1094
 
1086
1095
 
1087
1096
  def _remove_untracked_tree(repo: Path, relative: str) -> None:
@@ -168,8 +168,12 @@ State ownership. There is no re-interview of charter or roadmap scope:
168
168
  and prohibition ruling for the user to accept or change; it never rules on
169
169
  them silently. A requested change that contradicts the
170
170
  charter or the resolved roadmap entry is a scope change — this phase never
171
- edits the roadmap; surface it to the user for a `$gsd-path-roadmap` re-slice
172
- at the next milestone boundary.
171
+ edits the roadmap; surface it to the user for a `$gsd-path-roadmap`
172
+ re-slice. Before intent approval, that re-slice keeps `define/active` and
173
+ can change the scope of this milestone's `active` entry; after its
174
+ approval, draft INTENT.md again from the changed entry. In `corrections`
175
+ mode the intent is already approved, so the re-slice waits for the next
176
+ milestone boundary.
173
177
  4. On approval, finalize per the Output contract, setting `milestone` to the
174
178
  resolved entry's slug. The router continues with milestone-scoped research
175
179
  when the entry lists open questions, otherwise planning.
@@ -119,6 +119,9 @@ as stated in Lookahead mode.
119
119
  in the same wave. Same-wave tasks may share files only when one
120
120
  transitively depends on the other through `deps`; the build executes
121
121
  them in dependency layers.
122
+ - Require an optional `supersedes` field to be a list of different task
123
+ ids; each one names an existing task of an earlier wave, in the same
124
+ repo, that shares a declared file with the task.
122
125
  - Reject a declared dependency that carries neither data nor a prerequisite
123
126
  effect. A `deps` edge is valid only when the dependent consumes a symbol,
124
127
  signature, schema, endpoint, file format, or path named in that
@@ -27,7 +27,8 @@ return to `$gsd-path` for ownership checking. Legal entry is
27
27
  yet, `roadmap/active|blocked`, or a
28
28
  milestone-boundary re-slice: `inspect/active` or `define/active` with no
29
29
  approved INTENT.md for the next milestone and a user request to re-scope the
30
- remaining `pending` entries,
30
+ remaining `pending` entries or, at `define/active` only, to change the scope
31
+ of the `active` entry,
31
32
  or `roadmap/active` with STATE.milestone null and an `abandoned` entry in
32
33
  ROADMAP.md (the post-abandon re-slice the build orchestrator hands off).
33
34
  Enter from `decide/done` only with `pipeline_state.py transition`, exact
@@ -35,6 +36,8 @@ expected phase/status/milestone/branch/archive fields, event `roadmap started`,
35
36
  and `--set-phase roadmap --set-status active`; never edit STATE directly. In a
36
37
  milestone-boundary re-slice, preserve the entering `inspect/active` or
37
38
  `define/active` state throughout the re-slice.
39
+ A `define/active` state that the router reports in `corrections` mode already
40
+ has an approved INTENT.md; it blocks.
38
41
  Any later phase blocks; mid-milestone
39
42
  re-scope is never legal — finish or ship the active milestone first. A
40
43
  `decide/done` state with ROADMAP.md already present is milestone-scope decide;
@@ -71,8 +74,11 @@ precondition fails.
71
74
  give `.project/ROADMAP.before-reslice.md` with the instruction to preserve
72
75
  `shipped` entries byte-for-byte except Status/Archive/Integrated fields and
73
76
  to never modify `abandoned` entries at all. For a milestone-boundary
74
- re-slice, also preserve the existing `active` entry byte-for-byte; only
75
- `pending` entries are in scope.
77
+ re-slice entered at `inspect/active`, also preserve the existing `active`
78
+ entry byte-for-byte; only `pending` entries are in scope. Entered at
79
+ `define/active`, the `active` entry may also change as the user ruled, but
80
+ its heading (id and slug) and its Status, Depends on, Archive, and
81
+ Integrated fields stay unchanged.
76
82
  The output is exactly `.project/ROADMAP.md` — no other location is
77
83
  canonical.
78
84
  3. Gate ROADMAP.md:
@@ -96,8 +102,11 @@ precondition fails.
96
102
  - On a re-slice, `shipped` entries differ from
97
103
  `.project/ROADMAP.before-reslice.md` only in Status/Archive/Integrated;
98
104
  `abandoned` entries are byte-for-byte identical.
99
- - On a milestone-boundary re-slice, the prior `active` entry is byte-for-byte
100
- identical to `.project/ROADMAP.before-reslice.md`.
105
+ - On a milestone-boundary re-slice entered at `inspect/active`, the prior
106
+ `active` entry is byte-for-byte identical to
107
+ `.project/ROADMAP.before-reslice.md`. Entered at `define/active`, it
108
+ stays the only `active` entry and keeps its heading and its Status,
109
+ Depends on, Archive, and Integrated fields.
101
110
  4. Redispatch one complete corrected brief under logical task name `roadmap`,
102
111
  following the runtime dispatch contract and including all gate failures.
103
112
  Allow one revision round. If it still fails, keep the entering
@@ -160,7 +169,8 @@ precondition fails.
160
169
 
161
170
  The helper owns roadmap selection, expected state, baseline cleanup and
162
171
  the approval checkpoint. It journals before mutation, retains the baseline
163
- bytes for recovery, and refuses changes to settled or active entries.
172
+ bytes for recovery, and refuses changes to settled entries and every
173
+ `active` entry change that step 2 does not permit.
164
174
  A milestone-boundary re-slice retains Inspect or Define; a post-abandon
165
175
  re-slice enters Inspect. Require its typed result to report `status:
166
176
  approved`, the requested kind, milestone and returned commit. After an
@@ -267,7 +267,11 @@ The persisted `STATE.archive` field is the transaction identity.
267
267
  `python3 <absolute archive_milestone.py> close-members --repo <root>`
268
268
  after preflight passes and before recording shipment. It closes each
269
269
  locked member in lock order in that member's integration mode and
270
- journals each one. When it returns `awaiting-merge`, report the member PR
270
+ journals each one. Each member closes onto the default branch that
271
+ MEMBERS.md records for it (`main` when its section has no
272
+ `Default branch`); when the command reports
273
+ `remote default must be <recorded>`, stop and report it. When it returns
274
+ `awaiting-merge`, report the member PR
271
275
  link, stop, and rerun the same command after the user merges it; never
272
276
  merge a member PR yourself. When it returns `integrated`, keep its `body`
273
277
  for the ship commit below.
@@ -310,8 +314,10 @@ The persisted `STATE.archive` field is the transaction identity.
310
314
  milestone is not shipped until integration below passes.
311
315
  7. Integrate only after the postcommit `validate` passes, with the recorded
312
316
  ship commit and exact reviewed HEAD unchanged. Run `python3 <absolute archive_milestone.py> integrate --repo <root> --slug <STATE.milestone>`.
313
- This helper validates the ship commit, fetches origin, requires remote
314
- default `main`, and follows the locked `STATE.integration` mode:
317
+ This helper validates the ship commit, fetches origin, requires the remote
318
+ default to equal STATE `default_branch` (`main` when the field is absent),
319
+ and follows the locked `STATE.integration` mode. `main` and `origin/main`
320
+ below mean that recorded branch:
315
321
 
316
322
  - `direct` owns the resumable merge transaction. It creates the canonical
317
323
  named integration worktree, performs the hook-verified `--no-ff` merge,
@@ -344,6 +350,22 @@ The persisted `STATE.archive` field is the transaction identity.
344
350
  landing SHA. A closed unmerged PR, squash, rebase, merge queue, moved
345
351
  head, duplicate PR, or non-GitHub.com origin blocks. The remote bound
346
352
  branch may be absent after a valid merge because GitHub may auto-delete it.
353
+ - `external-landing` is for an origin where Path cannot open the review
354
+ itself, such as GitLab, Gitea, or GitHub Enterprise Server. It needs no
355
+ forge CLI. The helper publishes the bound branch at the exact ship commit,
356
+ never pushes `main`, and returns `status: awaiting-merge` with `branch`,
357
+ `merge_subject`, and `merge_body`. Present **Outcome**, and state in
358
+ **Next** that the user must open a merge request from `branch` to `main`
359
+ in their own forge and merge it with a merge commit. The merge commit
360
+ message must be exactly `merge_subject`, a blank line, then `merge_body`;
361
+ show both values verbatim in a code block. Stop this ship invocation;
362
+ Path never opens or merges the request. The forge may delete the source
363
+ branch after the merge. On rerun after the merge, the helper requires exactly
364
+ one commit with that subject on `origin/main` first-parent history, that
365
+ exact body, and two parents with the ship commit as second parent. It
366
+ then writes and pushes the annotated milestone tag containing the ship
367
+ SHA and landing SHA. A squash, rebase, fast-forward, or different merge
368
+ message blocks.
347
369
 
348
370
  A passing run returns the same proof exposed by `validate-integrated`.
349
371
  A non-zero result blocks; rerun the exact `integrate` command to resume a
@@ -354,7 +376,7 @@ The persisted `STATE.archive` field is the transaction identity.
354
376
  continuing. Never merge into or re-ship the closed branch.
355
377
  For a later validation recheck with origin network access, run
356
378
  `python3 <absolute archive_milestone.py> validate-integrated --repo <root> --slug <STATE.milestone>`.
357
- Both integration modes refresh the remote-default and mirrored milestone-tag
379
+ All integration modes refresh the remote-default and mirrored milestone-tag
358
380
  refs when an `origin` remote exists. Without that remote, validation resolves
359
381
  the existing remote-default refs locally, preserving offline direct-mode
360
382
  fixtures. PR mode also revalidates the PR identity, state, merge provenance,
@@ -179,6 +179,23 @@ selects a milestone branch.
179
179
  `define/active`; report that no brownfield signal fired, and route to
180
180
  the bundled [define contract](DEFINE.md).
181
181
 
182
+ ## Default branch
183
+
184
+ `initialize` records the default branch of `origin` one time, as STATE
185
+ `default_branch`. It reads the local `refs/remotes/origin/HEAD`; when that ref
186
+ is unset it records `main`. When the repository has an `origin`, run
187
+ `git remote set-head origin --auto` before `initialize`, so that the record is
188
+ the default branch of the forge. A STATE file without the field means `main`.
189
+
190
+ `<default_branch>` in the commands below is the `default_branch` value in the
191
+ `validate`, `route`, and `status` JSON, beside `state`. Never edit the field,
192
+ and never take the name from a later `origin/HEAD` lookup. When a helper
193
+ reports that the remote default differs from the recorded one, stop and report
194
+ it. In a project with members, STATE `default_branch` is the default branch of
195
+ the coordinator only. `members.py add` records the default branch of each
196
+ member in `.project/MEMBERS.md`; the member helpers read that record. The
197
+ names can differ.
198
+
182
199
  ## Integration choice
183
200
 
184
201
  New state uses the user shipping default (built-in: `direct`) for
@@ -190,7 +207,7 @@ helper; never edit these fields by hand:
190
207
  python3 <absolute-bundled-pipeline-state.py> configure-integration \
191
208
  --repo <absolute-root> \
192
209
  --scope <default-or-milestone> \
193
- --mode <direct-or-pull-request>
210
+ --mode <direct|pull-request|external-landing>
194
211
  ```
195
212
 
196
213
  `default` changes the project setting and changes the current milestone only
@@ -212,16 +229,23 @@ milestone boundary, never during build or ship. Resolve the bundled
212
229
  `scripts/members.py` to an absolute path and use it; never edit MEMBERS.md
213
230
  or a member marker by hand.
214
231
 
215
- - To add an existing repository, it needs a GitHub.com `origin` whose default
216
- is `main`, a clean worktree, and no active milestone of its own. Ask for the
217
- member name, checkout path, and integration (`direct`, `pull-request`, or
218
- `default`, which follows the milestone's choice), then run
232
+ - To add an existing repository, it needs a GitHub.com `origin`, a clean
233
+ worktree, and no active milestone of its own. Its default branch can have
234
+ any name. Run `git remote set-head origin --auto` in the member first: `add`
235
+ reads the member's local `origin/HEAD` one time and records the name in
236
+ MEMBERS.md as `Default branch`; an unset `origin/HEAD` records `main`. Ask
237
+ for the member name, checkout path, and integration (`direct`,
238
+ `pull-request`, or `default`, which follows the milestone's choice), then run
219
239
  `python3 <members.py> add --repo <absolute-root> --name <name> --checkout <path> --integration <mode>`.
240
+ When `validate` or member close later reports
241
+ `remote default must be <recorded>`, stop and report it; never edit the
242
+ record.
220
243
  - To create a new member repository, present the exact `owner/name`,
221
244
  visibility, and checkout path as the **Review** surface and get approval
222
245
  first, as for a new GitHub repository. Then run the same command with
223
246
  `--create <owner/name> --visibility <visibility>`. It journals the approved
224
- target before creating anything; rerun the identical command to resume.
247
+ target before creating anything; rerun the identical command to resume. A
248
+ new member repository uses `main`.
225
249
  - After adding a member, tell the user to install its guard hooks:
226
250
  `npx @opengsd/gsd-path@latest --member-of <absolute-root> --project <member checkout>`.
227
251
  - `python3 <members.py> validate --repo <absolute-root>` checks every member;
@@ -269,8 +293,8 @@ integration ancestry, cleanliness, and journal ownership before continuing.
269
293
  After it returns, continue the state transition or lookahead promotion below.
270
294
  Do not reconstruct this classification from Git output or Log prose.
271
295
  When the route returns `allow_remote_absent: true`, also pass
272
- `--allow-missing-previous`; this is valid only because a merged PR may have
273
- auto-deleted the published bound branch.
296
+ `--allow-missing-previous`; this is valid only because the forge may have
297
+ auto-deleted the published bound branch after the merge.
274
298
 
275
299
  Before ordinary routing, inspect `STATE.archive`.
276
300
 
@@ -328,7 +352,7 @@ promotion, `resume-next-handoff` resumes the verified `bind-next` transaction,
328
352
  `resume-undo` invokes `$gsd-path-undo` with the returned kind and expected HEAD,
329
353
  `block` stops with the returned reason. `bind-initial`
330
354
  means initialization is complete and phase work must wait for the initial
331
- router binding: resolve the exact fetched `origin/main` SHA, call `bind-initial` as
355
+ router binding: resolve the exact fetched `origin/<default_branch>` SHA, call `bind-initial` as
332
356
  above with `route.branch`, then persist its returned branch with
333
357
  `pipeline_state.py transition` using the route result's `state` phase and status plus its
334
358
  null branch and archive as expected fields. Set `--set-branch` to the helper's
@@ -371,7 +395,8 @@ on `NEEDS-USER`. Planning owns the single build-approval gate; never ask a
371
395
  second time. One user-driven exception to normal routing: at a program milestone
372
396
  boundary — `inspect/active` or `define/active` with no approved INTENT.md for
373
397
  the next milestone — a user request to re-scope the remaining `pending`
374
- entries routes to the bundled [roadmap contract](ROADMAP.md) in re-slice mode.
398
+ entries, or at `define/active` the `active` entry, routes to the bundled
399
+ [roadmap contract](ROADMAP.md) in re-slice mode.
375
400
 
376
401
  ## Lookahead planning (program flow)
377
402
 
@@ -400,7 +425,9 @@ template](templates/state.md) with `pipeline: gsd-path/v2`, `phase:
400
425
  inspect`, `status: active`, the selector's exact returned `milestone` slug as
401
426
  `milestone`, `branch: null`, and `archive: null`. Copy the active project's
402
427
  `integration_default` into both integration mode fields and set
403
- `integration_source: default`. Then follow the bundled
428
+ `integration_source: default`. Set `default_branch` to the active project's
429
+ value; when the active STATE.md has no `default_branch` line, delete that line
430
+ from the new file. Then follow the bundled
404
431
  phase contracts in their Lookahead mode — inspect, define (milestone +
405
432
  brownfield), research (only when the entry lists open questions), decide, and
406
433
  plan — rooted at `.project/next/`.
@@ -424,14 +451,14 @@ bundled integration check (`validate-integrated`); pending integration routes
424
451
  back to ship, never here. Preserve the previous archive path, ship SHA,
425
452
  integration SHA, and build branch in the state Log. Before fetching or binding
426
453
  the next program branch, fetch origin and resolve the exact current
427
- `origin/main` SHA. For a program roadmap, resolve the branch from that exact
454
+ `origin/<default_branch>` SHA. For a program roadmap, resolve the branch from that exact
428
455
  fetched commit through the bundled helper. With a saved lookahead track, run:
429
456
 
430
457
  ```text
431
458
  python3 <absolute-bundled-promote-lookahead.py> select-base \
432
459
  --repo <absolute-primary-root> \
433
- --base <exact-origin-main-sha> \
434
- --remote-default origin/main \
460
+ --base <exact-remote-default-sha> \
461
+ --remote-default origin/<default_branch> \
435
462
  --lookahead
436
463
  ```
437
464
 
@@ -440,8 +467,8 @@ Without a saved lookahead track, run:
440
467
  ```text
441
468
  python3 <absolute-bundled-promote-lookahead.py> select-base \
442
469
  --repo <absolute-primary-root> \
443
- --base <exact-origin-main-sha> \
444
- --remote-default origin/main
470
+ --base <exact-remote-default-sha> \
471
+ --remote-default origin/<default_branch>
445
472
  ```
446
473
 
447
474
  When the helper returns `status: complete`, report program completion and stop;
@@ -457,21 +484,22 @@ python3 <absolute-bundled-pipeline-git.py> bind-next \
457
484
  --branch <selected-branch> \
458
485
  --previous-branch <STATE.branch> \
459
486
  --ship <exact-ship-sha> \
460
- --remote-default origin/main \
461
- --base <exact-origin-main-sha> \
487
+ --remote-default origin/<default_branch> \
488
+ --base <exact-remote-default-sha> \
462
489
  --landing <validate-integrated-landing-sha>
463
490
  ```
464
491
 
465
492
  Add `--allow-missing-previous` when `validate-integrated` returned
466
- `mode: pull-request` and `origin/<STATE.branch>` is absent. GitHub may delete
467
- that head branch after merge; the local branch and exact ship SHA still bind
468
- the handoff. The helper independently verifies the published pull-request
469
- milestone tag and merge topology before accepting the missing branch.
493
+ `mode: pull-request` or `mode: external-landing` and `origin/<STATE.branch>`
494
+ is absent. The forge may delete that source branch after merge; the local
495
+ branch and exact ship SHA still bind the handoff. The helper independently
496
+ verifies the published milestone tag for `STATE.integration` and the merge
497
+ topology before accepting the missing branch.
470
498
 
471
499
  The helper requires the previous branch, while it still exists locally, to
472
500
  remain at the ship SHA, proves the ship commit is integrated into the exact
473
501
  base, rejects local or remote branch collisions,
474
- and switches the clean primary worktree without tracking main. It then
502
+ and switches the clean primary worktree without tracking the default branch. It then
475
503
  retires the integrated previous branch — deleted locally and on origin; the
476
504
  ship commit stays reachable from the integration merge and its tag. Repeating the
477
505
  same command while the new branch is current at the unchanged base is the
@@ -488,7 +516,7 @@ Log, then:
488
516
  --repo <absolute-primary-root> \
489
517
  --milestone <next-slug> \
490
518
  --branch gsd-path/M00N \
491
- --base <exact-current-origin-main-sha> \
519
+ --base <exact-current-remote-default-sha> \
492
520
  --landing <exact-milestone-merge-sha>
493
521
  ```
494
522