You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CLAUDE.md
+36Lines changed: 36 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -14,6 +14,42 @@ memory or assumptions from training — the facts and status are HERE. If
14
14
something you intend to do contradicts this document, stop and reconcile it
15
15
first.
16
16
17
+
### The Documentation Set — keep ALL of it current (do not let it float)
18
+
19
+
There are TWO authoritative docs and they must BOTH be read and kept in sync:
20
+
21
+
| Doc | Role | Update when |
22
+
|---|---|---|
23
+
|**CLAUDE.md** (this file) | Architecture, status, every fix's rationale, known issues, settings matrix | every change |
24
+
|**docs/EMS_LOGIC.md**| The behavioural SPECIFICATION — what the EMS should do per mode/knob, traced from inputs to action | every change that alters behaviour |
25
+
26
+
A past session updated only CLAUDE.md and let `docs/EMS_LOGIC.md` go stale —
27
+
that is the "floating basis" failure. **Before concluding any work, update
28
+
BOTH** (CLAUDE.md for the what/why/status, EMS_LOGIC.md for the behavioural
29
+
contract). `EMS.md` and the root `EMS_LOGIC.md` are older analysis docs — do
30
+
not treat them as current.
31
+
32
+
### Validate behaviour with the simulator — don't assert from memory
33
+
34
+
`tools/ems_simulator.py` runs `ems.calculate_schedule` on a library of named
35
+
scenarios (`tools/scenarios.py`) for BOTH engines, checks expectations, and
36
+
renders charts. When you change scheduling behaviour: add/adjust a scenario
37
+
that encodes the intended outcome, run `python tools/ems_simulator.py`, and
38
+
confirm it's green before claiming a fix works. Reproduce customer reports as
39
+
scenarios so they become permanent, readable regression tests.
40
+
41
+
### Engine default = GREEDY (decision, June 2026)
42
+
43
+
`scheduler_engine` defaults to **greedy** (multi-month track record, no solver
44
+
dependency). **MILP is opt-in.** A prior session flipped the default to MILP;
45
+
it was reverted after fact-checking showed the recent customer-reported bugs
46
+
were MILP-specific or shared-reserve (not greedy scheduling), plus MILP carries
47
+
a pulp/CBC dependency and was not yet validated for determinism. Do NOT flip
48
+
the default back to MILP without (a) the simulator harness showing MILP is
49
+
deterministic and correct across all knob scenarios, and (b) explicit user
50
+
agreement. Greedy's two-day reconstruction is less powerful on cross-day
51
+
arbitrage, but it is the proven, dependency-free path.
52
+
17
53
### The One Rule That Keeps Breaking — Single Point of Truth
18
54
19
55
**`ems.py` is the SINGLE SOURCE OF TRUTH for all scheduling logic. It must
0 commit comments