Melikshah commited on
Commit
5c44f63
·
verified ·
1 Parent(s): 91495a2

Upload folder using huggingface_hub

Browse files
DEMO_PLANS.md ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # DC-Ops: Scenario Demo Plans
2
+
3
+ > **All demos verified with 256/256 tests passing. Every plan resolves successfully in 8–10 steps.**
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ | # | Scenario | Facility | Steps | Reward | Key Skill Tested |
10
+ |---|----------|----------|-------|--------|-----------------|
11
+ | 1 | A1 — Setpoint Optimization | Default | **9** | +0.324 | Energy efficiency tuning (PUE optimization) |
12
+ | 2 | A2 — Thermal Event | Default | **8** | +0.873 | Single-failure incident response |
13
+ | 3 | A2 — Thermal Event | Large | **8** | +0.831 | Multi-zone awareness, H1 isolation |
14
+ | 4 | A4 — CRAC Cascade | Default | **8** | +1.230 | Multi-failure triage + load shedding |
15
+ | 5 | A4 — CRAC Cascade | Large | **8** | +1.150 | Multi-zone cascade with H1 envelope |
16
+ | 6 | B1 — UPS Alarm | Default | **8** | +0.512 | Power chain audit, alarm management |
17
+ | 7 | B3 — Generator Test | Default | **10** | +0.567 | 5-step protocol compliance |
18
+ | 8 | B4 — Power Failure | Default | **8** | +0.934 | Battery management, gen startup |
19
+ | 9 | B4 — Power Failure | Small | **8** | +0.948 | Aggressive load shedding at scale |
20
+
21
+ All demos resolve in **8–10 steps** and demonstrate proper operational procedure: **assess → diagnose → compensate → verify → resolve**.
22
+
23
+ ---
24
+
25
+ ## Demo 1: A1 — Cooling Setpoint Optimization
26
+
27
+ **Facility:** Default (2 zones, 160 kW, 4 CRACs)
28
+ **Difficulty:** Easy | **Budget:** 10 steps | **Result:** Resolved in 9 steps, cumulative reward **+0.324**
29
+
30
+ ### Context
31
+
32
+ All four CRACs are set to 15°C — far below what the servers need. This wastes energy: the compressors run hard, fans blow at 100%, and PUE sits at 1.87. ASHRAE A2 class allows inlet temps up to 27°C. The agent must raise setpoints and reduce fan speeds to approach the PUE target of 1.6 without overheating.
33
+
34
+ ### Step-by-Step
35
+
36
+ | Step | Command | Reward | Cumul | PUE | Inlets (A/B) | Reasoning |
37
+ |------|---------|--------|-------|-----|-------------|-----------|
38
+ | 1 | `check_status` | +0.131 | +0.131 | 1.87 | 17.1 / 17.1 | **Procedure rule:** must check status before adjusting setpoints (+0.2 bonus). Establishes baseline — all CRACs at 15°C, PUE 1.87, inlet temps far below recommended range. |
39
+ | 2 | `adjust_setpoint CRAC-1 24` | +0.047 | +0.178 | 1.80 | 17.7 / 17.1 | Raise from 15→24°C. CRAC-1 compressor works less → immediate PUE drop. Supply temp lags ~30s behind the setpoint due to first-order thermal lag. |
40
+ | 3 | `adjust_setpoint CRAC-2 24` | +0.039 | +0.217 | 1.76 | 19.2 / 17.0 | Same for CRAC-2. PUE continues falling. Zone A inlets rising as CRACs supply warmer air — still safely below 27°C limit. |
41
+ | 4 | `adjust_setpoint CRAC-3 24` | +0.038 | +0.255 | 1.71 | 20.7 / 17.6 | Zone B beginning to respond. The thermal mass (11.1 kJ/K per server) causes gradual warming — the RC network models this physical inertia. |
42
+ | 5 | `adjust_setpoint CRAC-4 24` | +0.025 | +0.280 | 1.69 | 21.9 / 19.1 | All CRACs at 24°C. PUE at 1.69 — still above 1.6 target. Diminishing returns from setpoint-only optimization; fan power reduction is the next lever. |
43
+ | 6 | `set_fan_speed CRAC-1 70` | −0.019 | +0.261 | 1.68 | 22.8 / 20.6 | Reduce fan from 100→70%. Fan power follows **cubic affinity law**: P = P_rated × (speed%)³. At 70%, fan power = 34% of rated — a 66% power reduction per CRAC fan. |
44
+ | 7 | `set_fan_speed CRAC-2 70` | −0.017 | +0.244 | 1.66 | 23.4 / 21.9 | PUE 1.66 — getting close. Inlet temps at 23.4°C — still 3.6°C below ASHRAE A2 recommended max (27°C). |
45
+ | 8 | `set_fan_speed CRAC-3 70` | −0.012 | +0.232 | 1.63 | 23.9 / 22.7 | Almost there. The diminishing negative rewards show the system approaching equilibrium. |
46
+ | 9 | `set_fan_speed CRAC-4 70` | **+0.092** | **+0.324** | **1.60** | 24.3 / 23.3 | **✓ RESOLVED.** PUE hits target (≤1.6). All inlets within ASHRAE recommended range (18–27°C). Speed bonus: (10−9)/10 = +0.1. |
47
+
48
+ ### Why This Works
49
+
50
+ The agent follows a two-phase optimization strategy:
51
+
52
+ 1. **Phase 1 (steps 2–5): Setpoint adjustment.** Raising setpoints from 15→24°C reduces compressor load. PUE drops 1.87→1.69 (10% improvement). But setpoint changes alone can't reach 1.6 because fan power is a significant fraction of total cooling power.
53
+
54
+ 2. **Phase 2 (steps 6–9): Fan speed reduction.** The cubic fan law means reducing speed from 100→70% cuts fan power by 66%. This pushes PUE from 1.69→1.60, crossing the target.
55
+
56
+ ---
57
+
58
+ ## Demo 2: A2 — Thermal Event Response (Default Facility)
59
+
60
+ **Facility:** Default (2 zones, 160 kW, 4 CRACs)
61
+ **Difficulty:** Medium | **Budget:** 15 steps | **Result:** Resolved in 8 steps, cumulative reward **+0.873**
62
+
63
+ ### Context
64
+
65
+ CRAC-3 compressor has failed. With only 3 of 4 CRACs operational, cooling capacity is reduced. The default facility has N+1 redundancy, so temperatures won't spike catastrophically, but the agent must diagnose the fault and compensate to ensure long-term stability.
66
+
67
+ ### Step-by-Step
68
+
69
+ | Step | Command | Reward | Cumul | Inlets (A/B) | Reasoning |
70
+ |------|---------|--------|-------|-------------|-----------|
71
+ | 1 | `check_status` | +0.204 | +0.204 | 19.8 / 20.0 | Assess the situation. Dashboard shows CRAC-3 as "!! COMPRESSOR" with no supply temp, no airflow, 0 kW. Zone B slightly warmer — the lost CRAC served zone B. |
72
+ | 2 | `diagnose CRAC-3` | +0.054 | +0.258 | 19.8 / 20.2 | **Unlocks the resolution gate.** Diagnostic report confirms "FAULT DETECTED: compressor." Procedure rule rewards diagnosing before adjusting (+0.3 bonus on subsequent setpoint changes). |
73
+ | 3 | `diagnose CRAC-1` | −0.021 | +0.237 | 19.8 / 20.4 | Verify remaining CRACs are healthy. Report: "No faults detected. Unit operating normally." |
74
+ | 4 | `adjust_setpoint CRAC-1 16` | +0.034 | +0.270 | 19.6 / 20.5 | Lower setpoint 18→16°C on a surviving CRAC. Increases cooling output. Earns procedure bonus (diagnosis was done first). |
75
+ | 5 | `adjust_setpoint CRAC-2 16` | +0.034 | +0.304 | 19.3 / 20.6 | Both zone A CRACs now overcooling to compensate. Zone A cools to 19.3°C while zone B stabilizes around 20.6°C. |
76
+ | 6 | `set_fan_speed CRAC-1 100` | +0.034 | +0.338 | 19.0 / 20.8 | Ensure max airflow on surviving CRACs. |
77
+ | 7 | `set_fan_speed CRAC-2 100` | +0.034 | +0.372 | 18.7 / 20.8 | Zone B stabilizing at ~20.8°C — well within ASHRAE A2 recommended range (27°C max). |
78
+ | 8 | `set_fan_speed CRAC-4 100` | **+0.501** | **+0.873** | 18.5 / 20.9 | **✓ RESOLVED.** All zones within recommended range for 2+ consecutive stable steps. Speed bonus: (15−8)/15 = +0.467. |
79
+
80
+ ---
81
+
82
+ ## Demo 3: A2 — Thermal Event Response (Large Facility)
83
+
84
+ **Facility:** Large (4 zones, 600 kW, 8 CRACs including H1 zone)
85
+ **Difficulty:** Medium | **Budget:** 15 steps | **Result:** Resolved in 8 steps, cumulative reward **+0.831**
86
+
87
+ ### Context
88
+
89
+ Same CRAC-3 failure, but in a larger facility with 4 zones including an H1 (high-density GPU) zone. The H1 zone has a tighter thermal envelope (recommended max 22°C vs 27°C for A2).
90
+
91
+ ### Step-by-Step
92
+
93
+ | Step | Command | Reward | Cumul | Inlets (A/B/C/D) | Reasoning |
94
+ |------|---------|--------|-------|-------------------|-----------|
95
+ | 1 | `check_status` | +0.207 | +0.207 | 20.0 / 20.8 / 19.2 / 19.7 | 4-zone dashboard. Zone B already 0.8°C warmer. Zone C (H1) at 19.2°C — only 2.8°C below its 22°C recommended max. |
96
+ | 2 | `diagnose CRAC-3` | +0.057 | +0.263 | 20.0 / 21.6 / 19.2 / 19.7 | FAULT: compressor. Zone B rising +0.8°C/step. Zone C stable — dedicated CRACs unaffected. |
97
+ | 3 | `diagnose CRAC-1` | −0.019 | +0.245 | 20.0 / 22.3 / 19.2 / 19.6 | Confirm CRAC-1 healthy. |
98
+ | 4 | `diagnose CRAC-2` | −0.019 | +0.225 | 20.0 / 23.0 / 19.2 / 19.6 | Confirm CRAC-2 healthy. Thorough diagnosis of all CRACs in the affected zone pair. |
99
+ | 5 | `adjust_setpoint CRAC-2 16` | +0.035 | +0.261 | 19.9 / 23.6 / 19.2 / 19.6 | Lower setpoint on surviving zone B CRAC. Procedure bonus earned (diagnosed first). |
100
+ | 6 | `adjust_setpoint CRAC-4 16` | +0.035 | +0.296 | 19.7 / 24.0 / 19.2 / 19.6 | Zone B rate of rise slowing — compensation taking effect. |
101
+ | 7 | `set_fan_speed CRAC-2 100` | +0.035 | +0.330 | 19.6 / 24.3 / 19.2 / 19.6 | Max airflow. Zone B at 24.3°C — 2.7°C below ASHRAE A2 recommended max. |
102
+ | 8 | `set_fan_speed CRAC-4 100` | **+0.501** | **+0.831** | 19.5 / 24.6 / 19.2 / 19.6 | **✓ RESOLVED.** Zone B stabilized at 24.6°C. H1 zone completely unaffected (19.2°C). Speed bonus: +0.467. |
103
+
104
+ ### Default vs Large Comparison
105
+
106
+ | Metric | Default | Large |
107
+ |--------|---------|-------|
108
+ | Max inlet temp | 20.9°C | 24.6°C |
109
+ | H1 zone impact | N/A | None (19.2°C) |
110
+ | Cumulative reward | +0.873 | +0.831 |
111
+
112
+ ---
113
+
114
+ ## Demo 4: A4 — CRAC Failure Cascade (Default Facility)
115
+
116
+ **Facility:** Default (2 zones, 160 kW, 4 CRACs)
117
+ **Difficulty:** Hard | **Budget:** 20 steps | **Result:** Resolved in 8 steps, cumulative reward **+1.230**
118
+
119
+ ### Context
120
+
121
+ Two CRACs fail simultaneously: CRAC-1 (compressor) and CRAC-3 (fan). Only CRAC-2 and CRAC-4 remain operational — 50% cooling capacity lost. The agent must diagnose both failures, aggressively compensate, and consider load shedding.
122
+
123
+ ### Step-by-Step
124
+
125
+ | Step | Command | Reward | Cumul | Inlets (A/B) | Reasoning |
126
+ |------|---------|--------|-------|-------------|-----------|
127
+ | 1 | `check_status` | +0.212 | +0.212 | 19.9 / 19.9 | Dashboard shows two red-flagged CRACs. 50% cooling capacity lost. |
128
+ | 2 | `diagnose CRAC-1` | +0.062 | +0.274 | 20.0 / 20.0 | "FAULT DETECTED: compressor." First of two required diagnoses. |
129
+ | 3 | `diagnose CRAC-3` | +0.027 | +0.301 | 20.1 / 20.1 | "FAULT DETECTED: fan." Both failures identified → resolution gate unlocked. Extra +0.2 procedure bonus for diagnosing both units. |
130
+ | 4 | `adjust_setpoint CRAC-2 16` | +0.062 | +0.363 | 20.2 / 20.2 | Lower surviving CRAC setpoint. Procedure bonus (+0.2) earned because diagnosis preceded this. |
131
+ | 5 | `adjust_setpoint CRAC-4 16` | +0.062 | +0.425 | 20.2 / 20.3 | Both survivors at aggressive 16°C setpoints. |
132
+ | 6 | `set_fan_speed CRAC-2 100` | +0.062 | +0.487 | 20.1 / 20.2 | Confirm max airflow. Temps stabilizing. |
133
+ | 7 | `set_fan_speed CRAC-4 100` | +0.062 | +0.549 | 20.1 / 20.2 | Temps flat at ~20.1°C. Stable for consecutive steps. |
134
+ | 8 | `set_rack_load B-05 4` | **+0.681** | **+1.230** | 20.0 / 20.1 | **✓ RESOLVED.** Load shed on hottest rack as precaution. Speed bonus: (20−8)/20 = +0.600. |
135
+
136
+ ### Why Load Shedding Matters
137
+
138
+ Reducing rack B-05 from 8 kW to 4 kW:
139
+ - Provides additional thermal margin (less heat to extract)
140
+ - Demonstrates workload migration capability
141
+ - Earns action quality bonus (+0.2 for interventions)
142
+
143
+ ---
144
+
145
+ ## Demo 5: A4 — CRAC Failure Cascade (Large Facility)
146
+
147
+ **Facility:** Large (4 zones, 600 kW, 8 CRACs)
148
+ **Difficulty:** Hard | **Budget:** 20 steps | **Result:** Resolved in 8 steps, cumulative reward **+1.150**
149
+
150
+ ### Step-by-Step
151
+
152
+ | Step | Command | Reward | Cumul | Inlets (A/B/C/D) | Reasoning |
153
+ |------|---------|--------|-------|-------------------|-----------|
154
+ | 1 | `check_status` | +0.210 | +0.210 | 20.4 / 20.4 / 19.2 / 19.7 | CRAC-1 and CRAC-3 down out of 8. Zones C/D (including H1) have their own CRACs. |
155
+ | 2 | `diagnose CRAC-1` | +0.059 | +0.269 | 20.8 / 20.8 / 19.2 / 19.7 | FAULT: compressor. Zone A/B rising ~0.4°C/step. |
156
+ | 3 | `diagnose CRAC-3` | +0.024 | +0.293 | 21.2 / 21.2 / 19.2 / 19.7 | FAULT: fan. Both diagnosed — resolution gate unlocked. |
157
+ | 4 | `diagnose CRAC-2` | +0.024 | +0.317 | 21.6 / 21.6 / 19.2 / 19.7 | Verify CRAC-2 healthy. With 2 failures, confirming survivor health is critical. |
158
+ | 5 | `adjust_setpoint CRAC-2 16` | +0.059 | +0.376 | 21.9 / 22.0 / 19.2 / 19.6 | Compensate. Zone B at 22.0°C — 13°C below ASHRAE A2 allowable max (35°C). |
159
+ | 6 | `adjust_setpoint CRAC-4 16` | +0.058 | +0.434 | 22.2 / 22.3 / 19.2 / 19.6 | Rate of rise slowing. H1 zone completely unaffected. |
160
+ | 7 | `set_fan_speed CRAC-2 100` | +0.058 | +0.492 | 22.5 / 22.5 / 19.2 / 19.6 | Max airflow on survivor. Zone B stabilizing. |
161
+ | 8 | `set_fan_speed CRAC-4 100` | **+0.658** | **+1.150** | 22.7 / 22.8 / 19.2 / 19.6 | **✓ RESOLVED.** All zones within allowable. Speed bonus: +0.600. |
162
+
163
+ ### Default vs Large Comparison
164
+
165
+ | Metric | Default | Large |
166
+ |--------|---------|-------|
167
+ | Final zone B inlet | 20.1°C | 22.8°C |
168
+ | H1 zone impact | N/A | None (19.2°C) |
169
+ | Cumulative reward | +1.230 | +1.150 |
170
+
171
+ ---
172
+
173
+ ## Demo 6: B1 — UPS Alarm Response
174
+
175
+ **Facility:** Default (2 zones, 160 kW)
176
+ **Difficulty:** Medium | **Budget:** 10 steps | **Result:** Resolved in 8 steps, cumulative reward **+0.512**
177
+
178
+ ### Context
179
+
180
+ A brief utility dip caused UPS-1 to transfer to battery. Utility has been restored and UPS switched back to double-conversion mode, but the alarm persists. The agent must investigate the entire power chain and acknowledge the alarm.
181
+
182
+ ### Step-by-Step
183
+
184
+ | Step | Command | Reward | Cumul | Reasoning |
185
+ |------|---------|--------|-------|-----------|
186
+ | 1 | `check_status` | −0.007 | −0.007 | Baseline assessment. Dashboard shows utility NORMAL, generator OFF, ATS on UTILITY. |
187
+ | 2 | `diagnose UPS-1` | +0.143 | +0.137 | **Key step.** Report: mode=double_conversion, SOC=86%. Resolution gate requires this diagnosis. |
188
+ | 3 | `diagnose UPS-2` | −0.007 | +0.130 | Verify redundant UPS. mode=double_conversion, SOC=87%. |
189
+ | 4 | `diagnose GEN-1` | −0.007 | +0.123 | Generator in standby and ready — confirming readiness is proper procedure. |
190
+ | 5 | `diagnose PDU-A-01` | −0.007 | +0.117 | Verify power distribution is intact. |
191
+ | 6 | `check_status` | −0.007 | +0.110 | Re-verify overall state before closing incident. |
192
+ | 7 | `diagnose PDU-B-01` | −0.007 | +0.103 | Complete the power chain audit. |
193
+ | 8 | `acknowledge_alarm` | **+0.408** | **+0.512** | **✓ RESOLVED.** Alarm acknowledged after thorough investigation. Speed bonus: (10−8)/10 = +0.200. |
194
+
195
+ ### Reward Structure Note
196
+
197
+ Steps 3–7 return −0.007 each because the delta-based progress metric doesn't change during investigation — only the final acknowledgment triggers progress completion. The cumulative reward is still positive (+0.512) thanks to the large resolution step reward.
198
+
199
+ ---
200
+
201
+ ## Demo 7: B3 — Generator Test Protocol
202
+
203
+ **Facility:** Default (2 zones, 160 kW)
204
+ **Difficulty:** Easy | **Budget:** 15 steps | **Result:** Resolved in 10 steps, cumulative reward **+0.567**
205
+
206
+ ### Context
207
+
208
+ Routine monthly generator test. No fault, no emergency — the agent must follow the 5-step protocol: check → start → verify → stop → acknowledge.
209
+
210
+ ### Step-by-Step
211
+
212
+ | Step | Command | Reward | Cumul | Generator State | Reasoning |
213
+ |------|---------|--------|-------|----------------|-----------|
214
+ | 1 | `check_status` | −0.007 | −0.007 | OFF | Baseline. All systems normal. |
215
+ | 2 | `diagnose GEN-1` | −0.007 | −0.013 | off | Pre-test inspection — verify before starting. |
216
+ | 3 | `start_generator` | +0.113 | +0.100 | START_DELAY→CRANKING | Generator start sequence initiated. |
217
+ | 4 | `wait` | −0.022 | +0.078 | READY/LOADED | Let the generator complete warmup. |
218
+ | 5 | `diagnose GEN-1` | +0.043 | +0.122 | ready | **Critical verification.** Confirms generator running properly. |
219
+ | 6 | `check_status` | −0.007 | +0.115 | LOADED | Full dashboard confirms generator loaded. |
220
+ | 7 | `stop_generator` | +0.113 | +0.228 | COOLDOWN | Initiate cooldown (300s for turbocharger). |
221
+ | 8 | `wait` | −0.022 | +0.207 | COOLDOWN | Allow cooldown to proceed. |
222
+ | 9 | `diagnose GEN-1` | −0.032 | +0.175 | cooldown | Post-shutdown inspection. |
223
+ | 10 | `acknowledge_alarm` | **+0.392** | **+0.567** | COOLDOWN | **✓ RESOLVED.** Protocol complete: started ✓, verified ✓, stopped ✓, acknowledged ✓. Speed bonus: (15−10)/15 = +0.333. |
224
+
225
+ ### Protocol Enforcement
226
+
227
+ B3 tracks four internal flags that must be set in order:
228
+
229
+ 1. `_started` — `start_generator` issued
230
+ 2. `_verified` — `diagnose GEN-1` while generator is running
231
+ 3. `_stopped` — `stop_generator` (only if started + verified)
232
+ 4. `_completed` — `acknowledge_alarm` (only if stopped)
233
+
234
+ The agent **cannot skip steps** — issuing `stop_generator` before `diagnose GEN-1` won't set `_stopped`.
235
+
236
+ ---
237
+
238
+ ## Demo 8: B4 — Power Failure Cascade (Default Facility)
239
+
240
+ **Facility:** Default (2 zones, 160 kW)
241
+ **Difficulty:** Hard | **Budget:** 20 steps | **Result:** Resolved in 8 steps, cumulative reward **+0.934**
242
+
243
+ ### Context
244
+
245
+ Total utility power loss. UPS batteries bridging while generator starts. Generator warmup extended (15s vs default 8s). Agent must manage battery life, consider load shedding, and verify generator operation.
246
+
247
+ ### Step-by-Step
248
+
249
+ | Step | Command | Reward | Cumul | Key Metrics | Reasoning |
250
+ |------|---------|--------|-------|-------------|-----------|
251
+ | 1 | `check_status` | +0.108 | +0.108 | UPS on battery, SOC ~97% | Utility LOST. ATS initiating transfer. Generator auto-starting. |
252
+ | 2 | `diagnose UPS-1` | +0.131 | +0.239 | mode=on_battery, SOC=95% | **Resolution gate unlocked.** Battery draining ~2%/step at 160 kW load. |
253
+ | 3 | `diagnose UPS-2` | +0.078 | +0.317 | mode=on_battery, SOC=90% | Redundant UPS also on battery. |
254
+ | 4 | `start_generator` | −0.007 | +0.310 | Gen: CRANKING→READY | Generator already auto-starting — hence slight negative reward for redundant command. |
255
+ | 5 | `set_rack_load A-05 4` | +0.062 | +0.371 | IT load: 156 kW | Shed 4 kW to extend battery life. |
256
+ | 6 | `set_rack_load B-05 4` | +0.054 | +0.425 | IT load: 152 kW | Total shed: 8 kW (5% of IT load). Conservative but effective. |
257
+ | 7 | `wait` | −0.052 | +0.373 | Gen: LOADED, ATS: GEN | Generator online. UPS batteries begin recharging. |
258
+ | 8 | `diagnose GEN-1` | **+0.561** | **+0.934** | state=loaded | **✓ RESOLVED.** All conditions met: gen loaded, temps OK, SOC >10%. Speed bonus: (20−8)/20 = +0.600. |
259
+
260
+ ### Battery SOC Timeline
261
+
262
+ | Step | Sim Time | SOC (UPS-1) | Event |
263
+ |------|----------|-------------|-------|
264
+ | 0 | 0 min | 97% | Utility lost |
265
+ | 2 | 2 min | 95% | Diagnosed |
266
+ | 4 | 4 min | ~90% | Gen starting |
267
+ | 6 | 6 min | ~87% | Load shed |
268
+ | 7 | 7 min | ~88% | Gen loaded, recharging begins |
269
+ | 8 | 8 min | ~89% | Resolved |
270
+
271
+ ---
272
+
273
+ ## Demo 9: B4 — Power Failure Cascade (Small Facility)
274
+
275
+ **Facility:** Small (1 zone, 80 kW, 2 CRACs)
276
+ **Difficulty:** Hard | **Budget:** 20 steps | **Result:** Resolved in 8 steps, cumulative reward **+0.948**
277
+
278
+ ### Step-by-Step
279
+
280
+ | Step | Command | Reward | Cumul | Key Metrics | Reasoning |
281
+ |------|---------|--------|-------|-------------|-----------|
282
+ | 1 | `check_status` | +0.111 | +0.111 | 1 zone, UPS on battery | Smaller facility: 80 kW IT load, 1 zone, 2 CRACs. Less redundancy. |
283
+ | 2 | `diagnose UPS-1` | +0.133 | +0.244 | SOC=91% | Battery draining faster relative to capacity. Gate unlocked. |
284
+ | 3 | `start_generator` | +0.073 | +0.317 | Gen starting | Explicit start command. |
285
+ | 4 | `set_rack_load A-05 4` | +0.066 | +0.383 | IT: 76 kW | 5% load reduction. |
286
+ | 5 | `set_rack_load A-04 4` | +0.056 | +0.438 | IT: 72 kW | 10% load reduction. |
287
+ | 6 | `set_rack_load A-03 4` | +0.042 | +0.481 | IT: 68 kW | 15% total load shed — more aggressive for smaller facility. |
288
+ | 7 | `wait` | −0.069 | +0.412 | Gen LOADED | Generator online. Battery recharging. |
289
+ | 8 | `diagnose GEN-1` | **+0.537** | **+0.948** | state=loaded | **✓ RESOLVED.** Speed bonus: +0.600. |
290
+
291
+ ### Small vs Default Comparison
292
+
293
+ | Metric | Default (160 kW) | Small (80 kW) |
294
+ |--------|-----------------|---------------|
295
+ | Racks shed | 2 (8 kW, 5%) | 3 (12 kW, 15%) |
296
+ | Cumulative reward | +0.934 | +0.948 |
297
+
298
+ The small facility earns slightly higher reward due to more aggressive proportional load shedding, producing a stronger positive signal from the power safety component.
299
+
300
+ ---
301
+
302
+ ## Resolution Gate Design
303
+
304
+ Each affected scenario requires the agent to actually **do something** before resolution:
305
+
306
+ | Scenario | Diagnosis Gate | Min Steps |
307
+ |----------|---------------|-----------|
308
+ | A2 | Must `diagnose CRAC-3` | ≥ 8 steps |
309
+ | A4 | Must `diagnose CRAC-1` AND `diagnose CRAC-3` | ≥ 8 steps |
310
+ | B4 | Must `diagnose UPS-*` | ≥ 8 steps |
311
+
312
+ Without these gates, scenarios A2, A4, and B4 would auto-resolve within 2–3 steps of passive `wait` commands due to:
313
+
314
+ - N+1 cooling redundancy handling CRAC failures naturally
315
+ - Generator auto-start/load completing within one 60-second agent step
316
+ - `resolved` only checking `_stable_count >= 2` with no gate on agent behavior
317
+
318
+ **Reward ordering validates the design:** fast diagnosis > late diagnosis > no diagnosis (never resolves).
scenarios/power_scenarios.py CHANGED
@@ -352,7 +352,7 @@ class PowerFailureCascade(Scenario):
352
  """
353
 
354
  _CONSECUTIVE_STABLE_STEPS = 2
355
- _MIN_STEPS_BEFORE_RESOLUTION = 4 # Hard scenario needs investigation
356
 
357
  def __init__(self) -> None:
358
  super().__init__()
 
352
  """
