Repository navigation
feat: ten real-world scenarios recorded against the live backend, plus two live-only fixes they caught - #16
Merged
Merged
Conversation
…s two live-only fixes they caught
scripts/scenarios.py plays a normal commuter, leaving now / soon, prioritise, a skipped form,
a plug-in hybrid, a fleet van, an early leaver, a grid-API outage and a two-wave lunchtime rush
at SIM_SPEED=120, checks the promise each scenario makes (36 checks) and records every request,
response, event and number to docs/scenarios/run.{md,json}. 36/36 pass; EV load never above
headroom over the whole run.
Fixes found by the recording (in-process tests could not see either):
- A burst of plug-ins over HTTP held the 1.833 kW static share each on top of a plan that already
filled the feed, because the control loop ticks while the handler awaits the threaded re-solve:
20 arrivals = +26 kW over headroom for a sim-minute. Sim.arrive now gives a newcomer its share
only out of headroom nobody holds yet (full share after DYN_VALID_MIN if no plan ever lands).
- meter_history() anchors a session's record to the first minute it records; a re-solve landing a
tick late used to shift every sample a minute early and report a peak above the feed.
Also: POST /sessions/{id}/unplug (the driver pulls the plug; receipt + re-solve), assistant pins
a bay named in the question into its snapshot and answers "leaves early" questions.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017thvbGo7rTVnG2f46cLMzU
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
scripts/scenarios.py— ten real-world scenarios against the live backend, told as stories and recorded. Each one: who is involved, what they do (driver REST), what the site does (plan/meter/event frames on/ws, the FM's status), the promise it must keep (checks), and what the operator assistant says when asked. Transcript indocs/scenarios/run.md(+run.jsonwith every request/response); every line is a real request or a frame from/ws, nothing mocked.36/36 checks pass. Whole run: EV load exceeded headroom by at most 0.0 kW over 335 meter frames.
Two real bugs the recording caught (neither visible to the in-process tests)
POST /sessions//demo/oversubscribeplug cars in at the 1.833 kW static share, thenawait(event broadcast, threaded solve) before the plan lands; the control loop ticks in that gap. 20 arrivals on a plan that already filled the feed = +26 kW for a sim-minute (run 2 printed 136.09 vs 110.0 kW). Fix inSim.arrive: a newcomer's provisional limit is its share out of headroom nobody holds yet, reverting to the full share afterDYN_VALID_MINif no plan ever lands — the no-backend guarantee is unchanged.test_a_burst_of_plug_ins_never_draws_above_headroom_before_the_plan_catches_upfails on the old code (136.66 vs 110).resolve()capturesnow, then awaits; if a tick runs meanwhile, the session'shist.startis a minute earlier than its first recorded draw, every sample shifts a minute early, and a 0→7 kW ramp at a slot boundary leaks into the previous slot's 5-min average (run 3 reported a 151.8 kW peak on a 150 kW feed that never happened). Fix:meter_history()anchorsstartto the first minute it records.test_meter_history_anchors_start_to_the_first_minute_it_recordsfails on the old code.Also
POST /sessions/{id}/unplug— the driver pulls the plug (a real charger's StopTransaction); returns the receipt, re-solves without the car. Sharedunplug_session()with the demo. Test added; contract regenerated.when/hourno longer route to the signal answer. Tests added.Checks
pytest: 96 passed, 1 skipped (cache test needs a key)scripts/smoke.py:SMOKE OK;scripts/scenarios.py:SCENARIOS OK36/36web/untouched (assistant drawer unchanged);wattwise/untouchedAssumptions
docs/scenarios/as the last known-good transcript; it is not diff-checked by CI (numbers vary run to run).🤖 Generated with Claude Code
https://claude.ai/code/session_017thvbGo7rTVnG2f46cLMzU