@danmoisan/drm-copilot-mcp 0.0.1 → 0.0.5

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 (156) hide show
  1. package/out/mcp-server.js +5 -1
  2. package/package.json +21 -5
  3. package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +15 -3
  4. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_branch_base_check_unmerged_pr_deps.md +16 -0
  5. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_every_change_through_lifecycle.md +15 -0
  6. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_policy_compliance_not_optional.md +18 -0
  7. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_potential_to_issue_creates_github_issue.md +13 -0
  8. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_remediation_plan_em_dash_required.md +13 -0
  9. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_small_bug_uses_minor_audit.md +13 -0
  10. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +13 -0
  11. package/resources/claude-customizations/.claude/agents/atomic-executor.md +7 -7
  12. package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +4 -5
  13. package/resources/claude-customizations/.claude/agents/feature-review.md +7 -3
  14. package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -1
  15. package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
  16. package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +245 -0
  17. package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +273 -0
  18. package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +148 -0
  19. package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +190 -0
  20. package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +216 -0
  21. package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +84 -15
  22. package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +1 -1
  23. package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +75 -5
  24. package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +93 -0
  25. package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +68 -0
  26. package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +46 -0
  27. package/resources/claude-customizations/.claude/rules/benchmark-baselines.md +35 -0
  28. package/resources/claude-customizations/.claude/rules/ci-workflows.md +36 -0
  29. package/resources/claude-customizations/.claude/rules/csharp.md +62 -16
  30. package/resources/claude-customizations/.claude/rules/general-code-change.md +12 -3
  31. package/resources/claude-customizations/.claude/rules/general-unit-test.md +47 -2
  32. package/resources/claude-customizations/.claude/rules/orchestrator-state.md +39 -0
  33. package/resources/claude-customizations/.claude/rules/powershell.md +5 -5
  34. package/resources/claude-customizations/.claude/rules/python.md +4 -3
  35. package/resources/claude-customizations/.claude/rules/quality-tiers.md +51 -0
  36. package/resources/claude-customizations/.claude/rules/typescript.md +37 -8
  37. package/resources/claude-customizations/.claude/settings.json +37 -12
  38. package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -2
  39. package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +25 -10
  40. package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +6 -6
  41. package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +8 -8
  42. package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +17 -6
  43. package/resources/claude-customizations/.claude/skills/human-exception-runbook/SKILL.md +52 -0
  44. package/resources/claude-customizations/.claude/skills/human-exception-runbook/example.runbook.md +36 -0
  45. package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -4
  46. package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +96 -3
  47. package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +3 -3
  48. package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +4 -4
  49. package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +3 -3
  50. package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +1 -1
  51. package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +90 -17
  52. package/resources/claude-dir-customizations/.mcp.json +3 -3
  53. package/resources/codex-and-agents-customizations/.agents/README.md +1 -1
  54. package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +0 -5
  55. package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +52 -0
  56. package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +16 -8
  57. package/resources/codex-and-agents-customizations/.agents/skills/benchmark-baselines/SKILL.md +44 -0
  58. package/resources/codex-and-agents-customizations/.agents/skills/ci-workflows/SKILL.md +45 -0
  59. package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +3 -11
  60. package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +1 -5
  61. package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -6
  62. package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +0 -5
  63. package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +0 -5
  64. package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +0 -5
  65. package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +8 -17
  66. package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +13 -14
  67. package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +1 -6
  68. package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +0 -5
  69. package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +86 -0
  70. package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +111 -0
  71. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/SKILL.md +57 -0
  72. package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/example.runbook.md +36 -0
  73. package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +0 -9
  74. package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -9
  75. package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +0 -9
  76. package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +0 -5
  77. package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +93 -8
  78. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +48 -0
  79. package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +61 -2
  80. package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +3 -8
  81. package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +0 -10
  82. package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +4 -8
  83. package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -6
  84. package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +0 -5
  85. package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +3 -9
  86. package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +1 -9
  87. package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +4 -9
  88. package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +0 -5
  89. package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +1 -5
  90. package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -6
  91. package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +0 -5
  92. package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +2 -6
  93. package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +57 -0
  94. package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +0 -5
  95. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +91 -72
  96. package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +1 -1
  97. package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +0 -10
  98. package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +0 -5
  99. package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +0 -5
  100. package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +0 -5
  101. package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +2 -6
  102. package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +0 -5
  103. package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +86 -0
  104. package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +297 -0
  105. package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +0 -22
  106. package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +1 -5
  107. package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +2 -6
  108. package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +0 -5
  109. package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +5 -5
  110. package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +91 -63
  111. package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +1 -1
  112. package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
  113. package/resources/codex-and-agents-customizations/.codex/config.toml +51 -136
  114. package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +1 -1
  115. package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +4 -3
  116. package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +5 -0
  117. package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +68 -0
  118. package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +15 -0
  119. package/resources/config/orchestration-routing.json +84 -0
  120. package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +1 -1
  121. package/resources/customizations/.github/agents/atomic_executor.agent.md +1 -1
  122. package/resources/customizations/.github/agents/atomic_planning.agent.md +10 -10
  123. package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +6 -2
  124. package/resources/customizations/.github/agents/feature-review.agent.md +2 -2
  125. package/resources/customizations/.github/agents/orchestrator.agent.md +6 -2
  126. package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +4 -4
  127. package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +10 -10
  128. package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -2
  129. package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +2 -2
  130. package/resources/customizations/.github/agents/python-orchestrator.agent.md +6 -2
  131. package/resources/customizations/.github/agents/staged-review.agent.md +1 -1
  132. package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +6 -6
  133. package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +1 -1
  134. package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +5 -3
  135. package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +5 -3
  136. package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +14 -1
  137. package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +11 -7
  138. package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +10 -1
  139. package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +2 -2
  140. package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +5 -0
  141. package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +7 -0
  142. package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +127 -0
  143. package/resources/scripts/dev_tools/_orchestrator_state_routing.py +216 -0
  144. package/resources/scripts/dev_tools/push_down_claude_customizations.py +191 -5
  145. package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +103 -411
  146. package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +107 -0
  147. package/resources/scripts/dev_tools/validate_orchestrator_state.py +428 -0
  148. package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +448 -0
  149. package/resources/templates/push_down_claude_customizations.py +227 -6
  150. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +0 -11
  151. package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +0 -19
  152. package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +0 -11
  153. package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +0 -1
  154. package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +0 -13
  155. package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +0 -3
  156. package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +0 -11