353
 
354
  _CONSECUTIVE_STABLE_STEPS = 2
355
+ _MIN_STEPS_BEFORE_RESOLUTION = 8 # Hard scenario needs investigation
356
 
357
  def __init__(self) -> None:
358
  super().__init__()
scenarios/thermal_scenarios.py CHANGED
@@ -161,7 +161,7 @@ class ThermalEventResponse(Scenario):
161
 
162
  _FAILED_UNIT = "CRAC-3"
163
  _CONSECUTIVE_STABLE_STEPS = 2
164
- _MIN_STEPS_BEFORE_RESOLUTION = 5 # Agent must take at least 5 actions
165
 
166
  def __init__(self) -> None:
167
  super().__init__()
@@ -321,7 +321,7 @@ class CRACFailureCascade(Scenario):
321
  ("CRAC-3", CRACFaultType.FAN),
322
  ]
323
  _CONSECUTIVE_STABLE_STEPS = 2
324
- _MIN_STEPS_BEFORE_RESOLUTION = 5 # Hard scenario needs investigation time
325
 
326
  def __init__(self) -> None:
327
  super().__init__()
 
161
 
162
  _FAILED_UNIT = "CRAC-3"
163
  _CONSECUTIVE_STABLE_STEPS = 2
164
+ _MIN_STEPS_BEFORE_RESOLUTION = 8 # Agent must take at least 8 actions
165
 
