Skip to content

Latest commit

 

History

History
84 lines (70 loc) · 4.92 KB

File metadata and controls

84 lines (70 loc) · 4.92 KB

The conformance contract (contract-v2)

OCPP DebugKit Studio and the TypeScript toolkit are two independent implementations of the same OCPP analysis behavior — one native (Zig), one for the browser and CI (TypeScript). They share no code. They meet only here: a machine-checked conformance contract that guarantees both produce the same analysis of the same trace.

That is the trust story. A trace captured in Studio opens in the toolkit's web inspector and vice versa; a failure Studio flags is a failure the toolkit flags. Two implementations agreeing is a stronger correctness signal than either alone — and it is enforced in CI on every change, not asserted in prose.

What the contract covers

  • Trace format. OCPP-J array messages — [2, id, action, payload] (Call), [3, id, payload] (CallResult), [4, id, errorCode, errorDescription, details] (CallError) — in any of three containers: a JSON object with an events array, JSONL (one message per line), or a bare array.
  • Event model. Each message normalizes to a canonical Event (unique id, message id, timestamp, direction, message type, action, payload, error fields, and the raw array). Direction inference and timestamp normalization (ISO 8601 or epoch) are part of the contract. See ADR-0005.
  • Session correlation. Events correlate into Sessions by transactionId, with connector- and time-based attribution of un-keyed events.
  • Failure taxonomy. The full OCPP 1.6J failure model — 16 detection rules, each with a stable FailureCode, a fixed severity (4 critical, 10 warning, 2 info), and the same thresholds as the reference (heartbeat 60 s, slow response 10 s, ±50 % heartbeat deviation, session bounds, the 5-minute boot window). The rules live in src/ocpp/detection.zig.
  • Scenarios. 18 shared scenario traces exercising the rules end to end, each pinned to the exact de-duplicated, sorted FailureCode set the reference implementation detects.

How conformance is enforced

The 18 scenarios and their expected failure-code sets are vendored from the toolkit — the source of truth — never hand-authored, so a golden can't drift from what the reference actually detects. On every change, native test runs Studio's full engine (parseTrace → buildSessionTimeline → detectFailures) over each fixture and asserts its detected code set equals the golden — the same comparison the toolkit's evaluateScenario makes. 18/18 must match; a release is blocked otherwise. studio ci runs the same check from the command line.

The corpus is a sample, not a proof: two implementations can both match every golden and still disagree on inputs no fixture reaches. That is not theoretical. Three rules disagreed with the specification here for as long as they did in the toolkit while the harness stayed green, because no fixture exercised a firmware status, a non-Invalid idTagInfo, or the connector-status transitions involved (#93). When a rule changes, widen the corpus rather than trusting the count.

The vendored fixtures, goldens, the harness, and the exact regeneration recipe live in src/ocpp/conformance/.

Freeze & versioning

The current contract is contract-v2 (OCPP 1.6J), 18 scenarios, regenerated against toolkit 0.4.5. The vendored fixtures and goldens are pinned, and the harness gates every build against them. The cut is recorded in ADR-0013; contract-v1 (15 scenarios, frozen for 0.5.0) is ADR-0012.

contract-v2 is a strict superset of v1: regenerating all 18 against toolkit 0.4.5 reproduces v1's 15 fixtures and goldens byte for byte, so every scenario v1 pinned, v2 pins identically.

The contract is immutable within a version. A change that alters detected output — a new or changed rule, a new scenario, a threshold change, or OCPP 2.0.1 — is a new contract version (contract-v3, …), regenerated against the matching toolkit release and re-tagged, never an in-place edit of a released version. Earlier versions stay reachable through the release tags: v0.5.4's tree carries contract-v1, so every released Studio remains pinned to a reproducible reference. This keeps "two implementations, one format" a checkable claim rather than a hope.

One question this policy leaves open, tracked in #94: whether a rule correction that leaves every golden matching needs a version bump at all, given that the contract's artifacts are the fixtures and the goldens. The corpus expansion above is not that case, since "a new scenario" is named explicitly, so it does not settle it.

See also ADR-0001 (independent implementation + shared contract) and docs/cli-parity.md (Studio ⇄ toolkit CLI parity).