@@ -1,124 +1,76 @@
1
1
  """Validate orchestration plan, review, and checkpoint artifacts.
2
2
 
3
3
  Purpose:
4
- Provide a fail-closed validator for deterministic orchestration contracts so
5
- plan approval, review completion, and checkpoint completion can rely on
6
- schema checks instead of narrative judgment.
4
+ Provide the stable CLI entrypoint for deterministic orchestration artifact
5
+ validation while delegating review- and checkpoint-specific logic to smaller
6
+ modules that remain under the repository file-size limit.
7
7
  """
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
11
  import argparse
12
- import json
13
12
  import re
14
13
  import sys
15
14
  from pathlib import Path
16
- from typing import Any, cast
15
+
16
+ from dev_tools.validate_orchestration_review_artifacts import (
17
+ validate_code_review_text,
18
+ validate_feature_audit_text,
19
+ )
20
+ from dev_tools.validate_orchestrator_state import (
21
+ validate_orchestrator_state_text,
22
+ )
23
+ from dev_tools.validate_policy_audit_artifact import validate_policy_audit_text
17
24
 
18
25
  PLAN_PHASE_RE = re.compile(r"^### Phase (?P<phase>\d+) — (?P<title>.+)$")
19
26
  PLAN_TASK_RE = re.compile(
20
27
  r"^- \[(?P<state>[ xX])\] \[P(?P<phase>\d+)-T(?P<task>\d+)\] (?P<title>.+)$"
21
28
  )
