Skip to content

HARPER_SET_CONFIG applied after component loading (thread-timing race) and not persisted at install — env-var-configured components silently fail to register #1618

Description

@heskew

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 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.
  • Direction from Nathan: fix the core loading order properly rather than working around it (e.g., PR feat(models): OpenAI-compatible /v1/* gateway as built-in Resources (#631, Phase 4 of #510) #1616 deliberately keeps its component default-off and its integration test depends on this fix; enabling things by default to dodge the race is not an acceptable pattern).

Suggested shape of the fix

  • Apply HARPER_DEFAULT_CONFIG / HARPER_CONFIG / HARPER_SET_CONFIG synchronously 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

Refs


🤖 Generated with Claude Code

Metadata

Metadata

Assignees

Labels

duplicateThis issue or pull request already exists

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions