Skip to content

Undeclared-placeholder scan ignores --customize exclusions, prompting for deselected components #364

Description

@bguidolim

Problem

ConfiguratorSupport.scanForUndeclaredPlaceholders (Sources/mcs/Sync/ConfiguratorSupport.swift:358-412) walks pack.components with no awareness of --customize exclusions:

for pack in packs {
    for component in pack.components {
        switch component.installAction {
        case let .copyPackFile(source, _, _): ...
        case let .settingsMerge(source): ...
        case let .mcpServer(config): ...

So a placeholder that appears only inside a deselected component's files is still collected, and Configurator.swift:692-706 prompts for it:

Set value for SOME_KEY

…for a file that will never be installed. The answer is stored in state.resolvedValues and substituted nowhere.

Configurator.configure already has excludedComponents in hand (Configurator.swift:228) and threads it into auto-install, template preloading, artifact installation, and settings composition. resolveAllValues (:642) is the one step that never received it.

Fix sketch

Thread excludedComponents from configure()resolveAllValuesscanForUndeclaredPlaceholders, and filter inside the component loop:

for pack in packs {
    let excluded = excludedComponents[pack.identifier] ?? []
    for component in pack.components where !excluded.contains(component.id) {

Templates (includeTemplates: true, global scope) stay unfiltered — template dependency filtering is a separate mechanism handled by preloadTemplates.

Care required

This scan is load-bearing: it is the safety net that catches placeholders which would otherwise survive emitWarnings: false substitution and get written literally into installed files. Narrowing it must not create a hole for a selected component:

  • Filter strictly by component id — do not narrow by artifact family or source path.
  • Excluded-but-required components (ComponentDefinition.isRequired) can never appear in the exclusion set (ConfiguratorSupport.selectComponentExclusions:140-141), so they stay covered.

Tests

Tests/MCSTests/LifecycleIntegrationTests.swift (or ConfiguratorSupport-level unit tests):

  • placeholder only in an excluded component's copyPackFile source → not prompted
  • same placeholder also used by a selected component → still prompted (regression guard)
  • excluded settingsMerge source and excluded mcpServer env/command/args → not prompted (all three families the scan covers)
  • no exclusions → unchanged behavior

Relation to #356

#356 proposes requiredBy on prompts, and correctly identifies that narrowing this scan is a prerequisite — otherwise a requiredBy-skipped prompt reappears as a raw Set value for X fallback. This half is independently valuable and carries no manifest schema change, so it is being split out.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Medium prioritybugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions