@hunter-harness/workflow-harness 0.2.85 → 0.3.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/harness/bundles/general/claude-code/.harness-build.json +1 -1
- package/harness/bundles/general/claude-code/contracts/workflow-policy.json +46 -17
- package/harness/bundles/general/claude-code/harness-archive/SKILL.md +2 -2
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/general/claude-code/harness-execute/SKILL.md +189 -0
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +10 -9
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +19 -91
- package/harness/bundles/general/claude-code/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/claude-code/harness-plan/reference.md +74 -83
- package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/claude-code/harness-review/protocols.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +13 -5
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +2 -2
- package/harness/bundles/general/claude-code/harness-submit/checklist.md +1 -1
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +11 -2
- package/harness/bundles/general/claude-code/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +23 -14
- package/harness/bundles/general/claude-code/scripts/harness_change.py +25 -7
- package/harness/bundles/general/claude-code/scripts/harness_context.py +154 -60
- package/harness/bundles/general/claude-code/scripts/harness_events.py +1 -1
- package/harness/bundles/general/claude-code/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/general/claude-code/scripts/harness_fixback.py +14 -10
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +293 -90
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +47 -2
- package/harness/bundles/general/claude-code/scripts/harness_paths.py +175 -0
- package/harness/bundles/general/claude-code/scripts/harness_phase.py +65 -23
- package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/general/claude-code/scripts/harness_review.py +25 -4
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/contracts/workflow-policy.json +46 -17
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +2 -2
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/general/codebuddy/harness-execute/SKILL.md +170 -0
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +10 -9
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +19 -91
- package/harness/bundles/general/codebuddy/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +74 -83
- package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/codebuddy/harness-review/protocols.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +13 -5
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +2 -2
- package/harness/bundles/general/codebuddy/harness-submit/checklist.md +1 -1
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +11 -2
- package/harness/bundles/general/codebuddy/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +23 -14
- package/harness/bundles/general/codebuddy/scripts/harness_change.py +25 -7
- package/harness/bundles/general/codebuddy/scripts/harness_context.py +154 -60
- package/harness/bundles/general/codebuddy/scripts/harness_events.py +1 -1
- package/harness/bundles/general/codebuddy/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +14 -10
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +293 -90
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +47 -2
- package/harness/bundles/general/codebuddy/scripts/harness_paths.py +175 -0
- package/harness/bundles/general/codebuddy/scripts/harness_phase.py +65 -23
- package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/general/codebuddy/scripts/harness_review.py +25 -4
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/contracts/workflow-policy.json +46 -17
- package/harness/bundles/general/codex/harness-archive/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-execute/SKILL.md +170 -0
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-plan/SKILL.md +10 -9
- package/harness/bundles/general/codex/harness-plan/checklist.md +19 -91
- package/harness/bundles/general/codex/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/codex/harness-plan/reference.md +74 -83
- package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/codex/harness-review/protocols.md +1 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +13 -5
- package/harness/bundles/general/codex/harness-submit/SKILL.md +2 -2
- package/harness/bundles/general/codex/harness-submit/checklist.md +1 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +11 -2
- package/harness/bundles/general/codex/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/general/codex/scripts/harness_archive.py +23 -14
- package/harness/bundles/general/codex/scripts/harness_change.py +25 -7
- package/harness/bundles/general/codex/scripts/harness_context.py +154 -60
- package/harness/bundles/general/codex/scripts/harness_events.py +1 -1
- package/harness/bundles/general/codex/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/general/codex/scripts/harness_fixback.py +14 -10
- package/harness/bundles/general/codex/scripts/harness_gate.py +293 -90
- package/harness/bundles/general/codex/scripts/harness_ledger.py +47 -2
- package/harness/bundles/general/codex/scripts/harness_paths.py +175 -0
- package/harness/bundles/general/codex/scripts/harness_phase.py +65 -23
- package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/general/codex/scripts/harness_review.py +25 -4
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/contracts/workflow-policy.json +46 -17
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-execute/SKILL.md +170 -0
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +10 -9
- package/harness/bundles/general/cursor/harness-plan/checklist.md +19 -91
- package/harness/bundles/general/cursor/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/cursor/harness-plan/reference.md +74 -83
- package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-review/SKILL.md +3 -3
- package/harness/bundles/general/cursor/harness-review/protocols.md +1 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +13 -5
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +2 -2
- package/harness/bundles/general/cursor/harness-submit/checklist.md +1 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +11 -2
- package/harness/bundles/general/cursor/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/general/cursor/scripts/harness_archive.py +23 -14
- package/harness/bundles/general/cursor/scripts/harness_change.py +25 -7
- package/harness/bundles/general/cursor/scripts/harness_context.py +154 -60
- package/harness/bundles/general/cursor/scripts/harness_events.py +1 -1
- package/harness/bundles/general/cursor/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/general/cursor/scripts/harness_fixback.py +14 -10
- package/harness/bundles/general/cursor/scripts/harness_gate.py +293 -90
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +47 -2
- package/harness/bundles/general/cursor/scripts/harness_paths.py +175 -0
- package/harness/bundles/general/cursor/scripts/harness_phase.py +65 -23
- package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/general/cursor/scripts/harness_review.py +25 -4
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/contracts/workflow-policy.json +46 -17
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-execute/SKILL.md +189 -0
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +10 -9
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +19 -91
- package/harness/bundles/java/claude-code/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/claude-code/harness-plan/reference.md +74 -83
- package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/claude-code/harness-review/protocols.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +13 -5
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +2 -2
- package/harness/bundles/java/claude-code/harness-submit/checklist.md +1 -1
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +11 -2
- package/harness/bundles/java/claude-code/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +23 -14
- package/harness/bundles/java/claude-code/scripts/harness_change.py +25 -7
- package/harness/bundles/java/claude-code/scripts/harness_context.py +154 -60
- package/harness/bundles/java/claude-code/scripts/harness_events.py +1 -1
- package/harness/bundles/java/claude-code/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/java/claude-code/scripts/harness_fixback.py +14 -10
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +293 -90
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +47 -2
- package/harness/bundles/java/claude-code/scripts/harness_paths.py +175 -0
- package/harness/bundles/java/claude-code/scripts/harness_phase.py +65 -23
- package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/java/claude-code/scripts/harness_review.py +25 -4
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/contracts/workflow-policy.json +46 -17
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-execute/SKILL.md +170 -0
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +10 -9
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +19 -91
- package/harness/bundles/java/codebuddy/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +74 -83
- package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/codebuddy/harness-review/protocols.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +13 -5
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +2 -2
- package/harness/bundles/java/codebuddy/harness-submit/checklist.md +1 -1
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +11 -2
- package/harness/bundles/java/codebuddy/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +23 -14
- package/harness/bundles/java/codebuddy/scripts/harness_change.py +25 -7
- package/harness/bundles/java/codebuddy/scripts/harness_context.py +154 -60
- package/harness/bundles/java/codebuddy/scripts/harness_events.py +1 -1
- package/harness/bundles/java/codebuddy/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +14 -10
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +293 -90
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +47 -2
- package/harness/bundles/java/codebuddy/scripts/harness_paths.py +175 -0
- package/harness/bundles/java/codebuddy/scripts/harness_phase.py +65 -23
- package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/java/codebuddy/scripts/harness_review.py +25 -4
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/contracts/workflow-policy.json +46 -17
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-archive/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-execute/SKILL.md +170 -0
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-package/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-plan/SKILL.md +10 -9
- package/harness/bundles/java/codex/harness-plan/checklist.md +19 -91
- package/harness/bundles/java/codex/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/codex/harness-plan/reference.md +74 -83
- package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/codex/harness-review/protocols.md +1 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +13 -5
- package/harness/bundles/java/codex/harness-submit/SKILL.md +2 -2
- package/harness/bundles/java/codex/harness-submit/checklist.md +1 -1
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +11 -2
- package/harness/bundles/java/codex/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/java/codex/scripts/harness_archive.py +23 -14
- package/harness/bundles/java/codex/scripts/harness_change.py +25 -7
- package/harness/bundles/java/codex/scripts/harness_context.py +154 -60
- package/harness/bundles/java/codex/scripts/harness_events.py +1 -1
- package/harness/bundles/java/codex/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/java/codex/scripts/harness_fixback.py +14 -10
- package/harness/bundles/java/codex/scripts/harness_gate.py +293 -90
- package/harness/bundles/java/codex/scripts/harness_ledger.py +47 -2
- package/harness/bundles/java/codex/scripts/harness_paths.py +175 -0
- package/harness/bundles/java/codex/scripts/harness_phase.py +65 -23
- package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/java/codex/scripts/harness_review.py +25 -4
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/contracts/workflow-policy.json +46 -17
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-execute/SKILL.md +170 -0
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-package/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +10 -9
- package/harness/bundles/java/cursor/harness-plan/checklist.md +19 -91
- package/harness/bundles/java/cursor/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/cursor/harness-plan/reference.md +74 -83
- package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-review/SKILL.md +3 -3
- package/harness/bundles/java/cursor/harness-review/protocols.md +1 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +13 -5
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +2 -2
- package/harness/bundles/java/cursor/harness-submit/checklist.md +1 -1
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +11 -2
- package/harness/bundles/java/cursor/scripts/harness_adoption_metrics.py +391 -0
- package/harness/bundles/java/cursor/scripts/harness_archive.py +23 -14
- package/harness/bundles/java/cursor/scripts/harness_change.py +25 -7
- package/harness/bundles/java/cursor/scripts/harness_context.py +154 -60
- package/harness/bundles/java/cursor/scripts/harness_events.py +1 -1
- package/harness/bundles/java/cursor/scripts/harness_events_sync.py +1 -0
- package/harness/bundles/java/cursor/scripts/harness_fixback.py +14 -10
- package/harness/bundles/java/cursor/scripts/harness_gate.py +293 -90
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +47 -2
- package/harness/bundles/java/cursor/scripts/harness_paths.py +175 -0
- package/harness/bundles/java/cursor/scripts/harness_phase.py +65 -23
- package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +140 -874
- package/harness/bundles/java/cursor/scripts/harness_review.py +25 -4
- package/harness/manifests/general/claude-code.json +40 -32
- package/harness/manifests/general/codebuddy.json +40 -32
- package/harness/manifests/general/codex.json +40 -32
- package/harness/manifests/general/cursor.json +40 -32
- package/harness/manifests/java/claude-code.json +42 -34
- package/harness/manifests/java/codebuddy.json +42 -34
- package/harness/manifests/java/codex.json +42 -34
- package/harness/manifests/java/cursor.json +42 -34
- package/hunter-workflow-family.json +4 -4
- package/package.json +1 -1
|
@@ -21,27 +21,18 @@ if str(SCRIPTS_DIR) not in sys.path:
|
|
|
21
21
|
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
22
22
|
|
|
23
23
|
import harness_ledger as hl # noqa: E402
|
|
24
|
+
import harness_paths as hpaths # noqa: E402
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
PHASE_GRAPH = {
|
|
27
|
-
"plan": ("
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"review": ("submit", "run"),
|
|
28
|
+
"plan": ("execute",),
|
|
29
|
+
"execute": ("review", "execute"),
|
|
30
|
+
"review": ("submit", "execute"),
|
|
31
31
|
"submit": (),
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"run",
|
|
37
|
-
"test",
|
|
38
|
-
"review",
|
|
39
|
-
"package",
|
|
40
|
-
"apidoc",
|
|
41
|
-
"submit",
|
|
42
|
-
"merge",
|
|
43
|
-
"archive",
|
|
44
|
-
)
|
|
34
|
+
# 唯一权威清单在 harness_paths(叶子模块,harness_phase 引的是同一个对象)。
|
|
35
|
+
WORKFLOW_PHASES = hpaths.WORKFLOW_PHASES
|
|
45
36
|
|
|
46
37
|
DISPLAY_TITLE_MAX_LENGTH = 80
|
|
47
38
|
|
|
@@ -270,13 +261,26 @@ def _contract(project: Path, change: str) -> tuple[Path, dict[str, Any], Path]:
|
|
|
270
261
|
|
|
271
262
|
|
|
272
263
|
def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
264
|
+
"""读出阶段计划;无法采信时说明原因,而不是悄悄退成 legacy。
|
|
265
|
+
|
|
266
|
+
以前这里遇到未知阶段名一律返回 (None, "legacy"):阶段计划整个失效,
|
|
267
|
+
`_allowed_next_phases` 退回硬编码的 PHASE_GRAPH,而调用方看不出发生过这件事。
|
|
268
|
+
未知阶段名不是假想问题——阶段清单少一个 merge 时,worktree 变更的
|
|
269
|
+
plannedPhases 就会带着 merge 走到这里。
|
|
270
|
+
|
|
271
|
+
未知名先过 LEGACY_PHASE_ALIASES 读时映射(阶段改名后历史 change 靠它继续可读),
|
|
272
|
+
仍然解析不了才降级,并把原因与具体阶段名带在 source 里。
|
|
273
|
+
|
|
274
|
+
权威切换(2026-08):v2 发布快照(plan-profile.json)优先,classify 工作
|
|
275
|
+
副本回退——发布后的阶段计划以已审批快照为准。
|
|
276
|
+
"""
|
|
277
|
+
loaded = hpaths.load_change_gate_policy(contract_root)
|
|
278
|
+
policy = loaded.get("policy")
|
|
279
|
+
if policy is None:
|
|
280
|
+
if loaded.get("working_error"):
|
|
281
|
+
return None, "legacy:policy-unreadable"
|
|
279
282
|
return None, "legacy"
|
|
283
|
+
unknown: list[str] = []
|
|
280
284
|
for field, source in (
|
|
281
285
|
("plannedPhases", "change"),
|
|
282
286
|
("defaultPhases", "policy-default"),
|
|
@@ -285,25 +289,31 @@ def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
|
285
289
|
if not isinstance(raw, list):
|
|
286
290
|
continue
|
|
287
291
|
phases = [str(item).strip() for item in raw if str(item).strip()]
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
if not phases or len(phases) != len(set(phases)):
|
|
293
|
+
continue
|
|
294
|
+
resolved = [hpaths.resolve_phase_name(item) for item in phases]
|
|
295
|
+
missing = [item for item, hit in zip(phases, resolved) if hit is None]
|
|
296
|
+
if missing:
|
|
297
|
+
unknown.extend(missing)
|
|
298
|
+
continue
|
|
299
|
+
# 映射后可能出现重复(两个旧名合并成同一个新阶段),保序去重。
|
|
300
|
+
return list(dict.fromkeys(str(item) for item in resolved)), source
|
|
301
|
+
if unknown:
|
|
302
|
+
return None, "legacy:unknown-phases=" + ",".join(dict.fromkeys(unknown))
|
|
294
303
|
return None, "legacy"
|
|
295
304
|
|
|
296
305
|
|
|
297
306
|
def _allowed_next_phases(contract_root: Path, from_phase: str) -> list[str]:
|
|
298
307
|
planned, _source = _phase_plan(contract_root)
|
|
308
|
+
resolved_from = hpaths.resolve_phase_name(from_phase) or from_phase
|
|
299
309
|
if planned is None:
|
|
300
|
-
return list(PHASE_GRAPH.get(
|
|
301
|
-
if
|
|
310
|
+
return list(PHASE_GRAPH.get(resolved_from, ()))
|
|
311
|
+
if resolved_from not in planned:
|
|
302
312
|
return []
|
|
303
|
-
index = planned.index(
|
|
313
|
+
index = planned.index(resolved_from)
|
|
304
314
|
allowed = planned[index + 1 : index + 2]
|
|
305
|
-
if
|
|
306
|
-
allowed = [*allowed, "
|
|
315
|
+
if resolved_from in {"execute", "review"} and "execute" in planned:
|
|
316
|
+
allowed = [*allowed, "execute"]
|
|
307
317
|
return list(dict.fromkeys(allowed))
|
|
308
318
|
|
|
309
319
|
|
|
@@ -322,12 +332,14 @@ def configure_phase_plan(
|
|
|
322
332
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
323
333
|
return {"ok": False, "code": _contract_error_code(exc), "error": str(exc)}
|
|
324
334
|
normalized = [str(item).strip() for item in phases if str(item).strip()]
|
|
335
|
+
resolved = [hpaths.resolve_phase_name(item) for item in normalized]
|
|
325
336
|
if (
|
|
326
337
|
not normalized
|
|
327
338
|
or len(normalized) != len(set(normalized))
|
|
328
|
-
or any(item
|
|
329
|
-
or
|
|
330
|
-
or
|
|
339
|
+
or any(item is None for item in resolved)
|
|
340
|
+
or len(set(resolved)) != len(resolved)
|
|
341
|
+
or resolved[0] != "plan"
|
|
342
|
+
or resolved[-1] != "archive"
|
|
331
343
|
):
|
|
332
344
|
return {
|
|
333
345
|
"ok": False,
|
|
@@ -340,6 +352,9 @@ def configure_phase_plan(
|
|
|
340
352
|
"ok": False,
|
|
341
353
|
"code": "PHASE_PLAN_JUSTIFICATION_REQUIRED",
|
|
342
354
|
}
|
|
355
|
+
# 旧名入参(plan,run,test,review,archive)归一为现阶段名后落盘;
|
|
356
|
+
# 上面已校验 resolved 无 None 且保序唯一。
|
|
357
|
+
normalized = [str(item) for item in resolved]
|
|
343
358
|
worktree_path = contract_root / "meta" / "worktree.json"
|
|
344
359
|
if worktree_path.is_file():
|
|
345
360
|
try:
|
|
@@ -405,6 +420,7 @@ def _paths(state_root: Path) -> dict[str, Path]:
|
|
|
405
420
|
"begins": runtime / "transition-begins.ndjson",
|
|
406
421
|
"current": runtime / "current-context.json",
|
|
407
422
|
"lease": runtime / "context-lease.json",
|
|
423
|
+
"adoptions": runtime / "context-adoptions.ndjson",
|
|
408
424
|
}
|
|
409
425
|
|
|
410
426
|
|
|
@@ -442,7 +458,7 @@ def _reselect_review_fixback(
|
|
|
442
458
|
state_root: Path,
|
|
443
459
|
executor: str,
|
|
444
460
|
) -> dict[str, Any]:
|
|
445
|
-
"""Supersede an unbegun review→submit choice with review→
|
|
461
|
+
"""Supersede an unbegun review→submit choice with review→execute."""
|
|
446
462
|
|
|
447
463
|
paths = _paths(state_root)
|
|
448
464
|
with _exclusive_state_lock(paths["runtime"] / "branch-selection.lock"):
|
|
@@ -450,8 +466,8 @@ def _reselect_review_fixback(
|
|
|
450
466
|
latest = transitions[-1] if transitions else None
|
|
451
467
|
if (
|
|
452
468
|
isinstance(latest, dict)
|
|
453
|
-
and latest.get("fromPhase") == "review"
|
|
454
|
-
and latest.get("toPhase") == "
|
|
469
|
+
and hpaths.resolve_phase_name(latest.get("fromPhase")) == "review"
|
|
470
|
+
and hpaths.resolve_phase_name(latest.get("toPhase")) == "execute"
|
|
455
471
|
and latest.get("trigger") == "review-fixback"
|
|
456
472
|
):
|
|
457
473
|
return {
|
|
@@ -503,14 +519,14 @@ def _reselect_review_fixback(
|
|
|
503
519
|
}
|
|
504
520
|
paths["lease"].unlink(missing_ok=True)
|
|
505
521
|
# Any submit context present here was only prepared, never begun. The
|
|
506
|
-
# new
|
|
522
|
+
# new execute context is written by prepare_context after this atomic choice.
|
|
507
523
|
paths["current"].unlink(missing_ok=True)
|
|
508
524
|
|
|
509
525
|
receipt: dict[str, Any] = {
|
|
510
526
|
"schemaVersion": 1,
|
|
511
527
|
"changeName": change,
|
|
512
528
|
"fromPhase": "review",
|
|
513
|
-
"toPhase": "
|
|
529
|
+
"toPhase": "execute",
|
|
514
530
|
"status": "OK",
|
|
515
531
|
"executor": executor,
|
|
516
532
|
"productCommit": _head(project),
|
|
@@ -519,8 +535,8 @@ def _reselect_review_fixback(
|
|
|
519
535
|
+ sum(
|
|
520
536
|
1
|
|
521
537
|
for item in transitions
|
|
522
|
-
if item.get("fromPhase") == "review"
|
|
523
|
-
and item.get("toPhase") == "
|
|
538
|
+
if hpaths.resolve_phase_name(item.get("fromPhase")) == "review"
|
|
539
|
+
and hpaths.resolve_phase_name(item.get("toPhase")) == "execute"
|
|
524
540
|
),
|
|
525
541
|
"closedAt": _now().isoformat(),
|
|
526
542
|
"previousReceiptHash": latest.get("receiptHash"),
|
|
@@ -534,7 +550,7 @@ def _reselect_review_fixback(
|
|
|
534
550
|
state_root,
|
|
535
551
|
transition_hash=receipt["receiptHash"],
|
|
536
552
|
from_phase="review",
|
|
537
|
-
to_phase="
|
|
553
|
+
to_phase="execute",
|
|
538
554
|
)
|
|
539
555
|
return {
|
|
540
556
|
"ok": True,
|
|
@@ -604,13 +620,20 @@ def _claim_prepared_context(
|
|
|
604
620
|
)
|
|
605
621
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
606
622
|
return {"ok": False, "code": "CONTEXT_CURRENT_INVALID"}
|
|
623
|
+
# 跨阶段推进必须有 receipt 证明它合法;同一个阶段换执行者不需要。
|
|
624
|
+
# 以前两者都要 receipt,于是上一阶段崩溃没能正常 close 时,接手的工具
|
|
625
|
+
# 连"继续把这个阶段干完"都做不到。并发保护不受影响:租约未过期而
|
|
626
|
+
# owner 不同,上面 CONTEXT_LEASE_HELD 已经拦下了,能走到这里只剩
|
|
627
|
+
# 「租约已过期」和「租约已被上一阶段 close 删除」两种情况。
|
|
628
|
+
adoption: dict[str, Any] | None = None
|
|
607
629
|
if recovery is None and isinstance(current, dict) and (
|
|
608
|
-
|
|
630
|
+
hpaths.resolve_phase_name(current.get("phase")) != phase
|
|
609
631
|
):
|
|
610
632
|
valid_receipt = (
|
|
611
633
|
isinstance(latest, dict)
|
|
612
|
-
and latest.get("toPhase") == phase
|
|
613
|
-
and latest.get("fromPhase")
|
|
634
|
+
and hpaths.resolve_phase_name(latest.get("toPhase")) == phase
|
|
635
|
+
and hpaths.resolve_phase_name(latest.get("fromPhase"))
|
|
636
|
+
== hpaths.resolve_phase_name(current.get("phase"))
|
|
614
637
|
)
|
|
615
638
|
if not valid_receipt:
|
|
616
639
|
return {
|
|
@@ -621,6 +644,19 @@ def _claim_prepared_context(
|
|
|
621
644
|
"toExecutor": executor,
|
|
622
645
|
"toPhase": phase,
|
|
623
646
|
}
|
|
647
|
+
executor_changed = (
|
|
648
|
+
isinstance(current, dict) and current.get("executor") != executor
|
|
649
|
+
)
|
|
650
|
+
if recovery is not None or executor_changed:
|
|
651
|
+
adoption = {
|
|
652
|
+
"previousExecutor": (
|
|
653
|
+
current.get("executor") if isinstance(current, dict) else None
|
|
654
|
+
),
|
|
655
|
+
"newExecutor": executor,
|
|
656
|
+
"reason": (
|
|
657
|
+
"lease_expired" if recovery is not None else "same_phase_handoff"
|
|
658
|
+
),
|
|
659
|
+
}
|
|
624
660
|
|
|
625
661
|
try:
|
|
626
662
|
execution_root = _execution_root(project, contract_root, state_root)
|
|
@@ -657,6 +693,20 @@ def _claim_prepared_context(
|
|
|
657
693
|
current_context["preparationId"] = preparation_id
|
|
658
694
|
_write_json_atomic(paths["lease"], lease)
|
|
659
695
|
_write_json_atomic(paths["current"], current_context)
|
|
696
|
+
if adoption is not None:
|
|
697
|
+
# 接管必须留痕。过期租约本来就允许任何执行者顶替,但以前只在返回体
|
|
698
|
+
# 里挂一个 recovery,退出进程就没了——事后查"这个阶段是谁接手的"
|
|
699
|
+
# 无据可依。收据形状照 harness_archive.adopt_existing_range。
|
|
700
|
+
adoption = {
|
|
701
|
+
"schemaVersion": 1,
|
|
702
|
+
"changeName": change,
|
|
703
|
+
"phase": phase,
|
|
704
|
+
**adoption,
|
|
705
|
+
"previousOwner": recovery.get("previousOwner") if recovery else None,
|
|
706
|
+
"expiredAt": recovery.get("expiredAt") if recovery else None,
|
|
707
|
+
"adoptedAt": now.isoformat(),
|
|
708
|
+
}
|
|
709
|
+
_append_ndjson(paths["adoptions"], adoption)
|
|
660
710
|
return {
|
|
661
711
|
"ok": True,
|
|
662
712
|
"lease": lease,
|
|
@@ -664,10 +714,25 @@ def _claim_prepared_context(
|
|
|
664
714
|
"transitions": transitions,
|
|
665
715
|
"latestTransition": latest,
|
|
666
716
|
"recovery": recovery,
|
|
717
|
+
"adoption": adoption,
|
|
667
718
|
"executionRoot": str(execution_root),
|
|
668
719
|
}
|
|
669
720
|
|
|
670
721
|
|
|
722
|
+
def _unknown_phase_error(phase: Any) -> dict[str, Any]:
|
|
723
|
+
return {
|
|
724
|
+
"ok": False,
|
|
725
|
+
"code": "PHASE_UNKNOWN",
|
|
726
|
+
"phase": str(phase),
|
|
727
|
+
"allowedPhases": list(WORKFLOW_PHASES),
|
|
728
|
+
"legacyAliases": dict(hpaths.LEGACY_PHASE_ALIASES),
|
|
729
|
+
"message": (
|
|
730
|
+
f"未知阶段名 {phase!r};合法阶段 {list(WORKFLOW_PHASES)},"
|
|
731
|
+
f"旧名别名 {hpaths.LEGACY_PHASE_ALIASES}。"
|
|
732
|
+
),
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
|
|
671
736
|
def prepare_context(
|
|
672
737
|
project: Path,
|
|
673
738
|
*,
|
|
@@ -680,6 +745,10 @@ def prepare_context(
|
|
|
680
745
|
preparation_id: str | None = None,
|
|
681
746
|
) -> dict[str, Any]:
|
|
682
747
|
project = Path(project).resolve()
|
|
748
|
+
canonical_phase = hpaths.resolve_phase_name(phase)
|
|
749
|
+
if canonical_phase is None:
|
|
750
|
+
return _unknown_phase_error(phase)
|
|
751
|
+
phase = canonical_phase
|
|
683
752
|
candidates = _active_changes(project)
|
|
684
753
|
if change is None:
|
|
685
754
|
if not candidates:
|
|
@@ -726,7 +795,7 @@ def prepare_context(
|
|
|
726
795
|
paths = _paths(state_root)
|
|
727
796
|
paths["runtime"].mkdir(parents=True, exist_ok=True)
|
|
728
797
|
reselection: dict[str, Any] | None = None
|
|
729
|
-
if trigger == "review-fixback" and phase == "
|
|
798
|
+
if trigger == "review-fixback" and phase == "execute":
|
|
730
799
|
reselection = _reselect_review_fixback(
|
|
731
800
|
project,
|
|
732
801
|
change,
|
|
@@ -768,9 +837,14 @@ def prepare_context(
|
|
|
768
837
|
_allowed_next_phases(contract_root, phase)
|
|
769
838
|
if planned_phases is not None
|
|
770
839
|
else (
|
|
771
|
-
list(
|
|
840
|
+
list(
|
|
841
|
+
PHASE_GRAPH.get(
|
|
842
|
+
hpaths.resolve_phase_name(str(latest.get("toPhase"))) or "",
|
|
843
|
+
(),
|
|
844
|
+
)
|
|
845
|
+
)
|
|
772
846
|
if latest
|
|
773
|
-
else ["plan", "
|
|
847
|
+
else ["plan", "execute"]
|
|
774
848
|
)
|
|
775
849
|
)
|
|
776
850
|
return {
|
|
@@ -1014,7 +1088,7 @@ def _bootstrap_v2_plan_transition(
|
|
|
1014
1088
|
"""v2 发布已 committed 却没有交接凭证时,补录 plan → to_phase 凭证。
|
|
1015
1089
|
|
|
1016
1090
|
v2 plan finalize 只写 plan-events.ndjson 与发布 journal,不碰 context 事务
|
|
1017
|
-
存储,于是
|
|
1091
|
+
存储,于是 execute 阶段 prepare 必报 HANDOFF_REQUIRED、begin 必报
|
|
1018
1092
|
LEGACY_BOOTSTRAP_REQUIRED——两个错误都不给恢复路径,调用方只能读脚本源码
|
|
1019
1093
|
自己拼出 classify + configure-plan + close,参数全靠现编,可审计性更差。
|
|
1020
1094
|
|
|
@@ -1061,6 +1135,14 @@ def close_transition(
|
|
|
1061
1135
|
status: str = "OK",
|
|
1062
1136
|
) -> dict[str, Any]:
|
|
1063
1137
|
project = Path(project).resolve()
|
|
1138
|
+
canonical_from = hpaths.resolve_phase_name(from_phase)
|
|
1139
|
+
canonical_to = hpaths.resolve_phase_name(to_phase)
|
|
1140
|
+
if canonical_from is None:
|
|
1141
|
+
return _unknown_phase_error(from_phase)
|
|
1142
|
+
if canonical_to is None:
|
|
1143
|
+
return _unknown_phase_error(to_phase)
|
|
1144
|
+
from_phase = canonical_from
|
|
1145
|
+
to_phase = canonical_to
|
|
1064
1146
|
try:
|
|
1065
1147
|
contract_root, _contract_data, state_root = _contract(project, change)
|
|
1066
1148
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1136,8 +1218,8 @@ def close_transition(
|
|
|
1136
1218
|
latest = transitions[-1] if transitions else None
|
|
1137
1219
|
if (
|
|
1138
1220
|
isinstance(latest, dict)
|
|
1139
|
-
and latest.get("fromPhase") == from_phase
|
|
1140
|
-
and latest.get("toPhase") == to_phase
|
|
1221
|
+
and hpaths.resolve_phase_name(latest.get("fromPhase")) == from_phase
|
|
1222
|
+
and hpaths.resolve_phase_name(latest.get("toPhase")) == to_phase
|
|
1141
1223
|
and latest.get("status") == status
|
|
1142
1224
|
and latest.get("artifacts") == artifact_entries
|
|
1143
1225
|
and (executor is None or latest.get("executor") == executor)
|
|
@@ -1158,7 +1240,9 @@ def close_transition(
|
|
|
1158
1240
|
effective_executor = executor or str(lease.get("owner") or "")
|
|
1159
1241
|
if not effective_executor:
|
|
1160
1242
|
return {"ok": False, "code": "CONTEXT_EXECUTOR_REQUIRED"}
|
|
1161
|
-
if lease.get("owner") != effective_executor or
|
|
1243
|
+
if lease.get("owner") != effective_executor or (
|
|
1244
|
+
hpaths.resolve_phase_name(lease.get("phase")) != from_phase
|
|
1245
|
+
):
|
|
1162
1246
|
return {
|
|
1163
1247
|
"ok": False,
|
|
1164
1248
|
"code": "CONTEXT_LEASE_MISMATCH",
|
|
@@ -1177,8 +1261,8 @@ def close_transition(
|
|
|
1177
1261
|
+ sum(
|
|
1178
1262
|
1
|
|
1179
1263
|
for item in transitions
|
|
1180
|
-
if item.get("fromPhase") == from_phase
|
|
1181
|
-
and item.get("toPhase") == to_phase
|
|
1264
|
+
if hpaths.resolve_phase_name(item.get("fromPhase")) == from_phase
|
|
1265
|
+
and hpaths.resolve_phase_name(item.get("toPhase")) == to_phase
|
|
1182
1266
|
)
|
|
1183
1267
|
)
|
|
1184
1268
|
receipt: dict[str, Any] = {
|
|
@@ -1204,7 +1288,7 @@ def close_transition(
|
|
|
1204
1288
|
_append_ndjson(paths["transitions"], receipt)
|
|
1205
1289
|
paths["lease"].unlink(missing_ok=True)
|
|
1206
1290
|
invalidation = None
|
|
1207
|
-
if to_phase == "
|
|
1291
|
+
if to_phase == "execute" and from_phase in {"execute", "review"}:
|
|
1208
1292
|
invalidation = _invalidate_for_fixback(
|
|
1209
1293
|
state_root,
|
|
1210
1294
|
transition_hash=receipt["receiptHash"],
|
|
@@ -1283,7 +1367,7 @@ def _begin_transition_unlocked(
|
|
|
1283
1367
|
),
|
|
1284
1368
|
}
|
|
1285
1369
|
receipt = transitions[-1]
|
|
1286
|
-
if receipt.get("toPhase") != phase:
|
|
1370
|
+
if hpaths.resolve_phase_name(receipt.get("toPhase")) != phase:
|
|
1287
1371
|
return {
|
|
1288
1372
|
"ok": False,
|
|
1289
1373
|
"code": "HANDOFF_REQUIRED",
|
|
@@ -1360,6 +1444,10 @@ def begin_transition(
|
|
|
1360
1444
|
"""Acknowledge a transition while serializing branch selection."""
|
|
1361
1445
|
|
|
1362
1446
|
project = Path(project).resolve()
|
|
1447
|
+
canonical_phase = hpaths.resolve_phase_name(phase)
|
|
1448
|
+
if canonical_phase is None:
|
|
1449
|
+
return _unknown_phase_error(phase)
|
|
1450
|
+
phase = canonical_phase
|
|
1363
1451
|
try:
|
|
1364
1452
|
_contract_root, _contract_data, state_root = _contract(project, change)
|
|
1365
1453
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1386,6 +1474,10 @@ def cancel_prepared_context(
|
|
|
1386
1474
|
"""Remove a target-phase preparation that never obtained its gate."""
|
|
1387
1475
|
|
|
1388
1476
|
project = Path(project).resolve()
|
|
1477
|
+
canonical_phase = hpaths.resolve_phase_name(phase)
|
|
1478
|
+
if canonical_phase is None:
|
|
1479
|
+
return _unknown_phase_error(phase)
|
|
1480
|
+
phase = canonical_phase
|
|
1389
1481
|
try:
|
|
1390
1482
|
_contract_root, _contract_data, state_root = _contract(project, change)
|
|
1391
1483
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1400,7 +1492,8 @@ def cancel_prepared_context(
|
|
|
1400
1492
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
1401
1493
|
current = None
|
|
1402
1494
|
if isinstance(current, dict) and (
|
|
1403
|
-
current.get("phase") == phase
|
|
1495
|
+
hpaths.resolve_phase_name(current.get("phase")) == phase
|
|
1496
|
+
and current.get("executor") == executor
|
|
1404
1497
|
and (
|
|
1405
1498
|
preparation_id is None
|
|
1406
1499
|
or current.get("preparationId") == preparation_id
|
|
@@ -1415,7 +1508,8 @@ def cancel_prepared_context(
|
|
|
1415
1508
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
1416
1509
|
lease = None
|
|
1417
1510
|
if isinstance(lease, dict) and (
|
|
1418
|
-
lease.get("phase") == phase
|
|
1511
|
+
hpaths.resolve_phase_name(lease.get("phase")) == phase
|
|
1512
|
+
and lease.get("owner") == executor
|
|
1419
1513
|
and (
|
|
1420
1514
|
preparation_id is None
|
|
1421
1515
|
or lease.get("preparationId") == preparation_id
|
|
@@ -1429,7 +1523,7 @@ def cancel_prepared_context(
|
|
|
1429
1523
|
for item in begins
|
|
1430
1524
|
if not (
|
|
1431
1525
|
receipt_hash is not None
|
|
1432
|
-
and item.get("phase") == phase
|
|
1526
|
+
and hpaths.resolve_phase_name(item.get("phase")) == phase
|
|
1433
1527
|
and item.get("executor") == executor
|
|
1434
1528
|
and item.get("receiptHash") == receipt_hash
|
|
1435
1529
|
and (
|
|
@@ -2014,7 +2014,7 @@ def cmd_append(args: argparse.Namespace) -> int:
|
|
|
2014
2014
|
"PHASE_ALREADY_CLOSED: refusing a second phase.end for the same "
|
|
2015
2015
|
"attempt. A retry needs a fresh run id AND the next attempt number "
|
|
2016
2016
|
"(attempts are global per phase, not per run id). For a published "
|
|
2017
|
-
"plan
|
|
2017
|
+
"plan rerun plan evidence-pack + plan finalize with the next attempt.",
|
|
2018
2018
|
as_json=as_json,
|
|
2019
2019
|
error_code="PHASE_ALREADY_CLOSED",
|
|
2020
2020
|
)
|
|
@@ -333,7 +333,7 @@ def open_review_batch(
|
|
|
333
333
|
_write_json(_session_path(change_dir), session)
|
|
334
334
|
he.append_event(
|
|
335
335
|
change_dir,
|
|
336
|
-
phase="
|
|
336
|
+
phase="execute",
|
|
337
337
|
type_="decision",
|
|
338
338
|
note=f"已从评审结果创建修复批次,共 {len(issue_entries)} 个代码修复项。",
|
|
339
339
|
run_id=run_id,
|
|
@@ -355,7 +355,7 @@ def _default_context_prepare(**kwargs: Any) -> dict[str, Any]:
|
|
|
355
355
|
|
|
356
356
|
return hctx.prepare_context(
|
|
357
357
|
kwargs["project"],
|
|
358
|
-
phase="
|
|
358
|
+
phase="execute",
|
|
359
359
|
executor=kwargs["executor"],
|
|
360
360
|
change=kwargs["change"],
|
|
361
361
|
trigger="review-fixback",
|
|
@@ -369,7 +369,7 @@ def _default_context_begin(**kwargs: Any) -> dict[str, Any]:
|
|
|
369
369
|
return hctx.begin_transition(
|
|
370
370
|
kwargs["project"],
|
|
371
371
|
kwargs["change"],
|
|
372
|
-
phase="
|
|
372
|
+
phase="execute",
|
|
373
373
|
executor=kwargs["executor"],
|
|
374
374
|
preparation_id=kwargs["preparation_id"],
|
|
375
375
|
)
|
|
@@ -381,7 +381,7 @@ def _default_context_cancel(**kwargs: Any) -> dict[str, Any]:
|
|
|
381
381
|
return hctx.cancel_prepared_context(
|
|
382
382
|
kwargs["project"],
|
|
383
383
|
kwargs["change"],
|
|
384
|
-
phase="
|
|
384
|
+
phase="execute",
|
|
385
385
|
executor=kwargs["executor"],
|
|
386
386
|
preparation_id=kwargs["preparation_id"],
|
|
387
387
|
)
|
|
@@ -394,7 +394,7 @@ def _default_gate_begin(**kwargs: Any) -> dict[str, Any]:
|
|
|
394
394
|
"begin",
|
|
395
395
|
"--json",
|
|
396
396
|
"--phase",
|
|
397
|
-
"
|
|
397
|
+
"execute",
|
|
398
398
|
"--change",
|
|
399
399
|
str(kwargs["change"]),
|
|
400
400
|
"--project",
|
|
@@ -405,6 +405,10 @@ def _default_gate_begin(**kwargs: Any) -> dict[str, Any]:
|
|
|
405
405
|
str(kwargs["run_id"]),
|
|
406
406
|
"--note",
|
|
407
407
|
"开始处理评审中确认需要修改的代码问题。",
|
|
408
|
+
# 显式标记这一轮是 review fixback。以前靠 gate 嗅探 note 里有没有
|
|
409
|
+
# "fixback" 字样——而上面这条 note 一个都没有,于是 fixback 的 run 事件
|
|
410
|
+
# 从来没被打上 trigger/from_phase。
|
|
411
|
+
"--fixback",
|
|
408
412
|
]
|
|
409
413
|
for option, key in (
|
|
410
414
|
("--executor-tool", "executor_tool"),
|
|
@@ -483,7 +487,7 @@ def launch_review_fixback(
|
|
|
483
487
|
started_at = time.monotonic()
|
|
484
488
|
start_event = he.append_event(
|
|
485
489
|
change_dir,
|
|
486
|
-
phase="
|
|
490
|
+
phase="execute",
|
|
487
491
|
type_="phase.prepare.start",
|
|
488
492
|
note="正在检查评审修复的前置条件。",
|
|
489
493
|
run_id=effective_run_id,
|
|
@@ -518,7 +522,7 @@ def launch_review_fixback(
|
|
|
518
522
|
message = str(result.get("message") or result.get("error") or "前置条件未满足,修复未启动。")
|
|
519
523
|
he.append_event(
|
|
520
524
|
change_dir,
|
|
521
|
-
phase="
|
|
525
|
+
phase="execute",
|
|
522
526
|
type_="phase.prepare.end",
|
|
523
527
|
status="BLOCKED",
|
|
524
528
|
code=code,
|
|
@@ -537,7 +541,7 @@ def launch_review_fixback(
|
|
|
537
541
|
"ok": False,
|
|
538
542
|
"code": code,
|
|
539
543
|
"message": message,
|
|
540
|
-
"recoveryAction": "处理提示的前置条件后重新执行 /harness-
|
|
544
|
+
"recoveryAction": "处理提示的前置条件后重新执行 /harness-execute --fixback",
|
|
541
545
|
"preparationDurationMs": duration,
|
|
542
546
|
"contextCancellation": cancellation,
|
|
543
547
|
}
|
|
@@ -562,7 +566,7 @@ def launch_review_fixback(
|
|
|
562
566
|
duration = max(0, round((time.monotonic() - started_at) * 1000))
|
|
563
567
|
he.append_event(
|
|
564
568
|
change_dir,
|
|
565
|
-
phase="
|
|
569
|
+
phase="execute",
|
|
566
570
|
type_="phase.prepare.end",
|
|
567
571
|
status="STARTED",
|
|
568
572
|
message="前置条件已满足,修复编码已启动。",
|
|
@@ -661,7 +665,7 @@ def resume_batch(
|
|
|
661
665
|
_write_json(session_path, session)
|
|
662
666
|
he.append_event(
|
|
663
667
|
change_dir,
|
|
664
|
-
phase="
|
|
668
|
+
phase="execute",
|
|
665
669
|
type_="decision",
|
|
666
670
|
note=(
|
|
667
671
|
"已恢复现有修复批次,将从未完成步骤继续。"
|