@hunter-harness/workflow-harness 0.2.72 → 0.2.74
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/harness-archive/SKILL.md +3 -3
- 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 +14 -10
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +49 -9
- package/harness/bundles/general/claude-code/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/general/claude-code/harness-run/checklist.md +4 -1
- package/harness/bundles/general/claude-code/harness-run/reference.md +3 -3
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +5 -4
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +4 -4
- package/harness/bundles/general/claude-code/harness-test/checklist.md +2 -0
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +82 -1
- package/harness/bundles/general/claude-code/scripts/harness_context.py +270 -0
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +71 -2
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +25 -4
- package/harness/bundles/general/claude-code/scripts/harness_profile.py +45 -0
- package/harness/bundles/general/claude-code/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +3 -3
- 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 +14 -10
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +49 -9
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/general/codebuddy/harness-run/checklist.md +4 -1
- package/harness/bundles/general/codebuddy/harness-run/reference.md +3 -3
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +5 -4
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +4 -4
- package/harness/bundles/general/codebuddy/harness-test/checklist.md +2 -0
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +82 -1
- package/harness/bundles/general/codebuddy/scripts/harness_context.py +270 -0
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +71 -2
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +25 -4
- package/harness/bundles/general/codebuddy/scripts/harness_profile.py +45 -0
- package/harness/bundles/general/codebuddy/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/harness-archive/SKILL.md +3 -3
- 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 +14 -10
- package/harness/bundles/general/codex/harness-plan/checklist.md +49 -9
- package/harness/bundles/general/codex/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/general/codex/harness-run/checklist.md +4 -1
- package/harness/bundles/general/codex/harness-run/reference.md +3 -3
- package/harness/bundles/general/codex/harness-submit/SKILL.md +5 -4
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +4 -4
- package/harness/bundles/general/codex/harness-test/checklist.md +2 -0
- package/harness/bundles/general/codex/scripts/harness_archive.py +82 -1
- package/harness/bundles/general/codex/scripts/harness_context.py +270 -0
- package/harness/bundles/general/codex/scripts/harness_gate.py +71 -2
- package/harness/bundles/general/codex/scripts/harness_ledger.py +25 -4
- package/harness/bundles/general/codex/scripts/harness_profile.py +45 -0
- package/harness/bundles/general/codex/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +3 -3
- 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 +14 -10
- package/harness/bundles/general/cursor/harness-plan/checklist.md +49 -9
- package/harness/bundles/general/cursor/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/general/cursor/harness-run/checklist.md +4 -1
- package/harness/bundles/general/cursor/harness-run/reference.md +3 -3
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +5 -4
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +4 -4
- package/harness/bundles/general/cursor/harness-test/checklist.md +2 -0
- package/harness/bundles/general/cursor/scripts/harness_archive.py +82 -1
- package/harness/bundles/general/cursor/scripts/harness_context.py +270 -0
- package/harness/bundles/general/cursor/scripts/harness_gate.py +71 -2
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +25 -4
- package/harness/bundles/general/cursor/scripts/harness_profile.py +45 -0
- package/harness/bundles/general/cursor/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +3 -3
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +3 -3
- 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 +3 -3
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +14 -10
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +49 -9
- package/harness/bundles/java/claude-code/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/java/claude-code/harness-run/checklist.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/reference.md +348 -348
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +5 -4
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +4 -4
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +82 -1
- package/harness/bundles/java/claude-code/scripts/harness_context.py +270 -0
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +71 -2
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +25 -4
- package/harness/bundles/java/claude-code/scripts/harness_profile.py +45 -0
- package/harness/bundles/java/claude-code/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +3 -3
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +3 -3
- 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 +3 -3
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +14 -10
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +49 -9
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/java/codebuddy/harness-run/checklist.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/reference.md +348 -348
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +5 -4
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +4 -4
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +82 -1
- package/harness/bundles/java/codebuddy/scripts/harness_context.py +270 -0
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +71 -2
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +25 -4
- package/harness/bundles/java/codebuddy/scripts/harness_profile.py +45 -0
- package/harness/bundles/java/codebuddy/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +3 -3
- package/harness/bundles/java/codex/harness-archive/SKILL.md +3 -3
- 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 +3 -3
- package/harness/bundles/java/codex/harness-plan/SKILL.md +14 -10
- package/harness/bundles/java/codex/harness-plan/checklist.md +49 -9
- package/harness/bundles/java/codex/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/java/codex/harness-run/checklist.md +1 -1
- package/harness/bundles/java/codex/harness-run/reference.md +348 -348
- package/harness/bundles/java/codex/harness-submit/SKILL.md +5 -4
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +4 -4
- package/harness/bundles/java/codex/scripts/harness_archive.py +82 -1
- package/harness/bundles/java/codex/scripts/harness_context.py +270 -0
- package/harness/bundles/java/codex/scripts/harness_gate.py +71 -2
- package/harness/bundles/java/codex/scripts/harness_ledger.py +25 -4
- package/harness/bundles/java/codex/scripts/harness_profile.py +45 -0
- package/harness/bundles/java/codex/scripts/harness_test_guard.py +8 -5
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +3 -3
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +3 -3
- 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 +3 -3
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +14 -10
- package/harness/bundles/java/cursor/harness-plan/checklist.md +49 -9
- package/harness/bundles/java/cursor/harness-plan/reference.md +83 -33
- 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-run/SKILL.md +6 -6
- package/harness/bundles/java/cursor/harness-run/checklist.md +1 -1
- package/harness/bundles/java/cursor/harness-run/reference.md +348 -348
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +5 -4
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +4 -4
- package/harness/bundles/java/cursor/scripts/harness_archive.py +82 -1
- package/harness/bundles/java/cursor/scripts/harness_context.py +270 -0
- package/harness/bundles/java/cursor/scripts/harness_gate.py +71 -2
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +25 -4
- package/harness/bundles/java/cursor/scripts/harness_profile.py +45 -0
- package/harness/bundles/java/cursor/scripts/harness_test_guard.py +8 -5
- package/harness/manifests/general/claude-code.json +26 -26
- package/harness/manifests/general/codebuddy.json +26 -26
- package/harness/manifests/general/codex.json +26 -26
- package/harness/manifests/general/cursor.json +26 -26
- package/harness/manifests/java/claude-code.json +27 -27
- package/harness/manifests/java/codebuddy.json +27 -27
- package/harness/manifests/java/codex.json +27 -27
- package/harness/manifests/java/cursor.json +27 -27
- package/hunter-workflow-family.json +5 -5
- package/package.json +1 -1
|
@@ -2024,6 +2024,70 @@ def _deferred_hint(deferred_ids: list[str], phase: str | None) -> str:
|
|
|
2024
2024
|
)
|
|
2025
2025
|
|
|
2026
2026
|
|
|
2027
|
+
_PROJECT_ROOT_HELP = (
|
|
2028
|
+
"project root PATH (defaults to resolving from CWD). Takes a path, not a project name."
|
|
2029
|
+
)
|
|
2030
|
+
|
|
2031
|
+
|
|
2032
|
+
def _resolve_project(args: argparse.Namespace) -> Path:
|
|
2033
|
+
"""--project 优先,未给时按 CWD 解析主项目根。
|
|
2034
|
+
|
|
2035
|
+
其他 harness 脚本都把 --project 当项目根且列为必填,只有 gate 例外——调用方
|
|
2036
|
+
按惯例传过来会被 argparse 拒掉。注意 begin/close 的 --project 是另一层语义
|
|
2037
|
+
(本阶段执行根/worktree),本函数只服务 classify/checkpoint。
|
|
2038
|
+
"""
|
|
2039
|
+
raw = getattr(args, "project", None)
|
|
2040
|
+
if raw:
|
|
2041
|
+
return Path(raw).expanduser().resolve()
|
|
2042
|
+
return hc.resolve_main_project_root()
|
|
2043
|
+
|
|
2044
|
+
|
|
2045
|
+
# 门禁消费的场景字段。v2 plan finalize 派生的 scenario_manifest 一个都没有:
|
|
2046
|
+
# 它只带 scenario_id/coverage_dimension/execution_level/evidence_requirements/
|
|
2047
|
+
# risk_level/task_refs/requirement_refs。
|
|
2048
|
+
_V2_MANIFEST_REQUIRED_FIELDS = (
|
|
2049
|
+
"id",
|
|
2050
|
+
"priority",
|
|
2051
|
+
"requiredEvidenceKind",
|
|
2052
|
+
"ownerPhase",
|
|
2053
|
+
"executableTestId",
|
|
2054
|
+
"testFile",
|
|
2055
|
+
"testTitle",
|
|
2056
|
+
)
|
|
2057
|
+
|
|
2058
|
+
|
|
2059
|
+
def _v2_artifact_manifest_gap(manifest: Any) -> dict[str, Any] | None:
|
|
2060
|
+
"""v2 plan artifact 包装的 scenario-manifest → 明确的不可消费错误。
|
|
2061
|
+
|
|
2062
|
+
不能"解包 + 字段改名"了事:包装体里既没有 priority 也没有
|
|
2063
|
+
requiredEvidenceKind,`required_ids` 会算成空集,C9 随即返回
|
|
2064
|
+
NO_LEDGER_REQUIRED_SCENARIOS——那是把证据门禁对所有 v2 计划静默关掉,
|
|
2065
|
+
比直接失败危险得多。所以这里点名缺口,让调用方回规划阶段补齐后重新发布。
|
|
2066
|
+
|
|
2067
|
+
v2 场景契约补齐这些字段后,解包逻辑加在这里。
|
|
2068
|
+
"""
|
|
2069
|
+
if not isinstance(manifest, dict) or manifest.get("artifact_type") != "scenario_manifest":
|
|
2070
|
+
return None
|
|
2071
|
+
content = manifest.get("content")
|
|
2072
|
+
present: set[str] = set()
|
|
2073
|
+
if isinstance(content, dict) and isinstance(content.get("scenarios"), list):
|
|
2074
|
+
for scenario in content["scenarios"]:
|
|
2075
|
+
if isinstance(scenario, dict):
|
|
2076
|
+
present.update(scenario.keys())
|
|
2077
|
+
return {
|
|
2078
|
+
"ok": False,
|
|
2079
|
+
"code": "SCENARIO_MANIFEST_V2_UNSUPPORTED",
|
|
2080
|
+
"message": (
|
|
2081
|
+
"meta/scenario-manifest.json 是 v2 plan artifact 包装体,缺少门禁消费的场景字段;"
|
|
2082
|
+
"请在规划阶段补齐后重新发布,不要手改派生产物"
|
|
2083
|
+
),
|
|
2084
|
+
"missingFields": [
|
|
2085
|
+
field for field in _V2_MANIFEST_REQUIRED_FIELDS if field not in present
|
|
2086
|
+
],
|
|
2087
|
+
"artifactType": "scenario_manifest",
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
|
|
2027
2091
|
def _validate_scenario_coverage(
|
|
2028
2092
|
change_dir: Path, phase: str | None = None
|
|
2029
2093
|
) -> dict[str, Any]:
|
|
@@ -2050,6 +2114,9 @@ def _validate_scenario_coverage(
|
|
|
2050
2114
|
"code": "SCENARIO_MANIFEST_INVALID",
|
|
2051
2115
|
"message": f"scenario-manifest.json unreadable: {exc}",
|
|
2052
2116
|
}
|
|
2117
|
+
v2_gap = _v2_artifact_manifest_gap(manifest)
|
|
2118
|
+
if v2_gap is not None:
|
|
2119
|
+
return v2_gap
|
|
2053
2120
|
scenarios = manifest.get("scenarios") if isinstance(manifest, dict) else None
|
|
2054
2121
|
if not isinstance(scenarios, list):
|
|
2055
2122
|
return {
|
|
@@ -3218,7 +3285,7 @@ def cmd_close(args: argparse.Namespace) -> int:
|
|
|
3218
3285
|
|
|
3219
3286
|
def cmd_classify(args: argparse.Namespace) -> int:
|
|
3220
3287
|
as_json = bool(args.json)
|
|
3221
|
-
project =
|
|
3288
|
+
project = _resolve_project(args)
|
|
3222
3289
|
try:
|
|
3223
3290
|
workflow = _load_workflow_policy(project=project)
|
|
3224
3291
|
except (OSError, ValueError, hwp.PolicyValidationError) as exc:
|
|
@@ -3271,7 +3338,7 @@ def cmd_classify(args: argparse.Namespace) -> int:
|
|
|
3271
3338
|
|
|
3272
3339
|
def cmd_checkpoint(args: argparse.Namespace) -> int:
|
|
3273
3340
|
as_json = bool(args.json)
|
|
3274
|
-
project =
|
|
3341
|
+
project = _resolve_project(args)
|
|
3275
3342
|
resolved = hc.resolve_change(project, args.change)
|
|
3276
3343
|
if not resolved.get("ok"):
|
|
3277
3344
|
return emit_error(
|
|
@@ -3425,6 +3492,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
3425
3492
|
p_close.set_defaults(func=cmd_close)
|
|
3426
3493
|
|
|
3427
3494
|
p_classify = sub.add_parser("classify", parents=[shared])
|
|
3495
|
+
p_classify.add_argument("--project", default=None, type=Path, help=_PROJECT_ROOT_HELP)
|
|
3428
3496
|
p_classify.add_argument("--change", default=None)
|
|
3429
3497
|
p_classify.add_argument("--stage", required=True, choices=["plan", "post-run"])
|
|
3430
3498
|
p_classify.add_argument(
|
|
@@ -3436,6 +3504,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
3436
3504
|
p_classify.set_defaults(func=cmd_classify)
|
|
3437
3505
|
|
|
3438
3506
|
p_checkpoint = sub.add_parser("checkpoint", parents=[shared])
|
|
3507
|
+
p_checkpoint.add_argument("--project", default=None, type=Path, help=_PROJECT_ROOT_HELP)
|
|
3439
3508
|
p_checkpoint.add_argument("checkpoint_action", choices=["status", "approve"])
|
|
3440
3509
|
p_checkpoint.add_argument("--id", required=True)
|
|
3441
3510
|
p_checkpoint.add_argument("--change", default=None)
|
|
@@ -304,12 +304,23 @@ def _compact_record_payload(payload: dict[str, Any]) -> dict[str, Any]:
|
|
|
304
304
|
|
|
305
305
|
|
|
306
306
|
def _compact_can_reuse_payload(payload: dict[str, Any]) -> dict[str, Any]:
|
|
307
|
-
"""C5: can-reuse compact — ok/reuse/code
|
|
308
|
-
|
|
307
|
+
"""C5: can-reuse compact — ok/reuse/code;拒绝复用时附带可执行的原因。
|
|
308
|
+
|
|
309
|
+
只回 ok/reuse/code 时,调用方拿到裸 `{"reuse": false}` 无从判断该怎么办,
|
|
310
|
+
只能再跑一次 `--verbose`——原因(profile 缺 verificationInputs、证据不完整等)
|
|
311
|
+
是单行短文本,值得留在默认输出里。允许复用时保持原样精简。
|
|
312
|
+
"""
|
|
313
|
+
compact = {
|
|
309
314
|
"ok": payload.get("ok", True),
|
|
310
315
|
"reuse": payload.get("reuse"),
|
|
311
316
|
"code": payload.get("code"),
|
|
312
317
|
}
|
|
318
|
+
if payload.get("reuse") is not True:
|
|
319
|
+
for key in ("reason", "executionNeed", "detail"):
|
|
320
|
+
value = payload.get(key)
|
|
321
|
+
if value not in (None, "", [], {}):
|
|
322
|
+
compact[key] = value
|
|
323
|
+
return compact
|
|
313
324
|
|
|
314
325
|
|
|
315
326
|
def emit_compact_or_verbose(
|
|
@@ -2581,9 +2592,19 @@ def cmd_record(args: argparse.Namespace) -> int:
|
|
|
2581
2592
|
error_code="PROFILE_INPUT_FILES_CONFLICT",
|
|
2582
2593
|
)
|
|
2583
2594
|
files = profile_files
|
|
2584
|
-
|
|
2595
|
+
# NOT_APPLICABLE 的 validation 没有输入文件可言。门禁 close 又要求
|
|
2596
|
+
# requiredValidations 每项都有 entry——两条规则叠加会逼调用方拿无关文件凑数,
|
|
2597
|
+
# ledger 从此声称该 validation 的输入是那些文件,是假证据。
|
|
2598
|
+
not_applicable = str(getattr(args, "applicability", "") or "") == "NOT_APPLICABLE"
|
|
2599
|
+
if not files and not not_applicable:
|
|
2600
|
+
return emit_error(
|
|
2601
|
+
"record requires --files or a non-empty --profile-input file set; "
|
|
2602
|
+
"unless --applicability NOT_APPLICABLE (then --applicability-reason is required)",
|
|
2603
|
+
as_json=as_json,
|
|
2604
|
+
)
|
|
2605
|
+
if not_applicable and not _nonempty_str(getattr(args, "applicability_reason", None)):
|
|
2585
2606
|
return emit_error(
|
|
2586
|
-
"
|
|
2607
|
+
"NOT_APPLICABLE requires --applicability-reason",
|
|
2587
2608
|
as_json=as_json,
|
|
2588
2609
|
)
|
|
2589
2610
|
|
|
@@ -1101,6 +1101,43 @@ def _derive_verification_graph(profile: dict[str, Any]) -> None:
|
|
|
1101
1101
|
}
|
|
1102
1102
|
|
|
1103
1103
|
|
|
1104
|
+
def manual_profile_template(
|
|
1105
|
+
excluded: tuple[str, ...] | list[str], components: list[str]
|
|
1106
|
+
) -> dict[str, Any]:
|
|
1107
|
+
"""歧义时交给调用方的可填骨架。
|
|
1108
|
+
|
|
1109
|
+
骨架本身就是 `empty_profile_skeleton`——defaultsFingerprint、excludedRoots
|
|
1110
|
+
默认集、commands/verificationInputs/verificationGraph 的键都已就位;这里只是
|
|
1111
|
+
补上 commands 的条目形状与 requiredCoverage 取值,省掉调用方去源码里翻。
|
|
1112
|
+
占位值用 `<...>` 包裹,便于替换后 grep 自检。
|
|
1113
|
+
"""
|
|
1114
|
+
template = empty_profile_skeleton(excluded)
|
|
1115
|
+
template["projectType"] = (
|
|
1116
|
+
f"<从 detectedComponents 选定:{'|'.join(components)}>" if components else "<项目类型>"
|
|
1117
|
+
)
|
|
1118
|
+
template["commands"] = {
|
|
1119
|
+
"unitTest": {
|
|
1120
|
+
"command": "<在项目根可直接执行的增量测试命令>",
|
|
1121
|
+
"scope": "incremental",
|
|
1122
|
+
"inputs": ["<相对项目根的 glob,如 <component>/test/**>"],
|
|
1123
|
+
"coverage": "unitTest",
|
|
1124
|
+
"requiredCoverage": "incremental",
|
|
1125
|
+
"dependsOn": [],
|
|
1126
|
+
"source": "user",
|
|
1127
|
+
},
|
|
1128
|
+
"unitTestFull": {
|
|
1129
|
+
"command": "<在项目根可直接执行的全量测试命令>",
|
|
1130
|
+
"scope": "full",
|
|
1131
|
+
"inputs": ["<相对项目根的 glob,如 <component>/**>"],
|
|
1132
|
+
"coverage": "unitTestFull",
|
|
1133
|
+
"requiredCoverage": "module",
|
|
1134
|
+
"dependsOn": [],
|
|
1135
|
+
"source": "user",
|
|
1136
|
+
},
|
|
1137
|
+
}
|
|
1138
|
+
return template
|
|
1139
|
+
|
|
1140
|
+
|
|
1104
1141
|
def detect(project: Path) -> dict[str, Any]:
|
|
1105
1142
|
project = project.resolve()
|
|
1106
1143
|
existing = load_profile(project)
|
|
@@ -1120,6 +1157,14 @@ def detect(project: Path) -> dict[str, Any]:
|
|
|
1120
1157
|
"applied": False,
|
|
1121
1158
|
"detectedComponents": components,
|
|
1122
1159
|
"message": "multiple or nested project components require an explicit profile",
|
|
1160
|
+
# 拒绝生成可以,但不能连结构都不给:调用方否则只能反读本文件源码去凑
|
|
1161
|
+
# v3 形状。骨架不落盘——一份占位 profile 看起来"已配好"比没有更糟。
|
|
1162
|
+
"profileTemplate": manual_profile_template(excluded, components),
|
|
1163
|
+
"hint": (
|
|
1164
|
+
"手工声明一份 profile:以 profileTemplate 为骨架,按 detectedComponents "
|
|
1165
|
+
"选定产品包,commands 里的 inputs 用相对项目根的 glob(如 "
|
|
1166
|
+
f"'<component>/test/**'),填好后写入 {project / PROFILE_REL}"
|
|
1167
|
+
),
|
|
1123
1168
|
}
|
|
1124
1169
|
if project_type == "unknown" and existing:
|
|
1125
1170
|
return {
|
|
@@ -332,12 +332,15 @@ def _matches_pattern(rel: str, pattern: str) -> bool:
|
|
|
332
332
|
|
|
333
333
|
|
|
334
334
|
def _standard_test_path(rel: str) -> bool:
|
|
335
|
+
"""路径中出现 test/tests 目录段即视为标准测试路径。
|
|
336
|
+
|
|
337
|
+
此前只认 parts[0],于是 monorepo(packages/cli/tests/…)与"仓库根 + 同名
|
|
338
|
+
子包"(kld-sdd/test/…)这类常见布局全被拒,调用方被迫先补 build-profile
|
|
339
|
+
才能记录一次 stale-test-repair。段级匹配不放宽语义:testing/ 与
|
|
340
|
+
tests-helper/ 仍然不算,目录本身(末段)也不算文件。
|
|
341
|
+
"""
|
|
335
342
|
parts = rel.split("/")
|
|
336
|
-
|
|
337
|
-
return True
|
|
338
|
-
if any(parts[index:index + 2] == ["src", "test"] for index in range(len(parts) - 1)):
|
|
339
|
-
return True
|
|
340
|
-
return False
|
|
343
|
+
return any(part in ("test", "tests") for part in parts[:-1])
|
|
341
344
|
|
|
342
345
|
|
|
343
346
|
def _allowed_test_path(project: Path, rel: str) -> bool:
|
|
@@ -3,7 +3,7 @@ name: harness-archive
|
|
|
3
3
|
description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到 .harness/archive/,含归档元数据。仅当用户显式调用
|
|
4
4
|
/harness-archive 时使用;不得被其他阶段 skill 自动接续触发。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=ecbe1a870731d9da; overlay=none; agent=codex; do not edit -->
|
|
7
7
|
# harness-archive — 变更归档
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -39,9 +39,9 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
|
|
|
39
39
|
## 统一读取协议
|
|
40
40
|
|
|
41
41
|
1. **`.harness/changes/<change-name>/` 是唯一真相源** — 所有输入从该目录读取,产物写入对应子目录
|
|
42
|
-
2. **change-name 优先从 frontmatter 读取** — `spec/*-design.md`、`plans/*-plan.md` 的 YAML `change-name`
|
|
42
|
+
2. **change-name 优先从 frontmatter 读取** — `plans/*-design.md`、`spec/*-design.md`、`plans/*-plan.md` 的 YAML `change-name`
|
|
43
43
|
3. **frontmatter 缺失时兼容旧格式** — 从路径推断,标记 `🟡 legacy-plan`,不失败
|
|
44
|
-
4. **
|
|
44
|
+
4. **design** — 设计真相源按序取第一个存在的:`plans/<change>-design.md`(v2 发布产物,哈希绑定)→ `spec/<change>-design.md`(legacy 手写)。两份**同时存在**时以 `plans/` 为准,并记 `🟡 WARN 设计文档双份`——v2 发布的那份才受完整性门禁保护,读手写的那份等于绕过校验
|
|
45
45
|
5. **plan** — 任务真相源:`plans/<change>-plan.md`
|
|
46
46
|
6. **implementation-detail** — 自适应执行参考;legacy 缺失 🟡WARN,不阻断
|
|
47
47
|
7. **test-scenarios** — 测试真相源:`plans/<change>-test-scenarios.md`
|
|
@@ -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=ecbe1a870731d9da; overlay=none; agent=codex; do not edit -->
|
|
7
7
|
# harness-codebase-map — 代码库地图
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-knowledge-ingest
|
|
3
3
|
description: 确认归档 ZIP 已上传并由 Hunter Platform 在服务端解包、校验和入库。客户端不再构建或维护本地知识索引。
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=ecbe1a870731d9da; overlay=none; agent=codex; do not edit -->
|
|
6
6
|
# harness-knowledge-ingest
|
|
7
7
|
|
|
8
8
|
知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: harness-knowledge-query
|
|
3
3
|
description: 在规划、实现或排查前,通过 hunter-harness CLI 查询远端项目知识库。远端不可用时直接报告不可用,不建立本地索引或离线回退。
|
|
4
4
|
---
|
|
5
|
-
<!-- generated by harness_deploy.py; core=
|
|
5
|
+
<!-- generated by harness_deploy.py; core=ecbe1a870731d9da; overlay=none; agent=codex; do not edit -->
|
|
6
6
|
# harness-knowledge-query
|
|
7
7
|
|
|
8
8
|
项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
|
|
@@ -3,7 +3,7 @@ name: harness-plan
|
|
|
3
3
|
description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。仅当用户显式调用 /harness-plan 或明确要求进入
|
|
4
4
|
Harness 规划阶段时使用;不得因用户描述需求就自动触发。
|
|
5
5
|
---
|
|
6
|
-
<!-- generated by harness_deploy.py; core=
|
|
6
|
+
<!-- generated by harness_deploy.py; core=ecbe1a870731d9da; overlay=none; agent=codex; do not edit -->
|
|
7
7
|
# harness-plan — 需求规划
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
@@ -21,9 +21,9 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
|
|
|
21
21
|
## 统一读取协议
|
|
22
22
|
|
|
23
23
|
1. **`.harness/changes/<change-name>/` 是唯一真相源** — 所有输入从该目录读取,产物写入对应子目录
|
|
24
|
-
2. **change-name 优先从 frontmatter 读取** — `spec/*-design.md`、`plans/*-plan.md` 的 YAML `change-name`
|
|
24
|
+
2. **change-name 优先从 frontmatter 读取** — `plans/*-design.md`、`spec/*-design.md`、`plans/*-plan.md` 的 YAML `change-name`
|
|
25
25
|
3. **frontmatter 缺失时兼容旧格式** — 从路径推断,标记 `🟡 legacy-plan`,不失败
|
|
26
|
-
4. **
|
|
26
|
+
4. **design** — 设计真相源按序取第一个存在的:`plans/<change>-design.md`(v2 发布产物,哈希绑定)→ `spec/<change>-design.md`(legacy 手写)。两份**同时存在**时以 `plans/` 为准,并记 `🟡 WARN 设计文档双份`——v2 发布的那份才受完整性门禁保护,读手写的那份等于绕过校验
|
|
27
27
|
5. **plan** — 任务真相源:`plans/<change>-plan.md`
|
|
28
28
|
6. **implementation-detail** — 自适应执行参考;legacy 缺失 🟡WARN,不阻断
|
|
29
29
|
7. **test-scenarios** — 测试真相源:`plans/<change>-test-scenarios.md`
|
|
@@ -65,14 +65,15 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
|
|
|
65
65
|
|
|
66
66
|
| 阶段 | 动作 |
|
|
67
67
|
|------|------|
|
|
68
|
-
| 0 |
|
|
69
|
-
| 0.5 |
|
|
70
|
-
| 0.
|
|
68
|
+
| 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问。环境体检并入 0.5 的引导命令,不再单独跑 doctor |
|
|
69
|
+
| 0.5 | 先定英文 `change-name`(kebab-case,`^[a-z0-9]+(-[a-z0-9]+)*$`)与一次性中文展示标题(建议 6~24 个可见字符,保留必要产品名),然后**一条命令完成引导**:<br>`python <skills-root>/scripts/harness_context.py bootstrap-plan --project . --change <cn> --executor <tool> --title "<中文标题>" --json`<br>它按序做完 doctor → 建 change 骨架 → prepare → state capture(首次把当时 HEAD 固定为不可变 `changeBase`)→ classify(落 `meta/gate-policy.json`)→ 生成合规 `plan_<uuid>` run-id 并追加 `phase.start`,返回紧凑摘要:`runId`/`attempt`/`tier`/`defaultPhases`/`conditionalPhases`/`requiredValidations`/`changeBase`/`head`/`executionRoot`。**重跑复用同一 run-id、不重复写 `phase.start`**(换 run-id 会让 finalize 按生命周期身份 fail-closed)。finalizer 必须复用该 `runId`/`attempt` |
|
|
70
|
+
| 0.5b | 仅在引导失败需要单步排查时用等价分解——**每条的参数都是必填,少一个就是白跑一轮**:<br>`harness_runtime.py doctor --project . --change-dir ".harness/changes/<cn>" --agent <claude-code\|codebuddy\|codex\|cursor> --json`<br>`harness_context.py prepare --project . --change <cn> --phase plan --executor <tool> --title "<中文标题>" --json`<br>`harness_state.py capture --project . --change-dir ".harness/changes/<cn>" --json`<br>`harness_gate.py classify --change <cn> --stage plan --json`<br>`harness_events.py append --change-dir ".harness/changes/<cn>" --phase plan --type phase.start --run-id plan_<uuid> --attempt 1`<br>⚠️ `--change-dir` 一律是 `.harness/changes/<cn>`(状态目录),**不是** prepare 返回的 `executionRoot`(代码执行根,无 worktree 时等于项目根)——填错会把 gate-policy/events 写到项目根 |
|
|
71
|
+
| 0.6 | 用引导返回的 `tier`/`defaultPhases`/`requiredValidations` 生成 `plannedPhases`,向用户用中文说明可选阶段;确认后运行 `harness_context.py configure-plan --project . --change <cn> --phases "plan,run,...,archive" --operator <tool> --reason "<中文原因>" --json`。无 Git 或不需要提交时不得加入 `submit`;快速迭代默认 `plan,run,archive`。省略项由脚本写入 `skippedPhases`,不得伪造阶段事件 |
|
|
71
72
|
| 1 | 直接执行一次 `npx hunter-harness knowledge query "<用户需求原文>" --limit 10 --json`。这是唯一执行入口,不扫描技能目录、不查找其他脚本;失败记 `issue` 并继续,不建立本地索引或离线回退 |
|
|
72
73
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
73
74
|
| 3 | 按复杂度执行有预算的代码探索;简单修复不得扩散到无关模块 |
|
|
74
75
|
| 4 | **设计审批包** blocking user confirmation;确认事件早于 approved 设计文档和 `meta/worktree.json` |
|
|
75
|
-
| 5–6 |
|
|
76
|
+
| 5–6 | **v2(默认)**:任务与场景只沉淀进 `meta/plan-evidence-input.json`(自然输入,字段定稿时点见 `reference.md` 阶段 8 v2 表);`plans/*.md` 四份由 finalize 派生,**不得手写**——手写的会被派生渲染覆盖,只是白写。**legacy**:才手写 plan + implementation-detail + test-scenarios → `plans/` |
|
|
76
77
|
| 7.5 | 仅 `--adversarial` 对抗评审 |
|
|
77
78
|
| 8 | **v2 路径(新 change 优先)**:`npx hunter-harness plan evidence-pack --input <meta/plan-evidence-input.json> --output <meta/plan-evidence.json>`,再 `npx hunter-harness plan finalize --input <meta/plan-evidence.json>`;exit 0 且 `code:"PLAN_FINALIZED"` 即发布完成(契约见 `reference.md` 阶段 8 v2 路径)。**legacy 路径**:自然输入不完整(如缺真实审批记录)时才在临时产物集上运行 `harness_plan_finalize.py finalize`,随后立即运行 `verify`;成功后把 finalizer 返回的绝对 `receiptPath` 原样传给 `harness_context.py close`,`--to-phase` 必须取 `plannedPhases` 中 plan 的真实后继,不得写死。写 append-only handoff receipt;不得手写占位路径;原子发布、派生清单计数对账、完整生命周期、render → `checklist.md` |
|
|
78
79
|
|
|
@@ -95,16 +96,19 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
95
96
|
| 规则 | 要点 |
|
|
96
97
|
|------|------|
|
|
97
98
|
| 产物路径 | 只写 `.harness/changes/<cn>/`;禁止 superpowers 输入 |
|
|
99
|
+
| 设计真相源 | **v2** = `plans/<cn>-design.md`(finalize 派生、哈希绑定、八 target 之一);**legacy** = `spec/<cn>-design.md`。同一 change 只有一份设计权威,禁止两处并存导致漂移;下游读取顺序见 `shared/read-protocol.md` |
|
|
98
100
|
| Change 标题 | 首次 Plan 同时确定英文 `change-name` 与中文展示标题;英文名保持目录和机器标识不变,中文标题由 `prepare --title` 持久化,后续阶段只复用、不重新生成 |
|
|
99
101
|
| 阶段计划 | Plan 必须持久化 `plannedPhases`;固定从 plan 开始、以 archive 结束。Test、Review、Submit、Package、API 文档可按项目策略省略;高风险必需项只能转为“提前结束且不可发布”,不得伪装通过 |
|
|
100
102
|
| 产品边界 | `ownership.productPaths` 必须覆盖计划会修改的源文件、测试文件和构建入口;只写目录前缀或精确文件,禁止 `**` 通配。finalize 前对照任务表补齐,避免归档阶段才发现边界缺口 |
|
|
101
103
|
| 空目录 | 不得为“预留目录”生成 `.gitkeep`;只有产品明确需要跟踪空目录时才能创建,并在计划中说明业务原因 |
|
|
102
|
-
| 设计审批包 | 一次 blocking user confirmation 含 worktree(读 `harness.json` `defaultWorktree
|
|
104
|
+
| 设计审批包 | 一次 blocking user confirmation 含 worktree(读 `harness.json` `defaultWorktree`)。必须同时展示 **in_scope 与 out_of_scope 两个列表**——只展示"做什么"会让范围误判活到发布之后,代价是整份计划 republish |
|
|
105
|
+
| 引用即追问 | 需求引用了外部设计文档章节(贴段落、指 `### Bn`、说"之前设计的时候如…")时,阶段 2 必须确认该章节是否纳入本次范围,落到 in_scope 或 out_of_scope;引用 ≠ 纳入,也 ≠ 排除 |
|
|
103
106
|
| 阶段 8 | 二选一且不得混用:**v2** = `hunter-harness plan finalize`(证据包 → 八 target + journal committed + plan-events.ndjson);**legacy** = 六项标准产物先进入 staging,仅 finalizer 校验成功后发布并写唯一 `phase.end`/log,随后 `verify` 确认 start/end、收据完整覆盖六项标准产物、哈希、全部任务表和非空场景清单一致。失败均不得手工补终态 |
|
|
104
107
|
| 发布后改产物 | 用 `harness_plan_finalize.py republish --run-id <全新> --reason "<why>"` 一次完成(新 attempt + 换收据 + 重新派生 manifest)。重跑 `finalize` 会报 `PLAN_FINALIZATION_HASH_CONFLICT`;**绝不手改 `meta/scenario-manifest.json`**(派生物,手改必致 `ARTIFACT_HASH_DRIFT`)→ `reference.md`「发布后修订计划」 |
|
|
105
|
-
| v2 输入骨架 | 不要猜 `plan-evidence-input.json`
|
|
108
|
+
| v2 输入骨架 | 不要猜 `plan-evidence-input.json` 结构:`npx hunter-harness plan evidence-pack --print-template` 给出**一个字不改就能通过 evidence-pack** 的骨架(结构合法;`change_key`/`run_id` 仍须换成真实身份才能 finalize),逐项替换即可。结构不符时命令返回 `PLAN_EVIDENCE_INPUT_INVALID`,带 `field_path` 与 `problems[]`(缺失/多余键、枚举取值)——按 problems 改完重跑;**不得**为找契约去反编译 `dist/bin.js` 或翻 npx 缓存。带不了 `<>` 的占位字段与硬约束清单 → `reference.md` 阶段 8 v2 路径 |
|
|
106
109
|
| Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
|
|
107
110
|
| 知识查询 | 阶段 1 失败不得假装已读历史,也不得改用本地索引或其他执行入口 |
|
|
111
|
+
| 读命令输出 | `--json` 输出是完整结构,**不得**接 `\| tail -N` / `\| head -N` 后据此判断——截断的 JSON 解析不了,只会逼出一次补读。输出太长时读命令写下的文件(classify → `meta/gate-policy.json`),或用 `bootstrap-plan` 的紧凑摘要 |
|
|
108
112
|
| 歧义优先检查 | 否定、对比、动作对象或范围存在多种合理解释时,最小取证后先给推荐理解并一次一问;确认前不深挖错误方向 |
|
|
109
113
|
| 简单修复探索预算 | 预计不超过 2 个代码文件、且不涉及认证/安全/迁移/并发/API 契约重设时,最多 1 次合并 CodeGraph 查询 + 1 次定向补查、1 个用户澄清问题;无关发现只记非阻断说明 |
|
|
110
114
|
| 精简产物 | 简单修复只保留实现所需的设计、任务、边界和测试;禁止在 spec/plan/detail/scenarios 中重复同一背景和结论 |
|
|
@@ -122,7 +126,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
122
126
|
|
|
123
127
|
## 交互白名单
|
|
124
128
|
|
|
125
|
-
1. **设计审批包**(阶段 4):设计 + 场景表 + worktree + change-name
|
|
129
|
+
1. **设计审批包**(阶段 4):设计 + **范围(做什么/不做什么)** + 场景表 + worktree + change-name
|
|
126
130
|
2. **decision-grilling**(阶段 2/3 澄清):语义歧义或高风险业务裁决(一次一问)
|
|
127
131
|
|
|
128
132
|
## 执行日志
|
|
@@ -12,9 +12,12 @@ description: harness-plan 的阶段检查清单和覆盖检查列表。仅在执
|
|
|
12
12
|
|
|
13
13
|
**判定**:stdout 为空 → ✅ 继续;stdout 非空 → baseline 隔离 + `decision`(note 含变更文件列表);Bash 被拒 → PowerShell 重试。
|
|
14
14
|
|
|
15
|
-
## 阶段 0.5
|
|
15
|
+
## 阶段 0.5:一次性引导与知识查询
|
|
16
16
|
|
|
17
|
-
- [ ]
|
|
17
|
+
- [ ] 定好 change-name(kebab-case)与中文展示标题后,运行一次 `harness_context.py bootstrap-plan --project . --change <cn> --executor <tool> --title "<中文标题>" --json`
|
|
18
|
+
- [ ] 引导返回 `code:"PLAN_BOOTSTRAPPED"`,记下 `runId`/`attempt`/`tier`/`defaultPhases`/`changeBase`;后续 finalize 必须复用同一 `runId`/`attempt`
|
|
19
|
+
- [ ] 不再手工生成 run-id、不再单独跑 doctor/prepare/capture/classify/append;需要单步排查时才用 SKILL.md 阶段 0.5b 的等价分解
|
|
20
|
+
- [ ] 引导失败时按返回的 `code` 处理(`PROJECT_ROOT_INVALID` → 该项目未 init),**不得**跳过引导直接写产物
|
|
18
21
|
- [ ] 项目已绑定平台时执行一次远端 knowledge `query`;不另跑前置 sync,不创建本地索引
|
|
19
22
|
- [ ] 查询失败追加 `issue`,不得回退本地 archive/SQLite、重跑“sync + query”循环或假装已读取历史
|
|
20
23
|
|
|
@@ -22,6 +25,7 @@ description: harness-plan 的阶段检查清单和覆盖检查列表。仅在执
|
|
|
22
25
|
|
|
23
26
|
- [ ] 否定、对比、动作对象、范围或保留/删除关系不存在未确认的多义解释
|
|
24
27
|
- [ ] 若存在歧义,仅完成最小取证后一次一问,并给出推荐理解
|
|
28
|
+
- [ ] **需求里引用了外部设计文档/章节(贴了段落、给了 `xxx.md` 的 `### Bn` 小节、说"之前设计的时候如…")时,必须确认该章节本次是否纳入**——引用不等于纳入,也不等于排除。把它列进 `in_scope` 或 `out_of_scope` 后再进入阶段 4;漏判会导致计划发布后整体作废重来(republish),是本流程最贵的返工
|
|
25
29
|
- [ ] 简单修复探索预算:最多 1 次合并 CodeGraph 查询 + 1 次定向补查、1 个澄清问题
|
|
26
30
|
- [ ] 无关发现只记非阻断 `issue`,未扩展当前方案或问题列表
|
|
27
31
|
|
|
@@ -65,16 +69,21 @@ description: harness-plan 的阶段检查清单和覆盖检查列表。仅在执
|
|
|
65
69
|
**展示内容**:
|
|
66
70
|
|
|
67
71
|
1. 设计摘要 + 关键证据 + 风险 + 变更清单
|
|
68
|
-
2.
|
|
69
|
-
3.
|
|
70
|
-
4.
|
|
71
|
-
5.
|
|
72
|
+
2. **本次做什么(in_scope)/ 本次不做什么(out_of_scope)** — 两个列表都必须显式列出,不得只展示"做什么"。用户看到"不做"清单才有机会当场纠正范围误判;`out_of_scope` 为空时写"无",不得省略该行。这两个列表随后原样进入 `plan-evidence-input.json` 的 `intent` 与 `approval.content`(两处必须集合相等)
|
|
73
|
+
3. 测试场景表摘要 + 8 维度覆盖检查
|
|
74
|
+
4. worktree 选项(是/否,含推荐理由)
|
|
75
|
+
5. change-name(自动生成,可修改)
|
|
76
|
+
6. 确认进入任务拆分
|
|
72
77
|
|
|
73
|
-
|
|
78
|
+
确认后立即追加 decision 事件,并写入 `meta/worktree.json`。设计文档按路径分流:
|
|
79
|
+
|
|
80
|
+
- **v2**:审批内容写进 `meta/plan-evidence-input.json` 的 `approval.content`(含 `approver_id`),
|
|
81
|
+
`plans/<change>-design.md` 由 finalize 从审批内容派生——**不要**手写它,手写的会被覆盖
|
|
82
|
+
- **legacy**:写 `spec/<change>-design.md`(含下方 frontmatter)
|
|
74
83
|
|
|
75
84
|
- [ ] 确认事件早于 approved 设计文档;未获确认时不得先落盘 `status: approved`
|
|
76
85
|
|
|
77
|
-
设计文档必须包含 frontmatter:
|
|
86
|
+
legacy 设计文档必须包含 frontmatter:
|
|
78
87
|
```yaml
|
|
79
88
|
---
|
|
80
89
|
change-name: <change-name>
|
|
@@ -209,6 +218,37 @@ source: harness-plan
|
|
|
209
218
|
|
|
210
219
|
> **缺任一文件 → ❌FAIL,不得宣称 plan 完成。**
|
|
211
220
|
|
|
221
|
+
> **先认路径再对表**:v2 与 legacy 的完整性口径不同,混用会得出错误结论。
|
|
222
|
+
|
|
223
|
+
### v2 路径(新 change 默认)
|
|
224
|
+
|
|
225
|
+
- [ ] 只手写 `meta/plan-evidence-input.json`;`plans/*.md` 由 finalize 派生,**不得**手写后再被覆盖
|
|
226
|
+
- [ ] `evidence-pack` 返回 `code:"PLAN_EVIDENCE_PACK_BUILT"`;结构报错按 `field_path`/`problems[]` 修正后重跑
|
|
227
|
+
- [ ] `finalize` exit 0 且 `code:"PLAN_FINALIZED"`
|
|
228
|
+
- [ ] 八 target 齐全:`plans/` ×4(design / implementation-detail / plan / test-scenarios)+ `meta/` ×4(gate-policy / implementation-checkpoints / scenario-manifest / worktree)
|
|
229
|
+
- [ ] `meta/publication-journals/<op>.json` 的 `state === "committed"`
|
|
230
|
+
- [ ] `meta/plan-events.ndjson` 含 `artifact_published` 与 `phase_ended` 两类终态事件
|
|
231
|
+
- [ ] 以上任一缺失都不得手工补写;回到对应阶段改自然输入后重跑
|
|
232
|
+
|
|
233
|
+
| 文件(v2) | 必须存在 | 检查结果 |
|
|
234
|
+
|------|:---:|:---:|
|
|
235
|
+
| `.harness/changes/<change>/meta/plan-evidence-input.json` | ✅ | □ |
|
|
236
|
+
| `.harness/changes/<change>/plans/<change>-design.md` | ✅ | □ |
|
|
237
|
+
| `.harness/changes/<change>/plans/<change>-plan.md` | ✅ | □ |
|
|
238
|
+
| `.harness/changes/<change>/plans/<change>-implementation-detail.md` | ✅ | □ |
|
|
239
|
+
| `.harness/changes/<change>/plans/<change>-test-scenarios.md` | ✅ | □ |
|
|
240
|
+
| `.harness/changes/<change>/meta/gate-policy.json` | ✅ | □ |
|
|
241
|
+
| `.harness/changes/<change>/meta/worktree.json` | ✅ | □ |
|
|
242
|
+
| `.harness/changes/<change>/meta/implementation-checkpoints.json` | ✅ | □ |
|
|
243
|
+
| `.harness/changes/<change>/meta/scenario-manifest.json`(非空且计数一致) | ✅ | □ |
|
|
244
|
+
| `.harness/changes/<change>/meta/publication-journals/<op>.json`(committed) | ✅ | □ |
|
|
245
|
+
| `.harness/changes/<change>/meta/plan-events.ndjson` | ✅ | □ |
|
|
246
|
+
| `.harness/changes/<change>/events.ndjson` | ✅ | □ |
|
|
247
|
+
|
|
248
|
+
> v2 过渡期**不写** `meta/plan-finalization.json` 与 `logs/execution-log.md`;缺这两项不算失败,不得为凑表手工补。
|
|
249
|
+
|
|
250
|
+
### legacy 路径(自然输入不完整时的回退)
|
|
251
|
+
|
|
212
252
|
- [ ] 所有待发布产物先写入 staging,不直接覆盖正式 change 目录
|
|
213
253
|
- [ ] 执行 `harness_plan_finalize.py finalize --change-dir ... --staging-dir ... --change ... --run-id <plan-run-id> --attempt <attempt> --json`;身份必须与本次 `phase.start` 完全相同
|
|
214
254
|
- [ ] finalizer 返回 `ok=true`、`artifactsHash`、绝对 `receiptPath` 与稳定 `artifactRef=meta/plan-finalization.json`;重复执行返回 `idempotent=true`
|
|
@@ -220,7 +260,7 @@ source: harness-plan
|
|
|
220
260
|
- [ ] 禁止在 finalizer 之前手工追加成功 `phase.end`
|
|
221
261
|
- [ ] context close 的 `--artifact` 只传 finalizer 原样返回的 `receiptPath` 或 `artifactRef`,不得猜测、拼接或使用 `<plan-finalization>` 占位文本
|
|
222
262
|
|
|
223
|
-
|
|
|
263
|
+
| 文件(legacy) | 必须存在 | 检查结果 |
|
|
224
264
|
|------|:---:|:---:|
|
|
225
265
|
| `.harness/changes/<change>/spec/<change>-design.md` | ✅ | □ |
|
|
226
266
|
| `.harness/changes/<change>/plans/<change>-plan.md` | ✅ | □ |
|