Implements the first phase of ADR-0023 selective hot-reloading. Adds
viper.WatchConfig wiring + an OnConfigChange handler that re-unmarshals
the Config struct on file changes and applies the hot-reloadable subset.
Phase 1 reloadable field: logging.level — re-applied via SetupLogging
on every change. The remaining 3 fields listed in ADR-0023
(api.v2_enabled, telemetry sampler type/ratio, auth.jwt.ttl) follow the
same pattern and will land in subsequent phase PRs without further
infrastructure work.
Changes:
- pkg/config/config.go : Config struct gets unexported viper + reloadMu
fields; new WatchAndApply(ctx) method starts the watcher and stops it
on context cancel. Defensive: no-op when no config file is in use.
- pkg/server/server.go Run() : calls WatchAndApply(rootCtx) so the
watcher stops on graceful shutdown.
- pkg/config/config_hot_reload_test.go (new) : 3 unit tests covering
end-to-end reload, no-config-file no-op, nil-viper no-op. Race
detector clean.
- adr/0023-config-hot-reloading.md : Status → Phase 1 Implemented;
remaining fields explicitly Proposed for follow-up phases.
Verifier verdict: APPROVE. Race detector passes. Full BDD suite still
green. The @flaky scenario in features/config/config_hot_reloading.feature
remains @flaky for now — activating it requires reliable cross-process
file-watching behaviour which is sensitive to filesystem semantics on
the CI runner; the unit test exercises the same code path deterministically.