docs(wiki): full 5-page wiki matching the rotatingMachine reference format
Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
156
wiki/Reference-Limitations.md
Normal file
156
wiki/Reference-Limitations.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Reference — Limitations
|
||||
|
||||

|
||||
|
||||
> [!NOTE]
|
||||
> What `dashboardAPI` does not do, current rough edges, and open questions. Open items live in `.agents/improvements/IMPROVEMENTS_BACKLOG.md` and `.claude/refactor/OPEN_QUESTIONS.md` in the superproject.
|
||||
>
|
||||
> Pending full node review (2026-05). Content reflects `CONTRACT.md` and current source only.
|
||||
|
||||
---
|
||||
|
||||
## When you would not use this node
|
||||
|
||||
| Scenario | Use instead |
|
||||
|:---|:---|
|
||||
| You maintain Grafana dashboards by hand | Skip dashboardAPI — it will overwrite your customisations on every `child.register` (upsert is `overwrite: true`). |
|
||||
| You need arbitrary Grafana API calls (annotations, alerts, data sources, folders) | A plain `http request` node. dashboardAPI only emits `POST /api/dashboards/db` envelopes. |
|
||||
| You want to forward tick / measurement data to Grafana | This is not what dashboardAPI does. Wire telemetry through Port 1 of an EVOLV process node directly into InfluxDB; Grafana queries InfluxDB. |
|
||||
| You want to use dashboardAPI as a BaseDomain-capable child of something else | Not supported — dashboardAPI does not extend `BaseDomain` and cannot register as a child of `machineGroupControl` / `pumpingStation` / similar. See [No BaseNodeAdapter / BaseDomain](#no-basenodeadapter--basedomain) below. |
|
||||
| You expect EVOLV nodes to auto-discover dashboardAPI | They don't. Port 2 of the emitter must be wired into dashboardAPI's input explicitly. |
|
||||
|
||||
---
|
||||
|
||||
## Known limitations
|
||||
|
||||
### Legacy filename drift
|
||||
|
||||
The entry file and editor HTML are currently lowercase — `dashboardapi.js` and `dashboardapi.html` — rather than `dashboardAPI.js` / `dashboardAPI.html` per the canonical folder-name convention in `.claude/rules/node-architecture.md`.
|
||||
|
||||
The convention rule explicitly calls this out as legacy drift to fix when the file is next touched. A rename is a four-touch change:
|
||||
|
||||
1. `dashboardapi.js` → `dashboardAPI.js`
|
||||
2. `dashboardapi.html` → `dashboardAPI.html`
|
||||
3. `package.json#node-red.nodes` — key remains `dashboardapi` (the Node-RED type id is independent of the filename) but the value becomes `dashboardAPI.js`.
|
||||
4. Superproject submodule references and any `require()` paths.
|
||||
|
||||
The Node-RED **type id** (`dashboardapi`, lowercase, registered via `RED.nodes.registerType('dashboardapi', …)`) must stay `dashboardapi` to avoid breaking existing flows in the wild. The rename is purely the source-file path. Tracked.
|
||||
|
||||
### Example flow stubs
|
||||
|
||||
The three shipped flows (`basic.flow.json`, `integration.flow.json`, `edge.flow.json`) are placeholders. Their inject nodes don't fire a payload that matches the `child.register` resolver:
|
||||
|
||||
| File | Current behaviour | What's wrong |
|
||||
|:---|:---|:---|
|
||||
| `basic.flow.json` | Inject `topic: 'ping'` | Not `child.register`; registry silently drops. |
|
||||
| `integration.flow.json` | Inject `topic: 'registerChild'` with `payload: 'example-child-id'` (string) | The string id has no live Node-RED node behind it; `RED.nodes.getNode('example-child-id')` returns null; throws `'Missing or invalid child node'`. |
|
||||
| `edge.flow.json` | Inject `topic: 'doesNotExist'` | Works as a registry-coverage probe (silent drop is correct) but exercises nothing. |
|
||||
|
||||
Working wiring patterns are documented inline in [Reference — Examples](Reference-Examples#working-wiring-patterns). Replacement of the stubs is tracked in `IMPROVEMENTS_BACKLOG.md` (P9 wiki cleanup follow-up).
|
||||
|
||||
### No BaseNodeAdapter / BaseDomain
|
||||
|
||||
Most EVOLV nodes inherit a common adapter / domain base class. dashboardAPI does not. The decision is recorded in `OPEN_QUESTIONS.md` (2026-05-10) — four blockers (no platform config JSON, no periodic output, no parent registration, no status badge / tick / measurements). Until `BaseNodeAdapter` grows passive-mode flags (skip-registration + skip-output-stream), the bespoke adapter shape is the correct compromise.
|
||||
|
||||
Consequence: dashboardAPI cannot be introspected via the standard `getOutput()` channel. Debugging relies on watching Port 0 in a debug node.
|
||||
|
||||
### No domain output / no manifest
|
||||
|
||||
Per `.claude/rules/output-coverage.md`, every node should ship a `test/_output-manifest.md` enumerating every Port-0/1/2 key in populated and degraded states. dashboardAPI's output surface is **one envelope shape**, emitted only when a dashboard is successfully generated — there is no degraded "partial envelope" state to test. The manifest collapses to:
|
||||
|
||||
| Port | Output | Populated state | Degraded state |
|
||||
|:---|:---|:---|:---|
|
||||
| 0 | `{topic, url, method, headers, payload, meta}` envelope | Emitted once per generated dashboard | **Not emitted** — on resolution failure the handler throws and nodeClass sets a red status badge instead |
|
||||
| 1 | (unused) | — | — |
|
||||
| 2 | (unused) | — | — |
|
||||
|
||||
The full output-coverage rule applies prospectively; no backfill manifest exists yet. Tracked.
|
||||
|
||||
### Template discovery is filename-based
|
||||
|
||||
The template lookup is `softwareType` ↔ filename. Renaming a node's `softwareType` (e.g. `rotatingmachine` → `rotatingMachine`) requires either renaming the template file or adding an alias arm in `_templateFileForSoftwareType`. The `machineGroupControl → machineGroup.json` mapping is a one-off alias because the historical filename was abbreviated.
|
||||
|
||||
> [!NOTE]
|
||||
> Verify in full review: which softwareType does the current `rotatingMachine` emit? The shipped template is `config/machine.json` — if `rotatingMachine`'s `functionality.softwareType` is `'rotatingmachine'` (lowercase), the case-insensitive fallback won't find it and dashboard generation will warn-and-skip. Flagged.
|
||||
|
||||
### No retry / circuit-breaker on downstream HTTP
|
||||
|
||||
dashboardAPI emits the upsert envelope and is done. If the downstream `http request` node fails (Grafana down, 5xx, network timeout), the dashboard upsert is silently dropped — no retry, no DLQ, no status badge propagation back to dashboardAPI. The caller is responsible for wiring retry logic into the http-request path.
|
||||
|
||||
### `oneditsave` doesn't read all editor fields uniformly
|
||||
|
||||
`dashboardapi.html` `oneditsave` reads `['name', 'protocol', 'host', 'port', 'bearerToken', 'defaultBucket']` via direct DOM lookups, separately from the logger menu's `saveEditor`. Adding a new editor field requires touching both the form HTML and the `oneditsave` whitelist. Mild; not load-bearing.
|
||||
|
||||
### Config default mismatch
|
||||
|
||||
The runtime `_buildConfig` defaults `general.logging.enabled` to `Boolean(config?.general?.logging?.enabled)` — effectively `false` when the editor doesn't set it. But `dependencies/dashboardapi/dashboardapiConfig.json` declares the default as `true`. The editor menu (`loggerMenu`) bridges these via the standard EVOLV logger pattern, but the divergence is worth confirming — logger enabled vs disabled changes whether `Skipping dashboard generation: no template …` warns appear at all.
|
||||
|
||||
> [!NOTE]
|
||||
> Confirm in full review which side wins by default for a freshly-dropped node. Flagged.
|
||||
|
||||
### `bucket` resolution priority is global-then-per-position
|
||||
|
||||
`buildDashboard` reads `this.config.defaultBucket || this.config.bucketMap[position] || defaultBucketForPosition(position)`. The global override fires **before** the per-position map. If you want per-position buckets to win over a global default, the current code doesn't do that — you'd need to leave `defaultBucket` empty and rely solely on `bucketMap` + the position fallback.
|
||||
|
||||
Open question whether the "global beats per-position" priority is the intended semantics. Flagged.
|
||||
|
||||
### No InfluxDB bucket validation
|
||||
|
||||
The bucket name is templated into the Grafana dashboard JSON without any check that the bucket exists in InfluxDB. A typo produces a dashboard that renders panels saying "no data" with no upstream warning. Tracked.
|
||||
|
||||
---
|
||||
|
||||
## Open questions (tracked)
|
||||
|
||||
| Question | Where it lives |
|
||||
|:---|:---|
|
||||
| Should `BaseNodeAdapter` grow a passive / HTTP-only mode (skip-registration + skip-output-stream) so dashboardAPI can extend it? | `.claude/refactor/OPEN_QUESTIONS.md` (2026-05-10) — "dashboardAPI skipped BaseNodeAdapter + BaseDomain" |
|
||||
| Confirm `rotatingMachine` softwareType ↔ `config/machine.json` mapping | Internal — flag during full review |
|
||||
| Bucket priority: should per-position `bucketMap` beat global `defaultBucket`? | Internal |
|
||||
| Should dashboardAPI emit a Port-2 status / health pulse so other EVOLV nodes can detect it? | Internal |
|
||||
| Should `child.register` aliases include older topic names (e.g. `RegisterChild`, `register-child`) for legacy compat? | Internal |
|
||||
| Add an explicit `child.unregister` / `dashboard.delete` topic to remove orphaned Grafana dashboards | Internal |
|
||||
| Provide a programmatic way to bulk-regenerate all dashboards for an existing deployment (e.g. `cmd.regenerate-all`) | Internal |
|
||||
| Retry / DLQ for failed Grafana upserts | TBD |
|
||||
|
||||
---
|
||||
|
||||
## Migration notes
|
||||
|
||||
### From the `registerChild` alias
|
||||
|
||||
The canonical topic since 2026-Q1 is `child.register`. The `registerChild` alias still works but logs a one-time deprecation warning on first use. Migrate callers when convenient:
|
||||
|
||||
```diff
|
||||
- msg.topic = 'registerChild';
|
||||
+ msg.topic = 'child.register';
|
||||
```
|
||||
|
||||
Both topics accept identical payloads.
|
||||
|
||||
### From bare-string node-id payloads
|
||||
|
||||
The handler resolves bare-string payloads via `RED.nodes.getNode(id) → node._flow.getNode(id) → null`. This works at runtime but is brittle for tests and for flows where the emitter and dashboardAPI live on different `_flow` instances. Prefer the inline `{source: {config: {...}}}` or `{config: {...}}` shapes for tests and for any flow that imports both sides as JSON (no `RED.nodes` registry at compile time).
|
||||
|
||||
### From hand-curated Grafana dashboards
|
||||
|
||||
If you're moving from hand-curated dashboards to dashboardAPI-generated ones:
|
||||
|
||||
1. Export your existing dashboard JSON from Grafana.
|
||||
2. Replace the templating-var values for `measurement` and `bucket` with placeholders.
|
||||
3. Save as `nodes/dashboardAPI/config/<softwareType>.json`.
|
||||
4. The next `child.register` for that softwareType will upsert (overwrite) the existing dashboard, preserving the UID if you set it to match `stableUid(softwareType:nodeId)`.
|
||||
|
||||
If you want to **preserve the UID** of an existing hand-curated dashboard, compute `sha1(softwareType:nodeId).slice(0, 12)` and check it matches your existing UID. If not, either rename the node id, or accept that the first upsert will create a new dashboard alongside the old one.
|
||||
|
||||
---
|
||||
|
||||
## Related pages
|
||||
|
||||
| Page | Why |
|
||||
|:---|:---|
|
||||
| [Home](Home) | Intuitive overview |
|
||||
| [Reference — Contracts](Reference-Contracts) | Topic + payload resolution + envelope shape |
|
||||
| [Reference — Architecture](Reference-Architecture) | Code map, lifecycle, "no BaseNodeAdapter" rationale |
|
||||
| [Reference — Examples](Reference-Examples) | Shipped flows + debug recipes + working wiring patterns |
|
||||
| [EVOLV — Open Questions](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/refactor/OPEN_QUESTIONS.md) | Cross-node open questions and decisions log |
|
||||
Reference in New Issue
Block a user