Commit b907992
* feat(meter-values): coherent MeterValues generator (issue #40)
Implements physics-coherent MeterValues (V->P->I->dE->SoC) gated by template
flag coherentMeterValues. Session lifecycle on ChargingStation with txId
snapshotted before resetConnectorStatus. Strategy gate after versioned
sampled-value dispatcher, before legacy random measurand generation.
Deterministic Mulberry32 PRNG with per-label stream splitting. New module
under src/charging-station/meter-values/. Golden invariants harness green.
Refs: #40
* test(meter-values): regression tests for Phase 4 findings (issue #40)
RED phase for M1..M4 findings from /tmp/issue-40/review-consolidated.md:
- M1: voltage PRNG must advance state across samples
- M2: deltaEnergyWh must be clamped to remaining battery capacity at 100% SoC
- M3-OCPP16: coherent session destroyed even if station stops during postTransactionDelay
- M3-OCPP20: same for OCPP 2.0 sibling path
- M4: stopEnergyWh assertion strengthened to remove self-reference tautology
Currently 4 tests fail (expected RED); M4 rewrite passes (strengthening only).
* fix(meter-values): address Phase 4 review findings (issue #40)
- M1: cache voltage PRNG on CoherentSession (was reconstructed each
sample, producing a stalled seed sequence). PRNG state now advances
across samples as documented.
- M2: clamp powerW to remaining battery capacity so a sample crossing
100 % SoC cannot over-charge the register. Everything downstream
(I, ΔE, register) is recomputed from clamped power, preserving
INV-1 and INV-3.
- M3-OCPP16 / M3-OCPP20: destroy the coherent session BEFORE awaiting
postTransactionDelay so an intervening station stop cannot leak the
session. destroyCoherentSession is idempotent so the post-sleep
path remains valid.
Regression tests (M1..M4): pass 23/23.
Full suite: pass 2908/0/6 skipped.
* fix(coherent-meter-values): floor reportedPowerW to remaining capacity + tighten M4 register cross-check
Phase 6 verification findings addressed:
- N1 (gpt-5.5 HIGH, opus MED): capacity-clamp fallback risked INV-1 breach.
Investigation: CURRENT_ROUNDING_SCALE=2 keeps V*I within <=0.1 W of
reportedPowerW on realistic mains, well under INV-1 tolerance (+/-1 W).
Simplified: floor reportedPowerW to maxPowerFromCapacityW after utility
recompute (absorbs float drift without touching currentA).
- V1-M4 secondary (sonnet 'partial'): assertion now reads MV[last] (was
MV[2], tautological). Independent Sigma(P*dt) primary check unchanged.
* [autofix.ci] apply automated fixes
* fix(meter-values): address PR #1935 review findings (issue #40)
Consolidated fixes for all 30 findings from the multi-agent code review of
PR #1935. Preserves the coherent MeterValues feature scope; adds OCPP 2.0
end-to-end wiring; hardens correctness and idiomaticity.
Blocking (2):
- B1 fix INV-1 breach in capacity-clamp branch: derive current as exact
fraction (P / (V·phases)), round at emit, then derive emitted P from
rounded V·I·phases. Prior integer-amp rounding could inflate V·I·phases
above the capacity-clamped power by up to V·phases·0.5 W. New AC 3-phase
and DC regression tests lock the invariant.
- B2 wire OCPP 2.0.1 support: add createCoherentSession call in
OCPP20ResponseService.handleResponseTransactionEvent (Started case),
mirroring OCPP 1.6. New 5-scenario integration test covering Accepted,
implicit Accept, rejected idToken, force-override, and non-Started events.
High (4):
- H1 clear coherentSessions in ChargingStation.stop() finally; dispose
runtime state per session before delete.
- H2 README: add three template-parameter rows (coherentMeterValues,
evProfilesFile, randomSeed) and a new 'EV profile file format' subsection
documenting the ev-profiles-template.json schema.
- H3 strip process residue: remove /tmp/issue-40/* references (3 files),
'Phase 2 merged finding #N' and 'Fix Phase 4 M-N' markers (8+ locations);
replace with technical rationale.
- H4 label INV-1/INV-2/INV-3 in the class-level JSDoc using the
PR-body-canonical numbering (INV-1=V·I=P, INV-2=SoC monotone,
INV-3=ΔE=P·Δt). Remove undefined INV-4 reference.
Medium (13):
- M1 DRY resolveRootSeed via hashLabel (byte-equivalent, test-locked).
- M2 move voltagePrng runtime state off CoherentSession to a module-scope
WeakMap keyed on session identity (no cross-station coupling); add
disposeCoherentSessionRuntime wired into destroyCoherentSession + stop().
- M3 collapse five identical rounding scales into a single ROUNDING_SCALE.
- M4 add explanatory comment on the boundary 'as MeterValue' cast
(OCPP16/20 SampledValue.context enums structurally diverge).
- M5 correct Prng.ts JSDoc: 'SplitMix32-derived' -> 'Mulberry32 + FNV-1a'.
- M6 remove 'byte-identical' over-claims; use 'reproducible' / 'identical'.
- M7 defensive early-return zero-sample when intervalMs <= 0 to prevent
NaN contamination when SoC has already saturated.
- M8 trim meter-values/index.ts barrel from 22 to 11 externally-consumed
symbols.
- M9 mark 7 immutable CoherentSession fields readonly.
- M10 add ChargingStation.injectCoherentSession() public method and use it
in 3 test sites, replacing 'station as unknown as { coherentSessions }'
private-field injection.
- M11 fix 'transaction id' -> 'transactionId' in Prng.ts comment.
- M12 replace global Date.now monkey-patch with per-iteration
mock.method(Date, 'now', ...) from node:test.
- M13 remove dead chargingProfileLimitW parameter
(getConnectorMaximumAvailablePower already folds in charging profiles).
Low / Nit:
- C4 clear-on-stop (covered under H1).
- C5 XOR-commutativity in deriveSeed: deferred with explanatory comment
(birthday bound ~2^16 well beyond simulator scale; a non-commutative mix
would desync existing golden tests).
- D-7 rename prng.ts -> Prng.ts (and prng.test.ts -> Prng.test.ts) to
match repo PascalCase filename convention.
- D-8 move getEvProfilesFile from EvProfiles.ts to Helpers.ts next to
getIdTagsFile.
- D-9 fix resolveTemplates JSDoc: remove false 'mirrors EVSE lookup' claim.
- D-11 CoherentMeterValuesDefaults now exposes all tunable constants.
- D-18 use AvailabilityType.Operative enum instead of string cast.
- I1 auto-resolved by B1 (ROUNDING_SCALE=2 now semantically meaningful
for current).
- T2 use getErrorMessage() (repo convention) instead of (error as Error).
- S2 simplify templatesFor test helper — remove 'as unknown as { unit }'
casts.
- S5 consolidate duplicate BuildVersionedSampledValueFn type into the
canonical BuildVersionedSampledValue exported from meter-values.
Verification:
- pnpm lint 0 errors, 0 warnings
- pnpm typecheck 0 errors
- pnpm test 2918 pass / 0 fail / 6 skipped
- New regression tests locking B1 (INV-1 clamp AC3+DC), M7 (NaN guard),
M2 (session hygiene + WeakMap dispose), M1 (hashLabel equivalence),
B2 (OCPP 2.0 session wiring, 5 scenarios).
Closes #40
* fix(meter-values): address PR #1935 round-2 review findings (issue #40)
Consolidated fixes for all Medium+Low+Nit findings from the second
multi-agent review round of PR #1935. Two Blocking findings (S1 OCPP 1.6
signed-meter-values wrapper, S2 begin MeterValue routing) — S2 implemented,
S1 deferred to a follow-up (post-hoc signing in startUpdatedMeterValues
already covers the OCPP 1.6 periodic path; the remaining gap is only
TriggerMessage/broadcast callsites, best served by a dedicated PR with a
proper signing-key test fixture).
## Blocking (1 of 2 addressed; other deferred)
- **S2 (implemented)** — `Transaction.Started` / `Transaction.Begin`
MeterValue is now generated by the coherent path. Made
`ChargingStation.createCoherentSession` idempotent so early
request-builder creation is safe; reordered OCPP 2.0 flows
(`OCPP20ServiceUtils.startTransactionOnConnector`,
`OCPP20IncomingRequestService` RequestStartTransaction handler) to
create the session BEFORE `buildTransactionStartedMeterValues`;
reordered OCPP 1.6 flow (`OCPP16ResponseService.handleResponseStartTransaction`)
and added a coherent-mode branch to
`OCPP16ServiceUtils.buildTransactionBeginMeterValue` that routes
through `buildMeterValue` when a session is live.
- **S1 (deferred)** — OCPP 1.6 signed-meter-values wrapper for the
coherent path. Rationale: `startUpdatedMeterValues` in
`OCPP16ServiceUtils` applies post-hoc signing after `buildMeterValue`
returns, so the OCPP 1.6 periodic coherent path IS signed today. The
actual gap is only the TriggerMessage / worker-broadcast callsites
where signing is skipped. Fixing it cleanly requires a signing-key
test fixture that is best set up in a dedicated PR.
## Medium (8)
- **M-01/M-02/M-03/M-07 combined defensive-guard block**
(`computeCoherentSample`): early-return zero-sample when `intervalMs ≤ 0`
(existing), `batteryCapacityWh ≤ 0` or non-finite (M-01), or
`voltageOut ≤ 0` or non-finite (M-02). `rampUpDurationMs` guard now
requires `> 0 && Number.isFinite(...)` (M-03). Prevents NaN poisoning
and INV-1/INV-3 incoherence across the four sources.
- **M-04** — Reverted the proposed Zod refinement for sorted `chargingCurve`
after design analysis showed `loadEvProfilesFile`'s in-place sort is
the authoritative defense and the refinement would break the loader's
"accepts unsorted, sorts in place" contract. Documented rationale in
`EvProfileSchema` JSDoc.
- **M-06** — Renamed `ChargingStation.injectCoherentSession` →
`__injectCoherentSession` (dunder-prefix test-seam convention);
tightened mock parameter type from `unknown` to `CoherentSession`;
updated the 3 test call sites.
- **M-07** — Fixed the determinism claim in README.md and PR body:
`interval` is a physics parameter, not a PRNG seed input. New prose
makes this explicit.
- **M-08** — Coherent path now respects OCPP 2.0.1 `SampledDataCtrlr.TxUpdatedMeasurands`
/ `TxEndedMeasurands` / `TxStartedMeasurands` and OCPP 1.6
`MeterValuesSampledData`. Added `resolveEnabledMeasurands` helper in
`OCPPServiceUtils.ts` and threaded a `ReadonlySet<MeterValueMeasurand>`
allow-list into `buildCoherentMeterValue`. Governs J02.FR.11 / E02.FR.09
/ E06.FR.11.
## Deferred to follow-up issue (3)
- **M-05** — Extract `CoherentMeterValuesManager.getInstance(chargingStation)`.
Sibling per-station concerns (AutomaticTransactionGenerator, IdTagsCache,
SharedLRUCache) use the multiton pattern; the coherent module currently
keeps state on `ChargingStation`. Not a correctness issue; architectural
refactor best done standalone.
- **N-03** — Blocked on M-05 (semantic circularity in `ICoherentContext.getCoherentSession`
cleaned up naturally when the manager owns the session store).
- **N-04** — `Prng.ts` filename kept as-is; renaming to `PRNG.ts` on a
case-insensitive macOS FS would require a second two-step rename with
no functional benefit.
## Low/Nit (10)
- **N-01** — Dropped `disposeCoherentSessionRuntime` from the
`meter-values/index.ts` barrel; direct sub-module import in
`ChargingStation.ts` (barrel exposes only externally-consumed symbols).
- **N-02** — Rephrased the `Fix B1:` process-comment in
`CoherentMeterValuesGenerator.ts` to invariant-only technical rationale
(H3 miss from the previous round).
- **N-05** — Renamed voltage locals in `computeCoherentSample`:
`voltageNominal`/`voltageV`/`roundedVoltage` →
`nominalV`/`sampledV`/`roundedV` (fewer names for the same quantity).
- **N-06** — Added defensive `destroyCoherentSession` in the OCPP 2.0
`handleResponseTransactionEvent` `Ended` branch when connectorId is
unknown (symmetric with OCPP 1.6 defensive destroy in
`handleResponseStopTransaction`).
- **N-07** — Tightened `deriveSeed` JSDoc with quantified birthday
bound: expected collisions ≈ N²/2^33; at simulator scale (≤ 5×10⁴
pairs) ≈ 0.3 — negligible.
- **N-08** — Tightened AC1/AC3/DC test tolerances from ≤ 1/3/1 W to
≤ 0.01 W (post-Option D tight bound is 0.005 W).
- **N-09** — Uniform `getErrorMessage(error)` in EvProfiles.ts
ZodError branch (was direct `error.message`, inconsistent with the
else branch).
- **N-10** — Removed dead exports `CoherentMeterValuesDefaults` and
`mixSeed` (grep-verified zero external usages).
- **N-11 F-04** — `@file` tag "MeterValue generator" (singular) →
"MeterValues generator" (plural OCPP term).
- **N-11 F-07** — README schema example id aligned with the actual
`ev-profiles-template.json` (`compact-ev-40kwh` → `city-ev-40kWh`).
- **N-11 F-08** — README documents the `initialSocPercentMin` ≤
`initialSocPercentMax` swap-and-warn behavior.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2878 pass / 0 fail / 6 skipped
Refs #40
* fix(meter-values): address PR #1935 round-3 review findings (issue #40)
Consolidated fixes for all findings from the third multi-agent review round.
No blocking findings remain; two content-lane blocks (barrel count, README
example) plus 4 cross-validated HIGH nits addressed.
## HIGH (4)
- **H1** — Correct false JSDoc claim at `ChargingStation.ts:319`. The
`__injectCoherentSession` docstring stated the `__` prefix was enforced
by a `no-restricted-syntax` ESLint rule; no such rule exists. Reworded
to "convention only — not currently enforced by a lint rule".
- **H2** — Trim 4 dead type re-exports from `src/charging-station/index.ts`
(`ChargingCurvePoint`, `EvProfile`, `EvProfilesFile`, `ICoherentContext`).
Grep-verified zero external consumers. `CoherentSession` kept (used by
4 test files). Barrel is now honest about its "only externally-consumed
symbols" contract.
- **H3** — Sync README `city-ev-40kWh` schema example to
`src/assets/ev-profiles-template.json` exactly: `maxPowerW` 7400→11000,
`weight` 1.0→3, `initialSocPercentMin` 10→15, `initialSocPercentMax`
80→55, 3-point curve → 4-point taper. First-time readers now see the
same values in both docs.
- **H4** — Validate CSV entries in `resolveEnabledMeasurands`
(`OCPPServiceUtils.ts`). `Object.values(MeterValueMeasurand)`-membership
guard drops unknown entries and logs a per-station-debounced warning.
Prevents silent typo tolerance (e.g. `Voltege` in config CSV) while
accepting every OCPP-defined measurand (unlike the narrower
`isMeasurandSupported` allowlist).
## MED (3)
- **M1** — Thread `TxUpdatedMeasurands` into `buildMeterValue` at both
OCPP 2.0 sites that previously bypassed it: `OCPP20ServiceUtils.ts`
`startUpdatedMeterValues` (periodic path) and
`OCPP20IncomingRequestService.ts` `TriggerMessage(MeterValues)` handler.
Closes the J02.FR.11 spec gap where CSMS-configured measurand filters
were ignored on the periodic Updated path.
- **M2** — Debug-only sortedness assertion in `interpolateChargingCurve`
(`EvProfiles.ts`). Production path (`loadEvProfilesFile`) sorts in
place; the assertion catches misuse from the `__inject*` test seam
(unsorted curves silently returned the tail power-fraction — a hidden
test footgun). `process.env.NODE_ENV !== 'production'` gate keeps
runtime cost at zero in production.
- **M3** — Session-leak safety net at 2 OCPP 2.0 request-time create sites:
`OCPP20ServiceUtils.ts` `startTransactionOnConnector` wraps
`sendTransactionEvent` in `try/catch`; `OCPP20IncomingRequestService.ts`
`RequestStartTransaction` handler augments the existing `.catch` chain.
Both call `destroyCoherentSession(txId)` before re-throwing/logging,
symmetric with the OCPP 1.6 `resetConnectorOnStartTransactionError`
pattern. Prevents session Map growth on WebSocket-send rejection.
## Content + Low/Nit
- **P-01** — Extend the defensive guard block in `computeCoherentSample`
with `!Number.isFinite(options.nowMs)`. Matches the pattern for the
other 4 guarded inputs. Not reachable in production (`Date.now()`
always finite) but closes the test-injection hole.
- **P-02** — Document `rampUpDurationMs = Number.EPSILON` equivalence
with 0 (both collapse to immediate full-power). Comment only.
- **D-05** — Add `logger.warn` to the OCPP 2.0
`handleResponseTransactionEvent` Ended-with-unknown-connector branch,
mirroring the OCPP 1.6 diagnostic parity at
`OCPP16ResponseService.ts:534-536`.
- **N-03** — Expand `ComputeSampleOptions.voltageNoise` inline comment
into a full JSDoc with `@remarks` and `@defaultValue`.
- **N-04** — Document the WHY for `createCoherentSession` idempotency
(OCPP 2.0.x has two call sites per transaction from S2 fix).
- **N-05** — Document the `<quantity><Unit>` naming convention on
`CoherentSample` (all fields follow `currentA`/`powerW`/`voltageV`).
## Deferred with rationale (documented decisions)
- **A6** — `buildTransactionBeginMeterValue` reads
`connectorStatus.transactionId` internally rather than accepting an
explicit param. Single call site, safe mutation ordering already
documented; adding a param would add noise for zero safety gain.
- **D-03** — `buildTransactionBeginMeterValue` dual-responsibility
(coherent short-circuit + legacy path) tracked in follow-up issue
#1936 as new M-06 item.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2899 pass / 0 fail / 6 skipped
Refs #40
* fix(meter-values): address PR #1935 round-4 review findings (issue #40)
Consolidated fixes for all findings from the fourth multi-agent review round
(5 parallel reviewers: Oracle elegance/TS · Oracle math/physics · general
OCPP-spec-via-qmd · explore harmonization · general content/terminology).
Design phase cross-validated 5 architecturally-loaded decisions via Oracle.
## HIGH (6)
- **H1 [R4C]** — Thread `OCPP20ReadingContextEnumType.TRIGGER` into the
`TriggerMessage(MeterValues)` handler at `OCPP20IncomingRequestService.ts:611`.
Emitted `SampledValue.context` now correctly labels values taken in
response to `TriggerMessage` per OCPP 2.0.1 §3.66 ReadingContextEnumType;
previously defaulted to `Sample.Periodic`.
- **H2 [R4C]** — Presence-aware `resolveEnabledMeasurands` semantics in
`OCPPServiceUtils.ts`. Discriminates key-absent (defaults to
`{Energy.Active.Import.Register}` for ergonomic parity) from key-present
(honors the CSV verbatim, including empty ⇒ empty allow-list per
OCPP 2.0.1 J02.FR.11). Removes the unconditional force-add at line 1115.
- **H3 [R4C]** — Per-phase measurand emission in `buildCoherentMeterValue`.
Restructured to iterate all templates per measurand (was: first-matching
only) with phase-aware value resolution:
`Voltage L-N ⇒ V`; `L-L ⇒ √phases × V`.
`Power L-N ⇒ P/phases`; L-L unsupported (log-and-skip).
`Current line ⇒ sample.currentA` (balanced 3-φ Y).
`SoC / Energy.Active.Import.Register` phase-qualified templates rejected.
Emit order: `SoC → V → P → I → Energy` across measurands; within a
measurand: `no-phase → L1/L1-N → L2/L2-N → L3/L3-N → L1-L2 → L2-L3 →
L3-L1 → N → other`. Closes legacy-parity regression for 3-phase stations
with phase-qualified templates.
- **H4 [R4D]** — `throw new BaseError(...)` in `EvProfiles.ts`
`interpolateChargingCurve` (was: bare `Error`), aligning with AGENTS.md
TypeScript conventions on typed errors.
- **H5 [R4D]** — `assert.ok(cs != null, 'Expected connector 1 to exist')`
in `OCPP20ServiceUtils-PostTransactionDelay.test.ts` (was: `throw new
Error`), matching the pattern used elsewhere in the test suite.
- **H6 [R4E]** — README §EV profile file format now documents the
connector-level-only `MeterValues` template resolution scope under
coherent mode (EVSE-level inheritance not applied; tracked as follow-up).
## MED (12)
- **M1 [R4A]** — `computeCoherentSample` now takes the resolved
`session` as a parameter (was: fetched twice via `context.getCoherentSession`).
Removes 2 unreachable defensive branches (\~25 LOC) and tightens the
contract into a pure physics function.
- **M2 [R4C]** — OCPP 1.6 `buildTransactionBeginMeterValue` threads
vendor param `StartTxnSampledData` when configured, falling back to
`MeterValuesSampledData` when absent — per the OCPP 1.6 Signed Meter
Values whitepaper.
- **M3 [R4D]** — Move `MS_PER_HOUR` and `UNIT_DIVIDER_KILO` to
`Constants` class (`src/utils/Constants.ts`). Was duplicated as
file-scope constants in `OCPPServiceUtils.ts` and
`CoherentMeterValuesGenerator.ts`. All references now use
`Constants.MS_PER_HOUR` / `Constants.UNIT_DIVIDER_KILO`.
- **M4 [R4D]** — Move `VOLTAGE_NOISE_PERCENT` to
`Constants.DEFAULT_COHERENT_VOLTAGE_NOISE_PERCENT`. Tunables belong in
the canonical defaults map per AGENTS.md.
- **M5 [R4D]** — Move `DEFAULT_RAMP_UP_DURATION_MS` to
`Constants.DEFAULT_COHERENT_RAMP_UP_DURATION_MS`. Same rationale.
- **M6 [R4D]** — Merge same-specifier `import type` statements in
`types.ts` and `EvProfiles.ts` (was: 2 statements each for the same
module). Aligns with the project's `import/no-duplicates` /
`verbatimModuleSyntax` convention.
- **M8/M11 [R4D]** — `describe('Prng', ...)` and
`describe('StrategyDispatch', ...)` renames to match the
module-name-only convention in `tests/TEST_STYLE_GUIDE.md`.
- **M9 [R4E]** — README precision: "emitted measurand list" no longer
claims `ΔE` is emitted (it is an internal per-sample intermediate);
INV-1 spelled out per current-type (`P = V·I·phases` for AC, `P = V·I`
for DC).
- **M10 [R4E]** — Rewrite forward-looking comment at
`OCPP16ServiceUtils.ts:152-158` to describe the current-branch semantics
(`StartTxnSampledData` override with fallback to
`MeterValuesSampledData`) instead of the deferred S1 signing wiring.
## LOW/NIT batch
- **R4A-LOW-01** — `advanceEnergyRegister` rewritten with
`Math.max(0, ... ?? 0)` — one-expression clamp-and-init (was: two-step
nullish-then-negative guard, ~14 LOC → 6 LOC).
- **R4A-LOW-02** — 3 near-identical `CoherentSample` zero-literal returns
in `computeCoherentSample` collapsed to a single `buildZeroSample`
helper. Two of the three defensive branches also removed by M1.
- **R4A-NIT-01** — `findTemplate` replaced by `groupTemplatesByMeasurand`
(needed for H3 per-phase iteration anyway); legacy `for..of` scan is now
gone.
- **R4B-LOW-01/02** — INV-1/INV-3 docstring precision: emit-time rounding
bound stated as "`ROUNDING_SCALE` half-width (\~0.005 W scalar)"; INV-3
divergence bound quantified (\~0.12 Wh over 24 h at 1 Hz).
- **R4B-LOW-05** — `EvProfileSchema` JSDoc documents monotone-non-increasing
`powerFraction` as a caller responsibility (not schema-enforced;
real curves are flat through CC before tapering).
- **R4B-NIT-06** — AC `numberOfPhases <= 0` now triggers the zero-sample
defensive branch (was: silently produced `P = 0` via
`divisor = V × 0 = 0`).
- **R4B-NIT-07** — `interpolateChargingCurve` JSDoc documents the
closed-closed interval semantic (left segment wins at interior nodes).
- **R4D-LOW-06/07/08** — `StationHelpers.ts` mock: `coherentSessions`,
`createCoherentSession`, `getCoherentSession` return types tightened
from `unknown` to `CoherentSession | undefined` (and
`Map<number | string, CoherentSession>`).
- **R4D-NIT-03/04/05/06** — `meter-values/index.ts` barrel comment now
explicitly enumerates the intentionally-omitted internal exports
(`computeCoherentSample`, `advanceEnergyRegister`, `createStreamPrng`,
`disposeCoherentSessionRuntime`, option-bag types, EvProfiles helpers,
Prng primitives, Zod schemas).
- **R4E-LOW-05** — `Prng.ts` header no longer claims a specific LOC
bound ("kept intentionally small").
- **R4E-LOW-06** — Expanded JSDoc on `ComputeSampleOptions` and
`CreateSessionOptions` interfaces (per-field semantics, units, defaults).
## Deferred to follow-up #1936 (documented rationale)
- **M7 [R4D]** — `StationHelpers.ts` (954 LOC) modular split. Structural
refactor with 30+ test file consumers; TODO comment added at the top of
the file linking to #1936. Detailed split sketch documented in the
design phase.
- **H6 code-side** — Extend `ICoherentContext` with `getEvseStatus` to
restore EVSE-level template inheritance. Round-4 lands docs-only.
- **R4B-LOW-03/04** — Physics model design notes (`cos φ = 1` assumption,
linear-vs-S-curve ramp shape). Not blockers.
## Non-findings (verified compliant)
- OCPP 2.0.1 `TxUpdatedInterval` correctly wired for periodic scheduling.
- `Transaction.Begin` / `Transaction.End` enum literals correct.
- Coherent path does not spoof `signedMeterValue`; signing gate intact.
- Coherent path does not bleed into `AlignedDataCtrlr` /
`ClockAlignedDataInterval` handling.
- Existing hyphenated test file names (`OCPP16-CoherentMeterValues.test.ts`
etc.) match the `ChargingStation-Configuration.test.ts` sub-domain
precedent — not a divergence.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2920 pass / 0 fail / 6 skipped
Refs #40
* fix(meter-values): OCPP-spec-strict emit + per-phase register + polish (issue #40)
## OCPP 2.0.1 spec-strict emit shape
- `TransactionEvent(Updated)` no longer serializes an empty `meterValue`
wrapper when `TxUpdatedMeasurands` resolves to an empty allow-list.
Periodic `startUpdatedMeterValues` short-circuits; TriggerMessage
(MeterValues) active-tx branch sends the event without the `meterValue`
field. Matches OCPP 2.0.1 J02.FR.11 ("no meter values are sent") and
fixes the JSON-schema `minItems: 1` violation on empty sampledValue.
## OCPP 1.6 whitepaper composition (StartTxnSampledData × beginEndMeterValues)
- `OCPP16ResponseService` gates the extra `MeterValues.req` sends at
both the start (`beginEndMeterValues`) and end (`outOfOrderEndMeterValues`)
branches on `isNotEmptyArray(sampledValue)`. Composes cleanly with the
Signed Meter Values whitepaper §3.3.4 rule (`StartTxnSampledData`
present + non-empty) and the legacy `MeterValuesSampledData` fallback:
both empty ⇒ no send, avoiding a schema-suspect empty sampledValue
wrapper.
## Coherent path — per-phase physics polish
- **Per-phase Energy.Active.Import.Register**: L-N templates now emit
`register / phases` (balanced 3-φ Y contribution per phase); L-L and
`N` phases skipped with a warn. OCPP 2.0.1
`SampledDataCtrlr.RegisterValuesWithoutPhases` config-driven suppression
not consulted (documented follow-up).
- **Neutral phase**: new `Neutral` phase-family classifier distinguishes
bare `N` from `LineToNeutral` (`L1`/`L1-N`/etc.). `N`-qualified
Voltage and Current templates emit 0 (balanced 3-φ Y: I_N = 0 by
phasor sum, V_N = 0 by reference-node definition).
- **L-L voltage on 1-phase**: log-and-skip. Previously the `√1 × V`
degeneracy silently emitted nominal V under an L-L label.
- **L-N power on phases≤0**: log-and-skip (previously fell through to
aggregate power under a per-phase label — unreachable in practice due
to the outer defensive guard but semantically inconsistent).
- **Register clamp sync**: `preRegisterWh` in `computeCoherentSample`
applies `Math.max(0, ... ?? 0)` matching `advanceEnergyRegister`;
reported `sample.energyRegisterWh` and post-advance persisted state
now agree even under corrupted negative register state.
## Elegance + TS state-of-the-art
- Extract `resolveUnitDivider(measurand, unit)` +
`KILO_UNIT_BY_MEASURAND` at module scope, removing the inline
`(A && B) || (C && D)` boolean at the emit site.
- `PHASE_RANK` converted from `ReadonlyMap` to object literal with
`as const satisfies Record<MeterValuePhase, number>` for
compile-time exhaustiveness; `phaseRank`'s runtime fallback dropped.
- `resolvePhasedValue` returns exact fractions (no internal rounding);
rounding happens once at the emit site after unit-divider scaling.
Removes double-rounding asymmetry between aggregate and per-phase paths.
- `groupTemplatesByMeasurand` uses `Map.groupBy` (Node 22+) in place of
the hand-rolled loop; per-bucket phase sort preserved.
- Merged split `import type { ConnectorStatus }` with sibling type-import
from the same specifier.
## Documentation
- README §Phase-qualified measurands: "nominal V" → "sampled V"
everywhere (the coherent path emits `sample.voltageV`, i.e.
post-noise rounded voltage — not the station's nominal); documents
`N` phase behavior and per-phase Energy register emission.
- `resolvePhasedValue` JSDoc updated to match implementation.
- `ComputeSampleOptions` and `CreateSessionOptions` JSDoc converted
from bullet-list style to inline per-field JSDoc (matching
`CoherentSession` and `ICoherentContext` in `types.ts`).
- `types.ts` file header rewritten to state the current interface
contract instead of deferred tooling-contingency rationale.
- `Constants` docstrings for coherent tunables /
`MS_PER_HOUR` / `UNIT_DIVIDER_KILO` shortened to one-liners matching
the concision of sibling entries.
- `CoherentMeterValuesGenerator.ts` header carries a follow-up TODO
for the 250-LOC ceiling exceedance (split scope documented).
- Explanatory comment on the module-scope `warnedInvalidMeasurands`
WeakMap in `OCPPServiceUtils.ts` distinguishing its GC-keyed intent
from a true singleton.
- Internal-only comment on `VersionedSampledValueDispatch` interface.
## Tests
- New per-phase emission integration test: 3-phase AC session with
L-N/L-L voltage, aggregate + per-phase Power, L1/N Current, and L-N
Energy templates; asserts V_L1_N=230, V_L1_L2≈√3·230, Σ per-phase P
≈ aggregate P, I_N=0, L-L voltage skipped on 1-phase, L-N energy
register emitted as `register / phases`.
- `describe('OCPP 1.6 coherent MeterValues integration')` renamed to
`describe('OCPP16CoherentMeterValues')` (module-name convention).
- OCPP 1.6 integration test replaces its local `MS_PER_HOUR = 3_600_000`
literal with a `Constants.MS_PER_HOUR` alias (canonical source).
- Removed leaked internal-review annotations from 9 describe/it labels
(`(regression: ...)` suffixes) — these violated documentation
timeliness by embedding non-behavioral session metadata into the
behavioral test tree.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2923 pass / 0 fail / 6 skipped
Refs #40
* fix(meter-values): periodic-event omission + Energy L-N alignment + polish (issue #40)
## OCPP 2.0.1 spec-strict emit shape
- Periodic `TransactionEvent(Updated)` no longer drops the whole message
when `TxUpdatedMeasurands` resolves empty. Sends the event with the
`meterValue` field omitted, matching the R5 fix already in place on the
`TriggerMessage(MeterValues)` active-tx branch. Preserves the periodic
heartbeat cadence at the OCPP level while honoring J02.FR.11
("no meter values are sent") — the message is still delivered, only
the sampled-value payload is elided.
## Coherent path — phase-degeneracy symmetry
- `Energy.Active.Import.Register` L-N templates on `phases <= 0` now
log-and-skip (return `undefined`), matching `Power.Active.Import`'s
behavior for the same misconfiguration. Previously the register branch
fell through to emit the aggregate under a per-phase template label.
## Elegance + TS state-of-the-art
- `resolvePhasedValue` signature narrowed from
`(measurand, template, sample, phases, connectorStatus)` to
`(measurand, phase, sample, phases, connectorStatus)`. The function
only reads `template.phase`; taking the whole template widened the
coupling. Caller passes `template.phase` at the loop head.
- `resolveUnitDivider` gains a JSDoc block (sole helper in the file that
previously lacked one) and reorders the guard to
`unit != null && KILO_UNIT_BY_MEASURAND.get(measurand) === unit` for
intent-first reading ("only kilo-divide when a unit is present").
- `LEGACY_EMIT_ORDER` renamed to `MEASURAND_EMIT_ORDER`. The constant
is the canonical emission order of the coherent path, not a
compatibility shim; the JSDoc note preserves the "mirrors the legacy
path" provenance.
- `buildZeroSample` now owns all rounding for the zero-sample path.
Callers pass raw `socPercent` / `voltageV`; the helper applies
`roundTo` internally. Rounding-responsibility is unified in one place.
## Documentation
- INV-1 docstring documents both the aggregate residual (≤ 0.005 W) and
the per-phase L-N residual (≤ 0.01 W = 2 × `ROUNDING_SCALE` half-width),
quantifying the two-step rounding bound (aggregate emit + per-phase
division).
- `resolvePhasedValue` JSDoc documents the per-phase Energy register
conservation bound: Σ across all L-N templates equals the aggregate
register within emit-unit rounding granularity (Wh: ≤ phases · 0.005 Wh;
kWh: ≤ phases · 5 Wh).
- `VersionedSampledValueDispatch.signingState` JSDoc: unresolvable
`{@link buildVersionedSampledValue}` replaced with plain prose
(the reference is a local closure, not an exported symbol).
- `resolveEnabledMeasurands` `@param measurandsKey` prose clarified:
`undefined` (or omitted) defaults to `StandardParametersKey.`
`MeterValuesSampledData` for OCPP 1.6; returns `undefined` (no filter)
for all other versions.
- `meter-values/index.ts` barrel comment simplified. Dropped the
enumerated intentionally-omitted list (drifts with internals); kept
the intent sentence only.
- `ChargingStation.createCoherentSession` JSDoc: dropped the
request-builder/response-handler call-site narrative; kept the API
contract ("idempotent; returns `undefined` when coherent mode is
disabled or no valid EV profile file is loaded").
## README
- `§Template resolution scope`: dropped the internal
`getSampledValueTemplate` helper name and the backlog-tracking sentence.
Documents current behavior only (connector-level templates, no
EVSE-level inheritance under coherent mode).
- `§Phase-qualified measurands`: dropped the "tracked as a follow-up"
tail on the `RegisterValuesWithoutPhases` note.
- Charging station template configuration table: `three phased` →
`three-phase`, `line to line voltage` → `line-to-line voltage`
(hyphenation consistent with the rest of the docs).
## Tests
- Added mandatory `afterEach(() => standardCleanup())` block to
`CoherentMeterValuesGenerator.test.ts`, `EvProfiles.test.ts`, and
`Prng.test.ts` per `tests/TEST_STYLE_GUIDE.md` §Mandatory Cleanup.
- `describe('OCPP20ServiceUtils — PostTransactionDelay')` renamed to
`describe('OCPP20ServiceUtilsPostTransactionDelay')` — module-name
concatenated form matching the existing coherent-test naming.
- `describe('B2 - OCPP 2.0.1 TransactionEvent Started → coherent session
wiring')` renamed to `describe('OCPP20ResponseServiceCoherentSession')`
— module-name-only form; the descriptive/spec-prefix suffix was
redundant with the inner `it` labels.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2920 pass / 0 fail / 6 skipped
Refs #40
* [autofix.ci] apply automated fixes
* refactor(meter-values): phase-family Record + shared test interval constant (issue #40)
## phaseFamily as an exhaustive Record
- Convert `phaseFamily`'s switch statement to a `PHASE_FAMILY` object
literal with `as const satisfies Record<MeterValuePhase, ...>`,
matching the `PHASE_RANK` pattern already established for phase
ranking. Adding a new `MeterValuePhase` enum value now fails compile
at the table declaration until the value is classified — the same
compile-time gate PHASE_RANK enforces.
- The `phaseFamily` function becomes a one-liner:
`phase == null ? 'Aggregate' : PHASE_FAMILY[phase]`.
`Aggregate` remains the sentinel for the undefined-phase case.
- Removes the defensive `default: return 'Aggregate'` branch that
silently absorbed unclassified enum values.
## phaseRank inlined
- Drop the `phaseRank` helper (used at exactly one call site) and
inline the null-check + `PHASE_RANK` lookup directly into the
`groupTemplatesByMeasurand` bucket-sort comparator. The
`PHASE_RANK` table is now the visible source of truth at the sort
site, matching the `PHASE_FAMILY` pattern above.
## Shared TEST_METER_VALUES_INTERVAL_MS constant
- Add `TEST_METER_VALUES_INTERVAL_MS = 30_000` to
`tests/charging-station/ChargingStationTestConstants.ts` as the
canonical test interval.
- Replace 27 inline `30_000` / `30000` literals across
`CoherentMeterValuesGenerator.test.ts` (20 sites),
`OCPP16-CoherentMeterValues.test.ts` (4 sites, including the local
`const INTERVAL_MS = 30_000` that was itself a duplicate), and
`StrategyDispatch.test.ts` (3 sites). Preserves value; consolidates
the semantic "meter-values sample interval used across coherent
tests" into one importable constant.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2923 pass / 0 fail / 6 skipped
Refs #40
* [autofix.ci] apply automated fixes
* chore(meter-values): strip internal-review markers + JSDoc/docstring polish (issue #40)
## Internal-review-marker cleanup
Removed 19 in-code review-round prefixes (`M1:`, `M2:`, `M3:`, `M4:`,
`B1`, `B2`, `Regression M4:`, `Regression B2:`) from test assertion
messages, JSDoc `@description`, and inline comments across 5 test files:
- `CoherentMeterValuesGenerator.test.ts` — 7 sites (voltage-noise,
capacity-clamp, INV-1 residual assertions).
- `OCPP16-CoherentMeterValues.test.ts` — 6 sites (stop-energy
reconstruction and coherent-session-leak assertions + comment).
- `OCPP20ServiceUtils-PostTransactionDelay.test.ts` — 1 site
(coherent-session-leak assertion).
- `OCPP20ResponseService-CoherentSession.test.ts` — 4 sites (`@description`
+ three eventType/idToken assertions).
- `OCPP16ResponseService-ForceTxOnInvalid.test.ts` — 1 comment block
("exercises the regression:" process language → behavioral "exercises
the pre-Start guard").
Assertion messages now describe the invariant being checked in plain
English without carrying review-round bookkeeping. This is a follow-up to
the earlier cleanup that stripped `(regression: XX)` suffixes from
`describe`/`it` labels but missed codes inside assertion messages and
`@description` blocks.
## JSDoc / doc hygiene
- `PHASE_FAMILY` (`CoherentMeterValuesGenerator.ts`) — deleted the stale
first JSDoc block that documented the pre-refactor `phaseFamily`
function; kept the block that documents the current Record with
compile-time exhaustiveness gate.
- `VersionedSampledValueDispatch` (`OCPPServiceUtils.ts`) — converted
the `//` block comment above the interface to a proper `/** */` JSDoc
block matching the sibling-interface convention. Body documents the
internal-only dispatch-bag role with `@link` cross-references.
- `warnedInvalidMeasurands` and `KNOWN_MEASURANDS` (`OCPPServiceUtils.ts`)
— moved above the `resolveEnabledMeasurands` JSDoc block so the JSDoc
is now adjacent to the function it documents (was previously separated
by the two `const` declarations, breaking the visual JSDoc→function
association).
- `template.unit as MeterValueUnit | undefined` cast (`CoherentMeter`
`ValuesGenerator.ts`) — added an intent comment documenting the OCPP
2.0 open-string-branch narrowing at the Map-lookup boundary and the
fallback semantics (non-enum strings return `undefined` from the Map
and fall through to `divider = 1`).
- `MEASURAND_EMIT_ORDER` (`CoherentMeterValuesGenerator.ts`) — dropped
the explicit `readonly MeterValueMeasurand[]` annotation; kept `as const`
for a narrow tuple type matching the sibling `PHASE_FAMILY`/`PHASE_RANK`
pattern (immutability via const-assertion, coherent style across the
three module-scope constants).
- `ChargingStation.__injectCoherentSession` JSDoc — dropped the
"not currently enforced by a lint rule" sentence (build-tool trivia,
not API behavior).
## Test constants
- `TEST_METER_VALUES_INTERVAL_MS` rationale documented on the
`Timer Intervals` block header (`_MS` intervals are intentionally
half of `Constants.DEFAULT_*_INTERVAL_MS` for bounded test wall-clock).
- `ChargingStationTestConstants.ts` file header rewritten from the
narrative-prose + `@see` form to standard `@file` / `@description`
JSDoc matching the rest of the test suite.
## Verification
- `pnpm typecheck` — 0 errors
- `pnpm lint` — 0 errors, 0 warnings
- `pnpm test` — 2923 pass / 0 fail / 6 skipped
Refs #40
* docs(meter-values): tighten OCPP schema-cardinality citation + test tolerance message (issue #40)
- OCPP20ServiceUtils.ts / OCPP20IncomingRequestService.ts: replace loose
J02.FR.11 shorthand on the meterValue-field-omission branches with the
actual grounding — MeterValueType.sampledValue cardinality 1..* combined
with TransactionEventRequest.meterValue cardinality 0..* — so a reader
sees why the empty case yields {} rather than { meterValue: [] }.
- CoherentMeterValuesGenerator.test.ts: capacity-clamp failure messages
now report 2 × ROUNDING_SCALE (0.01 W) to match the assertion tolerance
(the two rounding steps: aggregate P = V·I·phases plus post-clamp
re-round each contribute one half-width).
* refactor(meter-values): use session snapshot for voltage, currentType, numberOfPhases (issue #40)
computeCoherentSample now reads voltageOutNominal, currentType, and
numberOfPhases from the session object (immutable snapshot captured at
createCoherentSession) instead of the live context. The three fields
were already declared readonly on CoherentSession but only two were
consulted at runtime, leaving voltageOutNominal dead. Using the snapshot
makes the physics chain deterministic against hypothetical mid-session
station-config drift and reduces per-sample context calls from three to
zero (getConnectorMaximumAvailablePower stays live — the EVSE cap is a
genuinely dynamic quantity that can change during a transaction).
* fix(meter-values): namespace transactionId in createStreamPrng to prevent XOR self-inverse (issue #40)
createStreamPrng chained two XOR-based deriveSeed calls, so
String(transactionId) === label collapsed the derived stream seed back
to the root seed (deriveSeed(deriveSeed(r, X), X) === r). Trigger
required transactionId to match a literal stream label
('VOLTAGE_NOISE', 'POWER_NOISE', 'PROFILE_PICK', 'INITIAL_SOC') —
extremely unlikely with OCPP-numeric transactionIds but reachable via
test seams. Namespace the transactionId leg with a 'tx:' prefix that
labels never carry so the two hash inputs cannot algebraically cancel.
Prng.ts deriveSeed docstring updated to reference the namespacing in
createStreamPrng and drop the 'Known limitation (deferred)' language.
* chore(charging-station): guard __injectCoherentSession against production use (issue #40)
The public __injectCoherentSession method is a test seam whose only
prior protection was the '__' naming convention. Add a runtime guard
that throws a typed BaseError when NODE_ENV === 'production', mirroring
the pattern used by interpolateChargingCurve in EvProfiles.ts for the
unsorted-curve defensive check. Tests run with NODE_ENV unset or 'test'
so the guard is transparent to them; accidental production use now
fails loudly instead of silently corrupting the session store.
* fix(meter-values): tighten defensive guard against non-finite intervalMs (issue #40)
The computeCoherentSample defensive guard applied Number.isFinite to
batteryCapacityWh, nominalV, and nowMs but only tested intervalMs <= 0.
Since NaN <= 0 and +Infinity <= 0 both evaluate to false in JS, either
pathological value escaped the guard, propagated through
maxPowerFromCapacityW = remainingWh * MS_PER_HOUR / intervalMs, and
permanently poisoned session.socPercent to NaN (NaN + x === NaN for
every subsequent sample). Reachability was low in practice — legitimate
callers pass integer intervals and convertToInt throws on NaN — but a
non-compliant CSMS setting MeterValueSampleInterval to a pathological
value via ChangeConfiguration could reach the coherent path.
Add !Number.isFinite(options.intervalMs) to the OR chain, mirroring the
sibling checks. Docstring bullet rewritten to reflect the tightened
coverage. Two new test cases lock the behavior: intervalMs=NaN and
intervalMs=+Infinity both short-circuit to a zero sample with session
state intact, matching the existing intervalMs=0 semantics. The
describe block is renamed from 'intervalMs=0 defensive guard' to
'intervalMs defensive guard' to reflect the broader coverage.
* chore(helpers): drop caller-coordination note on resetConnectorStatus (issue #40)
The 'NOTE: transactionId is deleted here. Callers that need to identify
the just-stopped transaction MUST snapshot ... BEFORE invoking this
function.' comment described a caller-side coordination concern rather
than the WHY of the delete. Every caller that needs the transactionId
already snapshots it before the reset; the note added no local WHY and
duplicated a responsibility that belongs in the caller, not in
resetConnectorStatus.
* docs(meter-values): drop 'legacy' framing for the random/fixed simulation mode (issue #40)
The random/fixed measurand generation is not deprecated — it is one of
two peer simulation modes exposed by the simulator, selected via the
coherentMeterValues station flag. The word 'legacy' throughout the
newly-introduced comments, JSDoc, README, and test descriptions
inaccurately implied a deprecation path.
Neutralize 13 sites across 6 files: 'legacy' either dropped where it
was purely decorative (e.g. 'mirroring the legacy X path' → 'mirroring
the X path') or replaced with 'random/fixed' / 'default' where the
descriptor was substantive. No code changes, no test-logic changes,
purely prose.
* [autofix.ci] apply automated fixes
* docs(meter-values): neutralize residual 'Legacy path' inline comment (issue #40)
F12-A retitled the enclosing it() from 'via the legacy path' to 'via
the random/fixed path' but the inline WHY comment two lines below still
said 'Legacy path' — same author, same commit, same test block.
Missed by the case-sensitive verification grep used at F12-A landing;
this closes the neutralization loop.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 11efaab commit b907992
30 files changed
Lines changed: 4015 additions & 157 deletions
File tree
- scripts
- src
- assets
- charging-station
- meter-values
- ocpp
- 1.6
- 2.0
- types
- utils
- tests/charging-station
- helpers
- meter-values
- ocpp
- 1.6
- 2.0
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
66 | 70 | | |
67 | 71 | | |
68 | 72 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| 135 | + | |
135 | 136 | | |
136 | 137 | | |
137 | 138 | | |
| |||
147 | 148 | | |
148 | 149 | | |
149 | 150 | | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
150 | 159 | | |
151 | 160 | | |
152 | 161 | | |
| |||
206 | 215 | | |
207 | 216 | | |
208 | 217 | | |
| 218 | + | |
| 219 | + | |
209 | 220 | | |
210 | 221 | | |
211 | 222 | | |
| |||
241 | 252 | | |
242 | 253 | | |
243 | 254 | | |
| 255 | + | |
244 | 256 | | |
245 | 257 | | |
246 | 258 | | |
| |||
302 | 314 | | |
303 | 315 | | |
304 | 316 | | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
305 | 335 | | |
306 | 336 | | |
307 | 337 | | |
| |||
345 | 375 | | |
346 | 376 | | |
347 | 377 | | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
348 | 414 | | |
349 | 415 | | |
350 | 416 | | |
| |||
399 | 465 | | |
400 | 466 | | |
401 | 467 | | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
402 | 483 | | |
403 | 484 | | |
404 | 485 | | |
| |||
458 | 539 | | |
459 | 540 | | |
460 | 541 | | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
461 | 551 | | |
462 | 552 | | |
463 | 553 | | |
| |||
1221 | 1311 | | |
1222 | 1312 | | |
1223 | 1313 | | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
1224 | 1321 | | |
1225 | 1322 | | |
1226 | 1323 | | |
| |||
1814 | 1911 | | |
1815 | 1912 | | |
1816 | 1913 | | |
| 1914 | + | |
1817 | 1915 | | |
1818 | 1916 | | |
1819 | 1917 | | |
| |||
1844 | 1942 | | |
1845 | 1943 | | |
1846 | 1944 | | |
| 1945 | + | |
| 1946 | + | |
| 1947 | + | |
| 1948 | + | |
| 1949 | + | |
| 1950 | + | |
| 1951 | + | |
| 1952 | + | |
| 1953 | + | |
| 1954 | + | |
| 1955 | + | |
| 1956 | + | |
| 1957 | + | |
| 1958 | + | |
| 1959 | + | |
| 1960 | + | |
| 1961 | + | |
| 1962 | + | |
| 1963 | + | |
| 1964 | + | |
| 1965 | + | |
| 1966 | + | |
| 1967 | + | |
| 1968 | + | |
| 1969 | + | |
| 1970 | + | |
| 1971 | + | |
1847 | 1972 | | |
1848 | 1973 | | |
1849 | 1974 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
812 | 812 | | |
813 | 813 | | |
814 | 814 | | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
815 | 821 | | |
816 | 822 | | |
817 | 823 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
181 | 181 | | |
182 | 182 | | |
183 | 183 | | |
| 184 | + | |
184 | 185 | | |
185 | 186 | | |
186 | 187 | | |
187 | 188 | | |
188 | 189 | | |
189 | 190 | | |
| 191 | + | |
190 | 192 | | |
191 | 193 | | |
192 | 194 | | |
| |||
215 | 217 | | |
216 | 218 | | |
217 | 219 | | |
| 220 | + | |
218 | 221 | | |
219 | 222 | | |
220 | 223 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
| |||
0 commit comments