@opengsd/gsd-path 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. package/AGENTS.md +2 -207
  2. package/CHANGELOG.md +331 -69
  3. package/DOCS.md +25 -9
  4. package/FULL.md +12 -5
  5. package/GUIDE.md +1 -1
  6. package/HOOKS.md +104 -14
  7. package/QUICK.md +5 -2
  8. package/README.md +131 -111
  9. package/RUNTIME.md +2 -2
  10. package/UPDATE.md +61 -11
  11. package/WORKFLOW.md +44 -7
  12. package/package.json +13 -9
  13. package/platforms/shared-agents/dispatch.md +13 -0
  14. package/scripts/_common.py +619 -18
  15. package/scripts/archive_milestone.py +160 -86
  16. package/scripts/bootstrap_repository.py +8 -5
  17. package/scripts/build_recovery.py +100 -32
  18. package/scripts/build_state.py +143 -24
  19. package/scripts/check_docs_audit.py +91 -7
  20. package/scripts/check_handoffs.py +662 -50
  21. package/scripts/check_task_briefs.py +338 -30
  22. package/scripts/check_update.py +2 -2
  23. package/scripts/core_hook_gate.py +10 -1
  24. package/scripts/core_hook_settings.py +11 -4
  25. package/scripts/detect_project.py +587 -32
  26. package/scripts/discussion_records.py +19 -13
  27. package/scripts/discussion_validate.py +152 -50
  28. package/scripts/dispatch_driver.py +501 -46
  29. package/scripts/git_guard.py +118 -31
  30. package/scripts/guard_hook.py +1567 -194
  31. package/scripts/install.mjs +77 -46
  32. package/scripts/install.py +611 -50
  33. package/scripts/integration.py +580 -25
  34. package/scripts/isolation.py +1438 -57
  35. package/scripts/lean_verification.py +99 -19
  36. package/scripts/loop_run.py +31 -29
  37. package/scripts/members.py +706 -0
  38. package/scripts/migrate_core.py +2 -2
  39. package/scripts/path_config.py +5 -5
  40. package/scripts/pipeline_diagnose.py +82 -31
  41. package/scripts/pipeline_git.py +124 -34
  42. package/scripts/pipeline_state.py +287 -87
  43. package/scripts/pipeline_undo.py +218 -30
  44. package/scripts/promote_lookahead.py +1 -1
  45. package/scripts/review_panel.py +1 -1
  46. package/scripts/runtime_store.py +55 -11
  47. package/scripts/skill-resources.json +37 -5
  48. package/scripts/state_checkpoint.py +135 -44
  49. package/scripts/state_promote.py +2 -0
  50. package/scripts/status_runtime.py +58 -10
  51. package/scripts/sync_skill_resources.py +8 -7
  52. package/scripts/task_context.py +12 -3
  53. package/scripts/token_budget.py +12 -8
  54. package/scripts/wizard.mjs +1 -0
  55. package/scripts/workflow_run.py +107 -30
  56. package/scripts/worktree_paths.py +72 -10
  57. package/skills/gsd-path/BUILD.md +7 -1
  58. package/skills/gsd-path/DECIDE.md +11 -4
  59. package/skills/gsd-path/DEFINE.md +36 -4
  60. package/skills/gsd-path/DOCS-AUDIT.md +6 -4
  61. package/skills/gsd-path/INSPECT.md +5 -4
  62. package/skills/gsd-path/PLAN.md +18 -4
  63. package/skills/gsd-path/RESEARCH.md +13 -1
  64. package/skills/gsd-path/ROADMAP.md +2 -1
  65. package/skills/gsd-path/SHIP.md +33 -11
  66. package/skills/gsd-path/SKILL.md +45 -1
  67. package/skills/gsd-path/references/build-native.md +63 -15
  68. package/skills/gsd-path/references/codebase-mapper.md +2 -1
  69. package/skills/gsd-path/references/dispatch.md +13 -0
  70. package/skills/gsd-path/references/docs-auditor.md +7 -1
  71. package/skills/gsd-path/references/operating-rules.md +214 -0
  72. package/skills/gsd-path/references/planner.md +22 -4
  73. package/skills/gsd-path/references/reviewer-final.md +20 -2
  74. package/skills/gsd-path/references/reviewer-wave.md +18 -5
  75. package/skills/gsd-path/references/reviewer.md +3 -1
  76. package/skills/gsd-path/references/spec-probes.md +150 -0
  77. package/skills/gsd-path/scripts/_common.py +619 -18
  78. package/skills/gsd-path/scripts/archive_milestone.py +160 -86
  79. package/skills/gsd-path/scripts/bootstrap_repository.py +8 -5
  80. package/skills/gsd-path/scripts/build_recovery.py +100 -32
  81. package/skills/gsd-path/scripts/build_state.py +143 -24
  82. package/skills/gsd-path/scripts/check_docs_audit.py +91 -7
  83. package/skills/gsd-path/scripts/check_handoffs.py +662 -50
  84. package/skills/gsd-path/scripts/check_task_briefs.py +338 -30
  85. package/skills/gsd-path/scripts/check_update.py +2 -2
  86. package/skills/gsd-path/scripts/detect_project.py +587 -32
  87. package/skills/gsd-path/scripts/discussion_records.py +19 -13
  88. package/skills/gsd-path/scripts/discussion_validate.py +152 -50
  89. package/skills/gsd-path/scripts/dispatch_driver.py +501 -46
  90. package/skills/gsd-path/scripts/git_guard.py +118 -31
  91. package/skills/gsd-path/scripts/integration.py +580 -25
  92. package/skills/gsd-path/scripts/isolation.py +1438 -57
  93. package/skills/gsd-path/scripts/lean_verification.py +99 -19
  94. package/skills/gsd-path/scripts/loop_run.py +31 -29
  95. package/skills/gsd-path/scripts/members.py +706 -0
  96. package/skills/gsd-path/scripts/path_config.py +5 -5
  97. package/skills/gsd-path/scripts/pipeline_git.py +124 -34
  98. package/skills/gsd-path/scripts/pipeline_state.py +287 -87
  99. package/skills/gsd-path/scripts/promote_lookahead.py +1 -1
  100. package/skills/gsd-path/scripts/review_panel.py +1 -1
  101. package/skills/gsd-path/scripts/state_checkpoint.py +135 -44
  102. package/skills/gsd-path/scripts/state_promote.py +2 -0
  103. package/skills/gsd-path/scripts/status_runtime.py +58 -10
  104. package/skills/gsd-path/scripts/task_context.py +12 -3
  105. package/skills/gsd-path/scripts/token_budget.py +12 -8
  106. package/skills/gsd-path/scripts/workflow_run.py +107 -30
  107. package/skills/gsd-path/scripts/worktree_paths.py +72 -10
  108. package/skills/gsd-path/templates/codebase.md +1 -1
  109. package/skills/gsd-path/templates/docs-audit.md +6 -2
  110. package/skills/gsd-path/templates/final-review.md +16 -4
  111. package/skills/gsd-path/templates/gap-review.md +2 -1
  112. package/skills/gsd-path/templates/intent.md +30 -0
  113. package/skills/gsd-path/templates/patch-findings.md +3 -3
  114. package/skills/gsd-path/templates/plan.md +17 -2
  115. package/skills/gsd-path/templates/research-handoff.md +14 -3
  116. package/skills/gsd-path/templates/state.md +1 -1
  117. package/skills/gsd-path/templates/task.md +1 -0
  118. package/skills/gsd-path/templates/wave-review.md +16 -4
  119. package/skills/gsd-path-build/SKILL.md +7 -1
  120. package/skills/gsd-path-build/references/build-native.md +63 -15
  121. package/skills/gsd-path-build/references/dispatch.md +13 -0
  122. package/skills/gsd-path-build/references/operating-rules.md +214 -0
  123. package/skills/gsd-path-build/references/reviewer-final.md +20 -2
  124. package/skills/gsd-path-build/references/reviewer-wave.md +18 -5
  125. package/skills/gsd-path-build/references/reviewer.md +3 -1
  126. package/skills/gsd-path-build/references/spec-probes.md +150 -0
  127. package/skills/gsd-path-build/scripts/_common.py +619 -18
  128. package/skills/gsd-path-build/scripts/archive_milestone.py +160 -86
  129. package/skills/gsd-path-build/scripts/build_recovery.py +100 -32
  130. package/skills/gsd-path-build/scripts/build_state.py +143 -24
  131. package/skills/gsd-path-build/scripts/check_handoffs.py +662 -50
  132. package/skills/gsd-path-build/scripts/check_task_briefs.py +338 -30
  133. package/skills/gsd-path-build/scripts/detect_project.py +587 -32
  134. package/skills/gsd-path-build/scripts/discussion_records.py +19 -13
  135. package/skills/gsd-path-build/scripts/discussion_validate.py +152 -50
  136. package/skills/gsd-path-build/scripts/dispatch_driver.py +501 -46
  137. package/skills/gsd-path-build/scripts/integration.py +580 -25
  138. package/skills/gsd-path-build/scripts/isolation.py +1438 -57
  139. package/skills/gsd-path-build/scripts/loop_run.py +31 -29
  140. package/skills/gsd-path-build/scripts/members.py +706 -0
  141. package/skills/gsd-path-build/scripts/path_config.py +5 -5
  142. package/skills/gsd-path-build/scripts/pipeline_git.py +124 -34
  143. package/skills/gsd-path-build/scripts/pipeline_state.py +287 -87
  144. package/skills/gsd-path-build/scripts/promote_lookahead.py +1 -1
  145. package/skills/gsd-path-build/scripts/review_panel.py +1 -1
  146. package/skills/gsd-path-build/scripts/state_checkpoint.py +135 -44
  147. package/skills/gsd-path-build/scripts/state_promote.py +2 -0
  148. package/skills/gsd-path-build/scripts/task_context.py +12 -3
  149. package/skills/gsd-path-build/scripts/token_budget.py +12 -8
  150. package/skills/gsd-path-build/scripts/workflow_run.py +107 -30
  151. package/skills/gsd-path-build/scripts/worktree_paths.py +72 -10
  152. package/skills/gsd-path-build/templates/task.md +1 -0
  153. package/skills/gsd-path-build/templates/wave-review.md +16 -4
  154. package/skills/gsd-path-decide/SKILL.md +11 -4
  155. package/skills/gsd-path-decide/references/dispatch.md +13 -0
  156. package/skills/gsd-path-decide/references/operating-rules.md +214 -0
  157. package/skills/gsd-path-decide/scripts/_common.py +619 -18
  158. package/skills/gsd-path-decide/scripts/archive_milestone.py +160 -86
  159. package/skills/gsd-path-decide/scripts/build_recovery.py +100 -32
  160. package/skills/gsd-path-decide/scripts/check_handoffs.py +662 -50
  161. package/skills/gsd-path-decide/scripts/check_task_briefs.py +338 -30
  162. package/skills/gsd-path-decide/scripts/detect_project.py +587 -32
  163. package/skills/gsd-path-decide/scripts/discussion_records.py +19 -13
  164. package/skills/gsd-path-decide/scripts/discussion_validate.py +152 -50
  165. package/skills/gsd-path-decide/scripts/integration.py +580 -25
  166. package/skills/gsd-path-decide/scripts/isolation.py +1438 -57
  167. package/skills/gsd-path-decide/scripts/loop_run.py +31 -29
  168. package/skills/gsd-path-decide/scripts/members.py +706 -0
  169. package/skills/gsd-path-decide/scripts/path_config.py +5 -5
  170. package/skills/gsd-path-decide/scripts/pipeline_git.py +124 -34
  171. package/skills/gsd-path-decide/scripts/pipeline_state.py +287 -87
  172. package/skills/gsd-path-decide/scripts/promote_lookahead.py +1 -1
  173. package/skills/gsd-path-decide/scripts/review_panel.py +1 -1
  174. package/skills/gsd-path-decide/scripts/state_checkpoint.py +135 -44
  175. package/skills/gsd-path-decide/scripts/state_promote.py +2 -0
  176. package/skills/gsd-path-decide/scripts/worktree_paths.py +72 -10
  177. package/skills/gsd-path-define/SKILL.md +36 -4
  178. package/skills/gsd-path-define/references/operating-rules.md +214 -0
  179. package/skills/gsd-path-define/references/spec-probes.md +150 -0
  180. package/skills/gsd-path-define/scripts/_common.py +619 -18
  181. package/skills/gsd-path-define/scripts/archive_milestone.py +160 -86
  182. package/skills/gsd-path-define/scripts/build_recovery.py +100 -32
  183. package/skills/gsd-path-define/scripts/check_handoffs.py +662 -50
  184. package/skills/gsd-path-define/scripts/check_task_briefs.py +338 -30
  185. package/skills/gsd-path-define/scripts/detect_project.py +587 -32
  186. package/skills/gsd-path-define/scripts/discussion_records.py +19 -13
  187. package/skills/gsd-path-define/scripts/discussion_validate.py +152 -50
  188. package/skills/gsd-path-define/scripts/integration.py +580 -25
  189. package/skills/gsd-path-define/scripts/isolation.py +1438 -57
  190. package/skills/gsd-path-define/scripts/loop_run.py +31 -29
  191. package/skills/gsd-path-define/scripts/members.py +706 -0
  192. package/skills/gsd-path-define/scripts/path_config.py +5 -5
  193. package/skills/gsd-path-define/scripts/pipeline_git.py +124 -34
  194. package/skills/gsd-path-define/scripts/pipeline_state.py +287 -87
  195. package/skills/gsd-path-define/scripts/promote_lookahead.py +1 -1
  196. package/skills/gsd-path-define/scripts/review_panel.py +1 -1
  197. package/skills/gsd-path-define/scripts/state_checkpoint.py +135 -44
  198. package/skills/gsd-path-define/scripts/state_promote.py +2 -0
  199. package/skills/gsd-path-define/scripts/worktree_paths.py +72 -10
  200. package/skills/gsd-path-define/templates/intent.md +30 -0
  201. package/skills/gsd-path-define/templates/state.md +1 -1
  202. package/skills/gsd-path-discuss/SKILL.md +2 -1
  203. package/skills/gsd-path-discuss/references/operating-rules.md +214 -0
  204. package/skills/gsd-path-discuss/scripts/_common.py +619 -18
  205. package/skills/gsd-path-discuss/scripts/discussion_records.py +19 -13
  206. package/skills/gsd-path-discuss/scripts/loop_run.py +31 -29
  207. package/skills/gsd-path-discuss/scripts/path_config.py +5 -5
  208. package/skills/gsd-path-discuss/scripts/review_panel.py +1 -1
  209. package/skills/gsd-path-discuss/scripts/worktree_paths.py +72 -10
  210. package/skills/gsd-path-docs-audit/SKILL.md +6 -4
  211. package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
  212. package/skills/gsd-path-docs-audit/references/docs-auditor.md +7 -1
  213. package/skills/gsd-path-docs-audit/references/operating-rules.md +214 -0
  214. package/skills/gsd-path-docs-audit/scripts/_common.py +619 -18
  215. package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +160 -86
  216. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +100 -32
  217. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +91 -7
  218. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +662 -50
  219. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +338 -30
  220. package/skills/gsd-path-docs-audit/scripts/detect_project.py +587 -32
  221. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +19 -13
  222. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +152 -50
  223. package/skills/gsd-path-docs-audit/scripts/integration.py +580 -25
  224. package/skills/gsd-path-docs-audit/scripts/isolation.py +1438 -57
  225. package/skills/gsd-path-docs-audit/scripts/loop_run.py +31 -29
  226. package/skills/gsd-path-docs-audit/scripts/members.py +706 -0
  227. package/skills/gsd-path-docs-audit/scripts/path_config.py +5 -5
  228. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +124 -34
  229. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +287 -87
  230. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +1 -1
  231. package/skills/gsd-path-docs-audit/scripts/review_panel.py +1 -1
  232. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +135 -44
  233. package/skills/gsd-path-docs-audit/scripts/state_promote.py +2 -0
  234. package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +72 -10
  235. package/skills/gsd-path-docs-audit/templates/docs-audit.md +6 -2
  236. package/skills/gsd-path-forensics/SKILL.md +2 -1
  237. package/skills/gsd-path-forensics/references/operating-rules.md +214 -0
  238. package/skills/gsd-path-forensics/scripts/_common.py +619 -18
  239. package/skills/gsd-path-forensics/scripts/discussion_records.py +19 -13
  240. package/skills/gsd-path-forensics/scripts/loop_run.py +31 -29
  241. package/skills/gsd-path-forensics/scripts/path_config.py +5 -5
  242. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +82 -31
  243. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +218 -30
  244. package/skills/gsd-path-forensics/scripts/review_panel.py +1 -1
  245. package/skills/gsd-path-forensics/scripts/worktree_paths.py +72 -10
  246. package/skills/gsd-path-inspect/SKILL.md +5 -4
  247. package/skills/gsd-path-inspect/references/codebase-mapper.md +2 -1
  248. package/skills/gsd-path-inspect/references/dispatch.md +13 -0
  249. package/skills/gsd-path-inspect/references/docs-auditor.md +7 -1
  250. package/skills/gsd-path-inspect/references/operating-rules.md +214 -0
  251. package/skills/gsd-path-inspect/scripts/_common.py +619 -18
  252. package/skills/gsd-path-inspect/scripts/archive_milestone.py +160 -86
  253. package/skills/gsd-path-inspect/scripts/build_recovery.py +100 -32
  254. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +91 -7
  255. package/skills/gsd-path-inspect/scripts/check_handoffs.py +662 -50
  256. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +338 -30
  257. package/skills/gsd-path-inspect/scripts/detect_project.py +587 -32
  258. package/skills/gsd-path-inspect/scripts/discussion_records.py +19 -13
  259. package/skills/gsd-path-inspect/scripts/discussion_validate.py +152 -50
  260. package/skills/gsd-path-inspect/scripts/integration.py +580 -25
  261. package/skills/gsd-path-inspect/scripts/isolation.py +1438 -57
  262. package/skills/gsd-path-inspect/scripts/loop_run.py +31 -29
  263. package/skills/gsd-path-inspect/scripts/members.py +706 -0
  264. package/skills/gsd-path-inspect/scripts/path_config.py +5 -5
  265. package/skills/gsd-path-inspect/scripts/pipeline_git.py +124 -34
  266. package/skills/gsd-path-inspect/scripts/pipeline_state.py +287 -87
  267. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +1 -1
  268. package/skills/gsd-path-inspect/scripts/review_panel.py +1 -1
  269. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +135 -44
  270. package/skills/gsd-path-inspect/scripts/state_promote.py +2 -0
  271. package/skills/gsd-path-inspect/scripts/workflow_run.py +107 -30
  272. package/skills/gsd-path-inspect/scripts/worktree_paths.py +72 -10
  273. package/skills/gsd-path-inspect/templates/codebase.md +1 -1
  274. package/skills/gsd-path-inspect/templates/docs-audit.md +6 -2
  275. package/skills/gsd-path-inspect/templates/state.md +1 -1
  276. package/skills/gsd-path-loop/SKILL.md +2 -1
  277. package/skills/gsd-path-loop/references/operating-rules.md +214 -0
  278. package/skills/gsd-path-loop/scripts/_common.py +619 -18
  279. package/skills/gsd-path-loop/scripts/discussion_records.py +19 -13
  280. package/skills/gsd-path-loop/scripts/loop_run.py +31 -29
  281. package/skills/gsd-path-loop/scripts/path_config.py +5 -5
  282. package/skills/gsd-path-loop/scripts/review_panel.py +1 -1
  283. package/skills/gsd-path-loop/scripts/worktree_paths.py +72 -10
  284. package/skills/gsd-path-migrate/SKILL.md +2 -1
  285. package/skills/gsd-path-migrate/references/operating-rules.md +214 -0
  286. package/skills/gsd-path-migrate/scripts/_common.py +619 -18
  287. package/skills/gsd-path-migrate/scripts/core_hook_gate.py +10 -1
  288. package/skills/gsd-path-migrate/scripts/core_hook_settings.py +11 -4
  289. package/skills/gsd-path-migrate/scripts/discussion_records.py +19 -13
  290. package/skills/gsd-path-migrate/scripts/loop_run.py +31 -29
  291. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -2
  292. package/skills/gsd-path-migrate/scripts/path_config.py +5 -5
  293. package/skills/gsd-path-migrate/scripts/review_panel.py +1 -1
  294. package/skills/gsd-path-plan/SKILL.md +18 -4
  295. package/skills/gsd-path-plan/references/dispatch.md +13 -0
  296. package/skills/gsd-path-plan/references/operating-rules.md +214 -0
  297. package/skills/gsd-path-plan/references/planner.md +22 -4
  298. package/skills/gsd-path-plan/references/spec-probes.md +150 -0
  299. package/skills/gsd-path-plan/scripts/_common.py +619 -18
  300. package/skills/gsd-path-plan/scripts/archive_milestone.py +160 -86
  301. package/skills/gsd-path-plan/scripts/build_recovery.py +100 -32
  302. package/skills/gsd-path-plan/scripts/check_handoffs.py +662 -50
  303. package/skills/gsd-path-plan/scripts/check_task_briefs.py +338 -30
  304. package/skills/gsd-path-plan/scripts/detect_project.py +587 -32
  305. package/skills/gsd-path-plan/scripts/discussion_records.py +19 -13
  306. package/skills/gsd-path-plan/scripts/discussion_validate.py +152 -50
  307. package/skills/gsd-path-plan/scripts/integration.py +580 -25
  308. package/skills/gsd-path-plan/scripts/isolation.py +1438 -57
  309. package/skills/gsd-path-plan/scripts/loop_run.py +31 -29
  310. package/skills/gsd-path-plan/scripts/members.py +706 -0
  311. package/skills/gsd-path-plan/scripts/path_config.py +5 -5
  312. package/skills/gsd-path-plan/scripts/pipeline_git.py +124 -34
  313. package/skills/gsd-path-plan/scripts/pipeline_state.py +287 -87
  314. package/skills/gsd-path-plan/scripts/promote_lookahead.py +1 -1
  315. package/skills/gsd-path-plan/scripts/review_panel.py +1 -1
  316. package/skills/gsd-path-plan/scripts/state_checkpoint.py +135 -44
  317. package/skills/gsd-path-plan/scripts/state_promote.py +2 -0
  318. package/skills/gsd-path-plan/scripts/workflow_run.py +107 -30
  319. package/skills/gsd-path-plan/scripts/worktree_paths.py +72 -10
  320. package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
  321. package/skills/gsd-path-plan/templates/plan.md +17 -2
  322. package/skills/gsd-path-plan/templates/task.md +1 -0
  323. package/skills/gsd-path-research/SKILL.md +13 -1
  324. package/skills/gsd-path-research/references/dispatch.md +13 -0
  325. package/skills/gsd-path-research/references/operating-rules.md +214 -0
  326. package/skills/gsd-path-research/scripts/_common.py +619 -18
  327. package/skills/gsd-path-research/scripts/archive_milestone.py +160 -86
  328. package/skills/gsd-path-research/scripts/build_recovery.py +100 -32
  329. package/skills/gsd-path-research/scripts/check_handoffs.py +662 -50
  330. package/skills/gsd-path-research/scripts/check_task_briefs.py +338 -30
  331. package/skills/gsd-path-research/scripts/detect_project.py +587 -32
  332. package/skills/gsd-path-research/scripts/discussion_records.py +19 -13
  333. package/skills/gsd-path-research/scripts/discussion_validate.py +152 -50
  334. package/skills/gsd-path-research/scripts/integration.py +580 -25
  335. package/skills/gsd-path-research/scripts/isolation.py +1438 -57
  336. package/skills/gsd-path-research/scripts/loop_run.py +31 -29
  337. package/skills/gsd-path-research/scripts/members.py +706 -0
  338. package/skills/gsd-path-research/scripts/path_config.py +5 -5
  339. package/skills/gsd-path-research/scripts/pipeline_git.py +124 -34
  340. package/skills/gsd-path-research/scripts/pipeline_state.py +287 -87
  341. package/skills/gsd-path-research/scripts/promote_lookahead.py +1 -1
  342. package/skills/gsd-path-research/scripts/review_panel.py +1 -1
  343. package/skills/gsd-path-research/scripts/state_checkpoint.py +135 -44
  344. package/skills/gsd-path-research/scripts/state_promote.py +2 -0
  345. package/skills/gsd-path-research/scripts/worktree_paths.py +72 -10
  346. package/skills/gsd-path-research/templates/research-handoff.md +14 -3
  347. package/skills/gsd-path-roadmap/SKILL.md +2 -1
  348. package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
  349. package/skills/gsd-path-roadmap/references/operating-rules.md +214 -0
  350. package/skills/gsd-path-roadmap/scripts/_common.py +619 -18
  351. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +160 -86
  352. package/skills/gsd-path-roadmap/scripts/build_recovery.py +100 -32
  353. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +662 -50
  354. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +338 -30
  355. package/skills/gsd-path-roadmap/scripts/detect_project.py +587 -32
  356. package/skills/gsd-path-roadmap/scripts/discussion_records.py +19 -13
  357. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +152 -50
  358. package/skills/gsd-path-roadmap/scripts/integration.py +580 -25
  359. package/skills/gsd-path-roadmap/scripts/isolation.py +1438 -57
  360. package/skills/gsd-path-roadmap/scripts/loop_run.py +31 -29
  361. package/skills/gsd-path-roadmap/scripts/members.py +706 -0
  362. package/skills/gsd-path-roadmap/scripts/path_config.py +5 -5
  363. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +124 -34
  364. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +287 -87
  365. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +1 -1
  366. package/skills/gsd-path-roadmap/scripts/review_panel.py +1 -1
  367. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +135 -44
  368. package/skills/gsd-path-roadmap/scripts/state_promote.py +2 -0
  369. package/skills/gsd-path-roadmap/scripts/worktree_paths.py +72 -10
  370. package/skills/gsd-path-ship/SKILL.md +33 -11
  371. package/skills/gsd-path-ship/references/dispatch.md +13 -0
  372. package/skills/gsd-path-ship/references/operating-rules.md +214 -0
  373. package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
  374. package/skills/gsd-path-ship/references/reviewer-wave.md +18 -5
  375. package/skills/gsd-path-ship/references/reviewer.md +3 -1
  376. package/skills/gsd-path-ship/references/spec-probes.md +150 -0
  377. package/skills/gsd-path-ship/scripts/_common.py +619 -18
  378. package/skills/gsd-path-ship/scripts/archive_milestone.py +160 -86
  379. package/skills/gsd-path-ship/scripts/build_recovery.py +100 -32
  380. package/skills/gsd-path-ship/scripts/build_state.py +143 -24
  381. package/skills/gsd-path-ship/scripts/check_handoffs.py +662 -50
  382. package/skills/gsd-path-ship/scripts/check_task_briefs.py +338 -30
  383. package/skills/gsd-path-ship/scripts/detect_project.py +587 -32
  384. package/skills/gsd-path-ship/scripts/discussion_records.py +19 -13
  385. package/skills/gsd-path-ship/scripts/discussion_validate.py +152 -50
  386. package/skills/gsd-path-ship/scripts/integration.py +580 -25
  387. package/skills/gsd-path-ship/scripts/isolation.py +1438 -57
  388. package/skills/gsd-path-ship/scripts/lean_verification.py +99 -19
  389. package/skills/gsd-path-ship/scripts/loop_run.py +31 -29
  390. package/skills/gsd-path-ship/scripts/members.py +706 -0
  391. package/skills/gsd-path-ship/scripts/path_config.py +5 -5
  392. package/skills/gsd-path-ship/scripts/pipeline_git.py +124 -34
  393. package/skills/gsd-path-ship/scripts/pipeline_state.py +287 -87
  394. package/skills/gsd-path-ship/scripts/promote_lookahead.py +1 -1
  395. package/skills/gsd-path-ship/scripts/review_panel.py +1 -1
  396. package/skills/gsd-path-ship/scripts/state_checkpoint.py +135 -44
  397. package/skills/gsd-path-ship/scripts/state_promote.py +2 -0
  398. package/skills/gsd-path-ship/scripts/workflow_run.py +107 -30
  399. package/skills/gsd-path-ship/scripts/worktree_paths.py +72 -10
  400. package/skills/gsd-path-ship/templates/final-review.md +16 -4
  401. package/skills/gsd-path-ship/templates/gap-review.md +2 -1
  402. package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
  403. package/skills/gsd-path-ship/templates/wave-review.md +16 -4
  404. package/skills/gsd-path-undo/SKILL.md +2 -1
  405. package/skills/gsd-path-undo/references/operating-rules.md +214 -0
  406. package/skills/gsd-path-undo/scripts/_common.py +619 -18
  407. package/skills/gsd-path-undo/scripts/discussion_records.py +19 -13
  408. package/skills/gsd-path-undo/scripts/loop_run.py +31 -29
  409. package/skills/gsd-path-undo/scripts/path_config.py +5 -5
  410. package/skills/gsd-path-undo/scripts/pipeline_undo.py +218 -30
  411. package/skills/gsd-path-undo/scripts/review_panel.py +1 -1
  412. package/skills/gsd-path-undo/scripts/worktree_paths.py +72 -10
  413. package/skills/path/BUILD.md +7 -1
  414. package/skills/path/DECIDE.md +11 -4
  415. package/skills/path/DEFINE.md +36 -4
  416. package/skills/path/DOCS-AUDIT.md +6 -4
  417. package/skills/path/INSPECT.md +5 -4
  418. package/skills/path/PLAN.md +18 -4
  419. package/skills/path/RESEARCH.md +13 -1
  420. package/skills/path/ROADMAP.md +2 -1
  421. package/skills/path/SHIP.md +33 -11
  422. package/skills/path/SKILL.md +45 -1
  423. package/skills/path/references/build-native.md +63 -15
  424. package/skills/path/references/codebase-mapper.md +2 -1
  425. package/skills/path/references/dispatch.md +13 -0
  426. package/skills/path/references/docs-auditor.md +7 -1
  427. package/skills/path/references/operating-rules.md +214 -0
  428. package/skills/path/references/planner.md +22 -4
  429. package/skills/path/references/reviewer-final.md +20 -2
  430. package/skills/path/references/reviewer-wave.md +18 -5
  431. package/skills/path/references/reviewer.md +3 -1
  432. package/skills/path/references/spec-probes.md +150 -0
  433. package/skills/path/scripts/_common.py +619 -18
  434. package/skills/path/scripts/archive_milestone.py +160 -86
  435. package/skills/path/scripts/bootstrap_repository.py +8 -5
  436. package/skills/path/scripts/build_recovery.py +100 -32
  437. package/skills/path/scripts/build_state.py +143 -24
  438. package/skills/path/scripts/check_docs_audit.py +91 -7
  439. package/skills/path/scripts/check_handoffs.py +662 -50
  440. package/skills/path/scripts/check_task_briefs.py +338 -30
  441. package/skills/path/scripts/check_update.py +2 -2
  442. package/skills/path/scripts/detect_project.py +587 -32
  443. package/skills/path/scripts/discussion_records.py +19 -13
  444. package/skills/path/scripts/discussion_validate.py +152 -50
  445. package/skills/path/scripts/dispatch_driver.py +501 -46
  446. package/skills/path/scripts/git_guard.py +118 -31
  447. package/skills/path/scripts/integration.py +580 -25
  448. package/skills/path/scripts/isolation.py +1438 -57
  449. package/skills/path/scripts/lean_verification.py +99 -19
  450. package/skills/path/scripts/loop_run.py +31 -29
  451. package/skills/path/scripts/members.py +706 -0
  452. package/skills/path/scripts/path_config.py +5 -5
  453. package/skills/path/scripts/pipeline_git.py +124 -34
  454. package/skills/path/scripts/pipeline_state.py +287 -87
  455. package/skills/path/scripts/promote_lookahead.py +1 -1
  456. package/skills/path/scripts/review_panel.py +1 -1
  457. package/skills/path/scripts/state_checkpoint.py +135 -44
  458. package/skills/path/scripts/state_promote.py +2 -0
  459. package/skills/path/scripts/status_runtime.py +58 -10
  460. package/skills/path/scripts/task_context.py +12 -3
  461. package/skills/path/scripts/token_budget.py +12 -8
  462. package/skills/path/scripts/workflow_run.py +107 -30
  463. package/skills/path/scripts/worktree_paths.py +72 -10
  464. package/skills/path/templates/codebase.md +1 -1
  465. package/skills/path/templates/docs-audit.md +6 -2
  466. package/skills/path/templates/final-review.md +16 -4
  467. package/skills/path/templates/gap-review.md +2 -1
  468. package/skills/path/templates/intent.md +30 -0
  469. package/skills/path/templates/patch-findings.md +3 -3
  470. package/skills/path/templates/plan.md +17 -2
  471. package/skills/path/templates/research-handoff.md +14 -3
  472. package/skills/path/templates/state.md +1 -1
  473. package/skills/path/templates/task.md +1 -0
  474. package/skills/path/templates/wave-review.md +16 -4
  475. package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  476. package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  477. package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  478. package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  479. package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  480. package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  481. package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
