@hunter-harness/workflow-harness 0.2.30 → 0.2.31

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.
Files changed (146) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +3 -3
  3. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +3 -3
  4. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +3 -3
  5. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +3 -3
  6. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +6 -6
  7. package/harness/bundles/general/claude-code/harness-plan/checklist.md +10 -4
  8. package/harness/bundles/general/claude-code/harness-plan/reference.md +17 -17
  9. package/harness/bundles/general/claude-code/harness-review/SKILL.md +3 -3
  10. package/harness/bundles/general/claude-code/harness-run/SKILL.md +4 -4
  11. package/harness/bundles/general/claude-code/harness-run/checklist.md +2 -2
  12. package/harness/bundles/general/claude-code/harness-run/reference.md +3 -12
  13. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +3 -3
  14. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +3 -3
  15. package/harness/bundles/general/claude-code/harness-test/SKILL.md +3 -3
  16. package/harness/bundles/general/claude-code/scripts/harness_gate.py +97 -14
  17. package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +364 -74
  18. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  19. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +3 -3
  20. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +3 -3
  21. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +3 -3
  22. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +3 -3
  23. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +6 -6
  24. package/harness/bundles/general/codebuddy/harness-plan/checklist.md +10 -4
  25. package/harness/bundles/general/codebuddy/harness-plan/reference.md +17 -17
  26. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +3 -3
  27. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +4 -4
  28. package/harness/bundles/general/codebuddy/harness-run/checklist.md +2 -2
  29. package/harness/bundles/general/codebuddy/harness-run/reference.md +3 -12
  30. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +3 -3
  31. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +3 -3
  32. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +3 -3
  33. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +97 -14
  34. package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +364 -74
  35. package/harness/bundles/general/codex/.harness-build.json +1 -1
  36. package/harness/bundles/general/codex/harness-archive/SKILL.md +3 -3
  37. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +3 -3
  38. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +3 -3
  39. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +3 -3
  40. package/harness/bundles/general/codex/harness-plan/SKILL.md +6 -6
  41. package/harness/bundles/general/codex/harness-plan/checklist.md +10 -4
  42. package/harness/bundles/general/codex/harness-plan/reference.md +17 -17
  43. package/harness/bundles/general/codex/harness-review/SKILL.md +3 -3
  44. package/harness/bundles/general/codex/harness-run/SKILL.md +4 -4
  45. package/harness/bundles/general/codex/harness-run/checklist.md +2 -2
  46. package/harness/bundles/general/codex/harness-run/reference.md +3 -12
  47. package/harness/bundles/general/codex/harness-submit/SKILL.md +3 -3
  48. package/harness/bundles/general/codex/harness-sync/SKILL.md +3 -3
  49. package/harness/bundles/general/codex/harness-test/SKILL.md +3 -3
  50. package/harness/bundles/general/codex/scripts/harness_gate.py +97 -14
  51. package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +364 -74
  52. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  53. package/harness/bundles/general/cursor/harness-archive/SKILL.md +3 -3
  54. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +3 -3
  55. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +3 -3
  56. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +3 -3
  57. package/harness/bundles/general/cursor/harness-plan/SKILL.md +6 -6
  58. package/harness/bundles/general/cursor/harness-plan/checklist.md +10 -4
  59. package/harness/bundles/general/cursor/harness-plan/reference.md +17 -17
  60. package/harness/bundles/general/cursor/harness-review/SKILL.md +3 -3
  61. package/harness/bundles/general/cursor/harness-run/SKILL.md +4 -4
  62. package/harness/bundles/general/cursor/harness-run/checklist.md +2 -2
  63. package/harness/bundles/general/cursor/harness-run/reference.md +3 -12
  64. package/harness/bundles/general/cursor/harness-submit/SKILL.md +3 -3
  65. package/harness/bundles/general/cursor/harness-sync/SKILL.md +3 -3
  66. package/harness/bundles/general/cursor/harness-test/SKILL.md +3 -3
  67. package/harness/bundles/general/cursor/scripts/harness_gate.py +97 -14
  68. package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +364 -74
  69. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  70. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +3 -3
  71. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +3 -3
  72. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +3 -3
  73. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +3 -3
  74. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +3 -3
  75. package/harness/bundles/java/claude-code/harness-package/SKILL.md +3 -3
  76. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +6 -6
  77. package/harness/bundles/java/claude-code/harness-plan/checklist.md +10 -4
  78. package/harness/bundles/java/claude-code/harness-plan/reference.md +17 -17
  79. package/harness/bundles/java/claude-code/harness-review/SKILL.md +3 -3
  80. package/harness/bundles/java/claude-code/harness-run/SKILL.md +4 -4
  81. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +3 -3
  82. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +3 -3
  83. package/harness/bundles/java/claude-code/harness-test/SKILL.md +3 -3
  84. package/harness/bundles/java/claude-code/scripts/harness_gate.py +97 -14
  85. package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +364 -74
  86. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  87. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +3 -3
  88. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +3 -3
  89. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +3 -3
  90. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +3 -3
  91. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +3 -3
  92. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +3 -3
  93. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +6 -6
  94. package/harness/bundles/java/codebuddy/harness-plan/checklist.md +10 -4
  95. package/harness/bundles/java/codebuddy/harness-plan/reference.md +17 -17
  96. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +3 -3
  97. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +4 -4
  98. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +3 -3
  99. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +3 -3
  100. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +3 -3
  101. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +97 -14
  102. package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +364 -74
  103. package/harness/bundles/java/codex/.harness-build.json +1 -1
  104. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +3 -3
  105. package/harness/bundles/java/codex/harness-archive/SKILL.md +3 -3
  106. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +3 -3
  107. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +3 -3
  108. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +3 -3
  109. package/harness/bundles/java/codex/harness-package/SKILL.md +3 -3
  110. package/harness/bundles/java/codex/harness-plan/SKILL.md +6 -6
  111. package/harness/bundles/java/codex/harness-plan/checklist.md +10 -4
  112. package/harness/bundles/java/codex/harness-plan/reference.md +17 -17
  113. package/harness/bundles/java/codex/harness-review/SKILL.md +3 -3
  114. package/harness/bundles/java/codex/harness-run/SKILL.md +4 -4
  115. package/harness/bundles/java/codex/harness-submit/SKILL.md +3 -3
  116. package/harness/bundles/java/codex/harness-sync/SKILL.md +3 -3
  117. package/harness/bundles/java/codex/harness-test/SKILL.md +3 -3
  118. package/harness/bundles/java/codex/scripts/harness_gate.py +97 -14
  119. package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +364 -74
  120. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  121. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +3 -3
  122. package/harness/bundles/java/cursor/harness-archive/SKILL.md +3 -3
  123. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +3 -3
  124. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +3 -3
  125. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +3 -3
  126. package/harness/bundles/java/cursor/harness-package/SKILL.md +3 -3
  127. package/harness/bundles/java/cursor/harness-plan/SKILL.md +6 -6
  128. package/harness/bundles/java/cursor/harness-plan/checklist.md +10 -4
  129. package/harness/bundles/java/cursor/harness-plan/reference.md +17 -17
  130. package/harness/bundles/java/cursor/harness-review/SKILL.md +3 -3
  131. package/harness/bundles/java/cursor/harness-run/SKILL.md +4 -4
  132. package/harness/bundles/java/cursor/harness-submit/SKILL.md +3 -3
  133. package/harness/bundles/java/cursor/harness-sync/SKILL.md +3 -3
  134. package/harness/bundles/java/cursor/harness-test/SKILL.md +3 -3
  135. package/harness/bundles/java/cursor/scripts/harness_gate.py +97 -14
  136. package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +364 -74
  137. package/harness/manifests/general/claude-code.json +19 -19
  138. package/harness/manifests/general/codebuddy.json +19 -19
  139. package/harness/manifests/general/codex.json +19 -19
  140. package/harness/manifests/general/cursor.json +19 -19
  141. package/harness/manifests/java/claude-code.json +19 -19
  142. package/harness/manifests/java/codebuddy.json +19 -19
  143. package/harness/manifests/java/codex.json +19 -19
  144. package/harness/manifests/java/cursor.json +19 -19
  145. package/hunter-workflow-family.json +4 -4
  146. package/package.json +1 -1
