From e03a7a51b72f3b97539b4ce19fb57e36abf3694c Mon Sep 17 00:00:00 2001 From: Rene De Ren Date: Mon, 11 May 2026 14:25:34 +0200 Subject: [PATCH] P9 follow-up: expand wiki template + add Home/Archive template MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WIKI_TEMPLATE.md — extend the canonical per-node page from 9 to 14 sections: + Header band (commit hash + regen date) + Code map (flowchart TB w/ subgraphs over concern modules) + Child registration (mirrors ChildRouter declarations) + Data model — getOutput() (abstract schema + optional concrete sample) + Debug recipes (symptom → first thing to check) + AUTOGEN markers around topic-contract + data-model schema so the Phase 9 regen script can rewrite in place. + 'Picking a visual' table: Mermaid is default, plots/SVG/screenshots allowed where they serve the data. + Archive banner snippet. WIKI_HOME_TEMPLATE.md (new) — Home.md + Archive.md templates: - Platform-wide Mermaid graph of 11 active nodes, S88-coloured. - Navigation table grouped by S88 level. - Standards-pointer table to .claude/rules + .claude/refactor docs. - Live refactor-status table for returning visitors. - Archive index template with archival-date column. No wiki pages written yet — next step is one worked example (pumpingStation) before any change to the Gitea wiki repo. Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/refactor/WIKI_HOME_TEMPLATE.md | 141 +++++++++ .claude/refactor/WIKI_TEMPLATE.md | 377 +++++++++++++++++-------- 2 files changed, 396 insertions(+), 122 deletions(-) create mode 100644 .claude/refactor/WIKI_HOME_TEMPLATE.md diff --git a/.claude/refactor/WIKI_HOME_TEMPLATE.md b/.claude/refactor/WIKI_HOME_TEMPLATE.md new file mode 100644 index 0000000..3b74379 --- /dev/null +++ b/.claude/refactor/WIKI_HOME_TEMPLATE.md @@ -0,0 +1,141 @@ +# Platform wiki home — `Home.md` template + +The landing page for the EVOLV Gitea wiki. Same visual-first rules as `WIKI_TEMPLATE.md`: diagrams lead, tables annotate, ≤ 60 words per paragraph. + +`Home.md` answers three questions for a first-time visitor: + +1. **What is this platform?** One paragraph. +2. **What nodes exist and how do they relate?** One platform-wide Mermaid graph + a navigation table. +3. **Where do I find the conventions?** A pointer table to the rule files in `.claude/`. + +Plus a live refactor-status table so a returning visitor knows what changed since they last looked. + +## Template — copy the block below as the seed for `Home.md` + +``` + + +# EVOLV — Wastewater treatment plant automation + +> **Reflects code as of `` · regenerated `` via `npm run wiki:home`** + +EVOLV is a Node-RED node library for wastewater plant automation, developed by the R&D team at Waterschap Brabantse Delta. Nodes follow the ISA-88 (S88) batch control standard. The library exposes 11 active nodes spanning four S88 levels: from Process Cell down to Control Module, plus one utility node for dashboard integration. + +## Platform overview + +~~~mermaid +flowchart TB + subgraph PC["Process Cell"] + ps[pumpingStation]:::pc + end + subgraph UN["Unit"] + mgc[machineGroupControl]:::unit + vgc[valveGroupControl]:::unit + reactor[reactor]:::unit + settler[settler]:::unit + monster[monster]:::unit + end + subgraph EM["Equipment"] + rm[rotatingMachine]:::equip + v[valve]:::equip + diff[diffuser]:::equip + end + subgraph CM["Control Module"] + meas[measurement]:::ctrl + end + subgraph UT["Utility"] + dash[dashboardAPI]:::neutral + end + ps --> mgc + ps --> vgc + mgc --> rm + vgc --> v + reactor --> diff + meas -.data.-> rm + meas -.data.-> v + meas -.data.-> reactor + meas -.data.-> settler + 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 +~~~ + +S88 colours: Process Cell `#0c99d9`, Unit `#50a8d9`, Equipment `#86bbdd`, Control Module `#a9daee`. Solid arrow = parent/child relationship. Dashed arrow = data flow (`measurement` feeds many node types). + +## Live nodes + +| S88 | Node | One-liner | Wiki | +|---|---|---|---| +| 🟦 Process Cell | **pumpingStation** | Manages a wet-well basin, hands demand to one or more group controllers. | [→](pumpingStation) | +| 🔷 Unit | **machineGroupControl** | Load-sharing across a group of rotatingMachines. | [→](machineGroupControl) | +| 🔷 Unit | **valveGroupControl** | Coordinated valve control across a group of valves. | [→](valveGroupControl) | +| 🔷 Unit | **reactor** | Bioreactor — couples diffuser + measurements + kinetics. | [→](reactor) | +| 🔷 Unit | **settler** | Settler / clarifier modelling. | [→](settler) | +| 🔷 Unit | **monster** | Composite-sample sensor surrogate. | [→](monster) | +| 🟦 Equipment | **rotatingMachine** | Single pump / compressor — curves, state machine, prediction. | [→](rotatingMachine) | +| 🟦 Equipment | **valve** | Single valve actuator with FSM. | [→](valve) | +| 🟦 Equipment | **diffuser** | Aeration diffuser, gas-side modelling. | [→](diffuser) | +| 🔹 Control Module | **measurement** | Sensor signal-conditioning, scaling, calibration. | [→](measurement) | +| ⚪ Utility | **dashboardAPI** | Bridge between FlowFuse dashboard widgets and EVOLV. | [→](dashboardAPI) | + +## Standards & conventions + +| Document | What it covers | Where | +|---|---|---| +| Node architecture (3-tier) | entry → nodeClass → specificClass | `.claude/rules/node-architecture.md` | +| Flow layout (Node-RED tabs) | Tab boundaries, lanes, S88 colours, link channels | `.claude/rules/node-red-flow-layout.md` | +| Topic naming (`set.` / `cmd.` / `evt.`) | Canonical input + output topics | `.claude/refactor/CONTRACTS.md` §1 | +| Wiki page shape | Per-node page template | `.claude/refactor/WIKI_TEMPLATE.md` | +| Wiki home shape | This page's template | `.claude/refactor/WIKI_HOME_TEMPLATE.md` | +| generalFunctions stability rules | What's safe to change | `.claude/rules/general-functions.md` | + +## Refactor status + +| Tier | What | Status | +|---|---|---| +| 1 | Add infra in generalFunctions (additive only) | ✅ done | +| 2 | Pilot: pumpingStation | ✅ done | +| 3 | Convert measurement, MGC, rotatingMachine | ✅ done | +| 4 | Convert valve, VGC, reactor, settler, monster, diffuser | ✅ done | +| 4* | dashboardAPI | ⏸️ out of scope (no `generalFunctions` dep) | +| 5 | Canonical topic names + alias deprecation | 🟡 partial | +| 6 | development → main promotion | ⏳ pending Docker E2E | +| 7 | Wiki refactor (this work) | 🟡 in progress | + +## Archive + +Pre-refactor pages live under `Archive/`. See [Archive index](Archive). + + +``` + +## Notes for the maintainer + +- `npm run wiki:home` (not yet built) re-renders the platform Mermaid block if any node's `softwareType` registration changes. Until then, the diagram is hand-maintained. +- Refactor-status rows flip as tiers land. Anyone landing a tier updates the table in the same PR. +- The "Live nodes" table is hand-maintained but small — bulk changes happen only when a node is added or retired. +- The Mermaid graph above mirrors what's in `.claude/rules/node-red-flow-layout.md` §10.1 (lane convention). If the rule changes, mirror it here. + +## Archive index — `Archive.md` template + +A separate page that lists every archived page with its archival date and the era it describes. + +``` + + +# Archive — pre-refactor wiki pages + +Pages kept for historical reference. **Do not update them.** Corrections go on the current page; if you find a meaningful inaccuracy in the archived page, leave it and add a note to the *current* page explaining what changed. + +| Page | Era | Archived on | +|---|---|---| +| [pumpingStation (pre-refactor)](Archive/pumpingStation-pre-refactor) | Pre-Tier-2 (May 2026) | 2026-05-11 | +| [rotatingMachine (pre-refactor)](Archive/rotatingMachine-pre-refactor) | Pre-Tier-3 (May 2026) | 2026-05-11 | +| ... | ... | ... | + +Each archived page carries the standard banner at its top (see `WIKI_TEMPLATE.md` → Archive banner). + + +``` diff --git a/.claude/refactor/WIKI_TEMPLATE.md b/.claude/refactor/WIKI_TEMPLATE.md index 89e4e20..eee65de 100644 --- a/.claude/refactor/WIKI_TEMPLATE.md +++ b/.claude/refactor/WIKI_TEMPLATE.md @@ -1,48 +1,83 @@ # 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. +Canonical structure for every node's Gitea wiki landing page. **Visual-first**, scannable, ≤ 60 words per paragraph anywhere on the page. ## 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. +The platform has 12 nodes that all share the same architectural skeleton (BaseDomain + BaseNodeAdapter + ChildRouter + commands registry). The wiki should mirror that uniformity: a reader flips between nodes and finds the same 14 sections in the same order. Diagrams lead. Tables annotate. Prose only fills gaps. -Mermaid blocks lead. Tables annotate. Prose only fills gaps. +## Picking a visual -## Template — copy this whole file as the seed for each node's wiki +The default is Mermaid (Gitea renders it natively). It's the right tool for graph-shaped things — neighbours, lifecycles, state machines, file maps. But Mermaid doesn't render data: when a section is about *what a curve looks like* or *what the predicted vs measured signal does over time*, use: + +| Need | Tool | Where the artifact lives | +|---|---|---| +| Graph (nodes + edges, hierarchy, state) | Mermaid `flowchart` / `sequenceDiagram` / `stateDiagram-v2` | inline in the wiki page | +| XY data (pump curves, prediction trace, drift over time) | Generated PNG/SVG via a small `npm run wiki:plots` script | committed under `wiki/_partial-plots//*.svg` | +| Table of facts / config / topics | Markdown table | inline | +| Screenshot (dashboard, editor form) | PNG ≤ 200 KB | `wiki/_partial-screenshots//*.png` | +| ASCII layout (when Mermaid is overkill) | code block | inline | + +Lead with the visual that serves the section. Don't gate it on "is this Mermaid". + +## Section list + +Sections 1–9 and 11–14 are mandatory for every node. Section 10 (State chart) is mandatory for stateful nodes (`rotatingMachine`, `valve`, `pumpingStation`, …) and skipped for pure aggregators (`measurement`, `dashboardAPI`). + +| # | Section | Visual lead | Auto-gen? | +|---|---|---|---| +| 0 | Header band (git hash + regen date) | — | yes | +| 1 | What this node is | — (single paragraph) | no | +| 2 | Position in the platform | Mermaid `flowchart LR` | no | +| 3 | Capability matrix | table | no | +| 4 | Code map | Mermaid `flowchart TB` w/ subgraphs | no | +| 5 | Topic contract | table | **yes** (`wiki:contract`) | +| 6 | Child registration | Mermaid + table | no | +| 7 | Lifecycle | Mermaid `sequenceDiagram` | no | +| 8 | Data model — `getOutput()` | table + concrete sample | **yes** (`wiki:datamodel`) | +| 9 | Configuration — form ↔ config | Mermaid `flowchart TB` | no | +| 10 | State chart (stateful only) | Mermaid `stateDiagram-v2` | no | +| 11 | Examples | table + screenshots | no | +| 12 | Debug recipes | table | no | +| 13 | When NOT to use this node | bullets | no | +| 14 | Known limitations | table | no | + +## Template — copy the block below as the seed for each node's wiki + +(The block uses standard markdown syntax. The outer fence below is for visual delimitation in this README only; when seeding a new wiki page, copy the *content* between the `BEGIN TEMPLATE` / `END TEMPLATE` markers verbatim.) + +``` + -```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." +> **Reflects code as of `` · regenerated `` via `npm run wiki:all`** +> If this banner is stale, the page may be out of date. Treat as informative, not authoritative. -## 1. Position in the platform +## 1. What this node is -```mermaid +One paragraph, ≤ 60 words. Plain English. State the *role*, not the *implementation*. + +> Example: "**rotatingMachine** models a single pump or compressor. It takes pressure measurements from upstream and downstream, predicts the resulting flow + power from supplier-provided characteristic curves, and drives a state machine for startup/shutdown sequences. Used as a child of `machineGroupControl` when grouped, or directly under a `pumpingStation`." + +## 2. Position in the platform + +~~~mermaid flowchart LR - parent[] -->|set.demand| this[] + parent[machineGroupControl
Unit]:::unit -->|set.demand| this[rotatingMachine
Equipment]:::equip this -->|evt.state-change| parent - sensor[] -->|data.flow| this + sensor_up[measurement up]:::ctrl -->|data.pressure| this + sensor_dn[measurement down]:::ctrl -->|data.pressure| 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 -``` + classDef unit fill:#50a8d9,color:#000 + classDef equip fill:#86bbdd,color:#000 + classDef ctrl fill:#a9daee,color:#000 +~~~ -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`. +S88 colours are mandatory. Map: Process Cell `#0c99d9`, Unit `#50a8d9`, Equipment `#86bbdd`, Control Module `#a9daee`. Source of truth: `.claude/rules/node-red-flow-layout.md`. -## 2. Capability matrix +## 3. Capability matrix | Capability | Status | Notes | |---|---|---| @@ -50,54 +85,141 @@ Equipment / Control Module). Match the colour codes from | 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 | +| Supports multi-parent registration | ⚠️ | Possible but not fully tested — see CONTRACT.md | -Keep this table to ≤ 10 rows. For longer feature inventories, link out. +Cap at 10 rows. Longer inventories link out. -## 3. Topic contract +## 4. Code map -> Auto-generated from `src/commands/index.js`. Do NOT hand-edit. -> Re-run `npm run wiki:contract` after any change to commands. +~~~mermaid +flowchart TB + subgraph nodeRED["nodeClass.js — adapter (BaseNodeAdapter)"] + nc["buildDomainConfig()
static DomainClass, commands"] + end + subgraph domain["specificClass.js — orchestrator (BaseDomain)"] + sc["Machine.configure()
declares ChildRouter rules"] + end + subgraph concerns["src/ concern modules"] + curves["curves/
characteristic curve loader"] + prediction["prediction/
flow + power predictor"] + drift["drift/
prediction-vs-measured assessor"] + flow["flow/
aggregation + smoothing"] + state["state/
FSM transitions"] + io["io/
output formatting helpers"] + display["display/
status badge composition"] + end + nc --> sc + sc --> concerns +~~~ + +| Module | Owns | Read first if you're changing… | +|---|---|---| +| `curves/` | Supplier characteristic curves, interpolation | Curve fitting, asset selection | +| `prediction/` | Flow + power predictors | Predicted output values | +| `drift/` | Quality of prediction vs measurement | Health status / alarms | +| `flow/` | Aggregation, smoothing | Flow reporting | +| `state/` | FSM (off → idle → operational → …) | Startup / shutdown behaviour | + +Update this section when you rename or split a directory. + +## 5. Topic contract + +> **Auto-generated** from `src/commands/index.js`. Do NOT hand-edit between the markers. Re-run `npm run wiki:contract`. + + | 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). | -| ... | ... | ... | ... | +| `set.mode` | `setMode` | `string` (`auto`\|`manual`\|`maintenance`) | Switches operating mode. | +| `cmd.startup` | `execSequence` (with `payload.action='startup'`) | `{source: string}` | Triggers startup sequence. | -## 4. Lifecycle — what one tick (or event) does + -```mermaid +## 6. Child registration + +What children this node accepts and what it does with each event the child can emit. Mirrors the `ChildRouter` declarations in `specificClass.js` → `configure()`. + +~~~mermaid +flowchart LR + subgraph kids["accepted children (softwareType)"] + m_up["measurement
type=pressure
position=upstream"]:::ctrl + m_dn["measurement
type=pressure
position=downstream"]:::ctrl + end + m_up -->|data.pressure| handler1[pressure handler
updates measurements/upstream] + m_dn -->|data.pressure| handler2[pressure handler
updates measurements/downstream] + handler1 --> recompute[prediction.recompute] + handler2 --> recompute + recompute --> emit[emitter.emit 'output-changed'] + classDef ctrl fill:#a9daee,color:#000 +~~~ + +| softwareType | filter | wired to | side-effect | +|---|---|---|---| +| `measurement` | `type=pressure, position=upstream` | `pressureHandlers.onUpstream` | prediction recomputes | +| `measurement` | `type=pressure, position=downstream` | `pressureHandlers.onDownstream` | prediction recomputes | + +## 7. Lifecycle — what one event (or tick) 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 + sensor->>node: data.pressure (3.4 bar, upstream) + node->>node: ChildRouter → pressure handler + node->>node: prediction recomputes + node->>node: drift assesses prediction vs measured + 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) -``` + node->>node: state.handleInput → maybe transition +~~~ -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. +One screen max. For multiple distinct flows (idle vs running vs error), pick the most common and link out to the rest. -## 5. Configuration — editor form & where each field lands +## 8. Data model — `getOutput()` -```mermaid +What lands on Port 0. Composed in domain `getOutput()`, then delta-compressed by `outputUtils.formatMsg`. + +**Abstract schema** (always include): + + + +| Key | Type | Unit | Source | +|---|---|---|---| +| `...` | number | per `UnitPolicy.output(type)` | MeasurementContainer | +| `state` | string | — | `state/` | +| `predictionHealth.level` | 0–3 | — | `drift/` | +| `predictionHealth.flags` | string[] | — | `drift/` | + + + +**Concrete sample** (include only when the *shape* is hard to grok from the schema — e.g. nested objects, sparse keys, or unit conventions a newcomer would get wrong): + +~~~json +{ + "flow.measured.downstream.default": 12.4, + "pressure.measured.upstream.default": 3.4, + "power.measured.atequipment.default": 18.2, + "state": "operational", + "predictionHealth": { "level": 1, "flags": ["pressure_init_warming"], "message": "warmup phase", "source": "rotatingMachine#pump-A" } +} +~~~ + +Concrete samples must come from a known-good test run — never made-up values. Regenerate when concern modules change shape. + +## 9. Configuration — editor form ↔ config keys + +~~~mermaid flowchart TB subgraph editor["Node-RED editor form"] - f1[Mode] - f2[Demand] - f3[Threshold percent] + f1[Mode dropdown] + f2[Demand input] + f3[Threshold %] end - subgraph config["Domain config"] + subgraph config["Domain config slice"] c1[control.mode] c2[control.targets.demand] c3[safety.thresholdPercent] @@ -105,28 +227,17 @@ flowchart TB 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 | +| Form field | Config key | Default | Range | Where used | +|---|---|---|---|---| +| Mode | `control.mode` | `auto` | enum | `control/strategies.js` | +| Demand | `control.targets.demand` | `0` | ≥ 0 | `dispatch/` | +| Threshold % | `safety.thresholdPercent` | `95` | 0–100 | `safety/guards.js` | -## 6. Examples +## 10. State chart (stateful nodes only) -| 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 +~~~mermaid stateDiagram-v2 [*] --> off off --> idle: cmd.startup @@ -136,78 +247,100 @@ stateDiagram-v2 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). +Skip this section for stateless nodes (`measurement`, `dashboardAPI`). -## 8. When you would NOT use this node +## 11. Examples -- "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." +| Tier | File | What it shows | Mandatory? | +|---|---|---|---| +| Basic | `examples/01-Basic.json` | Inject + dashboard, no parent | ✅ | +| Integration | `examples/02-Integration.json` | Wired to `` + 1 child | ✅ if has parent | +| Dashboard | `examples/03-Dashboard.json` | Live FlowFuse charts | ⭕ optional | -Two or three bullets, each one sentence. Forces explicit non-goals. +One screenshot per tier where helpful. PNG ≤ 200 KB under `wiki/_partial-screenshots//`. Docker compose snippet under `examples/README.md`. -## 9. Known limitations / current issues +## 12. Debug recipes + +How to diagnose the common failure modes. One table row per recipe. + +| Symptom | First thing to check | Where to look | +|---|---|---| +| Status badge stuck on `⚠ no input` | Did the measurement child register? Watch Port 2. | Editor debug tap on Port 2 | +| `flow.measured.downstream` not updating | Confirm the child's emitted topic matches the `ChildRouter` filter. | `specificClass.js` → `configure()` | +| Prediction `level=3` | Run `enableLog: 'debug'` *temporarily*; look for drift evaluator output. | container log | + +> Never ship `enableLog: 'debug'` in a demo — fills the container log within seconds and obscures real errors. Use only for live debugging. + +## 13. When you would NOT use this node + +Two or three bullets, one sentence each. Forces explicit non-goals. + +- Use rotatingMachine for a **single** pump. For groups of 2+ pumps with load sharing, use `machineGroupControl` as the parent. +- Don't use rotatingMachine to model a passive non-return valve — use `valve` (no curve, no FSM-driven motor). + +## 14. 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 | +| 1 | Drift confidence drops to 0 when pressure missing > 30 s | `.claude/refactor/OPEN_QUESTIONS.md` | +| 2 | Multi-parent teardown ordering | Gitea issue #42 | -Link to repo issues when they exist. Keep this table living — it's the -contract with the user about what "works". +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). +1. Section 2 (Position in the platform) appears **before any prose**. Diagrams lead. +2. Every section opens with a diagram, table, or chart. Prose annotates the visual; never the other way round. +3. **Max 60 words per paragraph.** A paragraph longer than that splits into bullets or moves into a table. +4. The topic contract (section 5) and data-model schema (section 8) are **auto-generated** between the `BEGIN AUTOGEN` / `END AUTOGEN` markers. Don't hand-edit between markers. +5. Mermaid is the default for graph structures. Use generated SVG/PNG for XY data (curves, time series). Use tables for facts. +6. Skip `classDiagram` (we don't expose classes to users) and `gantt` (no schedules in node docs). +7. **Concrete sample payloads must come from a known-good test run.** Made-up numbers rot silently. +8. S88 colour codes are non-negotiable in section 2. Match the palette in `.claude/rules/node-red-flow-layout.md`. -## Auto-generation notes (Phase 9 follow-up) +## Archive banner — paste at the top of every archived page -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)); +``` +> **⚠️ ARCHIVED — pre-refactor (Tier 1–4, 2026-05)** +> +> This page describes the architecture before the platform refactor. +> The current page is **[](../)**. +> +> Kept for historical reference only. **Do not update.** ``` -`describeSchema` walks the lightweight schema (`{type, properties}`) -and produces a one-line readable form. Wire each node's `package.json`: +Archived pages move to `Archive/-pre-refactor.md` in the Gitea wiki repo. After moving, the page is read-only — corrections go on the current page, not the archive. + +## Auto-generation — Phase 9 follow-up + +Two scripts per node, wired in `package.json`: ```json "scripts": { - "wiki:contract": "node scripts/generate-contract.js > wiki/_partial-topics.md" + "wiki:contract": "node scripts/generate-contract.js > wiki/_partial-topics.md", + "wiki:datamodel": "node scripts/generate-datamodel.js > wiki/_partial-datamodel.md", + "wiki:all": "npm run wiki:contract && npm run wiki:datamodel" } ``` -Then a thin wiki page `.md` includes `_partial-topics.md` (or -the section is regenerated in-place between markers). +- **`generate-contract.js`** walks `src/commands/index.js`, emits one table row per descriptor between the topic-contract markers. +- **`generate-datamodel.js`** instantiates the domain with the default config, calls `getOutput()`, emits the abstract schema between the datamodel-schema markers. If `wiki/sample-output.fixture.json` exists, the concrete-sample block below the markers is also overwritten. +- `describeSchema` walks the lightweight `{type, properties}` schema and produces a one-line readable form. -## What lives in the gitea wiki vs the repo +## What lives where -- `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. +| Artifact | Location | Hand-edited? | +|---|---|---| +| Canonical page source | `wiki/.md` in the node's repo | Yes (except inside AUTOGEN markers) | +| Auto-generated partials | written inline between AUTOGEN markers | No — generated | +| Plots | `wiki/_partial-plots//*.svg` | No — generated | +| Screenshots | `wiki/_partial-screenshots//*.png` | Yes (committed) | +| Gitea wiki UI | mirror — re-rendered from `wiki/` on push | No | +| Archived pre-refactor pages | `Archive/-pre-refactor.md` in the wiki repo | No (read-only after archival) | + +The Gitea wiki repo is separate from each node's source repo. The `wiki/` directory in each node's repo is canonical; a `wiki-sync` workflow (not yet built) mirrors it into the Gitea wiki repo on each push to `development` / `main`.