@@ -17,6 +17,7 @@ import os
17
17
  import re
18
18
  import shutil
19
19
  import sys
20
+ from datetime import date
20
21
 
21
22
  # Runtime helpers must not modify their immutable installation.
22
23
  sys.dont_write_bytecode = True
@@ -25,22 +26,30 @@ from pathlib import Path, PurePosixPath
25
26
  from typing import Optional, Sequence
26
27
 
27
28
  def _load_pipeline_modules():
28
- try:
29
- import archive_milestone
30
- import isolation
31
- import pipeline_git
32
- import pipeline_state
33
- import state_checkpoint
29
+ if __package__:
30
+ from . import archive_milestone
31
+ from . import isolation
32
+ from . import pipeline_git
33
+ from . import pipeline_state
34
+ from . import state_checkpoint
34
35
  return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
35
- except ModuleNotFoundError as error:
36
- if error.name not in {
37
- "archive_milestone",
38
- "isolation",
39
- "pipeline_git",
40
- "pipeline_state",
41
- "state_checkpoint",
42
- }:
43
- raise
36
+ else:
37
+ try:
38
+ import archive_milestone
39
+ import isolation
40
+ import pipeline_git
41
+ import pipeline_state
42
+ import state_checkpoint
43
+ return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
44
+ except ModuleNotFoundError as error:
45
+ if error.name not in {
46
+ "archive_milestone",
47
+ "isolation",
48
+ "pipeline_git",
49
+ "pipeline_state",
50
+ "state_checkpoint",
51
+ }:
52
+ raise
44
53
  try:
45
54
  from scripts import archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
46
55
  return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
@@ -94,10 +103,20 @@ UNDO_TRANSACTION_SCHEMA = pipeline_state.UNDO_TRANSACTION_SCHEMA
94
103
  UNDO_TRANSACTION_NAME = pipeline_state.UNDO_TRANSACTION_NAME
95
104
  ROADMAP_APPROVAL_SUBJECT = "roadmap: program roadmap approved"
96
105
  TASK_SUBJECT_RE = re.compile(r"^(T\d{3,}): .+")
97
- KINDS = ("checkpoint", "task", "uncommitted-archive", "lookahead")
106
+ KINDS = ("checkpoint", "task", "member-task", "uncommitted-archive", "lookahead")
98
107
  PROMOTION_PREFIX = "router: promote lookahead milestone "
99
108
  ABANDON_PREFIX = "build: abandon milestone "
100
109
  INTEGRATE_PREFIX = "integrate: "
110
+ SHIP_LOG_ONLY_LINE = re.compile(
111
+ r"- (?P<date>\d{4}-\d{2}-\d{2}) — ship — (?P<event>[^\r\n]+)\n\Z"
112
+ )
113
+ SHIPMENT_RECORD_LINE = re.compile(
114
+ r"- (?P<date>\d{4}-\d{2}-\d{2}) — shipped — (?P<event>[^\r\n]+)\n\Z"
115
+ )
116
+ SHIPMENT_EVENTS = {
117
+ "archive preflight passed; shipment recorded",
118
+ "archive preflight passed; shipment recorded; program complete",
119
+ }
101
120
 
