@hunter-harness/workflow-harness 0.2.30 → 0.2.32

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 +92 -20
  17. package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  34. package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  51. package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  68. package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  85. package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  102. package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  119. package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +461 -82
  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 +92 -20
  136. package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +461 -82
  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,33 +1606,57 @@ 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
+ str(s.get("priority", "")).upper() in {"P0", "P1"}
1639
+ or s.get("requiredEvidenceKind") == "ledger"
1640
+ )
1614
1641
  }
1615
- if not p0_ids:
1616
- return {"ok": True, "code": "NO_P0_SCENARIOS"}
1642
+ if not required_ids:
1643
+ return {"ok": True, "code": "NO_LEDGER_REQUIRED_SCENARIOS"}
1617
1644
 
1618
- ledger_path = change_dir / "evidence" / "verification-ledger.json"
1619
- if not ledger_path.is_file():
1645
+ try:
1646
+ ledger, ledger_path = hl.load_ledger(change_dir)
1647
+ except (OSError, ValueError, json.JSONDecodeError) as exc:
1620
1648
  return {
1621
1649
  "ok": False,
1622
1650
  "code": "SCENARIO_COVERAGE_FAILED",
1623
- "message": "ledger missing; cannot verify P0 scenario coverage",
1624
- "missing": sorted(p0_ids),
1651
+ "message": f"ledger unreadable: {exc}",
1652
+ "missing": sorted(required_ids),
1625
1653
  }
1626
- try:
1627
- ledger = json.loads(ledger_path.read_text(encoding="utf-8-sig"))
1628
- except (OSError, json.JSONDecodeError) as exc:
1654
+ if ledger is None or ledger_path is None:
1629
1655
  return {
1630
1656
  "ok": False,
1631
1657
  "code": "SCENARIO_COVERAGE_FAILED",
1632
- "message": f"ledger unreadable: {exc}",
1633
- "missing": sorted(p0_ids),
1658
+ "message": "ledger missing; cannot verify required scenario coverage",
1659
+ "missing": sorted(required_ids),
1634
1660
  }
1635
1661
  covered: set[str] = set()
1636
1662
  validations = ledger.get("validations") or {}
@@ -1640,15 +1666,38 @@ def _validate_scenario_coverage(change_dir: Path) -> dict[str, Any]:
1640
1666
  ids = entry.get("scenarioIds")
1641
1667
  if isinstance(ids, list):
1642
1668
  covered.update(str(i) for i in ids)
1643
- missing = sorted(p0_ids - covered)
1669
+ missing = sorted(required_ids - covered)
1644
1670
  if missing:
1645
1671
  return {
1646
1672
  "ok": False,
1647
1673
  "code": "SCENARIO_COVERAGE_FAILED",
1648
- "message": f"P0 scenarios without ledger entry: {', '.join(missing)}",
1674
+ "message": (
1675
+ "ledger-required scenarios without ledger entry: "
1676
+ + ", ".join(missing)
1677
+ ),
1649
1678
  "missing": missing,
1650
1679
  }
1651
- return {"ok": True, "code": "SCENARIO_COVERAGE_OK", "covered": sorted(covered & p0_ids)}
1680
+ return {
1681
+ "ok": True,
1682
+ "code": "SCENARIO_COVERAGE_OK",
1683
+ "covered": sorted(covered & required_ids),
1684
+ }
1685
+
1686
+
1687
+ def validate_plan_handoff(change_dir: Path) -> dict[str, Any]:
1688
+ """Verify a finalized modern plan before the first run-side effect."""
1689
+ receipt_path = change_dir / "meta" / "plan-finalization.json"
1690
+ plans_root = change_dir / "plans"
1691
+ has_plan_artifacts = plans_root.is_dir() and any(
1692
+ plans_root.glob("*-plan.md")
1693
+ )
1694
+ if not receipt_path.is_file() and not has_plan_artifacts:
1695
+ return {
1696
+ "ok": True,
1697
+ "code": "PLAN_HANDOFF_NOT_APPLICABLE",
1698
+ "skipped": True,
1699
+ }
1700
+ return hpf.verify_plan(change_dir)
1652
1701
 
1653
1702
 
1654
1703
  def cmd_begin(args: argparse.Namespace) -> int:
@@ -1663,6 +1712,28 @@ def cmd_begin(args: argparse.Namespace) -> int:
1663
1712
  extra={k: v for k, v in resolved.items() if k not in {"ok", "message"}},
1664
1713
  )
1665
1714
  change_dir = Path(resolved["changeDir"])
1715
+ plan_verification: dict[str, Any] | None = None
1716
+ if args.phase == "run":
1717
+ plan_verification = validate_plan_handoff(change_dir)
1718
+ if not plan_verification.get("ok"):
1719
+ code = str(
1720
+ plan_verification.get("code") or "PLAN_HANDOFF_INVALID"
1721
+ )
1722
+ message = str(
1723
+ plan_verification.get("error")
1724
+ or plan_verification.get("message")
1725
+ or "finalized plan verification failed"
1726
+ )
1727
+ return emit_error(
1728
+ code,
1729
+ message,
1730
+ as_json=as_json,
1731
+ extra={
1732
+ key: value
1733
+ for key, value in plan_verification.items()
1734
+ if key not in {"ok", "code", "error", "message"}
1735
+ },
1736
+ )
1666
1737
  concurrency_block = hc.check_concurrency_block(project, resolved["changeId"])
1667
1738
  if concurrency_block is not None:
1668
1739
  record_blocked_attempt(
@@ -1847,6 +1918,7 @@ def cmd_begin(args: argparse.Namespace) -> int:
1847
1918
  "event": event_result,
1848
1919
  "testGuard": guard_result,
1849
1920
  "policySchemaVersion": policy.get("schemaVersion"),
1921
+ "planVerification": plan_verification,
1850
1922
  "projection": projection,
1851
1923
  "executionRootSource": execution_hint["source"],
1852
1924
  }