You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
HARPER_SET_CONFIG applied after component loading (thread-timing race) and not persisted at install — env-var-configured components silently fail to register #1618
HARPER_SET_CONFIG (and by extension env-var-driven config) is unreliable for anything component-loading reads at boot: it is applied to the in-memory config after components load on some platforms/timings, and the install-time application does not persist it to the written config file. Net effect: a component key delivered via env var may be silently ignored — the component never registers, no error, no warning.
Found while debugging PR #1616's integration-test 404s (the modelsGateway component); the mechanism is general and affects any env-var-configured deployment (Docker/Fabric-style) activating or configuring components via HARPER_SET_CONFIG.
Evidence
1. Ordering race (Linux CI, deterministic there; opposite on macOS). From the failing suite's Harper instance log (PR #1616, run 28810803532, shard 4/6):
17:37:26.137 [main/0] [info]: All root applications loaded ← componentLoader ran
17:37:26.494 [http/1] [debug] [env-config]: Applied HARPER_SET_CONFIG at runtime ← merged after
17:37:26.507 [http/1] [debug]: Config file updated with runtime env var values
Components were loaded from a config that did not yet contain the env-supplied key → /v1/* 404s. The same boot on macOS serves 200 — the runtime application happens to win there. Same code, thread-timing-dependent outcome.
2. Install-time application doesn't persist.config/configUtils.ts:163 calls applyRuntimeEnvVarConfig(configDoc, null, { isInstall: true }) before writing the fresh config file — but after a fresh local install with HARPER_SET_CONFIG='{"modelsGateway":{"enabled":true}}', the written harperdb-config.yaml does not contain the key (verified directly). So even a fresh install under env config produces a file that component loading can't see the env config in, leaving only the racy runtime path (configUtils.ts:341).
(There is also a known sub-issue that flattenObject in config/harperConfigEnvVars.ts silently drops empty-object values like modelsGateway: {} — no leaf paths — noted in PR #1616's history. The non-empty {enabled: true} form still hits the two problems above, so fixing the flatten alone is insufficient.)
Why this matters
Env-var config is the primary mechanism for containerized deployments and the integration-test harness (@harperfast/integration-testing passes suite config exclusively via HARPER_SET_CONFIG — see its harperLifecycle).
Silent mis-registration: nothing logs that a component key arrived too late to matter.
Apply HARPER_DEFAULT_CONFIG / HARPER_CONFIG / HARPER_SET_CONFIGsynchronously during initial config resolution on every thread, before any component loading — i.e. the resolved config object handed to componentLoader must already include env-var config, deterministically, on all platforms.
Make the install-time application actually persist into the freshly written config file (or make the boot path not depend on the file for env-supplied values).
Keep the existing drift-detection/restore semantics (hasPersistedEnvConfigState) intact.
Consider a debug log when env config introduces keys that affect component activation, to make future ordering regressions visible.
Acceptance
Fresh boot with HARPER_SET_CONFIG='{"modelsGateway":{"enabled":true}}' registers the component on Linux and macOS, first boot and subsequent boots.
Summary
HARPER_SET_CONFIG(and by extension env-var-driven config) is unreliable for anything component-loading reads at boot: it is applied to the in-memory config after components load on some platforms/timings, and the install-time application does not persist it to the written config file. Net effect: a component key delivered via env var may be silently ignored — the component never registers, no error, no warning.Found while debugging PR #1616's integration-test 404s (the
modelsGatewaycomponent); the mechanism is general and affects any env-var-configured deployment (Docker/Fabric-style) activating or configuring components viaHARPER_SET_CONFIG.Evidence
1. Ordering race (Linux CI, deterministic there; opposite on macOS). From the failing suite's Harper instance log (PR #1616, run 28810803532, shard 4/6):
Components were loaded from a config that did not yet contain the env-supplied key →
/v1/*404s. The same boot on macOS serves 200 — the runtime application happens to win there. Same code, thread-timing-dependent outcome.2. Install-time application doesn't persist.
config/configUtils.ts:163callsapplyRuntimeEnvVarConfig(configDoc, null, { isInstall: true })before writing the fresh config file — but after a fresh local install withHARPER_SET_CONFIG='{"modelsGateway":{"enabled":true}}', the writtenharperdb-config.yamldoes not contain the key (verified directly). So even a fresh install under env config produces a file that component loading can't see the env config in, leaving only the racy runtime path (configUtils.ts:341).(There is also a known sub-issue that
flattenObjectinconfig/harperConfigEnvVars.tssilently drops empty-object values likemodelsGateway: {}— no leaf paths — noted in PR #1616's history. The non-empty{enabled: true}form still hits the two problems above, so fixing the flatten alone is insufficient.)Why this matters
@harperfast/integration-testingpasses suite config exclusively viaHARPER_SET_CONFIG— see itsharperLifecycle).Suggested shape of the fix
HARPER_DEFAULT_CONFIG/HARPER_CONFIG/HARPER_SET_CONFIGsynchronously during initial config resolution on every thread, before any component loading — i.e. the resolved config object handed tocomponentLoadermust already include env-var config, deterministically, on all platforms.hasPersistedEnvConfigState) intact.Acceptance
HARPER_SET_CONFIG='{"modelsGateway":{"enabled":true}}'registers the component on Linux and macOS, first boot and subsequent boots.integrationTests/server/v1-gateway.test.ts) passes in CI without workarounds.Refs
config/configUtils.ts:163(install-time apply),:341(runtime apply),:915(applyRuntimeEnvVarConfig);config/harperConfigEnvVars.ts(flattenObject,applyRuntimeEnvConfig);components/componentLoader.ts:387-394(config-keyed component loading).🤖 Generated with Claude Code