22
- COVERAGE_PERCENT_RE = re.compile(r"\b\d+(?:\.\d+)?%")
23
-
24
- POLICY_AUDIT_REQUIRED_HEADINGS = (
25
- "## Executive Summary",
26
- "## 1. General Unit Test Policy Compliance",
27
- "## 2. General Code Change Policy Compliance",
28
- "## 3. Language-Specific Code Change Policy Compliance",
29
- "## 4. Language-Specific Unit Test Policy Compliance",
30
- "## 5. Test Coverage Detail",
31
- "## 6. Test Execution Metrics",
32
- "## 7. Code Quality Checks",
33
- "## 8. Gaps and Exceptions",
34
- "## 9. Summary of Changes",
35
- "## 10. Compliance Verdict",
36
- "## Appendix A: Test Inventory",
37
- "## Appendix B: Toolchain Commands Reference",
38
- )
39
- POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = (
40
- "TypeScript baseline coverage artifact:",
41
- "TypeScript post-change coverage artifact:",
42
- "PowerShell baseline coverage artifact:",
43
- "PowerShell post-change coverage artifact:",
44
- "Per-language comparison summary:",
45
- )
46
- POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison"
47
- CODE_REVIEW_REQUIRED_HEADINGS = (
48
- "## Executive Summary",
49
- "## Findings Table",
50
- )
51
- FEATURE_AUDIT_REQUIRED_HEADINGS = (
52
- "## Scope and Baseline",
53
- "## Acceptance Criteria Inventory",
54
- "## Acceptance Criteria Evaluation",
55
- "## Summary",
56
- "## Acceptance Criteria Check-off",
57
- )
58
- REQUIRED_STATE_KEYS = (
59
- "objective",
60
- "change_budget_estimate",
61
- "path_selected",
62
- "promotion-type",
63
- "short-name",
64
- "relativeFile",
65
- "long-name",
66
- "issue-num",
67
- "feature-folder",
68
- "work-mode",
69
- "plan-path",
70
- "completed_steps",
71
- "next_step",
72
- "last_updated",
73
- "step5_status",
74
- "step6_status",
75
- "step7_status",
76
- "step8_status",
77
- "step9_status",
78
- "step10_status",
79
- "delegation_receipts",
80
- "blocked_reason",
81
- )
82
- VALID_STEP_STATUS = {"not-applicable", "pending", "delegated", "verified", "blocked"}
83
- VALID_BLOCKED_REASONS = {
84
- "none",
85
- "spawn_agent_unavailable",
86
- "delegation_launch_failed",
87
- "delegate_no_receipt",
88
- "delegate_contract_incomplete",
89
- "validator_failed",
90
- "user_requested_stop",
91
- }
92
- REQUIRED_RECEIPT_KEYS = (
93
- "step",
94
- "agent_name",
95
- "agent_id",
96
- "skill_source",
97
- "started_at",
98
- "completed_at",
99
- "result_signal",
100
- "artifact_paths",
101
- )
102
- PLACEHOLDER_MARKERS = (
103
- "[n]",
104
- "[path",
105
- "[artifact",
106
- "[section reference",
107
- "[language]",
108
- "tbd",
109
- "unverified",
110
- "missing",
111
- )
112
29
 
113
30
 
114
31
  def _read_text(path: Path) -> str:
115
- """Read a UTF-8 artifact from disk."""
32
+ """Read a UTF-8 artifact from disk.
33
+
34
+ Purpose:
35
+ Centralize file reading for the CLI dispatcher and monkeypatched unit
36
+ tests.
37
+
38
+ Args:
39
+ path (Path): Artifact path to read.
40
+
41
+ Returns:
42
+ str: UTF-8 text content for the requested artifact.
43
+
44
+ Raises:
45
+ OSError: Raised when the file cannot be read.
46
+
47
+ Side Effects:
48
+ Reads from disk.
49
+ """
116
50
 
