Summary
When a pack is deselected via mcs sync or removed via mcs pack remove, its declared prompt keys linger in state.resolvedValues indefinitely. Nothing reads them, but a later-installed pack that happens to declare the same key will see the stale value as a "prior" and try to reuse it through the #339 reuse flow.
Why this matters
Cross-pack key reuse is rare but plausible — BRANCH_PREFIX, LABEL_PREFIX, DEFAULT_ASSIGNEE are the realistic collision candidates (conventional keys multiple packs would reasonably reuse). The worst-case symptom after a pack swap:
- User removes pack A (which used
BRANCH_PREFIX = "bruno")
- User adds pack B (also declares
BRANCH_PREFIX)
- First
mcs sync after adding B shows the Reuse N values? gate with B's "prior" of "bruno" — which was actually A's answer the user never intended to share
No data corruption: the user can say n and re-answer. But the gate surfaces a value the current selection never authored, which is surprising.
Proposed fix
In Configurator.unconfigurePack (Sources/mcs/Sync/Configurator.swift), after removing the pack from state:
- Walk the removed pack's declared prompt keys.
- For each, check whether any remaining selected pack still declares the same key (via
declaredPrompts(context:)).
- If no remaining pack declares the key, delete it from
state.resolvedValues.
declaredPrompts(context:) needs a ProjectConfigContext — the pack being unconfigured is already in memory at that point, and a minimal context can be synthesized.
Scope
Sources/mcs/Sync/Configurator.swift — unconfigurePack augmentation
Sources/mcs/Core/ProjectState.swift — new helper like mutating func removeResolvedValues(keys:) (or inline the dict mutation)
- Tests: add a lifecycle case to
PromptValueReuseLifecycleTests — pack A with key X → remove A → pack B declaring same X → assert B is asked fresh
Related
Summary
When a pack is deselected via
mcs syncor removed viamcs pack remove, its declared prompt keys linger instate.resolvedValuesindefinitely. Nothing reads them, but a later-installed pack that happens to declare the same key will see the stale value as a "prior" and try to reuse it through the #339 reuse flow.Why this matters
Cross-pack key reuse is rare but plausible —
BRANCH_PREFIX,LABEL_PREFIX,DEFAULT_ASSIGNEEare the realistic collision candidates (conventional keys multiple packs would reasonably reuse). The worst-case symptom after a pack swap:BRANCH_PREFIX = "bruno")BRANCH_PREFIX)mcs syncafter adding B shows theReuse N values?gate with B's "prior" of"bruno"— which was actually A's answer the user never intended to shareNo data corruption: the user can say
nand re-answer. But the gate surfaces a value the current selection never authored, which is surprising.Proposed fix
In
Configurator.unconfigurePack(Sources/mcs/Sync/Configurator.swift), after removing the pack from state:declaredPrompts(context:)).state.resolvedValues.declaredPrompts(context:)needs aProjectConfigContext— the pack being unconfigured is already in memory at that point, and a minimal context can be synthesized.Scope
Sources/mcs/Sync/Configurator.swift—unconfigurePackaugmentationSources/mcs/Core/ProjectState.swift— new helper likemutating func removeResolvedValues(keys:)(or inline the dict mutation)PromptValueReuseLifecycleTests— pack A with key X → remove A → pack B declaring same X → assert B is asked freshRelated
.claude/memories/decision_architecture_prompt_value_reuse_on_resync.md— documents the "not pruned yet" gap