102
121
 
103
122
  class UndoError(RuntimeError):
@@ -367,6 +386,80 @@ def pending_transaction(repo: Path) -> Optional[dict[str, object]]:
367
386
  raise UndoError(str(error)) from error
368
387
 
369
388
 
389
+ def _valid_state_event_line(line: str, phase: str) -> bool:
390
+ pattern = SHIP_LOG_ONLY_LINE if phase == "ship" else SHIPMENT_RECORD_LINE
391
+ match = pattern.fullmatch(line)
392
+ if match is None:
393
+ return False
394
+ try:
395
+ event_date = date.fromisoformat(match.group("date"))
396
+ except ValueError:
397
+ return False
398
+ event = match.group("event")
399
+ return event_date.isoformat() == match.group("date") and event == " ".join(event.split())
400
+
401
+
402
+ def _owned_ship_log_events(
403
+ prepared_state: str,
404
+ current_state: str,
405
+ phase: object,
406
+ status: object,
407
+ ) -> Optional[str]:
408
+ """Return only ship log lines appended around a helper-owned archive event.
409
+
410
+ The prepared text must remain byte-for-byte unchanged. For shipped/done,
411
+ record-shipment changes only phase and status before appending its one
412
+ generated shipment event, so validate that exact prefix and event shape.
413
+ """
414
+ if (phase, status) == ("ship", "active"):
415
+ if current_state == prepared_state:
416
+ return ""
417
+ if not current_state.startswith(prepared_state):
418
+ return None
419
+ suffix = current_state[len(prepared_state):]
420
+ separator = "" if prepared_state.endswith("\n") else "\n"
421
+ if separator:
422
+ if not suffix.startswith(separator):
423
+ return None
424
+ suffix = suffix[len(separator):]
425
+ lines = suffix.splitlines(keepends=True)
426
+ if not lines or "".join(lines) != suffix:
427
+ return None
428
+ if not all(_valid_state_event_line(line, "ship") for line in lines):
429
+ return None
430
+ return separator + suffix
431
+
432
+ if (phase, status) != ("shipped", "done"):
433
+ return None
434
+ try:
435
+ shipped_prefix = pipeline_state._set_frontmatter(
436
+ prepared_state,
437
+ {"phase": "shipped", "status": "done"},
438
+ )
439
+ except PipelineStateError:
440
+ return None
441
+ if not current_state.startswith(shipped_prefix):
442
+ return None
443
+ suffix = current_state[len(shipped_prefix):]
444
+ separator = "" if shipped_prefix.endswith("\n") else "\n"
445
+ if separator:
446
+ if not suffix.startswith(separator):
447
+ return None
448
+ suffix = suffix[len(separator):]
449
+ lines = suffix.splitlines(keepends=True)
450
+ if not lines or "".join(lines) != suffix:
451
+ return None
452
+ shipment_event = lines[-1]
453
+ if not _valid_state_event_line(shipment_event, "shipped"):
454
+ return None
455
+ if SHIPMENT_RECORD_LINE.fullmatch(shipment_event).group("event") not in SHIPMENT_EVENTS:
456
+ return None
457
+ ship_events = lines[:-1]
458
+ if not all(_valid_state_event_line(line, "ship") for line in ship_events):
459
+ return None
460
+ return separator + "".join(ship_events) if ship_events else ""
461
+
462
+
370
463
  def _archive_metadata_error(
371
464
  repo: Path,
372
465
  state_fields: dict[str, object],
@@ -412,8 +505,13 @@ def _archive_metadata_error(
412
505
  if final_review.exists() or gap_reviews:
413
506
  reviewed_head, _ = archive_milestone.parse_final_review(archive_path)
414
507
  archive_milestone.validate_gap_reviews(archive_path, reviewed_head)
415
- if reviewed_head != _optional_rev(repo, "HEAD"):
416
- return "archive undo final review does not match current HEAD"
508
+ if not archive_milestone.reviewed_head_covers(
509
+ repo, reviewed_head, _optional_rev(repo, "HEAD")
510
+ ):
511
+ return (
512
+ "archive undo final review does not match current HEAD; "
513
+ f"{archive_milestone._common.RUNTIME_PIN_ALLOWANCE}"
514
+ )
417
515
  expected_inventory.add("review/FINAL.md")
418
516
  expected_inventory.update(
419
517
  path.relative_to(archive_path).as_posix() for path in gap_reviews
@@ -468,10 +566,14 @@ def _archive_metadata_error(
468
566
  "archive",
469
567
  configured,
470
568
  )
471
- current_state = (repo / ".project" / "STATE.md").read_text(encoding="utf-8")
569
+ current_state = (repo / ".project" / "STATE.md").read_bytes().decode("utf-8")
472
570
  phase = state_fields.get("phase")
473
571
  status = state_fields.get("status")
572
+ ship_events = _owned_ship_log_events(prepared_state, current_state, phase, status)
474
573
  if (phase, status) == ("ship", "active"):
574
+ if ship_events is None:
575
+ return "archive undo found unowned STATE.md changes"
576
+ prepared_state += ship_events
475
577
  if current_state != prepared_state:
476
578
  return "archive undo found unowned STATE.md changes"
477
579
  if ".project/ROADMAP.md" in dirty:
@@ -479,14 +581,13 @@ def _archive_metadata_error(
479
581
  return None
480
582
  if (phase, status) != ("shipped", "done"):
481
583
  return "archive undo requires ship/active or shipped/done"
584
+ if ship_events is None:
585
+ return "archive undo found unowned shipment STATE.md changes"
586
+ prepared_state += ship_events
482
587
 
483
588
  prepared = _state_from_text(prepared_state, "prepared archive STATE.md")
484
- events = (
485
- "archive preflight passed; shipment recorded",
486
- "archive preflight passed; shipment recorded; program complete",
487
- )
488
589
  rendered_states = []
489
- for event in events:
590
+ for event in SHIPMENT_EVENTS:
490
591
  try:
491
592
  _, _, rendered = _render_transition(
492
593
  prepared,
@@ -528,6 +629,7 @@ def _prepare_transaction(
528
629
  branch: str,
529
630
  archive: Optional[str],
530
631
  discussion: Optional[dict[str, bytes]],
632
+ member_fields: Optional[dict[str, str]] = None,
531
633
  ) -> dict[str, object]:
532
634
  transaction = {
533
635
  "schema": UNDO_TRANSACTION_SCHEMA,
@@ -545,6 +647,8 @@ def _prepare_transaction(
545
647
  ),
546
648
  "discussion": _encode_discussion(discussion),
547
649
  }
650
+ if member_fields is not None:
651
+ transaction.update(member_fields)
548
652
  _write_json(_git_path(repo, UNDO_TRANSACTION_NAME), transaction)
549
653
  return transaction
550
654
 
@@ -641,7 +745,7 @@ def _transaction_recovery_stage(
641
745
  expected_head = str(transaction["expected_head"])
642
746
  parent = str(transaction["parent"])
643
747
  current = _optional_rev(repo, "HEAD")
644
- if transaction["kind"] == "checkpoint":
748
+ if transaction["kind"] in {"checkpoint", "member-task"}:
645
749
  allowed = {expected_head, parent}
646
750
  else:
647
751
  allowed = {expected_head}
@@ -662,8 +766,60 @@ def _transaction_recovery_stage(
662
766
  return "reset"
663
767
 
664
768
 
769
+ def _member_undo_parent(repo: Path, member: str, landing: str) -> str:
770
+ """The member landing's parent, while that landing is the unpublished bound tip."""
771
+ checkout, _, entry = isolation._member_context(repo, member)
772
+ bound = entry["branch"]
773
+ if _run_git(checkout, "rev-parse", f"refs/heads/{bound}").stdout.strip() != landing:
774
+ raise UndoError(f"member {member} {bound} moved past this landing")
775
+ _require_member_unpublished(checkout, member, landing, bound)
776
+ return _run_git(checkout, "rev-parse", f"{landing}^").stdout.strip()
777
+
778
+
779
+ def _require_member_unpublished(checkout: Path, member: str, landing: str, bound: str) -> None:
780
+ for ref, where in (("refs/remotes/origin/main", "origin/main"), (f"refs/remotes/origin/{bound}", f"origin/{bound}")):
781
+ if _run_git(checkout, "merge-base", "--is-ancestor", landing, ref, check=False).returncode == 0:
782
+ raise UndoError(f"member {member} landing is already on {where}")
783
+
784
+
785
+ def _require_no_member_landing_journal(repo: Path) -> None:
786
+ directory = isolation.common_git_dir(repo).joinpath(*isolation.MEMBER_LANDING_DIR)
787
+ if any(directory.glob("*.json")):
788
+ raise UndoError("member landing journal is pending; recover member landing first")
789
+
790
+
791
+ def _undo_member_landing(repo: Path, transaction: dict[str, object]) -> None:
792
+ """Reset the member bound branch first; a resumed undo finds it already reset."""
793
+ member = str(transaction["member"])
794
+ checkout, _, entry = isolation._member_context(repo, member)
795
+ tip = _run_git(checkout, "rev-parse", f"refs/heads/{entry['branch']}").stdout.strip()
796
+ if tip == transaction["member_parent"]:
797
+ _require_member_unpublished(checkout, member, str(transaction["landing"]), entry["branch"])
798
+ return
799
+ if tip != transaction["landing"]:
800
+ raise UndoError(f"member {member} bound branch moved during undo")
801
+ if _member_undo_parent(repo, member, str(transaction["landing"])) != transaction["member_parent"]:
802
+ raise UndoError(f"member {member} landing parent changed during undo")
803
+ bound = Path(isolation.member_bound_checkout(repo, member)["checkout"])
804
+ if _run_git(bound, "status", "--porcelain", "--untracked-files=all").stdout:
805
+ raise UndoError(f"member {member} bound checkout is dirty")
806
+ _run_git(bound, "reset", "--hard", str(transaction["member_parent"]))
807
+
808
+
665
809
  def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
810
+ if transaction["kind"] == "member-task":
811
+ with isolation._member_landing_lock(repo):
812
+ _finish_transaction_locked(repo, transaction)
813
+ return
814
+ _finish_transaction_locked(repo, transaction)
815
+
816
+
817
+ def _finish_transaction_locked(repo: Path, transaction: dict[str, object]) -> None:
818
+ if transaction["kind"] == "member-task":
819
+ _require_no_member_landing_journal(repo)
666
820
  stage = _transaction_recovery_stage(repo, transaction)
821
+ if transaction["kind"] == "member-task":
822
+ _undo_member_landing(repo, transaction)
667
823
  if stage == "prepared":
668
824
  _require_unpublished_reset(repo, str(transaction["branch"]))
669
825
  _reset_to(repo, str(transaction["parent"]))
@@ -675,11 +831,7 @@ def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
675
831
  _remove_untracked_tree(repo, archive)
676
832
  path = _git_path(repo, UNDO_TRANSACTION_NAME)
677
833
  path.unlink()
678
- descriptor = os.open(path.parent, os.O_RDONLY)
679
- try:
680
- os.fsync(descriptor)
681
- finally:
682
- os.close(descriptor)
834
+ pipeline_state._common.fsync_directory(path.parent)
683
835
 
684
836
 
685
837
  def classify_undo(repo: Path) -> dict[str, object]:
@@ -821,6 +973,28 @@ def classify_undo(repo: Path) -> dict[str, object]:
821
973
  proof_error = _task_proof_error(resolved, head)
822
974
  if proof_error:
823
975
  return _blocked([f"task landing ownership is unproven: {proof_error}"])
976
+ record = isolation.MEMBER_RECORD_RE.search(body)
977
+ if record is not None:
978
+ try:
979
+ _require_no_member_landing_journal(resolved)
980
+ member_parent = _member_undo_parent(resolved, record["member"], record["landing"])
981
+ except (IsolationError, UndoError, PipelineStateError) as error:
982
+ return _blocked([f"member landing undo is unsafe: {error}"])
983
+ return {
984
+ "kind": "member-task",
985
+ "branch": recorded_branch,
986
+ "head": head,
987
+ "parent": parent,
988
+ "subject": subject,
989
+ "member": record["member"],
990
+ "landing": record["landing"],
991
+ "member_parent": member_parent,
992
+ "effects": [
993
+ f"reset member {record['member']} bound branch to {member_parent}",
994
+ f"reset {recorded_branch} to {parent}",
995
+ ],
996
+ "blocked": [],
997
+ }
824
998
  return {
825
999
  "kind": "task",
826
1000
  "branch": recorded_branch,
@@ -978,6 +1152,20 @@ def apply_undo(repo: Path, kind: str, expected_head: str) -> dict[str, object]:
978
1152
  discussion,
979
1153
  )
980
1154
  _finish_transaction(resolved, transaction)
1155
+ elif kind == "member-task":
1156
+ with isolation._member_landing_lock(resolved):
1157
+ _require_no_member_landing_journal(resolved)
1158
+ if preview(resolved)["target"] != target:
1159
+ raise UndoError("member task undo target changed after preview")
1160
+ if _worktree_changes(resolved):
1161
+ raise UndoError("worktree changed after member task undo preview")
1162
+ _require_unpublished_reset(resolved, str(target["branch"]))
1163
+ transaction = _prepare_transaction(
1164
+ resolved, kind, expected_head, str(target["parent"]), str(target["branch"]), None, None,
1165
+ {"member": str(target["member"]), "landing": str(target["landing"]),
1166
+ "member_parent": str(target["member_parent"])},
1167
+ )
1168
+ _finish_transaction_locked(resolved, transaction)
981
1169
  elif kind == "task":
982
1170
  parent = target["parent"]
983
1171
  if not parent:
@@ -205,7 +205,7 @@ def select_fetched_base(
205
205
  resolved = subprocess.run(
206
206
  ["git", "-C", str(root), "rev-parse", "--verify", f"{remote_default}^{{commit}}"],
207
207
  capture_output=True,
208
- text=True,
208
+ encoding="utf-8", errors="replace",
209
209
  check=False,
210
210
  )
211
211
  if resolved.returncode != 0 or resolved.stdout.strip() != base:
@@ -470,7 +470,7 @@ def merge_artifacts(
470
470
  lines.append(artifact["text"].rstrip())
471
471
  lines.append("")
472
472
  output.parent.mkdir(parents=True, exist_ok=True)
473
- output.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
473
+ output.write_bytes(("\n".join(lines).rstrip() + "\n").encode("utf-8"))
474
474
  return {
475
475
  "output": str(output.resolve()),
476
476
  "families": families,
@@ -8,6 +8,7 @@ from pathlib import Path
8
8
  import shutil
9
9
  import shlex
10
10
  import tempfile
11
+ import time
11
12
  from contextlib import contextmanager
12
13
 
13
14
  try:
@@ -22,10 +23,42 @@ RUNTIME_FILES = (
22
23
  "review_panel.py", "_common.py", "worktree_paths.py", "build_recovery.py",
23
24
  "state_checkpoint.py", "state_promote.py", "discussion_validate.py", "integration.py",
24
25
  "build_state.py", "lean_verification.py", "check_docs_audit.py",
25
- "path_config.py", "model_policy.py", "loop_run.py",
26
+ "path_config.py", "model_policy.py", "loop_run.py", "members.py",
26
27
  )
27
28
  GUARDS = ("guard_hook.py", "git_guard.py")
28
29
 
30
+ # Optional owner-recorded provenance on .gsd-path/runtime.json declarations,
31
+ # e.g. {"source": "<npm version or package id>", "patch_ref": "<commit sha
32
+ # or patch list>", "note": "<owner label>"}. Provenance is display/audit
33
+ # metadata ONLY: it never joins the hashed manifest input (manifest_digest
34
+ # covers exactly {"version", "files"}), never acts as an alternate accepted
35
+ # digest, and never bypasses or weakens validate_runtime. A declaration
36
+ # without provenance is stock and stays exactly as valid as one with it.
37
+ PROVENANCE_KEYS = ("source", "patch_ref", "note")
38
+
39
+ # Access denied and sharing violation: on Windows a scanner or indexer that
40
+ # briefly opens a freshly written file blocks renaming the directory holding it.
41
+ _WINDOWS_BUSY_ERRORS = (5, 32)
42
+ _RENAME_ATTEMPTS = 20
43
+
44
+
45
+ def _rename_directory(source, destination):
46
+ """Path.rename, retried while Windows briefly holds a file inside ``source``."""
47
+ if os.name != "nt":
48
+ source.rename(destination)
49
+ return
50
+ for attempt in range(_RENAME_ATTEMPTS):
51
+ try:
52
+ source.rename(destination)
53
+ return
54
+ except PermissionError as error:
55
+ # Never retry onto a directory that appeared meanwhile.
56
+ if (getattr(error, "winerror", None) not in _WINDOWS_BUSY_ERRORS
57
+ or os.path.lexists(destination)
58
+ or attempt == _RENAME_ATTEMPTS - 1):
59
+ raise
60
+ time.sleep(min(0.01 * 2 ** attempt, 0.25))
61
+
29
62
 
30
63
  def guard_launcher(name):
31
64
  if name not in GUARDS:
@@ -41,7 +74,7 @@ def guard_launcher(name):
41
74
 
42
75
 
43
76
  def source_manifest(source):
44
- version = json.loads((source / "package.json").read_text())["version"]
77
+ version = json.loads((source / "package.json").read_text(encoding="utf-8"))["version"]
45
78
  files = {}
46
79
  for name in (*RUNTIME_FILES, *GUARDS, "status_runtime.py"):
47
80
  path = source / "scripts" / name
@@ -107,7 +140,7 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
107
140
  shutil.copyfile(source / "scripts" / name, staging / name)
108
141
  if hashlib.sha256((staging / name).read_bytes()).hexdigest() != digest:
109
142
  raise ValueError(f"runtime source changed while installing: {name}")
110
- (staging / "manifest.json").write_text(pin_text(manifest), encoding="utf-8")
143
+ (staging / "manifest.json").write_bytes(pin_text(manifest).encode("utf-8"))
111
144
  # Serialize publication/repair, including two explicit restorations.
112
145
  previous = Path(temporary) / "previous"
113
146
  with publication_lock(parent, pin["digest"]):
@@ -118,13 +151,13 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
118
151
  except ValueError:
119
152
  if not repair:
120
153
  raise
121
- destination.rename(previous)
154
+ _rename_directory(destination, previous)
122
155
  try:
123
- staging.rename(destination)
156
+ _rename_directory(staging, destination)
124
157
  status_runtime.validate_runtime(pin)
125
158
  except BaseException:
126
159
  if previous.exists() and not destination.exists():
127
- previous.rename(destination)
160
+ _rename_directory(previous, destination)
128
161
  raise
129
162
  return pin
130
163
 
@@ -167,7 +200,7 @@ def recover_migration(project):
167
200
  return
168
201
  if journal.is_symlink():
169
202
  raise ValueError(f"unsafe runtime migration journal: {journal}")
170
- data = json.loads(journal.read_text())
203
+ data = json.loads(journal.read_text(encoding="utf-8"))
171
204
  recorded_project = data.get("project")
172
205
  if (data.get("schema") != "gsd-path/runtime-migration/v1"
173
206
  or not isinstance(recorded_project, str)
@@ -196,7 +229,7 @@ def recover_migration(project):
196
229
  journal.unlink()
197
230
 
198
231
 
199
- def operate(source, project, action, *, dry_run=False):
232
+ def operate(source, project, action, *, dry_run=False, provenance=None):
200
233
  if project.is_symlink() or (project / ".gsd-path").is_symlink():
201
234
  raise ValueError("unsafe project runtime directory")
202
235
  if action == "restore":
@@ -204,12 +237,23 @@ def operate(source, project, action, *, dry_run=False):
204
237
  publish(source, expected=pin, dry_run=dry_run, repair=True)
205
238
  return pin
206
239
  if action == "upgrade":
207
- status_runtime.declaration(project)
240
+ previous = status_runtime.declaration(project)
208
241
  pin = publish(source, dry_run=dry_run)
242
+ # Explicit provenance replaces the recorded object. Without new flags,
243
+ # an existing entry carries forward only while the pinned digest is
244
+ # unchanged — a different source drops stale hotfix metadata instead
245
+ # of stamping it onto bytes it no longer describes. Metadata only —
246
+ # it never changes the pinned digest.
247
+ if provenance is None and previous.get("digest") == pin["digest"]:
248
+ provenance = previous.get("provenance")
249
+ if provenance:
250
+ pin = {**pin, "provenance": provenance}
209
251
  if not dry_run:
210
252
  launcher = project / ".gsd-path/status_runtime.py"
211
- original = launcher.read_text(encoding="utf-8")
212
- replacement = (source / "scripts/status_runtime.py").read_text(encoding="utf-8")
253
+ # Exact bytes: read_text() would turn CRLF into LF, leaving the
254
+ # launcher unequal to the runtime's byte-for-byte copy.
255
+ original = launcher.read_bytes().decode("utf-8")
256
+ replacement = (source / "scripts/status_runtime.py").read_bytes().decode("utf-8")
213
257
  # Both launchers understand the same declaration schema. Publishing
214
258
  # the compatible launcher first leaves the old selection usable.
215
259
  if replacement != original:
@@ -10,7 +10,8 @@
10
10
  "cursor": {"local_root": ".cursor/skills", "guard_tier": "native-fail-closed", "child_apis": ["Task"]},
11
11
  "zed": {"local_root": ".agents/skills", "guard_tier": "git-only", "invocation_prefix": "/", "child_apis": ["spawn_agent"]},
12
12
  "kiro": {"local_root": ".kiro/skills", "guard_tier": "git-only", "child_apis": ["invoke_sub_agent"]},
13
- "kimi": {"local_root": ".kimi-code/skills", "guard_tier": "git-only", "child_apis": ["Agent"]}
13
+ "kimi": {"local_root": ".kimi-code/skills", "guard_tier": "git-only", "child_apis": ["Agent"]},
14
+ "muse": {"local_root": ".agents/skills", "guard_tier": "git-only", "invocation_prefix": "/", "child_apis": ["muse.subagent_spawn"]}
14
15
  },
15
16
  "skills": [
16
17
  "gsd-path",
@@ -55,6 +56,7 @@
55
56
  "scripts/integration.py",
56
57
  "scripts/archive_milestone.py",
57
58
  "scripts/bootstrap_repository.py",
59
+ "scripts/members.py",
58
60
  "scripts/detect_project.py",
59
61
  "scripts/promote_lookahead.py",
60
62
  "scripts/discussion_records.py",
@@ -95,11 +97,14 @@
95
97
  "skills/",
96
98
  "platforms/",
97
99
  "AGENTS.md",
98
- "WORKFLOW.md"
100
+ "WORKFLOW.md",
101
+ "!**/__pycache__/**",
102
+ "!**/*.pyc"
99
103
  ],
100
104
  "phase_resources": {
101
105
  "gsd-path-build": [
102
106
  "references/runtime-selection.md",
107
+ "references/operating-rules.md",
103
108
  "references/build-recovery.md",
104
109
  "references/build-native.md",
105
110
  "references/build-abandon.md",
@@ -112,6 +117,7 @@
112
117
  "references/reviewer-skeptic.md",
113
118
  "references/reviewer-final.md",
114
119
  "references/reviewer-panel.md",
120
+ "references/spec-probes.md",
115
121
 
116
122
  "templates/task.md",
117
123
  "templates/wave-review.md",
@@ -120,11 +126,13 @@
120
126
  ],
121
127
  "gsd-path-discuss": [
122
128
  "references/runtime-selection.md",
129
+ "references/operating-rules.md",
123
130
  "templates/answers.md",
124
131
  "templates/dialogue.md"
125
132
  ],
126
133
  "gsd-path-docs-audit": [
127
134
  "references/runtime-selection.md",
135
+ "references/operating-rules.md",
128
136
  "references/dispatch.md",
129
137
  "references/model-policy.md",
130
138
  "references/docs-auditor.md",
@@ -132,13 +140,16 @@
132
140
  ],
133
141
  "gsd-path-define": [
134
142
  "references/runtime-selection.md",
143
+ "references/operating-rules.md",
135
144
  "references/build-recovery.md",
145
+ "references/spec-probes.md",
136
146
  "templates/charter.md",
137
147
  "templates/intent.md",
138
148
  "templates/state.md"
139
149
  ],
140
150
  "gsd-path-inspect": [
141
151
  "references/runtime-selection.md",
152
+ "references/operating-rules.md",
142
153
  "references/codebase-mapper.md",
143
154
  "references/dispatch.md",
144
155
  "references/model-policy.md",
@@ -148,21 +159,26 @@
148
159
  "templates/state.md"
149
160
  ],
150
161
  "gsd-path-forensics": [
151
- "references/runtime-selection.md"
162
+ "references/runtime-selection.md",
163
+ "references/operating-rules.md"
152
164
  ],
153
165
  "gsd-path-migrate": [
154
- "references/runtime-selection.md"
166
+ "references/runtime-selection.md",
167
+ "references/operating-rules.md"
155
168
  ],
156
169
  "gsd-path-loop": [
157
170
  "references/runtime-selection.md",
171
+ "references/operating-rules.md",
158
172
  "templates/loop.md"
159
173
  ],
160
174
  "gsd-path-plan": [
161
175
  "references/runtime-selection.md",
176
+ "references/operating-rules.md",
162
177
  "references/build-recovery.md",
163
178
  "references/dispatch.md",
164
179
  "references/model-policy.md",
165
180
  "references/planner.md",
181
+ "references/spec-probes.md",
166
182
  "templates/patch-findings.md",
167
183
  "templates/plan.md",
168
184
  "templates/plan-panel.md",
@@ -170,6 +186,7 @@
170
186
  ],
171
187
  "gsd-path-research": [
172
188
  "references/runtime-selection.md",
189
+ "references/operating-rules.md",
173
190
  "references/dispatch.md",
174
191
  "references/model-policy.md",
175
192
  "references/researcher.md",
@@ -178,6 +195,7 @@
178
195
  ],
179
196
  "gsd-path-roadmap": [
180
197
  "references/runtime-selection.md",
198
+ "references/operating-rules.md",
181
199
  "references/dispatch.md",
182
200
  "references/model-policy.md",
183
201
  "references/roadmapper.md",
@@ -185,6 +203,7 @@
185
203
  ],
186
204
  "gsd-path-ship": [
187
205
  "references/runtime-selection.md",
206
+ "references/operating-rules.md",
188
207
  "references/dispatch.md",
189
208
  "references/model-policy.md",
190
209
  "references/reviewer.md",
@@ -193,6 +212,7 @@
193
212
  "references/reviewer-skeptic.md",
194
213
  "references/reviewer-final.md",
195
214
  "references/reviewer-panel.md",
215
+ "references/spec-probes.md",
196
216
 
197
217
  "templates/archive-manifest.md",
198
218
  "templates/final-review.md",
@@ -202,13 +222,15 @@
202
222
  ],
203
223
  "gsd-path-decide": [
204
224
  "references/runtime-selection.md",
225
+ "references/operating-rules.md",
205
226
  "references/dispatch.md",
206
227
  "references/model-policy.md",
207
228
  "references/decider.md",
208
229
  "templates/synthesis.md"
209
230
  ],
210
231
  "gsd-path-undo": [
211
- "references/runtime-selection.md"
232
+ "references/runtime-selection.md",
233
+ "references/operating-rules.md"
212
234
  ]
213
235
  },
214
236
  "script_targets": [
@@ -259,6 +281,16 @@
259
281
  ["scripts/discussion_validate.py", "skills/gsd-path-ship/scripts/discussion_validate.py"],
260
282
  ["scripts/integration.py", "skills/gsd-path-ship/scripts/integration.py"],
261
283
  ["scripts/bootstrap_repository.py", "skills/gsd-path/scripts/bootstrap_repository.py"],
284
+ ["scripts/members.py", "skills/gsd-path/scripts/members.py"],
285
+ ["scripts/members.py", "skills/gsd-path-build/scripts/members.py"],
286
+ ["scripts/members.py", "skills/gsd-path-decide/scripts/members.py"],
287
+ ["scripts/members.py", "skills/gsd-path-define/scripts/members.py"],
288
+ ["scripts/members.py", "skills/gsd-path-docs-audit/scripts/members.py"],
289
+ ["scripts/members.py", "skills/gsd-path-inspect/scripts/members.py"],
290
+ ["scripts/members.py", "skills/gsd-path-plan/scripts/members.py"],
291
+ ["scripts/members.py", "skills/gsd-path-research/scripts/members.py"],
292
+ ["scripts/members.py", "skills/gsd-path-roadmap/scripts/members.py"],
293
+ ["scripts/members.py", "skills/gsd-path-ship/scripts/members.py"],
262
294
  ["scripts/detect_project.py", "skills/gsd-path/scripts/detect_project.py"],
263
295
  ["scripts/detect_project.py", "skills/gsd-path-define/scripts/detect_project.py"],
264
296
  ["scripts/detect_project.py", "skills/gsd-path-inspect/scripts/detect_project.py"],