117
51
  return path.read_text(encoding="utf-8")
118
52
 
119
53
 
120
54
  def validate_plan_text(text: str) -> list[str]:
121
- """Validate canonical atomic-plan structure."""
55
+ """Validate canonical atomic-plan structure.
56
+
57
+ Purpose:
58
+ Enforce the repository's required phase and task formatting for atomic
59
+ execution plans.
60
+
61
+ Args:
62
+ text (str): Full plan document text.
63
+
64
+ Returns:
65
+ list[str]: Validation errors describing any structural contract
66
+ violations.
67
+
68
+ Raises:
69
+ None.
70
+
71
+ Side Effects:
72
+ None.
73
+ """
122
74
 
123
75
  errors: list[str] = []
124
76
  current_phase: int | None = None
@@ -126,6 +78,8 @@ def validate_plan_text(text: str) -> list[str]:
126
78
  expected_task_num: dict[int, int] = {}
127
79
  found_task = False
128
80
 
81
+ # Walk the document in source order so numbering and phase mismatches are
82
+ # reported against the same line numbers a maintainer sees in the plan.
129
83
  for line_number, line in enumerate(text.splitlines(), start=1):
130
84
  if line.startswith("### Phase "):
131
85
  match = PLAN_PHASE_RE.match(line)
@@ -179,323 +133,26 @@ def validate_plan_text(text: str) -> list[str]:
179
133
  return errors
180
134
 
181
135
 
