Description
App.config does two unrelated jobs, and that is the bug. It holds the values an app author bundles at build time, and the values an operator supplies through site.config or the runtime config API. mergeApp flattens both into one object before addAppConfigs runs, so provenance is lost by the time getAppConfig resolves anything.
The consequence is that every key an app bundles is a key commonAppConfig can never supply. getAppConfig merges with merge({}, commonAppConfig, appConfigs[id]), so a value an operator sets site-wide loses to whatever the app's author shipped. Overrides are fragile for the same reason: an operator changing one value must spread the app's existing config back in, and forgetting the inner spread silently discards every other default.
Flipping the merge order is not the fix. MFE_CONFIG_OVERRIDES reaches apps through per-app config, so the flip breaks a channel operators depend on: edx-platform maps /api/mfe_config/v1 onto commonAppConfig and /api/mfe_config/v1?mfe=<name> onto per-app config, and an app-specific override must beat site-wide values.
The fix is to stop overloading one field. App.defaultConfig holds the app author's bundled values and resolves below commonAppConfig, which resolves below config. The two fields are held separately, so operator-supplied configuration can never write into an app's bundled defaults. ADR 0017 records the decision and #298 implements it.
Apps to update
Bundled defaults move from config to defaultConfig:
Checked and needing no change: frontend-app-notifications, frontend-app-instructor-dashboard, frontend-app-base-test, frontend-app-sample.
LLM usage notice
Filed with assistance from Claude.
Description
App.configdoes two unrelated jobs, and that is the bug. It holds the values an app author bundles at build time, and the values an operator supplies throughsite.configor the runtime config API.mergeAppflattens both into one object beforeaddAppConfigsruns, so provenance is lost by the timegetAppConfigresolves anything.The consequence is that every key an app bundles is a key
commonAppConfigcan never supply.getAppConfigmerges withmerge({}, commonAppConfig, appConfigs[id]), so a value an operator sets site-wide loses to whatever the app's author shipped. Overrides are fragile for the same reason: an operator changing one value must spread the app's existing config back in, and forgetting the inner spread silently discards every other default.Flipping the merge order is not the fix.
MFE_CONFIG_OVERRIDESreaches apps through per-appconfig, so the flip breaks a channel operators depend on: edx-platform maps/api/mfe_config/v1ontocommonAppConfigand/api/mfe_config/v1?mfe=<name>onto per-appconfig, and an app-specific override must beat site-wide values.The fix is to stop overloading one field.
App.defaultConfigholds the app author's bundled values and resolves belowcommonAppConfig, which resolves belowconfig. The two fields are held separately, so operator-supplied configuration can never write into an app's bundled defaults. ADR 0017 records the decision and #298 implements it.Apps to update
Bundled defaults move from
configtodefaultConfig:defaultConfig)Checked and needing no change: frontend-app-notifications, frontend-app-instructor-dashboard, frontend-app-base-test, frontend-app-sample.
LLM usage notice
Filed with assistance from Claude.