@hunter-harness/workflow-harness 0.2.11 → 0.2.13
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 +2 -2
- package/harness/bundles/general/claude-code/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/general/codebuddy/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/general/codex/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/general/cursor/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/java/claude-code/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/java/codebuddy/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/java/codex/harness-sync/reference.md +5 -4
- 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 +2 -2
- package/harness/bundles/java/cursor/harness-sync/reference.md +5 -4
- 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 +43 -27
- package/harness/manifests/general/codebuddy.json +43 -27
- package/harness/manifests/general/codex.json +43 -27
- package/harness/manifests/general/cursor.json +43 -27
- package/harness/manifests/java/claude-code.json +43 -27
- package/harness/manifests/java/codebuddy.json +43 -27
- package/harness/manifests/java/codex.json +43 -27
- package/harness/manifests/java/cursor.json +43 -27
- 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"],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-apidoc
|
|
3
3
|
description: 从 Java 后端代码生成结构化前端 API 文档(Controller/VO/ErrorCode)。使用场景:接口文档、前端接口文档、API 文档生成
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-apidoc — 前端接口文档(Java overlay)
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-archive
|
|
|
3
3
|
description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到
|
|
4
4
|
.harness/archive/,含归档元数据和可视化最终总结。使用场景:归档、完成归档、收尾、打包产出物
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-archive — 变更归档
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-codebase-map
|
|
|
3
3
|
description: 分析现有代码库并生成 .harness/codebase/map/
|
|
4
4
|
下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-codebase-map — 代码库地图
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-knowledge-ingest
|
|
|
3
3
|
description: 从 .harness/archive 归档整理、同步和维护项目知识索引。适用场景:ingest knowledge、sync
|
|
4
4
|
knowledge、rebuild knowledge index、promote knowledge、确认知识条目、检查知识库是否过期。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-knowledge-ingest
|
|
8
8
|
|
|
9
9
|
从 `.harness/archive/**/reports/final/summary-data.json` 抽取项目知识,生成并维护本地 `.harness/knowledge/` 索引。
|
|
@@ -3,7 +3,7 @@ name: harness-knowledge-query
|
|
|
3
3
|
description: 根据新需求、设计任务、代码修改请求或问题排查,在规划和编码前查询 .harness/knowledge
|
|
4
4
|
历史上下文。适用场景:query knowledge、查找历史需求、根据归档理解需求、继续之前类似开发、生成需求上下文包。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-knowledge-query
|
|
8
8
|
|
|
9
9
|
并行 change 中查询必须传 `--change <change-id>`;成功后以该 change 的 `meta/knowledge-context.json` 为稳定指针。全局 `context-packs/latest.json` 仅向后兼容,不得用于判断多个 active change 的上下文归属。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-package
|
|
3
3
|
description: 增量模块打包:拉取最新→编译验证→mvn package→汇总 jar/war。使用场景:打包、package、发版准备
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-package — 增量模块打包(Java overlay)
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-plan
|
|
3
3
|
description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。使用场景:需求分析、feature plan、技术方案设计、实现方案规划
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-plan — 需求规划
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -58,7 +58,7 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
|
|
|
58
58
|
|
|
59
59
|
| 阶段 | 动作 |
|
|
60
60
|
|------|------|
|
|
61
|
-
| 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问 |
|
|
61
|
+
| 0 | 用当前解释器运行 `harness_runtime.py doctor`,后续消费绝对 argv;git status;脏工作区 → baseline 隔离 + `decision`,不询问 |
|
|
62
62
|
| 0.5 | 先初始化 change-name + `phase.start`,从第一条知识查询起保留事件证据 |
|
|
63
63
|
| 1 | `harness-knowledge-query` 单次 query(内部 ensure-current;失败记 `issue`) |
|
|
64
64
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
@@ -66,7 +66,7 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
|
|
|
66
66
|
| 4 | **设计审批包** AskUserQuestion;确认事件早于 approved 设计文档和 `meta/worktree.json` |
|
|
67
67
|
| 5–6 | plan + implementation-detail + test-scenarios → `plans/` |
|
|
68
68
|
| 7.5 | 仅 `--adversarial` 对抗评审 |
|
|
69
|
-
| 8 |
|
|
69
|
+
| 8 | 在临时产物集上运行 `harness_plan_finalize.py finalize`;原子发布、唯一 `phase.end`、render → `checklist.md` |
|
|
70
70
|
|
|
71
71
|
change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`)
|
|
72
72
|
|
|
@@ -82,7 +82,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
82
82
|
|------|------|
|
|
83
83
|
| 产物路径 | 只写 `.harness/changes/<cn>/`;禁止 superpowers 输入 |
|
|
84
84
|
| 设计审批包 | 一次 AskUserQuestion 含 worktree(读 `harness.json` `defaultWorktree`) |
|
|
85
|
-
| 阶段 8 | spec/plan/detail/scenarios/worktree.json
|
|
85
|
+
| 阶段 8 | spec/plan/detail/scenarios/worktree.json 先进入 staging;仅 finalizer 校验成功后发布并写唯一 `phase.end`/log,失败不得手工补终态 |
|
|
86
86
|
| Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
|
|
87
87
|
| 知识查询 | 0.5 失败不得假装已读历史 |
|
|
88
88
|
| 歧义优先检查 | 否定、对比、动作对象或范围存在多种合理解释时,最小取证后先给推荐理解并一次一问;确认前不深挖错误方向 |
|
|
@@ -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
|
## 参考 — 详细格式
|
|
@@ -3,7 +3,7 @@ name: harness-review
|
|
|
3
3
|
description: 6维度代码审查(架构/安全/规范/兼容/测试/性能),对照项目规则(见
|
|
4
4
|
.harness/context-index.json)和测试场景表,在隔离上下文运行。使用场景:代码审查、提交前检查、合并评审
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-review — 代码审查
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-run
|
|
3
3
|
description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编译验证),逐变更簇实现计划中的任务。使用场景:开始编码、实现功能、写代码、TDD 编码
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-run — 需求编码
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -3,7 +3,7 @@ name: harness-submit
|
|
|
3
3
|
description: 最终提交封装:验证→中文 commit→提交/推送;worktree 模式含 --no-ff
|
|
4
4
|
合并回主分支。使用场景:提交代码、commit、push、合并分支、merge to main、完成开发
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
7
7
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-sync
|
|
3
3
|
description: 检查并更新项目AI元数据(CodeGraph索引、harness-codebase-map分析、CLAUDE.md、AGENTS.md、.harness/完整性),确保Claude对代码库的理解与最新代码一致。当用户说'同步/更新索引/刷新元数据/检查一致性'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-sync — 元数据同步
|
|
7
7
|
|
|
8
8
|
## Purpose
|
|
@@ -39,7 +39,7 @@ python <skills-root>/scripts/harness_sync.py finalize --project . --run-id <run-
|
|
|
39
39
|
| 3.5 | `harness_knowledge.py sync`;可 `sync --update`;失败不得假装可用。**知识闭环主入口**是 `/harness-knowledge-ingest auto`(含 Agent judge),sync 不重复列人工知识待办 |
|
|
40
40
|
| 3.6 | 单次运行 `harness_knowledge.py maintain --project . --drain --json`,有界推进全部 `.harness/knowledge/maintenance-outbox/{pending,failed}`;不得为每个条目重复启动 Python/重建索引(§8.2:archive close 只 enqueue,sync 异步推进 outbox 到 completed/pending-judge) |
|
|
41
41
|
| 4 | CLAUDE.md 完整性/行数 → 超限 AskUserQuestion 瘦身 |
|
|
42
|
-
| 5 | AGENTS.md
|
|
42
|
+
| 5 | AGENTS.md 与各 Agent 指令入口一致;Claude Code 启用时验证 CLAUDE.md 引用 AGENTS.md,禁止反向循环引用 |
|
|
43
43
|
| 6 | `.harness/` 结构(init 规程 → `reference.md` 第 6 步);已装 skill 新鲜度只经 `hunter-harness refresh --dry-run --json` 的 post-adaptation freshness 判断,禁止 raw build 字节比较 |
|
|
44
44
|
| 7–9 | `项目规则(见 .harness/context-index.json)/`、构建配置、测试目录 — **只提示不自动修复** |
|
|
45
45
|
|
|
@@ -19,16 +19,17 @@ powershell.exe -Command "git -C '<项目路径>' diff --stat HEAD~5 2>$null"
|
|
|
19
19
|
|
|
20
20
|
### 2. CodeGraph 索引
|
|
21
21
|
|
|
22
|
-
检查索引状态,**优先使用 MCP
|
|
22
|
+
检查索引状态,**优先使用 MCP 工具**:若当前环境提供 `mcp__codegraph__codegraph_status` 则调用;没有 status 工具但提供 `codegraph_explore` 时,执行一次只读查询验证索引确实可响应,再用 Glob 比对 `.codegraph/` 目录修改时间与最近提交时间。两种 MCP 工具都不可用时才仅按时间戳降级。不允许通过普通 Bash 调 codegraph 命令:
|
|
23
23
|
|
|
24
24
|
| 判断条件 | 状态 | 操作 |
|
|
25
25
|
|----------|:----:|------|
|
|
26
26
|
| 覆盖率 > 0% 且索引时间在最近提交之后 | ✅OK | 无需操作 |
|
|
27
|
+
| `codegraph_explore` 查询成功且索引时间在最近提交之后 | ✅OK(功能已验证,覆盖率数值未暴露) | 报告真实证据,不虚构覆盖率百分比 |
|
|
27
28
|
| 覆盖率 = 0% | ❌FAIL(未初始化) | 通过 PowerShell 执行 `npx @colbymchenry/codegraph && codegraph init --index` |
|
|
28
29
|
| 索引时间在最近提交之前 | 🟡WARN(过期) | 同上 |
|
|
29
30
|
|
|
30
31
|
> 前提:项目构建命令必须已成功。构建失败时先执行 `npx hunter-harness` 初始化检查。
|
|
31
|
-
> 若 MCP
|
|
32
|
+
> 若 status/explore MCP 工具均不可用,且时间戳证据也不足,标记 🟡WARN(CodeGraph 状态无法验证) 并在报告中说明具体缺失证据。成功的 explore 只能证明索引可用,不得伪造覆盖率数值。
|
|
32
33
|
|
|
33
34
|
### 3. harness-codebase-map 分析文档
|
|
34
35
|
|
|
@@ -61,7 +62,7 @@ powershell.exe -Command "git -C '<项目路径>' diff --stat HEAD~5 2>$null"
|
|
|
61
62
|
|
|
62
63
|
### 5. AGENTS.md 一致性
|
|
63
64
|
|
|
64
|
-
检查 `AGENTS.md`
|
|
65
|
+
检查 `AGENTS.md` 是否包含项目概述和规则索引。Claude Code adapter 启用时,检查 `CLAUDE.md` 引用 `AGENTS.md`(canonical managed block 使用 `@AGENTS.md`),让共享约束保持单一来源;不得要求 `AGENTS.md` 反向引用 `CLAUDE.md`,否则会形成循环,且会破坏未启用 Claude Code 的项目。
|
|
65
66
|
|
|
66
67
|
### 6. .harness/ 完整性
|
|
67
68
|
|
|
@@ -133,7 +134,7 @@ powershell.exe -Command "git -C '<项目路径>' diff --stat HEAD~5 2>$null"
|
|
|
133
134
|
| CodeGraph | 🟡WARN(索引过期) | 索引已过期(上次: 3天前,最近提交: 今天),已重新索引 |
|
|
134
135
|
| harness-codebase-map (.harness/codebase/map/) | ✅OK | 2 天前更新,变更量 5 个文件,无需更新 |
|
|
135
136
|
| CLAUDE.md | ✅OK | 180 行,6 个必要章节完整 |
|
|
136
|
-
| AGENTS.md | ✅OK |
|
|
137
|
+
| AGENTS.md | ✅OK | 共享规则索引完整;CLAUDE.md 已单向引用 AGENTS.md |
|
|
137
138
|
| .harness/ | ✅OK | config 目录存在,1 个变更目录(contribution-module) |
|
|
138
139
|
|
|
139
140
|
### 自动更新
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-test
|
|
3
3
|
description: 测试执行:读取场景表,执行单元测试+API接口测试+数据兼容验证,输出测试报告。当用户说'跑测试/验证/跑用例/接口测试/单元测试'时使用
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=14a6b9abc6a451bd; overlay=java; agent=codebuddy; do not edit -->
|
|
6
6
|
# harness-test — 测试执行
|
|
7
7
|
|
|
8
8
|
## Purpose
|