@@ -33,6 +33,7 @@ import harness_change as hc # noqa: E402
33
33
  import harness_events as he # noqa: E402
34
34
  import harness_ledger as hl # noqa: E402
35
35
  import harness_paths as hp # noqa: E402
36
+ import harness_plan_finalize as hpf # noqa: E402
36
37
  import harness_workflow_policy as hwp # noqa: E402
37
38
  import harness_test_guard as htg # noqa: E402
38
39
 
@@ -1588,10 +1589,11 @@ def _phase_event_exists(change_dir: Path, phase: str, type_: str, run_id: str) -
1588
1589
 
1589
1590
 
1590
1591
  def _validate_scenario_coverage(change_dir: Path) -> dict[str, Any]:
1591
- """C9: validate all P0 scenarios have a ledger entry with scenarioIds covering them.
1592
+ """C9: validate all ledger-required scenarios are covered by ledger entries.
1592
1593
 
1593
1594
  Reads meta/scenario-manifest.json and evidence/verification-ledger.json.
1594
- Returns ok=True when manifest missing (backward compat) or all P0 scenarios covered.
1595
+ Returns ok=True when a legacy manifest is missing or all required scenarios
1596
+ are covered. A present but empty manifest is always invalid.
1595
1597
  """
1596
1598
  manifest_path = change_dir / "meta" / "scenario-manifest.json"
1597
1599
  if not manifest_path.is_file():
@@ -1604,24 +1606,52 @@ def _validate_scenario_coverage(change_dir: Path) -> dict[str, Any]:
1604
1606
  "code": "SCENARIO_MANIFEST_INVALID",
1605
1607
  "message": f"scenario-manifest.json unreadable: {exc}",
1606
1608
  }
1607
- scenarios = manifest.get("scenarios") or []
1608
- p0_ids = {
1609
+ scenarios = manifest.get("scenarios") if isinstance(manifest, dict) else None
1610
+ if not isinstance(scenarios, list):
1611
+ return {
1612
+ "ok": False,
1613
+ "code": "SCENARIO_MANIFEST_INVALID",
1614
+ "message": "scenario-manifest.json scenarios must be a list",
1615
+ }
1616
+ if not scenarios:
1617
+ return {
1618
+ "ok": False,
1619
+ "code": "SCENARIO_MANIFEST_EMPTY",
1620
+ "message": "scenario-manifest.json must contain at least one scenario",
1621
+ }
1622
+ invalid_items = [
1623
+ index
1624
+ for index, scenario in enumerate(scenarios)
1625
+ if not isinstance(scenario, dict) or not str(scenario.get("id") or "").strip()
1626
+ ]
1627
+ if invalid_items:
1628
+ return {
1629
+ "ok": False,
1630
+ "code": "SCENARIO_MANIFEST_INVALID",
1631
+ "message": f"scenario entries missing IDs at indexes: {invalid_items}",
1632
+ }
1633
+ required_ids = {
1609
1634
  str(s.get("id"))
1610
1635
  for s in scenarios
1611
1636
  if isinstance(s, dict)
1612
- and str(s.get("priority", "")).upper() == "P0"
1613
- and s.get("requiredEvidenceKind") == "ledger"
1637
+ and (
1638
+ s.get("requiredEvidenceKind") == "ledger"
1639
+ or (
1640
+ not s.get("requiredEvidenceKind")
1641
+ and str(s.get("priority", "")).upper() in {"P0", "P1"}
1642
+ )
1643
+ )
1614
1644
  }
1615
- if not p0_ids:
1616
- return {"ok": True, "code": "NO_P0_SCENARIOS"}
1645
+ if not required_ids:
1646
+ return {"ok": True, "code": "NO_LEDGER_REQUIRED_SCENARIOS"}
1617
1647
 
1618
1648
  ledger_path = change_dir / "evidence" / "verification-ledger.json"
1619
1649
  if not ledger_path.is_file():
1620
1650
  return {
1621
1651
  "ok": False,
1622
1652
  "code": "SCENARIO_COVERAGE_FAILED",
1623
- "message": "ledger missing; cannot verify P0 scenario coverage",
1624
- "missing": sorted(p0_ids),
1653
+ "message": "ledger missing; cannot verify required scenario coverage",
1654
+ "missing": sorted(required_ids),
1625
1655
  }
1626
1656
  try:
1627
1657
  ledger = json.loads(ledger_path.read_text(encoding="utf-8-sig"))
@@ -1630,7 +1660,7 @@ def _validate_scenario_coverage(change_dir: Path) -> dict[str, Any]:
1630
1660
  "ok": False,
1631
1661
  "code": "SCENARIO_COVERAGE_FAILED",
1632
1662
  "message": f"ledger unreadable: {exc}",
1633
- "missing": sorted(p0_ids),
1663
+ "missing": sorted(required_ids),
1634
1664
  }
1635
1665
  covered: set[str] = set()
1636
1666
  validations = ledger.get("validations") or {}
@@ -1640,15 +1670,38 @@ def _validate_scenario_coverage(change_dir: Path) -> dict[str, Any]:
1640
1670
  ids = entry.get("scenarioIds")
1641
1671
  if isinstance(ids, list):
1642
1672
  covered.update(str(i) for i in ids)
1643
- missing = sorted(p0_ids - covered)
1673
+ missing = sorted(required_ids - covered)
1644
1674
  if missing:
1645
1675
  return {
1646
1676
  "ok": False,
1647
1677
  "code": "SCENARIO_COVERAGE_FAILED",
1648
- "message": f"P0 scenarios without ledger entry: {', '.join(missing)}",
1678
+ "message": (
1679
+ "ledger-required scenarios without ledger entry: "
1680
+ + ", ".join(missing)
1681
+ ),
1649
1682
  "missing": missing,
1650
1683
  }
1651
- return {"ok": True, "code": "SCENARIO_COVERAGE_OK", "covered": sorted(covered & p0_ids)}
1684
+ return {
1685
+ "ok": True,
1686
+ "code": "SCENARIO_COVERAGE_OK",
1687
+ "covered": sorted(covered & required_ids),
1688
+ }
1689
+
1690
+
1691
+ def validate_plan_handoff(change_dir: Path) -> dict[str, Any]:
1692
+ """Verify a finalized modern plan before the first run-side effect."""
1693
+ receipt_path = change_dir / "meta" / "plan-finalization.json"
1694
+ plans_root = change_dir / "plans"
1695
+ has_plan_artifacts = plans_root.is_dir() and any(
1696
+ plans_root.glob("*-plan.md")
1697
+ )
1698
+ if not receipt_path.is_file() and not has_plan_artifacts:
1699
+ return {
1700
+ "ok": True,
1701
+ "code": "PLAN_HANDOFF_NOT_APPLICABLE",
1702
+ "skipped": True,
1703
+ }
1704
+ return hpf.verify_plan(change_dir)
1652
1705
 
1653
1706
 
1654
1707
  def cmd_begin(args: argparse.Namespace) -> int:
@@ -1663,6 +1716,35 @@ def cmd_begin(args: argparse.Namespace) -> int:
1663
1716
  extra={k: v for k, v in resolved.items() if k not in {"ok", "message"}},
1664
1717
  )
1665
1718
  change_dir = Path(resolved["changeDir"])
1719
+ plan_verification: dict[str, Any] | None = None
1720
+ if args.phase == "run":
1721
+ plan_verification = validate_plan_handoff(change_dir)
1722
+ if not plan_verification.get("ok"):
1723
+ code = str(
1724
+ plan_verification.get("code") or "PLAN_HANDOFF_INVALID"
1725
+ )
1726
+ message = str(
1727
+ plan_verification.get("error")
1728
+ or plan_verification.get("message")
1729
+ or "finalized plan verification failed"
1730
+ )
1731
+ record_blocked_attempt(
1732
+ change_dir,
1733
+ phase=args.phase,
1734
+ code=code,
1735
+ message=message,
1736
+ run_id=args.run_id or os.environ.get("HUNTER_HARNESS_RUN_ID"),
1737
+ )
1738
+ return emit_error(
1739
+ code,
1740
+ message,
1741
+ as_json=as_json,
1742
+ extra={
1743
+ key: value
1744
+ for key, value in plan_verification.items()
1745
+ if key not in {"ok", "code", "error", "message"}
1746
+ },
1747
+ )
1666
1748
  concurrency_block = hc.check_concurrency_block(project, resolved["changeId"])
1667
1749
  if concurrency_block is not None:
1668
1750
  record_blocked_attempt(
@@ -1847,6 +1929,7 @@ def cmd_begin(args: argparse.Namespace) -> int:
1847
1929
  "event": event_result,
1848
1930
  "testGuard": guard_result,
1849
1931
  "policySchemaVersion": policy.get("schemaVersion"),
1932
+ "planVerification": plan_verification,
1850
1933
  "projection": projection,
1851
1934
  "executionRootSource": execution_hint["source"],
1852
1935
  }