@hunter-harness/workflow-harness 0.2.86 → 0.3.1
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 -10
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +2 -13
- package/harness/bundles/general/claude-code/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/general/claude-code/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +92 -25
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +4 -2
- package/harness/bundles/general/claude-code/scripts/harness_paths.py +120 -5
- package/harness/bundles/general/claude-code/scripts/harness_phase.py +41 -17
- package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +2 -13
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/general/codebuddy/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +92 -25
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +4 -2
- package/harness/bundles/general/codebuddy/scripts/harness_paths.py +120 -5
- package/harness/bundles/general/codebuddy/scripts/harness_phase.py +41 -17
- package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/general/codex/harness-plan/checklist.md +2 -13
- package/harness/bundles/general/codex/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/general/codex/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/general/codex/scripts/harness_gate.py +92 -25
- package/harness/bundles/general/codex/scripts/harness_ledger.py +4 -2
- package/harness/bundles/general/codex/scripts/harness_paths.py +120 -5
- package/harness/bundles/general/codex/scripts/harness_phase.py +41 -17
- package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/general/cursor/harness-plan/checklist.md +2 -13
- package/harness/bundles/general/cursor/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/general/cursor/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/general/cursor/scripts/harness_gate.py +92 -25
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +4 -2
- package/harness/bundles/general/cursor/scripts/harness_paths.py +120 -5
- package/harness/bundles/general/cursor/scripts/harness_phase.py +41 -17
- package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +2 -13
- package/harness/bundles/java/claude-code/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/java/claude-code/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +92 -25
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +4 -2
- package/harness/bundles/java/claude-code/scripts/harness_paths.py +120 -5
- package/harness/bundles/java/claude-code/scripts/harness_phase.py +41 -17
- package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +2 -13
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/java/codebuddy/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +92 -25
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +4 -2
- package/harness/bundles/java/codebuddy/scripts/harness_paths.py +120 -5
- package/harness/bundles/java/codebuddy/scripts/harness_phase.py +41 -17
- package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/java/codex/harness-plan/checklist.md +2 -13
- package/harness/bundles/java/codex/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/java/codex/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/java/codex/scripts/harness_gate.py +92 -25
- package/harness/bundles/java/codex/scripts/harness_ledger.py +4 -2
- package/harness/bundles/java/codex/scripts/harness_paths.py +120 -5
- package/harness/bundles/java/codex/scripts/harness_phase.py +41 -17
- package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +16 -873
- 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 -10
- package/harness/bundles/java/cursor/harness-plan/checklist.md +2 -13
- package/harness/bundles/java/cursor/harness-plan/reference.md +43 -81
- 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 +8 -2
- 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 +46 -15
- package/harness/bundles/java/cursor/scripts/harness_context.py +94 -43
- 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 +10 -10
- package/harness/bundles/java/cursor/scripts/harness_gate.py +92 -25
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +4 -2
- package/harness/bundles/java/cursor/scripts/harness_paths.py +120 -5
- package/harness/bundles/java/cursor/scripts/harness_phase.py +41 -17
- package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +16 -873
- package/harness/manifests/general/claude-code.json +36 -28
- package/harness/manifests/general/codebuddy.json +36 -28
- package/harness/manifests/general/codex.json +36 -28
- package/harness/manifests/general/cursor.json +36 -28
- package/harness/manifests/java/claude-code.json +38 -30
- package/harness/manifests/java/codebuddy.json +38 -30
- package/harness/manifests/java/codex.json +38 -30
- package/harness/manifests/java/cursor.json +38 -30
- package/hunter-workflow-family.json +2 -2
- package/package.json +1 -1
|
@@ -25,10 +25,9 @@ import harness_paths as hpaths # noqa: E402
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
PHASE_GRAPH = {
|
|
28
|
-
"plan": ("
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"review": ("submit", "run"),
|
|
28
|
+
"plan": ("execute",),
|
|
29
|
+
"execute": ("review", "execute"),
|
|
30
|
+
"review": ("submit", "execute"),
|
|
32
31
|
"submit": (),
|
|
33
32
|
}
|
|
34
33
|
|
|
@@ -271,14 +270,16 @@ def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
|
271
270
|
|
|
272
271
|
未知名先过 LEGACY_PHASE_ALIASES 读时映射(阶段改名后历史 change 靠它继续可读),
|
|
273
272
|
仍然解析不了才降级,并把原因与具体阶段名带在 source 里。
|
|
273
|
+
|
|
274
|
+
权威切换(2026-08):v2 发布快照(plan-profile.json)优先,classify 工作
|
|
275
|
+
副本回退——发布后的阶段计划以已审批快照为准。
|
|
274
276
|
"""
|
|
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"
|
|
277
282
|
return None, "legacy"
|
|
278
|
-
try:
|
|
279
|
-
policy = _read_json(policy_path)
|
|
280
|
-
except (OSError, ValueError, json.JSONDecodeError):
|
|
281
|
-
return None, "legacy:policy-unreadable"
|
|
282
283
|
unknown: list[str] = []
|
|
283
284
|
for field, source in (
|
|
284
285
|
("plannedPhases", "change"),
|
|
@@ -304,14 +305,15 @@ def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
|
304
305
|
|
|
305
306
|
def _allowed_next_phases(contract_root: Path, from_phase: str) -> list[str]:
|
|
306
307
|
planned, _source = _phase_plan(contract_root)
|
|
308
|
+
resolved_from = hpaths.resolve_phase_name(from_phase) or from_phase
|
|
307
309
|
if planned is None:
|
|
308
|
-
return list(PHASE_GRAPH.get(
|
|
309
|
-
if
|
|
310
|
+
return list(PHASE_GRAPH.get(resolved_from, ()))
|
|
311
|
+
if resolved_from not in planned:
|
|
310
312
|
return []
|
|
311
|
-
index = planned.index(
|
|
313
|
+
index = planned.index(resolved_from)
|
|
312
314
|
allowed = planned[index + 1 : index + 2]
|
|
313
|
-
if
|
|
314
|
-
allowed = [*allowed, "
|
|
315
|
+
if resolved_from in {"execute", "review"} and "execute" in planned:
|
|
316
|
+
allowed = [*allowed, "execute"]
|
|
315
317
|
return list(dict.fromkeys(allowed))
|
|
316
318
|
|
|
317
319
|
|
|
@@ -330,12 +332,14 @@ def configure_phase_plan(
|
|
|
330
332
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
331
333
|
return {"ok": False, "code": _contract_error_code(exc), "error": str(exc)}
|
|
332
334
|
normalized = [str(item).strip() for item in phases if str(item).strip()]
|
|
335
|
+
resolved = [hpaths.resolve_phase_name(item) for item in normalized]
|
|
333
336
|
if (
|
|
334
337
|
not normalized
|
|
335
338
|
or len(normalized) != len(set(normalized))
|
|
336
|
-
or any(item
|
|
337
|
-
or
|
|
338
|
-
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"
|
|
339
343
|
):
|
|
340
344
|
return {
|
|
341
345
|
"ok": False,
|
|
@@ -348,6 +352,9 @@ def configure_phase_plan(
|
|
|
348
352
|
"ok": False,
|
|
349
353
|
"code": "PHASE_PLAN_JUSTIFICATION_REQUIRED",
|
|
350
354
|
}
|
|
355
|
+
# 旧名入参(plan,run,test,review,archive)归一为现阶段名后落盘;
|
|
356
|
+
# 上面已校验 resolved 无 None 且保序唯一。
|
|
357
|
+
normalized = [str(item) for item in resolved]
|
|
351
358
|
worktree_path = contract_root / "meta" / "worktree.json"
|
|
352
359
|
if worktree_path.is_file():
|
|
353
360
|
try:
|
|
@@ -451,7 +458,7 @@ def _reselect_review_fixback(
|
|
|
451
458
|
state_root: Path,
|
|
452
459
|
executor: str,
|
|
453
460
|
) -> dict[str, Any]:
|
|
454
|
-
"""Supersede an unbegun review→submit choice with review→
|
|
461
|
+
"""Supersede an unbegun review→submit choice with review→execute."""
|
|
455
462
|
|
|
456
463
|
paths = _paths(state_root)
|
|
457
464
|
with _exclusive_state_lock(paths["runtime"] / "branch-selection.lock"):
|
|
@@ -459,8 +466,8 @@ def _reselect_review_fixback(
|
|
|
459
466
|
latest = transitions[-1] if transitions else None
|
|
460
467
|
if (
|
|
461
468
|
isinstance(latest, dict)
|
|
462
|
-
and latest.get("fromPhase") == "review"
|
|
463
|
-
and latest.get("toPhase") == "
|
|
469
|
+
and hpaths.resolve_phase_name(latest.get("fromPhase")) == "review"
|
|
470
|
+
and hpaths.resolve_phase_name(latest.get("toPhase")) == "execute"
|
|
464
471
|
and latest.get("trigger") == "review-fixback"
|
|
465
472
|
):
|
|
466
473
|
return {
|
|
@@ -512,14 +519,14 @@ def _reselect_review_fixback(
|
|
|
512
519
|
}
|
|
513
520
|
paths["lease"].unlink(missing_ok=True)
|
|
514
521
|
# Any submit context present here was only prepared, never begun. The
|
|
515
|
-
# new
|
|
522
|
+
# new execute context is written by prepare_context after this atomic choice.
|
|
516
523
|
paths["current"].unlink(missing_ok=True)
|
|
517
524
|
|
|
518
525
|
receipt: dict[str, Any] = {
|
|
519
526
|
"schemaVersion": 1,
|
|
520
527
|
"changeName": change,
|
|
521
528
|
"fromPhase": "review",
|
|
522
|
-
"toPhase": "
|
|
529
|
+
"toPhase": "execute",
|
|
523
530
|
"status": "OK",
|
|
524
531
|
"executor": executor,
|
|
525
532
|
"productCommit": _head(project),
|
|
@@ -528,8 +535,8 @@ def _reselect_review_fixback(
|
|
|
528
535
|
+ sum(
|
|
529
536
|
1
|
|
530
537
|
for item in transitions
|
|
531
|
-
if item.get("fromPhase") == "review"
|
|
532
|
-
and item.get("toPhase") == "
|
|
538
|
+
if hpaths.resolve_phase_name(item.get("fromPhase")) == "review"
|
|
539
|
+
and hpaths.resolve_phase_name(item.get("toPhase")) == "execute"
|
|
533
540
|
),
|
|
534
541
|
"closedAt": _now().isoformat(),
|
|
535
542
|
"previousReceiptHash": latest.get("receiptHash"),
|
|
@@ -543,7 +550,7 @@ def _reselect_review_fixback(
|
|
|
543
550
|
state_root,
|
|
544
551
|
transition_hash=receipt["receiptHash"],
|
|
545
552
|
from_phase="review",
|
|
546
|
-
to_phase="
|
|
553
|
+
to_phase="execute",
|
|
547
554
|
)
|
|
548
555
|
return {
|
|
549
556
|
"ok": True,
|
|
@@ -620,12 +627,13 @@ def _claim_prepared_context(
|
|
|
620
627
|
# 「租约已过期」和「租约已被上一阶段 close 删除」两种情况。
|
|
621
628
|
adoption: dict[str, Any] | None = None
|
|
622
629
|
if recovery is None and isinstance(current, dict) and (
|
|
623
|
-
current.get("phase") != phase
|
|
630
|
+
hpaths.resolve_phase_name(current.get("phase")) != phase
|
|
624
631
|
):
|
|
625
632
|
valid_receipt = (
|
|
626
633
|
isinstance(latest, dict)
|
|
627
|
-
and latest.get("toPhase") == phase
|
|
628
|
-
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"))
|
|
629
637
|
)
|
|
630
638
|
if not valid_receipt:
|
|
631
639
|
return {
|
|
@@ -711,6 +719,20 @@ def _claim_prepared_context(
|
|
|
711
719
|
}
|
|
712
720
|
|
|
713
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
|
+
|
|
714
736
|
def prepare_context(
|
|
715
737
|
project: Path,
|
|
716
738
|
*,
|
|
@@ -723,6 +745,10 @@ def prepare_context(
|
|
|
723
745
|
preparation_id: str | None = None,
|
|
724
746
|
) -> dict[str, Any]:
|
|
725
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
|
|
726
752
|
candidates = _active_changes(project)
|
|
727
753
|
if change is None:
|
|
728
754
|
if not candidates:
|
|
@@ -769,7 +795,7 @@ def prepare_context(
|
|
|
769
795
|
paths = _paths(state_root)
|
|
770
796
|
paths["runtime"].mkdir(parents=True, exist_ok=True)
|
|
771
797
|
reselection: dict[str, Any] | None = None
|
|
772
|
-
if trigger == "review-fixback" and phase == "
|
|
798
|
+
if trigger == "review-fixback" and phase == "execute":
|
|
773
799
|
reselection = _reselect_review_fixback(
|
|
774
800
|
project,
|
|
775
801
|
change,
|
|
@@ -811,9 +837,14 @@ def prepare_context(
|
|
|
811
837
|
_allowed_next_phases(contract_root, phase)
|
|
812
838
|
if planned_phases is not None
|
|
813
839
|
else (
|
|
814
|
-
list(
|
|
840
|
+
list(
|
|
841
|
+
PHASE_GRAPH.get(
|
|
842
|
+
hpaths.resolve_phase_name(str(latest.get("toPhase"))) or "",
|
|
843
|
+
(),
|
|
844
|
+
)
|
|
845
|
+
)
|
|
815
846
|
if latest
|
|
816
|
-
else ["plan", "
|
|
847
|
+
else ["plan", "execute"]
|
|
817
848
|
)
|
|
818
849
|
)
|
|
819
850
|
return {
|
|
@@ -1057,7 +1088,7 @@ def _bootstrap_v2_plan_transition(
|
|
|
1057
1088
|
"""v2 发布已 committed 却没有交接凭证时,补录 plan → to_phase 凭证。
|
|
1058
1089
|
|
|
1059
1090
|
v2 plan finalize 只写 plan-events.ndjson 与发布 journal,不碰 context 事务
|
|
1060
|
-
存储,于是
|
|
1091
|
+
存储,于是 execute 阶段 prepare 必报 HANDOFF_REQUIRED、begin 必报
|
|
1061
1092
|
LEGACY_BOOTSTRAP_REQUIRED——两个错误都不给恢复路径,调用方只能读脚本源码
|
|
1062
1093
|
自己拼出 classify + configure-plan + close,参数全靠现编,可审计性更差。
|
|
1063
1094
|
|
|
@@ -1104,6 +1135,14 @@ def close_transition(
|
|
|
1104
1135
|
status: str = "OK",
|
|
1105
1136
|
) -> dict[str, Any]:
|
|
1106
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
|
|
1107
1146
|
try:
|
|
1108
1147
|
contract_root, _contract_data, state_root = _contract(project, change)
|
|
1109
1148
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1179,8 +1218,8 @@ def close_transition(
|
|
|
1179
1218
|
latest = transitions[-1] if transitions else None
|
|
1180
1219
|
if (
|
|
1181
1220
|
isinstance(latest, dict)
|
|
1182
|
-
and latest.get("fromPhase") == from_phase
|
|
1183
|
-
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
|
|
1184
1223
|
and latest.get("status") == status
|
|
1185
1224
|
and latest.get("artifacts") == artifact_entries
|
|
1186
1225
|
and (executor is None or latest.get("executor") == executor)
|
|
@@ -1201,7 +1240,9 @@ def close_transition(
|
|
|
1201
1240
|
effective_executor = executor or str(lease.get("owner") or "")
|
|
1202
1241
|
if not effective_executor:
|
|
1203
1242
|
return {"ok": False, "code": "CONTEXT_EXECUTOR_REQUIRED"}
|
|
1204
|
-
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
|
+
):
|
|
1205
1246
|
return {
|
|
1206
1247
|
"ok": False,
|
|
1207
1248
|
"code": "CONTEXT_LEASE_MISMATCH",
|
|
@@ -1220,8 +1261,8 @@ def close_transition(
|
|
|
1220
1261
|
+ sum(
|
|
1221
1262
|
1
|
|
1222
1263
|
for item in transitions
|
|
1223
|
-
if item.get("fromPhase") == from_phase
|
|
1224
|
-
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
|
|
1225
1266
|
)
|
|
1226
1267
|
)
|
|
1227
1268
|
receipt: dict[str, Any] = {
|
|
@@ -1247,7 +1288,7 @@ def close_transition(
|
|
|
1247
1288
|
_append_ndjson(paths["transitions"], receipt)
|
|
1248
1289
|
paths["lease"].unlink(missing_ok=True)
|
|
1249
1290
|
invalidation = None
|
|
1250
|
-
if to_phase == "
|
|
1291
|
+
if to_phase == "execute" and from_phase in {"execute", "review"}:
|
|
1251
1292
|
invalidation = _invalidate_for_fixback(
|
|
1252
1293
|
state_root,
|
|
1253
1294
|
transition_hash=receipt["receiptHash"],
|
|
@@ -1326,7 +1367,7 @@ def _begin_transition_unlocked(
|
|
|
1326
1367
|
),
|
|
1327
1368
|
}
|
|
1328
1369
|
receipt = transitions[-1]
|
|
1329
|
-
if receipt.get("toPhase") != phase:
|
|
1370
|
+
if hpaths.resolve_phase_name(receipt.get("toPhase")) != phase:
|
|
1330
1371
|
return {
|
|
1331
1372
|
"ok": False,
|
|
1332
1373
|
"code": "HANDOFF_REQUIRED",
|
|
@@ -1403,6 +1444,10 @@ def begin_transition(
|
|
|
1403
1444
|
"""Acknowledge a transition while serializing branch selection."""
|
|
1404
1445
|
|
|
1405
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
|
|
1406
1451
|
try:
|
|
1407
1452
|
_contract_root, _contract_data, state_root = _contract(project, change)
|
|
1408
1453
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1429,6 +1474,10 @@ def cancel_prepared_context(
|
|
|
1429
1474
|
"""Remove a target-phase preparation that never obtained its gate."""
|
|
1430
1475
|
|
|
1431
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
|
|
1432
1481
|
try:
|
|
1433
1482
|
_contract_root, _contract_data, state_root = _contract(project, change)
|
|
1434
1483
|
except (OSError, ValueError, json.JSONDecodeError) as exc:
|
|
@@ -1443,7 +1492,8 @@ def cancel_prepared_context(
|
|
|
1443
1492
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
1444
1493
|
current = None
|
|
1445
1494
|
if isinstance(current, dict) and (
|
|
1446
|
-
current.get("phase") == phase
|
|
1495
|
+
hpaths.resolve_phase_name(current.get("phase")) == phase
|
|
1496
|
+
and current.get("executor") == executor
|
|
1447
1497
|
and (
|
|
1448
1498
|
preparation_id is None
|
|
1449
1499
|
or current.get("preparationId") == preparation_id
|
|
@@ -1458,7 +1508,8 @@ def cancel_prepared_context(
|
|
|
1458
1508
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
1459
1509
|
lease = None
|
|
1460
1510
|
if isinstance(lease, dict) and (
|
|
1461
|
-
lease.get("phase") == phase
|
|
1511
|
+
hpaths.resolve_phase_name(lease.get("phase")) == phase
|
|
1512
|
+
and lease.get("owner") == executor
|
|
1462
1513
|
and (
|
|
1463
1514
|
preparation_id is None
|
|
1464
1515
|
or lease.get("preparationId") == preparation_id
|
|
@@ -1472,7 +1523,7 @@ def cancel_prepared_context(
|
|
|
1472
1523
|
for item in begins
|
|
1473
1524
|
if not (
|
|
1474
1525
|
receipt_hash is not None
|
|
1475
|
-
and item.get("phase") == phase
|
|
1526
|
+
and hpaths.resolve_phase_name(item.get("phase")) == phase
|
|
1476
1527
|
and item.get("executor") == executor
|
|
1477
1528
|
and item.get("receiptHash") == receipt_hash
|
|
1478
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",
|
|
@@ -487,7 +487,7 @@ def launch_review_fixback(
|
|
|
487
487
|
started_at = time.monotonic()
|
|
488
488
|
start_event = he.append_event(
|
|
489
489
|
change_dir,
|
|
490
|
-
phase="
|
|
490
|
+
phase="execute",
|
|
491
491
|
type_="phase.prepare.start",
|
|
492
492
|
note="正在检查评审修复的前置条件。",
|
|
493
493
|
run_id=effective_run_id,
|
|
@@ -522,7 +522,7 @@ def launch_review_fixback(
|
|
|
522
522
|
message = str(result.get("message") or result.get("error") or "前置条件未满足,修复未启动。")
|
|
523
523
|
he.append_event(
|
|
524
524
|
change_dir,
|
|
525
|
-
phase="
|
|
525
|
+
phase="execute",
|
|
526
526
|
type_="phase.prepare.end",
|
|
527
527
|
status="BLOCKED",
|
|
528
528
|
code=code,
|
|
@@ -541,7 +541,7 @@ def launch_review_fixback(
|
|
|
541
541
|
"ok": False,
|
|
542
542
|
"code": code,
|
|
543
543
|
"message": message,
|
|
544
|
-
"recoveryAction": "处理提示的前置条件后重新执行 /harness-
|
|
544
|
+
"recoveryAction": "处理提示的前置条件后重新执行 /harness-execute --fixback",
|
|
545
545
|
"preparationDurationMs": duration,
|
|
546
546
|
"contextCancellation": cancellation,
|
|
547
547
|
}
|
|
@@ -566,7 +566,7 @@ def launch_review_fixback(
|
|
|
566
566
|
duration = max(0, round((time.monotonic() - started_at) * 1000))
|
|
567
567
|
he.append_event(
|
|
568
568
|
change_dir,
|
|
569
|
-
phase="
|
|
569
|
+
phase="execute",
|
|
570
570
|
type_="phase.prepare.end",
|
|
571
571
|
status="STARTED",
|
|
572
572
|
message="前置条件已满足,修复编码已启动。",
|
|
@@ -665,7 +665,7 @@ def resume_batch(
|
|
|
665
665
|
_write_json(session_path, session)
|
|
666
666
|
he.append_event(
|
|
667
667
|
change_dir,
|
|
668
|
-
phase="
|
|
668
|
+
phase="execute",
|
|
669
669
|
type_="decision",
|
|
670
670
|
note=(
|
|
671
671
|
"已恢复现有修复批次,将从未完成步骤继续。"
|