Files
dashboardAPI/wiki/Reference-Limitations.md
znetsixe a9fc51d6f0 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>
2026-05-19 09:42:14 +02:00

11 KiB

Reference — Limitations

code-ref

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 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.jsdashboardAPI.js
  2. dashboardapi.htmldashboardAPI.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. 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. rotatingmachinerotatingMachine) requires either renaming the template file or adding an alias arm in _templateFileForSoftwareType. The machineGroupControl &rarr; 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:

- 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) &rarr; node._flow.getNode(id) &rarr; 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.


Page Why
Home Intuitive overview
Reference — Contracts Topic + payload resolution + envelope shape
Reference — Architecture Code map, lifecycle, "no BaseNodeAdapter" rationale
Reference — Examples Shipped flows + debug recipes + working wiring patterns
EVOLV — Open Questions Cross-node open questions and decisions log