# Wiki page template — every node uses this shape This is the canonical structure for every node's gitea wiki landing page. Visual-first, scannable, ≤ 60 words of unbroken prose anywhere. ## Why this shape The platform now has 12 nodes with the same architectural skeleton (BaseDomain + BaseNodeAdapter + ChildRouter + commands registry). The wiki should mirror that uniformity: a reader can flip between nodes and find the same sections in the same order. Mermaid blocks lead. Tables annotate. Prose only fills gaps. ## Template — copy this whole file as the seed for each node's wiki ```markdown # > One-paragraph "what is this node". Cap 60 words. Plain English. > Example: "rotatingMachine models a single pump or compressor — > takes pressure measurements and predicts flow + power from supplier > curves. State machine drives startup/shutdown sequences." ## 1. Position in the platform ```mermaid flowchart LR parent[] -->|set.demand| this[] this -->|evt.state-change| parent sensor[] -->|data.flow| this this -->|child.register| parent classDef proc fill:#0c99d9,color:#fff classDef unit fill:#50a8d9 classDef equip fill:#86bbdd classDef ctrl fill:#a9daee class this ``` The Mermaid block shows the typical neighbours and the data direction. Pick the right `classDef` for the S88 level (Process Cell / Unit / Equipment / Control Module). Match the colour codes from `.claude/rules/node-red-flow-layout.md`. ## 2. Capability matrix | Capability | Status | Notes | |---|---|---| | Predicts flow from pressure | ✅ | | | Receives manual setpoint | ✅ | Topic `set.setpoint` | | Auto-start on demand from parent | ✅ | | | Self-calibrating | ❌ | Calibration is operator-triggered (`cmd.calibrate`) | | Supports multi-parent registration | ⚠️ | Possible but not fully tested — see CONTRACT.md notes | Keep this table to ≤ 10 rows. For longer feature inventories, link out. ## 3. Topic contract > Auto-generated from `src/commands/index.js`. Do NOT hand-edit. > Re-run `npm run wiki:contract` after any change to commands. | Canonical topic | Aliases | Payload | Effect | |---|---|---|---| | `set.mode` | `setMode` | `string` (`auto` \| `manual` \| `maintenance`) | Switches operating mode. | | `cmd.startup` | `execSequence` (with `payload.action='startup'`) | `{source: string}` | Triggers startup sequence (state machine). | | ... | ... | ... | ... | ## 4. Lifecycle — what one tick (or event) does ```mermaid sequenceDiagram participant parent participant node as this node participant sensor as measurement child participant out as Port-0 output sensor->>node: data.flow (12 m³/h, downstream) node->>node: route → measurementHandlers node->>node: drift assess → predictionHealth update node->>node: getOutput composes snapshot node->>out: msg{topic, payload, [process|influx]} parent->>node: set.demand (15 m³/h) node->>node: control.dispatch node->>parent: child.register (handshake) ``` Keep the diagram to one screen. If you have multiple distinct flows (idle vs running vs error), pick the most common one and link out to the others. ## 5. Configuration — editor form & where each field lands ```mermaid flowchart TB subgraph editor["Node-RED editor form"] f1[Mode] f2[Demand] f3[Threshold percent] end subgraph config["Domain config"] c1[control.mode] c2[control.targets.demand] c3[safety.thresholdPercent] end f1 --> c1 f2 --> c2 f3 --> c3 ``` | Form field | Config key | Default | Range | |---|---|---|---| | Mode | `control.mode` | `auto` | enum | | Demand | `control.targets.demand` | `0` | ≥ 0 | | Threshold % | `safety.thresholdPercent` | `95` | 0–100 | ## 6. Examples | Tier | File | What it shows | |---|---|---| | Basic | `examples/01-Basic.json` | Inject + dashboard, no parent | | Integration | `examples/02-Integration.json` | Wired to `` + 1 measurement child | | Dashboard | `examples/03-Dashboard.json` | Live FlowFuse charts of flow / power / state | Include one screenshot per tier where helpful — keep them under 200 KB each. Link to a runnable docker compose snippet under `examples/README.md`. ## 7. State chart (only for stateful nodes) ```mermaid stateDiagram-v2 [*] --> off off --> idle: cmd.startup idle --> warmingup: setpoint > 0 warmingup --> operational: warmup_time elapsed operational --> coolingdown: cmd.shutdown coolingdown --> off: cooldown_time elapsed operational --> emergencystop: cmd.estop emergencystop --> off: cmd.reset ``` Skip this section for stateless / pure-aggregator nodes (e.g. measurement, dashboardAPI). ## 8. When you would NOT use this node - "Use rotatingMachine for a SINGLE pump. For groups of 2+ pumps with load sharing, use machineGroupControl as the parent." - "Use measurement only for sensor signal conditioning. For setpoint injection, use the dashboard or a parent's command topic." Two or three bullets, each one sentence. Forces explicit non-goals. ## 9. Known limitations / current issues | # | Issue | Tracked in | |---|---|---| | 1 | Drift confidence drops to 0 when pressure is missing for > 30 s | `OPEN_QUESTIONS.md` 2026-05-10 | | 2 | Multi-parent teardown ordering | `OPEN_QUESTIONS.md` 2026-05-10 | Link to repo issues when they exist. Keep this table living — it's the contract with the user about what "works". ``` ## Hard rules for editors 1. The Mermaid platform-position block is **section 1**, before any prose. Diagrams first. 2. Each section opens with a diagram or table; prose annotates the visual, not the other way round. 3. No more than **60 words of unbroken prose** anywhere on a page. 4. The topic contract is **auto-generated** from `src/commands/index.js`. Don't hand-write it. 5. Use `flowchart LR` for node connections, `sequenceDiagram` for tick-to-output flow, `stateDiagram-v2` for state machines. 6. Skip `classDiagram` (we don't expose classes to users) and `gantt` (no schedules in node docs). ## Auto-generation notes (Phase 9 follow-up) The "Topic contract" table in section 3 should be generated by a small `npm run wiki:contract` script, per node. Implementation: ```js // scripts/generate-contract.js const commands = require('../src/commands'); const rows = commands.map((c) => ({ topic: c.topic, aliases: (c.aliases || []).join(', ') || '—', payload: describeSchema(c.payloadSchema), effect: c.description || '— (handler-only)', })); console.log(toMarkdownTable(rows)); ``` `describeSchema` walks the lightweight schema (`{type, properties}`) and produces a one-line readable form. Wire each node's `package.json`: ```json "scripts": { "wiki:contract": "node scripts/generate-contract.js > wiki/_partial-topics.md" } ``` Then a thin wiki page `.md` includes `_partial-topics.md` (or the section is regenerated in-place between markers). ## What lives in the gitea wiki vs the repo - `wiki/` directory in the repo (where present): canonical, version- controlled. - gitea wiki UI: cosmetic mirror — re-rendered from `wiki/` on push. - Auto-generated partials (`_partial-*.md`): committed under `wiki/` but generated; never hand-edited.