@danmoisan/drm-copilot-mcp 1.0.24 → 1.0.27
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 +1045 -214
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/feature-review.md +5 -3
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +11 -4
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +5 -2
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +28 -8
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +109 -5
- package/resources/claude-customizations/.claude/hooks/enforce-mermaid-validation.ps1 +390 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +28 -8
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +117 -46
- package/resources/claude-customizations/.claude/lib/bash/parallel-manifest-validate.sh +115 -3
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +105 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusConfig.psm1 +32 -52
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +107 -99
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +295 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusValidation.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +312 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +392 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +500 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidGrammar.psm1 +491 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidLineScanner.psm1 +488 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidMarkdownFences.psm1 +298 -0
- package/resources/claude-customizations/.claude/lib/mermaid/MermaidValidation.psm1 +496 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorState.psm1 +58 -67
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCheckpointValue.psm1 +383 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexModelReceipts.psm1 +297 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCodexTopologyReceipts.psm1 +298 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletion.psm1 +232 -43
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateCompletionChecks.psm1 +416 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateModelReceipts.psm1 +366 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateReceipts.psm1 +408 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingContract.psm1 +428 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateRoutingMatrix.psm1 +377 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateUnconditional.psm1 +166 -0
- package/resources/claude-customizations/.claude/rules/general-unit-test.md +1 -1
- package/resources/claude-customizations/.claude/rules/mermaid.md +142 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +88 -3
- package/resources/claude-customizations/.claude/rules/plan-acceptance-gates.md +116 -0
- package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
- package/resources/claude-customizations/.claude/rules/quality-tiers.md +3 -3
- package/resources/claude-customizations/.claude/settings.json +5 -0
- package/resources/claude-customizations/.claude/skills/atomic-plan-contract/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/feature-review-workflow/SKILL.md +4 -4
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/SKILL.md +184 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/c4.md +50 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/class.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/er.md +56 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/flowchart.md +68 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/gantt.md +51 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/other-types.md +82 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/pie.md +32 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/sequence.md +63 -0
- package/resources/claude-customizations/.claude/skills/mermaid-diagram/references/state.md +49 -0
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +10 -5
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +116 -41
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +95 -13
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +7 -3
- package/resources/claude-customizations/.claude/skills/powershell-qa-gate/SKILL.md +1 -1
- package/resources/claude-customizations/config/blast-radius.json +9 -3
- package/resources/claude-customizations/pack-manifests/core.json +31 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/customizations/.github/skills/evidence-and-timestamp-conventions/SKILL.md +13 -0
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +37 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.mmd"
|
|
4
|
+
- "**/*.mermaid"
|
|
5
|
+
description: Mermaid diagram authoring standards, validation mandate, and managed-diagram constraint.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Mermaid Diagram Standards
|
|
9
|
+
|
|
10
|
+
This rule governs Mermaid diagrams in this repository. The authoring workflow, the per-type syntax
|
|
11
|
+
references, and the generation recipes live in `.claude/skills/mermaid-diagram/SKILL.md`; this file
|
|
12
|
+
carries the constraints.
|
|
13
|
+
|
|
14
|
+
The pinned Mermaid documentation version for the whole surface is **11.17.0**
|
|
15
|
+
(https://mermaid.js.org/intro/syntax-reference.html). The keyword allowlist and the per-type arrow
|
|
16
|
+
token sets are a snapshot of that version, recorded in `.claude/lib/mermaid/MermaidGrammar.psm1`.
|
|
17
|
+
|
|
18
|
+
## Diagram File Conventions
|
|
19
|
+
|
|
20
|
+
- A standalone diagram belongs in a `.mmd` file (`.mermaid` is also recognized). The whole file is
|
|
21
|
+
one diagram: optional YAML frontmatter, optional `%%{init: ...}%%` directives, the diagram-type
|
|
22
|
+
keyword line, then the body.
|
|
23
|
+
- A diagram embedded in prose belongs in a fenced ` ```mermaid ` block in the Markdown file that
|
|
24
|
+
discusses it. GitHub renders such fences natively in Markdown, pull requests, and issues.
|
|
25
|
+
- The first line after any frontmatter, directive, comment, and blank line must be the
|
|
26
|
+
diagram-type keyword. Mermaid keywords are case-sensitive: `C4Context`, `stateDiagram-v2`, and
|
|
27
|
+
`sequenceDiagram` are exact spellings.
|
|
28
|
+
- Mermaid has no backslash escape. To place a double quote inside a label, use the `#quot;` entity;
|
|
29
|
+
a backslash before a closing quote closes the span rather than escaping it.
|
|
30
|
+
- Do not commit a diagram file as a test fixture. Diagram fixtures belong in PowerShell
|
|
31
|
+
here-strings inside the Pester suites, because a `PreToolUse` hook fires on the write of its own
|
|
32
|
+
fixtures.
|
|
33
|
+
|
|
34
|
+
## Validation Mandate
|
|
35
|
+
|
|
36
|
+
Every diagram written to this repository passes through the structural gate
|
|
37
|
+
`.claude/hooks/enforce-mermaid-validation.ps1` on `Write` and `Edit`. The gate is registered in the
|
|
38
|
+
`Write|Edit` matcher of `.claude/settings.json` and runs the dependency-free validator in
|
|
39
|
+
`.claude/lib/mermaid/`.
|
|
40
|
+
|
|
41
|
+
What the gate rejects, naming the defect class and the line number:
|
|
42
|
+
|
|
43
|
+
- a missing, non-keyword, or misspelled first-line diagram keyword;
|
|
44
|
+
- YAML frontmatter that opens with `---` and is never closed;
|
|
45
|
+
- an empty or whitespace-only diagram body;
|
|
46
|
+
- unbalanced `[]`, `()`, or `{}` on structural lines of a bracket-structural diagram type,
|
|
47
|
+
computed by a quote-aware scanner;
|
|
48
|
+
- an unterminated double-quoted label;
|
|
49
|
+
- an arrow or edge token that is not valid for the declared diagram type;
|
|
50
|
+
- a `subgraph` with no matching `end`.
|
|
51
|
+
|
|
52
|
+
What the gate does NOT do, stated plainly so "validated" is not overclaimed: it does not prove a
|
|
53
|
+
diagram renders, and it performs no parse. Semantic and deep-grammar errors — an undefined node
|
|
54
|
+
reference in a `click` statement, a malformed gantt date, an invalid `classDef` property, a wrong
|
|
55
|
+
`section` structure, an invalid participant reference — are outside its reach. A `Valid` verdict
|
|
56
|
+
means no defect of a checked class was found, nothing more.
|
|
57
|
+
|
|
58
|
+
Where the gate declines to judge, it allows. An unknown but keyword-shaped first-line token is
|
|
59
|
+
allowed with a drift warning, because the allowlist is a pinned snapshot and an out-of-date
|
|
60
|
+
allowlist must cost a warning rather than a false rejection. Diagram types outside the deep-checked
|
|
61
|
+
set (flowchart, sequence, class, state, ER) are keyword-checked only. An `Edit` payload carries a
|
|
62
|
+
fragment rather than the resulting file, so the syntax check is not attempted and the next `Write`
|
|
63
|
+
catches a regression.
|
|
64
|
+
|
|
65
|
+
## Managed Diagrams: Do Not Hand-Edit
|
|
66
|
+
|
|
67
|
+
A `.mmd` or `.mermaid` file whose frontmatter carries an `id:` key is connected to the Mermaid Chart
|
|
68
|
+
cloud sync workflow:
|
|
69
|
+
|
|
70
|
+
```yaml
|
|
71
|
+
---
|
|
72
|
+
id: cbd9e9ba-a2cb-47c5-a98e-8c28a753428d
|
|
73
|
+
---
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Such a diagram must not be hand-edited. The next sync overwrites the edit, so the change is lost
|
|
77
|
+
and the diff is misleading in the meantime. The gate denies both `Write` and `Edit` on a file whose
|
|
78
|
+
on-disk frontmatter carries a non-empty `id:`, with the reason token
|
|
79
|
+
`MERMAID_MANAGED_DIAGRAM_BLOCKED:`.
|
|
80
|
+
|
|
81
|
+
To change a managed diagram, use the Mermaid Chart sync workflow in VS Code (Mermaid Chart
|
|
82
|
+
extension: **Sync Diagram with Mermaid**, then **Review Mermaid Sync**) and pull the synced result.
|
|
83
|
+
Connecting a diagram, reviewing a sync, and accepting or rejecting synced commits are interactive
|
|
84
|
+
VS Code actions; they are human steps, not automatable from a Claude Code session.
|
|
85
|
+
|
|
86
|
+
The opt-out marker below never suppresses this constraint: the marker applies to fenced blocks in
|
|
87
|
+
Markdown, and the managed-diagram gate is keyed on diagram file paths.
|
|
88
|
+
|
|
89
|
+
## Opt-Out Marker for Deliberate Counter-Examples
|
|
90
|
+
|
|
91
|
+
Documentation legitimately quotes invalid Mermaid to demonstrate a defect. Placing the exact HTML
|
|
92
|
+
comment on the line immediately preceding a fence suppresses validation for that one block:
|
|
93
|
+
|
|
94
|
+
```text
|
|
95
|
+
<!-- mermaid-validator: ignore -->
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Rules for the marker:
|
|
99
|
+
|
|
100
|
+
- The comment text is exactly `mermaid-validator: ignore`, case-sensitive. Whitespace around the
|
|
101
|
+
line and inside the comment delimiters is permitted.
|
|
102
|
+
- It must sit on the line immediately before the opening ` ```mermaid ` fence, with no intervening
|
|
103
|
+
line, blank or otherwise.
|
|
104
|
+
- Its scope is exactly one block. A second counter-example needs its own marker; an unmarked
|
|
105
|
+
invalid block in the same file is still denied.
|
|
106
|
+
- It applies only to fenced blocks in Markdown. Diagram files have no opt-out: a diagram file is by
|
|
107
|
+
definition a diagram.
|
|
108
|
+
- A ` ```mermaid ` fence nested inside an outer, longer fence is already treated as example text
|
|
109
|
+
rather than a diagram and needs no marker.
|
|
110
|
+
|
|
111
|
+
## Out of Scope: The Non-Portable Extension Mechanisms
|
|
112
|
+
|
|
113
|
+
The Copilot instruction pack at `.github/instructions/mermaid.instructions.md` relies on VS Code
|
|
114
|
+
extension mechanisms that no Claude Code session can invoke. They are recorded here so a later
|
|
115
|
+
reader does not read the omission as an oversight. The same record appears in
|
|
116
|
+
`.claude/skills/mermaid-diagram/SKILL.md`.
|
|
117
|
+
|
|
118
|
+
| Mechanism | Why it is not ported | What replaces it |
|
|
119
|
+
| --- | --- | --- |
|
|
120
|
+
| `mermaid-diagram-validator` LM tool | A VS Code Language Model API tool contributed by the extension; not an MCP tool and not callable from a Claude session | The structural gate in this repository, weaker than a real parse and documented as such |
|
|
121
|
+
| `mermaid-diagram-preview` LM tool, `mermaidChart.preview` | A VS Code webview | The conditional rendering paths in the skill; GitHub renders fences natively |
|
|
122
|
+
| `get-syntax-docs-mermaid` LM tool | A VS Code LM API tool | The bundled per-type references under the skill, pinned to 11.17.0, with a documented `WebFetch` fallback to mermaid.js.org |
|
|
123
|
+
| The sixteen `mermaidChart.*` command IDs | Each needs the VS Code command API, an active editor, and the extension host | Portable capabilities are ported by substitution: validation to the hook, generation to the skill recipes, preview to conditional rendering, sync cooperation to the `id:` guard. The command IDs themselves are not ported |
|
|
124
|
+
| `@mermaid-chart` Copilot Chat slash commands | Copilot Chat participants do not exist on the Claude surface | The eight generation intents are skill recipe sections |
|
|
125
|
+
| `mermaidChart.repairDiagram`, `mermaidChart.improveDiagram` | Mermaid AI credits and extension UI | The gate's specific defect messages plus ordinary editing. No credit-consuming path exists on this surface, so there is nothing to warn about |
|
|
126
|
+
| `mermaidChart.login`, `logout`, `connectDiagramToMermaidChart`, `syncDiagramWithMermaid`, `reviewAppCommits`, `regenerateDiagramWithMermaidAI` | Interactive OAuth and extension UI against the Mermaid Chart cloud | Human steps in VS Code. The automatable half is in scope and delivered: the `id:` managed-diagram guard above |
|
|
127
|
+
| `mermaidChart.createMermaidFile`, `mermaidChart.installAiSkills` | Extension UI; the second is the Copilot-surface distribution mechanism | Creating a diagram file is an ordinary `Write`. The Claude distribution mechanism is the bundled resources mirror plus the `pack-manifests/core.json` entry |
|
|
128
|
+
| Deep `mmdc`/Chromium validation | Chromium-backed, seconds-level latency, no validate-only mode; unfit for a per-write gate | Recorded as an optional CI-side follow-up consuming the validator's structured result |
|
|
129
|
+
|
|
130
|
+
## Example
|
|
131
|
+
|
|
132
|
+
A minimal valid diagram file, frontmatter included:
|
|
133
|
+
|
|
134
|
+
```mermaid
|
|
135
|
+
---
|
|
136
|
+
title: Request handling
|
|
137
|
+
---
|
|
138
|
+
flowchart LR
|
|
139
|
+
A[Client] --> B{Authenticated}
|
|
140
|
+
B -->|yes| C[Handler]
|
|
141
|
+
B -->|no| D[Reject]
|
|
142
|
+
```
|
|
@@ -26,7 +26,7 @@ Enforced by `validate_parallel_orchestrator_state_text(text, *, require_complete
|
|
|
26
26
|
|
|
27
27
|
3. **Mode enum.** `mode` must be `closed` or `open`.
|
|
28
28
|
|
|
29
|
-
4. **Bounded concurrency.** `max_concurrency` must be an integer from 1 through
|
|
29
|
+
4. **Bounded concurrency.** `max_concurrency` must be an integer from 1 through 32, and must not be a boolean.
|
|
30
30
|
|
|
31
31
|
5. **Item uniqueness and shape.** Each `items[]` entry must be an object whose `issue_num` is a positive integer unique across items and whose `feature_folder` is a non-empty string.
|
|
32
32
|
|
|
@@ -98,7 +98,7 @@ Enforced by `validate_parallel_manifest_text(text)` in `scripts/dev_tools/parall
|
|
|
98
98
|
|
|
99
99
|
- **M3 — Mode default.** `mode`, when present, must be `closed` or `open`. When absent it defaults to `closed`: the accessor `manifest_mode(mapping)` returns the default and the validator emits no error for absence.
|
|
100
100
|
|
|
101
|
-
- **M4 — Concurrency default.** `max_concurrency`, when present, must be an integer from 1 through
|
|
101
|
+
- **M4 — Concurrency default.** `max_concurrency`, when present, must be an integer from 1 through 32. When absent it defaults to `4`: the accessor `manifest_max_concurrency(mapping)` returns the default and the validator emits no error for absence.
|
|
102
102
|
|
|
103
103
|
- **M5 — Created-at.** `created_at` must be a non-empty string.
|
|
104
104
|
|
|
@@ -106,6 +106,22 @@ Enforced by `validate_parallel_manifest_text(text)` in `scripts/dev_tools/parall
|
|
|
106
106
|
|
|
107
107
|
- **M7 — Prohibited keys.** No `depends_on` key may appear at any level, and no `integration_branch` key may appear at top level. Presence is an explicit rejection.
|
|
108
108
|
|
|
109
|
+
- **M8 — Expected conflict components (optional assertion).** `expected_conflict_components`, when present, must be a list. Each entry must be an object carrying a required `members` list that is non-empty and holds positive integers, each of which resolves to an `items[].issue_num`, with no `issue_num` appearing in more than one component; and an optional `name` that, when present, must be a non-empty string. When the key is ABSENT the invariant contributes zero errors and the manifest's error list is byte-identical to what it was before M8 existed.
|
|
110
|
+
|
|
111
|
+
The value must be authored as a YAML BLOCK sequence. The destination-runtime bash YAML subset parser (`.claude/lib/bash/parallel-yaml-scan.sh`) rejects a non-empty flow collection, so a flow-style value such as `members: [101, 102]` is outside the supported subset and is not accepted on the bash path.
|
|
112
|
+
|
|
113
|
+
`expected_conflict_components` is an ASSERTION, not a declaration. It NEVER overrides a derived conflict edge, NEVER feeds `compute_cohorts`, and NEVER influences scheduling. It is consumed by a planner diagnostic (`scripts/dev_tools/parallel_lane_assertion.py`), invoked advisory-only, whose findings never block. Its name deliberately references the DERIVED conflict graph: the field asserts what the operator expects blast-radius derivation to produce, and a mismatch is a signal to re-examine the radii, never a licence to edit the graph. The prohibition on narrowing a radius beyond the configured exclusions to suppress an edge is unaffected, as is the `depends_on` prohibition of invariant 10, P3, and M7 — this key is not a dependency edge and does not express ordering.
|
|
114
|
+
|
|
115
|
+
Example, in the mandatory block-sequence form:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
expected_conflict_components:
|
|
119
|
+
- name: hooks-lane # optional, diagnostic label only
|
|
120
|
+
members: # required, non-empty, positive ints
|
|
121
|
+
- 101
|
|
122
|
+
- 102
|
|
123
|
+
```
|
|
124
|
+
|
|
109
125
|
## Cache Doctrine — the checkpoint is not the source of truth
|
|
110
126
|
|
|
111
127
|
The parallel-orchestrator checkpoint is a CACHE of durable state, not the source of truth. Every field it records is re-derivable from the repository and from GitHub:
|
|
@@ -135,10 +151,19 @@ Per-item `merge_commit_sha` is retained; only the run-level merge-pull-request b
|
|
|
135
151
|
|
|
136
152
|
## Concurrency Bound (A7)
|
|
137
153
|
|
|
138
|
-
`max_concurrency` is bounded at 1 through
|
|
154
|
+
`max_concurrency` is bounded at 1 through 32 inclusive and defaults to `4` when absent from the manifest. The design document sets only the default of 4. Booleans are rejected even though `True` and `False` are integers in Python.
|
|
155
|
+
|
|
156
|
+
The upper bound is derived from a constraint analysis of this surface alone. No other surface's bound is a reason for it. The findings recorded here so that downstream features do not re-litigate them:
|
|
157
|
+
|
|
158
|
+
- **No constraint binds hard below O(100) concurrent worktrees.** Git worktrees, per-item feature branches, checkpoint size, and the cohort-coloring computation all scale well past a hundred concurrent items; none of them fails, or degrades sharply, anywhere near 32.
|
|
159
|
+
- **The first-binding constraint is GitHub Actions job concurrency**, which begins to bite at roughly 10 to 20 concurrent items on a typical plan. It binds by QUEUING, not by failing: excess jobs wait for a runner and the run completes more slowly. A `max_concurrency` above that point is therefore not an error, merely a setting whose marginal throughput is absorbed by the queue.
|
|
160
|
+
- **The ceiling of 32 is a SANITY limit, not a capacity limit.** Its purpose is to reject an order-of-magnitude operator typo (`320` for `32`), not to express a supported maximum. Do not read a value at or below 32 as an assurance that the runner pool can serve it.
|
|
161
|
+
- **Under the per-edge cohort barrier `max_concurrency` is a pure throughput throttle.** Mutual exclusion inside a conflict component is automatic: a conflicting neighbour in a strictly prior current-generation cohort must be `merged` or `worktree_removed` before an item starts, so raising the cap can never co-schedule two conflicting items. Raising it changes only how many independent lanes advance at once.
|
|
139
162
|
|
|
140
163
|
The bound is enforced in three places with the same semantics: orchestrator invariant 4, planner invariant P2, and manifest invariant M4.
|
|
141
164
|
|
|
165
|
+
The epic surface is unaffected. `max_parallel_features` remains bounded at `1..8`; it is a different field on a different surface and is not changed by this bound.
|
|
166
|
+
|
|
142
167
|
## Drift-Event Recording Rule (A8)
|
|
143
168
|
|
|
144
169
|
`drift_events[].action` is the two-member enum `{raised_blocking_finding, halted_later_started_item}`. The recording rule is: one event per drift occurrence, carrying the STRONGEST action taken. `halted_later_started_item` subsumes `raised_blocking_finding`, so an occurrence that halted a later-started item records exactly one event with `action == 'halted_later_started_item'` and does not additionally record a `raised_blocking_finding` event for the same occurrence.
|
|
@@ -173,6 +198,65 @@ F3 deliberately excludes the kickoff-prompt contract module `scripts/dev_tools/p
|
|
|
173
198
|
|
|
174
199
|
F3's `require_ready_for_execution` gate is STRUCTURAL ONLY. It enforces the kickoff-PATH invariant (P9: `kickoff_prompt_path` must equal `artifacts/orchestration/parallel-kickoff-<parallel_slug>.md`) and does not parse or cross-check kickoff CONTENT. The deeper readiness-integrity machinery of the epic surface — git-integrity checks, launch-evidence binding, and kickoff-contract cross-checks — is left to F4, which may layer repository-aware checks behind an additional keyword without changing the schema. F3 likewise does not recompute the cohort coloring (planner invariant P5).
|
|
175
200
|
|
|
201
|
+
## Blast-Radius Contention Doctrine (issue #489)
|
|
202
|
+
|
|
203
|
+
The conflict graph that seeds cohorts is only as good as the evidence that produces its edges. Two
|
|
204
|
+
classes of derivation defect made thematically unrelated items contend, and the corrections below
|
|
205
|
+
are part of the landed contract. Enforcement remains prose plus validator logic; no JSON Schema is
|
|
206
|
+
authored, imported, or read for any of it.
|
|
207
|
+
|
|
208
|
+
### Read-by-mandate classification
|
|
209
|
+
|
|
210
|
+
Every agent in this repository is instructed to read the policy rules, the tier map, and the process
|
|
211
|
+
artifacts before doing any work. A plan that cites `.claude/rules/python.md` or `quality-tiers.yml`
|
|
212
|
+
is therefore reporting compliance with the reading order, not declaring that its diff will write
|
|
213
|
+
those files. Counting such a citation as contention made every well-formed plan collide with every
|
|
214
|
+
other well-formed plan.
|
|
215
|
+
|
|
216
|
+
`config/blast-radius.json` carries an optional `mandate_reads` list enumerating those paths as exact
|
|
217
|
+
entries and `**` subtree globs. That list is the mandate-read exclusion set. `derive_blast_radius` removes matching citations from the harvest
|
|
218
|
+
before resolving modules and shared surfaces, and `validate_blast_radius` removes them from its
|
|
219
|
+
plan-side extraction so V1 and V2 stay self-consistent against a radius derived from the same plan.
|
|
220
|
+
The key is optional and fail-closed: a truth table that omits it excludes nothing and reproduces
|
|
221
|
+
pre-change behaviour exactly.
|
|
222
|
+
|
|
223
|
+
Three constraints bound the mandate-read exclusion:
|
|
224
|
+
|
|
225
|
+
1. **The planner remains obliged to enumerate a genuine write explicitly.** An exclusion describes
|
|
226
|
+
the default reading relationship, not a permanent ban. When an item's plan will actually write an
|
|
227
|
+
excluded path, the planner appends that exact path to the declared radius after normalization.
|
|
228
|
+
2. **`quality-tiers.yml` stays a shared surface.** It is listed in both `shared_surfaces` and
|
|
229
|
+
`mandate_reads`: the first governs what happens when an item really writes it, the second governs
|
|
230
|
+
what happens when an item merely cites it.
|
|
231
|
+
3. **`detect_escaped_paths` makes the read/write distinction exact at execution time.** The
|
|
232
|
+
derivation heuristic reads intent from plan text and can be wrong in either direction; drift
|
|
233
|
+
detection compares the declared radius against the paths a diff actually touched, so an item that
|
|
234
|
+
wrote an excluded path is caught against observed evidence rather than against prose.
|
|
235
|
+
|
|
236
|
+
The extractor additionally rejects three token shapes that were never write claims: a wildcard-free
|
|
237
|
+
token whose final component names a directory rather than a file, a `docs/features/` glob whose
|
|
238
|
+
wildcard occupies or truncates the feature-folder segment, and a contract token carrying no ASCII
|
|
239
|
+
letter. `artifacts/` is not a known top-level segment, so a bare `artifacts/**` subtree claim no
|
|
240
|
+
longer satisfies the shape rules.
|
|
241
|
+
|
|
242
|
+
### Module-map granularity criterion
|
|
243
|
+
|
|
244
|
+
Issue #472 removed the location-bucket modules `docs` and `tests` because a bucket keyed on where a
|
|
245
|
+
file lives rather than on which subsystem owns it attaches to nearly every work item. The same
|
|
246
|
+
reasoning extends to umbrella buckets keyed on a top-level directory that essentially every item
|
|
247
|
+
writes into: an umbrella that matches almost every radius is not a coherent unit of contention,
|
|
248
|
+
because a level that always fires carries no information and only suppresses concurrency.
|
|
249
|
+
|
|
250
|
+
Under that criterion `python-dev-tools`, `vscode-extension`, `claude-runtime`, `copilot-surface`,
|
|
251
|
+
and `agents-surface` were removed, leaving the seven subsystem modules `mcp-server`, `benchmarks`,
|
|
252
|
+
`poshqc`, `powershell-dev-tools`, `codex-runtime`, `config`, and `schemas`. Removing a module never
|
|
253
|
+
weakens the relation below the path level: two items editing the same file still contend on
|
|
254
|
+
`path_overlap`, and two items editing a declared shared surface still contend on
|
|
255
|
+
`shared_surface_overlap`.
|
|
256
|
+
|
|
257
|
+
A candidate module belongs in the map when it names a subsystem an item could plausibly not touch.
|
|
258
|
+
A candidate that matches the majority of work items belongs nowhere.
|
|
259
|
+
|
|
176
260
|
## Enforcement
|
|
177
261
|
|
|
178
262
|
- `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`.
|
|
@@ -182,3 +266,4 @@ F3's `require_ready_for_execution` gate is STRUCTURAL ONLY. It enforces the kick
|
|
|
182
266
|
- 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.
|
|
183
267
|
- 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.
|
|
184
268
|
- 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`.
|
|
269
|
+
- 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`.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Atomic-Plan Acceptance Gates (G1 through G6)
|
|
2
|
+
|
|
3
|
+
This rule governs the acceptance-gate rules the plan validator applies to the shell commands an atomic plan states as acceptance conditions. 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).
|
|
4
|
+
|
|
5
|
+
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`, both fed by the command extractor (`scripts/dev_tools/plan_gate_commands.py` and `extensions/drm-copilot/src/lib/validate/plan-gate-commands.ts`). Enforcement is validator logic plus this prose file. No JSON Schema is authored, imported, or read.
|
|
6
|
+
|
|
7
|
+
## Scope of Invocation — no grandfathering or exemption mechanism
|
|
8
|
+
|
|
9
|
+
The plan validator only ever runs against the single artifact it is pointed at. No CI job, test, or scheduled task sweeps the committed plan corpus, and none is added by this feature. A pre-existing plan that would produce a finding is therefore never evaluated unless someone deliberately points the validator at it.
|
|
10
|
+
|
|
11
|
+
That scope is the argument against a grandfathering list, an exemption marker, a per-plan suppression comment, and an allowlist file. Each of those mechanisms exists to protect an existing corpus from a newly added sweep. With no sweep there is nothing to protect, and the mechanism would add a suppression surface whose only reachable use is to silence a finding on the plan currently being authored — which is precisely the case the gate exists to report.
|
|
12
|
+
|
|
13
|
+
The consequence is that adding a rule to this set is cheap in migration cost and expensive in authoring cost. Weigh a new rule on its false-positive rate at authoring time, not on how many committed plans it would have flagged.
|
|
14
|
+
|
|
15
|
+
## Rule Table
|
|
16
|
+
|
|
17
|
+
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.
|
|
18
|
+
|
|
19
|
+
| Rule | Condition | Shipped severity |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| **G1** | A non-placeholder `--cov` value whose text, truncated at the first `::`, ends with `.py`. A `.py` suffix proves a filesystem path, which `coverage.py` rejects; the check is context-free and needs no repository lookup. | **Blocking** |
|
|
22
|
+
| **G2** | A `--cov` value containing a path separator whose text plus `.py` is a tracked file. The tracked sibling names the intended module exactly, so the dotted remedy is known. | **Blocking** |
|
|
23
|
+
| **G3** | A `--cov` value containing a path separator that resolves to neither a tracked file plus `.py` nor a tracked directory. Data collection is unknown rather than provably absent. | **Warning** |
|
|
24
|
+
| **G4** | A `--cov` value supplied space-separated (`--cov <value>`) rather than with `=`. The ambiguous form can bind the following positional argument. Independent of resolvability, so it is reported for every value. | **Warning** |
|
|
25
|
+
| **G5** | A checkable search literal that is absent from the tracked tree **and** not quoted in the plan document outside the command span it was read from. | **Warning** (see below) |
|
|
26
|
+
| **G6** | A checkable search literal absent from every single line of a tracked file but present in that file's sliding-window join of adjacent lines. A line-oriented search returns zero matches. | **Warning** |
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
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, and the Blocking list is byte-identical to the pre-change output for the same text.
|
|
31
|
+
|
|
32
|
+
### Attribution window
|
|
33
|
+
|
|
34
|
+
A command span is attributed to the current `P#-T#` when it sits on a task line or on a following line that is not itself a task line and is not separated from the task line by a Markdown ATX heading. A span in the document preamble, in a phase preamble, or after an intervening heading belongs to no task and is dropped rather than reported. A span that belongs to no task cannot be reported against one.
|
|
35
|
+
|
|
36
|
+
### Graceful degradation
|
|
37
|
+
|
|
38
|
+
A repository seam that raises, or that reports a non-zero exit, causes G2, G3, G5, and G6 to be skipped. No finding is produced and no exception escapes the evaluation entry point. A validation run must never fail because the repository could not be queried.
|
|
39
|
+
|
|
40
|
+
## Severity Decisions
|
|
41
|
+
|
|
42
|
+
### G5 — fixed by the corpus measurement and by nothing else
|
|
43
|
+
|
|
44
|
+
The shipped G5 severity was not chosen by argument. It was fixed by a pre-declared rule applied to a measurement over the committed plan corpus: Blocking if and only if the total G5 finding count is greater than zero **and** the recorded false-positive count is zero; otherwise Warning.
|
|
45
|
+
|
|
46
|
+
The measurement is recorded in `docs/features/active/2026-08-17-reject-unfalsifiable-acceptance-gates-in-atomic-plans-486/evidence/qa-gates/g5-corpus-measurement.2026-08-20T12-02.md`. It scanned 166 plan files, evaluated 100 candidate literals, and produced a total G5 finding count of 0. A zero false-positive count over zero findings measures nothing, so the first conjunct failed and **G5 ships as a Warning**.
|
|
47
|
+
|
|
48
|
+
The zero count is a property of the corpus, not a defect in the measurement. Every committed plan is a tracked file, so a fixed-string search for a literal quoted inside a committed plan always finds at least that plan itself, and the tree-absence condition holds for no committed candidate. The measurement artifact records the four checks that established this (non-vacuous enumeration, a working repository seam, a self-hit on every sampled lookup, and predicate-order equivalence with the shipped rule).
|
|
49
|
+
|
|
50
|
+
The rule remains meaningful for its intended use. The validator runs against a single plan artifact at authoring time, when that plan is typically uncommitted and therefore untracked, so its own text does not satisfy the tracked-tree presence test. The plan-quotation condition is what exonerates a literal the plan instructs the executor to create.
|
|
51
|
+
|
|
52
|
+
A later feature may revisit the severity, but only against a fresh measurement taken the same way. The severity is a single constant in each runtime (`G5_SEVERITY`), and a parity test asserts the two constants agree.
|
|
53
|
+
|
|
54
|
+
### G6 — ships as a Warning
|
|
55
|
+
|
|
56
|
+
The Blocking argument for G6 is real and is preserved here rather than discarded. A literal present only across a line wrap is *provably* unmatched by a line-oriented search: the tracked evidence shows the phrase exists in the file yet matches no single line, so the assertion is known to return zero matches. That is a stronger evidential position than G3, which only reports that resolution is unknown, and it is comparable to G1, which is Blocking.
|
|
57
|
+
|
|
58
|
+
G6 nonetheless ships as a Warning because of a residual false-positive case the rule cannot distinguish. The window join is computed over the file's committed text at `HEAD`. When the plan's own task is what rewrites that file so the phrase lands on one line, the pre-change committed text legitimately wraps the phrase and the post-change text does not. G6 then reports a search that will match after the task runs. The plan-quotation exoneration catches the common form of this case, but only when the plan quotes the literal contiguously in prose outside the command span; a plan that paraphrases the intended edit is still reported.
|
|
59
|
+
|
|
60
|
+
Rejecting such a plan would block a correct plan on evidence about a state the plan is about to change. Surfacing the finding without failing the gate gives the author the same information at no such cost. Reclassifying G6 as Blocking requires first eliminating that case, for example by evaluating the window join against the working tree rather than `HEAD`.
|
|
61
|
+
|
|
62
|
+
### The G6 sliding window is four adjacent non-blank lines
|
|
63
|
+
|
|
64
|
+
The window size is fixed at four adjacent non-blank lines. Blank lines are removed before windowing, and one window is emitted per start position, so the boundary is exact: two lines further apart than the window size never appear in the same join. The size is recorded here rather than left implicit so that a later feature can revise it against measured wrap-depth data instead of re-deriving it.
|
|
65
|
+
|
|
66
|
+
## Checkable-Literal Definition and the Placeholder Guard
|
|
67
|
+
|
|
68
|
+
G5 and G6 apply only to a *checkable* literal. The specification defines a checkable literal by two conditions: the command carries the fixed-string flag `-F`, or the pattern contains none of the regular-expression metacharacters `. * [ ] ^ $ \ ( ) { } | + ?`. That condition is conservative in POSIX BRE, POSIX ERE, PCRE, and the Rust regex dialect simultaneously, so no dialect-selection logic is required.
|
|
69
|
+
|
|
70
|
+
The shipped predicate **extends** that definition with a third condition, and the extension is deliberate: a pattern operand containing any placeholder or interpolation marker is never checkable, even when `-F` is supplied. The markers are `<`, `>`, `${`, `$(`, and `%` — the same set the coverage rules use to skip a placeholder `--cov` value.
|
|
71
|
+
|
|
72
|
+
The guard exists because a command span whose operand is a placeholder was never intended to be executed verbatim. It documents a command *shape*, so it states no real acceptance assertion, and the resolvability of a placeholder operand is not decidable. Without the guard, every plan that documents a command shape using a placeholder operand receives a G5 finding.
|
|
73
|
+
|
|
74
|
+
### Known false-negative class
|
|
75
|
+
|
|
76
|
+
The guard is purely textual, so it fires on any pattern containing a placeholder character in any role. A literal that uses `<`, `>`, or `%` as an ordinary character — a TypeScript generic, a comparison operator, a version constraint, a percentage, an HTML or XML tag — is therefore skipped and can never produce a G5 or G6 finding, however unfalsifiable the assertion actually is.
|
|
77
|
+
|
|
78
|
+
This is a false-negative class, not a defect to be silently tolerated: it is the cost side of the trade recorded below, and a later feature that narrows the guard must re-measure the false-positive side before doing so. Narrowing candidates include restricting the markers to bracket *pairs* enclosing an identifier-like token, or to the interpolation forms `${` and `$(` plus `%NAME%`, rather than treating every bare `<`, `>`, and `%` as a marker.
|
|
79
|
+
|
|
80
|
+
### Preflight measurement that fixed the trade
|
|
81
|
+
|
|
82
|
+
The trade was settled by measurement, not by preference. Across the 164-plan corpus examined at preflight, the placeholder guard suppressed exactly three pattern operands and suppressed zero additional findings:
|
|
83
|
+
|
|
84
|
+
1. An **angle-bracketed placeholder** inside a documented `git grep` command shape. This is the guard's intended target: the command was written to show a shape, not to be run.
|
|
85
|
+
2. A **TypeScript generic** of the `warnings?: ReadonlyArray<string>` shape. Its own plan quotes the token contiguously in prose, so the plan-quotation condition would have exonerated it regardless; the guard changed nothing for this operand.
|
|
86
|
+
3. A **version constraint** of the `Node >=18` shape. The token is present in the tracked tree, so the tree-absence condition never held and no finding would have been produced; the guard again changed nothing.
|
|
87
|
+
|
|
88
|
+
Only the first operand was suppressed by the guard in a way that altered the outcome, and it is the case the guard is for. The other two were already exonerated by conditions the guard does not touch. Against that, removing the guard would have produced a finding on every plan that documents a placeholder-bearing command shape. The measured cost of the guard on this corpus is therefore zero suppressed true positives.
|
|
89
|
+
|
|
90
|
+
## Message Formatting — no `repr()`, no `!r`, no `pythonRepr`
|
|
91
|
+
|
|
92
|
+
Every gate message renders the offending coverage value or search literal **between backticks**, in both runtimes, with no surrounding quote characters supplied by a formatting helper.
|
|
93
|
+
|
|
94
|
+
The following are prohibited in gate messages:
|
|
95
|
+
|
|
96
|
+
- Python `repr()` and the `!r` conversion in an f-string.
|
|
97
|
+
- Any `pythonRepr` helper on the TypeScript side.
|
|
98
|
+
|
|
99
|
+
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.
|
|
100
|
+
|
|
101
|
+
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 three 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.
|
|
102
|
+
|
|
103
|
+
## Authoring Guidance for Plan Authors
|
|
104
|
+
|
|
105
|
+
- Express coverage targets as importable dotted names (`--cov=scripts.dev_tools.module`), never as filesystem paths, and always with the `=` form.
|
|
106
|
+
- Where an acceptance condition is a search, assert a short, single-line, non-interpolated token that the plan quotes verbatim.
|
|
107
|
+
- Prefer a named test over a phrase search whenever a test can carry the assertion.
|
|
108
|
+
|
|
109
|
+
`.claude/skills/atomic-plan-contract/SKILL.md` carries the authoring-side statement of this guidance and cross-references this file.
|
|
110
|
+
|
|
111
|
+
## Enforcement
|
|
112
|
+
|
|
113
|
+
- `scripts/dev_tools/plan_gate_commands.py` extracts task-attributed command candidates; `scripts/dev_tools/plan_gate_discrimination.py` evaluates G1 through G6 and returns the two severity channels.
|
|
114
|
+
- `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.
|
|
115
|
+
- 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.
|
|
116
|
+
- `.claude/hooks/validate-planner-output.ps1` is not modified by this rule and carries no part of its enforcement.
|
|
@@ -61,7 +61,7 @@ Introduce the smallest seam that enables reliable mocking. Apply these options i
|
|
|
61
61
|
- Mock sparingly; prefer real code paths.
|
|
62
62
|
- No external dependencies in unit tests.
|
|
63
63
|
- Line coverage must remain >= 85% across all tiers (T1–T4) per `.claude/rules/quality-tiers.md`.
|
|
64
|
-
-
|
|
64
|
+
- Pester reports **command (instruction) coverage and line coverage only**. The uniform line-coverage threshold (>= 85% per `.claude/rules/quality-tiers.md`) applies. Branch coverage is not measurable by Pester for PowerShell; there is no PowerShell branch-coverage gate. This removes an unevaluable threshold, not a measurement obligation: PowerShell production files remain in the coverage denominator per the Coverage Exclusion Policy in `.claude/rules/general-unit-test.md`, and command coverage is reported for information only, with no threshold attached.
|
|
65
65
|
- Coverage regression on changed lines is a blocking finding.
|
|
66
66
|
|
|
67
67
|
### Deterministic Test Requirements
|
|
@@ -22,7 +22,7 @@ This rule defines the T1–T4 module rigor tier system used by all CI gates in t
|
|
|
22
22
|
|
|
23
23
|
## Uniform-vs-Tier-Dependent Gate Matrix
|
|
24
24
|
|
|
25
|
-
Per Authoritative Decision #2, line and branch coverage thresholds are uniform across all tiers. Other gates remain tier-dependent.
|
|
25
|
+
Per Authoritative Decision #2, line and branch coverage thresholds are uniform across all tiers. The line threshold applies to every coverage language; the branch threshold applies to languages whose coverage tooling measures branch coverage. Other gates remain tier-dependent.
|
|
26
26
|
|
|
27
27
|
### Uniform across all tiers (T1–T4)
|
|
28
28
|
|
|
@@ -31,7 +31,7 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
|
|
|
31
31
|
- Type errors: 0.
|
|
32
32
|
- Architecture violations: 0.
|
|
33
33
|
- Line coverage: >= 85%.
|
|
34
|
-
- Branch coverage: >= 75
|
|
34
|
+
- Branch coverage: >= 75% for languages whose coverage tooling measures branch coverage. PowerShell (Pester) and bash (kcov) are exempt from this threshold because neither tool measures branch coverage; no branch-coverage gate applies to them.
|
|
35
35
|
- No regression on changed lines.
|
|
36
36
|
|
|
37
37
|
### Tier-dependent
|
|
@@ -48,4 +48,4 @@ Per Authoritative Decision #2, line and branch coverage thresholds are uniform a
|
|
|
48
48
|
|
|
49
49
|
## Rationale (uniform coverage thresholds)
|
|
50
50
|
|
|
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% and branch coverage >= 75%
|
|
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 in this repository. 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`.
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"Skill(execute-hard-lock *)",
|
|
65
65
|
"Skill(identify-session-id *)",
|
|
66
66
|
"Skill(show-my-agent-tree *)",
|
|
67
|
+
"Skill(mermaid-diagram *)",
|
|
67
68
|
"Edit(/.claude/skills/execute-hard-lock/**)",
|
|
68
69
|
"Edit(/.claude/skills/feature-review-workflow/**)",
|
|
69
70
|
"Edit(/.claude/skills/csharp-qa-gate/**)"
|
|
@@ -170,6 +171,10 @@
|
|
|
170
171
|
{
|
|
171
172
|
"type": "command",
|
|
172
173
|
"command": "pwsh -NoProfile -File .claude/hooks/enforce-discovery-artifact-gate.ps1"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"type": "command",
|
|
177
|
+
"command": "pwsh -NoProfile -File .claude/hooks/enforce-mermaid-validation.ps1"
|
|
173
178
|
}
|
|
174
179
|
]
|
|
175
180
|
},
|
|
@@ -157,6 +157,21 @@ Before a plan can be treated as approved:
|
|
|
157
157
|
- reject the plan if that validator exits non-zero,
|
|
158
158
|
- do not treat human-readable summaries as a substitute for validator success.
|
|
159
159
|
|
|
160
|
+
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.
|
|
161
|
+
|
|
162
|
+
## Wrap-Tolerant Assertion Authoring (Mandatory)
|
|
163
|
+
|
|
164
|
+
An acceptance condition must be able to fail. A condition whose command returns the same result whatever the executor does verifies nothing, however precise it reads. Author every acceptance condition in a wrap-tolerant form: one that survives line wrapping and shell quoting in the file it asserts against.
|
|
165
|
+
|
|
166
|
+
Rules:
|
|
167
|
+
|
|
168
|
+
- **Prefer a named test over a phrase search.** When a test can carry the assertion, name the test and its node ID and assert its pass count. A test node ID is stable under reformatting; a prose phrase is not. Reserve searches for cases where no test can express the condition.
|
|
169
|
+
- **Single-line token rule.** Where a search is unavoidable, assert a short, single-line, non-interpolated token that the plan quotes verbatim. A multi-word phrase drawn from prose is wrap-fragile: once the target file reflows, the phrase spans two lines and a line-oriented search returns zero matches even though the text is present. Rule G6 in `.claude/rules/plan-acceptance-gates.md` reports this case.
|
|
170
|
+
- **No placeholders in an asserted token.** A token containing `<`, `>`, `${`, `$(`, or `%` is treated as a documented command shape rather than a real assertion and is skipped by the gate, so it gates nothing. Substitute the concrete value.
|
|
171
|
+
- **Dotted coverage-argument form.** Coverage assertions must name an importable dotted module, for example `--cov=scripts.dev_tools.plan_gate_discrimination`. The filesystem-path spellings `--cov=scripts/dev_tools/module.py` and `--cov=scripts/dev_tools/module` collect no data, so a coverage threshold asserted against them cannot fail. Rules G1 through G3 report those spellings.
|
|
172
|
+
- **Use the `=` form, not the space-separated form.** `--cov <value>` can bind the following positional argument. Rule G4 reports it.
|
|
173
|
+
- **Quote what the task will create.** When an asserted literal does not yet exist in the tree, quote the exact literal in the plan prose outside the command span. The gate reads that quotation as the executor's instruction and exonerates the assertion; a paraphrase does not.
|
|
174
|
+
|
|
160
175
|
## Plan-Path Continuity Contract (Mandatory)
|
|
161
176
|
|
|
162
177
|
When a caller provides an explicit target plan file path (for example `${plan-path}` or `${file}`):
|
package/resources/claude-customizations/.claude/skills/evidence-and-timestamp-conventions/SKILL.md
CHANGED
|
@@ -110,6 +110,19 @@ When evidence artifacts are used for automated checking or plan reconciliation,
|
|
|
110
110
|
- `Command: <exact command>`
|
|
111
111
|
- `EXIT_CODE: <int>`
|
|
112
112
|
|
|
113
|
+
One optional field may also be declared:
|
|
114
|
+
- `ExpectedExitCode: <int>` — the exit code the gate is expected to produce.
|
|
115
|
+
|
|
116
|
+
Rules for the optional expectation field:
|
|
117
|
+
- The spelling is exact and case-sensitive: `ExpectedExitCode`. `expectedexitcode` and `Expected Exit Code` do not match the accept-list and are discarded as unrecognized rows.
|
|
118
|
+
- The value is a single integer. A leading sign is accepted and no range check is applied; the value is used for an equality comparison only.
|
|
119
|
+
- When the field is absent the expectation defaults to `0`, so every artifact that omits it keeps its existing result. Writing `ExpectedExitCode: 0` explicitly renders identically to omitting the field.
|
|
120
|
+
- A present but non-integer value (including an empty value) makes the WHOLE artifact `unparseable`. An unparseable artifact is dropped by the collector filter, so a typo in the expectation removes the row from the PR body rather than degrading it to `fail`.
|
|
121
|
+
- When the field is duplicated, the FIRST occurrence wins in both the Python and the TypeScript parser; later occurrences are ignored.
|
|
122
|
+
- The field is per-FILE, not per-gate: one artifact carries exactly one expectation, so an artifact recording several gates cannot express a different expectation for each. Record a gate that needs a non-zero expectation in its own artifact file.
|
|
123
|
+
|
|
124
|
+
A gate whose observed `EXIT_CODE` equals its declared expectation is normalized to `pass`. The observed exit code is still displayed, and the rendered row additionally carries ` - Expected EXIT_CODE: <int>` between the `EXIT_CODE` and `Normalized result` lines when the expectation is non-zero.
|
|
125
|
+
|
|
113
126
|
### Baseline Evidence Output Summary (Required)
|
|
114
127
|
|
|
115
128
|
For baseline evidence artifacts stored under `evidence/baseline/`, include an output summary in addition to the schema fields above:
|
|
@@ -68,8 +68,14 @@ When orchestrator routing selects short path, promotion/folder initialization st
|
|
|
68
68
|
- `${feature-folder}/issue.md` contains an explicit `## Acceptance Criteria` section
|
|
69
69
|
- `${feature-folder}/spec.md` does not exist
|
|
70
70
|
- `${feature-folder}/user-story.md` does not exist
|
|
71
|
+
- the promoted record under `docs/features/potential/promoted/` is still present (see 4b)
|
|
71
72
|
- if any check fails, stop and remediate before planning
|
|
72
73
|
|
|
74
|
+
4b) Verify the promoted record was retained after `new_active_feature_folder`:
|
|
75
|
+
- the promoted file the earlier `potential_to_issue` step reported as its `destination_path` must still exist under `docs/features/potential/promoted/`
|
|
76
|
+
- `new_active_feature_folder` COPIES a promoted source into the active folder as `issue.md`; it MOVES a source resolved from `docs/features/potential/` directly. An absent promoted record after a promoted-source run is a defect, not expected cleanup (issue #487).
|
|
77
|
+
- this check applies to every work mode, not only `minor-audit`
|
|
78
|
+
|
|
73
79
|
5) Delegate minimal-audit plan creation to `atomic_planner` with directive:
|
|
74
80
|
- `DIRECTIVE: MINIMAL-AUDIT PLAN REQUIRED`
|
|
75
81
|
|
|
@@ -108,10 +108,10 @@ If the branch diff modifies any path matching `.github/workflows/**`, `scripts/b
|
|
|
108
108
|
- Python: `poetry run pytest --cov` → artifact: `artifacts/python/lcov.info`
|
|
109
109
|
- PowerShell: `mcp__drm-copilot__run_poshqc_test` → artifact: `artifacts/pester/powershell-coverage.xml`
|
|
110
110
|
- C#: `dotnet test --collect:"XPlat Code Coverage"` → artifact: `artifacts/csharp/coverage.xml`
|
|
111
|
-
- Coverage thresholds (uniform tier rule per quality-tiers.md):
|
|
112
|
-
- New code files (added in this feature): line coverage >= 85
|
|
113
|
-
- Modified files (changed but previously existing): line coverage >= 85%, branch coverage >= 75
|
|
114
|
-
- Repo-wide per language: line coverage >= 85
|
|
111
|
+
- Coverage thresholds (uniform tier rule per quality-tiers.md). The branch threshold applies only to branch-capable languages — TypeScript, Python, and C#. PowerShell is a coverage language and is fully subject to the line threshold and the no-regression requirement, but Pester measures command (instruction) coverage and line coverage only, so no branch percentage exists to evaluate and no branch threshold applies to it (see `.claude/rules/powershell.md`). Do not flag a missing PowerShell branch figure as FAIL:
|
|
112
|
+
- New code files (added in this feature): line coverage >= 85%, and branch coverage >= 75% for branch-capable languages. Flag as FAIL otherwise.
|
|
113
|
+
- Modified files (changed but previously existing): line coverage >= 85%, branch coverage >= 75% for branch-capable languages, and no regression on changed lines relative to baseline. Flag as FAIL otherwise.
|
|
114
|
+
- Repo-wide per language: line coverage >= 85%, and branch coverage >= 75% for branch-capable languages. Flag as FAIL otherwise.
|
|
115
115
|
- If coverage artifacts already exist from the executor run, inspect them instead of re-running.
|
|
116
116
|
- If no coverage artifact exists for a language that has changed files, flag as FAIL — coverage verification is mandatory for all languages with changed files.
|
|
117
117
|
- Run the smallest relevant subset first when the repo policy permits it.
|