@hunter-harness/workflow-harness 0.2.11 → 0.2.12
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/ci-metrics.schema.json +36 -0
- package/harness/bundles/general/claude-code/contracts/workflow-policy.json +30 -0
- package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +4 -4
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +6 -0
- package/harness/bundles/general/claude-code/harness-plan/reference.md +7 -2
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/checklist.md +3 -2
- package/harness/bundles/general/claude-code/harness-run/reference.md +6 -4
- package/harness/bundles/general/claude-code/harness-submit/SKILL.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 +1 -1
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +282 -120
- package/harness/bundles/general/claude-code/scripts/harness_events.py +400 -24
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +585 -21
- package/harness/bundles/general/claude-code/scripts/harness_integration.py +403 -18
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +225 -29
- package/harness/bundles/general/claude-code/scripts/harness_phase.py +926 -0
- package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/general/claude-code/scripts/harness_profile.py +50 -0
- package/harness/bundles/general/claude-code/scripts/harness_runtime.py +248 -0
- package/harness/bundles/general/claude-code/scripts/harness_state.py +15 -2
- package/harness/bundles/general/claude-code/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/general/claude-code/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/general/codebuddy/contracts/workflow-policy.json +30 -0
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +4 -4
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +6 -0
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +7 -2
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/checklist.md +3 -2
- package/harness/bundles/general/codebuddy/harness-run/reference.md +6 -4
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +282 -120
- package/harness/bundles/general/codebuddy/scripts/harness_events.py +400 -24
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +585 -21
- package/harness/bundles/general/codebuddy/scripts/harness_integration.py +403 -18
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +225 -29
- package/harness/bundles/general/codebuddy/scripts/harness_phase.py +926 -0
- package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/general/codebuddy/scripts/harness_profile.py +50 -0
- package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +248 -0
- package/harness/bundles/general/codebuddy/scripts/harness_state.py +15 -2
- package/harness/bundles/general/codebuddy/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/general/codebuddy/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/general/codex/contracts/workflow-policy.json +30 -0
- package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-plan/SKILL.md +4 -4
- package/harness/bundles/general/codex/harness-plan/checklist.md +6 -0
- package/harness/bundles/general/codex/harness-plan/reference.md +7 -2
- package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/checklist.md +3 -2
- package/harness/bundles/general/codex/harness-run/reference.md +6 -4
- package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codex/scripts/harness_archive.py +282 -120
- package/harness/bundles/general/codex/scripts/harness_events.py +400 -24
- package/harness/bundles/general/codex/scripts/harness_gate.py +585 -21
- package/harness/bundles/general/codex/scripts/harness_integration.py +403 -18
- package/harness/bundles/general/codex/scripts/harness_ledger.py +225 -29
- package/harness/bundles/general/codex/scripts/harness_phase.py +926 -0
- package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/general/codex/scripts/harness_profile.py +50 -0
- package/harness/bundles/general/codex/scripts/harness_runtime.py +248 -0
- package/harness/bundles/general/codex/scripts/harness_state.py +15 -2
- package/harness/bundles/general/codex/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/general/codex/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/general/cursor/contracts/workflow-policy.json +30 -0
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +4 -4
- package/harness/bundles/general/cursor/harness-plan/checklist.md +6 -0
- package/harness/bundles/general/cursor/harness-plan/reference.md +7 -2
- package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/checklist.md +3 -2
- package/harness/bundles/general/cursor/harness-run/reference.md +6 -4
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/cursor/scripts/harness_archive.py +282 -120
- package/harness/bundles/general/cursor/scripts/harness_events.py +400 -24
- package/harness/bundles/general/cursor/scripts/harness_gate.py +585 -21
- package/harness/bundles/general/cursor/scripts/harness_integration.py +403 -18
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +225 -29
- package/harness/bundles/general/cursor/scripts/harness_phase.py +926 -0
- package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/general/cursor/scripts/harness_profile.py +50 -0
- package/harness/bundles/general/cursor/scripts/harness_runtime.py +248 -0
- package/harness/bundles/general/cursor/scripts/harness_state.py +15 -2
- package/harness/bundles/general/cursor/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/general/cursor/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/java/claude-code/contracts/workflow-policy.json +30 -0
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +4 -4
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +6 -0
- package/harness/bundles/java/claude-code/harness-plan/reference.md +7 -2
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-submit/SKILL.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 +1 -1
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +282 -120
- package/harness/bundles/java/claude-code/scripts/harness_events.py +400 -24
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +585 -21
- package/harness/bundles/java/claude-code/scripts/harness_integration.py +403 -18
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +225 -29
- package/harness/bundles/java/claude-code/scripts/harness_phase.py +926 -0
- package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/java/claude-code/scripts/harness_profile.py +50 -0
- package/harness/bundles/java/claude-code/scripts/harness_runtime.py +248 -0
- package/harness/bundles/java/claude-code/scripts/harness_state.py +15 -2
- package/harness/bundles/java/claude-code/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/java/claude-code/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/java/codebuddy/contracts/workflow-policy.json +30 -0
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +4 -4
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +6 -0
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +7 -2
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +282 -120
- package/harness/bundles/java/codebuddy/scripts/harness_events.py +400 -24
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +585 -21
- package/harness/bundles/java/codebuddy/scripts/harness_integration.py +403 -18
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +225 -29
- package/harness/bundles/java/codebuddy/scripts/harness_phase.py +926 -0
- package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/java/codebuddy/scripts/harness_profile.py +50 -0
- package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +248 -0
- package/harness/bundles/java/codebuddy/scripts/harness_state.py +15 -2
- package/harness/bundles/java/codebuddy/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/java/codebuddy/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/java/codex/contracts/workflow-policy.json +30 -0
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-plan/SKILL.md +4 -4
- package/harness/bundles/java/codex/harness-plan/checklist.md +6 -0
- package/harness/bundles/java/codex/harness-plan/reference.md +7 -2
- package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codex/scripts/harness_archive.py +282 -120
- package/harness/bundles/java/codex/scripts/harness_events.py +400 -24
- package/harness/bundles/java/codex/scripts/harness_gate.py +585 -21
- package/harness/bundles/java/codex/scripts/harness_integration.py +403 -18
- package/harness/bundles/java/codex/scripts/harness_ledger.py +225 -29
- package/harness/bundles/java/codex/scripts/harness_phase.py +926 -0
- package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/java/codex/scripts/harness_profile.py +50 -0
- package/harness/bundles/java/codex/scripts/harness_runtime.py +248 -0
- package/harness/bundles/java/codex/scripts/harness_state.py +15 -2
- package/harness/bundles/java/codex/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/java/codex/scripts/harness_workflow_policy.py +19 -0
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/contracts/ci-metrics.schema.json +36 -0
- package/harness/bundles/java/cursor/contracts/workflow-policy.json +30 -0
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +4 -4
- package/harness/bundles/java/cursor/harness-plan/checklist.md +6 -0
- package/harness/bundles/java/cursor/harness-plan/reference.md +7 -2
- package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/cursor/scripts/harness_archive.py +282 -120
- package/harness/bundles/java/cursor/scripts/harness_events.py +400 -24
- package/harness/bundles/java/cursor/scripts/harness_gate.py +585 -21
- package/harness/bundles/java/cursor/scripts/harness_integration.py +403 -18
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +225 -29
- package/harness/bundles/java/cursor/scripts/harness_phase.py +926 -0
- package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +361 -0
- package/harness/bundles/java/cursor/scripts/harness_profile.py +50 -0
- package/harness/bundles/java/cursor/scripts/harness_runtime.py +248 -0
- package/harness/bundles/java/cursor/scripts/harness_state.py +15 -2
- package/harness/bundles/java/cursor/scripts/harness_test_guard.py +188 -0
- package/harness/bundles/java/cursor/scripts/harness_workflow_policy.py +19 -0
- package/harness/manifests/general/claude-code.json +42 -26
- package/harness/manifests/general/codebuddy.json +42 -26
- package/harness/manifests/general/codex.json +42 -26
- package/harness/manifests/general/cursor.json +42 -26
- package/harness/manifests/java/claude-code.json +42 -26
- package/harness/manifests/java/codebuddy.json +42 -26
- package/harness/manifests/java/codex.json +42 -26
- package/harness/manifests/java/cursor.json +42 -26
- package/hunter-workflow-family.json +2 -2
- package/package.json +1 -1
|
@@ -266,6 +266,8 @@ def capture_current_state(
|
|
|
266
266
|
segment_files=files,
|
|
267
267
|
)
|
|
268
268
|
changed: list[str] = []
|
|
269
|
+
baseline_created = previous is None
|
|
270
|
+
unresolved: list[str] = []
|
|
269
271
|
if previous:
|
|
270
272
|
old_segments = previous.get("segments") or {}
|
|
271
273
|
for name, segment in fresh["segments"].items():
|
|
@@ -275,7 +277,12 @@ def capture_current_state(
|
|
|
275
277
|
else:
|
|
276
278
|
changed.append(name)
|
|
277
279
|
else:
|
|
278
|
-
|
|
280
|
+
# A first observation establishes the baseline; it is not evidence
|
|
281
|
+
# that every segment changed during the current phase.
|
|
282
|
+
unresolved = sorted(fresh["segments"])
|
|
283
|
+
fresh["baselineCreated"] = baseline_created
|
|
284
|
+
fresh["changedSegments"] = sorted(changed)
|
|
285
|
+
fresh["unresolvedSegments"] = unresolved
|
|
279
286
|
write_snapshot(change_dir, fresh)
|
|
280
287
|
return fresh, changed
|
|
281
288
|
|
|
@@ -312,7 +319,13 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
312
319
|
"ok": True,
|
|
313
320
|
"path": str(snapshot_path(change_dir)),
|
|
314
321
|
"changedSegments": changed,
|
|
315
|
-
"reusedSegments": sorted(
|
|
322
|
+
"reusedSegments": sorted(
|
|
323
|
+
set(snapshot["segments"])
|
|
324
|
+
- set(changed)
|
|
325
|
+
- set(snapshot.get("unresolvedSegments") or [])
|
|
326
|
+
),
|
|
327
|
+
"baselineCreated": bool(snapshot.get("baselineCreated")),
|
|
328
|
+
"unresolvedSegments": list(snapshot.get("unresolvedSegments") or []),
|
|
316
329
|
"git": snapshot["git"],
|
|
317
330
|
}
|
|
318
331
|
if args.json:
|
|
@@ -564,6 +564,159 @@ def record(
|
|
|
564
564
|
return _result(True, action, "RECORDED", [rel for _, rel in validated], manifestPath=str(manifest_path))
|
|
565
565
|
|
|
566
566
|
|
|
567
|
+
def rehome(
|
|
568
|
+
from_project: Path | str,
|
|
569
|
+
to_project: Path | str,
|
|
570
|
+
change_dir: Path | str,
|
|
571
|
+
expected_head: str,
|
|
572
|
+
) -> dict[str, Any]:
|
|
573
|
+
"""Atomically hand test ownership from a merged feature worktree to target."""
|
|
574
|
+
action = "rehome"
|
|
575
|
+
from_root = Path(from_project).resolve()
|
|
576
|
+
to_root = Path(to_project).resolve()
|
|
577
|
+
if not from_root.is_dir() or not to_root.is_dir():
|
|
578
|
+
return _result(False, action, "PROJECT_ROOT_MISSING", [])
|
|
579
|
+
if harness_paths.repository_identity(from_root) != harness_paths.repository_identity(to_root):
|
|
580
|
+
return _result(False, action, "REPOSITORY_MISMATCH", [])
|
|
581
|
+
to_head_result = _git(to_root, "rev-parse", "--verify", "HEAD")
|
|
582
|
+
to_head = to_head_result.stdout.strip() if to_head_result.returncode == 0 else ""
|
|
583
|
+
if not expected_head or to_head != expected_head:
|
|
584
|
+
return _result(
|
|
585
|
+
False, action, "EXPECTED_HEAD_MISMATCH", [],
|
|
586
|
+
expectedHead=expected_head, actualHead=to_head,
|
|
587
|
+
)
|
|
588
|
+
from_head_result = _git(from_root, "rev-parse", "--verify", "HEAD")
|
|
589
|
+
from_head = from_head_result.stdout.strip() if from_head_result.returncode == 0 else ""
|
|
590
|
+
from_tree_result = _git(from_root, "rev-parse", "HEAD^{tree}")
|
|
591
|
+
to_tree_result = _git(to_root, "rev-parse", f"{expected_head}^{{tree}}")
|
|
592
|
+
from_tree = from_tree_result.stdout.strip() if from_tree_result.returncode == 0 else ""
|
|
593
|
+
to_tree = to_tree_result.stdout.strip() if to_tree_result.returncode == 0 else ""
|
|
594
|
+
if not from_tree or from_tree != to_tree:
|
|
595
|
+
return _result(
|
|
596
|
+
False, action, "TREE_MISMATCH", [],
|
|
597
|
+
fromHead=from_head, toHead=to_head, fromTree=from_tree, toTree=to_tree,
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
change_root = _change_dir(from_root, change_dir)
|
|
601
|
+
if change_root is None:
|
|
602
|
+
return _result(False, action, "CHANGE_DIR_OUTSIDE_PROJECT", [])
|
|
603
|
+
manifest_path = _manifest_path(change_root)
|
|
604
|
+
if manifest_path is None:
|
|
605
|
+
return _result(False, action, "MANIFEST_PATH_OUTSIDE_PROJECT", [])
|
|
606
|
+
lock_path = manifest_path.with_name(manifest_path.name + ".lock")
|
|
607
|
+
try:
|
|
608
|
+
with _exclusive_lock(lock_path, wait_seconds=5.0):
|
|
609
|
+
try:
|
|
610
|
+
manifest = _read_json(manifest_path)
|
|
611
|
+
except FileNotFoundError:
|
|
612
|
+
return _result(False, action, "MANIFEST_MISSING", [])
|
|
613
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
614
|
+
return _result(False, action, "MANIFEST_INVALID", [], error=str(exc))
|
|
615
|
+
is_v2 = isinstance(manifest, dict) and manifest.get("schemaVersion") == 2
|
|
616
|
+
entries = manifest.get("files") if isinstance(manifest, dict) else None
|
|
617
|
+
if not isinstance(entries, list):
|
|
618
|
+
return _result(False, action, "MANIFEST_INVALID", [])
|
|
619
|
+
if not is_v2 and (
|
|
620
|
+
manifest.get("schemaVersion") != SCHEMA_VERSION
|
|
621
|
+
or manifest.get("mode") != MODE
|
|
622
|
+
or manifest.get("projectRoot") != str(from_root)
|
|
623
|
+
):
|
|
624
|
+
return _result(False, action, "MANIFEST_PROJECT_MISMATCH", [])
|
|
625
|
+
if is_v2:
|
|
626
|
+
error, validated = _validate_existing_manifest_v2(
|
|
627
|
+
from_root, manifest, require_files=False
|
|
628
|
+
)
|
|
629
|
+
if error:
|
|
630
|
+
return _result(False, action, error, [])
|
|
631
|
+
else:
|
|
632
|
+
validated: dict[str, dict[str, Any]] = {}
|
|
633
|
+
for item in entries:
|
|
634
|
+
if not _entry_shape_valid(item):
|
|
635
|
+
return _result(False, action, "MANIFEST_INVALID", [])
|
|
636
|
+
rel = item["path"]
|
|
637
|
+
source, normalized, error = _validate_file(from_root, rel)
|
|
638
|
+
if error or normalized != rel or source is None:
|
|
639
|
+
return _result(False, action, error or "MANIFEST_INVALID", [rel])
|
|
640
|
+
if item["sha256"] != _sha256(source):
|
|
641
|
+
return _result(False, action, "HASH_DRIFT", [rel])
|
|
642
|
+
validated[rel] = dict(item)
|
|
643
|
+
|
|
644
|
+
updated = json.loads(json.dumps(manifest))
|
|
645
|
+
updated_entries: list[dict[str, Any]] = []
|
|
646
|
+
for rel, item in sorted(validated.items()):
|
|
647
|
+
target, normalized, error = _validate_file(to_root, rel)
|
|
648
|
+
if error or normalized != rel or target is None:
|
|
649
|
+
return _result(False, action, "TARGET_CONTENT_MISMATCH", [rel])
|
|
650
|
+
replacement = dict(item)
|
|
651
|
+
if is_v2:
|
|
652
|
+
digest = logical_file_hash(to_root, rel)
|
|
653
|
+
source_digest = item.get("logicalHash") or item.get("binaryHash")
|
|
654
|
+
if digest != source_digest:
|
|
655
|
+
return _result(False, action, "TARGET_CONTENT_MISMATCH", [rel])
|
|
656
|
+
replacement["logicalHash"] = digest
|
|
657
|
+
replacement["binaryHash"] = (
|
|
658
|
+
None if digest.startswith("gitblob:") else digest
|
|
659
|
+
)
|
|
660
|
+
replacement["ignored"] = _is_ignored(to_root, rel)
|
|
661
|
+
else:
|
|
662
|
+
digest = _sha256(target)
|
|
663
|
+
if digest != item["sha256"]:
|
|
664
|
+
return _result(False, action, "TARGET_CONTENT_MISMATCH", [rel])
|
|
665
|
+
replacement["sha256"] = digest
|
|
666
|
+
replacement["ignored"] = _is_ignored(to_root, rel)
|
|
667
|
+
replacement["trackedBefore"] = (
|
|
668
|
+
_git(to_root, "ls-files", "--error-unmatch", "--", rel).returncode == 0
|
|
669
|
+
)
|
|
670
|
+
updated_entries.append(replacement)
|
|
671
|
+
|
|
672
|
+
before_hash = _sha256(manifest_path)
|
|
673
|
+
handoff_at = time.strftime("%Y-%m-%dT%H:%M:%S")
|
|
674
|
+
handoff_id = "handoff-" + hashlib.sha256(
|
|
675
|
+
f"{from_root}\0{to_root}\0{from_head}\0{to_head}".encode("utf-8")
|
|
676
|
+
).hexdigest()[:20]
|
|
677
|
+
handoffs = updated.get("handoffs")
|
|
678
|
+
if handoffs is None:
|
|
679
|
+
handoffs = []
|
|
680
|
+
if not isinstance(handoffs, list):
|
|
681
|
+
return _result(False, action, "MANIFEST_INVALID", [])
|
|
682
|
+
handoff = {
|
|
683
|
+
"id": handoff_id,
|
|
684
|
+
"fromRoot": str(from_root),
|
|
685
|
+
"toRoot": str(to_root),
|
|
686
|
+
"fromHead": from_head,
|
|
687
|
+
"toHead": to_head,
|
|
688
|
+
"expectedHead": expected_head,
|
|
689
|
+
"treeHash": to_tree,
|
|
690
|
+
"at": handoff_at,
|
|
691
|
+
"manifestHashBefore": before_hash,
|
|
692
|
+
}
|
|
693
|
+
if not any(isinstance(item, dict) and item.get("id") == handoff_id for item in handoffs):
|
|
694
|
+
handoffs.append(handoff)
|
|
695
|
+
updated["files"] = updated_entries
|
|
696
|
+
updated["projectRoot"] = str(to_root)
|
|
697
|
+
updated["head"] = to_head
|
|
698
|
+
updated["handoffs"] = handoffs
|
|
699
|
+
_write_json(manifest_path, updated)
|
|
700
|
+
after_hash = _sha256(manifest_path)
|
|
701
|
+
except LockUnavailable:
|
|
702
|
+
return _result(False, action, "MANIFEST_LOCKED", [])
|
|
703
|
+
return _result(
|
|
704
|
+
True,
|
|
705
|
+
action,
|
|
706
|
+
"REHOMED",
|
|
707
|
+
sorted(validated),
|
|
708
|
+
fromRoot=str(from_root),
|
|
709
|
+
toRoot=str(to_root),
|
|
710
|
+
fromHead=from_head,
|
|
711
|
+
toHead=to_head,
|
|
712
|
+
treeHash=to_tree,
|
|
713
|
+
handoffId=handoff_id,
|
|
714
|
+
manifestHashBefore=before_hash,
|
|
715
|
+
manifestHashAfter=after_hash,
|
|
716
|
+
manifestPath=str(manifest_path),
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
567
720
|
def _stage_locked(
|
|
568
721
|
project_root: Path, change_root: Path, manifest_path: Path, index_path: Path
|
|
569
722
|
) -> dict[str, Any]:
|
|
@@ -709,6 +862,31 @@ def begin(project: Path | str, change_dir: Path | str) -> dict[str, Any]:
|
|
|
709
862
|
if not _manifest_target_inside(change_root, snapshot_path):
|
|
710
863
|
return _result(False, action, "SNAPSHOT_PATH_OUTSIDE_PROJECT", [])
|
|
711
864
|
|
|
865
|
+
if snapshot_path.is_file():
|
|
866
|
+
try:
|
|
867
|
+
snapshot = _read_json(snapshot_path)
|
|
868
|
+
except (OSError, json.JSONDecodeError) as exc:
|
|
869
|
+
return _result(False, action, "SNAPSHOT_INVALID", [], error=str(exc))
|
|
870
|
+
entries = snapshot.get("files") if isinstance(snapshot, dict) else None
|
|
871
|
+
if (
|
|
872
|
+
not isinstance(snapshot, dict)
|
|
873
|
+
or snapshot.get("schemaVersion") != SCHEMA_VERSION
|
|
874
|
+
or snapshot.get("mode") != MODE
|
|
875
|
+
or snapshot.get("projectRoot") != str(project_root)
|
|
876
|
+
or not isinstance(entries, list)
|
|
877
|
+
or any(not isinstance(item, dict) or not isinstance(item.get("path"), str)
|
|
878
|
+
for item in entries)
|
|
879
|
+
):
|
|
880
|
+
return _result(False, action, "SNAPSHOT_INVALID", [])
|
|
881
|
+
return _result(
|
|
882
|
+
True,
|
|
883
|
+
action,
|
|
884
|
+
"SNAPSHOT_REUSED",
|
|
885
|
+
[item["path"] for item in entries],
|
|
886
|
+
snapshotPath=str(snapshot_path),
|
|
887
|
+
fileCount=len(entries),
|
|
888
|
+
)
|
|
889
|
+
|
|
712
890
|
files = _enumerate_allowed_test_files(project_root)
|
|
713
891
|
snapshot = {
|
|
714
892
|
"schemaVersion": SCHEMA_VERSION,
|
|
@@ -867,6 +1045,12 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
867
1045
|
close_parser.add_argument("--project", required=True)
|
|
868
1046
|
close_parser.add_argument("--change-dir", required=True)
|
|
869
1047
|
close_parser.add_argument("--json", action="store_true")
|
|
1048
|
+
rehome_parser = sub.add_parser("rehome")
|
|
1049
|
+
rehome_parser.add_argument("--from", dest="from_project", required=True)
|
|
1050
|
+
rehome_parser.add_argument("--to", dest="to_project", required=True)
|
|
1051
|
+
rehome_parser.add_argument("--change-dir", required=True)
|
|
1052
|
+
rehome_parser.add_argument("--expected-head", required=True)
|
|
1053
|
+
rehome_parser.add_argument("--json", action="store_true")
|
|
870
1054
|
mark_parser = sub.add_parser("mark")
|
|
871
1055
|
mark_parser.add_argument("--project", required=True)
|
|
872
1056
|
mark_parser.add_argument("--change-dir", required=True)
|
|
@@ -883,6 +1067,10 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
883
1067
|
elif args.action == "mark":
|
|
884
1068
|
files = [item.strip() for item in args.files.split(",") if item.strip()]
|
|
885
1069
|
result = mark(args.project, args.change_dir, files)
|
|
1070
|
+
elif args.action == "rehome":
|
|
1071
|
+
result = rehome(
|
|
1072
|
+
args.from_project, args.to_project, args.change_dir, args.expected_head
|
|
1073
|
+
)
|
|
886
1074
|
else:
|
|
887
1075
|
result = stage(args.project, args.change_dir)
|
|
888
1076
|
print(json.dumps(result, ensure_ascii=False, indent=2 if args.json else None))
|
|
@@ -19,6 +19,8 @@ TOP_LEVEL_KEYS = frozenset(
|
|
|
19
19
|
"skills",
|
|
20
20
|
"requiredArtifacts",
|
|
21
21
|
"requiredValidations",
|
|
22
|
+
"validationPhases",
|
|
23
|
+
"capabilityGates",
|
|
22
24
|
"conditionalStages",
|
|
23
25
|
"interactionWhitelist",
|
|
24
26
|
"checkpointRules",
|
|
@@ -48,6 +50,9 @@ SKILL_KEYS = frozenset(
|
|
|
48
50
|
)
|
|
49
51
|
|
|
50
52
|
CONDITIONAL_STAGE_KEYS = frozenset({"tiers", "signals"})
|
|
53
|
+
CAPABILITY_GATE_KEYS = frozenset(
|
|
54
|
+
{"signals", "requiredStages", "requiredValidations"}
|
|
55
|
+
)
|
|
51
56
|
CHECKPOINT_RULE_KEYS = frozenset(
|
|
52
57
|
{
|
|
53
58
|
"afterTasks",
|
|
@@ -121,6 +126,20 @@ def validate_policy(data: Any) -> dict[str, Any]:
|
|
|
121
126
|
for phase, items in section_data.items():
|
|
122
127
|
_require_type(items, list, f"{section}.{phase}")
|
|
123
128
|
|
|
129
|
+
validation_phases = data["validationPhases"]
|
|
130
|
+
_require_type(validation_phases, dict, "validationPhases")
|
|
131
|
+
for verification, phase in validation_phases.items():
|
|
132
|
+
_require_type(phase, str, f"validationPhases.{verification}")
|
|
133
|
+
|
|
134
|
+
capability_gates = data["capabilityGates"]
|
|
135
|
+
_require_type(capability_gates, dict, "capabilityGates")
|
|
136
|
+
for capability, gate in capability_gates.items():
|
|
137
|
+
path = f"capabilityGates.{capability}"
|
|
138
|
+
_require_type(gate, dict, path)
|
|
139
|
+
_reject_unknown(gate, CAPABILITY_GATE_KEYS, path)
|
|
140
|
+
for key in CAPABILITY_GATE_KEYS:
|
|
141
|
+
_require_type(gate[key], list, f"{path}.{key}")
|
|
142
|
+
|
|
124
143
|
conditional = data["conditionalStages"]
|
|
125
144
|
_require_type(conditional, dict, "conditionalStages")
|
|
126
145
|
for stage_name, stage in conditional.items():
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://hunter-harness.dev/contracts/ci-metrics.schema.json",
|
|
4
|
+
"title": "Hunter Harness CI Metrics",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"schemaVersion",
|
|
9
|
+
"runner",
|
|
10
|
+
"source",
|
|
11
|
+
"suites",
|
|
12
|
+
"passed",
|
|
13
|
+
"failed",
|
|
14
|
+
"skipped",
|
|
15
|
+
"setupErrors",
|
|
16
|
+
"durationMs",
|
|
17
|
+
"headSha"
|
|
18
|
+
],
|
|
19
|
+
"properties": {
|
|
20
|
+
"schemaVersion": { "const": 1 },
|
|
21
|
+
"runner": { "enum": ["junit", "vitest", "playwright"] },
|
|
22
|
+
"source": { "type": ["string", "null"] },
|
|
23
|
+
"suites": { "type": ["integer", "null"], "minimum": 0 },
|
|
24
|
+
"passed": { "type": ["integer", "null"], "minimum": 0 },
|
|
25
|
+
"failed": { "type": ["integer", "null"], "minimum": 0 },
|
|
26
|
+
"skipped": { "type": ["integer", "null"], "minimum": 0 },
|
|
27
|
+
"setupErrors": { "type": ["integer", "null"], "minimum": 0 },
|
|
28
|
+
"durationMs": { "type": ["integer", "null"], "minimum": 0 },
|
|
29
|
+
"headSha": {
|
|
30
|
+
"anyOf": [
|
|
31
|
+
{ "type": "null" },
|
|
32
|
+
{ "type": "string", "pattern": "^[0-9a-f]{40}([0-9a-f]{24})?$" }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -138,6 +138,36 @@
|
|
|
138
138
|
"submit": [],
|
|
139
139
|
"package": ["package"]
|
|
140
140
|
},
|
|
141
|
+
"validationPhases": {
|
|
142
|
+
"compile": "run",
|
|
143
|
+
"unitTest": "run",
|
|
144
|
+
"unitTestFull": "test",
|
|
145
|
+
"apiTest": "test",
|
|
146
|
+
"dbCompatibility": "test",
|
|
147
|
+
"package": "package"
|
|
148
|
+
},
|
|
149
|
+
"capabilityGates": {
|
|
150
|
+
"deployment": {
|
|
151
|
+
"signals": ["deploy-required"],
|
|
152
|
+
"requiredStages": ["package"],
|
|
153
|
+
"requiredValidations": ["package"]
|
|
154
|
+
},
|
|
155
|
+
"container": {
|
|
156
|
+
"signals": ["install-verification"],
|
|
157
|
+
"requiredStages": ["package"],
|
|
158
|
+
"requiredValidations": ["package"]
|
|
159
|
+
},
|
|
160
|
+
"api": {
|
|
161
|
+
"signals": ["api-diff-present"],
|
|
162
|
+
"requiredStages": ["apidoc"],
|
|
163
|
+
"requiredValidations": ["apiTest"]
|
|
164
|
+
},
|
|
165
|
+
"database": {
|
|
166
|
+
"signals": ["migration"],
|
|
167
|
+
"requiredStages": [],
|
|
168
|
+
"requiredValidations": ["dbCompatibility"]
|
|
169
|
+
}
|
|
170
|
+
},
|
|
141
171
|
"conditionalStages": {
|
|
142
172
|
"review": {
|
|
143
173
|
"tiers": ["standard", "full"],
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-apidoc — 前端接口文档(Java overlay)
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-archive — 变更归档
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-codebase-map — 代码库地图
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-knowledge-ingest
|
|
25
25
|
|
|
26
26
|
从 `.harness/archive/**/reports/final/summary-data.json` 抽取项目知识,生成并维护本地 `.harness/knowledge/` 索引。
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-knowledge-query
|
|
25
25
|
|
|
26
26
|
并行 change 中查询必须传 `--change <change-id>`;成功后以该 change 的 `meta/knowledge-context.json` 为稳定指针。全局 `context-packs/latest.json` 仅向后兼容,不得用于判断多个 active change 的上下文归属。
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-package — 增量模块打包(Java overlay)
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-plan — 需求规划
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -76,7 +76,7 @@ disallowed-tools:
|
|
|
76
76
|
|
|
77
77
|
| 阶段 | 动作 |
|
|
78
78
|
|------|------|
|
|
79
|
-
| 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问 |
|
|
79
|
+
| 0 | 用当前解释器运行 `harness_runtime.py doctor`,后续消费绝对 argv;git status;脏工作区 → baseline 隔离 + `decision`,不询问 |
|
|
80
80
|
| 0.5 | 先初始化 change-name + `phase.start`,从第一条知识查询起保留事件证据 |
|
|
81
81
|
| 1 | `harness-knowledge-query` 单次 query(内部 ensure-current;失败记 `issue`) |
|
|
82
82
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
@@ -84,7 +84,7 @@ disallowed-tools:
|
|
|
84
84
|
| 4 | **设计审批包** AskUserQuestion;确认事件早于 approved 设计文档和 `meta/worktree.json` |
|
|
85
85
|
| 5–6 | plan + implementation-detail + test-scenarios → `plans/` |
|
|
86
86
|
| 7.5 | 仅 `--adversarial` 对抗评审 |
|
|
87
|
-
| 8 |
|
|
87
|
+
| 8 | 在临时产物集上运行 `harness_plan_finalize.py finalize`;原子发布、唯一 `phase.end`、render → `checklist.md` |
|
|
88
88
|
|
|
89
89
|
change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`)
|
|
90
90
|
|
|
@@ -100,7 +100,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
100
100
|
|------|------|
|
|
101
101
|
| 产物路径 | 只写 `.harness/changes/<cn>/`;禁止 superpowers 输入 |
|
|
102
102
|
| 设计审批包 | 一次 AskUserQuestion 含 worktree(读 `harness.json` `defaultWorktree`) |
|
|
103
|
-
| 阶段 8 | spec/plan/detail/scenarios/worktree.json
|
|
103
|
+
| 阶段 8 | spec/plan/detail/scenarios/worktree.json 先进入 staging;仅 finalizer 校验成功后发布并写唯一 `phase.end`/log,失败不得手工补终态 |
|
|
104
104
|
| Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
|
|
105
105
|
| 知识查询 | 0.5 失败不得假装已读历史 |
|
|
106
106
|
| 歧义优先检查 | 否定、对比、动作对象或范围存在多种合理解释时,最小取证后先给推荐理解并一次一问;确认前不深挖错误方向 |
|
|
@@ -213,6 +213,12 @@ source: harness-plan
|
|
|
213
213
|
|
|
214
214
|
> **缺任一文件 → ❌FAIL,不得宣称 plan 完成。**
|
|
215
215
|
|
|
216
|
+
- [ ] 所有待发布产物先写入 staging,不直接覆盖正式 change 目录
|
|
217
|
+
- [ ] 执行 `harness_plan_finalize.py finalize --change-dir ... --staging-dir ... --change ... --run-id ... --attempt ... --json`
|
|
218
|
+
- [ ] finalizer 返回 `ok=true` 与 `artifactsHash`;重复执行返回 `idempotent=true`
|
|
219
|
+
- [ ] finalizer 失败时正式目录无半发布产物、无成功 `phase.end`、无伪造 execution log
|
|
220
|
+
- [ ] 禁止在 finalizer 之前手工追加成功 `phase.end`
|
|
221
|
+
|
|
216
222
|
| 文件 | 必须存在 | 检查结果 |
|
|
217
223
|
|------|:---:|:---:|
|
|
218
224
|
| `.harness/changes/<change>/spec/<change>-design.md` | ✅ | □ |
|
|
@@ -14,8 +14,11 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
14
14
|
{
|
|
15
15
|
"requested": true,
|
|
16
16
|
"created": false,
|
|
17
|
-
"
|
|
18
|
-
"
|
|
17
|
+
"agent": "<active-adapter>",
|
|
18
|
+
"worktreeRoot": "<adapter-worktree-root>",
|
|
19
|
+
"branchPrefix": "<adapter-branch-prefix>",
|
|
20
|
+
"path": "<adapter-worktree-root>/<change-name>",
|
|
21
|
+
"branch": "<adapter-branch-prefix><change-name>",
|
|
19
22
|
"decisionBy": "user",
|
|
20
23
|
"decisionAt": "YYYY-MM-DD HH:mm",
|
|
21
24
|
"ownerSkill": "harness-run"
|
|
@@ -38,6 +41,8 @@ description: harness-plan 的需求提取模板、任务拆分规则、测试场
|
|
|
38
41
|
|
|
39
42
|
### 决策事件 note 示例
|
|
40
43
|
|
|
44
|
+
`path` 与 `branch` 必须来自 `harness_runtime.py adapter`/`meta/runtime.json`,不得复制其他 agent 的历史路径。Codex 的合同固定为 `.codex/worktrees/<change-name>` 与 `codex/<change-name>`。
|
|
45
|
+
|
|
41
46
|
`用户选择使用 Worktree;决策文件为 meta/worktree.json;requested=true, created=false;创建责任为 harness-run。`
|
|
42
47
|
|
|
43
48
|
## 参考 — 详细格式
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
- Bash(codegraph *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-review — 代码审查
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
- Bash(codegraph *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-run — 需求编码
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -19,7 +19,7 @@ disallowed-tools:
|
|
|
19
19
|
- Bash(awk *)
|
|
20
20
|
- Bash(curl *)
|
|
21
21
|
---
|
|
22
|
-
<!-- generated by harness_deploy.py; core=
|
|
22
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
23
23
|
# harness-sync — 元数据同步
|
|
24
24
|
|
|
25
25
|
## Purpose
|
|
@@ -22,7 +22,7 @@ disallowed-tools:
|
|
|
22
22
|
- Bash(node *)
|
|
23
23
|
- Bash(codegraph *)
|
|
24
24
|
---
|
|
25
|
-
<!-- generated by harness_deploy.py; core=
|
|
25
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-test — 测试执行
|
|
27
27
|
|
|
28
28
|
## Purpose
|