fix(MM-69): address PR review — UTF-8 safety, error context, pure core
Critical:
- config_loader: replace std::env::vars() with vars_os() + manual
EZPDS_* filter; non-UTF-8 env var values return ConfigError::Invalid
instead of panicking
- config: replace to_string_lossy() with .to_str().ok_or_else() for
the derived database_url default; non-UTF-8 data_dir is now an
explicit error at config-load time rather than silent corruption
Important:
- config: apply_env_overrides now takes RawConfig by value and returns
Result<RawConfig, ConfigError> — genuinely functional (no mutation)
- config: EZPDS_PORT parse errors now include the source ParseIntError
- config: ConfigError::Io is now a struct variant carrying the file
path, surfacing it without anyhow::Context
- config: add env_override_wins_over_toml_value test (precedence
contract was previously untested)
- config_loader: add loads_minimal_valid_toml_produces_missing_field_error
test (empty file → MissingField through the full I/O path)
- relay: tracing subscriber init uses .try_init() instead of .init();
panic on double-registration is now a structured error via run()
- Cargo.toml: move tempfile to workspace.dependencies per convention
- relay/main.rs: drop redundant (env: EZPDS_CONFIG) from CLI arg doc