2 Commits
Author SHA1 Message Date
jensandClaude Sonnet 5 92b9bdc1ba config: generalize config_validate into a shared schema engine
require_schema(config, schema) is a generic recursive declarative
checker (nested-dict schema, leaves name required type(s), each
intermediate object node gets its own dict-type check so a wrong-typed
section is named directly instead of surfacing as a confusing "missing
child" error). validate_temp_ctrl() is now just require_schema(config,
TEMPCTRL_SCHEMA) against a declarative schema dict, replacing the
hand-rolled nested loops.

utils/sud_validate.py's static structural check ('steps' must be a
list) now goes through the same require_schema()/SUD_SCHEMA - one
shared mechanism for both server config.json and sud.json documents.
The genuinely dynamic per-step check (ramp.rate required only when a
step sets its own temperature) stays hand-written, since it depends on
the document's content, not just its shape.

Added TestRequireSchema, exercising the generic engine directly
against a schema unrelated to TempCtrl.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4oEE99rkKVU8L8tkzXWdG
2026-07-11 20:40:32 +02:00
jensandClaude Sonnet 5 0171cb20c7 config: fail fast on missing TempCtrl PID gains
Config access was unchecked dict[key] everywhere, so a missing/
misnamed gain (we've hit this once already: config.json.sim's gain/
Model nesting mismatch) surfaced as a bare KeyError from deep inside
some component's __init__ or first process() tick, with no indication
which config key was wrong.

utils/config_validate.py adds a small stdlib-only dotted-path checker
(no schema library - matches this project's stdlib-first leaning) and
validate_temp_ctrl(), scoped to the section that actually caused an
incident: TempCtrl.pid_type plus every kp/ki/kd/kt gain under
TempCtrl.Outer and TempCtrl.Inner.{Heat,Hold,Cool}. Called once in
server/brewpi.py right after json.load(), before any factory runs.
Optional-with-default keys (Outer.y_hold_min, Inner.Hold.yi_max,
Thresholds) stay optional here too.

Heater/Stirrer/TempSensor/Pot sections and unknown-key warnings are
deliberately left for later - see components/pid/TODO.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4oEE99rkKVU8L8tkzXWdG
2026-07-11 12:33:57 +02:00