ExpandConfigurationAsync wrote through config[key] = ..., which only sets the
providers' in-memory Data; a file provider's reload replaces it, so editing
appsettings.json on a running service reverted every expanded key to its
${secret:...} placeholder.
- ConfigurationManager: expanded values are pinned in an internal overlay
source appended last; its provider's Load() is a no-op and Build always
returns the same provider, so reloads (and source rebuilds) keep the pins
- any other IConfigurationRoot: in-place write as before, re-applied from the
root's reload token
- all references resolve before anything is written (a fail-closed miss no
longer leaves the config half expanded)
- tests: SecretExpansionReloadTests (real JSON file + Reload(), options
monitor, plain root); three fail without the fix
- docs: README reload note, CHANGELOG
- code-reviews: Secrets-003 Resolved; README regenerated
Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV