@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,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
|