Tier A #2. Zero refutations.
Source: docs/plans/dynamic-workflow-migration.md §2 (merged in #2162).
Why this one wins
The fan-out width is already deterministic — list-components.sh emits the roster. 34 of 38 components have no script of their own, so the checks are genuinely agent-shaped rather than script-shaped. And unlike most candidates, configure-all does not hold context: fork, so its context-pressure problem is live and unaddressed.
Shape: fan-out-and-synthesize, one check agent per applicable roster row.
Design decisions from the adversarial pass
- The classify agent is deleted. Applicability is
types === 'all' || types.split(',').includes(projectType) over a field the script already emits. No agent decides this.
--fix never enters the workflow. Pre-commit and linting both write .pre-commit-config.yaml; parallel fixers would race.
- A floor, not just a ceiling. Below ~15 applicable components the sequential path is cheaper than 15 agent preambles.
Sketch
export const meta = { name:'configure-all-check', phases:[{title:'Check'},{title:'Synthesize'}] }
const { roster, projectType, ambiguous = [] } = (typeof args === 'string') ? JSON.parse(args) : args
if (!roster?.length) { log('empty roster — list-components.sh returned STATUS=ERROR; abort'); return { abort:true } }
// TYPES is manifest data, not a judgement. No agent decides this.
const applicable = roster.filter(r => r.types === 'all' || r.types.split(',').includes(projectType))
const skipped = roster.filter(r => !applicable.includes(r)).map(r => ({...r, reason:`TYPES=${r.types}`}))
if (applicable.length < 15) { log(`${applicable.length} components — sequential path is cheaper; abort`); return { abort:true } }
phase(`Check — ${applicable.length} components, READ-ONLY, ≤5 in flight`)
const checks = []
for (let i = 0; i < applicable.length; i += 5) {
const wave = applicable.slice(i, i + 5)
const got = await parallel(wave.map(c => () => agent(
`Invoke /configure:${c.component} --check-only via SlashCommand. READ-ONLY — report findings, write nothing.`,
{ label:`check:${c.component}`, phase:'Check', schema: CHECK_SCHEMA })))
checks.push(...got.map((r, j) => r || { component: wave[j].component, status:'ERROR', issues:['agent returned null'], files:[] }))
}
phase('Synthesize — BARRIER: the fix plan must see every component at once')
const report = await agent(SYNTH_PROMPT(checks, skipped), // groups components contending for the same file
{ label:'synthesize', phase:'Synthesize', schema: REPORT_SCHEMA })
return { report, fixPlan: report.fixPlan } // --fix applied OUTSIDE, sequentially, by the skill
Two hard prerequisites the design omitted
allowed-tools currently has no Task/Agent — add it, or the skill cannot dispatch at all.
- Each check agent's toolset must include
SlashCommand, or it will re-derive a component check from scratch instead of invoking /configure:<component>.
SKILL.md delta
New ### Step 3b: Heavy path — parallel check fan-out (optional) between Steps 3 and 4, with the template framing and the explicit floor. Step 5 gains:
--fix never runs inside the workflow. Several components mutate the same files; parallel fixers would race. Apply the fixPlan sequentially.
Replace the hardcoded four-way ## Agent Teams (Optional) table with a pointer to the harness. Note that exitCode cannot come from a workflow — the skill converts the report to a process exit code.
Acceptance
Blocked by #2163 (layout convention).
Tier A #2. Zero refutations.
Source:
docs/plans/dynamic-workflow-migration.md§2 (merged in #2162).Why this one wins
The fan-out width is already deterministic —
list-components.shemits the roster. 34 of 38 components have no script of their own, so the checks are genuinely agent-shaped rather than script-shaped. And unlike most candidates,configure-alldoes not holdcontext: fork, so its context-pressure problem is live and unaddressed.Shape: fan-out-and-synthesize, one check agent per applicable roster row.
Design decisions from the adversarial pass
types === 'all' || types.split(',').includes(projectType)over a field the script already emits. No agent decides this.--fixnever enters the workflow. Pre-commit and linting both write.pre-commit-config.yaml; parallel fixers would race.Sketch
Two hard prerequisites the design omitted
allowed-toolscurrently has noTask/Agent— add it, or the skill cannot dispatch at all.SlashCommand, or it will re-derive a component check from scratch instead of invoking/configure:<component>.SKILL.md delta
New
### Step 3b: Heavy path — parallel check fan-out (optional)between Steps 3 and 4, with the template framing and the explicit floor. Step 5 gains:Replace the hardcoded four-way
## Agent Teams (Optional)table with a pointer to the harness. Note thatexitCodecannot come from a workflow — the skill converts the report to a process exit code.Acceptance
workflows/configure-all-check.workflow.jsbeside SKILL.mdallowed-toolsgainsTask/Agent; check agents getSlashCommand<15floor and read-only-check invariant present## Agent Teams (Optional)table replaced, not left to driftBlocked by #2163 (layout convention).