@danmoisan/drm-copilot-mcp 1.1.18 → 1.1.19
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 +989 -662
- package/package.json +3 -2
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +11 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +10 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +12 -4
- package/resources/claude-customizations/.claude/agents/epic-planner.md +5 -4
- package/resources/claude-customizations/.claude/agents/feature-review.md +6 -4
- package/resources/claude-customizations/.claude/agents/orchestrator.md +5 -4
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +31 -13
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +9 -6
- package/resources/claude-customizations/.claude/agents/pr-author.md +15 -2
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -1
- package/resources/claude-customizations/.claude/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-completion-consistency.ps1 +111 -46
- package/resources/claude-customizations/.claude/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +8 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-invocation-origin.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-resolution.ps1 +116 -59
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +55 -23
- package/resources/claude-customizations/.claude/hooks/enforce-epic-wave-barrier.ps1 +74 -75
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +127 -35
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +61 -57
- package/resources/claude-customizations/.claude/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-feature-folder-order.ps1 +129 -39
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +7 -1
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +39 -51
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +17 -12
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-abandon-gate.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-cohort-barrier.ps1 +65 -50
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-drift-gate.ps1 +49 -42
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +54 -72
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +279 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +129 -75
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.artifact-root.ps1 +233 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.docs-only.ps1 +224 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.ps1 +69 -24
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner-helpers.ps1 +29 -18
- package/resources/claude-customizations/.claude/hooks/enforce-prd-feature-before-planner.ps1 +10 -4
- package/resources/claude-customizations/.claude/hooks/enforce-promotion-mcp-only.ps1 +14 -5
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/claude-customizations/.claude/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/claude-customizations/.claude/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/claude-customizations/.claude/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-payload.ps1 +484 -0
- package/resources/claude-customizations/.claude/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/claude-customizations/.claude/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/claude-customizations/.claude/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/claude-customizations/.claude/hooks/subagentstop-envelope.ps1 +192 -0
- package/resources/claude-customizations/.claude/hooks/validate-bash.ps1 +9 -3
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +40 -42
- package/resources/claude-customizations/.claude/hooks/validate-executor-output.ps1 +66 -38
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-metrics.ps1 +180 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage-rules.ps1 +195 -0
- package/resources/claude-customizations/.claude/hooks/validate-feature-review-coverage.ps1 +141 -395
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-resolution.ps1 +311 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-routing.ps1 +170 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +115 -190
- package/resources/claude-customizations/.claude/hooks/validate-planner-output.ps1 +64 -32
- package/resources/claude-customizations/.claude/hooks/validate-pr-author-output.ps1 +39 -44
- package/resources/claude-customizations/.claude/hooks/validate-prd-feature-output.ps1 +43 -14
- package/resources/claude-customizations/.claude/hooks/validate-required-artifact-output.ps1 +66 -36
- package/resources/claude-customizations/.claude/hooks/validate-task-researcher-output.ps1 +31 -34
- package/resources/claude-customizations/.claude/lib/bash/mutate-parallel-run.sh +191 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-cohorts.sh +13 -3
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-cli.sh +152 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation-ops.sh +193 -0
- package/resources/claude-customizations/.claude/lib/bash/parallel-mutation.sh +322 -0
- package/resources/claude-customizations/.claude/lib/bash/remove-parallel-item.sh +146 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +23 -33
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +86 -6
- package/resources/claude-customizations/.claude/lib/ci-gate/Invoke-CiGateParser.ps1 +91 -19
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1 +346 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +24 -3
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeItemResolution.psm1 +79 -2
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +3 -3
- package/resources/claude-customizations/.claude/rules/architecture-boundaries.md +5 -5
- package/resources/claude-customizations/.claude/rules/csharp.md +2 -2
- package/resources/claude-customizations/.claude/rules/general-code-change.md +1 -1
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +3 -2
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +37 -4
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +50 -5
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +47 -8
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +11 -7
- package/resources/claude-customizations/.claude/rules/shell.md +10 -8
- package/resources/claude-customizations/.claude/rules/typescript.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +3 -4
- package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +5 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_detached_lib.sh +1 -1
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh +2 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_scan_helper.sh +2 -0
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +33 -6
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -3
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +14 -6
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +52 -14
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +22 -9
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +79 -16
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +63 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +35 -12
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +3 -1
- package/resources/claude-customizations/.claude/skills/quota-throttling/SKILL.md +1 -1
- package/resources/claude-customizations/.claude/skills/remediation-handoff-atomic-planner/SKILL.md +2 -2
- package/resources/claude-customizations/pack-manifests/core.json +23 -0
- package/resources/codex-and-agents-customizations/.agents/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +5 -5
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-executor/SKILL.md +11 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +10 -0
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents/skills/epic-orchestrate/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +17 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-run/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review-workflow/SKILL.md +13 -5
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +15 -6
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +11 -7
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.agents-variants/csharp-legacy/skills/csharp-qa-gate/SKILL.md +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c1.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c2.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3-elevated.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c3.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor-c4.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-executor.toml +11 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c1.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c2.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3-elevated.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c3.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner-c4.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/atomic-planner.toml +10 -0
- package/resources/codex-and-agents-customizations/.codex/agents/epic-orchestrator.toml +2 -1
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +6 -6
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c1.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c2.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3-elevated.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c3.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator-c4.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +2 -2
- package/resources/codex-and-agents-customizations/.codex/codex-web-setup.sh +318 -273
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-powershell-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/check-python-test-purity.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-epic-child-launch-attestation.ps1 +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-checkpoint-monotonic.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +97 -44
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +105 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-child-worktree-binding.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-merge-gate.ps1 +37 -5
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-planning-only.ps1 +6 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-root-invocation.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-wave-barrier.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-epic-worktree-removal-gate.ps1 +54 -41
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-evidence-locations.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +35 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +31 -58
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-modes.ps1 +63 -47
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-targets.ps1 +433 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +24 -11
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-promotion-mcp-only.ps1 +13 -4
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-folder-resolution.ps1 +373 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/feature-review-coverage-thresholds.ps1 +85 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-heredoc.ps1 +119 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation-operands.ps1 +198 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-invocation.ps1 +254 -255
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload-powershell.ps1 +201 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-payload.ps1 +484 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-command-scanner.ps1 +27 -110
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-dependency-guard.ps1 +114 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-docs-only-diff.ps1 +493 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-bash.ps1 +8 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +7 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-feature-review-coverage.ps1 +24 -8
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +9 -0
- package/resources/customizations/.github/agents/csharp-typed-engineer.agent.md +2 -2
- package/resources/customizations/.github/instructions/csharp-code-change.instructions.md +4 -4
- package/resources/customizations/.github/instructions/csharp-unit-test.instructions.md +2 -2
- package/resources/customizations/.github/skills/acceptance-criteria-tracking/SKILL.md +1 -1
- package/resources/customizations/.github/skills/atomic-plan-contract/SKILL.md +4 -0
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +10 -1
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +1 -1
- package/resources/powershell/PoshQC/PoshQC.Coverage.psm1 +314 -0
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +25 -28
- package/resources/powershell/PoshQC/PoshQC.psm1 +1 -0
- package/resources/powershell/PoshQC/README.md +8 -2
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +2 -319
|
@@ -32,6 +32,37 @@ A hardened snapshot from another repository contains a JSON Schema for the orche
|
|
|
32
32
|
|
|
33
33
|
This prohibition is specific to the disqualified foreign schema identified by the `drmoisan.github.io/mix-calculator/` `$id`. A schema whose `$id` is repo-local and whose required-field set and `additionalProperties` policy match this repository's checkpoint contract is not the disqualified foreign artifact; even so, the repository's enforcement mechanism remains the Python validator prose-and-logic above, not an imported schema file.
|
|
34
34
|
|
|
35
|
+
## Required Top-Level Keys
|
|
36
|
+
|
|
37
|
+
Plain validation requires every key below at the top level of the orchestrator-state checkpoint. The authority is `REQUIRED_STATE_KEYS` in `scripts/dev_tools/validate_orchestrator_state.py`. The TypeScript port in `extensions/drm-copilot/src/lib/validate/orchestrator-state-core.ts` and the PowerShell port in `.claude/lib/orchestrator-state/OrchestratorState.psm1` carry the same keys in the same order.
|
|
38
|
+
|
|
39
|
+
- `objective`
|
|
40
|
+
- `change_budget_estimate`
|
|
41
|
+
- `path_selected`
|
|
42
|
+
- `promotion-type`
|
|
43
|
+
- `short-name`
|
|
44
|
+
- `relativeFile`
|
|
45
|
+
- `long-name`
|
|
46
|
+
- `issue-num`
|
|
47
|
+
- `feature-folder`
|
|
48
|
+
- `work-mode`
|
|
49
|
+
- `plan-path`
|
|
50
|
+
- `completed_steps`
|
|
51
|
+
- `next_step`
|
|
52
|
+
- `last_updated`
|
|
53
|
+
- `step5_status`
|
|
54
|
+
- `step6_status`
|
|
55
|
+
- `step7_status`
|
|
56
|
+
- `step8_status`
|
|
57
|
+
- `step9_status`
|
|
58
|
+
- `step10_status`
|
|
59
|
+
- `delegation_receipts`
|
|
60
|
+
- `blocked_reason`
|
|
61
|
+
|
|
62
|
+
The check is unconditional: it runs with or without `--require-complete`, `--require-pr-creation-ready`, `--require-model-routing`, `--require-codex-model-routing`, and `--require-codex-topology`, and it is skipped only for a `portable_orchestration_handoff` envelope. The check is presence-only: a key whose value is any JSON value, including `null`, satisfies it. Each absent key produces one error line, `Checkpoint missing required key: <key>`. Some keys carry further validation when present, such as the step-status vocabulary for the `step*_status` keys and the Blocked-Reason Vocabulary below for `blocked_reason`.
|
|
63
|
+
|
|
64
|
+
`last_updated` records when the checkpoint was last written. Write it as an ISO-8601 UTC date-time string, for example `2026-10-08T17:28:00Z`. The value is rewritten on every checkpoint write: after every completed step and every state transition, including halts. The validators check presence only and do not parse the value, so a non-UTC, placeholder, or `null` value still passes the required-key check.
|
|
65
|
+
|
|
35
66
|
## Scope and Backward Compatibility
|
|
36
67
|
|
|
37
68
|
These invariants apply only when the checkpoint contains a top-level `remediation_loop`; the per-cycle invariants apply when it has a `cycles` array, and the review-outcome and attempt-count invariants apply when their keys are present. A checkpoint with no `remediation_loop` (the existing step-based checkpoint shape) is unaffected: it validates exactly as before and produces no new errors. The invariants are additive.
|
|
@@ -170,7 +201,7 @@ The complexity-assessment and model-routing-receipt invariants above are key-gat
|
|
|
170
201
|
|
|
171
202
|
## Bare-Module CLI Contract
|
|
172
203
|
|
|
173
|
-
The validator module runs directly as `python -m scripts.dev_tools.validate_orchestrator_state <path> [--require-complete] [--require-model-routing] [--require-pr-creation-ready] [--require-codex-model-routing] [--require-codex-topology]`. The dispatcher `python -m scripts.dev_tools.validate_orchestration_artifacts orchestrator-state
|
|
204
|
+
The validator module runs directly as `python -m scripts.dev_tools.validate_orchestrator_state <path> [--require-complete] [--require-model-routing] [--require-pr-creation-ready] [--require-codex-model-routing] [--require-codex-topology]`. The dispatcher stays available and accepts the same flags in two invocation forms: the module form `python -m scripts.dev_tools.validate_orchestration_artifacts orchestrator-state`, run from the repository root, and the file-path form `python scripts/dev_tools/validate_orchestration_artifacts.py orchestrator-state`. Both forms reach the same `main()`, so their flags, output lines, and exit codes are identical, and a relative artifact path resolves against the working directory in both. The file-path form derives the repository root from the script location and inserts it first in `sys.path` only when the script runs without a package context. The bare-module validator is supported in the module form only. Exit code 0 means the checkpoint passed and the success line `orchestrator-state validation passed: <path>` is written to stdout. Exit code 1 means validation errors, written one per stderr line. Exit code 2 means the path is missing, unreadable, or not UTF-8, with one stderr diagnostic and no traceback; argparse usage errors also exit 2.
|
|
174
205
|
|
|
175
206
|
## Invariants (require_model_routing mode)
|
|
176
207
|
|
|
@@ -204,7 +235,7 @@ Enforcement is validator logic plus this prose, never an imported JSON Schema. T
|
|
|
204
235
|
|
|
205
236
|
These invariants apply only when a checkpoint contains a top-level `standalone_merge_authorizations` array. The key may appear in any of the three checkpoints the epic merge gate reads: `artifacts/orchestration/orchestrator-state.json`, `artifacts/orchestration/epic-orchestrator-state.json`, and `artifacts/orchestration/parallel-orchestrator-state.json`. A checkpoint with no such key (the existing checkpoint shape) is unaffected: it validates exactly as before and produces no new errors. The invariants are additive and key-gated. No JSON Schema file is authored, imported, or read for the block (see the Foreign Schema Warning above); the enforcing surface is the `PreToolUse` merge gate (issue #670).
|
|
206
237
|
|
|
207
|
-
Each entry records one authorized standalone merge with the shape `{ pr_number, pr_url, issue_num, branch_name, authorized_by, authorized_at, session_id, basis, run_slug? }`. The gate consults the array only for a `gh pr merge --merge` command that names an explicit pull request number, and only after its per-feature, epic, and parallel allow conditions have all declined.
|
|
238
|
+
Each entry records one authorized standalone merge with the shape `{ pr_number, pr_url, issue_num, branch_name, authorized_by, authorized_at, session_id, basis, run_slug? }`. The gate consults the array only for a `gh pr merge --merge` command that names an explicit pull request number, and only after its per-feature, epic, and parallel allow conditions have all declined. For a command that names an explicit pull request number, the gate reads the per-feature checkpoint `artifacts/orchestration/orchestrator-state.json` beneath the one live worktree whose checkpoint records that number in `pr_gate.pr_number` or in a `standalone_merge_authorizations` entry, and it reads no per-feature checkpoint when no live worktree or more than one records it; a bare command reads the checkpoint beneath the session worktree.
|
|
208
239
|
|
|
209
240
|
Honest disclosure: the standalone-merge authorization record is a policy-level, auditable declaration and is
|
|
210
241
|
not a cryptographic or security control.
|
|
@@ -243,7 +274,7 @@ The object has the shape `{ issue_num, issue_url, origin, verified_via, verified
|
|
|
243
274
|
| `verified_at` | Present, not `null`, and not a blank string. |
|
|
244
275
|
| `evidence` | A string with non-whitespace content. |
|
|
245
276
|
| `waived_tools` | A non-empty list of non-blank tool names that includes `potential_to_issue`. |
|
|
246
|
-
| `potential_record` |
|
|
277
|
+
| `potential_record` | When waiving a promotion-entry tool: required when `origin` is `epic_decomposition`, optional when `origin` is `transferred` or `filed_before_orchestration`, and validated whenever it is present (a path under `docs/features/potential/` ending in `.md`). |
|
|
247
278
|
|
|
248
279
|
The rules run in this order, and their errors accumulate:
|
|
249
280
|
|
|
@@ -255,10 +286,12 @@ The rules run in this order, and their errors accumulate:
|
|
|
255
286
|
6. `verified_at` must be present: absent, `null`, and blank strings are rejected; any other value passes.
|
|
256
287
|
7. `evidence` must be a non-empty string.
|
|
257
288
|
8. `waived_tools` must be a non-empty list of non-blank strings; otherwise no further rule-8 or rule-9 check runs. Each entry, in list order, receives the first applicable error of: listed more than once; not in the closed waivable set; not required by the selected route after promotion-type resolution; already holding a successful MCP receipt. The list must include `potential_to_issue`.
|
|
258
|
-
9. Only when the rule-8 shape check passed: each distinct waived promotion-entry tool (`new_potential_entry` or `new_potential_bug_entry`) requires a valid `potential_record
|
|
289
|
+
9. Only when the rule-8 shape check passed: each distinct waived promotion-entry tool (`new_potential_entry` or `new_potential_bug_entry`) requires a valid `potential_record`, except that rule 9 reports nothing when `origin` is `transferred` or `filed_before_orchestration` and the `potential_record` key is absent. A present `potential_record`, including `null`, is always validated.
|
|
259
290
|
|
|
260
291
|
The closed waivable set is `potential_to_issue`, `new_potential_entry`, and `new_potential_bug_entry`. `new_active_feature_folder`, `collect_pr_context`, `validate_orchestration_artifacts`, and every other tool can never be waived. All comparisons are ordinal and case-sensitive.
|
|
261
292
|
|
|
293
|
+
A lifecycle record moved to `docs/features/potential/promoted/` satisfies the `potential_record` path rule, because the rule checks only the `docs/features/potential/` prefix and the `.md` suffix and does not check that the file exists.
|
|
294
|
+
|
|
262
295
|
Fail-closed behavior: any adoption error waives nothing, so each missing receipt is still reported as `Checkpoint missing successful MCP receipt: <tool>.`. Adoption errors are placed after the receipt-loop errors and before the `local_execution_overrides` errors. The waiver affects only receipt presence: the declared `required_mcp_tools` equality check with the routing matrix is unchanged, so a checkpoint must still declare every route tool it waives.
|
|
263
296
|
|
|
264
297
|
## Enforcement
|
|
@@ -87,13 +87,13 @@ When `require_complete` is not passed, invariants 20 and 21 contribute zero erro
|
|
|
87
87
|
|
|
88
88
|
## Invariants (parallel planner checkpoint)
|
|
89
89
|
|
|
90
|
-
Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_execution=False)` in `scripts/dev_tools/validate_parallel_planner_state.py`. P1 through P4 are enforced unconditionally; P6 through
|
|
90
|
+
Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_execution=False)` in `scripts/dev_tools/validate_parallel_planner_state.py`. P1 through P4 are enforced unconditionally; P6 through P10 are ready-gate invariants, enforced only under `require_ready_for_execution`.
|
|
91
91
|
|
|
92
92
|
- **P1 — Required keys.** The checkpoint must carry `objective`, `parallel_slug`, `parallel_manifest_path`, `mode`, `max_concurrency`, `items`, `cohorts`, `conflict_edges`, `recolor_generation`, `completed_steps`, `next_step`, and `last_updated`. One error is emitted per missing key. `kickoff_prompt_path` is optional outside the ready gate.
|
|
93
93
|
|
|
94
94
|
- **P2 — Route-consistent identity.** `parallel_slug` and `parallel_manifest_path` must be non-empty strings; `mode` and `max_concurrency` satisfy orchestrator invariants 3 and 4.
|
|
95
95
|
|
|
96
|
-
- **P3 — Item shape.** Each `items[]` entry must carry `issue_num`, `feature_folder`, `kind`, `state`, `blast_radius`, `preparation_status`, `research_path`, `plan_path`, and `preflight_status`. `issue_num` must be a positive integer unique across items; `kind` must be in `{feature, bug}`; `state` must be in the item-state enum; `blast_radius` must satisfy orchestrator invariant 9; `complexity_band
|
|
96
|
+
- **P3 — Item shape.** Each `items[]` entry must carry `issue_num`, `feature_folder`, `kind`, `state`, `blast_radius`, `preparation_status`, `research_path`, `plan_path`, and `preflight_status`. `issue_num` must be a positive integer unique across items; `kind` must be in `{feature, bug}`; `state` must be in the item-state enum; `blast_radius` must satisfy orchestrator invariant 9; `complexity_band` is optional outside the ready gate (P10 requires it under `require_ready_for_execution`) and, when present, must be in `{C1, C2, C3, C4}`. The prohibited-key rejections of orchestrator invariants 10 and 11 apply.
|
|
97
97
|
|
|
98
98
|
- **P4 — Cohort and edge shape.** `cohorts[]`, `conflict_edges[]`, and `recolor_generation` satisfy orchestrator invariants 12 through 15.
|
|
99
99
|
|
|
@@ -107,7 +107,9 @@ Enforced by `validate_parallel_planner_state_text(text, *, require_ready_for_exe
|
|
|
107
107
|
|
|
108
108
|
- **P9 — Ready gate, kickoff path.** Under `require_ready_for_execution`, `kickoff_prompt_path` must be exactly `artifacts/orchestration/parallel-kickoff-<parallel_slug>.md`.
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
- **P10 — Ready gate, routing record.** Under `require_ready_for_execution`, each object-shaped item must carry `complexity_band` in `{C1, C2, C3, C4}`; a `complexity_assessment` object `{band, floor, signals_present, rationale, assessed_at}` whose `floor` equals `compute_complexity_floor(signals_present)`, whose `band` is at or above `floor` and equals `complexity_band`, and whose `rationale` and `assessed_at` are non-empty strings; and a Claude `model_routing_receipt` object `{agent, phase, complexity_band, fable_policy, table_model, clamped_from, model}` with `agent == 'orchestrator'`, `complexity_band` equal to the item's band, `fable_policy` in `{disabled, available, preferred}`, and `model` equal to `resolve_delegation_model('orchestrator', complexity_band, fable_policy)['model']`, including the disabled-mode clamp invariants. The checks run per item in this order: (1) the band enum, reported as `None` when absent; (2) the assessment object, skipping checks 3 through 5 when it fails; (3) the assessment entry checks of `_validate_complexity_assessments`, prefix-rewritten to `<item> complexity_assessment`; (4) `assessed_at`; (5) assessment band equals item band; (6) the receipt object, skipping checks 7 through 10 when it fails; (7) the receipt entry checks of `_validate_model_routing_receipts`, prefix-rewritten to `<item> model_routing_receipt`; (8) `agent`; (9) receipt band equals item band; (10) the `fable_policy` enum. Checks 5 and 9 are reported whenever the two values differ, including when check 1 failed. Each item's P10 errors follow that item's P7 errors.
|
|
111
|
+
|
|
112
|
+
The planner checkpoint carries no `epic_worthiness` analogue and no `NON_EPIC_RECOMMENDED` branch; the parallel surface has no worthiness verdict, and scale assessment happens before parallel planning is invoked. When `require_ready_for_execution` is not passed, P6 through P10 contribute zero errors.
|
|
111
113
|
|
|
112
114
|
## Invariants (parallel run manifest)
|
|
113
115
|
|
|
@@ -380,6 +382,44 @@ admits.
|
|
|
380
382
|
Enforcement of this rejection is prose plus validator logic, exactly as for the three shapes above.
|
|
381
383
|
No JSON Schema is authored, imported, or read for it, and `config/blast-radius.json` gains no key.
|
|
382
384
|
|
|
385
|
+
### File-shape recognition (issue #797)
|
|
386
|
+
|
|
387
|
+
The classifier accepts a wildcard-free token that carries a separator only when its final component
|
|
388
|
+
names a file. After any `:<line>` suffix is stripped, the final component names a file when either
|
|
389
|
+
condition holds:
|
|
390
|
+
|
|
391
|
+
1. **Dotted file name.** The component has a non-empty stem before its last dot, and the text after
|
|
392
|
+
that dot, lower-cased, fully matches the pattern
|
|
393
|
+
`[a-z][a-z0-9]*`
|
|
394
|
+
(an ASCII letter followed by ASCII letters or digits).
|
|
395
|
+
2. **Known file name.** The component is an exact, ordinal member of the closed known-name set:
|
|
396
|
+
`Dockerfile`, `Makefile`, `LICENSE`, `CODEOWNERS`, `NOTICE`, `.gitignore`, `.gitattributes`,
|
|
397
|
+
`.gitkeep`, `.gitmodules`, `.vscodeignore`, `.npmignore`, `.npmrc`, `.nvmrc`, `.editorconfig`,
|
|
398
|
+
`.prettierrc`, `.prettierignore`, `.eslintignore`, `.shellcheckrc`.
|
|
399
|
+
|
|
400
|
+
This rule replaces the former extension allowlist, which dropped files a plan writes with an
|
|
401
|
+
unlisted extension (`.bats`, `.cjs`, `.out`), every dotfile, and every extensionless file name. The
|
|
402
|
+
same predicate decides the wildcard branch: a wildcard token outside the known top-level segments is
|
|
403
|
+
accepted only when its final component names a file by this rule.
|
|
404
|
+
|
|
405
|
+
Directory-shaped tokens remain rejected (issue #489). A final component with no dot, a trailing
|
|
406
|
+
slash, a dot-directory such as `.claude` or `.git` that is not in the known-name set, a digit-led
|
|
407
|
+
tail such as `v1.2.0`, and a trailing dot all fail the predicate.
|
|
408
|
+
|
|
409
|
+
**Accepted residuals (fail-closed direction).** Three token shapes that do not name a file are
|
|
410
|
+
accepted by this rule: a dotted directory cited without a trailing slash, such as the C#-style
|
|
411
|
+
`src/<Product>.Domain`; host-qualified tokens such as `example.com/page.html` or `owner/repo.git`;
|
|
412
|
+
and refs whose final segment has a letter-led dotted tail. Each produces at most an extra contention
|
|
413
|
+
edge, which serializes work. A missed write schedules concurrent edits, which is the unsafe
|
|
414
|
+
direction under this doctrine. In the self-hosted repository W4 removes the host-qualified cases; in
|
|
415
|
+
destinations, where `path_roots` is empty, W2 and W3 bound them.
|
|
416
|
+
|
|
417
|
+
**Parity.** The known-name set and the extension pattern are code constants in both runtimes
|
|
418
|
+
(`scripts/dev_tools/_blast_radius_token_shapes.py` and
|
|
419
|
+
`.claude/lib/blast-radius/BlastRadiusTokenShape.psm1`), not configuration keys, so neither copy of
|
|
420
|
+
`config/blast-radius.json` changes. A Pester test reads the Python source and pins the PowerShell
|
|
421
|
+
known-name set and extension pattern equal to it.
|
|
422
|
+
|
|
383
423
|
### Module-map granularity criterion
|
|
384
424
|
|
|
385
425
|
Issue #472 removed the location-bucket modules `docs` and `tests` because a bucket keyed on where a
|
|
@@ -525,6 +565,11 @@ Write-intent extraction can drop a genuine write in these cases:
|
|
|
525
565
|
5. a new top-level directory not yet in `path_roots` (W4);
|
|
526
566
|
6. a genuine file whose stem is in the placeholder set (W6).
|
|
527
567
|
|
|
568
|
+
The file-shape classifier, which runs before write-intent extraction, drops one further case: a
|
|
569
|
+
genuine file cited only as a separator-free bare file name is not recorded, because only
|
|
570
|
+
repository-relative paths and configured root surfaces are accepted (issue #797). The planner
|
|
571
|
+
cites the repository-relative path or appends it to the declared radius.
|
|
572
|
+
|
|
528
573
|
Three mitigations bound these cases:
|
|
529
574
|
|
|
530
575
|
1. **The planner remains obliged to enumerate a genuine write explicitly.** When an item's plan will
|
|
@@ -635,10 +680,10 @@ shipped surface or a derived module.
|
|
|
635
680
|
## Enforcement
|
|
636
681
|
|
|
637
682
|
- `scripts/dev_tools/validate_parallel_orchestrator_state.py`, with the helper modules `scripts/dev_tools/_parallel_state_common.py`, `scripts/dev_tools/_parallel_state_structures.py`, and `scripts/dev_tools/_parallel_state_records.py`, appends one error per violated orchestrator invariant. The completion-gate invariants 20 and 21 run only when the caller passes `require_complete=True`.
|
|
638
|
-
- `scripts/dev_tools/validate_parallel_planner_state.py` appends one error per violated planner invariant. The ready-gate invariants P6 through
|
|
683
|
+
- `scripts/dev_tools/validate_parallel_planner_state.py`, with the helper module `scripts/dev_tools/_parallel_planner_state_routing.py` for invariant P10, appends one error per violated planner invariant. The ready-gate invariants P6 through P10 run only when the caller passes `require_ready_for_execution=True`.
|
|
639
684
|
- `scripts/dev_tools/parallel_manifest_contract.py` appends one error per violated manifest invariant and exposes the default-resolving accessors. Manifest validation is a library call, not an MCP artifact type.
|
|
640
685
|
- `scripts/dev_tools/validate_orchestration_artifacts.py` registers the CLI subparsers `parallel-orchestrator-state` (with `--require-complete`) and `parallel-planner-state` (with `--require-ready-for-execution`). An unknown artifact type continues to fail with `Unsupported artifact type: {type}`.
|
|
641
|
-
- The TypeScript parity port at `extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts`, `parallel-state-structures.ts`, `parallel-state-records.ts`, `parallel-orchestrator-state-core.ts`, and `parallel-planner-state-core.ts` reproduces the same invariants and is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for both new `artifact_type` values. Verified scope: 96 of 96 error strings matched across 43 constructed documents, for JSON-representable values that round-trip through both runtimes' native types. Three divergence classes are known outside that verified scope: (1) **`pythonRepr` quote selection** — `parallel-state-shared.ts:112-132` always single-quotes, while Python's `repr` switches to double quotes when the value contains a single quote (recorded repo-wide at `docs/features/potential/2026-08-07-python-repr-quote-selection-divergence.md`); (2) **integral floats** — `JSON.parse` erases Python's `int`/`float` distinction, so an integral float value produces a different Python-side error count than the TypeScript side; (3) **boolean/integer equality** — `parallel-state-structures.ts:228` uses `===`, so a boolean value is not selected the way Python's `True == 1` equality selects it, producing differing error counts.
|
|
686
|
+
- The TypeScript parity port at `extensions/drm-copilot/src/lib/validate/parallel-state-shared.ts`, `parallel-state-structures.ts`, `parallel-state-records.ts`, `parallel-orchestrator-state-core.ts`, and `parallel-planner-state-core.ts` reproduces the same invariants and is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for both new `artifact_type` values. Verified scope: 96 of 96 error strings matched across 43 constructed documents, for JSON-representable values that round-trip through both runtimes' native types. Three divergence classes are known outside that verified scope: (1) **`pythonRepr` quote selection** — `parallel-state-shared.ts:112-132` always single-quotes, while Python's `repr` switches to double quotes when the value contains a single quote (recorded repo-wide at `docs/features/potential/2026-08-07-python-repr-quote-selection-divergence.md`); (2) **integral floats** — `JSON.parse` erases Python's `int`/`float` distinction, so an integral float value produces a different Python-side error count than the TypeScript side; (3) **boolean/integer equality** — `parallel-state-structures.ts:228` uses `===`, so a boolean value is not selected the way Python's `True == 1` equality selects it, producing differing error counts. For ready-gate invariant P10, `extensions/drm-copilot/src/lib/validate/parallel-planner-state-routing.ts` enforces the P10 structural subset (the band enums, the assessment and receipt object checks, `signals_present` shape, `band >= floor` ordering, non-empty `rationale` and `assessed_at`, the band-equality cross-checks, `agent`, and the `fable_policy` enum) with byte-identical error strings; the Python validator is authoritative for floor equality, resolved-model equality, and the disabled clamp, which the TypeScript port does not check.
|
|
642
687
|
- Enforcement is therefore Python validator logic, plus the TypeScript parity port, plus this prose file. It is NEVER an imported JSON Schema. No schema file is read at validation time.
|
|
643
688
|
- The `parallel` route entry lives in `config/orchestration-routing.json` with `requires_pr_gate: false` (there is no run-level pull request to gate; each child's own route checkpoint enforces its per-item pull-request gate) and is mirrored byte-for-byte in `extensions/drm-copilot/resources/config/orchestration-routing.json`.
|
|
644
689
|
- The `PreToolUse` merge gate `.claude/hooks/enforce-epic-merge-gate.ps1` carries a parallel allow-branch that authorizes a per-item `gh pr merge --merge` from the parallel-orchestrator checkpoint when `route_id == "parallel"`, the target item's `merge_status == "ci_green"`, and the command's PR number matches that item's `pr_number`; any other case fails closed with `EPIC_MERGE_GATE_BLOCKED`.
|
|
@@ -7,14 +7,14 @@ paths:
|
|
|
7
7
|
- "docs/features/**/plan.*.md"
|
|
8
8
|
- "docs/features/**/remediation-plan.*.md"
|
|
9
9
|
- ".claude/skills/atomic-plan-contract/SKILL.md"
|
|
10
|
-
description: Acceptance-gate rules G1 through
|
|
10
|
+
description: Acceptance-gate rules G1 through G10 for atomic plans. G1 through G9 judge the shell commands a plan states as acceptance conditions; the document-level G10 rule reports a SCRATCH definition that is not namespaced by issue number.
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Atomic-Plan Acceptance Gates (G1 through G6)
|
|
14
14
|
|
|
15
|
-
This rule governs the acceptance-gate rules the plan validator applies to the shell commands
|
|
15
|
+
This rule governs the acceptance-gate rules the plan validator applies to an atomic plan: G1 through G9 judge the shell commands the plan states as acceptance conditions, and G10 judges the whole plan document. It exists because a plan can state an acceptance condition that cannot fail: a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. Such a condition reads as a verification step and gates nothing (issue #486).
|
|
16
16
|
|
|
17
|
-
The rules are enforced by `scripts/dev_tools/plan_gate_discrimination.py` and by the TypeScript parity port at `extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts` with its shared-predicate module `plan-gate-rules.ts
|
|
17
|
+
The rules are enforced by `scripts/dev_tools/plan_gate_discrimination.py` and by the TypeScript parity port at `extensions/drm-copilot/src/lib/validate/plan-gate-discrimination.ts` with its shared-predicate module `plan-gate-rules.ts`. G1 through G9 are fed by the command extractor (`scripts/dev_tools/plan_gate_commands.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts`); G10 reads the whole document through `scripts/dev_tools/plan_gate_scratch.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-scratch.ts`. Enforcement is validator logic plus this prose file. No JSON Schema is authored, imported, or read.
|
|
18
18
|
|
|
19
19
|
## Scope of Invocation — no grandfathering or exemption mechanism
|
|
20
20
|
|
|
@@ -26,7 +26,7 @@ The consequence is that adding a rule to this set is cheap in migration cost and
|
|
|
26
26
|
|
|
27
27
|
## Rule Table
|
|
28
28
|
|
|
29
|
-
Every finding string begins with the square-bracketed `P#-T#` identifier of the task the command is attributed to, and renders the offending value or literal between backticks.
|
|
29
|
+
Every finding string begins with the square-bracketed `P#-T#` identifier of the task the command is attributed to, and renders the offending value or literal between backticks. The G10 exception: a G10 finding begins with `Line N: ` instead, because a SCRATCH definition sits outside any task window; the prefix matches the structural-error prefix in the same error channel, and the offending logical line is still rendered between backticks.
|
|
30
30
|
|
|
31
31
|
| Rule | Condition | Shipped severity |
|
|
32
32
|
| --- | --- | --- |
|
|
@@ -40,14 +40,15 @@ Every finding string begins with the square-bracketed `P#-T#` identifier of the
|
|
|
40
40
|
| **G8** | A `git diff` invocation carrying no non-flag ref operand and neither `--cached` nor `--staged`. It compares the worktree against the index, which is ambient state: the comparison passes vacuously once the change is committed. Exonerated when the attributed task text carries a second `git diff` or a `git status` span. | **Warning** |
|
|
41
41
|
| **G8b** | A `git diff` invocation carrying a non-flag ref operand together with `--name-only` or `--name-status`, whose attributed task text carries neither a `git add` span nor a `git status --porcelain` span. A name-listing diff enumerates tracked changes only, so a path the plan creates is invisible to it. | **Warning** |
|
|
42
42
|
| **G9** | A command carrying a `--cov` token, carrying no token beginning `--cov-report=term` and no token beginning `--cov-fail-under`, whose project `addopts` value also carries no `--cov-report=term`. No coverage table is printed, so a coverage number the acceptance condition demands can never be read. | **Warning** |
|
|
43
|
+
| **G10** | An unfenced logical line of the plan document (a physical line plus its indented continuation lines) that matches the SCRATCH definition predicate, and whose text after the first definition match carries neither an `issue-<issue-num>` nor an `issue-<digits>` namespace. One finding per logical line, reported against its first physical line. | **Blocking** |
|
|
43
44
|
|
|
44
|
-
G1 through
|
|
45
|
+
G1 through G10 are the complete shipped set. G1 through G6 were added by issue #486, G7 through G9 by issue #519, and G10 by issue #932; the parenthetical in this file's title names the original set only.
|
|
45
46
|
|
|
46
47
|
G1 through G4 form a cascade over each `--cov` value: the value is decided once, so a value G1 rejects is never additionally reported by G2 or G3. G4 is evaluated independently of the cascade because the ambiguous form is a defect whatever the value resolves to. G6 is evaluated before G5, because cross-line presence falsifies G5's tree-absence claim.
|
|
47
48
|
|
|
48
49
|
G8b is a distinct rule from G8 and not a sub-case of it: G8 reports a diff with no ref operand, G8b reports one that has a ref operand but cannot observe an untracked path. A single invocation can satisfy only one of the two, because the presence of a ref operand decides between them.
|
|
49
50
|
|
|
50
|
-
G1 and G4 are context-free and run on every invocation. G2, G3, G5, and G6 require a repository seam; with no context supplied they do not run
|
|
51
|
+
G1 and G4 are context-free and run on every invocation. G2, G3, G5, and G6 require a repository seam; with no context supplied they do not run. G7, G8, and G8b are likewise context-free and run on every invocation. G9 requires the repository seam, because it reads the project `addopts` value through it, so with no context supplied G9 does not run. All four of the rules added by issue #519 ship in the Warning channel, so none of them can alter the Blocking list at all. G10 is context-free and document-level: it reads the whole plan text, including the preamble and terms lists the command extractor drops, runs on every invocation, and can add Blocking findings without a context.
|
|
51
52
|
|
|
52
53
|
### Attribution window
|
|
53
54
|
|
|
@@ -136,6 +137,43 @@ The remaining 4 findings are true positives, and each is the exact defect the ru
|
|
|
136
137
|
|
|
137
138
|
Counts, and every one of the 4 false positives named by plan path, task identifier, offending span, and the reason its acceptance condition is falsifiable: `docs/features/completed/2026-08-23-plan-acceptance-gates-miss-unobservable-and-ambient-state-gates-519/evidence/qa-gates/corpus-measurement.2026-08-24T00-00.md`.
|
|
138
139
|
|
|
140
|
+
### G10 — ships as Blocking by operator-approved scope and the pre-declared rule
|
|
141
|
+
|
|
142
|
+
G10 enforces the child-unique scratch location rule introduced by issue #900: a plan that uses scratch files points the `SCRATCH` token at `<session scratchpad>/issue-<issue-num>/`, so concurrent child runs in one session do not collide. Unlike G1 through G9, it judges document prose rather than task-attributed commands, because a SCRATCH definition is written in a plan preamble or terms list that the command extractor drops.
|
|
143
|
+
|
|
144
|
+
The detection contract has two steps, and both patterns use no lookbehind so the Python and JavaScript dialects agree. Step 1 is the definition predicate; step 2 is the namespace that accepts the line when it appears in the text after the first definition match:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
(?:^|[^A-Za-z0-9_<>$/.-])`?SCRATCH`?(?:\*\*)?[ \t]*(?:means\b|:=|=|:|is (?:the|a|an)\b|resolves to\b|abbreviates\b|denotes\b|refers to\b|stands for\b)
|
|
148
|
+
issue-(?:<issue-num>|[0-9]+)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Lines inside fenced code blocks are skipped, and a logical line is reported once however many definition matches it contains.
|
|
152
|
+
|
|
153
|
+
A continuation line is non-blank, begins with whitespace, and is not a fence line, so a heading or task line written at column 0 ends the logical line, and an indented heading or task line is absorbed into it. Both runtimes split the document into physical lines on the CR LF, LF, and CR terminators only; a form feed, a vertical tab, the information separators, NEL, and the Unicode line and paragraph separators do not end a physical line. Both runtimes share one explicit whitespace class for the blank-line test, the continuation test, and whitespace normalization, declared once per runtime as `PLAN_WHITESPACE_CLASS` in the command extractor module, with an identical pattern string in both: tab, line feed, vertical tab, form feed, carriage return, space, the Unicode space separators, and the Unicode line and paragraph separators. NEL, the information separators, and the byte-order mark are outside that class, so in both runtimes a line that begins with one of them ends the logical line, and the character is kept verbatim in the normalized text. G6 uses the same class for its single-line test, its sliding-window join, and the split of the search literal into words, so a tracked file that contains NEL, an information separator, or the byte-order mark produces the same G6 result in both runtimes; the plan-quotation exoneration, which reads the plan text rather than a tracked file, keeps each runtime's native class. The fence test keeps the command extractor's fence pattern, whose leading whitespace is each runtime's native class, so a fence line that begins with NEL, an information separator, or the byte-order mark can be recognized differently by the two runtimes, for G1 through G9 as well as for G10.
|
|
154
|
+
|
|
155
|
+
The severity was fixed by the same two-conjunct decision rule used for G5 through G9, written and committed before the measurement was taken: Blocking if and only if the total G10 finding count is greater than zero **and** the recorded false-positive count is zero; otherwise the measurement indicates Warning. The pre-declared false-positive definition is a flagged logical line that is not a SCRATCH definition, or that defines SCRATCH in the canonical issue-namespaced form.
|
|
156
|
+
|
|
157
|
+
The measurement is recorded in `docs/features/active/2026-10-15-plan-validator-accepts-bare-scratch-paths-932/evidence/qa-gates/g10-corpus-measurement.2026-10-16T01-21.md`. It scanned 493 plan and remediation-plan files under `docs/` at the merge base and produced 17 findings, all 17 true positives and 0 false positives, so both conjuncts hold and the rule yields Blocking.
|
|
158
|
+
|
|
159
|
+
G10 also ships Blocking by operator-approved scope for issue #932. The measurement alone is a weaker basis than the G7 through G9 precedent, because the research for issue #932 observed the committed plan corpus, including the definition forms the predicate targets, before the measurement was taken. The severity is a single constant in each runtime (`G10_SEVERITY`), and a parity test asserts the two constants agree.
|
|
160
|
+
|
|
161
|
+
### Known false-negative classes — G10
|
|
162
|
+
|
|
163
|
+
G10 does not report the following, and each is a stated limitation rather than a deferred promise:
|
|
164
|
+
|
|
165
|
+
- **Wrong issue number.** A namespaced definition whose issue number differs from the plan's own issue is accepted, because the predicate checks the namespace shape, not its value.
|
|
166
|
+
- **`SCRATCHPAD`-family tokens.** `SCRATCHPAD`, `<SCRATCHPAD>`, and `<SCRATCH>` tokens, and root paths written under them, are excluded by the preceding-character class and the token boundary.
|
|
167
|
+
- **Definition by reference.** A plan that defines SCRATCH by pointing at another plan's definition carries no definition text for the predicate to match.
|
|
168
|
+
- **Fenced definitions.** A definition placed inside a fenced code block is skipped, which is also what lets plans and specifications quote rejected forms as examples.
|
|
169
|
+
- **Any issue token after the definition.** A logical line is accepted when an `issue-<digits>` or `issue-<issue-num>` token appears anywhere in its text after the first definition match, including a cross-reference that is not the scratch location, such as `(see issue-900 for context)`. Step 2 checks the namespace shape anywhere in that text, not inside a path segment.
|
|
170
|
+
|
|
171
|
+
One false-positive class is possible and recorded: the colon connector matches prose in which the word SCRATCH is directly followed by a colon that introduces something other than a definition, as in the line below. The measured corpus contains no instance.
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
Each artifact names the token SCRATCH: it never records a host path.
|
|
175
|
+
```
|
|
176
|
+
|
|
139
177
|
## The Write-Mode Register
|
|
140
178
|
|
|
141
179
|
G7 reads a fixed register of six entries. Each entry is an argv predicate plus a set of observation markers matched case-sensitively as substrings of the owning task's attributed text. The register is data, not code, so the same six entries are transcribed into the TypeScript twin without porting behaviour.
|
|
@@ -239,7 +277,7 @@ The following are prohibited in gate messages:
|
|
|
239
277
|
|
|
240
278
|
The reason is byte-identity across the two runtimes. Python's `repr` selects its quote character based on the value's contents, switching to double quotes when the value contains a single quote, while the TypeScript `pythonRepr` helper used elsewhere in this repository always single-quotes. A value carrying an apostrophe would therefore render differently in the two runtimes, and the parity requirement would fail on exactly the class of value a maintainer is most likely to encounter in a path or a prose literal. Backtick delimiting has no content-dependent behaviour and needs no helper.
|
|
241
279
|
|
|
242
|
-
The prohibition is enforced by tests, not only by prose: a parity test asserts the Python gate module contains neither `!r` nor `repr(`, a companion test asserts no `pythonRepr(` call appears in any of the
|
|
280
|
+
The prohibition is enforced by tests, not only by prose: a parity test asserts the Python gate module contains neither `!r` nor `repr(`, a companion test asserts no `pythonRepr(` call appears in any of the TypeScript gate modules, and the parity fixture set includes an apostrophe-bearing `--cov` value and an apostrophe-bearing search literal whose expected strings are asserted identically in both runtimes.
|
|
243
281
|
|
|
244
282
|
## Authoring Guidance for Plan Authors
|
|
245
283
|
|
|
@@ -251,7 +289,8 @@ The prohibition is enforced by tests, not only by prose: a parity test asserts t
|
|
|
251
289
|
|
|
252
290
|
## Enforcement
|
|
253
291
|
|
|
254
|
-
- `scripts/dev_tools/plan_gate_commands.py` extracts task-attributed command candidates; `scripts/dev_tools/plan_gate_discrimination.py` evaluates G1 through
|
|
292
|
+
- `scripts/dev_tools/plan_gate_commands.py` extracts task-attributed command candidates; `scripts/dev_tools/plan_gate_discrimination.py` evaluates G1 through G9, calls `scripts/dev_tools/plan_gate_scratch.py` for G10, and returns the two severity channels.
|
|
255
293
|
- `scripts/dev_tools/validate_orchestration_artifacts.py` routes the existing `plan` artifact type through the two-channel entry point, prints each Warning to stderr prefixed with `PLAN GATE WARNING: `, and derives its exit code from the error channel alone. No new flag, option, or artifact type is added.
|
|
256
294
|
- The TypeScript parity port is dispatched from `extensions/drm-copilot/src/lib/validate/orchestration-artifacts.ts` for the existing `plan` artifact type. The MCP `validate_orchestration_artifacts` input-schema property-key set is unchanged; Warnings surface on an optional `warnings` field that is absent when there are none.
|
|
295
|
+
- `scripts/dev_tools/plan_gate_scratch.py` evaluates G10, the document-level SCRATCH definition rule, and `evaluate_plan_gates` in `scripts/dev_tools/plan_gate_discrimination.py` calls it on every invocation, with or without a context. The TypeScript twin `extensions/drm-copilot/src/lib/validate/plan-gate-scratch.ts` is called the same way from `evaluatePlanGates`. Through the Python CLI a G10 finding is printed as an error and the process exits 1; through the MCP service call it causes the call to throw with the message included.
|
|
257
296
|
- `.claude/hooks/validate-planner-output.ps1` is not modified by this rule and carries no part of its enforcement.
|
|
@@ -6,19 +6,21 @@ description: Module rigor tier system and uniform coverage thresholds.
|
|
|
6
6
|
|
|
7
7
|
# Module Rigor Tiers
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Applicability: this rule applies only when `quality-tiers.yml` exists at the repository root, which indicates that the repository has adopted module rigor tiers. When that file is absent, there is no tier classification requirement, no `tier-classification` CI stage, and no tier-dependent gate (the escape-hatch limits, property-test density, mutation score, contract-bump rule, determinism retry rate, golden tests, and E2E suite scope in the Tier-dependent table below), and the absence of `quality-tiers.yml` is not a defect. The coverage defaults listed under Uniform across all tiers do not depend on tier adoption; their precedence is stated in that section.
|
|
10
|
+
|
|
11
|
+
When `quality-tiers.yml` exists, this rule defines the T1–T4 module rigor tier system used by the repository's CI gates, and the tier definitions and gate matrix in this document are the tier system's source of truth.
|
|
10
12
|
|
|
11
13
|
## Tiers
|
|
12
14
|
|
|
13
|
-
- **T1 — Critical.** Behavior bugs cause silent data loss, model drift, or security holes. Examples
|
|
14
|
-
- **T2 — Core.** Bugs cause feature regressions but not data loss. Examples:
|
|
15
|
-
- **T3 — Adapters & UI.** Glue around APIs the team does not own. Examples:
|
|
15
|
+
- **T1 — Critical.** Behavior bugs cause silent data loss, model drift, or security holes. Examples: classifier and scoring engines, identifier allocators and hierarchy operations, adapters that write to an external system of record, authentication and token handling, command dispatch.
|
|
16
|
+
- **T2 — Core.** Bugs cause feature regressions but not data loss. Examples: domain and application layers, data-transfer objects, settings store abstractions, schema definitions.
|
|
17
|
+
- **T3 — Adapters & UI.** Glue around APIs the team does not own. Examples: user-interface surfaces, host-platform API wrappers, third-party API and SDK wrappers, persistence I/O.
|
|
16
18
|
- **T4 — Scaffolding.** Examples: DI wiring, bootstrap, build scripts, dev tooling, generated code, manifests.
|
|
17
19
|
|
|
18
20
|
## Source of Truth
|
|
19
21
|
|
|
20
|
-
- `quality-tiers.yml` at
|
|
21
|
-
-
|
|
22
|
+
- When `quality-tiers.yml` exists at the repository root, it maps every project to one tier.
|
|
23
|
+
- In a repository that runs a `tier-classification` CI stage, that stage validates that every project entry has a tier and that no unclassified project exists, and it fails CI for an unclassified project.
|
|
22
24
|
|
|
23
25
|
## Uniform-vs-Tier-Dependent Gate Matrix
|
|
24
26
|
|
|
@@ -26,6 +28,8 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
|
|
|
26
28
|
|
|
27
29
|
### Uniform across all tiers (T1–T4)
|
|
28
30
|
|
|
31
|
+
Threshold precedence: when the repository's root `CLAUDE.md` states line or branch coverage thresholds, those thresholds govern. The 85% line and 75% branch figures are defaults that apply only when the root `CLAUDE.md` states none. This precedence applies to every restatement of these figures in other rule files, agents, and skills. Each metric falls back independently: when the root `CLAUDE.md` states only a line threshold or only a branch threshold, the stated threshold governs that metric and the default governs the other.
|
|
32
|
+
|
|
29
33
|
- Format check: 100% pass.
|
|
30
34
|
- Lint errors: 0.
|
|
31
35
|
- Type errors: 0.
|
|
@@ -48,4 +52,4 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
|
|
|
48
52
|
|
|
49
53
|
## Rationale (uniform coverage thresholds)
|
|
50
54
|
|
|
51
|
-
High test coverage is a fundamental quality-control design choice that enables autonomous agentic development and trust in the work product. For that reason, line coverage >= 85% applies uniformly across T1–T4 to every coverage language, and branch coverage >= 75% applies uniformly across T1–T4 to every language whose coverage tooling measures branch coverage; tier-specific lower coverage floors are not used
|
|
55
|
+
High test coverage is a fundamental quality-control design choice that enables autonomous agentic development and trust in the work product. For that reason, line coverage >= 85% applies uniformly across T1–T4 to every coverage language, and branch coverage >= 75% applies uniformly across T1–T4 to every language whose coverage tooling measures branch coverage; tier-specific lower coverage floors are not used. These figures are defaults under the threshold precedence stated above: a root `CLAUDE.md` that states coverage thresholds overrides them. Each metric falls back independently, so a root `CLAUDE.md` that states only one of the two thresholds overrides only that one. The branch threshold is not applied to PowerShell or bash because Pester and kcov do not measure branch coverage. That exemption is a capability limit on an unevaluable threshold, not a licence to exclude files from measurement: PowerShell and bash production files remain in the coverage denominator under the Coverage Exclusion Policy in `.claude/rules/general-unit-test.md`.
|
|
@@ -45,11 +45,12 @@ single pass. Do not substitute the VS Code task wrappers for the native command
|
|
|
45
45
|
|
|
46
46
|
## Discovery Contract
|
|
47
47
|
|
|
48
|
-
- Search roots: `tools/`, `scripts/`, `.claude/lib/bash/`,
|
|
49
|
-
current working directory; a missing root is silently skipped. The `.claude/lib/bash/` root
|
|
50
|
-
the destination-portable bash library published by push-down,
|
|
51
|
-
scripts bundled inside a skill folder,
|
|
52
|
-
|
|
48
|
+
- Search roots: `tools/`, `scripts/`, `.claude/lib/bash/`, `.claude/skills/`, and `.codex/`, relative
|
|
49
|
+
to the current working directory; a missing root is silently skipped. The `.claude/lib/bash/` root
|
|
50
|
+
carries the destination-portable bash library published by push-down, the `.claude/skills/` root
|
|
51
|
+
carries scripts bundled inside a skill folder, and the `.codex/` root carries the Codex runtime
|
|
52
|
+
scripts (for example `.codex/codex-web-setup.sh`), so those scripts are held to the same format,
|
|
53
|
+
lint, test, and coverage standards as `tools/` and `scripts/`.
|
|
53
54
|
- A file is a shell script when its suffix (lowercased) is `.sh` or its first line is a
|
|
54
55
|
shebang whose resolved interpreter is `bash` or `sh` (including `env` and `env -S`/`-flag`
|
|
55
56
|
forms; the shebang is lowercased before parsing, so `#!/usr/bin/env BASH` qualifies).
|
|
@@ -63,9 +64,10 @@ single pass. Do not substitute the VS Code task wrappers for the native command
|
|
|
63
64
|
- Coverage is measured with kcov, which emits a single merged Cobertura report `cov.xml` under
|
|
64
65
|
`artifacts/pester/kcov` (or `SHELL_QC_KCOV_OUT_DIR`). The run prints
|
|
65
66
|
`Bash coverage (lines): NN.N%`.
|
|
66
|
-
- The kcov include pattern covers all
|
|
67
|
-
`.claude/lib/bash/`,
|
|
68
|
-
measured, not merely discovered. The `tests/` tree remains
|
|
67
|
+
- The kcov include pattern covers all five discovery roots — `tools/`, `scripts/`,
|
|
68
|
+
`.claude/lib/bash/`, `.claude/skills/`, and `.codex/` — so the Claude bash library, skill-bundled
|
|
69
|
+
scripts, and Codex runtime scripts are measured, not merely discovered. The `tests/` tree remains
|
|
70
|
+
excluded.
|
|
69
71
|
- kcov reports **line coverage only**. The uniform line-coverage threshold (>= 85% per
|
|
70
72
|
`.claude/rules/quality-tiers.md`) applies. Branch coverage is not measurable by kcov for
|
|
71
73
|
bash; there is no bash branch-coverage gate.
|
|
@@ -54,7 +54,7 @@ Run the toolchain in order: format → lint → type-check → test. Restart fro
|
|
|
54
54
|
|
|
55
55
|
## Architecture Boundaries
|
|
56
56
|
|
|
57
|
-
Layer rules and the
|
|
57
|
+
Layer rules and the host-neutral architecture assertions are defined in `.claude/rules/architecture-boundaries.md` under the heading "Host-Neutral Architecture Rules (enforceable assertions)". The TypeScript enforcement tool is `dependency-cruiser` with configuration file `.dependency-cruiser.cjs`.
|
|
58
58
|
|
|
59
59
|
## Property-Based and Mutation Testing
|
|
60
60
|
|
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
"Bash(git *)",
|
|
6
6
|
"Bash(poetry run *)",
|
|
7
7
|
"Bash(pwsh *)",
|
|
8
|
+
"Bash(bash .claude/lib/bash/abandon-parallel-item.sh*)",
|
|
8
9
|
"Bash(bash .claude/lib/bash/compute-cohorts.sh*)",
|
|
9
10
|
"Bash(bash .claude/lib/bash/compute-concurrency-batches.sh*)",
|
|
11
|
+
"Bash(bash .claude/lib/bash/mutate-parallel-run.sh*)",
|
|
12
|
+
"Bash(bash .claude/lib/bash/remove-parallel-item.sh*)",
|
|
10
13
|
"Bash(bash .claude/lib/bash/validate-parallel-manifest.sh*)",
|
|
11
14
|
"Read",
|
|
12
15
|
"Edit(docs/**)",
|
|
@@ -211,10 +214,6 @@
|
|
|
211
214
|
{
|
|
212
215
|
"matcher": "atomic-planner|atomic-executor|feature-review|task-researcher|prd-feature|staged-review|epic-review|status-updater|python-typed-engineer|powershell-typed-engineer|csharp-typed-engineer|typescript-engineer|orchestrator|epic-orchestrator|epic-planner",
|
|
213
216
|
"hooks": [
|
|
214
|
-
{
|
|
215
|
-
"type": "command",
|
|
216
|
-
"command": "pwsh -NoProfile -Command \"$input = $env:CLAUDE_HOOK_INPUT | ConvertFrom-Json; $output = $input.output; if (-not ($output -match '(plan-path|research-path|review-artifact|PREFLIGHT|evidence/)')) { Write-Error 'Subagent stopped without required completion artifact path'; exit 1 }; exit 0\""
|
|
217
|
-
},
|
|
218
217
|
{
|
|
219
218
|
"type": "command",
|
|
220
219
|
"command": "pwsh -NoProfile -File .claude/hooks/validate-discovery-artifact-gate.ps1"
|
package/resources/claude-customizations/.claude/skills/acceptance-criteria-tracking/SKILL.md
CHANGED
|
@@ -88,7 +88,7 @@ During feature review (feature-audit phase):
|
|
|
88
88
|
|
|
89
89
|
### When Orchestrators Enforce AC Tracking
|
|
90
90
|
|
|
91
|
-
Orchestrators do not directly check off AC items.
|
|
91
|
+
Orchestrators do not directly check off AC items. The one exception is a CI-dependent criterion, which the item's own orchestrator run checks off at S9 as described in `### CI-Dependent Criteria` above. For every other criterion, orchestrators instead:
|
|
92
92
|
|
|
93
93
|
1. Ensure delegated executors and reviewers reference this skill.
|
|
94
94
|
2. After executor or reviewer completion, verify that AC source files reflect delivered work (spot-check; do not re-execute verification).
|
|
@@ -104,6 +104,10 @@ For short-path/minimal-audit plans, Phase 0 evidence is incomplete unless both a
|
|
|
104
104
|
|
|
105
105
|
`Output Summary:` is mandatory for each command-step artifact and must concisely summarize the essential result signal (for example: pass/fail status, key counts, coverage headline, or primary diagnostic).
|
|
106
106
|
|
|
107
|
+
## Evidence Filename Timestamps in Plans
|
|
108
|
+
|
|
109
|
+
Plans name evidence artifacts `<name>.<timestamp>.md` and never fix a plan-time stamp in an evidence filename. An acceptance condition identifies a consumed evidence artifact by the derivation in `evidence-and-timestamp-conventions` (`### Evidence Filename Timestamp`): the lexicographically greatest file matching `<name>.*.md`, not a pre-stamped literal path. This section governs artifact paths only: asserted search tokens remain concrete.
|
|
110
|
+
|
|
107
111
|
## Coverage Evidence Contract (Mandatory when policy requires coverage)
|
|
108
112
|
|
|
109
113
|
For any language in scope where repository policy requires coverage validation:
|
|
@@ -191,7 +195,7 @@ Before a plan can be treated as approved:
|
|
|
191
195
|
|
|
192
196
|
The same validator call also applies the acceptance-gate rules G1 through G6 defined in `.claude/rules/plan-acceptance-gates.md`. Those rules report acceptance conditions that cannot fail — a coverage argument that collects no data, or a search for a literal that returns zero matches whatever the executor does. They run automatically on the existing `plan` route with no additional flag. Blocking findings appear in the validator's error output and fail the gate; Warnings are surfaced without failing it, prefixed with `PLAN GATE WARNING: ` on the CLI and carried on the optional `warnings` field of the MCP result. Read that rule file before authoring acceptance conditions.
|
|
193
197
|
|
|
194
|
-
The same call additionally applies the rules G7, G8, G8b, and G9, which report a write-mode command observed only by its exit code, an unanchored `git diff`, a name-listing diff with no companion span, and a coverage command that prints no table. All four ship in the Warning channel, so they surface without failing the gate. The complete shipped set is therefore G1 through
|
|
198
|
+
The same call additionally applies the rules G7, G8, G8b, and G9, which report a write-mode command observed only by its exit code, an unanchored `git diff`, a name-listing diff with no companion span, and a coverage command that prints no table. All four ship in the Warning channel, so they surface without failing the gate. The same call also applies G10, a document-level rule that reports a SCRATCH definition not namespaced by issue number. G10 ships in the Blocking channel and reports each finding with a `Line N: ` prefix rather than a task identifier, because the definition sits outside any task window. The complete shipped set is therefore G1 through G10.
|
|
195
199
|
|
|
196
200
|
## Wrap-Tolerant Assertion Authoring (Mandatory)
|
|
197
201
|
|
|
@@ -43,7 +43,7 @@ is_detached_candidate() {
|
|
|
43
43
|
#
|
|
44
44
|
# The predicate is the porcelain FLAG, not the branch field: emit_record writes the
|
|
45
45
|
# literal DETACHED into the branch field whenever the branch accumulator is empty
|
|
46
|
-
# (
|
|
46
|
+
# (emit_record, nested in parse_worktree_list in cleanup_worktrees_enumerate_lib.sh), which is also true of a
|
|
47
47
|
# bare-repository stanza, and a local branch literally named DETACHED would produce
|
|
48
48
|
# the same branch field with no `detached` flag.
|
|
49
49
|
#
|
|
@@ -348,6 +348,8 @@ cleanup_wt_derive_scan_roots() {
|
|
|
348
348
|
p=${paths[i]//\\//}
|
|
349
349
|
parent=${p%/*}
|
|
350
350
|
[[ -z $parent || $parent == "$p" ]] && continue
|
|
351
|
+
# A drive-relative parent (a registration directly under a drive root, such as D:/wt) is not an absolute root and is dropped.
|
|
352
|
+
cleanup_wt_is_absolute_path "$parent" || continue
|
|
351
353
|
n=$(normalize_wt_path "$parent")
|
|
352
354
|
[[ -z $n || -n ${seen[$n]:-} ]] && continue
|
|
353
355
|
[[ $n == "$main_norm" || $main_norm == "$n"/* ]] && continue
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
# the SHELL_QC_<TOOL>_BIN seams substitute a checked-in stand-in for a real dependency.
|
|
41
41
|
# An empty value is treated as missing and falls back to `.git`.
|
|
42
42
|
set -euo pipefail
|
|
43
|
+
# The library path is computed at runtime from BASH_SOURCE, so shellcheck (run without
|
|
44
|
+
# -x) cannot follow it; SC1091 is the expected, benign result.
|
|
43
45
|
# shellcheck source=.claude/skills/cleanup-merged-worktrees/scripts/cleanup_worktrees_enumerate_lib.sh
|
|
44
46
|
# shellcheck disable=SC1091
|
|
45
47
|
source "$(dirname -- "${BASH_SOURCE[0]}")/cleanup_worktrees_enumerate_lib.sh"
|
|
@@ -95,14 +95,32 @@ function of the DAG.
|
|
|
95
95
|
2. Before starting each wave, `epic-orchestrator` runs
|
|
96
96
|
`git fetch origin epic/<epic-slug>-integration` so the wave's child worktrees branch off the
|
|
97
97
|
current remote tip, not a stale local ref.
|
|
98
|
-
3.
|
|
98
|
+
3. Before each wave launches (wave 0 included), `epic-orchestrator` runs
|
|
99
|
+
`git fetch origin main` and then
|
|
100
|
+
`git rev-list --count origin/epic/<epic-slug>-integration..origin/main`. A zero count
|
|
101
|
+
proceeds directly to the wave. A non-zero count means `origin/main` has commits the
|
|
102
|
+
integration branch lacks, and the main-sync runs as a dedicated chore child item before the
|
|
103
|
+
wave launches, following the `epic-852-main-sync` / PR #882 pattern. Before delegating it,
|
|
104
|
+
`epic-orchestrator` writes the sync child's `features[]` row (with `depends_on: []`) and its
|
|
105
|
+
own `waves[]` entry to the epic checkpoint, because `enforce-epic-wave-barrier.ps1` denies a
|
|
106
|
+
delegation whose feature record is absent. The sync child must not reuse a manifest child's
|
|
107
|
+
issue number; it uses the epic issue number or a dedicated chore issue. Its branch is created
|
|
108
|
+
from the integration branch, merges `origin/main` with a merge commit
|
|
109
|
+
(`git merge --no-ff origin/main`; no rebase, no force-push), resolves any conflict inside its
|
|
110
|
+
own remediation loop, and opens a PR into the integration branch. The wave does not launch
|
|
111
|
+
until that PR has merged into the integration branch and the sync entry's `merge_status` is
|
|
112
|
+
`merged`. At most one main-sync child runs per wave: after it merges, `epic-orchestrator`
|
|
113
|
+
re-runs step 2 and launches the wave without repeating the count, and commits that reach
|
|
114
|
+
`origin/main` afterwards are picked up by the next wave's check or by the final integration
|
|
115
|
+
PR in step 6.
|
|
116
|
+
4. Each child feature's worktree/branch (created via
|
|
99
117
|
`Agent(orchestrator, isolation: "worktree", run_in_background: true)`) is branched from
|
|
100
118
|
`origin/<integration_branch>`, not `origin/main`. The child's own `orchestrator` instance
|
|
101
119
|
honors this via the epic-mode kickoff line below.
|
|
102
|
-
|
|
120
|
+
5. Each child feature's PR base branch is the integration branch, not `main` — an explicit
|
|
103
121
|
epic-mode override recorded in the checkpoint, not a reliance on `pr-base-branch-merge-base`'s
|
|
104
122
|
ancestry heuristic. Non-epic (standalone) orchestration is unchanged.
|
|
105
|
-
|
|
123
|
+
6. At epic completion (every feature in the final wave has `merge_status: "merged"`),
|
|
106
124
|
`epic-orchestrator` drives a final PR merging `epic/<epic-slug>-integration` into `main`,
|
|
107
125
|
delegating PR authoring to `Agent(pr-author)` and refreshing context via
|
|
108
126
|
`mcp__drm-copilot__collect_pr_context`. `epic-orchestrator` runs the same S9 CI-green
|
|
@@ -241,9 +259,15 @@ cross-call/conversation-state visibility.
|
|
|
241
259
|
prompt text, reads `artifacts/orchestration/epic-orchestrator-state.json`, looks up that
|
|
242
260
|
feature's `depends_on`, and denies with reason `EPIC_WAVE_BARRIER_BLOCKED` unless every
|
|
243
261
|
dependency's `merge_status` is `merged` or `worktree_removed`.
|
|
244
|
-
- **Layer 2 — retrospective backstop:** the wave-barrier ordering invariant
|
|
245
|
-
`validate_epic_orchestrator_state_text`, enforced at `epic-orchestrator` `SubagentStop` time
|
|
246
|
-
|
|
262
|
+
- **Layer 2 — retrospective backstop:** the wave-barrier ordering invariant of
|
|
263
|
+
`validate_epic_orchestrator_state_text`, enforced at `epic-orchestrator` `SubagentStop` time by a
|
|
264
|
+
PowerShell port, `Get-OrchestratorStateEpicWaveBarrierError` in
|
|
265
|
+
`.claude/lib/orchestrator-state/OrchestratorStateEpicWaveBarrier.psm1`, which the parameterized
|
|
266
|
+
`validate-orchestrator-output.ps1` hook invokes for `epic-orchestrator-state` after resolving the
|
|
267
|
+
epic checkpoint through `WorktreeRunResolution.psm1`. The hook starts no Python process. Parity
|
|
268
|
+
with `validate_epic_orchestrator_state_text` is pinned by the shared fixtures under
|
|
269
|
+
`tests/fixtures/epic_wave_barrier/`, and the Python validator remains the authority used through
|
|
270
|
+
the `mcp__drm-copilot__validate_orchestration_artifacts` call. It checks only a dependent feature
|
|
247
271
|
that is treated as started: one with a string `worktree_created_at`, or with a `merge_status`
|
|
248
272
|
other than `not_started` (a missing or non-string `merge_status` counts as started). It appends
|
|
249
273
|
exactly one error per violated dependency edge. When the dependency's `merge_status` is not
|
|
@@ -252,6 +276,9 @@ cross-call/conversation-state visibility.
|
|
|
252
276
|
Otherwise, when the dependency's `merge_confirmed_at` is later than the dependent's
|
|
253
277
|
`worktree_created_at`, the error is
|
|
254
278
|
`EPIC_WAVE_BARRIER_VIOLATION: <f> worktree_created_at precedes dependency <d> merge_confirmed_at`.
|
|
279
|
+
A violation blocks with an instruction to report it to the operator and halt. The `SubagentStop`
|
|
280
|
+
transport and exit-code defect that this check previously depended on was resolved by epic #904
|
|
281
|
+
and issue #928: a violation blocks the stop with exit 2 and a stderr reason.
|
|
255
282
|
|
|
256
283
|
Both layers are required; neither alone closes the gap. `epic-orchestrator` does not launch wave
|
|
257
284
|
N+1 until every wave-N feature's dependency edges are durably confirmed merged, verified against
|
|
@@ -211,7 +211,7 @@ With no ready feature checkpoint, the exemption admits two attribution-trailer f
|
|
|
211
211
|
- The trailer option: `git commit -m 'docs: plan' --trailer 'Co-Authored-By: Name <email>' --trailer 'Claude-Session: <url>' -- <exempt paths>`. The separate-value form and the `--trailer=<value>` form are both admitted, any number of times, on `git commit` only; `git add --trailer` and a trailer option with no value are denied. Git writes every trailer value into one trailer block.
|
|
212
212
|
- The one-paragraph multi-message form: the subject in the first `-m` and every trailer in one single-quoted second `-m` value, separated by a literal newline. Each `-m` value becomes its own paragraph and git parses only the last paragraph as the trailer block, so trailers split across separate `-m` values do not form one trailer block.
|
|
213
213
|
|
|
214
|
-
Quoting rules: `$` and backtick are literal and admitted inside single quotes, and denied outside quotes and inside double quotes, where the shell expands them. `<` and `>` are admitted inside single or double quotes and denied outside quotes. An unquoted `#` is denied anywhere, because it starts a shell comment that the exemption does not model; a `#` inside quotes is admitted. A typographic quote character (U+2018 to U+201E) anywhere in the command line is denied, because a PowerShell host reads it as a quote.
|
|
214
|
+
Quoting rules: `$` and backtick are literal and admitted inside single quotes, and denied outside quotes and inside double quotes, where the shell expands them. `<` and `>` are admitted inside single or double quotes and denied outside quotes. An unquoted `#` is denied anywhere, because it starts a shell comment that the exemption does not model; a `#` inside quotes is admitted. A typographic quote character (U+2018 to U+201E) anywhere in the command line is denied, because a PowerShell host reads it as a quote. Because the executing shell is undetermined (issue #735), a shape whose meaning differs between a POSIX shell and PowerShell is denied: a backslash anywhere in the command line is denied, and `{`, `}`, `,`, `(`, `)`, and `@` are denied outside quotes. Every staging operand must be a plain forward-slash repository-relative path that uses only the characters `A-Z a-z 0-9 . _ / -`.
|
|
215
215
|
|
|
216
216
|
Not admitted: heredoc-fed messages, including `git commit -m "$(cat <<'EOF' ... EOF)"` and `git commit -F - <<'EOF'`, and message files supplied through `-F <file>` or `--file=<file>`. Use one of the two forms above instead.
|
|
217
217
|
|