@@ -358,9 +358,17 @@ def record_declarations(self, degraded=False):
358358 Record which module declares each setting, and when it was last seen
359359
360360 Run after the ModuleCollector, since it needs the provenance the
361- collector works out while loading modules. Every setting in the config
362- definition gets a row: module-declared ones are attributed to the worker
363- that declared them, everything else to core.
361+ collector works out while loading modules. Every setting declared this
362+ boot gets a row: module-declared ones are attributed to the worker that
363+ declared them, core ones to `config_definition`.
364+
365+ Only settings that really were declared this boot are recorded.
366+ `config_definition` is merged rather than rebuilt, so it can still hold
367+ a setting from the *previous* boot's module cache - the boot right after
368+ an extension is switched off is exactly that case, since the sidecar is
369+ replaced wholesale but the definition is not. Recording those would
370+ attribute them to core, wiping out the extension they belong to, and
371+ they would end up offered for removal while the extension is merely off.
364372
365373 A setting in the `settings` table with *no* row here is one that nothing
366374 currently declares. That alone is not grounds to remove it - it may
@@ -378,7 +386,13 @@ def record_declarations(self, degraded=False):
378386
379387 declarations = []
380388 for setting , definition in self .config_definition .items ():
381- declared = self .setting_provenance .get (setting , {})
389+ declared = self .setting_provenance .get (setting )
390+ if declared is None and setting not in config_definition :
391+ # left over from the previous boot's module cache, not declared
392+ # by anything now. Leave whatever was recorded for it alone.
393+ continue
394+
395+ declared = declared or {}
382396
383397 try :
384398 # definitions can hold values JSON cannot represent (core has a
0 commit comments