Good First Issue
Add a new scenario meter-value-zero: a transaction where the meter register
reads zero throughout. This is a negative control. A flat register is not by
itself a detectable fault today, and the scenario pins that down so a future
change to METER_VALUE_ANOMALY cannot start reporting it by accident.
METER_VALUE_ANOMALY fires only on negative or decreasing cumulative readings.
An all-zero series is neither, so this trace must come back clean. Whether a
stuck register deserves its own rule is tracked separately in #144.
What to do
- Create
packages/toolkit/src/scenarios/__scenarios__/meter-value-zero.ts
- Build a synthetic trace of a transaction whose meter never advances:
BootNotification at 2026-01-15T09:00:00.000Z, and its CallResult with
interval: 300
Authorize with idTag: 'SYNTHETIC-TAG-017' at 09:00:30.000Z, accepted
StartTransaction on connector 1 at 09:01:00.000Z with meterStart: 0,
answered with transactionId: 100017
MeterValues at 09:02:00.000Z, 09:03:00.000Z and 09:04:00.000Z, each
carrying a single sampledValue of '0' with measurand
Energy.Active.Import.Register and unit Wh
StopTransaction at 09:05:00.000Z with meterStop: 0 and
reason: 'Local'
- A
CallResult for every Call
- Set
expectedFailures: []
- Add
{ type: 'no_failures', params: {} } as the assertion
- Import and register in
packages/toolkit/src/scenarios/index.ts
- Update the scenario count in every place that states it, see "Files to modify"
- Run
ocpp-debugkit ci to verify all scenarios pass, then run the full local
check from
Verify Locally.
ocpp-debugkit ci covers neither formatting nor lint nor types, and CI stops
at the first failure.
- Add a changeset with
pnpm changeset, and pick patch. Scenario additions
are patch releases, see
Adding a Scenario.
Why those timestamps
The transaction runs four minutes, comfortably past the sixty second floor that
SUSPICIOUS_SESSION_DURATION watches for. The whole trace also finishes inside
twice the three hundred second heartbeat interval, so TIMEOUT_NO_HEARTBEAT
stays silent without needing a heartbeat in the trace. This trace was run against
the detection engine and reports no failures.
Files to modify
packages/toolkit/src/scenarios/__scenarios__/meter-value-zero.ts (new)
packages/toolkit/src/scenarios/index.ts (register, and add to scenarioNames)
packages/toolkit/src/scenarios/index.test.ts (count, name order, getScenario)
tests/external-fixture/test.mjs (count)
README.md (count)
packages/toolkit/README.md (count)
.changeset/ (new changeset file)
The first two of the count files fail the test suite when they drift. The two
READMEs do not, so they are easy to miss.
Guidelines
- All data must be synthetic. This scenario reserves station ID
CS-SYNTHETIC-017, so please use that one.
- Follow the pattern in an existing scenario file.
meter-anomaly.ts is the
closest match for shape, and normal-session is the closest for a scenario
that expects no failures.
- Verify with
ocpp-debugkit scenario run meter-value-zero that no failures are
reported. If a rule does fire, adjust the trace rather than adding the code to
expectedFailures, since the whole point of this scenario is that it stays
clean.
- The scenario count depends on what has merged ahead of you. Run the suite and
use the number it reports rather than assuming.
How to claim
Comment "I'd like to work on this" and it will be assigned to you.
Please hold one open claim at a time. Once the pull request for it is merged,
say which issue you want next and it will be assigned. That keeps issues from
sitting claimed while another is still in review, so other newcomers can see
what is genuinely free.
Good First Issue
Add a new scenario
meter-value-zero: a transaction where the meter registerreads zero throughout. This is a negative control. A flat register is not by
itself a detectable fault today, and the scenario pins that down so a future
change to
METER_VALUE_ANOMALYcannot start reporting it by accident.METER_VALUE_ANOMALYfires only on negative or decreasing cumulative readings.An all-zero series is neither, so this trace must come back clean. Whether a
stuck register deserves its own rule is tracked separately in #144.
What to do
packages/toolkit/src/scenarios/__scenarios__/meter-value-zero.tsBootNotificationat2026-01-15T09:00:00.000Z, and itsCallResultwithinterval: 300AuthorizewithidTag: 'SYNTHETIC-TAG-017'at09:00:30.000Z, acceptedStartTransactionon connector 1 at09:01:00.000ZwithmeterStart: 0,answered with
transactionId: 100017MeterValuesat09:02:00.000Z,09:03:00.000Zand09:04:00.000Z, eachcarrying a single
sampledValueof'0'with measurandEnergy.Active.Import.Registerand unitWhStopTransactionat09:05:00.000ZwithmeterStop: 0andreason: 'Local'CallResultfor every CallexpectedFailures: []{ type: 'no_failures', params: {} }as the assertionpackages/toolkit/src/scenarios/index.tsocpp-debugkit cito verify all scenarios pass, then run the full localcheck from
Verify Locally.
ocpp-debugkit cicovers neither formatting nor lint nor types, and CI stopsat the first failure.
pnpm changeset, and pick patch. Scenario additionsare patch releases, see
Adding a Scenario.
Why those timestamps
The transaction runs four minutes, comfortably past the sixty second floor that
SUSPICIOUS_SESSION_DURATIONwatches for. The whole trace also finishes insidetwice the three hundred second heartbeat interval, so
TIMEOUT_NO_HEARTBEATstays silent without needing a heartbeat in the trace. This trace was run against
the detection engine and reports no failures.
Files to modify
packages/toolkit/src/scenarios/__scenarios__/meter-value-zero.ts(new)packages/toolkit/src/scenarios/index.ts(register, and add toscenarioNames)packages/toolkit/src/scenarios/index.test.ts(count, name order,getScenario)tests/external-fixture/test.mjs(count)README.md(count)packages/toolkit/README.md(count).changeset/(new changeset file)The first two of the count files fail the test suite when they drift. The two
READMEs do not, so they are easy to miss.
Guidelines
CS-SYNTHETIC-017, so please use that one.meter-anomaly.tsis theclosest match for shape, and
normal-sessionis the closest for a scenariothat expects no failures.
ocpp-debugkit scenario run meter-value-zerothat no failures arereported. If a rule does fire, adjust the trace rather than adding the code to
expectedFailures, since the whole point of this scenario is that it staysclean.
use the number it reports rather than assuming.
How to claim
Comment "I'd like to work on this" and it will be assigned to you.
Please hold one open claim at a time. Once the pull request for it is merged,
say which issue you want next and it will be assigned. That keeps issues from
sitting claimed while another is still in review, so other newcomers can see
what is genuinely free.