@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.
- package/out/mcp-server.js +5 -1
- package/package.json +21 -5
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +15 -3
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_branch_base_check_unmerged_pr_deps.md +16 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_every_change_through_lifecycle.md +15 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_policy_compliance_not_optional.md +18 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_potential_to_issue_creates_github_issue.md +13 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_remediation_plan_em_dash_required.md +13 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_small_bug_uses_minor_audit.md +13 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +13 -0
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +7 -7
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +4 -5
- package/resources/claude-customizations/.claude/agents/feature-review.md +7 -3
- package/resources/claude-customizations/.claude/agents/orchestrator.md +16 -1
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +245 -0
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +273 -0
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +148 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +190 -0
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +216 -0
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +84 -15
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +1 -1
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +75 -5
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +93 -0
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +68 -0
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +46 -0
- package/resources/claude-customizations/.claude/rules/benchmark-baselines.md +35 -0
- package/resources/claude-customizations/.claude/rules/ci-workflows.md +36 -0
- package/resources/claude-customizations/.claude/rules/csharp.md +62 -16
- package/resources/claude-customizations/.claude/rules/general-code-change.md +12 -3
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +47 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +39 -0
- package/resources/claude-customizations/.claude/rules/powershell.md +5 -5
- package/resources/claude-customizations/.claude/rules/python.md +4 -3
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +51 -0
- package/resources/claude-customizations/.claude/rules/typescript.md +37 -8
- package/resources/claude-customizations/.claude/settings.json +37 -12
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/csharp-qa-gate/SKILL.md +25 -10
- package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +6 -6
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +8 -8
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +17 -6
- package/resources/claude-customizations/.claude/skills/human-exception-runbook/SKILL.md +52 -0
- package/resources/claude-customizations/.claude/skills/human-exception-runbook/example.runbook.md +36 -0
- package/resources/claude-customizations/.claude/skills/invoke-csharp-engineer/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +96 -3
- package/resources/claude-customizations/.claude/skills/policy-audit-template-usage/SKILL.md +3 -3
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/pr-base-branch-merge-base/SKILL.md +3 -3
- package/resources/claude-customizations/.claude/skills/python-qa-gate/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +90 -17
- package/resources/claude-dir-customizations/.mcp.json +3 -3
- package/resources/codex-and-agents-customizations/.agents/README.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +52 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +16 -8
- package/resources/codex-and-agents-customizations/.agents/skills/benchmark-baselines/SKILL.md +44 -0
- package/resources/codex-and-agents-customizations/.agents/skills/ci-workflows/SKILL.md +45 -0
- package/resources/codex-and-agents-customizations/.agents/skills/commit-message/SKILL.md +3 -11
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +1 -5
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -6
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-orchestration-state-machine/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +8 -17
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +13 -14
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +1 -6
- package/resources/codex-and-agents-customizations/.agents/skills/fill-feature-docs/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +86 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +111 -0
- package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/SKILL.md +57 -0
- package/resources/codex-and-agents-customizations/.agents/skills/human-exception-runbook/example.runbook.md +36 -0
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +0 -9
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +0 -9
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +0 -9
- package/resources/codex-and-agents-customizations/.agents/skills/make-skill-template/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +93 -8
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-state/SKILL.md +48 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +61 -2
- package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +3 -8
- package/resources/codex-and-agents-customizations/.agents/skills/policy-compliance-order/SKILL.md +0 -10
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +4 -8
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -6
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-orchestration-state-machine/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +3 -9
- package/resources/codex-and-agents-customizations/.agents/skills/pr-author/SKILL.md +1 -9
- package/resources/codex-and-agents-customizations/.agents/skills/pr-base-branch-merge-base/SKILL.md +4 -9
- package/resources/codex-and-agents-customizations/.agents/skills/pr-context-artifacts/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +1 -5
- package/resources/codex-and-agents-customizations/.agents/skills/python-change-budget-router/SKILL.md +1 -6
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +2 -6
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +57 -0
- package/resources/codex-and-agents-customizations/.agents/skills/remediation-handoff-atomic-planner/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/SKILL.md +91 -72
- package/resources/codex-and-agents-customizations/.agents/skills/repo-automation-adapter/agents/openai.yaml +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +0 -10
- package/resources/codex-and-agents-customizations/.agents/skills/review-epic/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/review-feature/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/review-staged/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +2 -6
- package/resources/codex-and-agents-customizations/.agents/skills/skill-canonical-location-audit/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +86 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +297 -0
- package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +0 -22
- package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +1 -5
- package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +2 -6
- package/resources/codex-and-agents-customizations/.agents/skills/update-status/SKILL.md +0 -5
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +5 -5
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +91 -63
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-atomic-executor.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +51 -136
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/prompts/orchestrate-work.md +4 -3
- package/resources/codex-and-agents-customizations/.codex/scripts/post-codex-worktree-session.ps1 +5 -0
- package/resources/codex-and-agents-customizations/.github/workflows/_validate-orchestrator-state.yml +68 -0
- package/resources/codex-and-agents-customizations/.github/workflows/validate-orchestrator-state.yml +15 -0
- package/resources/config/orchestration-routing.json +84 -0
- package/resources/customizations/.github/agents/Powershell DI Unit Test Engineer.agent.md +1 -1
- package/resources/customizations/.github/agents/atomic_executor.agent.md +1 -1
- package/resources/customizations/.github/agents/atomic_planning.agent.md +10 -10
- package/resources/customizations/.github/agents/csharp-orchestrator.agent.md +6 -2
- package/resources/customizations/.github/agents/feature-review.agent.md +2 -2
- package/resources/customizations/.github/agents/orchestrator.agent.md +6 -2
- package/resources/customizations/.github/agents/powershell-atomic-executor.agent.md +4 -4
- package/resources/customizations/.github/agents/powershell-atomic-planning.agent.md +10 -10
- package/resources/customizations/.github/agents/powershell-orchestrator.agent.md +6 -2
- package/resources/customizations/.github/agents/powershell-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/agents/python-orchestrator.agent.md +6 -2
- package/resources/customizations/.github/agents/staged-review.agent.md +1 -1
- package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +6 -6
- package/resources/customizations/.github/prompts/generate-commit-message-repo.prompt.md +1 -1
- package/resources/customizations/.github/prompts/orchestrate-csharp-work.prompt.md +5 -3
- package/resources/customizations/.github/prompts/orchestrate-work.prompt.md +5 -3
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +14 -1
- package/resources/customizations/.github/skills/feature-promotion-lifecycle/SKILL.md +11 -7
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +10 -1
- package/resources/customizations/.github/skills/pr-base-branch-merge-base/SKILL.md +2 -2
- package/resources/customizations/.github/skills/remediation-handoff-atomic-planner/SKILL.md +5 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +7 -0
- package/resources/scripts/dev_tools/_orchestrator_state_human_interaction.py +127 -0
- package/resources/scripts/dev_tools/_orchestrator_state_routing.py +216 -0
- package/resources/scripts/dev_tools/push_down_claude_customizations.py +191 -5
- package/resources/scripts/dev_tools/validate_orchestration_artifacts.py +103 -411
- package/resources/scripts/dev_tools/validate_orchestration_review_artifacts.py +107 -0
- package/resources/scripts/dev_tools/validate_orchestrator_state.py +428 -0
- package/resources/scripts/dev_tools/validate_policy_audit_artifact.py +448 -0
- package/resources/templates/push_down_claude_customizations.py +227 -6
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_repo_root_is_source_of_truth.md +0 -11
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_vsce_verify_package_location.md +0 -19
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/project_extension_location.md +0 -11
- package/resources/claude-customizations/.claude/agent-memory/prd-feature/MEMORY.md +0 -1
- package/resources/claude-customizations/.claude/agent-memory/prd-feature/project_push_down_pattern.md +0 -13
- package/resources/claude-customizations/.claude/agent-memory/task-researcher/MEMORY.md +0 -3
- package/resources/claude-customizations/.claude/agent-memory/task-researcher/project_push_down_claude_dir.md +0 -11
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"""Validate policy-audit orchestration review artifacts.
|
|
2
|
+
|
|
3
|
+
Purpose:
|
|
4
|
+
Hold the policy-audit specific parsing helpers and substantive validation
|
|
5
|
+
checks so the review-artifact validator stays cohesive and below the
|
|
6
|
+
repository file-size limit.
|
|
7
|
+
|
|
8
|
+
Usage:
|
|
9
|
+
Import ``validate_policy_audit_text`` from this module when a caller needs
|
|
10
|
+
only policy-audit validation, or through
|
|
11
|
+
``scripts.dev_tools.validate_orchestration_artifacts`` for the stable CLI
|
|
12
|
+
entrypoint contract.
|
|
13
|
+
|
|
14
|
+
Flow:
|
|
15
|
+
1. Parse the coverage table, checklist lines, and per-language comparison
|
|
16
|
+
bullets from the policy-audit document.
|
|
17
|
+
2. Reject placeholder, malformed, or non-numeric coverage evidence when the
|
|
18
|
+
repository policy requires explicit percentages.
|
|
19
|
+
3. Return a list of contract violations for the caller to surface.
|
|
20
|
+
|
|
21
|
+
Invariants / Constraints:
|
|
22
|
+
- Placeholder markers are treated as failures.
|
|
23
|
+
- Coverage rows must retain numeric evidence unless the field is marked N/A.
|
|
24
|
+
- The public validator functions return lists of error strings and do not
|
|
25
|
+
print or mutate files.
|
|
26
|
+
|
|
27
|
+
Side Effects:
|
|
28
|
+
None.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from __future__ import annotations
|
|
32
|
+
|
|
33
|
+
import re
|
|
34
|
+
|
|
35
|
+
COVERAGE_PERCENT_RE = re.compile(r"\b\d+(?:\.\d+)?%")
|
|
36
|
+
POLICY_AUDIT_REQUIRED_HEADINGS = (
|
|
37
|
+
"## Executive Summary",
|
|
38
|
+
"## 1. General Unit Test Policy Compliance",
|
|
39
|
+
"## 2. General Code Change Policy Compliance",
|
|
40
|
+
"## 3. Language-Specific Code Change Policy Compliance",
|
|
41
|
+
"## 4. Language-Specific Unit Test Policy Compliance",
|
|
42
|
+
"## 5. Test Coverage Detail",
|
|
43
|
+
"## 6. Test Execution Metrics",
|
|
44
|
+
"## 7. Code Quality Checks",
|
|
45
|
+
"## 8. Gaps and Exceptions",
|
|
46
|
+
"## 9. Summary of Changes",
|
|
47
|
+
"## 10. Compliance Verdict",
|
|
48
|
+
"## Appendix A: Test Inventory",
|
|
49
|
+
"## Appendix B: Toolchain Commands Reference",
|
|
50
|
+
)
|
|
51
|
+
POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS = (
|
|
52
|
+
"TypeScript baseline coverage artifact:",
|
|
53
|
+
"TypeScript post-change coverage artifact:",
|
|
54
|
+
"PowerShell baseline coverage artifact:",
|
|
55
|
+
"PowerShell post-change coverage artifact:",
|
|
56
|
+
"Per-language comparison summary:",
|
|
57
|
+
)
|
|
58
|
+
POLICY_AUDIT_COMPARISON_HEADING = "### 1.2.1 Per-Language Coverage Comparison"
|
|
59
|
+
PLACEHOLDER_MARKERS = (
|
|
60
|
+
"[n]",
|
|
61
|
+
"[path",
|
|
62
|
+
"[artifact",
|
|
63
|
+
"[section reference",
|
|
64
|
+
"[language]",
|
|
65
|
+
"tbd",
|
|
66
|
+
"unverified",
|
|
67
|
+
"missing",
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _has_numeric_coverage(value: str) -> bool:
|
|
72
|
+
"""Return True when a coverage field contains a numeric percentage.
|
|
73
|
+
|
|
74
|
+
Purpose:
|
|
75
|
+
Identify whether a coverage field satisfies the policy requirement for
|
|
76
|
+
explicit numeric evidence.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
value (str): Raw coverage field text extracted from an audit artifact.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
bool: True when the value contains at least one percentage token.
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
None.
|
|
86
|
+
|
|
87
|
+
Side Effects:
|
|
88
|
+
None.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
return COVERAGE_PERCENT_RE.search(value) is not None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _is_na_value(value: str) -> bool:
|
|
95
|
+
"""Return True when an audit field explicitly records not-applicable.
|
|
96
|
+
|
|
97
|
+
Purpose:
|
|
98
|
+
Allow the validator to distinguish missing numeric evidence from fields
|
|
99
|
+
that are intentionally marked not applicable.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
value (str): Raw field text to inspect.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
bool: True when the value begins with an N/A marker.
|
|
106
|
+
|
|
107
|
+
Raises:
|
|
108
|
+
None.
|
|
109
|
+
|
|
110
|
+
Side Effects:
|
|
111
|
+
None.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
return value.strip().lower().startswith("n/a")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _has_placeholder_marker(value: str) -> bool:
|
|
118
|
+
"""Return True when a field still contains template placeholder text.
|
|
119
|
+
|
|
120
|
+
Purpose:
|
|
121
|
+
Fail closed when a review artifact still includes unfinished template or
|
|
122
|
+
draft markers.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
value (str): Raw field text to inspect.
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
bool: True when the field includes a known placeholder marker.
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
None.
|
|
132
|
+
|
|
133
|
+
Side Effects:
|
|
134
|
+
None.
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
lowered = value.lower()
|
|
138
|
+
return any(marker in lowered for marker in PLACEHOLDER_MARKERS)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _extract_policy_audit_coverage_rows(text: str) -> list[dict[str, str]]:
|
|
142
|
+
"""Parse the policy-audit coverage table into named row dictionaries.
|
|
143
|
+
|
|
144
|
+
Purpose:
|
|
145
|
+
Normalize coverage table rows so later validation checks can reason
|
|
146
|
+
about baseline, post-change, and new-code evidence by language.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
text (str): Full policy-audit artifact text.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
list[dict[str, str]]: Parsed coverage rows keyed by canonical column
|
|
153
|
+
names.
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
None.
|
|
157
|
+
|
|
158
|
+
Side Effects:
|
|
159
|
+
None.
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
rows: list[dict[str, str]] = []
|
|
163
|
+
|
|
164
|
+
# Interpret only the seven-column coverage table rows and ignore headers or
|
|
165
|
+
# separator rows.
|
|
166
|
+
for line in text.splitlines():
|
|
167
|
+
if not line.startswith("|"):
|
|
168
|
+
continue
|
|
169
|
+
cells = [cell.strip() for cell in line.split("|")[1:-1]]
|
|
170
|
+
if len(cells) != 7:
|
|
171
|
+
continue
|
|
172
|
+
language = cells[0]
|
|
173
|
+
if language in {"Language", "----------"} or not language:
|
|
174
|
+
continue
|
|
175
|
+
if set(language) == {"-"}:
|
|
176
|
+
continue
|
|
177
|
+
rows.append(
|
|
178
|
+
{
|
|
179
|
+
"Language": language,
|
|
180
|
+
"Files Changed": cells[1],
|
|
181
|
+
"Tests": cells[2],
|
|
182
|
+
"Test Result": cells[3],
|
|
183
|
+
"Baseline Coverage": cells[4],
|
|
184
|
+
"Post-Change Coverage": cells[5],
|
|
185
|
+
"New Code Coverage": cells[6],
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return rows
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _find_policy_audit_checklist_line(text: str, label: str) -> str | None:
|
|
193
|
+
"""Return the checklist line containing a required label.
|
|
194
|
+
|
|
195
|
+
Purpose:
|
|
196
|
+
Locate required evidence checklist entries without assuming a fixed line
|
|
197
|
+
number or surrounding context.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
text (str): Full policy-audit artifact text.
|
|
201
|
+
label (str): Required checklist label to locate.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
str | None: The matching checklist line, if present.
|
|
205
|
+
|
|
206
|
+
Raises:
|
|
207
|
+
None.
|
|
208
|
+
|
|
209
|
+
Side Effects:
|
|
210
|
+
None.
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
# Search only checklist bullets because the same label text may appear in
|
|
214
|
+
# narrative prose elsewhere in the document.
|
|
215
|
+
for line in text.splitlines():
|
|
216
|
+
stripped = line.strip()
|
|
217
|
+
if stripped.startswith("- ") and label in stripped:
|
|
218
|
+
return stripped
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _extract_policy_audit_comparison_lines(text: str) -> dict[str, str]:
|
|
223
|
+
"""Return per-language comparison lines keyed by normalized language name.
|
|
224
|
+
|
|
225
|
+
Purpose:
|
|
226
|
+
Capture the explicit comparison bullets under the per-language coverage
|
|
227
|
+
section so downstream checks can verify each language summary is present.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
text (str): Full policy-audit artifact text.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
dict[str, str]: Mapping of lowercase language name to the matching
|
|
234
|
+
comparison bullet.
|
|
235
|
+
|
|
236
|
+
Raises:
|
|
237
|
+
None.
|
|
238
|
+
|
|
239
|
+
Side Effects:
|
|
240
|
+
None.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
in_section = False
|
|
244
|
+
comparison_lines: dict[str, str] = {}
|
|
245
|
+
|
|
246
|
+
# Limit parsing to the per-language coverage section so unrelated bullets do
|
|
247
|
+
# not satisfy the evidence checks accidentally.
|
|
248
|
+
for line in text.splitlines():
|
|
249
|
+
stripped = line.strip()
|
|
250
|
+
if stripped == POLICY_AUDIT_COMPARISON_HEADING:
|
|
251
|
+
in_section = True
|
|
252
|
+
continue
|
|
253
|
+
if in_section and stripped.startswith("### "):
|
|
254
|
+
break
|
|
255
|
+
if not in_section or not stripped.startswith("- "):
|
|
256
|
+
continue
|
|
257
|
+
language, separator, _ = stripped[2:].partition(":")
|
|
258
|
+
if not separator:
|
|
259
|
+
continue
|
|
260
|
+
comparison_lines[language.strip().lower()] = stripped
|
|
261
|
+
|
|
262
|
+
return comparison_lines
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _comparison_line_has_labelled_percentage(line: str, label: str) -> bool:
|
|
266
|
+
"""Return True when the comparison line includes a labelled percentage.
|
|
267
|
+
|
|
268
|
+
Purpose:
|
|
269
|
+
Verify that each comparison bullet records numeric evidence after the
|
|
270
|
+
expected label, rather than narrative text alone.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
line (str): Comparison bullet text.
|
|
274
|
+
label (str): Required label to anchor the percentage search.
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
bool: True when the labelled numeric evidence is present.
|
|
278
|
+
|
|
279
|
+
Raises:
|
|
280
|
+
None.
|
|
281
|
+
|
|
282
|
+
Side Effects:
|
|
283
|
+
None.
|
|
284
|
+
"""
|
|
285
|
+
|
|
286
|
+
pattern = re.compile(rf"{re.escape(label)}.*?\d+(?:\.\d+)?%")
|
|
287
|
+
return pattern.search(line) is not None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def validate_policy_audit_substantive_requirements(text: str) -> list[str]:
|
|
291
|
+
"""Validate policy-audit evidence requirements beyond headings.
|
|
292
|
+
|
|
293
|
+
Purpose:
|
|
294
|
+
Enforce the numeric coverage and evidence checklist requirements that
|
|
295
|
+
turn the review template into an auditable artifact.
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
text (str): Full policy-audit artifact text.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
list[str]: Validation errors describing each missing or malformed
|
|
302
|
+
evidence element.
|
|
303
|
+
|
|
304
|
+
Raises:
|
|
305
|
+
None.
|
|
306
|
+
|
|
307
|
+
Side Effects:
|
|
308
|
+
None.
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
errors: list[str] = []
|
|
312
|
+
|
|
313
|
+
# Require every checklist line to exist and remain free of unresolved
|
|
314
|
+
# placeholders before the audit can report a passing verdict.
|
|
315
|
+
for label in POLICY_AUDIT_REQUIRED_CHECKLIST_LABELS:
|
|
316
|
+
line = _find_policy_audit_checklist_line(text, label)
|
|
317
|
+
if line is None:
|
|
318
|
+
errors.append(f"Policy audit missing required checklist line: {label}")
|
|
319
|
+
continue
|
|
320
|
+
if _has_placeholder_marker(line):
|
|
321
|
+
errors.append(
|
|
322
|
+
f"Policy audit checklist line still contains placeholder text: {label}"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
coverage_rows = _extract_policy_audit_coverage_rows(text)
|
|
326
|
+
if not coverage_rows:
|
|
327
|
+
errors.append("Policy audit missing coverage metrics table rows.")
|
|
328
|
+
|
|
329
|
+
if POLICY_AUDIT_COMPARISON_HEADING not in text:
|
|
330
|
+
errors.append(
|
|
331
|
+
"Policy audit missing required heading: "
|
|
332
|
+
f"{POLICY_AUDIT_COMPARISON_HEADING}"
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
comparison_lines = _extract_policy_audit_comparison_lines(text)
|
|
336
|
+
|
|
337
|
+
# Validate each language row against the comparison summary so baseline,
|
|
338
|
+
# post-change, and changed-code evidence remain synchronized.
|
|
339
|
+
for row in coverage_rows:
|
|
340
|
+
language = row["Language"]
|
|
341
|
+
baseline = row["Baseline Coverage"]
|
|
342
|
+
post_change = row["Post-Change Coverage"]
|
|
343
|
+
new_code = row["New Code Coverage"]
|
|
344
|
+
requires_coverage_comparison = any(
|
|
345
|
+
not _is_na_value(value) for value in (baseline, post_change, new_code)
|
|
346
|
+
)
|
|
347
|
+
|
|
348
|
+
if not _is_na_value(baseline) and not _has_numeric_coverage(baseline):
|
|
349
|
+
errors.append(
|
|
350
|
+
f"Policy audit missing numeric baseline coverage for {language}."
|
|
351
|
+
)
|
|
352
|
+
if not _is_na_value(post_change) and not _has_numeric_coverage(post_change):
|
|
353
|
+
errors.append(
|
|
354
|
+
f"Policy audit missing numeric post-change coverage for {language}."
|
|
355
|
+
)
|
|
356
|
+
if not _is_na_value(new_code) and not _has_numeric_coverage(new_code):
|
|
357
|
+
errors.append(
|
|
358
|
+
"Policy audit missing numeric new/changed-code coverage for "
|
|
359
|
+
f"{language}."
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
if not requires_coverage_comparison:
|
|
363
|
+
continue
|
|
364
|
+
|
|
365
|
+
comparison_line = comparison_lines.get(language.lower())
|
|
366
|
+
if comparison_line is None:
|
|
367
|
+
errors.append(
|
|
368
|
+
f"Policy audit missing per-language comparison line for {language}."
|
|
369
|
+
)
|
|
370
|
+
continue
|
|
371
|
+
|
|
372
|
+
if not _comparison_line_has_labelled_percentage(comparison_line, "Baseline:"):
|
|
373
|
+
errors.append(
|
|
374
|
+
f"Policy audit comparison line missing numeric baseline for {language}."
|
|
375
|
+
)
|
|
376
|
+
if not _comparison_line_has_labelled_percentage(
|
|
377
|
+
comparison_line, "Post-change:"
|
|
378
|
+
):
|
|
379
|
+
errors.append(
|
|
380
|
+
"Policy audit comparison line missing numeric post-change "
|
|
381
|
+
f"coverage for {language}."
|
|
382
|
+
)
|
|
383
|
+
if "Change:" not in comparison_line:
|
|
384
|
+
errors.append(
|
|
385
|
+
"Policy audit comparison line missing explicit change text for "
|
|
386
|
+
f"{language}."
|
|
387
|
+
)
|
|
388
|
+
if (
|
|
389
|
+
re.search(
|
|
390
|
+
r"Disposition:\s*(PASS|FAIL|N/A|INCOMPLETE|BLOCKED)",
|
|
391
|
+
comparison_line,
|
|
392
|
+
)
|
|
393
|
+
is None
|
|
394
|
+
):
|
|
395
|
+
errors.append(
|
|
396
|
+
f"Policy audit comparison line missing disposition for {language}."
|
|
397
|
+
)
|
|
398
|
+
if not _is_na_value(new_code) and not _comparison_line_has_labelled_percentage(
|
|
399
|
+
comparison_line, "New/changed-code coverage:"
|
|
400
|
+
):
|
|
401
|
+
errors.append(
|
|
402
|
+
"Policy audit comparison line missing numeric new/changed-code "
|
|
403
|
+
f"coverage for {language}."
|
|
404
|
+
)
|
|
405
|
+
if "Evidence:" not in comparison_line:
|
|
406
|
+
errors.append(
|
|
407
|
+
"Policy audit comparison line missing evidence reference for "
|
|
408
|
+
f"{language}."
|
|
409
|
+
)
|
|
410
|
+
elif _has_placeholder_marker(comparison_line):
|
|
411
|
+
errors.append(
|
|
412
|
+
"Policy audit comparison line still contains placeholder text for "
|
|
413
|
+
f"{language}."
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
return errors
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def validate_policy_audit_text(text: str) -> list[str]:
|
|
420
|
+
"""Validate template-derived policy-audit structure.
|
|
421
|
+
|
|
422
|
+
Purpose:
|
|
423
|
+
Enforce the required policy-audit headings and substantive evidence
|
|
424
|
+
checks for repository review artifacts.
|
|
425
|
+
|
|
426
|
+
Args:
|
|
427
|
+
text (str): Full policy-audit artifact text.
|
|
428
|
+
|
|
429
|
+
Returns:
|
|
430
|
+
list[str]: Validation errors for missing headings or evidence.
|
|
431
|
+
|
|
432
|
+
Raises:
|
|
433
|
+
None.
|
|
434
|
+
|
|
435
|
+
Side Effects:
|
|
436
|
+
None.
|
|
437
|
+
"""
|
|
438
|
+
|
|
439
|
+
errors: list[str] = []
|
|
440
|
+
if "Template Usage Instructions" in text:
|
|
441
|
+
errors.append("Policy audit still contains the template instruction block.")
|
|
442
|
+
if "[Component Name]" in text:
|
|
443
|
+
errors.append("Policy audit still contains placeholder component text.")
|
|
444
|
+
for heading in POLICY_AUDIT_REQUIRED_HEADINGS:
|
|
445
|
+
if heading not in text:
|
|
446
|
+
errors.append(f"Policy audit missing required heading: {heading}")
|
|
447
|
+
errors.extend(validate_policy_audit_substantive_requirements(text))
|
|
448
|
+
return errors
|