166
  def __init__(self) -> None:
167
  super().__init__()
 
321
  ("CRAC-3", CRACFaultType.FAN),
322
  ]
323
  _CONSECUTIVE_STABLE_STEPS = 2
324
+ _MIN_STEPS_BEFORE_RESOLUTION = 8 # Hard scenario needs investigation time
325
 
326
  def __init__(self) -> None:
327
  super().__init__()
server/static/index.html CHANGED
@@ -319,6 +319,96 @@ body{background:var(--bg);color:var(--text);font-family:var(--font-sans);min-hei
319
  .guide-table{font-size:0.7rem}
320
  .guide-table th,.guide-table td{padding:0.375rem 0.5rem}
321
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  </style>
323
  </head>
324
  <body>
@@ -335,6 +425,7 @@ body{background:var(--bg);color:var(--text);font-family:var(--font-sans);min-hei
335
  </div>
336
  <div class="header-tabs">
337
  <button class="tab-btn active" data-tab="console" onclick="switchTab('console')">Console</button>
 
338
  <button class="tab-btn" data-tab="guide" onclick="switchTab('guide')">Guide</button>
339
  </div>
340
  <div class="mobile-toggles">
@@ -524,6 +615,488 @@ Pick a scenario to start
524
  </div>
525
  </div><!-- /tabConsole -->
526
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
  <!-- Guide Tab -->
528
  <div class="guide-page" id="tabGuide">
529
  <div class="guide-inner">
@@ -1376,19 +1949,43 @@ function switchTab(tab) {
1376
  document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
1377
  document.querySelector(`.tab-btn[data-tab="${tab}"]`).classList.add('active');
1378
 
1379
- // Console tab uses display:contents, guide uses display:block
1380
  const consoleEl = document.getElementById('tabConsole');
 
1381
  const guideEl = document.getElementById('tabGuide');
 
 
 
 
 
1382
  if (tab === 'console') {
1383
  consoleEl.classList.add('active');
1384
- guideEl.classList.remove('active');
 
 
1385
  } else {
1386
- consoleEl.classList.remove('active');
1387
  guideEl.classList.add('active');
1388
  guideEl.scrollTop = 0;
1389
  }
1390
  }
1391
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1392
  // ─── Build weight profile visualizations ─────────────────────────────
1393
  function buildWeightProfiles() {
1394
  const profiles = {
 
319
  .guide-table{font-size:0.7rem}
320
  .guide-table th,.guide-table td{padding:0.375rem 0.5rem}
321
  }
322
+
323
+ /* ─── Demos Page ─── */
324
+ .demos-page{display:none;overflow-y:auto;padding:2rem 1.5rem;background:var(--bg)}
325
+ .demos-page.active{display:block}
326
+ .demos-inner{max-width:1000px;margin:0 auto}
327
+ .demos-hero{text-align:center;padding:2rem 1rem 1.5rem;margin-bottom:1.5rem}
328
+ .demos-hero h1{font-size:2rem;font-weight:800;letter-spacing:-0.03em;margin-bottom:0.5rem}
329
+ .demos-hero h1 span{color:var(--accent)}
330
+ .demos-hero p{color:var(--text-dim);font-size:0.9rem;max-width:620px;margin:0 auto;line-height:1.7}
331
+
332
+ /* Demo overview table */
333
+ .demo-overview{width:100%;border-collapse:collapse;font-size:0.78rem;margin:0 0 2rem;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
334
+ .demo-overview thead{background:var(--bg-card)}
335
+ .demo-overview th{text-align:left;padding:0.625rem 0.875rem;font-weight:600;color:var(--text);border-bottom:1px solid var(--border);font-size:0.72rem;text-transform:uppercase;letter-spacing:0.05em}
336
+ .demo-overview td{padding:0.5rem 0.875rem;border-bottom:1px solid var(--border);color:var(--text-dim);vertical-align:middle}
337
+ .demo-overview tr:last-child td{border-bottom:none}
338
+ .demo-overview tbody tr{cursor:pointer;transition:background 0.15s}
339
+ .demo-overview tbody tr:hover{background:var(--bg-card-hover)}
340
+ .demo-overview code{font-family:var(--font-mono);font-size:0.75rem;color:var(--cyan);background:var(--terminal-bg);padding:0.1rem 0.375rem;border-radius:3px}
341
+
342
+ /* Demo accordion items */
343
+ .demo-item{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);margin-bottom:1rem;overflow:hidden;transition:border-color 0.2s}
344
+ .demo-item:hover{border-color:rgba(59,130,246,0.3)}
345
+ .demo-item.open{border-color:var(--accent)}
346
+ .demo-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;cursor:pointer;user-select:none;gap:1rem}
347
+ .demo-header:hover{background:rgba(255,255,255,0.02)}
348
+ .demo-header-left{display:flex;align-items:center;gap:0.875rem;min-width:0}
349
+ .demo-badge{font-family:var(--font-mono);font-weight:800;font-size:0.85rem;color:var(--accent);background:rgba(59,130,246,0.1);padding:0.3rem 0.625rem;border-radius:var(--radius);white-space:nowrap}
350
+ .demo-title-block{min-width:0}
351
+ .demo-title-block h3{font-size:0.9rem;font-weight:700;color:var(--text);margin-bottom:0.15rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
352
+ .demo-title-block .demo-subtitle{font-size:0.72rem;color:var(--text-muted);display:flex;gap:0.75rem;flex-wrap:wrap}
353
+ .demo-title-block .demo-subtitle span{display:inline-flex;align-items:center;gap:0.25rem}
354
+ .demo-header-right{display:flex;align-items:center;gap:0.75rem;flex-shrink:0}
355
+ .demo-reward{font-family:var(--font-mono);font-weight:700;font-size:0.85rem;color:var(--green)}
356
+ .demo-chevron{width:20px;height:20px;color:var(--text-muted);transition:transform 0.2s;flex-shrink:0}
357
+ .demo-item.open .demo-chevron{transform:rotate(180deg)}
358
+ .demo-body{display:none;padding:0 1.25rem 1.25rem;animation:fadeIn 0.2s ease}
359
+ .demo-item.open .demo-body{display:block}
360
+ @keyframes fadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
361
+
362
+ /* Demo context */
363
+ .demo-context{background:var(--terminal-bg);border:1px solid var(--border);border-radius:var(--radius);padding:0.875rem 1rem;margin-bottom:1rem;font-size:0.8rem;color:var(--text-dim);line-height:1.65}
364
+
365
+ /* Demo step table */
366
+ .demo-steps{width:100%;border-collapse:collapse;font-size:0.75rem;margin:0.75rem 0;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
367
+ .demo-steps thead{background:rgba(59,130,246,0.06)}
368
+ .demo-steps th{text-align:left;padding:0.5rem 0.625rem;font-weight:600;color:var(--text);border-bottom:1px solid var(--border);font-size:0.68rem;text-transform:uppercase;letter-spacing:0.05em}
369
+ .demo-steps td{padding:0.4rem 0.625rem;border-bottom:1px solid var(--border);color:var(--text-dim);vertical-align:top;line-height:1.5}
370
+ .demo-steps tr:last-child td{border-bottom:none}
371
+ .demo-steps tbody tr:hover{background:var(--bg-card-hover)}
372
+ .demo-steps code{font-family:var(--font-mono);font-size:0.72rem;color:var(--cyan);background:var(--terminal-bg);padding:0.1rem 0.35rem;border-radius:3px;white-space:nowrap}
373
+ .demo-steps .step-num{font-family:var(--font-mono);font-weight:700;color:var(--text-muted);width:28px}
374
+ .demo-steps .rew-pos{color:var(--green);font-weight:600;font-family:var(--font-mono)}
375
+ .demo-steps .rew-neg{color:var(--red);font-weight:600;font-family:var(--font-mono)}
376
+ .demo-steps .rew-big{color:var(--green);font-weight:800;font-family:var(--font-mono)}
377
+ .demo-steps .resolved-row{background:rgba(34,197,94,0.06)}
378
+
379
+ /* Demo analysis box */
380
+ .demo-analysis{background:var(--terminal-bg);border:1px solid var(--border);border-radius:var(--radius);padding:0.875rem 1rem;margin-top:1rem;font-size:0.78rem;color:var(--text-dim);line-height:1.65}
381
+ .demo-analysis h4{font-size:0.8rem;font-weight:700;color:var(--text);margin-bottom:0.5rem}
382
+ .demo-analysis ul{padding-left:1.25rem;margin:0.5rem 0}
383
+ .demo-analysis li{margin-bottom:0.25rem}
384
+ .demo-analysis strong{color:var(--text)}
385
+
386
+ /* Demo comparison tables */
387
+ .demo-compare{width:100%;border-collapse:collapse;font-size:0.75rem;margin:0.75rem 0;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
388
+ .demo-compare thead{background:var(--bg-card)}
389
+ .demo-compare th{padding:0.4rem 0.625rem;font-weight:600;color:var(--text);border-bottom:1px solid var(--border);font-size:0.68rem;text-transform:uppercase;text-align:left}
390
+ .demo-compare td{padding:0.375rem 0.625rem;border-bottom:1px solid var(--border);color:var(--text-dim);font-family:var(--font-mono);font-size:0.72rem}
391
+ .demo-compare tr:last-child td{border-bottom:none}
392
+
393
+ /* Resolution gate table */
394
+ .demo-gate-table{width:100%;border-collapse:collapse;font-size:0.78rem;margin:1rem 0;border:1px solid var(--border);border-radius:var(--radius);overflow:hidden}
395
+ .demo-gate-table thead{background:rgba(239,68,68,0.06)}
396
+ .demo-gate-table th{text-align:left;padding:0.5rem 0.75rem;font-weight:600;color:var(--text);border-bottom:1px solid var(--border);font-size:0.72rem;text-transform:uppercase}
397
+ .demo-gate-table td{padding:0.5rem 0.75rem;border-bottom:1px solid var(--border);color:var(--text-dim);font-size:0.78rem}
398
+ .demo-gate-table tr:last-child td{border-bottom:none}
399
+ .demo-gate-table code{font-family:var(--font-mono);font-size:0.72rem;color:var(--cyan);background:var(--terminal-bg);padding:0.1rem 0.35rem;border-radius:3px}
400
+
401
+ @media(max-width:640px){
402
+ .demos-page{padding:1rem 0.75rem}
403
+ .demos-hero h1{font-size:1.5rem}
404
+ .demo-header{padding:0.75rem;flex-wrap:wrap}
405
+ .demo-header-left{flex:1;min-width:200px}
406
+ .demo-steps{font-size:0.68rem}
407
+ .demo-steps th,.demo-steps td{padding:0.3rem 0.4rem}
408
+ .demo-body{padding:0 0.75rem 0.75rem}
409
+ .demo-overview{font-size:0.7rem}
410
+ .demo-title-block h3{font-size:0.8rem}
411
+ }
412
  </style>
413
  </head>
414
  <body>
 
425
  </div>
426
  <div class="header-tabs">
427
  <button class="tab-btn active" data-tab="console" onclick="switchTab('console')">Console</button>
428
+ <button class="tab-btn" data-tab="demos" onclick="switchTab('demos')">Demos</button>
429
  <button class="tab-btn" data-tab="guide" onclick="switchTab('guide')">Guide</button>
430
  </div>
431
  <div class="mobile-toggles">
 
615
  </div>
616
  </div><!-- /tabConsole -->
617
 
618
+ <!-- Demos Tab -->
619
+ <div class="demos-page" id="tabDemos">
620
+ <div class="demos-inner">
621
+
622
+ <div class="demos-hero">
623
+ <h1>Scenario <span>Demos</span></h1>
624
+ <p>Nine verified demo walkthroughs across all scenarios and facility sizes. Each demo resolves in 8–10 steps following proper operational procedure: assess → diagnose → compensate → verify → resolve.</p>
625
+ </div>
626
+
627
+ <!-- Overview Table -->
628
+ <table class="demo-overview">
629
+ <thead>
630
+ <tr><th>#</th><th>Scenario</th><th>Facility</th><th>Steps</th><th>Reward</th><th>Key Skill</th></tr>
631
+ </thead>
632
+ <tbody>
633
+ <tr onclick="openDemo('demo1')"><td>1</td><td><code>A1</code> Setpoint Optimization</td><td>Default</td><td>9</td><td style="color:var(--green);font-weight:700">+0.324</td><td>PUE optimization</td></tr>
634
+ <tr onclick="openDemo('demo2')"><td>2</td><td><code>A2</code> Thermal Event</td><td>Default</td><td>8</td><td style="color:var(--green);font-weight:700">+0.873</td><td>Single-failure response</td></tr>
635
+ <tr onclick="openDemo('demo3')"><td>3</td><td><code>A2</code> Thermal Event</td><td>Large</td><td>8</td><td style="color:var(--green);font-weight:700">+0.831</td><td>Multi-zone + H1 isolation</td></tr>
636
+ <tr onclick="openDemo('demo4')"><td>4</td><td><code>A4</code> CRAC Cascade</td><td>Default</td><td>8</td><td style="color:var(--green);font-weight:700">+1.230</td><td>Multi-failure triage</td></tr>
637
+ <tr onclick="openDemo('demo5')"><td>5</td><td><code>A4</code> CRAC Cascade</td><td>Large</td><td>8</td><td style="color:var(--green);font-weight:700">+1.150</td><td>Multi-zone cascade</td></tr>
638
+ <tr onclick="openDemo('demo6')"><td>6</td><td><code>B1</code> UPS Alarm</td><td>Default</td><td>8</td><td style="color:var(--green);font-weight:700">+0.512</td><td>Power chain audit</td></tr>
639
+ <tr onclick="openDemo('demo7')"><td>7</td><td><code>B3</code> Generator Test</td><td>Default</td><td>10</td><td style="color:var(--green);font-weight:700">+0.567</td><td>Protocol compliance</td></tr>
640
+ <tr onclick="openDemo('demo8')"><td>8</td><td><code>B4</code> Power Failure</td><td>Default</td><td>8</td><td style="color:var(--green);font-weight:700">+0.934</td><td>Battery + gen startup</td></tr>
641
+ <tr onclick="openDemo('demo9')"><td>9</td><td><code>B4</code> Power Failure</td><td>Small</td><td>8</td><td style="color:var(--green);font-weight:700">+0.948</td><td>Aggressive load shedding</td></tr>
642
+ </tbody>
643
+ </table>
644
+
645
+ <!-- Demo 1: A1 Default -->
646
+ <div class="demo-item" id="demo1">
647
+ <div class="demo-header" onclick="toggleDemo('demo1')">
648
+ <div class="demo-header-left">
649
+ <span class="demo-badge">A1</span>
650
+ <div class="demo-title-block">
651
+ <h3>Cooling Setpoint Optimization</h3>
652
+ <div class="demo-subtitle">
653
+ <span>Default Facility</span>
654
+ <span>9 steps</span>
655
+ <span style="background:var(--green-dim);color:var(--green);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">EASY</span>
656
+ </div>
657
+ </div>
658
+ </div>
659
+ <div class="demo-header-right">
660
+ <span class="demo-reward">+0.324</span>
661
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
662
+ </div>
663
+ </div>
664
+ <div class="demo-body">
665
+ <div class="demo-context">
666
+ All four CRACs are set to 15°C — far below what the servers need. This wastes energy: compressors run hard, fans blow at 100%, and PUE sits at 1.87. ASHRAE A2 class allows inlet temps up to 27°C. The agent must raise setpoints and reduce fan speeds to approach the PUE target of 1.6 without overheating.
667
+ </div>
668
+ <table class="demo-steps">
669
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>PUE</th><th>Inlets</th><th>Reasoning</th></tr></thead>
670
+ <tbody>
671
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.131</td><td>+0.131</td><td>1.87</td><td>17.1 / 17.1</td><td>Procedure bonus (+0.2): must check before adjusting. Baseline — all CRACs at 15°C.</td></tr>
672
+ <tr><td class="step-num">2</td><td><code>adjust_setpoint CRAC-1 24</code></td><td class="rew-pos">+0.047</td><td>+0.178</td><td>1.80</td><td>17.7 / 17.1</td><td>Raise from 15→24°C. Compressor works less → immediate PUE drop.</td></tr>
673
+ <tr><td class="step-num">3</td><td><code>adjust_setpoint CRAC-2 24</code></td><td class="rew-pos">+0.039</td><td>+0.217</td><td>1.76</td><td>19.2 / 17.0</td><td>PUE continues falling. Zone A inlets rising — still safely below 27°C.</td></tr>
674
+ <tr><td class="step-num">4</td><td><code>adjust_setpoint CRAC-3 24</code></td><td class="rew-pos">+0.038</td><td>+0.255</td><td>1.71</td><td>20.7 / 17.6</td><td>Zone B responding. Thermal mass (11.1 kJ/K per server) causes gradual warming.</td></tr>
675
+ <tr><td class="step-num">5</td><td><code>adjust_setpoint CRAC-4 24</code></td><td class="rew-pos">+0.025</td><td>+0.280</td><td>1.69</td><td>21.9 / 19.1</td><td>All CRACs at 24°C. PUE 1.69 — still above 1.6 target. Fan reduction needed.</td></tr>
676
+ <tr><td class="step-num">6</td><td><code>set_fan_speed CRAC-1 70</code></td><td class="rew-neg">−0.019</td><td>+0.261</td><td>1.68</td><td>22.8 / 20.6</td><td>Fan power follows cubic law: at 70%, power = 34% of rated (66% saving).</td></tr>
677
+ <tr><td class="step-num">7</td><td><code>set_fan_speed CRAC-2 70</code></td><td class="rew-neg">−0.017</td><td>+0.244</td><td>1.66</td><td>23.4 / 21.9</td><td>PUE 1.66. Inlets 23.4°C — still 3.6°C below ASHRAE A2 max (27°C).</td></tr>
678
+ <tr><td class="step-num">8</td><td><code>set_fan_speed CRAC-3 70</code></td><td class="rew-neg">−0.012</td><td>+0.232</td><td>1.63</td><td>23.9 / 22.7</td><td>Almost there. System approaching equilibrium.</td></tr>
679
+ <tr class="resolved-row"><td class="step-num">9</td><td><code>set_fan_speed CRAC-4 70</code></td><td class="rew-big">+0.092</td><td><strong>+0.324</strong></td><td><strong>1.60</strong></td><td>24.3 / 23.3</td><td><strong>RESOLVED.</strong> PUE hits target (≤1.6). Speed bonus: (10−9)/10 = +0.1.</td></tr>
680
+ </tbody>
681
+ </table>
682
+ <div class="demo-analysis">
683
+ <h4>Why This Works</h4>
684
+ <ul>
685
+ <li><strong>Phase 1 (steps 2–5): Setpoint adjustment.</strong> Raising 15→24°C reduces compressor load. PUE drops 1.87→1.69 (10% improvement).</li>
686
+ <li><strong>Phase 2 (steps 6–9): Fan speed reduction.</strong> Cubic fan law means 100→70% cuts fan power by 66%. Pushes PUE from 1.69→1.60.</li>
687
+ </ul>
688
+ </div>
689
+ </div>
690
+ </div>
691
+
692
+ <!-- Demo 2: A2 Default -->
693
+ <div class="demo-item" id="demo2">
694
+ <div class="demo-header" onclick="toggleDemo('demo2')">
695
+ <div class="demo-header-left">
696
+ <span class="demo-badge">A2</span>
697
+ <div class="demo-title-block">
698
+ <h3>Thermal Event Response — Default</h3>
699
+ <div class="demo-subtitle">
700
+ <span>Default Facility (160 kW)</span>
701
+ <span>8 steps</span>
702
+ <span style="background:var(--yellow-dim);color:var(--yellow);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">MEDIUM</span>
703
+ </div>
704
+ </div>
705
+ </div>
706
+ <div class="demo-header-right">
707
+ <span class="demo-reward">+0.873</span>
708
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
709
+ </div>
710
+ </div>
711
+ <div class="demo-body">
712
+ <div class="demo-context">
713
+ CRAC-3 compressor has failed. With only 3 of 4 CRACs operational, cooling capacity is reduced. The default facility has N+1 redundancy, so temperatures won't spike catastrophically, but the agent must diagnose the fault and compensate to ensure long-term stability.
714
+ </div>
715
+ <table class="demo-steps">
716
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Inlets (A/B)</th><th>Reasoning</th></tr></thead>
717
+ <tbody>
718
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.204</td><td>+0.204</td><td>19.8 / 20.0</td><td>CRAC-3 shows "!! COMPRESSOR" — no supply temp, no airflow, 0 kW.</td></tr>
719
+ <tr><td class="step-num">2</td><td><code>diagnose CRAC-3</code></td><td class="rew-pos">+0.054</td><td>+0.258</td><td>19.8 / 20.2</td><td><strong>Unlocks resolution gate.</strong> Confirms "FAULT: compressor." +0.3 bonus on subsequent setpoint changes.</td></tr>
720
+ <tr><td class="step-num">3</td><td><code>diagnose CRAC-1</code></td><td class="rew-neg">−0.021</td><td>+0.237</td><td>19.8 / 20.4</td><td>Verify remaining CRACs healthy. "No faults detected."</td></tr>
721
+ <tr><td class="step-num">4</td><td><code>adjust_setpoint CRAC-1 16</code></td><td class="rew-pos">+0.034</td><td>+0.270</td><td>19.6 / 20.5</td><td>Lower setpoint 18→16°C. Increases cooling output. Earns procedure bonus.</td></tr>
722
+ <tr><td class="step-num">5</td><td><code>adjust_setpoint CRAC-2 16</code></td><td class="rew-pos">+0.034</td><td>+0.304</td><td>19.3 / 20.6</td><td>Both zone A CRACs overcooling to compensate.</td></tr>
723
+ <tr><td class="step-num">6</td><td><code>set_fan_speed CRAC-1 100</code></td><td class="rew-pos">+0.034</td><td>+0.338</td><td>19.0 / 20.8</td><td>Max airflow on surviving CRACs.</td></tr>
724
+ <tr><td class="step-num">7</td><td><code>set_fan_speed CRAC-2 100</code></td><td class="rew-pos">+0.034</td><td>+0.372</td><td>18.7 / 20.8</td><td>Zone B stabilizing at ~20.8°C — within ASHRAE recommended range.</td></tr>
725
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>set_fan_speed CRAC-4 100</code></td><td class="rew-big">+0.501</td><td><strong>+0.873</strong></td><td>18.5 / 20.9</td><td><strong>RESOLVED.</strong> All zones stable for 2+ steps. Speed bonus: (15−8)/15 = +0.467.</td></tr>
726
+ </tbody>
727
+ </table>
728
+ </div>
729
+ </div>
730
+
731
+ <!-- Demo 3: A2 Large -->
732
+ <div class="demo-item" id="demo3">
733
+ <div class="demo-header" onclick="toggleDemo('demo3')">
734
+ <div class="demo-header-left">
735
+ <span class="demo-badge">A2</span>
736
+ <div class="demo-title-block">
737
+ <h3>Thermal Event Response — Large</h3>
738
+ <div class="demo-subtitle">
739
+ <span>Large Facility (600 kW, H1 zone)</span>
740
+ <span>8 steps</span>
741
+ <span style="background:var(--yellow-dim);color:var(--yellow);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">MEDIUM</span>
742
+ </div>
743
+ </div>
744
+ </div>
745
+ <div class="demo-header-right">
746
+ <span class="demo-reward">+0.831</span>
747
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
748
+ </div>
749
+ </div>
750
+ <div class="demo-body">
751
+ <div class="demo-context">
752
+ Same CRAC-3 failure, but in a larger facility with 4 zones including an H1 (high-density GPU) zone. H1 has a tighter thermal envelope (recommended max 22°C vs 27°C for A2).
753
+ </div>
754
+ <table class="demo-steps">
755
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Inlets (A/B/C/D)</th><th>Reasoning</th></tr></thead>
756
+ <tbody>
757
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.207</td><td>+0.207</td><td>20.0 / 20.8 / 19.2 / 19.7</td><td>4-zone dashboard. Zone B 0.8°C warmer. Zone C (H1) at 19.2°C — 2.8°C below its 22°C max.</td></tr>
758
+ <tr><td class="step-num">2</td><td><code>diagnose CRAC-3</code></td><td class="rew-pos">+0.057</td><td>+0.263</td><td>20.0 / 21.6 / 19.2 / 19.7</td><td>FAULT: compressor. Zone B rising +0.8°C/step. Zone C stable.</td></tr>
759
+ <tr><td class="step-num">3</td><td><code>diagnose CRAC-1</code></td><td class="rew-neg">−0.019</td><td>+0.245</td><td>20.0 / 22.3 / 19.2 / 19.6</td><td>Confirm CRAC-1 healthy.</td></tr>
760
+ <tr><td class="step-num">4</td><td><code>diagnose CRAC-2</code></td><td class="rew-neg">−0.019</td><td>+0.225</td><td>20.0 / 23.0 / 19.2 / 19.6</td><td>Confirm CRAC-2 healthy. Thorough zone B CRAC audit.</td></tr>
761
+ <tr><td class="step-num">5</td><td><code>adjust_setpoint CRAC-2 16</code></td><td class="rew-pos">+0.035</td><td>+0.261</td><td>19.9 / 23.6 / 19.2 / 19.6</td><td>Lower surviving zone B CRAC. Procedure bonus earned.</td></tr>
762
+ <tr><td class="step-num">6</td><td><code>adjust_setpoint CRAC-4 16</code></td><td class="rew-pos">+0.035</td><td>+0.296</td><td>19.7 / 24.0 / 19.2 / 19.6</td><td>Rate of rise slowing. H1 zone unaffected.</td></tr>
763
+ <tr><td class="step-num">7</td><td><code>set_fan_speed CRAC-2 100</code></td><td class="rew-pos">+0.035</td><td>+0.330</td><td>19.6 / 24.3 / 19.2 / 19.6</td><td>Max airflow. Zone B 2.7°C below ASHRAE A2 max.</td></tr>
764
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>set_fan_speed CRAC-4 100</code></td><td class="rew-big">+0.501</td><td><strong>+0.831</strong></td><td>19.5 / 24.6 / 19.2 / 19.6</td><td><strong>RESOLVED.</strong> Zone B stabilized. H1 completely unaffected.</td></tr>
765
+ </tbody>
766
+ </table>
767
+ <div class="demo-analysis">
768
+ <h4>Default vs Large Comparison</h4>
769
+ <table class="demo-compare">
770
+ <thead><tr><th>Metric</th><th>Default</th><th>Large</th></tr></thead>
771
+ <tbody>
772
+ <tr><td>Max inlet temp</td><td>20.9°C</td><td>24.6°C</td></tr>
773
+ <tr><td>H1 zone impact</td><td>N/A</td><td>None (19.2°C)</td></tr>
774
+ <tr><td>Cumulative reward</td><td>+0.873</td><td>+0.831</td></tr>
775
+ </tbody>
776
+ </table>
777
+ </div>
778
+ </div>
779
+ </div>
780
+
781
+ <!-- Demo 4: A4 Default -->
782
+ <div class="demo-item" id="demo4">
783
+ <div class="demo-header" onclick="toggleDemo('demo4')">
784
+ <div class="demo-header-left">
785
+ <span class="demo-badge">A4</span>
786
+ <div class="demo-title-block">
787
+ <h3>CRAC Failure Cascade — Default</h3>
788
+ <div class="demo-subtitle">
789
+ <span>Default Facility (160 kW)</span>
790
+ <span>8 steps</span>
791
+ <span style="background:var(--red-dim);color:var(--red);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">HARD</span>
792
+ </div>
793
+ </div>
794
+ </div>
795
+ <div class="demo-header-right">
796
+ <span class="demo-reward">+1.230</span>
797
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
798
+ </div>
799
+ </div>
800
+ <div class="demo-body">
801
+ <div class="demo-context">
802
+ Two CRACs fail simultaneously: CRAC-1 (compressor) and CRAC-3 (fan). Only CRAC-2 and CRAC-4 remain — 50% cooling capacity lost. The agent must diagnose both failures, aggressively compensate, and consider load shedding.
803
+ </div>
804
+ <table class="demo-steps">
805
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Inlets (A/B)</th><th>Reasoning</th></tr></thead>
806
+ <tbody>
807
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.212</td><td>+0.212</td><td>19.9 / 19.9</td><td>Two red-flagged CRACs. 50% cooling capacity lost.</td></tr>
808
+ <tr><td class="step-num">2</td><td><code>diagnose CRAC-1</code></td><td class="rew-pos">+0.062</td><td>+0.274</td><td>20.0 / 20.0</td><td>"FAULT: compressor." First of two required diagnoses.</td></tr>
809
+ <tr><td class="step-num">3</td><td><code>diagnose CRAC-3</code></td><td class="rew-pos">+0.027</td><td>+0.301</td><td>20.1 / 20.1</td><td>"FAULT: fan." Both diagnosed → resolution gate unlocked. +0.2 procedure bonus.</td></tr>
810
+ <tr><td class="step-num">4</td><td><code>adjust_setpoint CRAC-2 16</code></td><td class="rew-pos">+0.062</td><td>+0.363</td><td>20.2 / 20.2</td><td>Lower surviving CRAC setpoint. Procedure bonus (diagnosis first).</td></tr>
811
+ <tr><td class="step-num">5</td><td><code>adjust_setpoint CRAC-4 16</code></td><td class="rew-pos">+0.062</td><td>+0.425</td><td>20.2 / 20.3</td><td>Both survivors at 16°C. Temps stabilizing.</td></tr>
812
+ <tr><td class="step-num">6</td><td><code>set_fan_speed CRAC-2 100</code></td><td class="rew-pos">+0.062</td><td>+0.487</td><td>20.1 / 20.2</td><td>Max airflow confirmed.</td></tr>
813
+ <tr><td class="step-num">7</td><td><code>set_fan_speed CRAC-4 100</code></td><td class="rew-pos">+0.062</td><td>+0.549</td><td>20.1 / 20.2</td><td>Temps flat at ~20.1°C. Stable consecutive steps.</td></tr>
814
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>set_rack_load B-05 4</code></td><td class="rew-big">+0.681</td><td><strong>+1.230</strong></td><td>20.0 / 20.1</td><td><strong>RESOLVED.</strong> Load shed for thermal margin. Speed bonus: (20−8)/20 = +0.600.</td></tr>
815
+ </tbody>
816
+ </table>
817
+ <div class="demo-analysis">
818
+ <h4>Why Load Shedding Matters</h4>
819
+ <ul>
820
+ <li>Reducing rack B-05 from 8 kW to 4 kW provides additional thermal margin</li>
821
+ <li>Demonstrates workload migration capability</li>
822
+ <li>Earns action quality bonus (+0.2 for interventions)</li>
823
+ </ul>
824
+ </div>
825
+ </div>
826
+ </div>
827
+
828
+ <!-- Demo 5: A4 Large -->
829
+ <div class="demo-item" id="demo5">
830
+ <div class="demo-header" onclick="toggleDemo('demo5')">
831
+ <div class="demo-header-left">
832
+ <span class="demo-badge">A4</span>
833
+ <div class="demo-title-block">
834
+ <h3>CRAC Failure Cascade — Large</h3>
835
+ <div class="demo-subtitle">
836
+ <span>Large Facility (600 kW, H1 zone)</span>
837
+ <span>8 steps</span>
838
+ <span style="background:var(--red-dim);color:var(--red);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">HARD</span>
839
+ </div>
840
+ </div>
841
+ </div>
842
+ <div class="demo-header-right">
843
+ <span class="demo-reward">+1.150</span>
844
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
845
+ </div>
846
+ </div>
847
+ <div class="demo-body">
848
+ <div class="demo-context">
849
+ CRAC-1 and CRAC-3 down out of 8 CRACs. Zones C/D (including H1) have dedicated CRACs and remain unaffected. Zones A/B share the affected CRACs.
850
+ </div>
851
+ <table class="demo-steps">
852
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Inlets (A/B/C/D)</th><th>Reasoning</th></tr></thead>
853
+ <tbody>
854
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.210</td><td>+0.210</td><td>20.4 / 20.4 / 19.2 / 19.7</td><td>CRAC-1 and CRAC-3 down. Zones C/D have own CRACs.</td></tr>
855
+ <tr><td class="step-num">2</td><td><code>diagnose CRAC-1</code></td><td class="rew-pos">+0.059</td><td>+0.269</td><td>20.8 / 20.8 / 19.2 / 19.7</td><td>FAULT: compressor. Zone A/B rising ~0.4°C/step.</td></tr>
856
+ <tr><td class="step-num">3</td><td><code>diagnose CRAC-3</code></td><td class="rew-pos">+0.024</td><td>+0.293</td><td>21.2 / 21.2 / 19.2 / 19.7</td><td>FAULT: fan. Both diagnosed → gate unlocked.</td></tr>
857
+ <tr><td class="step-num">4</td><td><code>diagnose CRAC-2</code></td><td class="rew-pos">+0.024</td><td>+0.317</td><td>21.6 / 21.6 / 19.2 / 19.7</td><td>Verify CRAC-2 healthy. Critical with 2 failures.</td></tr>
858
+ <tr><td class="step-num">5</td><td><code>adjust_setpoint CRAC-2 16</code></td><td class="rew-pos">+0.059</td><td>+0.376</td><td>21.9 / 22.0 / 19.2 / 19.6</td><td>Compensate. Zone B at 22.0°C — 13°C below ASHRAE allowable max (35°C).</td></tr>
859
+ <tr><td class="step-num">6</td><td><code>adjust_setpoint CRAC-4 16</code></td><td class="rew-pos">+0.058</td><td>+0.434</td><td>22.2 / 22.3 / 19.2 / 19.6</td><td>Rate of rise slowing. H1 zone unaffected.</td></tr>
860
+ <tr><td class="step-num">7</td><td><code>set_fan_speed CRAC-2 100</code></td><td class="rew-pos">+0.058</td><td>+0.492</td><td>22.5 / 22.5 / 19.2 / 19.6</td><td>Max airflow. Zone B stabilizing.</td></tr>
861
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>set_fan_speed CRAC-4 100</code></td><td class="rew-big">+0.658</td><td><strong>+1.150</strong></td><td>22.7 / 22.8 / 19.2 / 19.6</td><td><strong>RESOLVED.</strong> All zones within allowable. Speed bonus: +0.600.</td></tr>
862
+ </tbody>
863
+ </table>
864
+ <div class="demo-analysis">
865
+ <h4>Default vs Large Comparison</h4>
866
+ <table class="demo-compare">
867
+ <thead><tr><th>Metric</th><th>Default</th><th>Large</th></tr></thead>
868
+ <tbody>
869
+ <tr><td>Final zone B inlet</td><td>20.1°C</td><td>22.8°C</td></tr>
870
+ <tr><td>H1 zone impact</td><td>N/A</td><td>None (19.2°C)</td></tr>
871
+ <tr><td>Cumulative reward</td><td>+1.230</td><td>+1.150</td></tr>
872
+ </tbody>
873
+ </table>
874
+ </div>
875
+ </div>
876
+ </div>
877
+
878
+ <!-- Demo 6: B1 Default -->
879
+ <div class="demo-item" id="demo6">
880
+ <div class="demo-header" onclick="toggleDemo('demo6')">
881
+ <div class="demo-header-left">
882
+ <span class="demo-badge">B1</span>
883
+ <div class="demo-title-block">
884
+ <h3>UPS Alarm Response</h3>
885
+ <div class="demo-subtitle">
886
+ <span>Default Facility (160 kW)</span>
887
+ <span>8 steps</span>
888
+ <span style="background:var(--yellow-dim);color:var(--yellow);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">MEDIUM</span>
889
+ </div>
890
+ </div>
891
+ </div>
892
+ <div class="demo-header-right">
893
+ <span class="demo-reward">+0.512</span>
894
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
895
+ </div>
896
+ </div>
897
+ <div class="demo-body">
898
+ <div class="demo-context">
899
+ A brief utility dip caused UPS-1 to transfer to battery. Utility has been restored and UPS switched back to double-conversion mode, but the alarm persists. The agent must investigate the entire power chain and acknowledge the alarm.
900
+ </div>
901
+ <table class="demo-steps">
902
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Reasoning</th></tr></thead>
903
+ <tbody>
904
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-neg">−0.007</td><td>−0.007</td><td>Baseline. Utility NORMAL, generator OFF, ATS on UTILITY.</td></tr>
905
+ <tr><td class="step-num">2</td><td><code>diagnose UPS-1</code></td><td class="rew-pos">+0.143</td><td>+0.137</td><td><strong>Key step.</strong> mode=double_conversion, SOC=86%. Resolution gate requires this.</td></tr>
906
+ <tr><td class="step-num">3</td><td><code>diagnose UPS-2</code></td><td class="rew-neg">−0.007</td><td>+0.130</td><td>Verify redundant UPS. mode=double_conversion, SOC=87%.</td></tr>
907
+ <tr><td class="step-num">4</td><td><code>diagnose GEN-1</code></td><td class="rew-neg">−0.007</td><td>+0.123</td><td>Generator in standby — confirming readiness.</td></tr>
908
+ <tr><td class="step-num">5</td><td><code>diagnose PDU-A-01</code></td><td class="rew-neg">−0.007</td><td>+0.117</td><td>Verify power distribution intact.</td></tr>
909
+ <tr><td class="step-num">6</td><td><code>check_status</code></td><td class="rew-neg">−0.007</td><td>+0.110</td><td>Re-verify before closing incident.</td></tr>
910
+ <tr><td class="step-num">7</td><td><code>diagnose PDU-B-01</code></td><td class="rew-neg">−0.007</td><td>+0.103</td><td>Complete the power chain audit.</td></tr>
911
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>acknowledge_alarm</code></td><td class="rew-big">+0.408</td><td><strong>+0.512</strong></td><td><strong>RESOLVED.</strong> Alarm acknowledged after thorough investigation. Speed bonus: (10−8)/10 = +0.200.</td></tr>
912
+ </tbody>
913
+ </table>
914
+ <div class="demo-analysis">
915
+ <h4>Reward Structure Note</h4>
916
+ <p>Steps 3–7 return −0.007 each because the delta-based progress metric doesn't change during investigation — only the final acknowledgment triggers progress completion. The cumulative reward is still positive (+0.512) thanks to the large resolution step reward.</p>
917
+ </div>
918
+ </div>
919
+ </div>
920
+
921
+ <!-- Demo 7: B3 Default -->
922
+ <div class="demo-item" id="demo7">
923
+ <div class="demo-header" onclick="toggleDemo('demo7')">
924
+ <div class="demo-header-left">
925
+ <span class="demo-badge">B3</span>
926
+ <div class="demo-title-block">
927
+ <h3>Generator Test Protocol</h3>
928
+ <div class="demo-subtitle">
929
+ <span>Default Facility (160 kW)</span>
930
+ <span>10 steps</span>
931
+ <span style="background:var(--green-dim);color:var(--green);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">EASY</span>
932
+ </div>
933
+ </div>
934
+ </div>
935
+ <div class="demo-header-right">
936
+ <span class="demo-reward">+0.567</span>
937
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
938
+ </div>
939
+ </div>
940
+ <div class="demo-body">
941
+ <div class="demo-context">
942
+ Routine monthly generator test. No fault, no emergency — the agent must follow the 5-step protocol: check → start → verify → stop → acknowledge.
943
+ </div>
944
+ <table class="demo-steps">
945
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Gen State</th><th>Reasoning</th></tr></thead>
946
+ <tbody>
947
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-neg">−0.007</td><td>−0.007</td><td>OFF</td><td>Baseline. All systems normal.</td></tr>
948
+ <tr><td class="step-num">2</td><td><code>diagnose GEN-1</code></td><td class="rew-neg">−0.007</td><td>−0.013</td><td>off</td><td>Pre-test inspection — verify before starting.</td></tr>
949
+ <tr><td class="step-num">3</td><td><code>start_generator</code></td><td class="rew-pos">+0.113</td><td>+0.100</td><td>CRANKING</td><td>Generator start sequence initiated.</td></tr>
950
+ <tr><td class="step-num">4</td><td><code>wait</code></td><td class="rew-neg">−0.022</td><td>+0.078</td><td>LOADED</td><td>Let generator complete warmup.</td></tr>
951
+ <tr><td class="step-num">5</td><td><code>diagnose GEN-1</code></td><td class="rew-pos">+0.043</td><td>+0.122</td><td>ready</td><td><strong>Critical verification.</strong> Confirms generator running properly.</td></tr>
952
+ <tr><td class="step-num">6</td><td><code>check_status</code></td><td class="rew-neg">−0.007</td><td>+0.115</td><td>LOADED</td><td>Full dashboard confirms generator loaded.</td></tr>
953
+ <tr><td class="step-num">7</td><td><code>stop_generator</code></td><td class="rew-pos">+0.113</td><td>+0.228</td><td>COOLDOWN</td><td>Initiate cooldown (300s for turbocharger).</td></tr>
954
+ <tr><td class="step-num">8</td><td><code>wait</code></td><td class="rew-neg">−0.022</td><td>+0.207</td><td>COOLDOWN</td><td>Allow cooldown to proceed.</td></tr>
955
+ <tr><td class="step-num">9</td><td><code>diagnose GEN-1</code></td><td class="rew-neg">−0.032</td><td>+0.175</td><td>cooldown</td><td>Post-shutdown inspection.</td></tr>
956
+ <tr class="resolved-row"><td class="step-num">10</td><td><code>acknowledge_alarm</code></td><td class="rew-big">+0.392</td><td><strong>+0.567</strong></td><td>COOLDOWN</td><td><strong>RESOLVED.</strong> Protocol complete. Speed bonus: (15−10)/15 = +0.333.</td></tr>
957
+ </tbody>
958
+ </table>
959
+ <div class="demo-analysis">
960
+ <h4>Protocol Enforcement</h4>
961
+ <p>B3 tracks four internal flags that must be set <strong>in order</strong>:</p>
962
+ <ul>
963
+ <li><strong>_started</strong> — <code style="color:var(--cyan);font-size:0.72rem">start_generator</code> issued</li>
964
+ <li><strong>_verified</strong> — <code style="color:var(--cyan);font-size:0.72rem">diagnose GEN-1</code> while generator is running</li>
965
+ <li><strong>_stopped</strong> — <code style="color:var(--cyan);font-size:0.72rem">stop_generator</code> (only if started + verified)</li>
966
+ <li><strong>_completed</strong> — <code style="color:var(--cyan);font-size:0.72rem">acknowledge_alarm</code> (only if stopped)</li>
967
+ </ul>
968
+ <p>The agent <strong>cannot skip steps</strong> — issuing <code style="color:var(--cyan);font-size:0.72rem">stop_generator</code> before <code style="color:var(--cyan);font-size:0.72rem">diagnose GEN-1</code> won't set <code style="color:var(--cyan);font-size:0.72rem">_stopped</code>.</p>
969
+ </div>
970
+ </div>
971
+ </div>
972
+
973
+ <!-- Demo 8: B4 Default -->
974
+ <div class="demo-item" id="demo8">
975
+ <div class="demo-header" onclick="toggleDemo('demo8')">
976
+ <div class="demo-header-left">
977
+ <span class="demo-badge">B4</span>
978
+ <div class="demo-title-block">
979
+ <h3>Power Failure Cascade — Default</h3>
980
+ <div class="demo-subtitle">
981
+ <span>Default Facility (160 kW)</span>
982
+ <span>8 steps</span>
983
+ <span style="background:var(--red-dim);color:var(--red);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">HARD</span>
984
+ </div>
985
+ </div>
986
+ </div>
987
+ <div class="demo-header-right">
988
+ <span class="demo-reward">+0.934</span>
989
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
990
+ </div>
991
+ </div>
992
+ <div class="demo-body">
993
+ <div class="demo-context">
994
+ Total utility power loss. UPS batteries bridging while generator starts. Generator warmup extended (15s vs default 8s). Agent must manage battery life, consider load shedding, and verify generator operation.
995
+ </div>
996
+ <table class="demo-steps">
997
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Key Metrics</th><th>Reasoning</th></tr></thead>
998
+ <tbody>
999
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.108</td><td>+0.108</td><td>UPS battery, SOC ~97%</td><td>Utility LOST. ATS transferring. Generator auto-starting.</td></tr>
1000
+ <tr><td class="step-num">2</td><td><code>diagnose UPS-1</code></td><td class="rew-pos">+0.131</td><td>+0.239</td><td>on_battery, SOC=95%</td><td><strong>Resolution gate unlocked.</strong> Battery draining ~2%/step at 160 kW.</td></tr>
1001
+ <tr><td class="step-num">3</td><td><code>diagnose UPS-2</code></td><td class="rew-pos">+0.078</td><td>+0.317</td><td>on_battery, SOC=90%</td><td>Redundant UPS also on battery.</td></tr>
1002
+ <tr><td class="step-num">4</td><td><code>start_generator</code></td><td class="rew-neg">−0.007</td><td>+0.310</td><td>Gen: CRANKING</td><td>Gen already auto-starting — slight negative for redundant command.</td></tr>
1003
+ <tr><td class="step-num">5</td><td><code>set_rack_load A-05 4</code></td><td class="rew-pos">+0.062</td><td>+0.371</td><td>IT: 156 kW</td><td>Shed 4 kW to extend battery life.</td></tr>
1004
+ <tr><td class="step-num">6</td><td><code>set_rack_load B-05 4</code></td><td class="rew-pos">+0.054</td><td>+0.425</td><td>IT: 152 kW</td><td>Total shed: 8 kW (5% of IT load).</td></tr>
1005
+ <tr><td class="step-num">7</td><td><code>wait</code></td><td class="rew-neg">−0.052</td><td>+0.373</td><td>Gen LOADED, ATS: GEN</td><td>Generator online. Battery recharging.</td></tr>
1006
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>diagnose GEN-1</code></td><td class="rew-big">+0.561</td><td><strong>+0.934</strong></td><td>state=loaded</td><td><strong>RESOLVED.</strong> Gen loaded, temps OK, SOC &gt;10%. Speed bonus: (20−8)/20 = +0.600.</td></tr>
1007
+ </tbody>
1008
+ </table>
1009
+ <div class="demo-analysis">
1010
+ <h4>Battery SOC Timeline</h4>
1011
+ <table class="demo-compare">
1012
+ <thead><tr><th>Step</th><th>SOC (UPS-1)</th><th>Event</th></tr></thead>
1013
+ <tbody>
1014
+ <tr><td>0</td><td>97%</td><td>Utility lost</td></tr>
1015
+ <tr><td>2</td><td>95%</td><td>Diagnosed</td></tr>
1016
+ <tr><td>4</td><td>~90%</td><td>Gen starting</td></tr>
1017
+ <tr><td>6</td><td>~87%</td><td>Load shed</td></tr>
1018
+ <tr><td>7</td><td>~88%</td><td>Gen loaded, recharging begins</td></tr>
1019
+ <tr><td>8</td><td>~89%</td><td>Resolved</td></tr>
1020
+ </tbody>
1021
+ </table>
1022
+ </div>
1023
+ </div>
1024
+ </div>
1025
+
1026
+ <!-- Demo 9: B4 Small -->
1027
+ <div class="demo-item" id="demo9">
1028
+ <div class="demo-header" onclick="toggleDemo('demo9')">
1029
+ <div class="demo-header-left">
1030
+ <span class="demo-badge">B4</span>
1031
+ <div class="demo-title-block">
1032
+ <h3>Power Failure Cascade — Small</h3>
1033
+ <div class="demo-subtitle">
1034
+ <span>Small Facility (80 kW)</span>
1035
+ <span>8 steps</span>
1036
+ <span style="background:var(--red-dim);color:var(--red);padding:0.05rem 0.4rem;border-radius:999px;font-size:0.6rem;font-weight:700">HARD</span>
1037
+ </div>
1038
+ </div>
1039
+ </div>
1040
+ <div class="demo-header-right">
1041
+ <span class="demo-reward">+0.948</span>
1042
+ <svg class="demo-chevron" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"/></svg>
1043
+ </div>
1044
+ </div>
1045
+ <div class="demo-body">
1046
+ <div class="demo-context">
1047
+ Same power loss scenario in a smaller facility: 80 kW IT load, 1 zone, 2 CRACs. Less redundancy means more aggressive load shedding is needed.
1048
+ </div>
1049
+ <table class="demo-steps">
1050
+ <thead><tr><th>#</th><th>Command</th><th>Reward</th><th>Cumul</th><th>Key Metrics</th><th>Reasoning</th></tr></thead>
1051
+ <tbody>
1052
+ <tr><td class="step-num">1</td><td><code>check_status</code></td><td class="rew-pos">+0.111</td><td>+0.111</td><td>1 zone, UPS battery</td><td>80 kW IT, 1 zone, 2 CRACs. Less redundancy.</td></tr>
1053
+ <tr><td class="step-num">2</td><td><code>diagnose UPS-1</code></td><td class="rew-pos">+0.133</td><td>+0.244</td><td>SOC=91%</td><td>Battery draining faster relative to capacity. Gate unlocked.</td></tr>
1054
+ <tr><td class="step-num">3</td><td><code>start_generator</code></td><td class="rew-pos">+0.073</td><td>+0.317</td><td>Gen starting</td><td>Explicit start command.</td></tr>
1055
+ <tr><td class="step-num">4</td><td><code>set_rack_load A-05 4</code></td><td class="rew-pos">+0.066</td><td>+0.383</td><td>IT: 76 kW</td><td>5% load reduction.</td></tr>
1056
+ <tr><td class="step-num">5</td><td><code>set_rack_load A-04 4</code></td><td class="rew-pos">+0.056</td><td>+0.438</td><td>IT: 72 kW</td><td>10% load reduction.</td></tr>
1057
+ <tr><td class="step-num">6</td><td><code>set_rack_load A-03 4</code></td><td class="rew-pos">+0.042</td><td>+0.481</td><td>IT: 68 kW</td><td>15% total load shed — more aggressive for smaller facility.</td></tr>
1058
+ <tr><td class="step-num">7</td><td><code>wait</code></td><td class="rew-neg">−0.069</td><td>+0.412</td><td>Gen LOADED</td><td>Generator online. Battery recharging.</td></tr>
1059
+ <tr class="resolved-row"><td class="step-num">8</td><td><code>diagnose GEN-1</code></td><td class="rew-big">+0.537</td><td><strong>+0.948</strong></td><td>state=loaded</td><td><strong>RESOLVED.</strong> Speed bonus: +0.600.</td></tr>
1060
+ </tbody>
1061
+ </table>
1062
+ <div class="demo-analysis">
1063
+ <h4>Small vs Default Comparison</h4>
1064
+ <table class="demo-compare">
1065
+ <thead><tr><th>Metric</th><th>Default (160 kW)</th><th>Small (80 kW)</th></tr></thead>
1066
+ <tbody>
1067
+ <tr><td>Racks shed</td><td>2 (8 kW, 5%)</td><td>3 (12 kW, 15%)</td></tr>
1068
+ <tr><td>Cumulative reward</td><td>+0.934</td><td>+0.948</td></tr>
1069
+ </tbody>
1070
+ </table>
1071
+ <p style="margin-top:0.5rem">The small facility earns slightly higher reward due to more aggressive proportional load shedding, producing a stronger positive signal from the power safety component.</p>
1072
+ </div>
1073
+ </div>
1074
+ </div>
1075
+
1076
+ <!-- Resolution Gate Design -->
1077
+ <div style="margin-top:2rem;padding:1.5rem;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg)">
1078
+ <h3 style="font-size:1rem;font-weight:700;margin-bottom:0.75rem;display:flex;align-items:center;gap:0.5rem">
1079
+ <span style="color:var(--red)">&#x26A0;</span> Resolution Gate Design
1080
+ </h3>
1081
+ <p style="font-size:0.8rem;color:var(--text-dim);margin-bottom:1rem;line-height:1.65">
1082
+ Each affected scenario requires the agent to actually <strong style="color:var(--text)">do something</strong> before resolution. Without these gates, scenarios A2, A4, and B4 would auto-resolve within 2–3 steps of passive <code style="color:var(--cyan);background:var(--terminal-bg);padding:0.1rem 0.35rem;border-radius:3px;font-size:0.75rem">wait</code> commands.
1083
+ </p>
1084
+ <table class="demo-gate-table">
1085
+ <thead><tr><th>Scenario</th><th>Diagnosis Gate</th><th>Min Steps</th></tr></thead>
1086
+ <tbody>
1087
+ <tr><td><strong style="color:var(--accent)">A2</strong></td><td>Must <code>diagnose CRAC-3</code></td><td>≥ 8 steps</td></tr>
1088
+ <tr><td><strong style="color:var(--accent)">A4</strong></td><td>Must <code>diagnose CRAC-1</code> AND <code>diagnose CRAC-3</code></td><td>≥ 8 steps</td></tr>
1089
+ <tr><td><strong style="color:var(--accent)">B4</strong></td><td>Must <code>diagnose UPS-*</code></td><td>≥ 8 steps</td></tr>
1090
+ </tbody>
1091
+ </table>
1092
+ <p style="font-size:0.78rem;color:var(--text-muted);margin-top:0.75rem;line-height:1.6">
1093
+ <strong style="color:var(--text)">Reward ordering validates the design:</strong> fast diagnosis &gt; late diagnosis &gt; no diagnosis (never resolves).
1094
+ </p>
1095
+ </div>
1096
+
1097
+ </div>
1098
+ </div><!-- /tabDemos -->
1099
+
1100
  <!-- Guide Tab -->
1101
  <div class="guide-page" id="tabGuide">
1102
  <div class="guide-inner">
 
1949
  document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
1950
  document.querySelector(`.tab-btn[data-tab="${tab}"]`).classList.add('active');
1951
 
 
1952
  const consoleEl = document.getElementById('tabConsole');
1953
+ const demosEl = document.getElementById('tabDemos');
1954
  const guideEl = document.getElementById('tabGuide');
1955
+
1956
+ consoleEl.classList.remove('active');
1957
+ demosEl.classList.remove('active');
1958
+ guideEl.classList.remove('active');
1959
+
1960
  if (tab === 'console') {
1961
  consoleEl.classList.add('active');
1962
+ } else if (tab === 'demos') {
1963
+ demosEl.classList.add('active');
1964
+ demosEl.scrollTop = 0;
1965
  } else {
 
1966
  guideEl.classList.add('active');
1967
  guideEl.scrollTop = 0;
1968
  }
1969
  }
1970
 
1971
+ // ─── Demo accordion ──────────────────────────────────────────────────
1972
+ function toggleDemo(id) {
1973
+ const el = document.getElementById(id);
1974
+ if (el) el.classList.toggle('open');
1975
+ }
1976
+
1977
+ function openDemo(id) {
1978
+ const el = document.getElementById(id);
1979
+ if (el) {
1980
+ // Close all others
1981
+ document.querySelectorAll('.demo-item.open').forEach(d => {
1982
+ if (d.id !== id) d.classList.remove('open');
1983
+ });
1984
+ el.classList.add('open');
1985
+ setTimeout(() => el.scrollIntoView({ behavior: 'smooth', block: 'start' }), 50);
1986
+ }
1987
+ }
1988
+
1989
  // ─── Build weight profile visualizations ─────────────────────────────
1990
  function buildWeightProfiles() {
1991
  const profiles = {