Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ studio/
├── src/
│ ├── main.zig # Model, Msg, update, app wiring
│ ├── app.native # the view (declarative markup)
│ ├── ocpp/ # pure, headless OCPP engine (types, parser, …)
│ ├── ocpp/ # pure, headless OCPP engine (types, parser, detection, …)
│ │ └── conformance/ # vendored shared-contract fixtures + goldens + harness
│ └── tests.zig # headless view/model tests
├── scripts/smoke.sh # portable automation smoke test (Xvfb in CI)
├── docs/adr/ # architecture decision records
Expand Down
40 changes: 22 additions & 18 deletions CURRENT_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

## Active milestone

**S2 — Detection + conformance (0.1.0): in progress.** S1 — Engine core is
complete (see [ROADMAP.md](ROADMAP.md)).
**S2 — Detection + conformance (0.1.0): complete.** Next up: **S3 — Inspector UI**
(see [ROADMAP.md](ROADMAP.md)).

## What's done

Expand Down Expand Up @@ -53,22 +53,26 @@ conformance contract (behavior, not source) and tested via
correlates end to end (one completed session, transactionId 100001); engine
tests green headlessly on macOS + Linux.

### S2 — Detection + conformance ✅

The full 16-rule OCPP 1.6J failure taxonomy in `src/ocpp/detection.zig`, mirroring
the toolkit's `detection.ts`, plus a harness that locks Studio's output to the
toolkit's:

