Schema derived from Config::default() and the live config, help text for every shipped key, env locks and presence-only secrets, typed saves that preserve comments and validate through Config::load before an atomic rename, provider add/remove, the change history, and config reload on mtime. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHyYupFdBiR4VfoUM7NjSM
3.6 KiB
3.6 KiB
Step 5 handoff — settings
Landed
src/web/dashboard/settings.rs: a schema derived by walking serialized default and liveConfigvalues, including optional/env-only fields, exact field kinds and enum choices, derived environment names, source tracking, README/example-backed help text, stable group order, and dotted-path anchors./dashboard/settings: reload-on-mtime with a visible load-error banner and last-good config retention; secret presence-only rendering, environment locks, typed inputs, defaults/reset controls, and weight normalization notes.- Typed
toml_editsaves that preserve comments/order, collect field errors, write multiline string arrays, create missing tables, validate throughConfig::loadin<path>.tmp.<pid>, preserve permissions, rename atomically, swap the live config, and record one attributedconfig_changesrow per key. - Provider add/remove flows through the same validated writer, including name
and kind validation, role-reference refusal, placeholder defaults, audit
history, and redaction of a hand-written provider
api_keyfrom history. /dashboard/settings/history, newest first at 100 rows per page.- A step 5 CSS block and reset helper in
app.js;/etc/daily-epubadded to the server unit'sReadWritePaths. - Sixteen settings tests covering every schema and writer case listed in §17,
including router-level rendering and POST behavior through
oneshot.
Deviations and notes
- Shipped providers cannot be removed, even when unreferenced. They are members
of
Config::default(), so deleting their TOML table would immediately restore the built-in entry and falsely report success. They can be edited or left unreferenced; custom providers can be removed normally. FieldKind::EnumownsVec<String>rather than the plan sketch's static slice becausellm.bulkandllm.editormust include provider names derived at runtime. The rendered behavior and validation table are unchanged.- Restart notices also cover
server.public_url,server.session_days,server.login_attempts, andserver.login_window_minutes, in addition to the plan sketch'sdatabase_pathandserver.bind, because those values are captured when the server/session/throttle layers are built. - An absent key whose effective value is already the submitted default remains absent. This reconciles “only changed fields” with the no-JavaScript form posting every editable field; resetting an explicit non-default file value still writes the default explicitly.
- Step 6 should call
WebState::reload_if_changedbefore starting each job, as §4.2 requires. Step 5 supplies the shared helper; this branch's jobs module is intentionally still the parallel-step stub. - The shared brief's sandbox list omits three pre-existing OpenAI fake-server
tests that bind through the same
curate::llm::tests::servehelper as its four named Anthropic tests. The step 1 handoff records those three additional sandbox failures; they are not settings regressions.
Verification
cargo fmt: pass.cargo clippy --all-targets -- -D warnings: pass.- Focused
cargo test web::dashboard::settings -- --nocapture: 16 passed, 0 failed. - Unfiltered
cargo test: 379 library tests passed before the harness reported the expected loopback-bind failures (the 10 named library tests plus the three OpenAI tests noted above); no settings test failed. cargo testwith all pre-existing loopback listener tests excluded: 411 passed, 0 failed, 15 filtered out (379 library, 7 binary-unit, and 25 integration tests passed; 13 library listener tests and bothm7_servertests were filtered).