Skip to content

fix: cast env-var strings before comparing in updateConfigValue#499

Merged
cb1kenobi merged 1 commit into
mainfrom
fix/config-update-comparison-typecast
May 8, 2026
Merged

fix: cast env-var strings before comparing in updateConfigValue#499
cb1kenobi merged 1 commit into
mainfrom
fix/config-update-comparison-typecast

Conversation

@Devin-Holland
Copy link
Copy Markdown
Member

Summary

Fix updateConfigValue's "skip if no changes" check (config/configUtils.js:516) to cast env-var strings to typed values before comparing. Without this, every Harper restart rewrites the config file (and creates a backup) for any deployment that uses a boolean or array env var.

Why

Env vars arrive in process.env as strings — there is no boolean/number env var at the OS level. The check was using loose equality:

if (parsedArgs[arg] != flatConfigObj[arg.toLowerCase()]) {

Loose equality coerces string↔number cleanly ('9925' == 9925 → true) but not string↔boolean ('true' != true because 'true' becomes NaN, true becomes 1, and NaN != 1) and not string↔array. Any deployment with a boolean or array config env var trips the check on every boot.

This affects the default Harper Dockerfile, which sets LOGGING_STDSTREAMS=true. Every Harper container is rewriting its config and creating a backup on every restart, even with no actual config change. Same md5sum across N backups — observed in the field.

This was also the trigger for the partial-config corruption fixed in #493: every restart was opening the truncate window for fs.writeFileSync while concurrent readers were starting up. With #493's atomic write, the corruption no longer occurs, but the spurious writes and backups still happen. This PR stops them.

What changed

  • config/configUtils.js:511-526: cast parsedArgs[arg] through castConfigValue (the same coercion already used by the write path 80 lines below) and deep-compare with _.isEqual.
  • unitTests/config/configUtils.test.js: added two tests — one verifying string env values matching typed config values are detected as equal (the fix), one verifying genuine differences still trigger an update (no regression).

Areas to look at

  • The cast covers all the cases loose-equal handled, plus the ones it didn't. Walked through edge cases ('' vs null, '0' vs null, '3d' vs '3d', null vs undefined) and didn't find a regression — the new comparison agrees with castConfigValue, which is what the actual write path uses anyway.
  • castConfigValue ignores its param argument (pre-existing — there's a TS6133 diagnostic on it). Passing arg works because it's never read; if someone later wires param up, this comparison call site would need to use the canonical CONFIG_PARAM_MAP[arg.toLowerCase()] instead.
  • Out of scope, intentionally. Did NOT touch the duplicate initialize() calls (launch() runs it before forking, daemon child likely runs it again). With this fix, the second call sees no diff and skips cleanly. If duplicate writes still occur after this lands, that's a separate bug.

Test plan

  • npm run test:unit:config passes locally (130 passing)
  • Manually verify a Harper deploy with the stock Dockerfile no longer creates a new backup on every restart

updateConfigValue's "skip if values are the same" check used loose
equality, which handles string<->number ('9925' == 9925) but not
string<->boolean ('true' != true) or string<->array. Any deployment
with a boolean or array env var (e.g. LOGGING_STDSTREAMS=true in the
default Harper Dockerfile) hit the write path on every restart even
when nothing actually changed, generating a backup and rewriting the
config file each boot.

Cast the env value through castConfigValue (the same coercion the write
path applies a few lines below) and deep-compare. With this fix the
check correctly skips the update when env-derived values match the
on-disk config regardless of source type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Devin-Holland Devin-Holland requested a review from a team as a code owner May 8, 2026 15:23
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 8, 2026

Reviewed; no blockers found.

@cb1kenobi cb1kenobi merged commit f823327 into main May 8, 2026
41 of 43 checks passed
@cb1kenobi cb1kenobi deleted the fix/config-update-comparison-typecast branch May 8, 2026 16:35
github-actions Bot pushed a commit that referenced this pull request May 8, 2026
…typecast

fix: cast env-var strings before comparing in updateConfigValue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants