wiki: crisp overhaul — no decoration emoji, all 9 master pages refactored
Source-tree mirror of EVOLV.wiki.git refactor (27a42ee on wiki.git): - 7 master pages rewritten with clean design (Home, Architecture, Topology-Patterns, Topic-Conventions, Telemetry, Getting-Started, Glossary). Tables and Mermaid for visuals, gitea alert callouts for warnings, shields badges for metadata only. No emoji as decoration. - Archive.md becomes a removal-changelog pointing readers to git history and to the successor pages. - _Sidebar.md updated to navigate the new flat-name layout. - Concept / finding / manual pages: uniform mini-header (badges + "reference page" callout) added without rewriting domain content. - Every internal link now uses the flat naming that resolves on the live gitea wiki (Concept-ASM-Models, Finding-BEP-..., etc.). On wiki.git: 29 Archive-* pages hard-deleted (the git history preserves them; Archive.md documents the removal). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,32 +1,49 @@
|
||||
# Topology Patterns
|
||||
|
||||
> **Reflects code as of `9ab9f6b` · regenerated `2026-05-11`**
|
||||

|
||||
-brightgreen)
|
||||
|
||||
Typical plant configurations and how nodes wire together. Each pattern is **verified** against the corresponding nodes' `configure()` declarations.
|
||||
> [!NOTE]
|
||||
> Five canonical plant configurations and one worked example that combines them. Every edge in every diagram was checked against the parent's `configure()` declaration in source. Use these as templates when wiring your own plant.
|
||||
|
||||
## Pattern 1 — Pumping station with grouped pumps
|
||||
---
|
||||
|
||||
The canonical wet-well lift station. One basin, one demand controller (`pumpingStation`), one load-sharing coordinator (`machineGroupControl`), N pumps. Level + flow measurements feed the basin model.
|
||||
## Pattern index
|
||||
|
||||
| Pattern | When to use it |
|
||||
|:---|:---|
|
||||
| [1. Pumping station with grouped pumps](#1-pumping-station-with-grouped-pumps) | Lift station, single basin, N pumps load-shared |
|
||||
| [2. Reactor + diffuser + settler train](#2-reactor--diffuser--settler-train) | Biological treatment line |
|
||||
| [3. Valve group on a distribution manifold](#3-valve-group-on-a-distribution-manifold) | Multi-valve flow split with upstream flow context |
|
||||
| [4. Composite sampling](#4-composite-sampling) | Flow-proportional grab samples for lab analysis |
|
||||
| [5. Dashboard provisioning](#5-dashboard-provisioning) | Auto-generated Grafana dashboards |
|
||||
| [Worked example — small WWTP](#worked-example--small-wwtp) | All five patterns combined |
|
||||
|
||||
---
|
||||
|
||||
## 1. Pumping station with grouped pumps
|
||||
|
||||
The canonical wet-well lift station: one basin model, one demand controller (`pumpingStation`), one load-sharing coordinator (`machineGroupControl`), N pumps (`rotatingMachine` × N), measurements for level + flow + per-pump pressure.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph PC["Process Cell"]
|
||||
ps[pumpingStation]:::pc
|
||||
ps[pumpingStation]
|
||||
end
|
||||
subgraph UN["Unit"]
|
||||
mgc[machineGroupControl]:::unit
|
||||
mgc[machineGroupControl]
|
||||
end
|
||||
subgraph EM["Equipment"]
|
||||
rmA[rotatingMachine A]:::equip
|
||||
rmB[rotatingMachine B]:::equip
|
||||
rmC[rotatingMachine C]:::equip
|
||||
subgraph EM["Equipment Module"]
|
||||
rmA[rotatingMachine A]
|
||||
rmB[rotatingMachine B]
|
||||
rmC[rotatingMachine C]
|
||||
end
|
||||
subgraph CM["Control Module"]
|
||||
ml[measurement: level]:::ctrl
|
||||
mfin[measurement: inflow]:::ctrl
|
||||
mpA[measurement: pressure A]:::ctrl
|
||||
mpB[measurement: pressure B]:::ctrl
|
||||
mpC[measurement: pressure C]:::ctrl
|
||||
ml["measurement — level"]
|
||||
mfin["measurement — inflow"]
|
||||
mpA["measurement — pressure A"]
|
||||
mpB["measurement — pressure B"]
|
||||
mpC["measurement — pressure C"]
|
||||
end
|
||||
|
||||
ps --> mgc
|
||||
@@ -40,82 +57,102 @@ flowchart TB
|
||||
mpB -. data .-> rmB
|
||||
mpC -. data .-> rmC
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef equip fill:#86bbdd,color:#000
|
||||
classDef ctrl fill:#a9daee,color:#000
|
||||
class ps pc
|
||||
class mgc unit
|
||||
class rmA,rmB,rmC equip
|
||||
class ml,mfin,mpA,mpB,mpC ctrl
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff,stroke:#075a82,stroke-width:2px
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef equip fill:#86bbdd,color:#000,stroke:#5a90b2,stroke-width:2px
|
||||
classDef ctrl fill:#a9daee,color:#000,stroke:#76b7d4,stroke-width:2px
|
||||
```
|
||||
|
||||
**Data flow:**
|
||||
- `pumpingStation` computes basin volume + level dynamics from inflow/outflow measurements.
|
||||
- `pumpingStation` emits a demand setpoint downstream to `machineGroupControl` on its Port 0 or via `set.demand`.
|
||||
- `machineGroupControl` solves a per-pump operating point using each pump's characteristic curve + measured pressure, sends `set.setpoint` to each `rotatingMachine`.
|
||||
- Each `rotatingMachine` runs its own FSM (idle/warmingup/operational/coolingdown/emergencystop) and predicts flow/power from pressure + speed.
|
||||
### Data flow
|
||||
|
||||
**Notes:**
|
||||
- For a single-pump station, `pumpingStation` can register `rotatingMachine` directly (skip the MGC) — `pumpingStation`'s `configure()` accepts `machine` as a child softwareType.
|
||||
- For two stations in series, the downstream PS can register the upstream PS as a `pumpingstation` softwareType source.
|
||||
| Stage | What happens |
|
||||
|:---|:---|
|
||||
| Basin integration | `pumpingStation` integrates basin volume from inflow / outflow rates |
|
||||
| Demand computation | `pumpingStation` computes a demand setpoint and dispatches it to `machineGroupControl` |
|
||||
| Per-pump operating point | `machineGroupControl` solves a per-pump operating point using each pump's characteristic curve plus measured upstream pressure |
|
||||
| Pump dispatch | Each `rotatingMachine` runs its own FSM (`idle` → `warmingup` → `operational` → `coolingdown` → `emergencystop`, plus `accelerating` / `decelerating`) and predicts flow + power from speed + pressure |
|
||||
|
||||
## Pattern 2 — Reactor / settler train with aeration
|
||||
### Variants
|
||||
|
||||
Biological treatment line. Reactor runs ASM kinetics, diffuser drives O₂ transfer, settler clarifies effluent and returns sludge via a return pump.
|
||||
| Variant | How to wire |
|
||||
|:---|:---|
|
||||
| Single pump (no MGC) | `pumpingStation.configure()` accepts `machine` directly — skip the MGC and parent the `rotatingMachine` under `pumpingStation` |
|
||||
| Cascaded stations | `pumpingStation.configure()` accepts `pumpingstation` as a child — downstream PS registers upstream PS to read its predicted outflow |
|
||||
|
||||
---
|
||||
|
||||
## 2. Reactor + diffuser + settler train
|
||||
|
||||
Biological treatment line. `reactor` runs ASM kinetics (CSTR or PFR engine, set via `config.reactor_type`). `diffuser` injects OTR. `settler` clarifies the effluent and drives a return pump.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph UN["Unit"]
|
||||
reactor[reactor]:::unit
|
||||
settler[settler]:::unit
|
||||
reactor[reactor]
|
||||
settler[settler]
|
||||
end
|
||||
subgraph EM["Equipment"]
|
||||
diff[diffuser]:::equip
|
||||
rp[rotatingMachine<br/>return pump]:::equip
|
||||
subgraph EM["Equipment Module"]
|
||||
diff[diffuser]
|
||||
rp["rotatingMachine — return pump"]
|
||||
end
|
||||
subgraph CM["Control Module"]
|
||||
mt[measurement: temperature]:::ctrl
|
||||
mdo[measurement: dissolved O₂]:::ctrl
|
||||
mts[measurement: TSS]:::ctrl
|
||||
mt["measurement — temperature"]
|
||||
mdo["measurement — dissolved O2"]
|
||||
mts["measurement — TSS"]
|
||||
end
|
||||
|
||||
reactor ==stateChange==> settler
|
||||
diff -. OTR data .-> reactor
|
||||
settler -->|return pump child| rp
|
||||
settler -->|return pump| rp
|
||||
|
||||
mt -. data .-> reactor
|
||||
mdo -. data .-> reactor
|
||||
mts -. data .-> settler
|
||||
mdo -. data .-> diff
|
||||
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef equip fill:#86bbdd,color:#000
|
||||
classDef ctrl fill:#a9daee,color:#000
|
||||
class reactor,settler unit
|
||||
class diff,rp equip
|
||||
class mt,mdo,mts ctrl
|
||||
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef equip fill:#86bbdd,color:#000,stroke:#5a90b2,stroke-width:2px
|
||||
classDef ctrl fill:#a9daee,color:#000,stroke:#76b7d4,stroke-width:2px
|
||||
```
|
||||
|
||||
**Data flow:**
|
||||
- `reactor.configure()` registers `measurement` (temperature, DO) and upstream `reactor` (for chained tanks).
|
||||
- `diffuser` emits `data.otr` on its emitter; reactor subscribes via `emitter.on('otr', …)` — **not** a child registration, just a data subscription.
|
||||
- `reactor` emits `stateChange` after every kinetics step. `settler._connectReactor` subscribes via `emitter.on('stateChange', …)` and pulls effluent composition.
|
||||
- `settler.configure()` accepts `reactor` (the upstream), `machine` (return pump), and `measurement` children.
|
||||
### Two non-standard wirings
|
||||
|
||||
**Notes:**
|
||||
- Reactor supports two kinetics engines: CSTR (continuous-stirred tank) and PFR (plug-flow). Set via `config.reactor_type`.
|
||||
- DO setpoint feedback (DO measurement → diffuser airflow) is not wired automatically — connect via a small control function or use a `valveGroupControl` upstream of an airflow valve.
|
||||
> [!IMPORTANT]
|
||||
> `diffuser` → `reactor` is data-only. Diffuser fires `data.otr` on its emitter; reactor subscribes via `emitter.on('otr', ...)`. There is no `child.register` handshake between them. See `nodes/reactor/src/specificClass.js` `configure()`.
|
||||
|
||||
## Pattern 3 — Valve group on a distribution manifold
|
||||
> [!IMPORTANT]
|
||||
> `reactor` → `settler` is a `stateChange` subscription, not a parent / child edge. Settler's `_connectReactor` attaches `emitter.on('stateChange', ...)` to pull effluent composition from the upstream reactor. The `reactor` softwareType is registered as a child of settler even though the reactor is semantically upstream.
|
||||
|
||||
Multi-valve flow distribution. VGC computes per-valve K_v shares to satisfy a target distribution while respecting upstream flow availability.
|
||||
> [!CAUTION]
|
||||
> DO setpoint feedback is not automatic. A measured-DO → diffuser-airflow loop must be closed externally (a function node) or via a `valveGroupControl` upstream of an airflow valve.
|
||||
|
||||
---
|
||||
|
||||
## 3. Valve group on a distribution manifold
|
||||
|
||||
Multi-valve flow distribution. `valveGroupControl` computes per-valve K_v shares to satisfy a target split while respecting upstream flow availability.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph PC["Process Cell"]
|
||||
ps[pumpingStation<br/>upstream flow source]:::pc
|
||||
ps["pumpingStation — upstream flow source"]
|
||||
end
|
||||
subgraph UN["Unit"]
|
||||
vgc[valveGroupControl]:::unit
|
||||
vgc[valveGroupControl]
|
||||
end
|
||||
subgraph EM["Equipment"]
|
||||
vA[valve A]:::equip
|
||||
vB[valve B]:::equip
|
||||
vC[valve C]:::equip
|
||||
subgraph EM["Equipment Module"]
|
||||
vA[valve A]
|
||||
vB[valve B]
|
||||
vC[valve C]
|
||||
end
|
||||
|
||||
ps -. flow source .-> vgc
|
||||
@@ -123,95 +160,125 @@ flowchart TB
|
||||
vgc --> vB
|
||||
vgc --> vC
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef equip fill:#86bbdd,color:#000
|
||||
class ps pc
|
||||
class vgc unit
|
||||
class vA,vB,vC equip
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff,stroke:#075a82,stroke-width:2px
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef equip fill:#86bbdd,color:#000,stroke:#5a90b2,stroke-width:2px
|
||||
```
|
||||
|
||||
**Important detail:** `valveGroupControl.configure()` registers four extra softwareTypes — `machine`, `machinegroup`, `pumpingstation`, `valvegroupcontrol` — **not as S88 children** but as **flow sources**. VGC uses them to read upstream flow availability when computing per-valve splits. The arrow above is `child.register` from pumpingStation to vgc; the semantic relationship is "VGC knows about this upstream flow producer", not "VGC controls pumpingStation".
|
||||
> [!IMPORTANT]
|
||||
> VGC's child types are unusual. `valveGroupControl.configure()` registers five softwareTypes:
|
||||
> - `valve` — actual S88 child relationship (VGC controls these)
|
||||
> - `machine`, `machinegroup`, `pumpingstation`, `valvegroupcontrol` — flow sources. VGC reads upstream flow availability when computing splits. Semantic is "VGC knows about this flow producer", not "VGC controls it".
|
||||
>
|
||||
> See `nodes/valveGroupControl/src/specificClass.js` lines 13–49.
|
||||
|
||||
## Pattern 4 — Composite sampling
|
||||
---
|
||||
|
||||
`monster` runs a proportional sampling program — accumulates samples in a bucket based on integrated flow. Used as a virtual sensor for downstream lab analysis.
|
||||
## 4. Composite sampling
|
||||
|
||||
Virtual sensor for downstream lab analysis. `monster` accumulates samples in a bucket based on integrated flow — a flow-proportional grab sample.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph UN["Unit"]
|
||||
monster[monster]:::unit
|
||||
monster[monster]
|
||||
end
|
||||
subgraph CM["Control Module"]
|
||||
mflow[measurement: flow<br/>assetType MUST be 'flow']:::ctrl
|
||||
mq[measurement: any quality<br/>e.g. NH₄, COD]:::ctrl
|
||||
mflow["measurement — flow (assetType MUST be 'flow')"]
|
||||
mq["measurement — any quality (e.g. NH4, COD)"]
|
||||
end
|
||||
|
||||
mflow -. data .-> monster
|
||||
mq -. data .-> monster
|
||||
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef ctrl fill:#a9daee,color:#000
|
||||
class monster unit
|
||||
class mflow,mq ctrl
|
||||
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef ctrl fill:#a9daee,color:#000,stroke:#76b7d4,stroke-width:2px
|
||||
```
|
||||
|
||||
**Gotchas:**
|
||||
- `measurement.config.asset.type` MUST be `"flow"` exactly — `"flow-electromagnetic"` or any sub-type is silently ignored by monster's child router.
|
||||
- `monster.config.constraints.flowmeter` exists in the schema but is **not forwarded** by `buildDomainConfig` — toggling proportional-vs-time mode has no effect at runtime. (Tracked in OPEN_QUESTIONS.md.)
|
||||
> [!WARNING]
|
||||
> Two gotchas:
|
||||
> 1. `measurement.config.asset.type` must be exactly `"flow"`. A value like `"flow-electromagnetic"` is silently ignored by monster's child router.
|
||||
> 2. `monster.config.constraints.flowmeter` exists in the schema but is not forwarded by `buildDomainConfig`. Toggling proportional-vs-time mode has no runtime effect. Tracked in `.claude/refactor/OPEN_QUESTIONS.md`.
|
||||
|
||||
## Pattern 5 — Dashboard provisioning
|
||||
---
|
||||
|
||||
`dashboardAPI` doesn't operate on data — it generates Grafana dashboards. Any node can register with `dashboardAPI` via `child.register`; dashboardAPI then composes a dashboard JSON from the node's softwareType + measurements and POSTs to Grafana's HTTP API.
|
||||
## 5. Dashboard provisioning
|
||||
|
||||
`dashboardAPI` doesn't operate on data — it generates Grafana dashboards. Any node registers via `child.register`; dashboardAPI composes a dashboard JSON from softwareType plus measurements and POSTs to Grafana's HTTP API.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph EVOLV["EVOLV process nodes"]
|
||||
ps[pumpingStation]:::pc
|
||||
mgc[machineGroupControl]:::unit
|
||||
rm[rotatingMachine]:::equip
|
||||
subgraph EVOLV["EVOLV process nodes (any softwareType)"]
|
||||
direction TB
|
||||
ps[pumpingStation]
|
||||
mgc[machineGroupControl]
|
||||
rm[rotatingMachine]
|
||||
end
|
||||
subgraph UT["Utility"]
|
||||
dash[dashboardAPI]:::util
|
||||
dash[dashboardAPI]
|
||||
end
|
||||
grafana[(Grafana<br/>HTTP API)]:::ext
|
||||
grafana[("Grafana HTTP API")]
|
||||
|
||||
ps -. child.register .-> dash
|
||||
mgc -. child.register .-> dash
|
||||
rm -. child.register .-> dash
|
||||
dash -->|POST /api/dashboards/db| grafana
|
||||
dash ==>|POST /api/dashboards/db| grafana
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef equip fill:#86bbdd,color:#000
|
||||
classDef util fill:#dddddd,color:#000
|
||||
classDef ext fill:#fff2cc,color:#000
|
||||
class ps pc
|
||||
class mgc unit
|
||||
class rm equip
|
||||
class dash util
|
||||
class grafana ext
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff,stroke:#075a82,stroke-width:2px
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef equip fill:#86bbdd,color:#000,stroke:#5a90b2,stroke-width:2px
|
||||
classDef util fill:#dddddd,color:#000,stroke:#a8a8a8,stroke-width:2px
|
||||
classDef ext fill:#fff2cc,color:#000,stroke:#aa8400,stroke-width:2px
|
||||
```
|
||||
|
||||
**Notes:**
|
||||
- `dashboardAPI` is the one node in the platform that doesn't extend `BaseDomain` (it's a passive HTTP bridge — see OPEN_QUESTIONS.md for the deferral decision).
|
||||
- The `meta` field of dashboardAPI's outbound msg carries `{nodeId, softwareType, uid, title}` for correlating responses.
|
||||
| Behaviour | Detail |
|
||||
|:---|:---|
|
||||
| What it accepts | Any softwareType on `child.register` |
|
||||
| What it emits | One HTTP POST per registered child, payload from `nodes/dashboardAPI/src/config/templates/<softwareType>.json` |
|
||||
| Auth | Bearer token in `config.grafanaConnector.bearerToken` (when set) |
|
||||
| `meta` envelope | `{nodeId, softwareType, uid, title}` for correlating responses |
|
||||
| Architecture variance | The one node in the platform that does not extend `BaseDomain`. Documented in `.claude/refactor/OPEN_QUESTIONS.md` |
|
||||
|
||||
## Putting it all together — example plant
|
||||
---
|
||||
|
||||
A small WWTP combining all patterns:
|
||||
## Worked example — small WWTP
|
||||
|
||||
All five patterns combined.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph PC["Process Cell"]
|
||||
ps1[pumpingStation<br/>inlet lift]:::pc
|
||||
ps2[pumpingStation<br/>RAS pumping]:::pc
|
||||
ps1["pumpingStation — inlet lift"]
|
||||
ps2["pumpingStation — RAS pumping"]
|
||||
end
|
||||
subgraph UN["Unit"]
|
||||
mgc1[MGC inlet]:::unit
|
||||
mgc2[MGC RAS]:::unit
|
||||
vgc[VGC effluent split]:::unit
|
||||
r1[reactor aerobic]:::unit
|
||||
s1[settler]:::unit
|
||||
mon[monster<br/>composite sampler]:::unit
|
||||
mgc1["MGC inlet"]
|
||||
mgc2["MGC RAS"]
|
||||
vgc["VGC effluent split"]
|
||||
r1["reactor aerobic"]
|
||||
s1["settler"]
|
||||
mon["monster — composite sampler"]
|
||||
end
|
||||
subgraph EM["Equipment"]
|
||||
rm1[pump A]:::equip
|
||||
rm2[pump B]:::equip
|
||||
rm3[RAS pump]:::equip
|
||||
d1[diffuser]:::equip
|
||||
v1[valve 1]:::equip
|
||||
v2[valve 2]:::equip
|
||||
subgraph EM["Equipment Module"]
|
||||
rm1["pump A"]
|
||||
rm2["pump B"]
|
||||
rm3["RAS pump"]
|
||||
d1["diffuser"]
|
||||
v1["valve 1"]
|
||||
v2["valve 2"]
|
||||
end
|
||||
|
||||
ps1 --> mgc1
|
||||
@@ -228,21 +295,45 @@ flowchart TB
|
||||
vgc --> v1
|
||||
vgc --> v2
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff
|
||||
classDef unit fill:#50a8d9,color:#000
|
||||
classDef equip fill:#86bbdd,color:#000
|
||||
class ps1,ps2 pc
|
||||
class mgc1,mgc2,vgc,r1,s1,mon unit
|
||||
class rm1,rm2,rm3,d1,v1,v2 equip
|
||||
|
||||
classDef pc fill:#0c99d9,color:#fff,stroke:#075a82,stroke-width:2px
|
||||
classDef unit fill:#50a8d9,color:#000,stroke:#2c7ba8,stroke-width:2px
|
||||
classDef equip fill:#86bbdd,color:#000,stroke:#5a90b2,stroke-width:2px
|
||||
```
|
||||
|
||||
This is the kind of diagram each `wiki/Home.md` per node should be able to fit into — every edge is reproducible from a `configure()` declaration.
|
||||
| Sub-pattern | Recognise it |
|
||||
|:---|:---|
|
||||
| Pumping station with grouped pumps (×2) | `ps1 -> mgc1 -> {rm1, rm2}` and `ps2 -> mgc2 -> rm3` |
|
||||
| Reactor + settler train | `r1 ==stateChange==> s1` plus `d1 -. OTR .-> r1` |
|
||||
| Valve group on flow source | `ps2 -. flow source .-> vgc -> {v1, v2}` |
|
||||
| Settler return pump | `s1 -> rm3` |
|
||||
| Composite sampling | `mon` (would be wired to inflow + quality measurements not drawn) |
|
||||
|
||||
Every edge here is reproducible from one of the patterns above.
|
||||
|
||||
---
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- ❌ `pumpingStation → valveGroupControl` as a parent/child edge. PS does not register VGC. VGC registers PS as a *flow source*; the edge goes the other way semantically.
|
||||
- ❌ A `diffuser → reactor` child registration. Diffuser emits OTR via its emitter; reactor subscribes. No `child.register` handshake.
|
||||
- ❌ `measurement` parented under `dashboardAPI`. dashboardAPI accepts any node for Grafana provisioning, but `measurement` registers with the **process** node it's monitoring, not with dashboardAPI.
|
||||
> [!CAUTION]
|
||||
> `pumpingStation` → `valveGroupControl` as a parent / child edge. PS does not register VGC. VGC registers PS as a flow source — the edge goes the other way semantically.
|
||||
|
||||
> [!CAUTION]
|
||||
> `diffuser` → `reactor` as a child registration. Diffuser emits OTR via its emitter; reactor subscribes via `emitter.on`. No `child.register` handshake.
|
||||
|
||||
> [!CAUTION]
|
||||
> `measurement` parented under `dashboardAPI`. dashboardAPI accepts any node for Grafana provisioning, but `measurement` should register with the process node it is monitoring, not with dashboardAPI.
|
||||
|
||||
---
|
||||
|
||||
## Related pages
|
||||
|
||||
- [Home](Home) — top-level node map
|
||||
- [Architecture](Architecture) — 3-tier code structure + generalFunctions API
|
||||
- [Topic-Conventions](Topic-Conventions) — what topics flow between nodes
|
||||
| Page | Why |
|
||||
|:---|:---|
|
||||
| [Home](Home) | Top-level node map |
|
||||
| [Architecture](Architecture) | Three-tier code + generalFunctions API |
|
||||
| [Topic Conventions](Topic-Conventions) | What topics flow on each edge |
|
||||
| [Telemetry](Telemetry) | Port 0 / 1 / 2 InfluxDB layout |
|
||||
|
||||
Reference in New Issue
Block a user