@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
@@ -0,0 +1,428 @@
1
+ """Validate orchestration checkpoint state artifacts.
2
+
3
+ Purpose:
4
+ Hold the orchestrator-state validation logic and receipt-namespace rules so
5
+ the stable CLI entrypoint can remain small while preserving the existing
6
+ validator contract.
7
+
8
+ Usage:
9
+ Import ``validate_orchestrator_state_text`` from
10
+ ``scripts.dev_tools.validate_orchestration_artifacts`` or directly from this
11
+ module when a caller needs checkpoint validation.
12
+
13
+ Flow:
14
+ 1. Parse the checkpoint JSON payload.
15
+ 2. Validate required top-level keys and status values.
16
+ 3. Validate either the legacy list-based receipts or the additive
17
+ ``delegation_receipts.promotion.*`` namespace.
18
+
19
+ Invariants / Constraints:
20
+ - The validator accepts both the legacy list and the additive promotion
21
+ namespace forms for ``delegation_receipts``.
22
+ - Unsupported namespace keys are rejected.
23
+ - The validator returns error strings and never mutates the checkpoint.
24
+
25
+ Side Effects:
26
+ None.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ from typing import Any, cast
33
+
34
+ from dev_tools._orchestrator_state_human_interaction import (
35
+ HUMAN_INTERACTION_KEY,
36
+ _validate_human_interaction,
37
+ )
38
+ from dev_tools._orchestrator_state_routing import validate_routing_contract
39
+
40
+ REQUIRED_STATE_KEYS = (
41
+ "objective",
42
+ "change_budget_estimate",
43
+ "path_selected",
44
+ "promotion-type",
45
+ "short-name",
46
+ "relativeFile",
47
+ "long-name",
48
+ "issue-num",
49
+ "feature-folder",
50
+ "work-mode",
51
+ "plan-path",
52
+ "completed_steps",
53
+ "next_step",
54
+ "last_updated",
55
+ "step5_status",
56
+ "step6_status",
57
+ "step7_status",
58
+ "step8_status",
59
+ "step9_status",
60
+ "step10_status",
61
+ "delegation_receipts",
62
+ "blocked_reason",
63
+ )
64
+ VALID_STEP_STATUS = {
65
+ "not-applicable",
66
+ "pending",
67
+ "delegated",
68
+ "verified",
69
+ "blocked",
70
+ "not_started",
71
+ "in_progress",
72
+ "completed",
73
+ }
74
+ VALID_BLOCKED_REASONS = {
75
+ "none",
76
+ "spawn_agent_unavailable",
77
+ "delegation_launch_failed",
78
+ "delegate_no_receipt",
79
+ "delegate_contract_incomplete",
80
+ "validator_failed",
81
+ "user_requested_stop",
82
+ }
83
+ REQUIRED_RECEIPT_KEYS = (
84
+ "step",
85
+ "agent_name",
86
+ "agent_id",
87
+ "skill_source",
88
+ "started_at",
89
+ "completed_at",
90
+ "result_signal",
91
+ "artifact_paths",
92
+ )
93
+ PROMOTION_RECEIPT_NAMESPACE_KEY = "promotion"
94
+ PROMOTION_RECEIPT_KEYS = (
95
+ "potential_entry",
96
+ "issue",
97
+ "feature_folder",
98
+ )
99
+ REMEDIATION_LOOP_KEY = "remediation_loop"
100
+ REMEDIATION_CYCLES_KEY = "cycles"
101
+ # Execution statuses that may only be recorded once a cycle's preflight gate has
102
+ # cleared; recording any of these before preflight clears is a malformed cycle.
103
+ EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT = {
104
+ "in_progress",
105
+ "complete",
106
+ "failed",
107
+ }
108
+ PREFLIGHT_CLEARED_STATUS = "clear"
109
+
110
+
111
+ def _validate_remediation_cycle(index: int, cycle: dict[str, Any]) -> list[str]:
112
+ """Validate the three invariants for one remediation cycle.
113
+
114
+ Purpose:
115
+ Enforce the orchestrator-state remediation-cycle invariants documented
116
+ in `.claude/rules/orchestrator-state.md` for a single cycle object:
117
+ non-empty `plan_path`, execution only after a cleared preflight, and a
118
+ satisfied exit gate only with zero blocking findings.
119
+
120
+ Args:
121
+ index (int): Zero-based position of this cycle within the
122
+ `remediation_loop.cycles` array, used for error context.
123
+ cycle (dict[str, Any]): The raw cycle object extracted from the
124
+ checkpoint JSON.
125
+
126
+ Returns:
127
+ list[str]: One error string per violated invariant; an empty list when
128
+ the cycle satisfies all three invariants.
129
+
130
+ Raises:
131
+ None.
132
+
133
+ Side Effects:
134
+ None.
135
+ """
136
+
137
+ errors: list[str] = []
138
+
139
+ # Invariant 1: plan_path must be a non-empty, non-whitespace string.
140
+ plan_path = cycle.get("plan_path")
141
+ if not isinstance(plan_path, str) or not plan_path.strip():
142
+ errors.append(
143
+ f"Checkpoint remediation cycle #{index} plan_path must be a "
144
+ "non-empty string."
145
+ )
146
+
147
+ # Invariant 2: an execution status in the blocked set requires that the
148
+ # cycle's preflight gate reports exactly the cleared status.
149
+ execution_status = cycle.get("execution_status")
150
+ if execution_status in EXECUTION_STATUSES_REQUIRING_CLEAR_PREFLIGHT:
151
+ preflight = cycle.get("preflight")
152
+ # Read the nested preflight final status defensively; a missing or
153
+ # non-object preflight cannot satisfy the cleared requirement.
154
+ preflight_status: object = (
155
+ cast("dict[str, Any]", preflight).get("final_status")
156
+ if isinstance(preflight, dict)
157
+ else None
158
+ )
159
+ if preflight_status != PREFLIGHT_CLEARED_STATUS:
160
+ errors.append(
161
+ f"Checkpoint remediation cycle #{index} execution_status is "
162
+ f"{execution_status} but preflight.final_status is not 'clear'."
163
+ )
164
+
165
+ # Invariant 3: a satisfied exit gate requires zero blocking findings.
166
+ if cycle.get("exit_condition_met") is True and cycle.get("blocking_count") != 0:
167
+ errors.append(
168
+ f"Checkpoint remediation cycle #{index} exit_condition_met is true "
169
+ "but blocking_count is not 0."
170
+ )
171
+
172
+ return errors
173
+
174
+
175
+ def _validate_remediation_loop(remediation_loop: object) -> list[str]:
176
+ """Validate the remediation-loop structure and each of its cycles.
177
+
178
+ Purpose:
179
+ Apply the additive remediation-cycle invariants only when a checkpoint
180
+ carries a `remediation_loop`. When the structure is absent, malformed,
181
+ or has no cycles, the function produces no errors so existing
182
+ step-based checkpoints validate unchanged.
183
+
184
+ Args:
185
+ remediation_loop (object): The raw value of the checkpoint's top-level
186
+ `remediation_loop` key.
187
+
188
+ Returns:
189
+ list[str]: Validation errors collected across all cycles; empty when no
190
+ cycles are present or the structure carries no cycle objects.
191
+
192
+ Raises:
193
+ None.
194
+
195
+ Side Effects:
196
+ None.
197
+ """
198
+
199
+ errors: list[str] = []
200
+
201
+ # A non-object remediation_loop carries no cycles to validate; treat it as
202
+ # nothing to enforce rather than fabricating a structural error here.
203
+ if not isinstance(remediation_loop, dict):
204
+ return errors
205
+ loop_map = cast("dict[str, Any]", remediation_loop)
206
+
207
+ cycles = loop_map.get(REMEDIATION_CYCLES_KEY)
208
+ if not isinstance(cycles, list):
209
+ return errors
210
+ cycle_list = cast("list[object]", cycles)
211
+
212
+ # Validate each cycle independently so callers receive a complete error
213
+ # list instead of stopping at the first malformed cycle.
214
+ for index, cycle in enumerate(cycle_list):
215
+ if not isinstance(cycle, dict):
216
+ errors.append(f"Checkpoint remediation cycle #{index} must be an object.")
217
+ continue
218
+ errors.extend(_validate_remediation_cycle(index, cast("dict[str, Any]", cycle)))
219
+
220
+ return errors
221
+
222
+
223
+ def _validate_list_delegation_receipts(receipts: list[object]) -> list[str]:
224
+ """Validate the legacy list-based delegation receipt payload.
225
+
226
+ Purpose:
227
+ Preserve compatibility with older checkpoints that store delegation
228
+ receipts as a list of receipt objects.
229
+
230
+ Args:
231
+ receipts (list[object]): Raw receipt payload extracted from the
232
+ checkpoint JSON.
233
+
234
+ Returns:
235
+ list[str]: Validation errors for any malformed receipt objects.
236
+
237
+ Raises:
238
+ None.
239
+
240
+ Side Effects:
241
+ None.
242
+ """
243
+
244
+ errors: list[str] = []
245
+
246
+ # Validate each legacy receipt independently so callers receive a complete
247
+ # error list instead of stopping at the first malformed item.
248
+ for index, receipt in enumerate(receipts):
249
+ if not isinstance(receipt, dict):
250
+ errors.append(f"Checkpoint delegation receipt #{index} must be an object.")
251
+ continue
252
+ for key in REQUIRED_RECEIPT_KEYS:
253
+ if key not in receipt:
254
+ errors.append(
255
+ f"Checkpoint delegation receipt #{index} missing key: {key}"
256
+ )
257
+ artifact_paths = cast("dict[str, Any]", receipt).get("artifact_paths")
258
+ if artifact_paths is not None and not isinstance(artifact_paths, list):
259
+ errors.append(
260
+ "Checkpoint delegation receipt "
261
+ f"#{index} artifact_paths must be a list."
262
+ )
263
+
264
+ return errors
265
+
266
+
267
+ def _validate_namespaced_delegation_receipts(receipts: dict[str, Any]) -> list[str]:
268
+ """Validate the additive object namespace form of delegation receipts.
269
+
270
+ Purpose:
271
+ Enforce the reviewed ``delegation_receipts.promotion.*`` contract while
272
+ keeping the raw receipt payloads opaque to the validator.
273
+
274
+ Args:
275
+ receipts (dict[str, Any]): Object-form receipt payload extracted from
276
+ the checkpoint JSON.
277
+
278
+ Returns:
279
+ list[str]: Validation errors for unsupported object-shape keys.
280
+
281
+ Raises:
282
+ None.
283
+
284
+ Side Effects:
285
+ None.
286
+ """
287
+
288
+ errors: list[str] = []
289
+ unsupported_keys = sorted(
290
+ key for key in receipts if key != PROMOTION_RECEIPT_NAMESPACE_KEY
291
+ )
292
+ for key in unsupported_keys:
293
+ errors.append(
294
+ f"Checkpoint delegation_receipts object contains unsupported key: {key}"
295
+ )
296
+
297
+ promotion_receipts = receipts.get(PROMOTION_RECEIPT_NAMESPACE_KEY)
298
+ if promotion_receipts is None:
299
+ return errors
300
+ if not isinstance(promotion_receipts, dict):
301
+ errors.append(
302
+ "Checkpoint delegation_receipts.promotion must be an object namespace."
303
+ )
304
+ return errors
305
+
306
+ promotion_receipt_map = cast("dict[str, Any]", promotion_receipts)
307
+ unsupported_promotion_keys = sorted(
308
+ key for key in promotion_receipt_map if key not in PROMOTION_RECEIPT_KEYS
309
+ )
310
+
311
+ # Reject unknown nested keys while leaving the documented raw receipt values
312
+ # untouched and unnormalized.
313
+ for key in unsupported_promotion_keys:
314
+ errors.append(
315
+ "Checkpoint delegation_receipts.promotion contains unsupported key: "
316
+ f"{key}"
317
+ )
318
+
319
+ return errors
320
+
321
+
322
+ def validate_orchestrator_state_text(
323
+ text: str, *, require_complete: bool = False
324
+ ) -> list[str]:
325
+ """Validate checkpoint schema and completion-state fields.
326
+
327
+ Purpose:
328
+ Enforce the repository contract for orchestrator-state artifacts before
329
+ resume or review workflows rely on the checkpoint contents.
330
+
331
+ Args:
332
+ text (str): Raw checkpoint JSON text.
333
+ require_complete (bool): When True, require all tracked lifecycle states
334
+ to be completion-safe.
335
+
336
+ Returns:
337
+ list[str]: Validation errors for malformed or incomplete checkpoint
338
+ state.
339
+
340
+ Raises:
341
+ None.
342
+
343
+ Side Effects:
344
+ None.
345
+ """
346
+
347
+ errors: list[str] = []
348
+ try:
349
+ state = json.loads(text)
350
+ except json.JSONDecodeError as exc:
351
+ return [f"Checkpoint is not valid JSON: {exc}"]
352
+
353
+ if not isinstance(state, dict):
354
+ return ["Checkpoint root must be a JSON object."]
355
+ state_map = cast("dict[str, Any]", state)
356
+
357
+ # Require the canonical top-level fields before evaluating deeper state and
358
+ # receipt invariants.
359
+ for key in REQUIRED_STATE_KEYS:
360
+ if key not in state_map:
361
+ errors.append(f"Checkpoint missing required key: {key}")
362
+
363
+ for key in (
364
+ "step5_status",
365
+ "step6_status",
366
+ "step7_status",
367
+ "step8_status",
368
+ "step9_status",
369
+ "step10_status",
370
+ ):
371
+ value = state_map.get(key)
372
+ if value is not None and value not in VALID_STEP_STATUS:
373
+ errors.append(f"Checkpoint has invalid {key}: {value}")
374
+
375
+ blocked_reason = state_map.get("blocked_reason")
376
+ if blocked_reason is not None and blocked_reason not in VALID_BLOCKED_REASONS:
377
+ errors.append(f"Checkpoint has invalid blocked_reason: {blocked_reason}")
378
+
379
+ receipts = state_map.get("delegation_receipts")
380
+ if receipts is not None:
381
+ if isinstance(receipts, list):
382
+ errors.extend(
383
+ _validate_list_delegation_receipts(cast("list[object]", receipts))
384
+ )
385
+ elif isinstance(receipts, dict):
386
+ errors.extend(
387
+ _validate_namespaced_delegation_receipts(
388
+ cast("dict[str, Any]", receipts)
389
+ )
390
+ )
391
+ else:
392
+ errors.append(
393
+ "Checkpoint delegation_receipts must be a list or object namespace."
394
+ )
395
+
396
+ # Apply the additive remediation-cycle invariants only when the checkpoint
397
+ # carries a remediation_loop; absent the key, behavior is unchanged.
398
+ if REMEDIATION_LOOP_KEY in state_map:
399
+ errors.extend(_validate_remediation_loop(state_map.get(REMEDIATION_LOOP_KEY)))
400
+
401
+ # Apply the additive human_interaction invariants only when the checkpoint
402
+ # carries a human_interaction key; absent the key, behavior is unchanged.
403
+ if HUMAN_INTERACTION_KEY in state_map:
404
+ errors.extend(_validate_human_interaction(state_map.get(HUMAN_INTERACTION_KEY)))
405
+
406
+ if require_complete:
407
+ # Enforce completion-safe lifecycle states only when the caller opts into
408
+ # the stricter completion gate.
409
+ for key in (
410
+ "step5_status",
411
+ "step6_status",
412
+ "step7_status",
413
+ "step8_status",
414
+ "step9_status",
415
+ "step10_status",
416
+ ):
417
+ value = state_map.get(key)
418
+ if value in {"pending", "blocked"}:
419
+ errors.append(
420
+ f"Checkpoint completion validation failed: {key} is {value}."
421
+ )
422
+ if state_map.get("blocked_reason") not in {None, "none"}:
423
+ errors.append(
424
+ "Checkpoint completion validation failed: blocked_reason is not `none`."
425
+ )
426
+ errors.extend(validate_routing_contract(state_map))
427
+
428
+ return errors