@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.
- package/AGENTS.md +2 -207
- package/CHANGELOG.md +331 -69
- package/DOCS.md +25 -9
- package/FULL.md +12 -5
- package/GUIDE.md +1 -1
- package/HOOKS.md +104 -14
- package/QUICK.md +5 -2
- package/README.md +131 -111
- package/RUNTIME.md +2 -2
- package/UPDATE.md +61 -11
- package/WORKFLOW.md +44 -7
- package/package.json +13 -9
- package/platforms/shared-agents/dispatch.md +13 -0
- package/scripts/_common.py +619 -18
- package/scripts/archive_milestone.py +160 -86
- package/scripts/bootstrap_repository.py +8 -5
- package/scripts/build_recovery.py +100 -32
- package/scripts/build_state.py +143 -24
- package/scripts/check_docs_audit.py +91 -7
- package/scripts/check_handoffs.py +662 -50
- package/scripts/check_task_briefs.py +338 -30
- package/scripts/check_update.py +2 -2
- package/scripts/core_hook_gate.py +10 -1
- package/scripts/core_hook_settings.py +11 -4
- package/scripts/detect_project.py +587 -32
- package/scripts/discussion_records.py +19 -13
- package/scripts/discussion_validate.py +152 -50
- package/scripts/dispatch_driver.py +501 -46
- package/scripts/git_guard.py +118 -31
- package/scripts/guard_hook.py +1567 -194
- package/scripts/install.mjs +77 -46
- package/scripts/install.py +611 -50
- package/scripts/integration.py +580 -25
- package/scripts/isolation.py +1438 -57
- package/scripts/lean_verification.py +99 -19
- package/scripts/loop_run.py +31 -29
- package/scripts/members.py +706 -0
- package/scripts/migrate_core.py +2 -2
- package/scripts/path_config.py +5 -5
- package/scripts/pipeline_diagnose.py +82 -31
- package/scripts/pipeline_git.py +124 -34
- package/scripts/pipeline_state.py +287 -87
- package/scripts/pipeline_undo.py +218 -30
- package/scripts/promote_lookahead.py +1 -1
- package/scripts/review_panel.py +1 -1
- package/scripts/runtime_store.py +55 -11
- package/scripts/skill-resources.json +37 -5
- package/scripts/state_checkpoint.py +135 -44
- package/scripts/state_promote.py +2 -0
- package/scripts/status_runtime.py +58 -10
- package/scripts/sync_skill_resources.py +8 -7
- package/scripts/task_context.py +12 -3
- package/scripts/token_budget.py +12 -8
- package/scripts/wizard.mjs +1 -0
- package/scripts/workflow_run.py +107 -30
- package/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path/BUILD.md +7 -1
- package/skills/gsd-path/DECIDE.md +11 -4
- package/skills/gsd-path/DEFINE.md +36 -4
- package/skills/gsd-path/DOCS-AUDIT.md +6 -4
- package/skills/gsd-path/INSPECT.md +5 -4
- package/skills/gsd-path/PLAN.md +18 -4
- package/skills/gsd-path/RESEARCH.md +13 -1
- package/skills/gsd-path/ROADMAP.md +2 -1
- package/skills/gsd-path/SHIP.md +33 -11
- package/skills/gsd-path/SKILL.md +45 -1
- package/skills/gsd-path/references/build-native.md +63 -15
- package/skills/gsd-path/references/codebase-mapper.md +2 -1
- package/skills/gsd-path/references/dispatch.md +13 -0
- package/skills/gsd-path/references/docs-auditor.md +7 -1
- package/skills/gsd-path/references/operating-rules.md +214 -0
- package/skills/gsd-path/references/planner.md +22 -4
- package/skills/gsd-path/references/reviewer-final.md +20 -2
- package/skills/gsd-path/references/reviewer-wave.md +18 -5
- package/skills/gsd-path/references/reviewer.md +3 -1
- package/skills/gsd-path/references/spec-probes.md +150 -0
- package/skills/gsd-path/scripts/_common.py +619 -18
- package/skills/gsd-path/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path/scripts/bootstrap_repository.py +8 -5
- package/skills/gsd-path/scripts/build_recovery.py +100 -32
- package/skills/gsd-path/scripts/build_state.py +143 -24
- package/skills/gsd-path/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path/scripts/check_update.py +2 -2
- package/skills/gsd-path/scripts/detect_project.py +587 -32
- package/skills/gsd-path/scripts/discussion_records.py +19 -13
- package/skills/gsd-path/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path/scripts/dispatch_driver.py +501 -46
- package/skills/gsd-path/scripts/git_guard.py +118 -31
- package/skills/gsd-path/scripts/integration.py +580 -25
- package/skills/gsd-path/scripts/isolation.py +1438 -57
- package/skills/gsd-path/scripts/lean_verification.py +99 -19
- package/skills/gsd-path/scripts/loop_run.py +31 -29
- package/skills/gsd-path/scripts/members.py +706 -0
- package/skills/gsd-path/scripts/path_config.py +5 -5
- package/skills/gsd-path/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path/scripts/review_panel.py +1 -1
- package/skills/gsd-path/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path/scripts/state_promote.py +2 -0
- package/skills/gsd-path/scripts/status_runtime.py +58 -10
- package/skills/gsd-path/scripts/task_context.py +12 -3
- package/skills/gsd-path/scripts/token_budget.py +12 -8
- package/skills/gsd-path/scripts/workflow_run.py +107 -30
- package/skills/gsd-path/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path/templates/codebase.md +1 -1
- package/skills/gsd-path/templates/docs-audit.md +6 -2
- package/skills/gsd-path/templates/final-review.md +16 -4
- package/skills/gsd-path/templates/gap-review.md +2 -1
- package/skills/gsd-path/templates/intent.md +30 -0
- package/skills/gsd-path/templates/patch-findings.md +3 -3
- package/skills/gsd-path/templates/plan.md +17 -2
- package/skills/gsd-path/templates/research-handoff.md +14 -3
- package/skills/gsd-path/templates/state.md +1 -1
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +16 -4
- package/skills/gsd-path-build/SKILL.md +7 -1
- package/skills/gsd-path-build/references/build-native.md +63 -15
- package/skills/gsd-path-build/references/dispatch.md +13 -0
- package/skills/gsd-path-build/references/operating-rules.md +214 -0
- package/skills/gsd-path-build/references/reviewer-final.md +20 -2
- package/skills/gsd-path-build/references/reviewer-wave.md +18 -5
- package/skills/gsd-path-build/references/reviewer.md +3 -1
- package/skills/gsd-path-build/references/spec-probes.md +150 -0
- package/skills/gsd-path-build/scripts/_common.py +619 -18
- package/skills/gsd-path-build/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-build/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-build/scripts/build_state.py +143 -24
- package/skills/gsd-path-build/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-build/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-build/scripts/detect_project.py +587 -32
- package/skills/gsd-path-build/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-build/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-build/scripts/dispatch_driver.py +501 -46
- package/skills/gsd-path-build/scripts/integration.py +580 -25
- package/skills/gsd-path-build/scripts/isolation.py +1438 -57
- package/skills/gsd-path-build/scripts/loop_run.py +31 -29
- package/skills/gsd-path-build/scripts/members.py +706 -0
- package/skills/gsd-path-build/scripts/path_config.py +5 -5
- package/skills/gsd-path-build/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-build/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-build/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-build/scripts/review_panel.py +1 -1
- package/skills/gsd-path-build/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-build/scripts/state_promote.py +2 -0
- package/skills/gsd-path-build/scripts/task_context.py +12 -3
- package/skills/gsd-path-build/scripts/token_budget.py +12 -8
- package/skills/gsd-path-build/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-build/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +16 -4
- package/skills/gsd-path-decide/SKILL.md +11 -4
- package/skills/gsd-path-decide/references/dispatch.md +13 -0
- package/skills/gsd-path-decide/references/operating-rules.md +214 -0
- package/skills/gsd-path-decide/scripts/_common.py +619 -18
- package/skills/gsd-path-decide/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-decide/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-decide/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-decide/scripts/detect_project.py +587 -32
- package/skills/gsd-path-decide/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-decide/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-decide/scripts/integration.py +580 -25
- package/skills/gsd-path-decide/scripts/isolation.py +1438 -57
- package/skills/gsd-path-decide/scripts/loop_run.py +31 -29
- package/skills/gsd-path-decide/scripts/members.py +706 -0
- package/skills/gsd-path-decide/scripts/path_config.py +5 -5
- package/skills/gsd-path-decide/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-decide/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-decide/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-decide/scripts/review_panel.py +1 -1
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-decide/scripts/state_promote.py +2 -0
- package/skills/gsd-path-decide/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-define/SKILL.md +36 -4
- package/skills/gsd-path-define/references/operating-rules.md +214 -0
- package/skills/gsd-path-define/references/spec-probes.md +150 -0
- package/skills/gsd-path-define/scripts/_common.py +619 -18
- package/skills/gsd-path-define/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-define/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-define/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-define/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-define/scripts/detect_project.py +587 -32
- package/skills/gsd-path-define/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-define/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-define/scripts/integration.py +580 -25
- package/skills/gsd-path-define/scripts/isolation.py +1438 -57
- package/skills/gsd-path-define/scripts/loop_run.py +31 -29
- package/skills/gsd-path-define/scripts/members.py +706 -0
- package/skills/gsd-path-define/scripts/path_config.py +5 -5
- package/skills/gsd-path-define/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-define/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-define/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-define/scripts/review_panel.py +1 -1
- package/skills/gsd-path-define/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-define/scripts/state_promote.py +2 -0
- package/skills/gsd-path-define/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-define/templates/intent.md +30 -0
- package/skills/gsd-path-define/templates/state.md +1 -1
- package/skills/gsd-path-discuss/SKILL.md +2 -1
- package/skills/gsd-path-discuss/references/operating-rules.md +214 -0
- package/skills/gsd-path-discuss/scripts/_common.py +619 -18
- package/skills/gsd-path-discuss/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-discuss/scripts/loop_run.py +31 -29
- package/skills/gsd-path-discuss/scripts/path_config.py +5 -5
- package/skills/gsd-path-discuss/scripts/review_panel.py +1 -1
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-docs-audit/SKILL.md +6 -4
- package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +7 -1
- package/skills/gsd-path-docs-audit/references/operating-rules.md +214 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +619 -18
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +587 -32
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-docs-audit/scripts/integration.py +580 -25
- package/skills/gsd-path-docs-audit/scripts/isolation.py +1438 -57
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +31 -29
- package/skills/gsd-path-docs-audit/scripts/members.py +706 -0
- package/skills/gsd-path-docs-audit/scripts/path_config.py +5 -5
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-docs-audit/scripts/review_panel.py +1 -1
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +2 -0
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +6 -2
- package/skills/gsd-path-forensics/SKILL.md +2 -1
- package/skills/gsd-path-forensics/references/operating-rules.md +214 -0
- package/skills/gsd-path-forensics/scripts/_common.py +619 -18
- package/skills/gsd-path-forensics/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-forensics/scripts/loop_run.py +31 -29
- package/skills/gsd-path-forensics/scripts/path_config.py +5 -5
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +82 -31
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +218 -30
- package/skills/gsd-path-forensics/scripts/review_panel.py +1 -1
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-inspect/SKILL.md +5 -4
- package/skills/gsd-path-inspect/references/codebase-mapper.md +2 -1
- package/skills/gsd-path-inspect/references/dispatch.md +13 -0
- package/skills/gsd-path-inspect/references/docs-auditor.md +7 -1
- package/skills/gsd-path-inspect/references/operating-rules.md +214 -0
- package/skills/gsd-path-inspect/scripts/_common.py +619 -18
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-inspect/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-inspect/scripts/detect_project.py +587 -32
- package/skills/gsd-path-inspect/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-inspect/scripts/integration.py +580 -25
- package/skills/gsd-path-inspect/scripts/isolation.py +1438 -57
- package/skills/gsd-path-inspect/scripts/loop_run.py +31 -29
- package/skills/gsd-path-inspect/scripts/members.py +706 -0
- package/skills/gsd-path-inspect/scripts/path_config.py +5 -5
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-inspect/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-inspect/scripts/review_panel.py +1 -1
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-inspect/scripts/state_promote.py +2 -0
- package/skills/gsd-path-inspect/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-inspect/templates/codebase.md +1 -1
- package/skills/gsd-path-inspect/templates/docs-audit.md +6 -2
- package/skills/gsd-path-inspect/templates/state.md +1 -1
- package/skills/gsd-path-loop/SKILL.md +2 -1
- package/skills/gsd-path-loop/references/operating-rules.md +214 -0
- package/skills/gsd-path-loop/scripts/_common.py +619 -18
- package/skills/gsd-path-loop/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-loop/scripts/loop_run.py +31 -29
- package/skills/gsd-path-loop/scripts/path_config.py +5 -5
- package/skills/gsd-path-loop/scripts/review_panel.py +1 -1
- package/skills/gsd-path-loop/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-migrate/SKILL.md +2 -1
- package/skills/gsd-path-migrate/references/operating-rules.md +214 -0
- package/skills/gsd-path-migrate/scripts/_common.py +619 -18
- package/skills/gsd-path-migrate/scripts/core_hook_gate.py +10 -1
- package/skills/gsd-path-migrate/scripts/core_hook_settings.py +11 -4
- package/skills/gsd-path-migrate/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-migrate/scripts/loop_run.py +31 -29
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -2
- package/skills/gsd-path-migrate/scripts/path_config.py +5 -5
- package/skills/gsd-path-migrate/scripts/review_panel.py +1 -1
- package/skills/gsd-path-plan/SKILL.md +18 -4
- package/skills/gsd-path-plan/references/dispatch.md +13 -0
- package/skills/gsd-path-plan/references/operating-rules.md +214 -0
- package/skills/gsd-path-plan/references/planner.md +22 -4
- package/skills/gsd-path-plan/references/spec-probes.md +150 -0
- package/skills/gsd-path-plan/scripts/_common.py +619 -18
- package/skills/gsd-path-plan/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-plan/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-plan/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-plan/scripts/detect_project.py +587 -32
- package/skills/gsd-path-plan/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-plan/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-plan/scripts/integration.py +580 -25
- package/skills/gsd-path-plan/scripts/isolation.py +1438 -57
- package/skills/gsd-path-plan/scripts/loop_run.py +31 -29
- package/skills/gsd-path-plan/scripts/members.py +706 -0
- package/skills/gsd-path-plan/scripts/path_config.py +5 -5
- package/skills/gsd-path-plan/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-plan/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-plan/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-plan/scripts/review_panel.py +1 -1
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-plan/scripts/state_promote.py +2 -0
- package/skills/gsd-path-plan/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-plan/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
- package/skills/gsd-path-plan/templates/plan.md +17 -2
- package/skills/gsd-path-plan/templates/task.md +1 -0
- package/skills/gsd-path-research/SKILL.md +13 -1
- package/skills/gsd-path-research/references/dispatch.md +13 -0
- package/skills/gsd-path-research/references/operating-rules.md +214 -0
- package/skills/gsd-path-research/scripts/_common.py +619 -18
- package/skills/gsd-path-research/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-research/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-research/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-research/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-research/scripts/detect_project.py +587 -32
- package/skills/gsd-path-research/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-research/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-research/scripts/integration.py +580 -25
- package/skills/gsd-path-research/scripts/isolation.py +1438 -57
- package/skills/gsd-path-research/scripts/loop_run.py +31 -29
- package/skills/gsd-path-research/scripts/members.py +706 -0
- package/skills/gsd-path-research/scripts/path_config.py +5 -5
- package/skills/gsd-path-research/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-research/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-research/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-research/scripts/review_panel.py +1 -1
- package/skills/gsd-path-research/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-research/scripts/state_promote.py +2 -0
- package/skills/gsd-path-research/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-research/templates/research-handoff.md +14 -3
- package/skills/gsd-path-roadmap/SKILL.md +2 -1
- package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
- package/skills/gsd-path-roadmap/references/operating-rules.md +214 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +619 -18
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-roadmap/scripts/detect_project.py +587 -32
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-roadmap/scripts/integration.py +580 -25
- package/skills/gsd-path-roadmap/scripts/isolation.py +1438 -57
- package/skills/gsd-path-roadmap/scripts/loop_run.py +31 -29
- package/skills/gsd-path-roadmap/scripts/members.py +706 -0
- package/skills/gsd-path-roadmap/scripts/path_config.py +5 -5
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-roadmap/scripts/review_panel.py +1 -1
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-roadmap/scripts/state_promote.py +2 -0
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-ship/SKILL.md +33 -11
- package/skills/gsd-path-ship/references/dispatch.md +13 -0
- package/skills/gsd-path-ship/references/operating-rules.md +214 -0
- package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
- package/skills/gsd-path-ship/references/reviewer-wave.md +18 -5
- package/skills/gsd-path-ship/references/reviewer.md +3 -1
- package/skills/gsd-path-ship/references/spec-probes.md +150 -0
- package/skills/gsd-path-ship/scripts/_common.py +619 -18
- package/skills/gsd-path-ship/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-ship/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-ship/scripts/build_state.py +143 -24
- package/skills/gsd-path-ship/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-ship/scripts/detect_project.py +587 -32
- package/skills/gsd-path-ship/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-ship/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-ship/scripts/integration.py +580 -25
- package/skills/gsd-path-ship/scripts/isolation.py +1438 -57
- package/skills/gsd-path-ship/scripts/lean_verification.py +99 -19
- package/skills/gsd-path-ship/scripts/loop_run.py +31 -29
- package/skills/gsd-path-ship/scripts/members.py +706 -0
- package/skills/gsd-path-ship/scripts/path_config.py +5 -5
- package/skills/gsd-path-ship/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-ship/scripts/pipeline_state.py +287 -87
- package/skills/gsd-path-ship/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-ship/scripts/review_panel.py +1 -1
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +135 -44
- package/skills/gsd-path-ship/scripts/state_promote.py +2 -0
- package/skills/gsd-path-ship/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-ship/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-ship/templates/final-review.md +16 -4
- package/skills/gsd-path-ship/templates/gap-review.md +2 -1
- package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
- package/skills/gsd-path-ship/templates/wave-review.md +16 -4
- package/skills/gsd-path-undo/SKILL.md +2 -1
- package/skills/gsd-path-undo/references/operating-rules.md +214 -0
- package/skills/gsd-path-undo/scripts/_common.py +619 -18
- package/skills/gsd-path-undo/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-undo/scripts/loop_run.py +31 -29
- package/skills/gsd-path-undo/scripts/path_config.py +5 -5
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +218 -30
- package/skills/gsd-path-undo/scripts/review_panel.py +1 -1
- package/skills/gsd-path-undo/scripts/worktree_paths.py +72 -10
- package/skills/path/BUILD.md +7 -1
- package/skills/path/DECIDE.md +11 -4
- package/skills/path/DEFINE.md +36 -4
- package/skills/path/DOCS-AUDIT.md +6 -4
- package/skills/path/INSPECT.md +5 -4
- package/skills/path/PLAN.md +18 -4
- package/skills/path/RESEARCH.md +13 -1
- package/skills/path/ROADMAP.md +2 -1
- package/skills/path/SHIP.md +33 -11
- package/skills/path/SKILL.md +45 -1
- package/skills/path/references/build-native.md +63 -15
- package/skills/path/references/codebase-mapper.md +2 -1
- package/skills/path/references/dispatch.md +13 -0
- package/skills/path/references/docs-auditor.md +7 -1
- package/skills/path/references/operating-rules.md +214 -0
- package/skills/path/references/planner.md +22 -4
- package/skills/path/references/reviewer-final.md +20 -2
- package/skills/path/references/reviewer-wave.md +18 -5
- package/skills/path/references/reviewer.md +3 -1
- package/skills/path/references/spec-probes.md +150 -0
- package/skills/path/scripts/_common.py +619 -18
- package/skills/path/scripts/archive_milestone.py +160 -86
- package/skills/path/scripts/bootstrap_repository.py +8 -5
- package/skills/path/scripts/build_recovery.py +100 -32
- package/skills/path/scripts/build_state.py +143 -24
- package/skills/path/scripts/check_docs_audit.py +91 -7
- package/skills/path/scripts/check_handoffs.py +662 -50
- package/skills/path/scripts/check_task_briefs.py +338 -30
- package/skills/path/scripts/check_update.py +2 -2
- package/skills/path/scripts/detect_project.py +587 -32
- package/skills/path/scripts/discussion_records.py +19 -13
- package/skills/path/scripts/discussion_validate.py +152 -50
- package/skills/path/scripts/dispatch_driver.py +501 -46
- package/skills/path/scripts/git_guard.py +118 -31
- package/skills/path/scripts/integration.py +580 -25
- package/skills/path/scripts/isolation.py +1438 -57
- package/skills/path/scripts/lean_verification.py +99 -19
- package/skills/path/scripts/loop_run.py +31 -29
- package/skills/path/scripts/members.py +706 -0
- package/skills/path/scripts/path_config.py +5 -5
- package/skills/path/scripts/pipeline_git.py +124 -34
- package/skills/path/scripts/pipeline_state.py +287 -87
- package/skills/path/scripts/promote_lookahead.py +1 -1
- package/skills/path/scripts/review_panel.py +1 -1
- package/skills/path/scripts/state_checkpoint.py +135 -44
- package/skills/path/scripts/state_promote.py +2 -0
- package/skills/path/scripts/status_runtime.py +58 -10
- package/skills/path/scripts/task_context.py +12 -3
- package/skills/path/scripts/token_budget.py +12 -8
- package/skills/path/scripts/workflow_run.py +107 -30
- package/skills/path/scripts/worktree_paths.py +72 -10
- package/skills/path/templates/codebase.md +1 -1
- package/skills/path/templates/docs-audit.md +6 -2
- package/skills/path/templates/final-review.md +16 -4
- package/skills/path/templates/gap-review.md +2 -1
- package/skills/path/templates/intent.md +30 -0
- package/skills/path/templates/patch-findings.md +3 -3
- package/skills/path/templates/plan.md +17 -2
- package/skills/path/templates/research-handoff.md +14 -3
- package/skills/path/templates/state.md +1 -1
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +16 -4
- package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
|
@@ -17,12 +17,15 @@ from datetime import date
|
|
|
17
17
|
from pathlib import Path, PurePosixPath
|
|
18
18
|
from typing import Mapping, Optional, Sequence
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
from isolation import IsolationError, checkpoint as isolation_checkpoint,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if __package__:
|
|
21
|
+
from .isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
|
|
22
|
+
else:
|
|
23
|
+
try:
|
|
24
|
+
from isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
|
|
25
|
+
except ModuleNotFoundError as error: # pragma: no cover - package imports used by tests
|
|
26
|
+
if error.name != "isolation":
|
|
27
|
+
raise
|
|
28
|
+
from scripts.isolation import IsolationError, checkpoint as isolation_checkpoint, PROJECT_ENTRIES
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
if __package__:
|
|
@@ -66,6 +69,11 @@ def _sha256(content: str) -> str:
|
|
|
66
69
|
return hashlib.sha256(content.encode("utf-8")).hexdigest()
|
|
67
70
|
|
|
68
71
|
|
|
72
|
+
def _is_junk_file(path: Path) -> bool:
|
|
73
|
+
# Drift digests skip OS junk by name: Finder rewrites it whatever its ignore status.
|
|
74
|
+
return path.name in pipeline_state._common.OS_JUNK_NAMES and path.is_file() and not path.is_symlink()
|
|
75
|
+
|
|
76
|
+
|
|
69
77
|
def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
70
78
|
if path.is_symlink() or not path.is_dir():
|
|
71
79
|
raise PipelineStateError(f"promotion path must be a real directory: {path}")
|
|
@@ -74,7 +82,7 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
|
74
82
|
if child.is_symlink():
|
|
75
83
|
raise PipelineStateError(f"promotion path contains a symlink: {child}")
|
|
76
84
|
relative = child.relative_to(path).as_posix()
|
|
77
|
-
if PurePosixPath(relative).parts[0] in excluded:
|
|
85
|
+
if PurePosixPath(relative).parts[0] in excluded or _is_junk_file(child):
|
|
78
86
|
continue
|
|
79
87
|
if child.is_dir():
|
|
80
88
|
digest.update(f"d\0{relative}\0".encode())
|
|
@@ -87,15 +95,15 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
|
87
95
|
|
|
88
96
|
|
|
89
97
|
def _checkpoint_artifact_digest(project: Path, mutable_paths: set[str]) -> str:
|
|
90
|
-
"""Hash
|
|
98
|
+
"""Hash approval artifacts except helper-owned metadata and OS junk."""
|
|
91
99
|
digest = hashlib.sha256()
|
|
92
100
|
for child in sorted(project.rglob("*")):
|
|
93
101
|
if child.is_symlink():
|
|
94
102
|
raise PipelineStateError(f"checkpoint path contains a symlink: {child}")
|
|
95
103
|
relative = child.relative_to(project).as_posix()
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
# Finder can rewrite OS junk during approval; it must not cause artifact drift.
|
|
105
|
+
if (relative in mutable_paths or relative.split("/", 1)[0] not in PROJECT_ENTRIES
|
|
106
|
+
or _is_junk_file(child)):
|
|
99
107
|
continue
|
|
100
108
|
if child.is_dir():
|
|
101
109
|
digest.update(f"d\0{relative}\0".encode())
|
|
@@ -333,11 +341,7 @@ def _converge_checkpoint_file(path: Path, before: str, after: str, label: str) -
|
|
|
333
341
|
|
|
334
342
|
def _unlink_checkpoint_journal(path: Path) -> None:
|
|
335
343
|
path.unlink()
|
|
336
|
-
|
|
337
|
-
try:
|
|
338
|
-
os.fsync(descriptor)
|
|
339
|
-
finally:
|
|
340
|
-
os.close(descriptor)
|
|
344
|
+
pipeline_state._common.fsync_directory(path.parent)
|
|
341
345
|
|
|
342
346
|
|
|
343
347
|
def _resume_checkpoint_locked(
|
|
@@ -439,41 +443,85 @@ def _validate_plan_briefs(repo: Path, kind: str, project_dir: str) -> None:
|
|
|
439
443
|
if head.returncode != 0:
|
|
440
444
|
# Pre-Git approval defers base-dependent checks to build.
|
|
441
445
|
return
|
|
446
|
+
if __package__:
|
|
447
|
+
from .check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
|
|
448
|
+
else:
|
|
449
|
+
try:
|
|
450
|
+
from check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
|
|
451
|
+
except ModuleNotFoundError as error: # pragma: no cover - package imports
|
|
452
|
+
if error.name != "check_task_briefs":
|
|
453
|
+
raise
|
|
454
|
+
from scripts.check_task_briefs import BriefError, _member_bases, plan_validation_bases, validate_task_briefs
|
|
455
|
+
if __package__:
|
|
456
|
+
from . import check_handoffs
|
|
457
|
+
else:
|
|
458
|
+
try:
|
|
459
|
+
import check_handoffs
|
|
460
|
+
except ModuleNotFoundError as error:
|
|
461
|
+
if error.name != "check_handoffs":
|
|
462
|
+
raise
|
|
463
|
+
from scripts import check_handoffs
|
|
442
464
|
try:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
from scripts.check_task_briefs import BriefError, validate_task_briefs
|
|
448
|
-
try:
|
|
449
|
-
import check_handoffs
|
|
450
|
-
except ModuleNotFoundError as error:
|
|
451
|
-
if error.name != "check_handoffs":
|
|
452
|
-
raise
|
|
453
|
-
from scripts import check_handoffs
|
|
454
|
-
try:
|
|
455
|
-
tasks, dependency_files = check_handoffs.plan_brief_inputs(repo, project_dir)
|
|
456
|
-
landed_bases = {}
|
|
457
|
-
for task_id, text in tasks.items():
|
|
458
|
-
if check_handoffs._task_scalar(text, task_id, "status") != "done":
|
|
459
|
-
continue
|
|
460
|
-
agent = check_handoffs._task_scalar(text, task_id, "agent")
|
|
461
|
-
if agent in {"", "null"}:
|
|
462
|
-
raise BriefError(f"{task_id} landed task has no recorded agent")
|
|
463
|
-
recorded_base = check_handoffs._task_scalar(text, task_id, "base")
|
|
464
|
-
try:
|
|
465
|
-
landed_bases[task_id] = require_commit(repo, require_full_sha(recorded_base))
|
|
466
|
-
except IsolationError as error:
|
|
467
|
-
raise BriefError(f"{task_id} landed task has invalid historical base: {error}") from error
|
|
468
|
-
dependency_files[task_id] = set()
|
|
465
|
+
member_base = _member_bases(repo)
|
|
466
|
+
tasks, dependency_files, landed_bases = plan_validation_bases(
|
|
467
|
+
repo, project_dir, member_base, initial=True
|
|
468
|
+
)
|
|
469
469
|
validate_task_briefs(
|
|
470
470
|
repo, head.stdout.strip(), f"{project_dir}/tasks",
|
|
471
471
|
dependency_files=dependency_files, landed_bases=landed_bases,
|
|
472
|
+
member_base=member_base,
|
|
472
473
|
)
|
|
474
|
+
if project_dir == ".project/next":
|
|
475
|
+
# Promotion checks lookahead member tasks from the bases their briefs were checked at.
|
|
476
|
+
named = {
|
|
477
|
+
str(check_handoffs._strict_frontmatter(text, task_id).get("repo"))
|
|
478
|
+
for task_id, text in tasks.items()
|
|
479
|
+
if check_handoffs._strict_frontmatter(text, task_id).get("repo")
|
|
480
|
+
and check_handoffs._task_scalar(text, task_id, "status") != "done"
|
|
481
|
+
}
|
|
482
|
+
if named:
|
|
483
|
+
bases = {name: member_base(name)[1] for name in sorted(named)}
|
|
484
|
+
milestone = pipeline_state.load_state(repo, project_dir)[0].milestone
|
|
485
|
+
path = _lookahead_member_bases_path(repo, str(milestone))
|
|
486
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
487
|
+
pipeline_state._common.atomic_write(path, json.dumps(
|
|
488
|
+
{"schema": LOOKAHEAD_MEMBER_BASES_SCHEMA, "milestone": milestone, "bases": bases},
|
|
489
|
+
indent=2, sort_keys=True) + "\n")
|
|
473
490
|
except (BriefError, check_handoffs.HandoffError) as error:
|
|
474
491
|
raise PipelineStateError(f"task brief validation failed: {error}") from error
|
|
475
492
|
|
|
476
493
|
|
|
494
|
+
LOOKAHEAD_MEMBER_BASES_SCHEMA = "gsd-path/lookahead-member-bases/v1"
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
def _lookahead_member_bases_path(repo: Path, milestone: str) -> Path:
|
|
498
|
+
common = pipeline_state._run_git(repo, "rev-parse", "--path-format=absolute", "--git-common-dir").stdout.strip()
|
|
499
|
+
return Path(common) / "gsd-path" / "lookahead-member-bases" / f"{milestone}.json"
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def _lookahead_member_bases(repo: Path, milestone: str) -> Optional[dict]:
|
|
503
|
+
path = _lookahead_member_bases_path(repo, milestone)
|
|
504
|
+
if not path.is_file():
|
|
505
|
+
return None
|
|
506
|
+
value = json.loads(path.read_text(encoding="utf-8"))
|
|
507
|
+
if value.get("schema") != LOOKAHEAD_MEMBER_BASES_SCHEMA or value.get("milestone") != milestone:
|
|
508
|
+
return None
|
|
509
|
+
return value.get("bases")
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def _shipped_member_merges(repo: Path, landing: str) -> dict:
|
|
513
|
+
"""Member merges named by the ship commit the integration landing merged."""
|
|
514
|
+
if __package__:
|
|
515
|
+
from .pipeline_git import ship_member_rows
|
|
516
|
+
else:
|
|
517
|
+
from pipeline_git import ship_member_rows
|
|
518
|
+
ship = pipeline_state._run_git(repo, "rev-parse", "--verify", "--quiet", f"{landing}^2", check=False)
|
|
519
|
+
if ship.returncode != 0:
|
|
520
|
+
return {}
|
|
521
|
+
message = pipeline_state._run_git(repo, "show", "-s", "--format=%B", ship.stdout.strip()).stdout
|
|
522
|
+
return {row["name"]: row["merge"] for row in ship_member_rows(message)}
|
|
523
|
+
|
|
524
|
+
|
|
477
525
|
def checkpoint_approval(
|
|
478
526
|
repo: Path,
|
|
479
527
|
kind: str,
|
|
@@ -1027,6 +1075,46 @@ def _classify_plan_drift(
|
|
|
1027
1075
|
}
|
|
1028
1076
|
approved = _approved_task_contracts(repo, checkpoint)
|
|
1029
1077
|
current = _task_contracts_at(repo, revision)
|
|
1078
|
+
if __package__:
|
|
1079
|
+
from . import check_handoffs
|
|
1080
|
+
else:
|
|
1081
|
+
import check_handoffs
|
|
1082
|
+
# Member task paths live in member repos: compare each member from the base its brief
|
|
1083
|
+
# was checked at to the member merge the shipped milestone made (both fixed commits).
|
|
1084
|
+
task_repos = {
|
|
1085
|
+
task_id: str(check_handoffs._strict_frontmatter(contract.text, contract.path).get("repo") or "")
|
|
1086
|
+
for task_id, contract in approved.items()
|
|
1087
|
+
}
|
|
1088
|
+
active_member_tasks = {
|
|
1089
|
+
task_id for task_id, name in task_repos.items()
|
|
1090
|
+
if name and check_handoffs._task_scalar(approved[task_id].text, task_id, "status") != "done"
|
|
1091
|
+
}
|
|
1092
|
+
active_members = {task_repos[task_id] for task_id in active_member_tasks}
|
|
1093
|
+
member_changes: dict[str, list] = {}
|
|
1094
|
+
if active_members:
|
|
1095
|
+
bases = _lookahead_member_bases(repo, str(state.milestone)) or {}
|
|
1096
|
+
if any(name not in bases for name in active_members):
|
|
1097
|
+
return {
|
|
1098
|
+
"class": "unverifiable",
|
|
1099
|
+
"checkpoint": checkpoint,
|
|
1100
|
+
"task_ids": [],
|
|
1101
|
+
"changed_paths": [],
|
|
1102
|
+
"contract_paths": [],
|
|
1103
|
+
"member_tasks": True,
|
|
1104
|
+
"reason": "member bases were not recorded at plan approval",
|
|
1105
|
+
}
|
|
1106
|
+
if __package__:
|
|
1107
|
+
from . import members
|
|
1108
|
+
else:
|
|
1109
|
+
import members
|
|
1110
|
+
checkouts = {item["name"]: Path(item["checkout"]) for item in members.read_members(repo)}
|
|
1111
|
+
merges = _shipped_member_merges(repo, landing or revision)
|
|
1112
|
+
for name in active_members:
|
|
1113
|
+
member_changes[name] = [
|
|
1114
|
+
item for item in pipeline_state._run_git(
|
|
1115
|
+
checkouts[name], "diff", "--no-renames", "--name-only", "-z", bases[name], merges[name]
|
|
1116
|
+
).stdout.split("\0") if item
|
|
1117
|
+
] if name in merges else []
|
|
1030
1118
|
|
|
1031
1119
|
contract_paths: set[str] = set()
|
|
1032
1120
|
flagged_ids: set[str] = set()
|
|
@@ -1050,9 +1138,12 @@ def _classify_plan_drift(
|
|
|
1050
1138
|
|
|
1051
1139
|
product_paths: set[str] = set()
|
|
1052
1140
|
for task_id, contract in approved.items():
|
|
1141
|
+
member = task_repos.get(task_id)
|
|
1142
|
+
if member and task_id not in active_member_tasks:
|
|
1143
|
+
continue
|
|
1053
1144
|
matches = sorted(
|
|
1054
|
-
changed_path
|
|
1055
|
-
for changed_path in changed
|
|
1145
|
+
(f"{member}:{changed_path}" if member else changed_path)
|
|
1146
|
+
for changed_path in (member_changes[member] if member else changed)
|
|
1056
1147
|
if any(
|
|
1057
1148
|
changed_path == path
|
|
1058
1149
|
or changed_path.startswith(f"{path.rstrip('/')}/")
|
|
@@ -82,6 +82,8 @@ def _promotion_event(
|
|
|
82
82
|
if isinstance(task_ids, list) and task_ids:
|
|
83
83
|
return f"{prefix}; plan drift flagged tasks {', '.join(task_ids)}"
|
|
84
84
|
return f"{prefix}; plan contract changed after approval"
|
|
85
|
+
if drift_class == "unverifiable" and drift.get("member_tasks"):
|
|
86
|
+
return f"{prefix}; plan drift unverifiable because member bases were not recorded at plan approval"
|
|
85
87
|
if drift_class == "unverifiable":
|
|
86
88
|
return f"{prefix}; plan drift unverifiable because approval checkpoint is missing"
|
|
87
89
|
return prefix
|
|
@@ -13,10 +13,34 @@ import os
|
|
|
13
13
|
import tempfile
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
import _common
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
if __package__:
|
|
17
|
+
from . import _common
|
|
18
|
+
else:
|
|
19
|
+
try:
|
|
20
|
+
import _common
|
|
21
|
+
except ImportError:
|
|
22
|
+
from scripts import _common
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _worktree_list_porcelain(primary: Path) -> tuple[str, bool]:
|
|
26
|
+
try:
|
|
27
|
+
if __package__:
|
|
28
|
+
from . import pipeline_git as pg
|
|
29
|
+
else:
|
|
30
|
+
from scripts import pipeline_git as pg
|
|
31
|
+
except ImportError:
|
|
32
|
+
try:
|
|
33
|
+
import pipeline_git as pg
|
|
34
|
+
except ImportError:
|
|
35
|
+
pg = None
|
|
36
|
+
if pg is not None:
|
|
37
|
+
return pg.worktree_list_porcelain(primary)
|
|
38
|
+
try:
|
|
39
|
+
output = _git(primary, "worktree", "list", "--porcelain", "-z")
|
|
40
|
+
return output, True
|
|
41
|
+
except ValueError:
|
|
42
|
+
output = _git(primary, "worktree", "list", "--porcelain")
|
|
43
|
+
return output, False
|
|
20
44
|
|
|
21
45
|
|
|
22
46
|
def _git(primary: Path, *args: str) -> str:
|
|
@@ -27,7 +51,10 @@ def _git(primary: Path, *args: str) -> str:
|
|
|
27
51
|
|
|
28
52
|
|
|
29
53
|
def _identity(path: Path) -> str:
|
|
30
|
-
|
|
54
|
+
digest = hashlib.sha256(os.fsencode(path)).hexdigest()
|
|
55
|
+
# Two identities nest in every managed path; full digests would use about
|
|
56
|
+
# 130 of Windows' 260-character MAX_PATH before any repository content.
|
|
57
|
+
return digest[:16] if os.name == "nt" else digest
|
|
31
58
|
|
|
32
59
|
|
|
33
60
|
def _workspace(primary: Path, pin: bool) -> Path:
|
|
@@ -65,7 +92,7 @@ def _workspace(primary: Path, pin: bool) -> Path:
|
|
|
65
92
|
receipt.parent.mkdir(parents=True, exist_ok=True)
|
|
66
93
|
fd, temporary = tempfile.mkstemp(dir=receipt.parent)
|
|
67
94
|
try:
|
|
68
|
-
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
95
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as handle:
|
|
69
96
|
json.dump({"primary": str(primary), "root": str(workspace)}, handle)
|
|
70
97
|
try:
|
|
71
98
|
os.link(temporary, receipt)
|
|
@@ -76,17 +103,52 @@ def _workspace(primary: Path, pin: bool) -> Path:
|
|
|
76
103
|
return workspace
|
|
77
104
|
|
|
78
105
|
|
|
106
|
+
def release_workspace(primary: Path) -> bool:
|
|
107
|
+
"""Forget the pinned placement receipt once no linked worktrees remain.
|
|
108
|
+
|
|
109
|
+
Lets GSD_PATH_WORKTREE_ROOT (or a new default) apply again at the next
|
|
110
|
+
milestone's first allocation. Returns True when a receipt was removed;
|
|
111
|
+
any remaining linked worktree (including one only still registered) keeps
|
|
112
|
+
the pin.
|
|
113
|
+
"""
|
|
114
|
+
primary = primary.resolve()
|
|
115
|
+
common = Path(_git(primary, "rev-parse", "--git-common-dir"))
|
|
116
|
+
common = (primary / common).resolve()
|
|
117
|
+
receipt = common / "gsd-path" / "workspaces" / f"{_identity(primary)}.json"
|
|
118
|
+
if not receipt.is_file():
|
|
119
|
+
return False
|
|
120
|
+
output, nul_separated = _worktree_list_porcelain(primary)
|
|
121
|
+
records = output.split("\0\0") if nul_separated else [
|
|
122
|
+
block for block in output.strip().split("\n\n") if block.strip()
|
|
123
|
+
]
|
|
124
|
+
for record in records:
|
|
125
|
+
fields = record.split("\0") if nul_separated else record.splitlines()
|
|
126
|
+
for field in fields:
|
|
127
|
+
if field.startswith("worktree ") and Path(field[len("worktree "):]).resolve() != primary:
|
|
128
|
+
return False
|
|
129
|
+
receipt.unlink()
|
|
130
|
+
return True
|
|
131
|
+
|
|
132
|
+
|
|
79
133
|
def worktree_path(primary: Path, kind: str, name: str, *, pin: bool = False) -> Path:
|
|
80
134
|
primary = primary.resolve()
|
|
81
|
-
if kind not in {"task", "verify", "integrate"} or not name or Path(name).name != name or name in {".", ".."}:
|
|
135
|
+
if kind not in {"task", "verify", "integrate", "bound"} or not name or Path(name).name != name or name in {".", ".."}:
|
|
82
136
|
raise ValueError("invalid managed worktree kind or name")
|
|
137
|
+
if kind == "bound":
|
|
138
|
+
return _workspace(primary, pin) / kind / name
|
|
83
139
|
legacy = (primary.parent / f".{primary.name}-gsd-path-integrate-{name}"
|
|
84
140
|
if kind == "integrate" else primary.parent / f"{primary.name}.gsd-path" / kind / name)
|
|
85
141
|
branch = f"refs/heads/gsd-path-{kind}/{name}"
|
|
86
|
-
|
|
142
|
+
output, nul_separated = _worktree_list_porcelain(primary)
|
|
143
|
+
if nul_separated:
|
|
144
|
+
records = output.split("\0\0")
|
|
145
|
+
else:
|
|
146
|
+
records = [block for block in output.strip().split("\n\n") if block.strip()]
|
|
87
147
|
for record in records:
|
|
88
|
-
fields = record.split("\0")
|
|
89
|
-
|
|
148
|
+
fields = record.split("\0") if nul_separated else record.splitlines()
|
|
149
|
+
# Compare as paths: git prints forward slashes on Windows.
|
|
150
|
+
worktrees = [Path(field[len("worktree "):]) for field in fields if field.startswith("worktree ")]
|
|
151
|
+
if legacy in worktrees and f"branch {branch}" in fields:
|
|
90
152
|
return legacy
|
|
91
153
|
# Keep collision checks and missing-directory recovery at the old location.
|
|
92
154
|
if os.path.lexists(legacy):
|
|
@@ -3,7 +3,8 @@ name: gsd-path-ship
|
|
|
3
3
|
description: Verify a completed GSD Path milestone, manage evidence-backed patch decisions, request final shipping approval, and archive the validated result. Use only when the user explicitly invokes $gsd-path-ship or an active $gsd-path router or build orchestrator explicitly routes to this phase.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Before executing project helpers, read [runtime selection](references/runtime-selection.md)
|
|
6
|
+
Before executing project helpers, read [runtime selection](references/runtime-selection.md)
|
|
7
|
+
and [operating rules](references/operating-rules.md).
|
|
7
8
|
|
|
8
9
|
# GSD Path Ship Phase
|
|
9
10
|
|
|
@@ -82,10 +83,13 @@ so the position is unchanged. Then:
|
|
|
82
83
|
This owns pending-discussion and landing checks, project Verify isolation,
|
|
83
84
|
execution, output recording, collection, cleanup, and final-review reuse.
|
|
84
85
|
Keep its JSON receipt; do not reconstruct those operations in shell calls.
|
|
85
|
-
|
|
86
|
-
`final-gap-1.md` is the generated view
|
|
87
|
-
|
|
88
|
-
and
|
|
86
|
+
For a single-repo milestone, exact stdout/stderr live once in
|
|
87
|
+
`.project/build/verify-ledger.jsonl`; `final-gap-1.md` is the generated view
|
|
88
|
+
referencing that entry. For a member milestone, the gap records each member
|
|
89
|
+
head and holds the exact output; there is no reusable ledger entry.
|
|
90
|
+
Single-repo re-entry at the same command and commit reuses the execution,
|
|
91
|
+
including a failed one, and finishes interrupted collection without running
|
|
92
|
+
the command again.
|
|
89
93
|
Missing legacy output requires evidence reconciliation, not a blind rerun.
|
|
90
94
|
Any non-zero result stops this step; preserve its stderr and diagnose through
|
|
91
95
|
the bundled forensics contract. Do not launch reviewers while project Verify
|
|
@@ -121,9 +125,10 @@ so the position is unchanged. Then:
|
|
|
121
125
|
step 3 or create a fresh sidecar with `isolate-verify --name review-final`
|
|
122
126
|
and dispatch the integration reviewer under logical task name
|
|
123
127
|
`review_final`, assigning only
|
|
124
|
-
`.project/review/FINAL.md`. Its complete brief includes the
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
`.project/review/FINAL.md`. Its complete brief includes the project Verify
|
|
129
|
+
evidence from the ledger or the member milestone's gap output, every
|
|
130
|
+
collected gap verdict so Overall verdict is consistent with them, and
|
|
131
|
+
PLAN.md's `## Surface contract` when INTENT.md
|
|
127
132
|
names surfaces — that reviewer performs each Walkthrough and records the
|
|
128
133
|
surface and what it showed on every criterion the contract lists. Collect FINAL.md and retire its sidecar through the
|
|
129
134
|
same helper flow.
|
|
@@ -154,7 +159,12 @@ so the position is unchanged. Then:
|
|
|
154
159
|
then stop and do not invent a patch finding. A `not-met`,
|
|
155
160
|
`unverifiable`, or blocked gap with valid evidence sets `ship/blocked`,
|
|
156
161
|
writes `.project/review/PATCH-FINDINGS.md` from the patch-findings template,
|
|
157
|
-
|
|
162
|
+
copying the full `Risk: ...` line into each gap finding's Locator, its
|
|
163
|
+
`Found` field into Evidence, and its `Fix direction` field verbatim. For a
|
|
164
|
+
`FINAL.md` finding, use its `SC<n>` id as Locator and copy its `Finding` and
|
|
165
|
+
`Fix direction` fields verbatim. The patch validator requires these source
|
|
166
|
+
field values to match exactly; do not shorten or paraphrase them. Run
|
|
167
|
+
`python3 <absolute check_handoffs.py> patch --repo <absolute repo
|
|
158
168
|
root>`. Present the blocked outcome, link the resolved absolute
|
|
159
169
|
PATCH-FINDINGS.md path, and state that patch planning is next. The manifest
|
|
160
170
|
contains exactly those FINAL.md and gap rows. When routed by an active
|
|
@@ -253,6 +263,14 @@ The persisted `STATE.archive` field is the transaction identity.
|
|
|
253
263
|
at the current HEAD is the only artifact-producing remedy. The archive helper independently binds every FINAL.md
|
|
254
264
|
`SCn` heading id and normalized text to the archived INTENT.md; a renamed or
|
|
255
265
|
easier criterion blocks even if the earlier handoff gate was bypassed.
|
|
266
|
+
For a multi-repo milestone (the archive holds `build/members.json`), run
|
|
267
|
+
`python3 <absolute archive_milestone.py> close-members --repo <root>`
|
|
268
|
+
after preflight passes and before recording shipment. It closes each
|
|
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
|
|
271
|
+
link, stop, and rerun the same command after the user merges it; never
|
|
272
|
+
merge a member PR yourself. When it returns `integrated`, keep its `body`
|
|
273
|
+
for the ship commit below.
|
|
256
274
|
5. Only after preflight passes, record shipment through the journaled helper;
|
|
257
275
|
for a program it atomically replaces both ROADMAP.md and STATE.md, setting
|
|
258
276
|
the current entry to `Status: shipped` with the exact `Archive:` pointer:
|
|
@@ -270,10 +288,14 @@ The persisted `STATE.archive` field is the transaction identity.
|
|
|
270
288
|
idempotent after completion. Stage only
|
|
271
289
|
`.project/` paths, inspect the staged path list against the transaction and
|
|
272
290
|
create the ship phase's one commit with exact subject
|
|
273
|
-
`ship: M00N — <milestone-slug
|
|
291
|
+
`ship: M00N — <milestone-slug>`. For a single-repo milestone, its body has
|
|
292
|
+
exactly two consecutive lines,
|
|
274
293
|
`Archive: .project/archive/<NNN>-<slug>` then
|
|
275
294
|
`Reviewed-HEAD: <reviewed SHA>`, with no comment lines or blank line between them.
|
|
276
|
-
|
|
295
|
+
A multi-repo milestone's body is exactly the `body` that `close-members`
|
|
296
|
+
returned: those two lines, then one `Member-Reviewed-HEAD:` and one
|
|
297
|
+
`Member:` line per member.
|
|
298
|
+
Write the subject, a blank line, and the body lines to a message file,
|
|
277
299
|
then use `git commit -F <message-file>`. M00N and NNN come from STATE.archive.
|
|
278
300
|
There is no untracked-project exception and no product or older-archive
|
|
279
301
|
path may enter this commit.
|
|
@@ -44,6 +44,19 @@ use exactly one matching branch:
|
|
|
44
44
|
create another worktree. Encode task dependencies explicitly; launch
|
|
45
45
|
independent children concurrently up to the host's advertised
|
|
46
46
|
concurrent-subagent capacity.
|
|
47
|
+
- A `muse.subagent_spawn` tool (with `muse.subagent_wait`,
|
|
48
|
+
`muse.subagent_read_result`, and `muse.subagent_send_message` siblings) is
|
|
49
|
+
Muse Code. Omit `subagent_type` (general-purpose, full capability), pass the
|
|
50
|
+
logical task name as `task_name` and `role`, and the complete brief as
|
|
51
|
+
`objective`. Never set `worktree_isolation`. Keep the returned
|
|
52
|
+
`subagent_id`; send a correction to a still-live child with
|
|
53
|
+
`muse.subagent_send_message` mode `followup` and the complete new prompt,
|
|
54
|
+
otherwise start a fresh child. Collect with `muse.subagent_wait`
|
|
55
|
+
(`wait_for: task_terminal`) then `muse.subagent_read_result`; on
|
|
56
|
+
`root_capacity_exhausted`, wait for a child to finish and retry. Spawn has no
|
|
57
|
+
model or effort argument, so record no such capability. If only
|
|
58
|
+
`muse.workflow` is exposed (untrusted workspace), do not script or inline
|
|
59
|
+
the work; stop and report that the workspace must be trusted.
|
|
47
60
|
|
|
48
61
|
For every branch:
|
|
49
62
|
|