|
1 | | -# The conformance contract (`contract-v1`) |
| 1 | +# The conformance contract (`contract-v2`) |
2 | 2 |
|
3 | 3 | OCPP DebugKit Studio and the TypeScript [toolkit](https://github.com/ocpp-debugkit/toolkit) |
4 | 4 | are **two independent implementations** of the same OCPP analysis behavior — one |
@@ -28,35 +28,56 @@ and it is enforced in CI on every change, not asserted in prose. |
28 | 28 | 2 info**), and the same thresholds as the reference (heartbeat 60 s, slow |
29 | 29 | response 10 s, ±50 % heartbeat deviation, session bounds, the 5-minute boot |
30 | 30 | window). The rules live in [`src/ocpp/detection.zig`](../src/ocpp/detection.zig). |
31 | | -- **Scenarios.** **15 shared scenario traces** exercising the rules end to end, |
| 31 | +- **Scenarios.** **18 shared scenario traces** exercising the rules end to end, |
32 | 32 | each pinned to the exact de-duplicated, sorted `FailureCode` set the reference |
33 | 33 | implementation detects. |
34 | 34 |
|
35 | 35 | ## How conformance is enforced |
36 | 36 |
|
37 | | -The 15 scenarios and their expected failure-code sets are **vendored from the |
| 37 | +The 18 scenarios and their expected failure-code sets are **vendored from the |
38 | 38 | toolkit — the source of truth — never hand-authored**, so a golden can't drift |
39 | 39 | from what the reference actually detects. On every change, `native test` runs |
40 | 40 | Studio's full engine (`parseTrace → buildSessionTimeline → detectFailures`) over |
41 | 41 | each fixture and asserts its detected code set equals the golden — the same |
42 | | -comparison the toolkit's `evaluateScenario` makes. **15/15 must match; a release |
| 42 | +comparison the toolkit's `evaluateScenario` makes. **18/18 must match; a release |
43 | 43 | is blocked otherwise.** `studio ci` runs the same check from the command line. |
44 | 44 |
|
| 45 | +The corpus is a **sample, not a proof**: two implementations can both match every |
| 46 | +golden and still disagree on inputs no fixture reaches. That is not theoretical. |
| 47 | +Three rules disagreed with the specification here for as long as they did in the |
| 48 | +toolkit while the harness stayed green, because no fixture exercised a firmware |
| 49 | +status, a non-`Invalid` `idTagInfo`, or the connector-status transitions involved |
| 50 | +(#93). When a rule changes, widen the corpus rather than trusting the count. |
| 51 | + |
45 | 52 | The vendored fixtures, goldens, the harness, and the exact regeneration recipe |
46 | 53 | live in [`src/ocpp/conformance/`](../src/ocpp/conformance/README.md). |
47 | 54 |
|
48 | 55 | ## Freeze & versioning |
49 | 56 |
|
50 | | -For the 0.5.0 release the contract is **frozen as `contract-v1`** (OCPP 1.6J): |
51 | | -the vendored fixtures and goldens are pinned, and the harness gates every build |
52 | | -against them. The freeze rationale is recorded in |
53 | | -[ADR-0012](adr/0012-freeze-contract-v1.md). |
| 57 | +The current contract is **`contract-v2`** (OCPP 1.6J), 18 scenarios, regenerated |
| 58 | +against toolkit `0.4.5`. The vendored fixtures and goldens are pinned, and the |
| 59 | +harness gates every build against them. The cut is recorded in |
| 60 | +[ADR-0013](adr/0013-contract-v2-corpus.md); `contract-v1` (15 scenarios, frozen |
| 61 | +for 0.5.0) is [ADR-0012](adr/0012-freeze-contract-v1.md). |
| 62 | + |
| 63 | +`contract-v2` is a **strict superset** of v1: regenerating all 18 against toolkit |
| 64 | +0.4.5 reproduces v1's 15 fixtures and goldens byte for byte, so every scenario v1 |
| 65 | +pinned, v2 pins identically. |
54 | 66 |
|
55 | 67 | The contract is **immutable within a version.** A change that alters detected |
56 | 68 | output — a new or changed rule, a new scenario, a threshold change, or OCPP |
57 | | -2.0.1 — is a **new contract version** (`contract-v2`, …), regenerated against the |
58 | | -matching toolkit release and re-tagged, never an in-place edit of `contract-v1`. |
59 | | -This keeps "two implementations, one format" a checkable claim rather than a hope. |
| 69 | +2.0.1 — is a **new contract version** (`contract-v3`, …), regenerated against the |
| 70 | +matching toolkit release and re-tagged, never an in-place edit of a released |
| 71 | +version. Earlier versions stay reachable through the release tags: `v0.5.4`'s tree |
| 72 | +carries `contract-v1`, so every released Studio remains pinned to a reproducible |
| 73 | +reference. This keeps "two implementations, one format" a checkable claim rather |
| 74 | +than a hope. |
| 75 | + |
| 76 | +One question this policy leaves open, tracked in #94: whether a rule correction |
| 77 | +that leaves **every** golden matching needs a version bump at all, given that the |
| 78 | +contract's artifacts are the fixtures and the goldens. The corpus expansion above |
| 79 | +is not that case, since "a new scenario" is named explicitly, so it does not |
| 80 | +settle it. |
60 | 81 |
|
61 | 82 | See also [ADR-0001](adr/0001-independent-implementation.md) (independent |
62 | 83 | implementation + shared contract) and [docs/cli-parity.md](cli-parity.md) |
|
0 commit comments