182
- def _has_numeric_coverage(value: str) -> bool:
183
- """Return True when a coverage value contains a numeric percentage."""
184
-
185
- return COVERAGE_PERCENT_RE.search(value) is not None
186
-
187
-
188
- def _is_na_value(value: str) -> bool:
189
- """Return True when an audit field explicitly records not-applicable."""
190
-
191
- return value.strip().lower().startswith("n/a")
192
-
193
-
194
- def _has_placeholder_marker(value: str) -> bool:
195
- """Return True when an audit field still contains template placeholders."""
196
-
197
- lowered = value.lower()
198
- return any(marker in lowered for marker in PLACEHOLDER_MARKERS)
199
-
200
-
201
- def _extract_policy_audit_coverage_rows(text: str) -> list[dict[str, str]]:
202
- """Parse the coverage metrics table rows from a policy audit."""
203
-
204
- rows: list[dict[str, str]] = []
205
- for line in text.splitlines():
206
- if not line.startswith("|"):
207
- continue
208
- cells = [cell.strip() for cell in line.split("|")[1:-1]]
209
- if len(cells) != 7:
210
- continue
211
- language = cells[0]
212
- if language in {"Language", "----------"} or not language:
213
- continue
214
- if set(language) == {"-"}:
215
- continue
216
- rows.append(
217
- {
218
- "Language": language,
219
- "Files Changed": cells[1],
220
- "Tests": cells[2],
221
- "Test Result": cells[3],
222
- "Baseline Coverage": cells[4],
223
- "Post-Change Coverage": cells[5],
224
- "New Code Coverage": cells[6],
225
- }
226
- )
227
- return rows
228
-
229
-
230
- def _find_policy_audit_checklist_line(text: str, label: str) -> str | None:
231
- """Return the checklist line containing the provided label, if present."""
232
-
233
- for line in text.splitlines():
234
- stripped = line.strip()
235
- if stripped.startswith("- ") and label in stripped:
236
- return stripped
237
- return None
238
-
239
-
240
- def _extract_policy_audit_comparison_lines(text: str) -> dict[str, str]:
241
- """Return per-language comparison lines keyed by normalized language name."""
242
-
243
- in_section = False
244
- comparison_lines: dict[str, str] = {}
245
-
246
- for line in text.splitlines():
247
- stripped = line.strip()
248
- if stripped == POLICY_AUDIT_COMPARISON_HEADING:
249
- in_section = True
250
- continue
251
- if in_section and stripped.startswith("### "):
252
- break
253
- if not in_section or not stripped.startswith("- "):
254
- continue
255
- language, separator, _ = stripped[2:].partition(":")
256
- if not separator:
257
- continue
258
- comparison_lines[language.strip().lower()] = stripped
259
-
260
- return comparison_lines
261
-
262
-
263
- def _comparison_line_has_labelled_percentage(line: str, label: str) -> bool:
264
- """Return True when the line contains a numeric percentage after a label."""
265
-
266
- pattern = re.compile(rf"{re.escape(label)}.*?\d+(?:\.\d+)?%")
267
- return pattern.search(line) is not None
268
-
269
-
270
- def validate_policy_audit_substantive_requirements(text: str) -> list[str]:
271
- """Validate policy-audit evidence requirements beyond headings."""
272
-
273
- errors: list[str] = []
274
-
275
- for label in POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS:
276
- line = _find_policy_audit_checklist_line(text, label)
277
- if line is None:
278
- errors.append(f"Policy audit missing required checklist line: {label}")
279
- continue
280
- if _has_placeholder_marker(line):
281
- errors.append(
282
- f"Policy audit checklist line still contains placeholder text: {label}"
283
- )
284
-
285
- coverage_rows = _extract_policy_audit_coverage_rows(text)
286
- if not coverage_rows:
287
- errors.append("Policy audit missing coverage metrics table rows.")
288
-
289
- if POLICY_AUDIT_COMPARISON_HEADING not in text:
290
- errors.append(
291
- "Policy audit missing required heading: "
292
- f"{POLICY_AUDIT_COMPARISON_HEADING}"
293
- )
294
-
295
- comparison_lines = _extract_policy_audit_comparison_lines(text)
296
- for row in coverage_rows:
297
- language = row["Language"]
298
- baseline = row["Baseline Coverage"]
299
- post_change = row["Post-Change Coverage"]
300
- new_code = row["New Code Coverage"]
301
- requires_coverage_comparison = any(
302
- not _is_na_value(value) for value in (baseline, post_change, new_code)
303
- )
304
-
305
- if not _is_na_value(baseline) and not _has_numeric_coverage(baseline):
306
- errors.append(
307
- f"Policy audit missing numeric baseline coverage for {language}."
308
- )
309
- if not _is_na_value(post_change) and not _has_numeric_coverage(post_change):
310
- errors.append(
311
- f"Policy audit missing numeric post-change coverage for {language}."
312
- )
313
- if not _is_na_value(new_code) and not _has_numeric_coverage(new_code):
314
- errors.append(
315
- f"Policy audit missing numeric new/changed-code coverage for "
316
- f"{language}."
317
- )
318
-
319
- if not requires_coverage_comparison:
320
- continue
321
-
322
- comparison_line = comparison_lines.get(language.lower())
323
- if comparison_line is None:
324
- errors.append(
325
- "Policy audit missing per-language comparison line for " f"{language}."
326
- )
327
- continue
328
-
329
- if not _comparison_line_has_labelled_percentage(comparison_line, "Baseline:"):
330
- errors.append(
331
- f"Policy audit comparison line missing numeric baseline for "
332
- f"{language}."
333
- )
334
- if not _comparison_line_has_labelled_percentage(
335
- comparison_line, "Post-change:"
336
- ):
337
- errors.append(
338
- f"Policy audit comparison line missing numeric post-change "
339
- f"coverage for {language}."
340
- )
341
- if "Change:" not in comparison_line:
342
- errors.append(
343
- f"Policy audit comparison line missing explicit change text for "
344
- f"{language}."
345
- )
346
- if (
347
- re.search(
348
- r"Disposition:\s*(PASS|FAIL|N/A|INCOMPLETE|BLOCKED)",
349
- comparison_line,
350
- )
351
- is None
352
- ):
353
- errors.append(
354
- f"Policy audit comparison line missing disposition for " f"{language}."
355
- )
356
- if not _is_na_value(new_code) and not _comparison_line_has_labelled_percentage(
357
- comparison_line, "New/changed-code coverage:"
358
- ):
359
- errors.append(
360
- "Policy audit comparison line missing numeric new/changed-code "
361
- f"coverage for {language}."
362
- )
363
- if "Evidence:" not in comparison_line:
364
- errors.append(
365
- f"Policy audit comparison line missing evidence reference for "
366
- f"{language}."
367
- )
368
- elif _has_placeholder_marker(comparison_line):
369
- errors.append(
370
- "Policy audit comparison line still contains placeholder text for "
371
- f"{language}."
372
- )
373
-
374
- return errors
375
-
376
-
377
- def validate_policy_audit_text(text: str) -> list[str]:
378
- """Validate template-derived policy-audit structure."""
379
-
380
- errors: list[str] = []
381
- if "Template Usage Instructions" in text:
382
- errors.append("Policy audit still contains the template instruction block.")
383
- if "[Component Name]" in text:
384
- errors.append("Policy audit still contains placeholder component text.")
385
- for heading in POLICY_AUDIT_REQUIRED_HEADINGS:
386
- if heading not in text:
387
- errors.append(f"Policy audit missing required heading: {heading}")
388
- errors.extend(validate_policy_audit_substantive_requirements(text))
389
- return errors
390
-
391
-
392
- def validate_code_review_text(text: str) -> list[str]:
393
- """Validate audit-grade code-review structure."""
394
-
395
- errors: list[str] = []
396
- for heading in CODE_REVIEW_REQUIRED_HEADINGS:
397
- if heading not in text:
398
- errors.append(f"Code review missing required heading: {heading}")
399
- table_header = (
400
- "| Severity | File | Location | Finding | Recommendation | "
401
- "Rationale | Evidence |"
402
- )
403
- if table_header not in text:
404
- errors.append("Code review missing the required findings table header.")
405
- return errors
406
-
407
-
408
- def validate_feature_audit_text(text: str) -> list[str]:
409
- """Validate feature-audit structure."""
136
+ def build_parser() -> argparse.ArgumentParser:
137
+ """Create the CLI parser.
410
138
 
411
- errors: list[str] = []
412
- for heading in FEATURE_AUDIT_REQUIRED_HEADINGS:
413
- if heading not in text:
414
- errors.append(f"Feature audit missing required heading: {heading}")
415
- return errors
139
+ Purpose:
140
+ Define the stable command-line contract for orchestration artifact
141
+ validation.
416
142
 
143
+ Args:
144
+ None.
417
145
 
418
- def validate_orchestrator_state_text(
419
- text: str, *, require_complete: bool = False
420
- ) -> list[str]:
421
- """Validate checkpoint schema and completion-state fields."""
146
+ Returns:
147
+ argparse.ArgumentParser: Configured parser for the supported artifact
148
+ types.
422
149
 
423
- errors: list[str] = []
424
- try:
425
- state = json.loads(text)
426
- except json.JSONDecodeError as exc:
427
- return [f"Checkpoint is not valid JSON: {exc}"]
428
-
429
- if not isinstance(state, dict):
430
- return ["Checkpoint root must be a JSON object."]
431
- state_map = cast("dict[str, Any]", state)
432
-
433
- for key in REQUIRED_STATE_KEYS:
434
- if key not in state_map:
435
- errors.append(f"Checkpoint missing required key: {key}")
436
-
437
- for key in (
438
- "step5_status",
439
- "step6_status",
440
- "step7_status",
441
- "step8_status",
442
- "step9_status",
443
- "step10_status",
444
- ):
445
- value = state_map.get(key)
446
- if value is not None and value not in VALID_STEP_STATUS:
447
- errors.append(f"Checkpoint has invalid {key}: {value}")
448
-
449
- blocked_reason = state_map.get("blocked_reason")
450
- if blocked_reason is not None and blocked_reason not in VALID_BLOCKED_REASONS:
451
- errors.append(f"Checkpoint has invalid blocked_reason: {blocked_reason}")
452
-
453
- receipts = state_map.get("delegation_receipts")
454
- if receipts is not None and not isinstance(receipts, list):
455
- errors.append("Checkpoint delegation_receipts must be a list.")
456
- if isinstance(receipts, list):
457
- typed_receipts = cast("list[object]", receipts)
458
- for index, receipt in enumerate(typed_receipts):
459
- if not isinstance(receipt, dict):
460
- errors.append(
461
- f"Checkpoint delegation receipt #{index} must be an object."
462
- )
463
- continue
464
- for key in REQUIRED_RECEIPT_KEYS:
465
- if key not in receipt:
466
- errors.append(
467
- f"Checkpoint delegation receipt #{index} missing key: {key}"
468
- )
469
- artifact_paths = cast("dict[str, Any]", receipt).get("artifact_paths")
470
- if artifact_paths is not None and not isinstance(artifact_paths, list):
471
- errors.append(
472
- "Checkpoint delegation receipt "
473
- f"#{index} artifact_paths must be a list."
474
- )
475
-
476
- if require_complete:
477
- for key in (
478
- "step5_status",
479
- "step6_status",
480
- "step7_status",
481
- "step8_status",
482
- "step9_status",
483
- "step10_status",
484
- ):
485
- value = state_map.get(key)
486
- if value in {"pending", "blocked"}:
487
- errors.append(
488
- f"Checkpoint completion validation failed: {key} is {value}."
489
- )
490
- if state_map.get("blocked_reason") not in {None, "none"}:
491
- errors.append(
492
- "Checkpoint completion validation failed: blocked_reason is not `none`."
493
- )
494
- return errors
150
+ Raises:
151
+ None.
495
152
 
496
-
497
- def build_parser() -> argparse.ArgumentParser:
498
- """Create the CLI parser."""
153
+ Side Effects:
154
+ None.
155
+ """
499
156
 
