Declare a unit contract for measurement (static unitPolicy + CONTRACT.md) #1

Open
opened 2026-05-19 15:50:13 +00:00 by vps1_gitea_admin · 0 comments

Gap

measurement does not declare a static unitPolicy on its specificClass, and CONTRACT.md does not document unit semantics for the value flowing through the node. Every other domain node in EVOLV (pumpingStation, machineGroupControl, rotatingMachine, …) declares one via UnitPolicy.declare({ canonical, output, requireUnitForTypes }).

Where

  • src/specificClass.js:12 — class declares only static name = 'measurement';. No static unitPolicy = … block.
  • CONTRACT.md — documents msg.topic command surface but has no canonical/output unit table.

Why this matters

Without a declared contract:

  • Downstream consumers (parents like pumpingStation, rotatingMachine) infer the unit from assetType + variant context instead of validating against a contract. That is exactly the class of mismatch that caused the assetType: "flow" vs "flow-electromagnetic" integration bug previously logged in project memory.
  • Parents end up doing unit policing on incoming measurement values themselves.
  • The "measurement is the source of truth for a sensor reading" abstraction has no enforceable unit guarantee.

What other nodes do (reference)

// machineGroupControl/src/specificClass.js
static unitPolicy = UnitPolicy.declare({
  canonical: { flow: 'm3/s', pressure: 'Pa', power: 'W', temperature: 'K' },
  output:    { flow: 'm3/h', pressure: 'mbar', power: 'kW', temperature: 'C' },
  requireUnitForTypes: ['pressure', 'flow', 'power', 'temperature'],
});

Definition of done

  • static unitPolicy declared on Measurement in src/specificClass.js. Covers at minimum the assetTypes measurement actually supports today (flow, pressure, level, volume, power, temperature, …).
  • requireUnitForTypes choice justified — measurement is the source node so strictness usually lives at the parent, but the policy should still be explicit.
  • CONTRACT.md extended with a "Units" section: canonical vs. output unit per type, and the contract a parent can rely on when consuming a measurement value.
  • Tests in test/basic/ exercising the unit policy (canonical conversion, reject-on-missing-unit if requireUnitForTypes includes the type).
  • Cross-check pumpingStation / rotatingMachine / monster / dashboardAPI consumers — does any of them currently do unit guesswork that becomes redundant once measurement declares its policy? Remove the guesswork in the same PR.

Context

Surfaced during the 2026-05-19 fix for pumpingStation level-based control sending % to MGC's handleInput (which expects canonical m³/s). The MGC fix added an explicit setDemand(value, unit) entry point as the single source of truth for unit resolution at that boundary; the equivalent contract on the measurement source side is still missing.

## Gap `measurement` does not declare a `static unitPolicy` on its specificClass, and `CONTRACT.md` does not document unit semantics for the value flowing through the node. Every other domain node in EVOLV (`pumpingStation`, `machineGroupControl`, `rotatingMachine`, …) declares one via `UnitPolicy.declare({ canonical, output, requireUnitForTypes })`. ## Where - `src/specificClass.js:12` — class declares only `static name = 'measurement';`. No `static unitPolicy = …` block. - `CONTRACT.md` — documents `msg.topic` command surface but has no canonical/output unit table. ## Why this matters Without a declared contract: - Downstream consumers (parents like `pumpingStation`, `rotatingMachine`) infer the unit from `assetType` + variant context instead of validating against a contract. That is exactly the class of mismatch that caused the `assetType: "flow"` vs `"flow-electromagnetic"` integration bug previously logged in project memory. - Parents end up doing unit policing on incoming measurement values themselves. - The "measurement is the source of truth for a sensor reading" abstraction has no enforceable unit guarantee. ## What other nodes do (reference) ```js // machineGroupControl/src/specificClass.js static unitPolicy = UnitPolicy.declare({ canonical: { flow: 'm3/s', pressure: 'Pa', power: 'W', temperature: 'K' }, output: { flow: 'm3/h', pressure: 'mbar', power: 'kW', temperature: 'C' }, requireUnitForTypes: ['pressure', 'flow', 'power', 'temperature'], }); ``` ## Definition of done - [ ] `static unitPolicy` declared on `Measurement` in `src/specificClass.js`. Covers at minimum the assetTypes `measurement` actually supports today (flow, pressure, level, volume, power, temperature, …). - [ ] `requireUnitForTypes` choice justified — `measurement` is the *source* node so strictness usually lives at the parent, but the policy should still be explicit. - [ ] `CONTRACT.md` extended with a "Units" section: canonical vs. output unit per type, and the contract a parent can rely on when consuming a `measurement` value. - [ ] Tests in `test/basic/` exercising the unit policy (canonical conversion, reject-on-missing-unit if `requireUnitForTypes` includes the type). - [ ] Cross-check `pumpingStation` / `rotatingMachine` / `monster` / `dashboardAPI` consumers — does any of them currently do unit guesswork that becomes redundant once `measurement` declares its policy? Remove the guesswork in the same PR. ## Context Surfaced during the 2026-05-19 fix for pumpingStation level-based control sending `%` to MGC's `handleInput` (which expects canonical m³/s). The MGC fix added an explicit `setDemand(value, unit)` entry point as the single source of truth for unit resolution at that boundary; the equivalent contract on the `measurement` source side is still missing.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RnD/measurement#1