@danmoisan/drm-copilot-mcp 1.0.7 → 1.0.9
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 +82 -8
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agents/atomic-executor.md +1 -0
- package/resources/claude-customizations/.claude/agents/atomic-planner.md +1 -0
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -0
- package/resources/claude-customizations/.claude/agents/epic-orchestrator.md +1 -0
- package/resources/claude-customizations/.claude/agents/epic-review.md +1 -0
- package/resources/claude-customizations/.claude/agents/feature-review.md +1 -0
- package/resources/claude-customizations/.claude/agents/orchestrator.md +13 -0
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -0
- package/resources/claude-customizations/.claude/agents/prd-feature.md +1 -0
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -0
- package/resources/claude-customizations/.claude/agents/staged-review.md +1 -0
- package/resources/claude-customizations/.claude/agents/status-updater.md +1 -0
- package/resources/claude-customizations/.claude/agents/typescript-engineer.md +1 -0
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +182 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +9 -1
- package/resources/claude-customizations/.claude/lib/model-routing/ModelRouting.psm1 +209 -0
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +17 -0
- package/resources/claude-customizations/.claude/settings.json +4 -0
- package/resources/claude-customizations/.claude/skills/epic-orchestrate/SKILL.md +3 -3
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +22 -3
- package/resources/claude-customizations/pack-manifests/core.json +3 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +8 -2
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrate/SKILL.md +18 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +13 -0
- package/resources/codex-and-agents-customizations/.codex/agents/orchestrator.toml +15 -14
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-consistency.ps1 +144 -28
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-completion-helpers.ps1 +163 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Model-routing reference formulas for the orchestrator, ported from the Python references.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Provides the destination-runtime PowerShell ports of the two self-contained,
|
|
7
|
+
pure model-routing formulas that the `orchestrate` skill instructs the
|
|
8
|
+
orchestrator to run:
|
|
9
|
+
|
|
10
|
+
- Get-ComplexityFloor port of scripts/dev_tools/compute_complexity_floor.py
|
|
11
|
+
- Resolve-DelegationModel port of scripts/dev_tools/resolve_delegation_model.py
|
|
12
|
+
|
|
13
|
+
Both functions are pure and deterministic: they read no file at runtime and
|
|
14
|
+
encode only the fixed band ordering, the base complexity-to-model table, the
|
|
15
|
+
preferred overlay, and the disabled-mode clamp as module-scope constants.
|
|
16
|
+
Those literals are pinned to config/orchestration-routing.json (model_policy /
|
|
17
|
+
model_budget) by a static config-parity Pester test, and the Python modules
|
|
18
|
+
remain the validator's authoritative reference. This module is one half of a
|
|
19
|
+
two-language mirror; it never imports validator logic.
|
|
20
|
+
#>
|
|
21
|
+
|
|
22
|
+
Set-StrictMode -Version Latest
|
|
23
|
+
|
|
24
|
+
# The fixed complexity-band vocabulary, ordered from lowest to highest rigor.
|
|
25
|
+
# The array order defines "higher" and "lower" band comparisons used by the
|
|
26
|
+
# floor computation, mirroring BAND_ORDER in compute_complexity_floor.py.
|
|
27
|
+
$script:BAND_ORDER = @('C1', 'C2', 'C3', 'C4')
|
|
28
|
+
|
|
29
|
+
# The lowest band, returned when no floor signal is present (LOWEST_BAND).
|
|
30
|
+
$script:LOWEST_BAND = 'C1'
|
|
31
|
+
|
|
32
|
+
# Every present floor signal contributes this uniform candidate band, per the
|
|
33
|
+
# model_policy.complexity contract (each [floor] signal contributes C3).
|
|
34
|
+
$script:FLOOR_CANDIDATE_BAND = 'C3'
|
|
35
|
+
|
|
36
|
+
# Floors never exceed this ceiling; C4 is judgment-only and never floor-forced,
|
|
37
|
+
# so the computed floor is clamped to at most C3 (FLOOR_CEILING_BAND).
|
|
38
|
+
$script:FLOOR_CEILING_BAND = 'C3'
|
|
39
|
+
|
|
40
|
+
# The three session-level fable policies (model_budget.fable_policy).
|
|
41
|
+
$script:DISABLED_POLICY = 'disabled'
|
|
42
|
+
$script:PREFERRED_POLICY = 'preferred'
|
|
43
|
+
|
|
44
|
+
# The model tier removed from consideration under the disabled policy, the tier
|
|
45
|
+
# a disabled-mode fable cell clamps down to, and the recorded clamp reason.
|
|
46
|
+
$script:FABLE_MODEL = 'fable'
|
|
47
|
+
$script:DISABLED_CLAMP_MODEL = 'opus'
|
|
48
|
+
$script:DISABLED_CLAMP_REASON = 'fable_disabled'
|
|
49
|
+
|
|
50
|
+
# The base complexity-to-model table applied uniformly across delegated agents
|
|
51
|
+
# (BASE_COMPLEXITY_TO_MODEL). Pinned to model_policy.complexity_to_model.
|
|
52
|
+
$script:BASE_COMPLEXITY_TO_MODEL = @{
|
|
53
|
+
C1 = 'haiku'
|
|
54
|
+
C2 = 'sonnet'
|
|
55
|
+
C3 = 'opus'
|
|
56
|
+
C4 = 'fable'
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# The agents whose C3 cell the preferred overlay redirects to fable. No other
|
|
60
|
+
# agent and no other band is affected (PREFERRED_OVERLAY_AGENTS).
|
|
61
|
+
$script:PREFERRED_OVERLAY_AGENTS = @(
|
|
62
|
+
'atomic-planner',
|
|
63
|
+
'prd-feature',
|
|
64
|
+
'feature-review',
|
|
65
|
+
'task-researcher'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# The single band and target model the preferred overlay applies.
|
|
69
|
+
$script:PREFERRED_OVERLAY_BAND = 'C3'
|
|
70
|
+
$script:PREFERRED_OVERLAY_MODEL = 'fable'
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
function Get-ComplexityFloor {
|
|
74
|
+
<#
|
|
75
|
+
.SYNOPSIS
|
|
76
|
+
Compute the deterministic complexity-band floor from present floor signals.
|
|
77
|
+
|
|
78
|
+
.DESCRIPTION
|
|
79
|
+
Faithful PowerShell port of compute_complexity_floor
|
|
80
|
+
(scripts/dev_tools/compute_complexity_floor.py). Returns the deterministic
|
|
81
|
+
lower-bound complexity band implied by the set of present floor signals:
|
|
82
|
+
each present floor signal contributes a candidate band of C3, the floor is
|
|
83
|
+
the maximum triggered candidate band, and the floor never exceeds C3
|
|
84
|
+
(C4 is never floor-forced). With no floor signal present the floor is the
|
|
85
|
+
lowest band C1. The function is pure: it reads no file and does not mutate
|
|
86
|
+
its input, and the result is independent of input ordering.
|
|
87
|
+
|
|
88
|
+
.PARAMETER SignalsPresent
|
|
89
|
+
The names of the present signals flagged [floor] in the
|
|
90
|
+
model_policy.complexity catalog. Every element is treated as a triggered
|
|
91
|
+
floor signal contributing the candidate band C3. An empty collection means
|
|
92
|
+
no floor signal is present.
|
|
93
|
+
|
|
94
|
+
.OUTPUTS
|
|
95
|
+
System.String. The floor band: C1 when no floor signal is present,
|
|
96
|
+
otherwise the maximum triggered candidate band clamped to at most C3.
|
|
97
|
+
C4 is never returned.
|
|
98
|
+
#>
|
|
99
|
+
[CmdletBinding()]
|
|
100
|
+
[OutputType([string])]
|
|
101
|
+
param(
|
|
102
|
+
[Parameter(Mandatory = $true)]
|
|
103
|
+
[AllowEmptyCollection()]
|
|
104
|
+
[string[]] $SignalsPresent
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# With no present floor signal there is no candidate band to raise the floor
|
|
108
|
+
# above the lowest band, so the floor is C1 (mirrors the empty-input guard).
|
|
109
|
+
if (-not $SignalsPresent -or $SignalsPresent.Count -eq 0) {
|
|
110
|
+
return $script:LOWEST_BAND
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Each present floor signal contributes the uniform candidate band; the floor
|
|
114
|
+
# is the maximum triggered candidate rank across all of them. Because every
|
|
115
|
+
# signal contributes the same candidate band, the max equals that rank.
|
|
116
|
+
$candidateRank = $script:BAND_ORDER.IndexOf($script:FLOOR_CANDIDATE_BAND)
|
|
117
|
+
$highestRank = $candidateRank
|
|
118
|
+
|
|
119
|
+
# Clamp with the ceiling rank so the floor can never exceed C3; this is what
|
|
120
|
+
# keeps C4 from ever being floor-forced regardless of how many signals exist.
|
|
121
|
+
$ceilingRank = $script:BAND_ORDER.IndexOf($script:FLOOR_CEILING_BAND)
|
|
122
|
+
$floorRank = [Math]::Min($highestRank, $ceilingRank)
|
|
123
|
+
return $script:BAND_ORDER[$floorRank]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function Resolve-DelegationModel {
|
|
127
|
+
<#
|
|
128
|
+
.SYNOPSIS
|
|
129
|
+
Resolve the delegation model tier for an agent, band, and fable policy.
|
|
130
|
+
|
|
131
|
+
.DESCRIPTION
|
|
132
|
+
Faithful PowerShell port of resolve_delegation_model
|
|
133
|
+
(scripts/dev_tools/resolve_delegation_model.py). Applies the model_policy
|
|
134
|
+
selection formula to a single delegation: it computes the pre-clamp
|
|
135
|
+
table_model (the base complexity_to_model table plus any preferred overlay)
|
|
136
|
+
and the post-clamp model, recording the clamp provenance. The preferred
|
|
137
|
+
overlay redirects only the C3 cell to fable and only for the four overlay
|
|
138
|
+
agents; atomic-executor and pr-author C3 cells stay opus under every
|
|
139
|
+
policy. Under the disabled policy a fable table cell clamps to opus with
|
|
140
|
+
clamped_from = fable and clamp_reason = fable_disabled. The function is
|
|
141
|
+
pure: it reads no file and mutates no input.
|
|
142
|
+
|
|
143
|
+
.PARAMETER Agent
|
|
144
|
+
The target delegate agent name (for example atomic-planner). Only
|
|
145
|
+
participates in preferred-overlay eligibility.
|
|
146
|
+
|
|
147
|
+
.PARAMETER Band
|
|
148
|
+
The assessed complexity band, one of C1..C4. Used as the key into the
|
|
149
|
+
base complexity_to_model table. A band outside the table is the PowerShell
|
|
150
|
+
analog of the Python KeyError and causes a terminating error (throw).
|
|
151
|
+
|
|
152
|
+
.PARAMETER FablePolicy
|
|
153
|
+
The session fable policy, one of disabled, available, or preferred.
|
|
154
|
+
|
|
155
|
+
.OUTPUTS
|
|
156
|
+
System.Collections.Hashtable. A hashtable with keys table_model (the
|
|
157
|
+
pre-clamp table lookup, including any overlay), model (the post-clamp
|
|
158
|
+
result), clamped_from (fable when a clamp occurred, else $null), and
|
|
159
|
+
clamp_reason (fable_disabled when a clamp occurred, else $null).
|
|
160
|
+
#>
|
|
161
|
+
[CmdletBinding()]
|
|
162
|
+
[OutputType([hashtable])]
|
|
163
|
+
param(
|
|
164
|
+
[Parameter(Mandatory = $true)]
|
|
165
|
+
[string] $Agent,
|
|
166
|
+
[Parameter(Mandatory = $true)]
|
|
167
|
+
[string] $Band,
|
|
168
|
+
[Parameter(Mandatory = $true)]
|
|
169
|
+
[string] $FablePolicy
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# The preferred overlay redirects only the C3 cell to fable, and only for the
|
|
173
|
+
# overlay agents; every other case reads the base table unchanged. The three
|
|
174
|
+
# conditions (policy, agent membership, band) must all hold for the overlay.
|
|
175
|
+
if ($FablePolicy -eq $script:PREFERRED_POLICY -and
|
|
176
|
+
$script:PREFERRED_OVERLAY_AGENTS -contains $Agent -and
|
|
177
|
+
$Band -eq $script:PREFERRED_OVERLAY_BAND) {
|
|
178
|
+
$tableModel = $script:PREFERRED_OVERLAY_MODEL
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
# A band outside the base table is the PowerShell analog of the Python
|
|
182
|
+
# KeyError: fail fast rather than return a silently wrong value.
|
|
183
|
+
if (-not $script:BASE_COMPLEXITY_TO_MODEL.ContainsKey($Band)) {
|
|
184
|
+
throw "Unknown complexity band '$Band'; expected one of $($script:BAND_ORDER -join ', ')."
|
|
185
|
+
}
|
|
186
|
+
$tableModel = $script:BASE_COMPLEXITY_TO_MODEL[$Band]
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
# Under the disabled policy, fable is removed from consideration: a fable
|
|
190
|
+
# table cell clamps down to opus and records the clamp provenance.
|
|
191
|
+
if ($FablePolicy -eq $script:DISABLED_POLICY -and $tableModel -eq $script:FABLE_MODEL) {
|
|
192
|
+
return @{
|
|
193
|
+
table_model = $tableModel
|
|
194
|
+
model = $script:DISABLED_CLAMP_MODEL
|
|
195
|
+
clamped_from = $script:FABLE_MODEL
|
|
196
|
+
clamp_reason = $script:DISABLED_CLAMP_REASON
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
# No clamp applies: the resolved model is the table model verbatim.
|
|
201
|
+
return @{
|
|
202
|
+
table_model = $tableModel
|
|
203
|
+
model = $tableModel
|
|
204
|
+
clamped_from = $null
|
|
205
|
+
clamp_reason = $null
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
Export-ModuleMember -Function Get-ComplexityFloor, Resolve-DelegationModel
|
|
@@ -66,10 +66,27 @@ Each entry records one delegation with the shape `{ agent, phase, complexity_ban
|
|
|
66
66
|
|
|
67
67
|
The session `model_budget.fable_policy` switch is a three-way enum `disabled | available | preferred` defined in `config/orchestration-routing.json`, defaulting to `disabled`. It governs only the delegation model tier and is not a route input. `disabled` removes `fable` from the consideration set and clamps `fable` cells to `opus`; `available` applies the base `complexity_to_model` table as-is; `preferred` applies the `preferred_overlay` (which redirects only the C3 cell to `fable` for the overlay agents `atomic-planner`, `prd-feature`, `feature-review`, `task-researcher`) and leaves `atomic-executor` and `pr-author` C3 cells at `opus`. `route` is never an input to model selection.
|
|
68
68
|
|
|
69
|
+
## Require-Model-Routing Mode Scope and Backward Compatibility
|
|
70
|
+
|
|
71
|
+
The complexity-assessment and model-routing-receipt invariants above are key-gated: they run only when their key is present, so a checkpoint that omits both arrays passes at every stage. The `require_model_routing` mode adds an existence gate that closes that gap without changing the default behavior. It is an opt-in keyword on `validate_orchestrator_state_text(..., require_model_routing=False)` (CLI flag `--require-model-routing`; MCP parameter `require_model_routing`), defaulting off. Plain, `require_complete`, and `require_pr_creation_ready` calls are unaffected and produce byte-identical results.
|
|
72
|
+
|
|
73
|
+
## Invariants (require_model_routing mode)
|
|
74
|
+
|
|
75
|
+
These invariants apply only when a caller passes `require_model_routing=True` and the checkpoint records at least one delegation. A checkpoint with zero delegations (no well-formed `delegation_receipts[]` entry and a `next_step` that names no delegating agent) imposes no requirement, so genuinely old, delegation-free checkpoints stay valid.
|
|
76
|
+
|
|
77
|
+
1. **Required routing receipt once delegated.** Once the checkpoint records a delegation, the set of `model_routing_receipts[].agent` must be a superset of the delegated-agent set (each well-formed `delegation_receipts[].agent_name` plus a `next_step` that names a delegating agent). A delegated agent with no matching receipt is a violation. The delegating agent set excludes `orchestrator` (the caller, not a delegated subagent).
|
|
78
|
+
|
|
79
|
+
2. **Required complexity assessment per matched phase.** Each phase named by a routing receipt whose agent is in the delegated-agent set must have a `complexity_assessments[]` entry for that phase.
|
|
80
|
+
|
|
81
|
+
3. **Per-entry consistency reused, not reimplemented.** Present receipts and assessments must satisfy the model-routing-receipt and complexity-assessment invariants above; the gate reuses `_validate_model_routing_receipts` and `_validate_complexity_assessments` and never reimplements `compute_complexity_floor` or `resolve_delegation_model`. The gate logic lives in `scripts/dev_tools/_orchestrator_state_model_routing_gate.py`; enforcement is the Python validator, not an imported schema.
|
|
82
|
+
|
|
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
|
+
|
|
69
85
|
## Enforcement
|
|
70
86
|
|
|
71
87
|
- `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.
|
|
72
88
|
- `scripts/dev_tools/validate_orchestrator_state.py` likewise appends one error per violated `human_interaction` invariant when a `human_interaction` key is present, using the same literal, checkpoint-context-prefixed message style. The check does not import or read any schema file.
|
|
73
89
|
- `scripts/dev_tools/validate_orchestrator_state.py` appends one error per violated `complexity_assessments` invariant when a `complexity_assessments` key is present, delegating to `scripts/dev_tools/_orchestrator_state_complexity.py`, which recomputes the floor via `compute_complexity_floor`. The check does not import or read any schema file.
|
|
74
90
|
- `scripts/dev_tools/validate_orchestrator_state.py` appends one error per violated `model_routing_receipts` invariant when a `model_routing_receipts` key is present, delegating to `scripts/dev_tools/_orchestrator_state_model_routing.py`, which recomputes the resolved model via `resolve_delegation_model`. The check does not import or read any schema file.
|
|
91
|
+
- `scripts/dev_tools/validate_orchestrator_state.py` appends one error per violated `require_model_routing` invariant only when the caller passes `require_model_routing=True`, delegating to `scripts/dev_tools/_orchestrator_state_model_routing_gate.py`, which reuses the complexity and model-routing per-entry validators. When the flag is not passed the gate does not run, so existing calls are byte-identical.
|
|
75
92
|
- The validator is consumed by the MCP tool `validate_orchestration_artifacts`; backward compatibility for existing step-based checkpoints is preserved.
|
|
@@ -156,6 +156,10 @@
|
|
|
156
156
|
{
|
|
157
157
|
"type": "command",
|
|
158
158
|
"command": "pwsh -NoProfile -File .claude/hooks/enforce-epic-wave-barrier.ps1"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"type": "command",
|
|
162
|
+
"command": "pwsh -NoProfile -File .claude/hooks/enforce-model-routing-receipt.ps1"
|
|
159
163
|
}
|
|
160
164
|
]
|
|
161
165
|
}
|
|
@@ -115,9 +115,9 @@ The child's own `orchestrator` reads this line and applies the two-axis model-se
|
|
|
115
115
|
documented in `.claude/skills/orchestrate/SKILL.md` (`## Model Selection`): it assesses a
|
|
116
116
|
judgment-based `complexity_band`, records `complexity_assessments[]` and `model_routing_receipts[]`,
|
|
117
117
|
and resolves each delegation's model tier under the given `fable_policy`. The two canonical, tested
|
|
118
|
-
reference implementations are
|
|
119
|
-
(`
|
|
120
|
-
(`
|
|
118
|
+
reference implementations are `.claude/lib/model-routing/ModelRouting.psm1`
|
|
119
|
+
(`Get-ComplexityFloor`) and `.claude/lib/model-routing/ModelRouting.psm1`
|
|
120
|
+
(`Resolve-DelegationModel`). Default `fable_policy` is `disabled` when the marker is absent.
|
|
121
121
|
|
|
122
122
|
`route` is never an input to model selection; `route` remains file-count driven and governs only
|
|
123
123
|
agents, skills, and MCP tools. A skill whose frontmatter `context` field holds the value `fork`
|
|
@@ -24,6 +24,18 @@ On every invocation, the main session must:
|
|
|
24
24
|
2. If a valid checkpoint exists with a matching objective, resume from the recorded `next_step`.
|
|
25
25
|
3. If no checkpoint exists or the objective is new, begin the orchestration lifecycle from the start.
|
|
26
26
|
|
|
27
|
+
### Model-choice reconciliation on resume
|
|
28
|
+
|
|
29
|
+
Because model selection is required once delegation occurs (see `## Model Selection`), a resuming orchestrator must repair a missing model choice deterministically before delegating at a delegating `next_step`. When the resumed `next_step` is a delegating step:
|
|
30
|
+
|
|
31
|
+
a. **Preflight the checkpoint.** Run the orchestrator-state validator with `--require-model-routing` (via `mcp__drm-copilot__validate_orchestration_artifacts` or the local CLI) against `artifacts/orchestration/orchestrator-state.json` before the first delegation. Record the result in a `model_routing_preflight` block `{ status ("pass"|"fail"), checked_at (ISO-8601 UTC), validator_command, output_summary }`.
|
|
32
|
+
b. **Recompute the floor.** For the upcoming phase, recompute the complexity floor with `Get-ComplexityFloor -SignalsPresent <names>` (`.claude/lib/model-routing/ModelRouting.psm1`); do not reimplement the formula.
|
|
33
|
+
c. **Record the assessment.** Write a `complexity_assessments[]` entry `{ phase, band, floor, signals_present[], rationale, assessed_at }` with `floor` equal to the recomputed value and `band >= floor`.
|
|
34
|
+
d. **Resolve and record the receipt.** Resolve the model with `Resolve-DelegationModel -Agent <agent> -Band <complexity_band> -FablePolicy <fable_policy>` (`.claude/lib/model-routing/ModelRouting.psm1`) and write a `model_routing_receipts[]` entry `{ agent, phase, complexity_band, fable_policy, table_model, clamped_from | null, model }`.
|
|
35
|
+
e. **Persist and delegate.** Persist the checkpoint, then delegate with `model` equal to the receipt's `model`.
|
|
36
|
+
|
|
37
|
+
The orchestrator MUST NOT delegate at a delegating `next_step` while `model_routing_preflight` status is `fail`; it repairs the missing choice (steps b-e) and re-preflights until the status is `pass`.
|
|
38
|
+
|
|
27
39
|
## Autonomous-Execution Mandate
|
|
28
40
|
|
|
29
41
|
The orchestrator must achieve all actions agentically with no human interaction; full autonomy is a hard requirement. A silent manual blocker discovered at the end of a workflow is a defect, not an acceptable outcome. Every unautomatable (human-interaction) requirement must be detected early, resolved by exactly one of three permitted responses, and recorded in orchestrator state.
|
|
@@ -71,8 +83,10 @@ Model selection is a second axis, strictly separate from `route`. `route` (`smal
|
|
|
71
83
|
|
|
72
84
|
The two canonical, tested reference implementations express the formulas the orchestrator applies by judgment:
|
|
73
85
|
|
|
74
|
-
-
|
|
75
|
-
-
|
|
86
|
+
- `.claude/lib/model-routing/ModelRouting.psm1` (`Get-ComplexityFloor`) — the deterministic complexity-floor formula. Each present `[floor]` signal contributes a candidate band of `C3`; the floor is the maximum triggered candidate band; the floor never exceeds `C3`. C4 is never floor-forced; it is reached only by judgment.
|
|
87
|
+
- `.claude/lib/model-routing/ModelRouting.psm1` (`Resolve-DelegationModel`) — the delegation-model selection formula (base `complexity_to_model` table, the `preferred` overlay, and the `disabled` clamp).
|
|
88
|
+
|
|
89
|
+
The runnable reference the destination runtime applies is the `.claude`-resident PowerShell module above; the repository validator remains the Python authority (`scripts/dev_tools/compute_complexity_floor.py` and `scripts/dev_tools/resolve_delegation_model.py`), pinned to the same `config/orchestration-routing.json` truth table by a static config-parity test.
|
|
76
90
|
|
|
77
91
|
End-to-end procedure:
|
|
78
92
|
|
|
@@ -81,7 +95,11 @@ End-to-end procedure:
|
|
|
81
95
|
3. **Run the per-delegation selection order.** For each delegation, resolve the model as `resolve_delegation_model(agent, complexity_band, fable_policy)`: the `table_model` is the `preferred` overlay value when (`fable_policy == "preferred"` and the agent is in the overlay set `{atomic-planner, prd-feature, feature-review, task-researcher}` and `band == "C3"`), otherwise the base `complexity_to_model[band]`. Under `fable_policy == "disabled"`, a `fable` `table_model` clamps to `model = "opus"` with `clamped_from = "fable"`. `atomic-executor` and `pr-author` C3 cells stay `opus` under every policy.
|
|
82
96
|
4. **Emit a routing receipt.** Record a `model_routing_receipts[]` entry `{ agent, phase, complexity_band, fable_policy, table_model, clamped_from | null, model }`. `table_model` is the pre-clamp lookup; `model` is the post-clamp result.
|
|
83
97
|
|
|
84
|
-
The `complexity_assessments[]` and `model_routing_receipts[]` invariants are enforced by `scripts/dev_tools/validate_orchestrator_state.py` per `.claude/rules/orchestrator-state.md`; both arrays
|
|
98
|
+
The `complexity_assessments[]` and `model_routing_receipts[]` invariants are enforced by `scripts/dev_tools/validate_orchestrator_state.py` per `.claude/rules/orchestrator-state.md`; both arrays remain additive (a checkpoint that predates model routing stays valid).
|
|
99
|
+
|
|
100
|
+
### Required-once-delegated invariant (`require_model_routing` mode)
|
|
101
|
+
|
|
102
|
+
The `validate_orchestrator_state_text(...)` validator accepts a `require_model_routing` mode (CLI flag `--require-model-routing`; MCP parameter `require_model_routing`). Under this mode the arrays stop being merely optional: once the checkpoint records at least one delegation (a well-formed `delegation_receipts[]` entry, or a `next_step` that names a delegating agent), every delegated agent must have a matching `model_routing_receipts[]` entry, each matched receipt's phase must have a `complexity_assessments[]` entry, and every present receipt/assessment must be consistent with the reference formulas. A delegation-free checkpoint imposes no requirement, so old checkpoints stay valid. The gate is implemented in `scripts/dev_tools/_orchestrator_state_model_routing_gate.py`; it reuses the per-entry validators and never reimplements `compute_complexity_floor` or `resolve_delegation_model`. Two enforcement layers consume it: the completion gate (`.claude/hooks/validate-orchestrator-output.ps1` passes `--require-model-routing` and surfaces failures as `MODEL_ROUTING_BLOCKED:`), and the pre-delegation deterrent (`.claude/hooks/enforce-model-routing-receipt.ps1`, presence-only). The MCP TypeScript surface performs the existence check only (delegated-agent set ⊆ routing-receipt-agent set); the Python validator is authoritative for per-receipt correctness.
|
|
85
103
|
|
|
86
104
|
**`fork` caveat.** A skill whose frontmatter `context` field holds the value `fork` inherits the parent model and ignores a model override. Model selection therefore applies to agent delegations, not to fork-routed skill invocations.
|
|
87
105
|
|
|
@@ -126,6 +144,7 @@ The orchestrator must not report completion until:
|
|
|
126
144
|
1. All required artifacts for the selected workflow path are present on disk.
|
|
127
145
|
2. All validation gates (toolchain, acceptance criteria, audit artifacts) have passed.
|
|
128
146
|
3. The checkpoint file at `artifacts/orchestration/orchestrator-state.json` reflects the completed state.
|
|
147
|
+
4. The model-routing gate passes: `.claude/hooks/validate-orchestrator-output.ps1` runs the validator with `--require-model-routing` alongside `--require-complete` and refuses DONE with `MODEL_ROUTING_BLOCKED:` when a recorded delegation lacks a matching `model_routing_receipts[]` / `complexity_assessments[]` entry (see the required-once-delegated invariant under `## Model Selection`).
|
|
129
148
|
|
|
130
149
|
## Pre-Feature-Review Commit
|
|
131
150
|
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
".claude/hooks/enforce-epic-worktree-removal-gate.ps1",
|
|
23
23
|
".claude/hooks/enforce-evidence-locations.ps1",
|
|
24
24
|
".claude/hooks/enforce-feature-folder-order.ps1",
|
|
25
|
+
".claude/hooks/enforce-model-routing-receipt.ps1",
|
|
25
26
|
".claude/hooks/enforce-orchestration-preimplementation-gate.ps1",
|
|
26
27
|
".claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1",
|
|
27
28
|
".claude/hooks/enforce-pr-author-skill.ps1",
|
|
@@ -68,6 +69,7 @@
|
|
|
68
69
|
".claude/skills/review-staged/SKILL.md",
|
|
69
70
|
".claude/skills/skill-canonical-location-audit/SKILL.md",
|
|
70
71
|
".claude/skills/translate-copilot-to-claude/SKILL.md",
|
|
71
|
-
".claude/skills/update-status/SKILL.md"
|
|
72
|
+
".claude/skills/update-status/SKILL.md",
|
|
73
|
+
".claude/lib/model-routing/ModelRouting.psm1"
|
|
72
74
|
]
|
|
73
75
|
}
|
|
@@ -101,8 +101,14 @@ Lifecycle guardrails:
|
|
|
101
101
|
- `DIRECTIVE: MINIMAL-AUDIT PLAN REQUIRED`
|
|
102
102
|
|
|
103
103
|
8a) Resolve and persist `${plan-path}` before delegation:
|
|
104
|
-
-
|
|
105
|
-
-
|
|
104
|
+
- enumerate `${feature-folder}/plan*.md` files in deterministic filename order
|
|
105
|
+
- reuse the first existing `plan*.md` in `${feature-folder}` when present
|
|
106
|
+
- otherwise create exactly one canonical plan file path using the repository's
|
|
107
|
+
feature-folder plan naming convention and reuse it for all revisions
|
|
108
|
+
- never default to `${feature-folder}/plan.md` when a timestamped scaffolded
|
|
109
|
+
plan already exists
|
|
110
|
+
- if checkpoint state already contains a different `${plan-path}`, correct the
|
|
111
|
+
checkpoint before planner delegation instead of creating another plan file
|
|
106
112
|
|
|
107
113
|
9) Require preflight validation via `atomic_executor` until:
|
|
108
114
|
- `PREFLIGHT: ALL CLEAR`
|
|
@@ -109,6 +109,24 @@ staging, commits, or implementation delegation. This gate covers edits, formatte
|
|
|
109
109
|
If any required item is missing, implementation is blocked until the checkpoint
|
|
110
110
|
and lifecycle state are corrected.
|
|
111
111
|
|
|
112
|
+
## Plan-Path Resolution Gate
|
|
113
|
+
|
|
114
|
+
After active feature folder creation and before any planning delegation, the
|
|
115
|
+
main session must resolve `${plan-path}` from the active feature folder:
|
|
116
|
+
|
|
117
|
+
1. Enumerate existing `${feature-folder}/plan*.md` files in deterministic
|
|
118
|
+
filename order.
|
|
119
|
+
2. If one or more files exist, persist `${plan-path}` as the first existing
|
|
120
|
+
file and require every planner and executor handoff to use that exact path.
|
|
121
|
+
3. If no `plan*.md` file exists, create exactly one canonical target path using
|
|
122
|
+
the repository's feature-folder plan naming convention, persist that path,
|
|
123
|
+
and reuse it for all revisions.
|
|
124
|
+
4. Do not default to `${feature-folder}/plan.md` when a timestamped scaffolded
|
|
125
|
+
plan already exists.
|
|
126
|
+
5. If checkpoint state names a different plan path than the resolved existing
|
|
127
|
+
plan file, correct the checkpoint before planner delegation. Do not create a
|
|
128
|
+
second plan artifact to satisfy an incorrect checkpoint value.
|
|
129
|
+
|
|
112
130
|
## Pre-Implementation Violation Handling
|
|
113
131
|
|
|
114
132
|
If an implementation action is attempted before a required orchestration gate
|
package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md
CHANGED
|
@@ -101,6 +101,16 @@ Persist and reuse these fields exactly:
|
|
|
101
101
|
- `lifecycle_operations`
|
|
102
102
|
- `pre-implementation-violation`
|
|
103
103
|
|
|
104
|
+
Plan-path invariant:
|
|
105
|
+
- `${plan-path}` is resolved only after `${feature-folder}` exists.
|
|
106
|
+
- The orchestrator MUST enumerate existing `${feature-folder}/plan*.md` files
|
|
107
|
+
in deterministic filename order before planner delegation.
|
|
108
|
+
- If any existing plan file is present, `${plan-path}` MUST be that first
|
|
109
|
+
existing file. Do not persist or delegate against `${feature-folder}/plan.md`
|
|
110
|
+
when a timestamped scaffolded plan already exists.
|
|
111
|
+
- If checkpoint state conflicts with the resolved existing plan file, correct
|
|
112
|
+
checkpoint state before delegation and do not create a duplicate plan.
|
|
113
|
+
|
|
104
114
|
For small-path runs, also persist:
|
|
105
115
|
- `bootstrap_mode`
|
|
106
116
|
- `phase0_execution_summary`
|
|
@@ -310,6 +320,9 @@ Required behavior:
|
|
|
310
320
|
7. When those specialists are not yet migrated, perform the authoring steps directly without changing template headings.
|
|
311
321
|
8. Spawn `atomic-planner` to finalize `${plan-path}` and require `PREFLIGHT: ALL CLEAR`.
|
|
312
322
|
Hard enforcement for Step 7:
|
|
323
|
+
- Before spawning `atomic-planner`, resolve `${plan-path}` by enumerating
|
|
324
|
+
existing `${feature-folder}/plan*.md` files. Reuse the first existing file
|
|
325
|
+
in deterministic filename order, including timestamped scaffolded plans.
|
|
313
326
|
- The planning route MUST be `atomic-planner -> atomic-executor` for preflight validation.
|
|
314
327
|
- The planner MUST update `${plan-path}` in place and MUST NOT create additional `plan.*.md` files for revisions.
|
|
315
328
|
- The approved plan MUST include explicit Phase 0 baseline evidence tasks and explicit final-QA evidence or coverage tasks for each language in scope where policy requires them.
|
|
@@ -76,6 +76,8 @@ Every agent named above must exist as a native Codex agent under `.codex/agents/
|
|
|
76
76
|
- Do not rename, back up, or create sidecar checkpoint files.
|
|
77
77
|
- Do not create or edit `${feature-folder}/issue.md`, `${feature-folder}/spec.md`, `${feature-folder}/user-story.md`, or `plan*.md` until lifecycle setup succeeds.
|
|
78
78
|
- Do not persist placeholder lifecycle values such as `NONE`, `TBD`, or empty strings once lifecycle setup begins.
|
|
79
|
+
- After active folder creation and before planner delegation, resolve `${plan-path}` by enumerating existing `${feature-folder}/plan*.md` files in deterministic filename order. If a scaffolded timestamped plan exists, persist and delegate against that exact file. Do not default to `${feature-folder}/plan.md` and do not create a second plan artifact when a plan already exists.
|
|
80
|
+
- For issue #306, the canonical existing plan path is `docs/features/active/2026-07-04-codex-agent-role-config-306/plan.2026-07-04T13-47.md`; reuse that exact file and do not create `docs/features/active/2026-07-04-codex-agent-role-config-306/plan.md`.
|
|
79
81
|
|
|
80
82
|
## Checkpoint Persistence
|
|
81
83
|
|
|
@@ -133,17 +135,16 @@ The MCP validator and required CI checks are the hard completion boundary. There
|
|
|
133
135
|
Do not claim mission completion unless all required delegations completed with receipts and the required orchestration artifacts exist on disk.
|
|
134
136
|
'''
|
|
135
137
|
|
|
136
|
-
[
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
pr-base-branch-merge-base = true
|
|
138
|
+
[skills]
|
|
139
|
+
config = [
|
|
140
|
+
{ name = "policy-compliance-order", enabled = true },
|
|
141
|
+
{ name = "orchestrate", enabled = true },
|
|
142
|
+
{ name = "orchestrator-workflow", enabled = true },
|
|
143
|
+
{ name = "feature-promotion-lifecycle", enabled = true },
|
|
144
|
+
{ name = "repo-automation-adapter", enabled = true },
|
|
145
|
+
{ name = "atomic-plan-contract", enabled = true },
|
|
146
|
+
{ name = "acceptance-criteria-tracking", enabled = true },
|
|
147
|
+
{ name = "evidence-and-timestamp-conventions", enabled = true },
|
|
148
|
+
{ name = "pr-context-artifacts", enabled = true },
|
|
149
|
+
{ name = "pr-base-branch-merge-base", enabled = true },
|
|
150
|
+
]
|