500
157
  parser = argparse.ArgumentParser(
501
158
  description="Validate deterministic orchestration artifacts."
@@ -517,7 +174,24 @@ def build_parser() -> argparse.ArgumentParser:
517
174
 
518
175
 
519
176
  def _validate_from_args(args: argparse.Namespace) -> list[str]:
520
- """Dispatch the requested validator."""
177
+ """Dispatch the requested validator.
178
+
179
+ Purpose:
180
+ Route the parsed CLI request to the correct validator without changing
181
+ the public artifact-type names accepted by the entrypoint.
182
+
183
+ Args:
184
+ args (argparse.Namespace): Parsed CLI arguments.
185
+
186
+ Returns:
187
+ list[str]: Validation errors produced by the selected validator.
188
+
189
+ Raises:
190
+ None.
191
+
192
+ Side Effects:
193
+ Reads the target artifact from disk.
194
+ """
521
195
 
522
196
  path = Path(args.path)
523
197
  text = _read_text(path)
@@ -537,7 +211,25 @@ def _validate_from_args(args: argparse.Namespace) -> list[str]:
537
211
 
538
212
 
539
213
  def main(argv: list[str] | None = None) -> int:
540
- """Run the orchestration-artifact validator CLI."""
214
+ """Run the orchestration-artifact validator CLI.
215
+
216
+ Purpose:
217
+ Execute the stable CLI entrypoint that validates orchestration plans,
218
+ review artifacts, and checkpoint state.
219
+
220
+ Args:
221
+ argv (list[str] | None): Optional command-line arguments for testing or
222
+ programmatic invocation.
223
+
224
+ Returns:
225
+ int: Exit code `0` for success and `1` for validation failure.
226
+
227
+ Raises:
228
+ None.
229
+
230
+ Side Effects:
231
+ Reads files from disk and writes validation results to stdout/stderr.
232
+ """
541
233
 
542
234
  parser = build_parser()
543
235
  args = parser.parse_args(argv)
@@ -0,0 +1,107 @@
1
+ """Validate non-policy review-oriented orchestration artifacts.
2
+
3
+ Purpose:
4
+ Hold the code-review and feature-audit validators while re-exporting the
5
+ split policy-audit validator from its dedicated module.
6
+
7
+ Usage:
8
+ Import the public validation functions from
9
+ ``scripts.dev_tools.validate_orchestration_artifacts`` or directly from this
10
+ module when a caller needs the review-specific validators.
11
+
12
+ Flow:
13
+ 1. Delegate policy-audit validation to the split policy-audit module.
14
+ 2. Validate code-review and feature-audit headings locally.
15
+ 3. Return a list of contract violations for the caller to surface.
16
+
17
+ Invariants / Constraints:
18
+ - The public validator functions return lists of error strings and do not
19
+ print or mutate files.
20
+ - The module preserves the existing import surface for callers that still
21
+ import ``validate_policy_audit_text`` from this module.
22
+
23
+ Side Effects:
24
+ None.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ from dev_tools.validate_policy_audit_artifact import validate_policy_audit_text
30
+
31
+ __all__ = [
32
+ "validate_policy_audit_text",
33
+ "validate_code_review_text",
34
+ "validate_feature_audit_text",
35
+ ]
36
+
37
+ CODE_REVIEW_REQUIRED_HEADINGS = (
38
+ "## Executive Summary",
39
+ "## Findings Table",
40
+ )
41
+ FEATURE_AUDIT_REQUIRED_HEADINGS = (
42
+ "## Scope and Baseline",
43
+ "## Acceptance Criteria Inventory",
44
+ "## Acceptance Criteria Evaluation",
45
+ "## Summary",
46
+ "## Acceptance Criteria Check-off",
47
+ )
48
+
49
+
50
+ def validate_code_review_text(text: str) -> list[str]:
51
+ """Validate audit-grade code-review structure.
52
+
53
+ Purpose:
54
+ Require the minimal headings and findings table that repository code
55
+ reviews must include.
56
+
57
+ Args:
58
+ text (str): Full code-review artifact text.
59
+
60
+ Returns:
61
+ list[str]: Validation errors for missing headings or table structure.
62
+
63
+ Raises:
64
+ None.
65
+
66
+ Side Effects:
67
+ None.
68
+ """
69
+
70
+ errors: list[str] = []
71
+ for heading in CODE_REVIEW_REQUIRED_HEADINGS:
72
+ if heading not in text:
73
+ errors.append(f"Code review missing required heading: {heading}")
74
+ table_header = (
75
+ "| Severity | File | Location | Finding | Recommendation | "
76
+ "Rationale | Evidence |"
77
+ )
78
+ if table_header not in text:
79
+ errors.append("Code review missing the required findings table header.")
80
+ return errors
81
+
82
+
83
+ def validate_feature_audit_text(text: str) -> list[str]:
84
+ """Validate feature-audit structure.
85
+
86
+ Purpose:
87
+ Require the canonical sections that tie implementation evidence back to
88
+ acceptance criteria.
89
+
90
+ Args:
91
+ text (str): Full feature-audit artifact text.
92
+
93
+ Returns:
94
+ list[str]: Validation errors for any missing canonical sections.
95
+
96
+ Raises:
97
+ None.
98
+
99
+ Side Effects:
100
+ None.
101
+ """
102
+
103
+ errors: list[str] = []
104
+ for heading in FEATURE_AUDIT_REQUIRED_HEADINGS:
105
+ if heading not in text:
106
+ errors.append(f"Feature audit missing required heading: {heading}")
107
+ return errors