- **Failure model + foundational rules** (#19) — the `Failure` / `FailureCode` /
`FailureSeverity` model and rules 1–3.
- **Protocol & transaction rules** (#20) — rules 4–10.
- **Timing & anomaly rules** (#21) — rules 11–16.
- **Conformance harness** (#22) — 15 vendored scenario traces + goldens
(`src/ocpp/conformance/`, `contract-v1`, generated from the toolkit) and a
`native test` gate asserting Studio's de-duplicated, sorted `FailureCode` set
matches each golden.

**Exit criteria met:** 15/15 scenarios match the locked goldens.

## What's in progress

**S2 — Detection + conformance (0.1.0).** Building the 16-rule failure taxonomy
in Zig, mirroring the toolkit's `detection.ts`:

- **Failure model + foundational rules** (#19) — the `Failure` / `FailureCode`
(16-code taxonomy) / `FailureSeverity` model, the `detection.zig` orchestrator
with per-code severity + remediation metadata, and rules 1–3
(FAILED_AUTHORIZATION, CONNECTOR_FAULT, STATION_OFFLINE_DURING_SESSION).
- **Protocol & transaction rules** (#20) — rules 4–10: TIMEOUT_NO_HEARTBEAT,
METER_VALUE_GAP, INVALID_STOP_REASON, UNEXPECTED_START,
STATUS_TRANSITION_VIOLATION, DIAGNOSTICS_FAILURE, FIRMWARE_UPDATE_FAILURE.
- **Timing & anomaly rules** (#21) — rules 11–16: SUSPICIOUS_SESSION_DURATION,
SLOW_RESPONSE, HEARTBEAT_INTERVAL_VIOLATION, METER_VALUE_ANOMALY,
UNRESPONSIVE_CSMS, REPEATED_BOOT_NOTIFICATION. All 16 rules now run.
- Next: the conformance harness over the 15 shared scenarios (#22).
- Nothing in flight — S2 is closed; S3 is next.

## What's next

Expand All @@ -86,8 +90,8 @@ search / filter, handling traces far larger than a browser tab can hold.
| --- | --- |
| `repo` (tooling, CI) | ✅ done for S0 |
| `docs` (docs, ADRs) | ✅ done for S0 |
| `ocpp` (engine) | 🚧 detection in progress (S2) |
| `ocpp` (engine) | ✅ done for S2 |
| `ui` (native views) | ⬜ placeholder (S3) |
| `capture` (live proxy) | ⬜ not started (S5) |
| `cli` (headless) | ⬜ not started (S4) |
| `conformance` | ⬜ not started (S2) |
| `conformance` | ✅ done for S2 (15/15, `contract-v1`) |
14 changes: 8 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ the stable part.
| --- | --- | --- | --- |
| **S0** | 0.0.x | Foundation | ✅ Complete |
| **S1** | 0.1.0 | Engine core | ✅ Complete |
| **S2** | 0.1.0 | Detection + conformance | Next up |
| **S3** | 0.2.0 | Inspector UI | Planned |
| **S2** | 0.1.0 | Detection + conformance | ✅ Complete |
| **S3** | 0.2.0 | Inspector UI | Next up |
| **S4** | 0.3.0 | Analysis parity+ | Planned |
| **S5** | 0.4.0 | Live capture ⭐ | Planned |
| **S6** | 1.0.0 | 1.0 polish | Planned |
Expand All @@ -32,11 +32,13 @@ inference), and session correlation by transaction id. **Exit criteria met:** th
vendored `normal-session` fixture parses and correlates end to end; engine tests
run green headlessly (`native test -Dplatform=null`) on macOS + Linux.

## S2 — Detection + conformance (0.1.0)
## S2 — Detection + conformance (0.1.0)

The full OCPP 1.6J failure taxonomy in Zig, plus the conformance harness that
runs the shared scenario fixtures and checks Studio's detected failures against
locked goldens. **Exit:** the shared scenarios match, byte for byte.
The full OCPP 1.6J failure taxonomy in Zig — all 16 detection rules — plus the
conformance harness that runs the 15 shared scenario fixtures and checks Studio's
detected failures against locked goldens generated from the toolkit.
**Exit criteria met:** 15/15 scenarios match the `contract-v1` goldens under
`native test`.

## S3 — Inspector UI (0.2.0)

Expand Down
44 changes: 44 additions & 0 deletions src/ocpp/conformance/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Conformance contract (`contract-v1`)

Studio and the TypeScript toolkit are **independent implementations** of the same
OCPP analysis behavior (ADR-0001). This directory is the machine-checked contract
between them: the shared scenarios and the failure codes each must detect.

- **`fixtures/<name>.json`** — the 15 shared scenario **traces** (the input).
- **`goldens/<name>.json`** — each scenario's expected **de-duplicated, sorted
`FailureCode` set** (the output to match), as a JSON array of wire codes.
- **`harness.zig`** — runs, under `native test`, the full engine
(`parseTrace → buildSessionTimeline → detectFailures`) over every fixture and
asserts its detected code set equals the golden — the same comparison the
toolkit's `evaluateScenario` makes. A missing or extra code fails the scenario
by name.

## Generated, not hand-authored

Both the fixtures and the goldens are exported from the toolkit — the source of
truth — so a golden can never drift from what the reference implementation
actually detects. They are regenerated (not edited by hand) from the toolkit's
`scenarios` and `evaluateScenario`:

```js
// run against a built @ocpp-debugkit/toolkit
import { scenarios } from '@ocpp-debugkit/toolkit/scenarios';
import { evaluateScenario } from '@ocpp-debugkit/toolkit';
for (const s of scenarios) {
const detected = [...new Set(evaluateScenario(s).failures.map((f) => f.code))].sort();
// fixtures/<s.name>.json <- JSON.stringify(s.trace)
// goldens/<s.name>.json <- JSON.stringify(detected)
}
```

## Why it lives under `src/`

The Native SDK zero-config build (ADR-0004) embeds test data with `@embedFile`,
which resolves within the source module root. Keeping the vendored contract here
lets the harness embed it directly — no runtime file I/O, fully hermetic.

## Versioning

Tagged **`contract-v1`** (OCPP 1.6J). When the contract changes — new rules,
new scenarios, or OCPP 2.0.1 — regenerate against the matching toolkit release
and bump the tag.
Loading
Loading