Complete redesign of the platform-level wiki. Previous Home.md had a broken Mermaid diagram (showed pumpingStation → valveGroupControl as a parent/child edge, which isn't in any configure() declaration). Audit of all 12 specificClass.js configure() calls drives the new ground-truth hierarchy. New pages: - Home.md (rewritten — accurate mermaid, full node + concept index) - Architecture.md (3-tier code structure, generalFunctions API surface, child-registration sequence) - Topology-Patterns.md (5 verified plant configurations + worked example) - Topic-Conventions.md (set./cmd./evt./data./child. + unit policy + S88 palette + measurement key shape + status badge + HealthStatus) - Telemetry.md (Port 0/1/2 contracts + InfluxDB line-protocol layout + FlowFuse charts + Grafana provisioning) - Getting-Started.md (clone, install, Docker vs local, first example) - Glossary.md (S88, EVOLV runtime, WWTP, pumps, control, project terms) - _Sidebar.md (gitea wiki navigation) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.2 KiB
Topic Conventions
Reflects code as of
9ab9f6b· regenerated2026-05-11
Naming rules, unit policy, and S88 colour palette. Source of truth: .claude/refactor/CONTRACTS.md §1.
Topic prefixes
Every topic is <prefix>.<verb> lowercase. Five prefixes only.
flowchart LR
ui[UI / parent / driver]:::neutral
node[Node]:::tier3
child[Child]:::tier1
ui -->|set.x / cmd.x| node
node -->|evt.x| ui
child -->|data.x| node
node -->|data.x| child
child -->|child.register| node
classDef neutral fill:#dddddd
classDef tier3 fill:#50a8d9,color:#000
classDef tier1 fill:#a9daee,color:#000
| Prefix | Direction | Semantics | Examples |
|---|---|---|---|
set. |
inbound | Set a configurable value. Idempotent, no side-effects beyond storing the value. | set.mode, set.demand, set.position |
cmd. |
inbound | Trigger an action. Has side-effects (state transitions, motor commands). | cmd.startup, cmd.shutdown, cmd.calibrate, cmd.estop |
data. |
bidirectional | Carries measurement / process data. Used by measurement → parent and emitters. |
data.pressure, data.flow, data.temperature |
evt. |
outbound | Announces something happened. Consumer-driven. | evt.state-change, evt.alarm, evt.health |
child. |
inbound (parent) | Child node lifecycle. | child.register (with legacy alias registerChild) |
Anti-patterns to avoid:
- ❌ A topic that does two things (
setStartupto both set a flag and trigger startup). Split intoset.+cmd.. - ❌ Reusing a
cmd.topic for both inbound trigger and outbound ack — make a pairedevt.<verb>-complete. - ❌ Per-node prefixes (
pump.set.demand). The prefix is the kind, not the target.
Alias deprecation
Legacy topic names (pre-refactor) are still accepted as aliases. The current alias map per node lives in src/commands/index.js. Common aliases:
| Canonical | Legacy aliases |
|---|---|
set.mode |
setMode |
set.demand |
Qd, setDemand |
cmd.startup |
execSequence with payload.action='startup' |
cmd.shutdown |
execSequence with payload.action='shutdown' |
child.register |
registerChild |
data.pressure |
pressure |
data.flow |
flow |
Aliases are logged at debug level on use. Plan is to remove them in a future major version. Update integrations to canonical names.
Unit policy
Every node declares canonical + output units via UnitPolicy.declare({canonical, output}). The command registry coerces incoming msg.unit to the canonical unit before the handler runs. Outputs are emitted in the declared output unit (often human-friendly).
flowchart LR
ui[UI message<br/>e.g. 50 m³/h]:::neutral
coerce[unit coercion<br/>m³/h → m³/s]:::tier1
sc[specificClass<br/>canonical m³/s]:::tier3
out[output<br/>renders back to m³/h]:::tier2
ui --> coerce --> sc --> out
classDef neutral fill:#dddddd
classDef tier1 fill:#a9daee,color:#000
classDef tier3 fill:#50a8d9,color:#000
classDef tier2 fill:#86bbdd,color:#000
| Quantity | Canonical (internal) | Common output |
|---|---|---|
| Flow | m3/s |
m3/h, l/s, gpm |
| Pressure | Pa |
bar, mbar, kPa |
| Power | W |
kW, MW |
| Temperature | K |
degC, degF |
| Level | m |
m, cm |
| Volume | m3 |
m3, l |
Rule: anywhere in specificClass, treat values as canonical. Conversion happens at the boundary (input coercion + output formatting).
S88 colour palette
flowchart TB
A[Area<br/>#0f52a5]:::area
PC[Process Cell<br/>#0c99d9]:::pc
UN[Unit<br/>#50a8d9]:::unit
EM[Equipment Module<br/>#86bbdd]:::equip
CM[Control Module<br/>#a9daee]:::ctrl
UT[Utility / neutral<br/>#dddddd]:::neutral
A --> PC --> UN --> EM --> CM
UT -.- A
classDef area fill:#0f52a5,color:#fff
classDef pc fill:#0c99d9,color:#fff
classDef unit fill:#50a8d9,color:#000
classDef equip fill:#86bbdd,color:#000
classDef ctrl fill:#a9daee,color:#000
classDef neutral fill:#dddddd,color:#000
| Hex | S88 level | Used by |
|---|---|---|
#0f52a5 |
Area | (reserved — not in use yet) |
#0c99d9 |
Process Cell | pumpingStation |
#50a8d9 |
Unit | machineGroupControl, valveGroupControl, reactor, settler, monster |
#86bbdd |
Equipment Module | rotatingMachine, valve, diffuser |
#a9daee |
Control Module | measurement |
#dddddd |
Utility / neutral | dashboardAPI, helper function nodes |
Rule: every Mermaid diagram in this wiki, every Node-RED node's editor colour, and every dashboard grouping uses this palette. Source of truth: .claude/rules/node-red-flow-layout.md §14.
Known outliers (pending cleanup, tracked in OPEN_QUESTIONS.md):
settlereditor colour is#e4a363(orange) — should be#50a8d9.monstereditor colour is#4f8582(teal) — should be#50a8d9.diffusereditor colour was missing pre-refactor; now#86bbdd.dashboardAPIregisters under category'wbd typical'instead of'EVOLV'.
Measurement key shape
The MeasurementContainer stores values under composite keys:
<type>.<variant>.<position>.<childId>
| Segment | Examples |
|---|---|
type |
flow, pressure, power, temperature, level |
variant |
measured, predicted, setpoint, min, max |
position |
upstream, downstream, atequipment, inlet, outlet (always lowercase in keys) |
childId |
The registering child's id, OR default for internal computations |
Examples:
flow.measured.downstream.dashboard-sim-downstream— externally measured downstream flow.flow.predicted.downstream.default— node's own prediction.power.measured.atequipment.default— measured power at the equipment.pressure.measured.upstream.<childId>— pressure from a specific measurement child.
Gotcha: position is always lowercase in keys. The configuration form may use mixed case (atEquipment); the container normalises.
Status badge
statusBadge.compose(state) returns {fill, shape, text} for node.status(...):
| level | shape | fill | meaning |
|---|---|---|---|
info |
dot | blue | normal operation |
success |
dot | green | success / running optimally |
warning |
ring | yellow | degraded, attention needed |
error |
ring | red | fault, operator action required |
pending |
dot | grey | initialising / no data yet |
Composer reads from HealthStatus.level (0–3) — kept centralised so all nodes show consistent badges.
HealthStatus shape
{
"level": 0,
"flags": ["pressure_init_warming"],
"message": "warmup phase",
"source": "rotatingMachine#pump-A"
}
| Field | Range | Meaning |
|---|---|---|
level |
0..3 | 0 = healthy, 1 = degraded, 2 = warning, 3 = error |
flags |
string[] | Machine-readable reason codes. |
message |
string | Human-readable summary (one line). |
source |
string | <nodeType>#<id> — for routing UI / alarm correlation. |
Related pages
- Architecture — generalFunctions API surface
- Telemetry — Port-1 InfluxDB schema (where these conventions appear in stored data)
- Topology-Patterns — what topics flow where