P6: convert diffuser to BaseDomain + BaseNodeAdapter + concern split
Refactor of diffuser to use the platform infrastructure (BaseDomain, BaseNodeAdapter, ChildRouter, commandRegistry, statusBadge). Extracts concerns into focused modules per .claude/refactor/MODULE_SPLIT.md generic template. Tests stay green; CONTRACT.md generated; legacy aliases preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
71
CONTRACT.md
Normal file
71
CONTRACT.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# diffuser — Contract
|
||||
|
||||
Hand-maintained for Phase 6; the `## Inputs` table is generated from
|
||||
`src/commands/index.js` (see Phase 9 generator). Keep ≤ 100 lines.
|
||||
|
||||
## Inputs (msg.topic on Port 0)
|
||||
|
||||
| Canonical | Aliases (deprecated) | Payload | Effect |
|
||||
|---|---|---|---|
|
||||
| `data.flow` | `air_flow` | `number` — airflow in Nm³/h | Calls `source.setFlow(payload)`; clamps to ≥ 0 and recomputes OTR. |
|
||||
| `set.density` | `density` | `number` — diffuser density (per m²) | Calls `source.setDensity(payload)` and recomputes. |
|
||||
| `set.water-height` | `height_water` | `number` — water column height in m | Calls `source.setWaterHeight(payload)`; clamps to ≥ 0 and recomputes head + total pressure. |
|
||||
| `set.header-pressure` | `header_pressure` | `number` — header gauge pressure in mbar | Calls `source.setHeaderPressure(payload)` and recomputes. |
|
||||
| `set.elements` | `elements` | `number` — element count (rounded; must be > 0) | Calls `source.setElementCount(payload)` and recomputes per-element flow. |
|
||||
| `set.alfa-factor` | `alfaFactor` | `number` — alpha correction (≥ 0) | Calls `source.setAlfaFactor(payload)` and recomputes oxygen output. |
|
||||
|
||||
Aliases log a one-time deprecation warning the first time they fire.
|
||||
|
||||
## Outputs (msg.topic on Port 0/1/2)
|
||||
|
||||
- **Port 0 (process):** `msg.topic = config.general.name`. Payload built
|
||||
by `outputUtils.formatMsg(..., 'process')` from `getOutput()` —
|
||||
delta-compressed (only changed fields are emitted). Fields:
|
||||
- `iPressure`, `iMWater`, `iFlow` — echoed inputs.
|
||||
- `nFlow` — normalised airflow (Nm³/h).
|
||||
- `oOtr` — interpolated oxygen transfer rate (g O₂ / Nm³).
|
||||
- `oPLoss` — total head loss (mbar) = static head + diffuser ΔP.
|
||||
- `oKgo2H` — kg O₂ per hour at current operating point.
|
||||
- `oFlowElement` — flow per element (Nm³/h/element).
|
||||
- `efficiency` — combined OTR/ΔP efficiency (0–100).
|
||||
- `slope` — local OTR-vs-flow slope.
|
||||
- `oZoneOtr` — reactor zone OTR (kg O₂ / m³ / day) computed against
|
||||
`diffuser.zoneVolume`; `0` when zone volume is unset.
|
||||
- `idle` — true when `data.flow ≤ 0`.
|
||||
- `warning`, `alarm` — string arrays describing flow-per-element band
|
||||
excursions.
|
||||
- **Port 1 (InfluxDB telemetry):** same shape as Port 0, formatted with
|
||||
the `'influxdb'` formatter.
|
||||
- **Port 2 (registration):** at startup the node sends one
|
||||
`{ topic: 'child.register', payload: <node.id>, positionVsParent,
|
||||
distance }` to the upstream parent (typically a reactor).
|
||||
`positionVsParent` defaults to `'atEquipment'`.
|
||||
|
||||
## Port-count change (Phase 6)
|
||||
|
||||
Pre-refactor the diffuser exposed 4 outputs (process, dbase, reactor
|
||||
control with `topic: 'OTR'`, parent registration). The reactor control
|
||||
message merged into Port 0 as `oZoneOtr`; consumers that previously
|
||||
listened to the dedicated control port should switch to reading
|
||||
`payload.oZoneOtr` from the process output. The legacy `OTR` topic is
|
||||
removed in this refactor — there is no alias, since the data shape
|
||||
differs (single value vs full process payload).
|
||||
|
||||
## Events emitted by `source.measurements.emitter`
|
||||
|
||||
None today. The diffuser does not currently publish typed measurements
|
||||
through `MeasurementContainer`; all output flows via `getOutput()`.
|
||||
A future phase may promote `oOtr` and `oZoneOtr` to typed series so
|
||||
parent reactors can subscribe through the standard `ChildRouter`
|
||||
handshake.
|
||||
|
||||
## Events emitted by `source.emitter`
|
||||
|
||||
- `output-changed` — fires whenever an input setter recomputes the
|
||||
oxygen-transfer state. `BaseNodeAdapter` listens and pushes the
|
||||
delta-compressed Port 0 / Port 1 messages.
|
||||
|
||||
## Children registered by this node
|
||||
|
||||
None. The diffuser is a leaf Equipment Module; it registers itself with
|
||||
its parent (reactor / process cell) via the Port 2 handshake.
|
||||
Reference in New Issue
Block a user