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>
186 lines
7.2 KiB
Markdown
186 lines
7.2 KiB
Markdown
# Topic Conventions
|
||
|
||
> **Reflects code as of `9ab9f6b` · regenerated `2026-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.
|
||
|
||
```mermaid
|
||
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 (`setStartup` to both set a flag *and* trigger startup). Split into `set.` + `cmd.`.
|
||
- ❌ Reusing a `cmd.` topic for both inbound trigger and outbound ack — make a paired `evt.<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).
|
||
|
||
```mermaid
|
||
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
|
||
|
||
```mermaid
|
||
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):
|
||
- `settler` editor colour is `#e4a363` (orange) — should be `#50a8d9`.
|
||
- `monster` editor colour is `#4f8582` (teal) — should be `#50a8d9`.
|
||
- `diffuser` editor colour was missing pre-refactor; now `#86bbdd`.
|
||
- `dashboardAPI` registers 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
|
||
|
||
```json
|
||
{
|
||
"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](Architecture) — generalFunctions API surface
|
||
- [Telemetry](Telemetry) — Port-1 InfluxDB schema (where these conventions appear in stored data)
|
||
- [Topology-Patterns](Topology-Patterns) — what topics flow where
|