Skip to content

test(sitesim): judge Core with device-simulator's fuse model - #1812

Merged
frahlg merged 1 commit into
masterfrom
test/sitesim-shared-fuse
Oct 23, 2026
Merged

frahlg merged 1 commit into
masterfrom
test/sitesim-shared-fuse

Conversation

@frahlg

@frahlg frahlg commented Oct 23, 2026

Copy link
Copy Markdown
Member

What

go/internal/sitesim drops its port of the old gG curve and imports github.com/srcfl/device-simulator/fuse at 736051f (srcfl/device-simulator#9, merged 23 Oct). Each plant second steps every phase through fuse.Lookup("iec_gg").Step at the package's default 25 °C. Fuse.Preheat starts a phase warm through the package's Preheat. No tuning of the model, and no change to Core.

The site rig judges Core by the same package: on the device-simulator stack (#8 → #10 → #11, now on main), cmd/simulator steps fuse/, and the stack head 3bf737d carries the same fuse/fuse.go as main. So go/test/site (#1797) and sitesim share one fuse model once #1797 moves devsim.version to that stack; it still pins cba7142, which has the old curve.

Test-only. Core's binaries do not link device-simulator (go list -deps ./cmd/... for linux and darwin).

Preheat

Only where a scenario starts with the house near its limit:

  • the field matrix's three probe/25A/auto/mixed/*/car3p/2-20-2/1p-to-3p cases (L2 at 20 A of 25 A), through a new fieldCase.warm that is not part of the case name;
  • the new property test, at its first random load.

Every other case starts cold, as before.

Old curve and new model

Seconds to blow at a held current, from cold (the old curve was the same at every rating) and, for the model, warm after hours at the fuse less 2 A:

× In old 16 A cold 16 A warm 20 A cold 20 A warm 25 A cold 25 A warm
1.05 3,600 never never never never never never
1.25 3,600 never never never never never never
1.4 2,619 never never 5,772 5,098 3,819 3,079
1.5 2,158 2,420 1,749 1,726 1,162 1,630 1,013
1.6 1,801 1,340 766 993 512 963 438
1.8 1,008 443 31 345 30 342 24
2 600 32 10 42 12 41 11
2.5 248 7 4 9 5 9 4
3 121 4 2 5 2 5 2
5 20 1 1 1 1 1 1

They agree around 1.5 ×. At 2 × and above the old curve was 14 to 35 times slower (600 s at 2 ×, against 32 to 42 s). Just above the rating it blew in an hour, where a gG fuse never does. Cooling differs too: the old damage fell to zero over 300 s, while the model keeps heat in the body and holder. After 20 s at 2 × 25 A and 15 min at 0 A, a second 2 × overload melts in 38 s, against 41 s cold.

Verdicts

None changed.

  • TestSiteSimScenarios: every row as on master.
  • Field matrix: 340 cases, 29 fail an invariant (idle 23, own-raise 6), the same rows. FTW_FIELD_KNOWN=write leaves sitesim_field_known.txt as it was.

No case reaches the range where the two differ. The matrix peaks at 1.25 × (20 A on 16 A, the kettle); the scenarios peak at 1.56 × for 3 s (39 A on 25 A, "meter every 30 s after a cut"). A preloaded case that fails, or a 2 × case that passes, needs an overload of 1.4 to 2 × held for tens of seconds to minutes, and the matrix has none. The warm 2-20-2 cases peak at 20 A.

Property test

TestSiteSimRandomHouse, in go/internal/control/sitesim_property_test.go, runs seeds 1 to 5 for an hour each. Each seed picks a fuse (16, 20 or 25 A) and a charger delay (2, 5 or 40 s). The house steps every 15 to 180 s to random currents up to the fuse less 2 A on each phase. The fuse starts warm from the first load, and the car charges on Charge now. simSite.check judges every plant second:

  • the fuse never blows;
  • no phase stays over the fuse less 1 A (heat-read, as invariant (a)) longer than the charger's response plus 3 s, or 3 s after a raise of Core's own.

The run goes on after a failure, so a later blow still shows. Idle time with room is logged, not judged; the matrix judges it with the fuse's own memory. All five seeds take 0.5 s wall.

seed fuse charger house steps peak phase fuse damage, max car idle with room
1 20 A 2 s 34 25.1 A 0.41 14 min 18 s
2 25 A 40 s 36 37.8 A 0.60 17 min 7 s
3 16 A 40 s 32 19.9 A 0.45 11 min 16 s
4 16 A 40 s 44 20.2 A 0.47 9 min 18 s
5 20 A 5 s 35 26.9 A 0.44 16 min 18 s

The fuse holds in every seed. Seed 2 breaks (a), and the test lists it as known.

Finding: a landed cut still covers the next overage (seed 2)

25 A fuse, 40 s charger with no declared response time, so Core counts a cut as possibly unshown for 180 s.

  1. 12:31:44: L2 rises to 27.2 A. At 12:32:51 its heat budget runs out and Core cuts 8,970 → 5,520 W. The cut lands at 12:33:31.
  2. L1 then reads 24.8 A: over 24 A by reading, under it by heat. The run over the limit never ends.
  3. 12:35:04: L2 steps to 30.8 A, over 1.2 × 25 A. Core's log reads overage 4,712 W, unshown cut 3,450 W (the 12:32:51 cut, landed 94 s before), offer 5,520 W, cap 4,258 W. Core sends 4,140 W (6 A), not 0.
  4. L2 reads 30.8 A until the 6 A order lands at 12:35:45, then 28.8 A. (a) fails at 12:35:52, 47 s after the step, past the 46 s it allows.

The fuse is not at risk: 1.15 × never melts, and damage peaks at 0.60. It belongs to the matrix's netting family, where a cut nets the overage against the run's earlier cuts (ev_fuse_budget.go:436). randomHouseKnown lists it; the test fails once it passes, as the matrix's known rows do.

Cost

The model costs CPU. go test ./internal/sitesim/ ./internal/control/ -run 'SiteSim|Fuse' took 72 s user and 15 s wall on master, and 100 s and 21 s here (M5, 10 cores). Each Step finds the melting time twice: from cold for its Status, and from now. At a current that never melts, both searches scan to 10⁷ s.

Dependency

go get github.com/srcfl/device-simulator@736051f. The fuse package imports only the standard library. Minimal version selection raises github.com/go-ole/go-ole 1.2.6 → 1.3.0 (indirect, through gopsutil's WMI), which only Windows builds link. Dependabot's #1749 also edits go/go.mod.

Open PRs on these files

#1782 and #1789 (drafts) change the meter reading in sitesim.go and the checks in control/sitesim_test.go. This PR leaves both files alone: the fuse keeps step and AnyBlown, and Damage and Blown mirror the package's state. #1807 edits other hunks of sitesim_field_test.go.

Test evidence

This branch, M5 MacBook:

$ cd go && go test ./internal/sitesim/... ./internal/control/... -count=1
ok  	github.com/srcfl/ftw/go/internal/sitesim	0.156s
ok  	github.com/srcfl/ftw/go/internal/control	23.395s

$ FTW_FIELD_KNOWN=write go test ./internal/sitesim/ ./internal/control/ -run 'SiteSim|Fuse' -count=1 -v
field matrix: 340 cases, 29 fail an invariant; by kind map[idle:23 own-raise:6]
(sitesim_field_known.txt unchanged)

$ make verify
ok  	github.com/srcfl/ftw/go/internal/control	28.426s
ok  	github.com/srcfl/ftw/go/internal/sitesim	0.443s
verify: vet + test + build clean

🤖 Generated with Claude Code

sitesim drops its port of the old gG curve and steps each phase through
github.com/srcfl/device-simulator/fuse (iec_gg) at 736051f, the thermal
model the site rig uses. Fuse.Preheat starts a phase warm; the field
matrix's 2-20-2 probe uses it. No verdict changes in the scenarios or the
field matrix.

TestSiteSimRandomHouse runs seeds 1-5 for an hour each: random house
steps up to the fuse less 2 A, a warm fuse, a car on Charge now. The fuse
never blows. Seed 2 breaks invariant (a) and is listed as known: a cut
that landed 94 s earlier still nets against the next overage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg frahlg added the no-changeset PR intentionally exempt from the changeset requirement (dev tooling / non-shipping) label Oct 23, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T05:41:29.164288Z 4c124bd PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@frahlg
frahlg merged commit 7cccf99 into master Oct 23, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changeset PR intentionally exempt from the changeset requirement (dev tooling / non-shipping)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant