Problem
PromptDefinition (Sources/mcs/TechPack/PromptDefinition.swift) has no condition field, and CrossPackPromptResolver.collectDeclaredPrompts (Sources/mcs/Sync/CrossPackPromptResolver.swift:20-25) gathers prompts per pack, not per selected component:
packs.flatMap { $0.declaredPrompts(context: context) }
So a prompt is asked even when every component that consumes its placeholder was deselected via mcs sync --customize, and the answer goes nowhere. Harmless with one or two packs, increasingly irritating as packs accumulate prompts.
Sketch
Add an optional requiredBy: [String] (component ids) to PromptDefinition:
prompts:
- key: KB_GATE_MODE
type: select
requiredBy: [hook-gate-turn, hook-gate-record, hook-gate-check]
Skip the prompt when none of the listed ids are in the selected set; keep asking when requiredBy is absent (current behavior).
Insertion point: ProjectConfigContext is already threaded into declaredPrompts(context:) and is currently under-used — implementations read only isGlobalScope from it. Carrying the selected-component set on the context is cheaper than changing the collectDeclaredPrompts signature. The selection is known at Configurator.resolveAllValues (Configurator.swift:645).
Two details to settle before starting
1. Placeholder fallback is bigger than it looks. ConfiguratorSupport.scanForUndeclaredPlaceholders (called at Configurator.swift:695) takes packs, not the selected component set — so it scans deselected components' files too. A requiredBy-skipped prompt would then be re-asked as a raw Set value for KB_GATE_MODE inline prompt even when nothing selected uses it, which is strictly worse than today's behavior.
Narrowing that scan to selected components is therefore part of this work, not a follow-up — and it needs care: the scan is load-bearing as the safety net for emitWarnings: false substitution, and covers three artifact families (copyPackFile sources, settingsMerge file sources, mcpServer env/command/args).
Alternative worth considering: treat a requiredBy mismatch — a placeholder used by a component not listed in requiredBy — as an authoring error at mcs pack validate time. It's statically detectable and avoids the runtime question entirely.
2. Prior values. A skipped prompt must leave any stored prior untouched rather than clearing it, so re-enabling the component later doesn't lose the answer.
Validation to add
Every id in requiredBy must exist in the pack's components — catches typos and renames at mcs pack validate time.
Tests
Tests/MCSTests/CrossPackPromptResolverTests.swift:
- prompt with
requiredBy and no listed component selected → not asked
- prompt with
requiredBy and one listed component selected → asked
- prompt without
requiredBy → asked (regression guard)
- skipped prompt leaves prior value intact across a re-sync
requiredBy referencing an unknown component id → validation error
Problem
PromptDefinition(Sources/mcs/TechPack/PromptDefinition.swift) has no condition field, andCrossPackPromptResolver.collectDeclaredPrompts(Sources/mcs/Sync/CrossPackPromptResolver.swift:20-25) gathers prompts per pack, not per selected component:So a prompt is asked even when every component that consumes its placeholder was deselected via
mcs sync --customize, and the answer goes nowhere. Harmless with one or two packs, increasingly irritating as packs accumulate prompts.Sketch
Add an optional
requiredBy: [String](component ids) toPromptDefinition:Skip the prompt when none of the listed ids are in the selected set; keep asking when
requiredByis absent (current behavior).Insertion point:
ProjectConfigContextis already threaded intodeclaredPrompts(context:)and is currently under-used — implementations read onlyisGlobalScopefrom it. Carrying the selected-component set on the context is cheaper than changing thecollectDeclaredPromptssignature. The selection is known atConfigurator.resolveAllValues(Configurator.swift:645).Two details to settle before starting
1. Placeholder fallback is bigger than it looks.
ConfiguratorSupport.scanForUndeclaredPlaceholders(called atConfigurator.swift:695) takespacks, not the selected component set — so it scans deselected components' files too. ArequiredBy-skipped prompt would then be re-asked as a rawSet value for KB_GATE_MODEinline prompt even when nothing selected uses it, which is strictly worse than today's behavior.Narrowing that scan to selected components is therefore part of this work, not a follow-up — and it needs care: the scan is load-bearing as the safety net for
emitWarnings: falsesubstitution, and covers three artifact families (copyPackFilesources,settingsMergefile sources,mcpServerenv/command/args).Alternative worth considering: treat a
requiredBymismatch — a placeholder used by a component not listed inrequiredBy— as an authoring error atmcs pack validatetime. It's statically detectable and avoids the runtime question entirely.2. Prior values. A skipped prompt must leave any stored prior untouched rather than clearing it, so re-enabling the component later doesn't lose the answer.
Validation to add
Every id in
requiredBymust exist in the pack's components — catches typos and renames atmcs pack validatetime.Tests
Tests/MCSTests/CrossPackPromptResolverTests.swift:requiredByand no listed component selected → not askedrequiredByand one listed component selected → askedrequiredBy→ asked (regression guard)requiredByreferencing an unknown component id → validation error