Skip to content
Yoann Frayce
All systems
July 2026RAISE Hackathon 2026 · Crusoe track · remote

DepotOps

Chapter 1 — where the thesis started

A live operations agent that re-simulates hundreds of possible remainders of the night after every depot event, then tests what to do about it.

Sole authorPrivate repositoryView architecture
Futures simulated after each event
200
Paired futures per candidate action
400
Risk after the 18:40 charger failure
~68%
of 200 futures end with a van not ready
Risk after the recommended action
~68%~7%

Figures with a dotted underline carry their source. Hover one to see whether it was verified in code or reported in project documentation.

Context

The situation

Electric delivery depots run on a nightly plan built from averages. The plan is made once, in the evening, against a night that has not happened yet.

The problem

A point forecast is not the problem. The problem is that several things vary at once — arrival times, plug-in state of charge, charger availability, energy price — and a plan that is optimal for the expected night can fail badly on a plausible one. Deterministic optimisation does not cover that space.

What I built

Model the depot physically, then sample the night many times. A deterministic charging-physics engine allocates power under a hard site cap; a seeded scenario generator introduces delays, failures and price spikes. After each real event the agent re-runs hundreds of rollouts from the live state, and when risk jumps above the session baseline it evaluates five discrete counteractions against the same sampled futures and ranks them.

Every night a depot operator makes one bet: that tonight’s charging plan gets every van to its departure slot on time. Vans arrive late, a charger dies, the grid price spikes, and a plan that looked fine at 17:00 quietly becomes one where vans miss their morning routes. DepotOps detects that before it happens. After every event it simulates hundreds of possible remainders of the night from the live depot state, and when failure risk jumps above the session’s own measured baseline it plays five candidate interventions through the same sampled futures and recommends one — with the numbers attached.

Architecture

How it fits together

135 end with a van not readyevery van departs on time
  1. Depot eventsinput

    arrivals, failures, prices

  2. LiveSessiondeterministic

    live depot state, advanced event by event

  3. Charging physicsdeterministic

    power allocation under a hard site cap

  4. Monte Carlodeterministic

    200 futures after every event

  5. Risk detectorguard

    fires on a jump above session baseline

  6. Counterfactualsdeterministic

    5 actions × 400 paired futures

  7. Operator brieflanguage model

    LLM, with deterministic fallback

  8. Operator decisionoutput

    accept, override, ask why

The engine is pure: dataclasses and NumPy, no I/O, all randomness through injected seeds. The same seed gives byte-identical results, which is what makes the scripted demo testable in CI.

Key decisions

The choices that shaped it

Each of these was a fork in the road where the obvious option would have produced something that looked the same and behaved worse.
  1. 01

    The site cap is unbreakable by construction

    The allocator distributes a power budget rather than checking a limit afterwards. No charging policy, however wrong, can exceed the site cap — it is a structural guarantee, not a validation step that a future refactor could skip.

    engine/physics.py

  2. 02

    Counts, never confidence scores

    Every risk figure is phrased as a count over concrete simulated outcomes: X% of 200 simulated futures end with a van not ready. An operator can reason about a count of nights. An abstract confidence number invites either blind trust or dismissal.

  3. 03

    Paired futures, and a noise floor that is honoured

    Each candidate action is played through the same sampled nights, so the comparison reflects the actions rather than sampling luck. Differences that fall inside the Monte Carlo noise floor are treated as ties and decided on cost, instead of pretending to a precision the sample size does not support.

    agent/recommender.py

  4. 04

    The language model is not on the critical path

    It writes the operator brief and answers grounded "why" questions. It never chooses an action. If it is unreachable a deterministic template produces the same brief from the same numbers, and the operator cannot tell the difference.

    agent/briefing.py

  5. 05

    A real tariff, not an invented one

    The demo depot’s tariff is fitted from the EPEX France day-ahead curve for 12 December 2024, fetched from the free energy-charts.info API (Fraunhofer ISE, CC BY 4.0) — the same feed a production deployment would consume. The raw data is committed for provenance.

    scripts/fit_tariff.py

  6. 06

    The demo is a regression test

    The scripted story beats are pinned by a test that runs in CI on every push. The rehearsal runs on the build server, not just on stage, so the numbers in the write-up cannot drift away from the engine.

    tests/test_demo_story.py

Evidence

What it actually looked like

The DepotOps operator dashboard: the event feed on the left, the agent recommendation in the centre, and the live depot state on the right.

The operator interface: event feed, agent recommendation, live depot state.

Interface

Measured

Every figure, with its source

Futures simulated after each event
200
Paired futures per candidate action
400
Risk after the 18:40 charger failure
~68%
of 200 futures end with a van not ready
Risk after the recommended action
~68%~7%
Monte Carlo throughput
1,000 rollouts < 3s
Tests
30
physics invariants, seeded reproducibility, calibration gap, agent flow, API smoke, demo story

Figures with a dotted underline carry their source. Hover one to see whether it was verified in code or reported in project documentation.

Recognition

Result

First Place — Crusoe TrackRAISE Hackathon — The Battle Of The BoulevardRemote track · 4–5 July 2026

500+ participants

Awarded for placing as winner of the RAISE Hackathon Remote.

The RAISE Hackathon Certificate of First Place, awarded to Yoann Frayce for placing as winner of the RAISE Hackathon Remote on 4–5 July 2026, Track of Crusoe, signed by the RAISE Summit ecosystem lead.

Certificate of First Place — Crusoe track, 4–5 July 2026.

Certificate

The result is context. What the system does, and how it was measured, is everything above this.

My contribution

Sole author — engine, agent, API, interface and deployment.

What I owned

  • Deterministic charging-physics engine with a site cap that cannot be exceeded by construction
  • Seeded scenario generator behind an UncertaintyModel protocol
  • Monte Carlo layer, including mid-night rollouts from live state
  • Risk detector, five candidate actions, paired counterfactual evaluation and noise-aware ranking
  • FastAPI boundary, React operator interface, Docker Compose, Azure deployment and CI

Stack and limits

Built with

  • Python
  • NumPy
  • FastAPI
  • React
  • Vite
  • Docker
  • Azure Container Instances
  • GitHub Actions

Techniques

  • Seeded Monte Carlo simulation
  • Counterfactual evaluation on paired futures
  • Deterministic physics modelling
  • LLM briefing with deterministic fallback
  • Operator preference learning from overrides

What it is not

  • The charging model is decision-support, not physics: it does not model battery charge curves, thermal behaviour, cable losses or degradation.
  • All operational data is synthetic. No public depot-fleet telemetry exists, and that gap is part of what makes the problem worth working on.
  • It compares a fixed set of named policies. It does not search for an optimal one.
  • A production deployment would need integration with telematics, charge point management and an energy supplier, plus validation against measured outcomes.

What carried forward

Two things carried forward. First, that operators trust a count of simulated nights far more than a probability. Second, that the interesting boundary is not "how good is the model" but "which parts of the answer is the model allowed to produce at all". Forkcast was built to make that boundary the product.