This document records intentional, irreversible decisions.
Decision Use Rust for simulation correctness and TypeScript for orchestration.
Rationale
- Rust enforces FSM completeness and invariants
- TypeScript enables fast iteration and UX
Consequence Two-language system with explicit boundary.
Decision CLI is the primary interface; UI is read-only.
Rationale
- Determinism
- CI compatibility
- Reproducibility
Consequence No UI-driven behavior allowed.
Decision Use explicit ticks, not wall-clock time.
Rationale
- Replayability
- Debuggability
- Control over causality
Consequence Real-time realism is sacrificed.
Decision Implement OCPP 2.1 strictly.
Rationale
- Modern CPMS behavior
- Unified TransactionEvent model
- Cleaner ChargingProfile semantics
Consequence No legacy protocol support.
Decision All run outputs are immutable.
Rationale
- Trust
- Auditability
- Long-term comparison
Consequence Storage grows; pruning must be explicit.
Decision Do not simulate EV internals or grid physics.
Rationale
- Protocol bugs dominate CPMS failures
- Physics adds noise, not signal
Consequence
Power behavior is abstract but consistent. No physics-agent.
Decision Document what GridHammer will not do.
Rationale
- Prevent scope creep
- Maintain clarity
Consequence Some feature requests are rejected by design.
Decision GridHammer expressly forbids implementation of CPMS business logic (pricing, billing, invoicing, user ledgers, roaming settlement).
Rationale
- GridHammer is a test tool, not a CPMS.
- Implementing CPMS logic creates circular dependencies (testing our logic vs target logic).
- Focus must remain on protocol stress.
Consequence
Agents like pricing-agent, billing-agent, invoicing-agent, ledger-agent, user-agent, and settlement-agent are permanently out of scope.
Decision GridHammer will not implement OCPI, OCHP, OICP, or any roaming settlement protocols.
Rationale
- GridHammer simulates a single Charging Station (or set of EVSEs) connecting to a single CSMS.
- Roaming complexity belongs in the CSMS or a dedicated roaming simulator.
Consequence
No ocpi-agent or roaming-agent.
Decision The Gateway layer must be a dumb pipe. No message buffering (beyond TCP/WebSocket framing), no retry smoothing, no connection holding.
Rationale
- "Smart" gateways hide network/CSMS failures.
- We want to expose failures, not mask them.
Consequence
Network errors propagate immediately to the core FSM. No smart-gateway-agent.
Decision
ChargingProfile execution must be pure, synchronous, and deterministic. It resolves TxProfile, TxDefaultProfile, and ChargingStationMaxProfile into a single EnforcedLimit with an explicit EnforcementReason.
Rationale
- Zero Ambiguity: The CSMS must know exactly why a limit was applied (Profile vs. Station vs. Internal).
- Zero-Power Semantics: A limit of 0.0 must explicitly trigger
SuspendedEVSEorSuspendedEVstate. - Tie-breaking: Overlapping profiles are resolved by
stackLevel>id(or specific OCPP 2.1 rules), with no "undefined behavior".
Consequence
The Executor is a pure function. Evse logic depends on this output for all power limits. No "soft" limits or heuristics allowed.
Decision GridHammer will not simulate low-level ISO-15118 Power Line Communication (PLC) timing, signal modulation, or SLAC.
Rationale
- Focus on Application Layer: GridHammer targets OCPP 2.1 application layer logic and state transitions.
- Complexity: PLC simulation requires specialized PHY-layer modeling that distracts from protocol stress testing.
- Abstraction: We assume the EV-EVSE communication link is functional if the session exists.
Consequence
No plc-agent or low-level signal processing. Authentication and authorization happen at the OCPP level.
Decisions here change only if:
- They block correctness
- They block determinism
- They prevent real-world bug discovery
Preference is always to tighten, not loosen.