@danmoisan/drm-copilot-mcp 1.1.0 → 1.1.2
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 +10 -2
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +349 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +118 -6
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +34 -60
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +187 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +16 -0
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +62 -4
- package/resources/claude-customizations/.claude/skills/epic-plan/SKILL.md +27 -0
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +28 -0
- package/resources/claude-customizations/config/orchestration-routing.json +1 -1
- package/resources/claude-customizations/pack-manifests/core.json +2 -0
- package/resources/codex-and-agents-customizations/.agents/skills/architecture-boundaries/SKILL.md +0 -3
- package/resources/codex-and-agents-customizations/.agents/skills/csharp/SKILL.md +0 -3
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/csharp-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/epic-plan/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/evidence-and-timestamp-conventions/SKILL.md +2 -1
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/general-unit-test/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +3 -2
- package/resources/codex-and-agents-customizations/.agents/skills/policy-audit-template-usage/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +0 -4
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-change-budget-router/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/powershell-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/python-qa-gate/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/python-suppressions/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/quality-tiers/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/research-issue/SKILL.md +4 -3
- package/resources/codex-and-agents-customizations/.agents/skills/self-explanatory-code-commenting/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/tonality/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/translate-claude-to-codex/SKILL.md +3 -3
- package/resources/codex-and-agents-customizations/.agents/skills/translate-copilot-to-claude/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/typescript/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.agents/skills/typescript-suppressions/SKILL.md +0 -2
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1 +349 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +123 -6
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +1 -0
- package/resources/config/orchestration-routing.json +1 -1
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +17 -1
|
@@ -44,6 +44,16 @@ Set-StrictMode -Version Latest
|
|
|
44
44
|
# imports no sibling.
|
|
45
45
|
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusGlob.psm1') -Force
|
|
46
46
|
|
|
47
|
+
# Test-MultipleFeatureFolderSpan moved to BlastRadiusTokenShape.psm1, joining the
|
|
48
|
+
# new Test-PlaceholderMarker predicate that could not be added here: this module
|
|
49
|
+
# had two lines of headroom against the 500-line limit (issue #502). Both
|
|
50
|
+
# predicates are context-free shape tests, so they form one cohesive leaf. The
|
|
51
|
+
# import keeps every pre-existing call site and test source-compatible and
|
|
52
|
+
# introduces no cycle, because the TokenShape module imports no sibling. This
|
|
53
|
+
# follows the same re-import-and-re-export pattern used above for the relocated
|
|
54
|
+
# ordinal-sort helper.
|
|
55
|
+
Import-Module (Join-Path -Path $PSScriptRoot -ChildPath 'BlastRadiusTokenShape.psm1') -Force
|
|
56
|
+
|
|
47
57
|
# Plan-structure patterns. The regex text mirrors the Python constants so radius
|
|
48
58
|
# derivation and the plan validator can never disagree about which lines are
|
|
49
59
|
# phase headings and which are tasks.
|
|
@@ -71,12 +81,6 @@ $script:KnownTopLevelSegment = @(
|
|
|
71
81
|
# acceptance its unanchored form has; the token itself is recorded verbatim.
|
|
72
82
|
$script:LineSuffixPattern = [regex]::new(':\d+$')
|
|
73
83
|
|
|
74
|
-
# Documentation-corpus root and the index, counted after that prefix, of the
|
|
75
|
-
# segment that names one feature folder. A glob whose wildcard reaches this
|
|
76
|
-
# segment or any earlier one claims every feature folder in the corpus.
|
|
77
|
-
$script:FeatureCorpusPrefix = 'docs/features/'
|
|
78
|
-
$script:FeatureFolderSegmentIndex = 1
|
|
79
|
-
|
|
80
84
|
# Fallback acceptance rule: a token shaped <segment>/.../<name>.<ext> counts as a
|
|
81
85
|
# repository path when its final component carries one of these extensions.
|
|
82
86
|
$script:RecognizedPathExtension = [System.Collections.Generic.HashSet[string]]::new(
|
|
@@ -233,60 +237,6 @@ function Get-InlineCodeToken {
|
|
|
233
237
|
return @($token.ToArray())
|
|
234
238
|
}
|
|
235
239
|
|
|
236
|
-
function Test-MultipleFeatureFolderSpan {
|
|
237
|
-
<#
|
|
238
|
-
.SYNOPSIS
|
|
239
|
-
Report whether a glob claims more than one documentation feature folder.
|
|
240
|
-
|
|
241
|
-
.DESCRIPTION
|
|
242
|
-
Port of spans_multiple_feature_folders. The documentation corpus is laid
|
|
243
|
-
out as docs/features/<bucket>/<feature-folder>/..., so a glob whose
|
|
244
|
-
wildcard occupies or truncates the feature-folder segment claims every
|
|
245
|
-
feature folder in the corpus. That made two unrelated work items contend
|
|
246
|
-
purely because both wrote documentation (issue #489). A glob carrying a
|
|
247
|
-
complete, wildcard-free feature-folder segment claims one folder and is
|
|
248
|
-
retained.
|
|
249
|
-
|
|
250
|
-
.PARAMETER Token
|
|
251
|
-
A wildcard-bearing token already accepted by the shape rules of
|
|
252
|
-
Get-PathTokenKind.
|
|
253
|
-
|
|
254
|
-
.OUTPUTS
|
|
255
|
-
System.Boolean. True when the token is rooted in the documentation corpus
|
|
256
|
-
and its wildcard reaches the feature-folder segment or any earlier one.
|
|
257
|
-
#>
|
|
258
|
-
[CmdletBinding()]
|
|
259
|
-
[OutputType([bool])]
|
|
260
|
-
param(
|
|
261
|
-
[Parameter(Mandatory = $true)]
|
|
262
|
-
[AllowEmptyString()]
|
|
263
|
-
[string] $Token
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
if (-not $Token.StartsWith($script:FeatureCorpusPrefix,
|
|
267
|
-
[System.StringComparison]::Ordinal)) {
|
|
268
|
-
return $false
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
$segment = @($Token.Substring($script:FeatureCorpusPrefix.Length) -split '/')
|
|
272
|
-
|
|
273
|
-
# A token that stops at or before the feature-folder segment has had that
|
|
274
|
-
# segment truncated away by the wildcard, so it spans the whole corpus.
|
|
275
|
-
if ($segment.Count -le $script:FeatureFolderSegmentIndex) {
|
|
276
|
-
return $true
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
# Every segment up to and including the feature-folder name must be a literal
|
|
280
|
-
# for the claim to resolve to exactly one folder.
|
|
281
|
-
for ($index = 0; $index -le $script:FeatureFolderSegmentIndex; $index++) {
|
|
282
|
-
if ($segment[$index].IndexOf('*') -ge 0) {
|
|
283
|
-
return $true
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
return $false
|
|
288
|
-
}
|
|
289
|
-
|
|
290
240
|
function Get-PathTokenKind {
|
|
291
241
|
<#
|
|
292
242
|
.SYNOPSIS
|
|
@@ -300,6 +250,13 @@ function Get-PathTokenKind {
|
|
|
300
250
|
drive. Acceptance then requires one of the two documented shape rules, a
|
|
301
251
|
known top-level segment or a recognized final extension.
|
|
302
252
|
|
|
253
|
+
A token carrying any configured placeholder or interpolation marker is
|
|
254
|
+
rejected wherever the marker sits, because it documents a shape rather
|
|
255
|
+
than naming a file (issue #502). The rejection is silent and returns the
|
|
256
|
+
same null value the sibling rejections return: there is no diagnostic
|
|
257
|
+
channel and no finding rule, because a shape citation is not an error on
|
|
258
|
+
the author's part and reporting one would fire on almost every plan.
|
|
259
|
+
|
|
303
260
|
.PARAMETER Token
|
|
304
261
|
A single whitespace-free inline-code token.
|
|
305
262
|
|
|
@@ -337,6 +294,22 @@ function Get-PathTokenKind {
|
|
|
337
294
|
}
|
|
338
295
|
}
|
|
339
296
|
|
|
297
|
+
# A token carrying a placeholder or interpolation marker documents a shape
|
|
298
|
+
# rather than naming a file, so it is not a write claim (issue #502).
|
|
299
|
+
#
|
|
300
|
+
# Ordering, both directions. This runs AFTER the root-surface loop because
|
|
301
|
+
# that loop is exact ordinal equality against a configured surface name: a
|
|
302
|
+
# configured surface cannot contain a marker, so the two tests can never
|
|
303
|
+
# disagree, and putting the cheaper marker scan first would only add work to
|
|
304
|
+
# the common accepted case. It runs BEFORE the separator guard because a
|
|
305
|
+
# marker-bearing token frequently does carry a separator and would otherwise
|
|
306
|
+
# sail past that guard and reach the extension rule, which accepts it: the
|
|
307
|
+
# dominant corpus shape is an angle-bracketed leading segment followed by a
|
|
308
|
+
# real .md tail, and that is exactly the token this guard exists to reject.
|
|
309
|
+
if (Test-PlaceholderMarker -Token $Token) {
|
|
310
|
+
return $null
|
|
311
|
+
}
|
|
312
|
+
|
|
340
313
|
$separatorIndex = $Token.IndexOf('/')
|
|
341
314
|
if ($separatorIndex -lt 0 -or $separatorIndex -eq 0) {
|
|
342
315
|
return $null
|
|
@@ -492,6 +465,7 @@ Export-ModuleMember -Function `
|
|
|
492
465
|
ConvertTo-NormalizedLine, `
|
|
493
466
|
Get-PlanLineScan, `
|
|
494
467
|
Get-InlineCodeToken, `
|
|
468
|
+
Test-PlaceholderMarker, `
|
|
495
469
|
Test-MultipleFeatureFolderSpan, `
|
|
496
470
|
Get-PathTokenKind, `
|
|
497
471
|
Get-PathFromLine, `
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Blast-radius token-shape predicates, ported from the Python reference.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Destination-runtime PowerShell port of
|
|
7
|
+
scripts/dev_tools/_blast_radius_token_shapes.py. Holds the pure,
|
|
8
|
+
context-free shape tests that reject an inline-code token before
|
|
9
|
+
Get-PathTokenKind can record it as a repository path. A token can look like
|
|
10
|
+
a path and still name no file: a placeholder or interpolation marker makes it
|
|
11
|
+
a command or artifact shape, and a corpus-wide documentation glob makes it a
|
|
12
|
+
cross-corpus claim. Neither is evidence that a work item will write anything.
|
|
13
|
+
|
|
14
|
+
Test-PlaceholderMarker is new in issue #502.
|
|
15
|
+
Test-MultipleFeatureFolderSpan was relocated here from
|
|
16
|
+
BlastRadiusExtraction.psm1 in the same change, and the two module-scoped
|
|
17
|
+
documentation-corpus variables it reads travelled with it because $script:
|
|
18
|
+
scope is per module. The relocation exists because the extraction module had
|
|
19
|
+
two lines of headroom against the 500-line limit when the marker guard was
|
|
20
|
+
added, so an in-place guard was arithmetically impossible.
|
|
21
|
+
|
|
22
|
+
The Python module remains the authoritative reference implementation. This
|
|
23
|
+
module is a LEAF: it imports no sibling blast-radius module, so the
|
|
24
|
+
extraction module can import it with no possibility of a cycle. That
|
|
25
|
+
constraint is why the predicate does not live in BlastRadiusNormalization.psm1,
|
|
26
|
+
which already imports the extraction module.
|
|
27
|
+
|
|
28
|
+
Every function is pure: no filesystem, subprocess, network, or wall-clock
|
|
29
|
+
access, and no input is mutated.
|
|
30
|
+
|
|
31
|
+
Parity notes for maintainers:
|
|
32
|
+
- The marker array is character-identical to PLACEHOLDER_MARKERS in
|
|
33
|
+
scripts/dev_tools/_blast_radius_token_shapes.py and to the tuple of the
|
|
34
|
+
same name in scripts/dev_tools/plan_gate_coverage.py, whose origin is
|
|
35
|
+
the checkable-literal placeholder guard recorded in
|
|
36
|
+
.claude/rules/plan-acceptance-gates.md. The marker set is a module
|
|
37
|
+
constant, not a truth-table key: it describes what a path can never
|
|
38
|
+
contain rather than a policy a repository could tune.
|
|
39
|
+
- Every marker literal is single-quoted, and the two dollar forms are
|
|
40
|
+
built by character concatenation. A double-quoted PowerShell string
|
|
41
|
+
expands the subexpression form and the delimited-variable form, so a
|
|
42
|
+
double-quoted marker literal would silently define a DIFFERENT
|
|
43
|
+
vocabulary than the Python reference and the parity would fail on
|
|
44
|
+
exactly the two members that matter most.
|
|
45
|
+
- Substring search uses [System.StringComparison]::Ordinal so the result
|
|
46
|
+
is culture-independent and matches Python's byte-wise 'in' operator.
|
|
47
|
+
- Both predicates are total on every string, including the empty string, a
|
|
48
|
+
token consisting only of a marker, and a bare bracket pair. Neither
|
|
49
|
+
throws for any input, because the classifier that calls them runs over
|
|
50
|
+
every inline-code span in a document and a throw would abort an entire
|
|
51
|
+
derivation over one stray span.
|
|
52
|
+
#>
|
|
53
|
+
|
|
54
|
+
Set-StrictMode -Version Latest
|
|
55
|
+
|
|
56
|
+
# Placeholder and interpolation markers. A token carrying any of these was
|
|
57
|
+
# written to document a shape, not to name a file, so it can never be a write
|
|
58
|
+
# claim.
|
|
59
|
+
#
|
|
60
|
+
# The angle brackets are the dominant corpus shape and are also the strongest
|
|
61
|
+
# case: Windows forbids both characters in a filename outright, so an
|
|
62
|
+
# angle-bracketed token cannot name a file on the platform this repository is
|
|
63
|
+
# developed on. The two dollar forms are shell and PowerShell interpolation, and
|
|
64
|
+
# the percent form is the Windows shell's environment-variable syntax; each
|
|
65
|
+
# resolves at run time to text that is not in the token.
|
|
66
|
+
#
|
|
67
|
+
# The two dollar forms are assembled from single characters deliberately. Written
|
|
68
|
+
# as one single-quoted literal they would be correct, but assembling them makes
|
|
69
|
+
# the intent explicit at the definition site and removes any question of what a
|
|
70
|
+
# future edit to the quoting style would do.
|
|
71
|
+
$script:PlaceholderMarker = [string[]]@(
|
|
72
|
+
'<',
|
|
73
|
+
'>',
|
|
74
|
+
'$' + '{',
|
|
75
|
+
'$' + '(',
|
|
76
|
+
'%'
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Documentation-corpus root and the index, counted after that prefix, of the
|
|
80
|
+
# segment that names one feature folder. A glob whose wildcard reaches this
|
|
81
|
+
# segment or any earlier one claims every feature folder in the corpus.
|
|
82
|
+
$script:FeatureCorpusPrefix = 'docs/features/'
|
|
83
|
+
$script:FeatureFolderSegmentIndex = 1
|
|
84
|
+
|
|
85
|
+
function Test-PlaceholderMarker {
|
|
86
|
+
<#
|
|
87
|
+
.SYNOPSIS
|
|
88
|
+
Report whether a token carries a placeholder or interpolation marker.
|
|
89
|
+
|
|
90
|
+
.DESCRIPTION
|
|
91
|
+
Port of contains_placeholder_marker. A marker-bearing token documents a
|
|
92
|
+
shape rather than naming a file. Two work items that cite the same
|
|
93
|
+
mandated artifact shape therefore acquired a path-level conflict edge on
|
|
94
|
+
a string that resolves to nothing, which made thematically unrelated
|
|
95
|
+
items contend and serialized runs that had no reason to serialize
|
|
96
|
+
(issue #502).
|
|
97
|
+
|
|
98
|
+
The test is a plain substring scan over a fixed vocabulary, deliberately
|
|
99
|
+
context-free: it needs no repository lookup, no configuration, and no
|
|
100
|
+
knowledge of which segment the marker sits in. A marker anywhere in the
|
|
101
|
+
token is disqualifying, including in the filename position, because an
|
|
102
|
+
interpolated filename is as unresolvable as an interpolated directory.
|
|
103
|
+
|
|
104
|
+
.PARAMETER Token
|
|
105
|
+
A single whitespace-free inline-code token. The empty string is accepted
|
|
106
|
+
and reports false.
|
|
107
|
+
|
|
108
|
+
.OUTPUTS
|
|
109
|
+
System.Boolean. True when any configured marker appears anywhere in the
|
|
110
|
+
token, otherwise false.
|
|
111
|
+
#>
|
|
112
|
+
[CmdletBinding()]
|
|
113
|
+
[OutputType([bool])]
|
|
114
|
+
param(
|
|
115
|
+
[Parameter(Mandatory = $true)]
|
|
116
|
+
[AllowEmptyString()]
|
|
117
|
+
[string] $Token
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Ordinal comparison keeps the result culture-independent and byte-wise, so
|
|
121
|
+
# it agrees with Python's 'in' operator on every input.
|
|
122
|
+
foreach ($marker in $script:PlaceholderMarker) {
|
|
123
|
+
if ($Token.IndexOf($marker, [System.StringComparison]::Ordinal) -ge 0) {
|
|
124
|
+
return $true
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return $false
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function Test-MultipleFeatureFolderSpan {
|
|
132
|
+
<#
|
|
133
|
+
.SYNOPSIS
|
|
134
|
+
Report whether a glob claims more than one documentation feature folder.
|
|
135
|
+
|
|
136
|
+
.DESCRIPTION
|
|
137
|
+
Port of spans_multiple_feature_folders. The documentation corpus is laid
|
|
138
|
+
out as docs/features/<bucket>/<feature-folder>/..., so a glob whose
|
|
139
|
+
wildcard occupies or truncates the feature-folder segment claims every
|
|
140
|
+
feature folder in the corpus. That made two unrelated work items contend
|
|
141
|
+
purely because both wrote documentation (issue #489). A glob carrying a
|
|
142
|
+
complete, wildcard-free feature-folder segment claims one folder and is
|
|
143
|
+
retained.
|
|
144
|
+
|
|
145
|
+
.PARAMETER Token
|
|
146
|
+
A wildcard-bearing token already accepted by the shape rules of
|
|
147
|
+
Get-PathTokenKind.
|
|
148
|
+
|
|
149
|
+
.OUTPUTS
|
|
150
|
+
System.Boolean. True when the token is rooted in the documentation corpus
|
|
151
|
+
and its wildcard reaches the feature-folder segment or any earlier one.
|
|
152
|
+
#>
|
|
153
|
+
[CmdletBinding()]
|
|
154
|
+
[OutputType([bool])]
|
|
155
|
+
param(
|
|
156
|
+
[Parameter(Mandatory = $true)]
|
|
157
|
+
[AllowEmptyString()]
|
|
158
|
+
[string] $Token
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
if (-not $Token.StartsWith($script:FeatureCorpusPrefix,
|
|
162
|
+
[System.StringComparison]::Ordinal)) {
|
|
163
|
+
return $false
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
$segment = @($Token.Substring($script:FeatureCorpusPrefix.Length) -split '/')
|
|
167
|
+
|
|
168
|
+
# A token that stops at or before the feature-folder segment has had that
|
|
169
|
+
# segment truncated away by the wildcard, so it spans the whole corpus.
|
|
170
|
+
if ($segment.Count -le $script:FeatureFolderSegmentIndex) {
|
|
171
|
+
return $true
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Every segment up to and including the feature-folder name must be a literal
|
|
175
|
+
# for the claim to resolve to exactly one folder.
|
|
176
|
+
for ($index = 0; $index -le $script:FeatureFolderSegmentIndex; $index++) {
|
|
177
|
+
if ($segment[$index].IndexOf('*') -ge 0) {
|
|
178
|
+
return $true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return $false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Export-ModuleMember -Function `
|
|
186
|
+
Test-PlaceholderMarker, `
|
|
187
|
+
Test-MultipleFeatureFolderSpan
|
|
@@ -82,6 +82,22 @@ These invariants apply only when a caller passes `require_model_routing=True` an
|
|
|
82
82
|
|
|
83
83
|
The completion hook (`.claude/hooks/validate-orchestrator-output.ps1`) passes `--require-model-routing` alongside `--require-complete` and surfaces a gate failure as the `MODEL_ROUTING_BLOCKED:` block reason. The PreToolUse deterrent (`.claude/hooks/enforce-model-routing-receipt.ps1`) performs presence-only gating before a delegation. The MCP TypeScript surface performs the existence check only (delegated-agent set ⊆ routing-receipt-agent set); the Python validator remains authoritative for per-receipt correctness.
|
|
84
84
|
|
|
85
|
+
## Epic Launch-Binding Activation Scope
|
|
86
|
+
|
|
87
|
+
This section governs when the epic child launch-binding gate runs. It exists because the gate admitted the generic `require_complete` flag into an otherwise Codex-specific activation set, which made Codex-only launch evidence a universal completion requirement (issue #524).
|
|
88
|
+
|
|
89
|
+
The evidence the gate demands — `launch_receipt_path`, `launch_status_path`, `delegation_receipt`, and `model_routing_receipt` on each feature — has exactly one production writer, `.codex/scripts/launch-epic-child-wave.ps1`, on the Codex runtime. No Claude-runtime producer writes it, so an epic executed on the Claude runtime could never satisfy an unconditional gate.
|
|
90
|
+
|
|
91
|
+
1. **Unconditional under the two Codex enforcement flags.** When a caller passes `require_codex_model_routing` or `require_codex_topology`, launch-binding validation runs for every feature exactly as before, including the existing `skip_not_started` filter. Behaviour under either Codex flag is unchanged.
|
|
92
|
+
|
|
93
|
+
2. **Key-gated per feature under `require_complete` alone.** When `require_complete` is the only flag passed, the gate validates a feature only when that feature carries `launch_receipt_path` or `launch_status_path`. A feature carrying neither key is skipped and contributes zero errors.
|
|
94
|
+
|
|
95
|
+
3. **The presence test is deliberately either-key, so a partial binding still fails.** Presence means key membership, not value truthiness: a key present with an empty or null value still arms the gate. A feature carrying one launch path key and not the other is therefore validated, and the absent key produces its error. The test is never "both keys"; that spelling would let a half-written binding pass unexamined, and the partial-binding failure is the property that distinguishes this scope rule from deleting the gate.
|
|
96
|
+
|
|
97
|
+
The rest of the completion gate is unchanged. An epic whose feature is not merged, or whose `epic_merge_pr.merge_commit_sha` is missing or empty, still fails under `require_complete`.
|
|
98
|
+
|
|
99
|
+
Enforcement is validator logic plus this prose, never an imported JSON Schema. The activation scope lives in `scripts/dev_tools/_epic_orchestrator_state_launch_binding.py`, and the TypeScript parity port at `extensions/drm-copilot/src/lib/validate/epic-orchestrator-state-launch-binding.ts` reproduces it with byte-identical error strings. No schema file is authored, imported, or read for it.
|
|
100
|
+
|
|
85
101
|
## Enforcement
|
|
86
102
|
|
|
87
103
|
- `scripts/dev_tools/validate_orchestrator_state.py` appends one error per violated invariant when a `remediation_loop` is present, using the existing validator message style (literal, checkpoint-context prefixed). The validator returns a list of error strings and does not mutate its input.
|
|
@@ -233,11 +233,69 @@ Three constraints bound the mandate-read exclusion:
|
|
|
233
233
|
detection compares the declared radius against the paths a diff actually touched, so an item that
|
|
234
234
|
wrote an excluded path is caught against observed evidence rather than against prose.
|
|
235
235
|
|
|
236
|
-
The extractor additionally rejects
|
|
236
|
+
The extractor additionally rejects four token shapes that were never write claims: a wildcard-free
|
|
237
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,
|
|
239
|
-
letter
|
|
240
|
-
longer satisfies the shape rules.
|
|
238
|
+
wildcard occupies or truncates the feature-folder segment, a contract token carrying no ASCII
|
|
239
|
+
letter, and a token containing a placeholder or interpolation marker. `artifacts/` is not a known
|
|
240
|
+
top-level segment, so a bare `artifacts/**` subtree claim no longer satisfies the shape rules.
|
|
241
|
+
|
|
242
|
+
### Placeholder-shape rejection (issue #502)
|
|
243
|
+
|
|
244
|
+
The fourth shape is a token containing any member of the marker set
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
< > ${ $( %
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The set is not a configuration key and is not read from `config/blast-radius.json`. It originates in
|
|
251
|
+
the checkable-literal placeholder guard defined in `.claude/rules/plan-acceptance-gates.md`, which
|
|
252
|
+
uses the identical five markers to decide that a plan operand documents a command *shape* rather
|
|
253
|
+
than stating a real assertion. Both subsystems answer the same question about the same text, so the
|
|
254
|
+
two vocabularies are pinned equal by test rather than left to convention.
|
|
255
|
+
|
|
256
|
+
**A marker-bearing token never matches a tracked path.** A placeholder or interpolation form
|
|
257
|
+
resolves at run time to text that is not in the token, so the token as written names nothing. For
|
|
258
|
+
the two angle brackets the claim is stronger than a heuristic: Windows forbids both characters in a
|
|
259
|
+
filename outright, so an angle-bracketed token cannot name a file on the platform this repository is
|
|
260
|
+
developed on. Admitting such a token recorded a `paths` entry that no diff could ever touch, and two
|
|
261
|
+
items citing the identical shape then acquired a `path_overlap` edge on a string that resolves to
|
|
262
|
+
nothing.
|
|
263
|
+
|
|
264
|
+
**The dominant token is a mandated artifact shape, which is why the exposure was corpus-wide rather
|
|
265
|
+
than incidental.** Every agent in this repository is instructed to write its evidence to the
|
|
266
|
+
canonical scheme defined in `.claude/skills/evidence-and-timestamp-conventions/SKILL.md`, and that
|
|
267
|
+
scheme is non-overridable, so a well-formed plan quotes the same feature-relative artifact shape
|
|
268
|
+
that every other well-formed plan quotes. The shape is therefore the most widely shared token in the
|
|
269
|
+
corpus, and admitting it made compliance with the evidence-path scheme a source of contention. The
|
|
270
|
+
same reasoning applies to the feature-document shapes and to the session-keyed state-file shape.
|
|
271
|
+
|
|
272
|
+
**The planner remains obliged to enumerate a genuine write explicitly.** This rejection describes a
|
|
273
|
+
plan that documents a shape, not a permanent ban on the paths a shape resembles. When an item's plan
|
|
274
|
+
will actually write a path it expressed as a shape, the planner appends that exact concrete path to
|
|
275
|
+
the declared radius after normalization. This is the same obligation constraint 1 of the
|
|
276
|
+
mandate-read exclusion imposes, and `detect_escaped_paths` is the same backstop: drift detection
|
|
277
|
+
compares the declared radius against the paths a diff actually touched, so an item that wrote a path
|
|
278
|
+
it expressed only as a shape is caught against observed evidence rather than against prose.
|
|
279
|
+
|
|
280
|
+
**Accepted fail-open trade.** The rejection runs inside the classifier, upstream of shared-surface
|
|
281
|
+
resolution, so a marker-bearing token whose shape matches a configured `shared_surface_globs`
|
|
282
|
+
pattern is dropped before it can be reported as a touched shared surface. The trade is inherent to
|
|
283
|
+
that placement: a guard downstream of surface resolution would leave the token in `paths` and
|
|
284
|
+
reintroduce the path-level false edge it exists to remove. Corpus exposure was measured empty — no
|
|
285
|
+
plan in the 58-plan corpus examined for issue #502 cited a marker-bearing token whose shape matched a
|
|
286
|
+
configured shared-surface glob — and the planner obligation above is what keeps a genuine write
|
|
287
|
+
visible. A later change that widens the marker set must re-take that measurement.
|
|
288
|
+
|
|
289
|
+
**Known residual: the whitespace split.** Extraction harvests whitespace-free inline-code tokens, so
|
|
290
|
+
a placeholder form written with internal whitespace is split into fragments before the marker test
|
|
291
|
+
ever runs. Each fragment is then judged on its own shape and is normally rejected for an unrelated
|
|
292
|
+
reason, most often for carrying no separator. The residual is therefore benign in the accepting
|
|
293
|
+
direction but is recorded here because it means the rejection is not a complete guard against every
|
|
294
|
+
way a shape can be written; it is a guard against the whitespace-free forms the extractor actually
|
|
295
|
+
admits.
|
|
296
|
+
|
|
297
|
+
Enforcement of this rejection is prose plus validator logic, exactly as for the three shapes above.
|
|
298
|
+
No JSON Schema is authored, imported, or read for it, and `config/blast-radius.json` gains no key.
|
|
241
299
|
|
|
242
300
|
### Module-map granularity criterion
|
|
243
301
|
|
|
@@ -173,6 +173,33 @@ integration-to-main PR.
|
|
|
173
173
|
The `## Invocation Prompt` section is the exact text the user replays (from the main session,
|
|
174
174
|
never from an `orchestrator` agent) to launch execution.
|
|
175
175
|
|
|
176
|
+
### Integration Commit Form (issue #539)
|
|
177
|
+
|
|
178
|
+
The epic planner's own version-control operations — committing the epic manifest, the fanned-in
|
|
179
|
+
child feature folders and approved plans, and the durable kickoff copy — are orchestration
|
|
180
|
+
bookkeeping, not implementation. The preimplementation gate
|
|
181
|
+
(`.claude/hooks/enforce-orchestration-preimplementation-gate.ps1`) exempts them only when the
|
|
182
|
+
invocation is **pathspec-bearing**: every staging or integration invocation must name at least one
|
|
183
|
+
explicit path operand, and every operand must resolve inside one of the five exempt
|
|
184
|
+
orchestration-bookkeeping trees:
|
|
185
|
+
|
|
186
|
+
- `docs/features/epics/`
|
|
187
|
+
- `docs/features/parallel/`
|
|
188
|
+
- `docs/features/active/`
|
|
189
|
+
- `docs/features/potential/`
|
|
190
|
+
- `artifacts/orchestration/`
|
|
191
|
+
|
|
192
|
+
Use one of the two pathspec-bearing spellings:
|
|
193
|
+
|
|
194
|
+
- the message option followed by a double-dash separator and then the exempt path operands, or
|
|
195
|
+
- the exempt path operands named directly before the message option.
|
|
196
|
+
|
|
197
|
+
A pathless integration invocation — a message option with no path operand — is denied (D4 row 4),
|
|
198
|
+
as are whole-tree operands, tree-wide flags, pathspec-from-file options, history-rewriting or
|
|
199
|
+
content-widening options, and any operand that resolves outside the five exempt trees. Mixing one
|
|
200
|
+
exempt operand with one production operand denies the whole invocation. Name each exempt path
|
|
201
|
+
explicitly; the exemption is allow-side only and every parse ambiguity denies.
|
|
202
|
+
|
|
176
203
|
## Checkpoint Handling
|
|
177
204
|
|
|
178
205
|
Persist `artifacts/orchestration/epic-planner-state.json` after every completed step with the
|
|
@@ -522,6 +522,34 @@ Validate the artifact through `mcp__drm-copilot__validate_orchestration_artifact
|
|
|
522
522
|
`artifact_type: "parallel-kickoff"`. That artifact type dispatches to
|
|
523
523
|
`scripts/dev_tools/parallel_kickoff_contract.py`, which this feature delivers.
|
|
524
524
|
|
|
525
|
+
### Integration Commit Form (issue #539)
|
|
526
|
+
|
|
527
|
+
The parallel planner's own version-control operations — committing the run manifest
|
|
528
|
+
`docs/features/parallel/<slug>/parallel.md`, each item's prepared feature folder and approved
|
|
529
|
+
plan-path, and the durable kickoff copy `docs/features/parallel/<slug>/parallel-kickoff.md` — are
|
|
530
|
+
orchestration bookkeeping, not implementation. The preimplementation gate
|
|
531
|
+
(`.claude/hooks/enforce-orchestration-preimplementation-gate.ps1`) exempts them only when the
|
|
532
|
+
invocation is **pathspec-bearing**: every staging or integration invocation must name at least one
|
|
533
|
+
explicit path operand, and every operand must resolve inside one of the five exempt
|
|
534
|
+
orchestration-bookkeeping trees:
|
|
535
|
+
|
|
536
|
+
- `docs/features/epics/`
|
|
537
|
+
- `docs/features/parallel/`
|
|
538
|
+
- `docs/features/active/`
|
|
539
|
+
- `docs/features/potential/`
|
|
540
|
+
- `artifacts/orchestration/`
|
|
541
|
+
|
|
542
|
+
Use one of the two pathspec-bearing spellings:
|
|
543
|
+
|
|
544
|
+
- the message option followed by a double-dash separator and then the exempt path operands, or
|
|
545
|
+
- the exempt path operands named directly before the message option.
|
|
546
|
+
|
|
547
|
+
A pathless integration invocation — a message option with no path operand — is denied (D4 row 4),
|
|
548
|
+
as are whole-tree operands, tree-wide flags, pathspec-from-file options, history-rewriting or
|
|
549
|
+
content-widening options, and any operand that resolves outside the five exempt trees. Mixing one
|
|
550
|
+
exempt operand with one production operand denies the whole invocation. Name each exempt path
|
|
551
|
+
explicitly; the exemption is allow-side only and every parse ambiguity denies.
|
|
552
|
+
|
|
525
553
|
## Completion Report
|
|
526
554
|
|
|
527
555
|
The final report to the operator must include:
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
},
|
|
211
211
|
"model_budget": {
|
|
212
212
|
"description": "Session-level model budget. fable_policy is a three-way switch controlling whether the fable tier is disabled (removed and clamped to opus), available (used as-is), or preferred (applies the preferred_overlay).",
|
|
213
|
-
"fable_policy": "
|
|
213
|
+
"fable_policy": "available"
|
|
214
214
|
},
|
|
215
215
|
"codex_topology_policy": {
|
|
216
216
|
"description": "Codex-native production-file-count routing. This axis selects the initial implementation topology independently from C1-C4 model selection.",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
".claude/hooks/enforce-feature-folder-order.ps1",
|
|
34
34
|
".claude/hooks/enforce-model-routing-receipt.ps1",
|
|
35
35
|
".claude/hooks/enforce-orchestration-preimplementation-gate.ps1",
|
|
36
|
+
".claude/hooks/enforce-orchestration-preimplementation-gate-helpers.ps1",
|
|
36
37
|
".claude/hooks/enforce-parallel-abandon-gate.ps1",
|
|
37
38
|
".claude/hooks/enforce-parallel-cohort-barrier.ps1",
|
|
38
39
|
".claude/hooks/enforce-parallel-cohort-barrier-helpers.ps1",
|
|
@@ -129,6 +130,7 @@
|
|
|
129
130
|
".claude/lib/blast-radius/BlastRadiusValidation.psm1",
|
|
130
131
|
".claude/lib/blast-radius/BlastRadius.psm1",
|
|
131
132
|
".claude/lib/blast-radius/BlastRadiusNormalization.psm1",
|
|
133
|
+
".claude/lib/blast-radius/BlastRadiusTokenShape.psm1",
|
|
132
134
|
".claude/rules/parallel-orchestration.md",
|
|
133
135
|
".claude/rules/shell.md",
|
|
134
136
|
".claude/lib/bash/compute-cohorts.sh",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: csharp-change-budget-router
|
|
3
|
-
description: Budget-first routing contract for C# work: estimate production-file scope, choose small vs large path, enforce orchestration-first routing for larger changes, and use the VS Code extension command surface for promotion lifecycle steps when available.
|
|
3
|
+
description: 'Budget-first routing contract for C# work: estimate production-file scope, choose small vs large path, enforce orchestration-first routing for larger changes, and use the VS Code extension command surface for promotion lifecycle steps when available.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# C# Change Budget Router
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: csharp-qa-gate
|
|
3
|
-
description: Final QA gate for C# changes.
|
|
3
|
+
description: Final QA gate for C# changes. Runs CSharpier, .NET analyzers, nullable analysis, and MSTest; compares a captured baseline, enforces zero-regression deltas, and produces the required reporting block before completion.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# C# QA Gate
|
|
@@ -161,7 +161,7 @@ As each preparation finishes:
|
|
|
161
161
|
3. Backfill `issue_num` and `feature_folder` in `epic.md`.
|
|
162
162
|
4. Record `preparation_status: "prepared"`, `research_path`, `plan_path`,
|
|
163
163
|
`preflight_evidence_path`, and `preflight_status: "PREFLIGHT: ALL CLEAR"` in the planner
|
|
164
|
-
checkpoint. `research_path` must be under `
|
|
164
|
+
checkpoint. `research_path` must be under `docs/features/<feature>/research/` inside the feature folder.
|
|
165
165
|
Each child references its immutable receipt and the shared `wave.<wave_id>.status.json` path.
|
|
166
166
|
5. Remove the worktree only after its preparation branch is merged.
|
|
167
167
|
|
|
@@ -31,7 +31,8 @@ The following sub-paths under `artifacts/` are FORBIDDEN for evidence output:
|
|
|
31
31
|
|
|
32
32
|
Allowed `artifacts/` sub-paths (non-evidence orchestration use only):
|
|
33
33
|
- `artifacts/orchestration/`
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
Research output is not an `artifacts/` sub-path. Use `docs/features/<feature>/research/` for feature-associated research or `docs/research/` for one-off research.
|
|
35
36
|
|
|
36
37
|
No delegation prompt, plan task, or upstream agent instruction may override this scheme. If a caller supplies a non-canonical path, the receiving agent MUST reject it, substitute the canonical path, and record `EVIDENCE_LOCATION_OVERRIDE_REJECTED: <supplied path> replaced with <canonical path>`.
|
|
37
38
|
|
package/resources/codex-and-agents-customizations/.agents/skills/invoke-csharp-engineer/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: invoke-csharp-engineer
|
|
3
|
-
description: Invoke the csharp-typed-engineer worker to design, implement, and verify C# changes within typed repository boundaries. Applies CSharpier
|
|
3
|
+
description: Invoke the csharp-typed-engineer worker to design, implement, and verify C# changes within typed repository boundaries. Applies CSharpier, .NET analyzers, nullable analysis, and MSTest with the one-to-three production-file small-path budget and zero-regression quality gates.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Implement C# Skill
|
package/resources/codex-and-agents-customizations/.agents/skills/invoke-powershell-engineer/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: invoke-powershell-engineer
|
|
3
|
-
description: Invoke the powershell-typed-engineer worker to design, implement, and verify PowerShell changes within typed repository boundaries. Applies PoshQC
|
|
3
|
+
description: Invoke the powershell-typed-engineer worker to design, implement, and verify PowerShell changes within typed repository boundaries. Applies PoshQC formatting, analysis, and testing with a one-to-two production-file direct-mode budget, a three-production plus three-test batch cap, and zero-regression quality gates.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Implement PowerShell Skill
|
package/resources/codex-and-agents-customizations/.agents/skills/invoke-python-engineer/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: invoke-python-engineer
|
|
3
|
-
description: Invoke the python-typed-engineer worker to design, implement, and verify Python changes within typed repository boundaries. Applies Black
|
|
3
|
+
description: Invoke the python-typed-engineer worker to design, implement, and verify Python changes within typed repository boundaries. Applies Black, Ruff, Pyright, and Pytest with a three-production plus three-test per-batch budget and zero-regression quality gates.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Implement Python Skill
|