Fixes the two real bugs C.3 surfaced when flipping usgs_quake to central.
BUG #1 -- GUI save dropped ${VAR} secret refs (config_loader.save_section).
before: A GUI PUT round-trips the *interpolated* secret value (GET returns the
resolved key string, e.g. the real TomTom key). save_section's
check_secrets saw a literal string at a SECRET_FIELDS path, didn't
recognize it as a ref, and DROPPED it -- losing the on-disk
${TOMTOM_API_KEY} placeholder. C.3's flip PUT stripped TomTom's key.
after: check_secrets now reads the raw on-disk value (pre-interpolation) for
each secret field and decides three ways:
on-disk ${VAR} and new == resolved(VAR) -> keep the ${VAR} ref
on-disk ${VAR} and new != resolved(VAR) -> intentional change, store it
no on-disk ${VAR} ref -> reject (never write a raw
secret to a domain file)
${VAR} resolution mirrors load: os.environ first, then /data/secrets/.env.
The common case (GUI re-saves unchanged config) now preserves the
placeholder instead of dropping it.
BUG #2 -- CentralConsumer replayed the entire retained backlog on first flip.
before: js.subscribe(...) with no config -> default deliver_policy=all. Fine
for quake (682 msgs) but would flood the bus with ~330k traffic_flow
messages on first flip.
after: consumer_config() -> ConsumerConfig(deliver_policy=DeliverPolicy.NEW):
only messages published AFTER consumer creation. meshai won't see the
backlog on first flip -- acceptable, Central is a live firehose for
current events. (NOT geo-filtering -- that's a Central-side issue filed
separately for the Central project.)
Files: meshai/config_loader.py (save_section secret preservation),
meshai/central/consumer.py (consumer_config() + deliver_policy=NEW),
tests/test_save_section_secret_preserve.py (new),
tests/test_central_consumer.py (deliver_policy assertion).
Verification:
- (A) py_compile clean on config_loader.py + consumer.py.
- (C) pytest -q: 276 passed (272 + 4 new -- preserve-unchanged-ref,
changed-value-written, no-placeholder-still-rejects, deliver_policy=NEW).
The C.2.1 strip test still passes (no placeholder -> reject).
- (D) In-prod (rebuilt): GET+PUT /api/config/environmental round-trip ->
{"saved":true}; on-disk traffic.api_key stayed '${TOMTOM_API_KEY}'
(SECRET_REF_PRESERVED: True), not the literal key; disk restored to baseline.
consumer_config().deliver_policy == DeliverPolicy.NEW in the built image.
Follow-up for D rollout: the durable 'meshai-v04-central_quake_' created during
C.3 was made with deliver_policy=all; re-flipping a domain may need that stale
durable deleted on the Central NATS server first (config mismatch on re-subscribe).
D rollout (remaining domains) is now safe: GUI flips preserve secret refs and
new subscriptions don't replay huge backlogs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>