Files
generalFunctions/wiki/Reference-Limitations.md

218 lines
11 KiB
Markdown
Raw Normal View History

# Reference — Limitations
![code-ref](https://img.shields.io/badge/code--ref-48fa543-blue)
> [!NOTE]
> What `generalFunctions` does not do, current rough edges, stability/versioning rules, and open questions. For an intuitive overview, return to [Home](Home).
---
## When NOT to depend on this library
- **Passive HTTP gateway nodes** (e.g. `dashboardAPI`) may skip `BaseDomain` and `BaseNodeAdapter` entirely if they hold no domain state. A plain Node-RED node with HTTP endpoints needs only `logger`, `outputUtils`, and `configManager`. See the `dashboardAPI` wiki for the rationale.
- **External scripts or standalone tools** that need only unit conversion can import just `const { convert } = require('generalFunctions')` without pulling in the full domain stack.
- **Nodes at a different S88 level** that inherit from a third-party base class must not import from `src/domain/` or `src/nodered/` internal paths — they may only use root-level exports.
---
## Known limitations
### 1. `loadCurve` is deprecated
`loadCurve(modelId)` is kept as a thin shim over `assetResolver.resolve('curves', modelId)` so legacy consumers don't have to change in one go. New code should use `assetResolver` directly. Replacement `loadModel` exists but not every node has migrated.
- **Tracked in**: `OPEN_QUESTIONS.md` — Phase 8.5 cleanup.
### 2. `outlierDetection` (`DynamicClusterDeviation`) prints to `console.log`
The dynamic-cluster outlier detector emits diagnostic lines via `console.log` directly, bypassing the structured `logger`. This means its output cannot be silenced per-node and doesn't honour `logLevel`. Fix is routing through `logger` like the rest of the library.
- **Tracked in**: Code review backlog.
### 3. `configUtils.initConfig` silently strips unknown keys
When the user config carries a key that isn't in the schema, `configUtils.initConfig` (via `validationUtils.validateSchema`) silently drops it. This means a typo in an editor field name or a missed schema entry results in the default value being used — with no error, no warning, no log line.
Workaround: the schema must include every key the domain reads, with a sensible default. The 2026-05-11 monster schema fix was a direct consequence of this gotcha.
- **Tracked in**: `OPEN_QUESTIONS.md` — e.g. monster schema fix.
### 4. `state` (FSM) and `predict` are not yet integrated with `BaseDomain` lifecycle
The state machine and the prediction class are exported but not lifecycle-managed by `BaseDomain`. Consumer nodes wire them manually in `configure()` — constructor, event subscriptions, teardown. A second wave of refactor work will move them under the `BaseDomain` umbrella so subclasses get them for free.
- **Tracked in**: Architecture backlog.
### 5. `menuUtils` / `MenuManager` bypass the Node.js import path
These are served as browser JavaScript via the admin `endpointUtils` and run in the Node-RED editor's iframe. Deep changes require testing in both environments (Node-side schema validation, browser-side editor form rendering). There is no automated test harness for the browser side.
- **Tracked in**: `endpointUtils.js` comments.
### 6. `CascadePIDController` has no dedicated test suite
`PIDController` is unit-tested; the cascade variant is not. Adding tests is on the backlog.
- **Tracked in**: Test backlog.
### 7. Wiki autogen is hand-maintained
The API surface section is hand-maintained between the `<!-- BEGIN/END AUTOGEN: api-surface -->` markers in `CONTRACT.md`. There is no `npm run wiki:all` script (yet); when an export is added or changed, the table must be edited by hand. Mitigation: the source-of-truth is the barrel (`index.js`); when in doubt, trust the barrel.
- **Tracked in**: Phase 9 follow-up.
### 8. Single-side pressure handling lives in consumers
Consumer-node concerns like single-side pressure degradation, residue handling, and sequence-abort semantics are NOT centralised in this library &mdash; each consumer (`rotatingMachine`, `valveGroupControl`, &hellip;) implements its own variant. Cross-node consistency is by convention, not by enforcement. A future `BaseDomain` extension could pull common pressure-routing patterns up.
- **Tracked in**: Internal architecture notes.
### 9. Asset registry backends are not fully symmetric
`FileBackend` is the production default (sync, in-process JSON). `HttpBackend` is provided for remote-resolver scenarios but has fewer call sites and less test coverage. If you switch to `HttpBackend` in production, expect to find edge-case differences.
- **Tracked in**: Internal &mdash; not yet ticketed.
### 10. No editor form
`generalFunctions` is never placed in a flow. It has no Node-RED type registration, no `.html`, no admin endpoint of its own. Consumer nodes expose their own editor forms; each form field writes into a config key that `configManager.buildConfig` validates against the node's schema in `src/configs/<nodeName>.json`. This is a deliberate design choice, not a limitation &mdash; documented here for visitors searching for "where's the editor form".
---
## Stability + versioning
Source of truth: [`.claude/rules/general-functions.md`](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/rules/general-functions.md) in the superproject.
| Category | Rule |
|:---|:---|
| **Safe to add** | New named exports. New optional methods on existing classes. New config keys with defaults in the schema. |
| **Requires decision-gate interview** | Removing or renaming any export. Changing a method signature. Changing the output key format of `MeasurementContainer.getFlattenedOutput()`. Changing the `formatMsg` delta-compression behaviour. |
| **Forbidden without migration** | Breaking the 4-segment key shape (`type.variant.position.childId`). Changing Port 0/1/2 payload envelope. Changing the [CONTRACTS.md](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/refactor/CONTRACTS.md) §1&ndash;§9 shapes. |
### Cross-node impact
`generalFunctions` is a git submodule shared by all 12 node repos. **Any change here can break any node.** Before modifying any module:
```bash
# Identify all consumers of the symbol you're touching.
grep -r "require('generalFunctions')" nodes/*/
# Or for a specific export:
grep -rn "BaseDomain\|UnitPolicy\|MeasurementContainer" nodes/*/src/
```
After changes, run the test suites of every affected consumer node, not just `generalFunctions/test/`.
### Canonical units
`MeasurementContainer` and all internal processing assume canonical units:
| Quantity | Canonical |
|:---|:---|
| Pressure | `Pa` |
| Flow | `m3/s` |
| Power | `W` |
| Temperature | `K` |
Unit conversion happens at system boundaries (input via `CommandRegistry.units` normalisation, output via `UnitPolicy.output` rendering) &mdash; never in core logic. Code that assumes anything else is a bug.
---
## Deprecations
| Symbol | Status | Replacement | Plan |
|:---|:---|:---|:---|
| `loadCurve(modelId)` | deprecated | `assetResolver.resolve('curves', modelId)` | Remove after every consumer migrates. Tracked in Phase 8.5. |
When a symbol is marked deprecated:
1. The row in `CONTRACT.md` flips to `deprecated` and gains a "removed-in" line.
2. Consumers in `nodes/*` are updated to the replacement.
3. Each touched node's submodule pin is bumped in the superproject.
4. After one release on `development` with no consumers, the export and its row are removed.
---
## Open questions (tracked)
| Question | Where it lives |
|:---|:---|
| Phase 8.5: complete `loadCurve` &rarr; `assetResolver` migration | Internal |
| Route `DynamicClusterDeviation` log lines through `logger` | Code review backlog |
| Surface a warning when `configUtils.initConfig` strips a key not in schema | `OPEN_QUESTIONS.md` |
| Move `state` (FSM) and `predict` under `BaseDomain` lifecycle | Architecture backlog |
| Browser-side test harness for `menuUtils` | `endpointUtils.js` |
| Test suite for `CascadePIDController` | Test backlog |
| Wiki autogen script (`npm run wiki:all`) for the API surface section | Phase 9 follow-up |
| `HttpBackend` test coverage parity with `FileBackend` | Internal |
| Centralised single-side-pressure handling pattern in `BaseDomain` | Internal architecture notes |
---
## Migration notes
### Pre-refactor: per-node `registerChild` switch
The `ChildRouter` replaces hand-written `registerChild(child)` methods. The mechanical migration:
```js
// Before:
registerChild(child) {
switch (child.softwareType) {
case 'measurement':
if (child.config.asset.type === 'pressure' && child.positionVsParent === 'upstream') {
this._onUpstream(child);
} else if (child.config.asset.type === 'flow') {
this._onFlow(child);
}
break;
case 'machinegroup':
this._onMgcChild(child);
break;
}
}
// After (in configure()):
this.router
.onMeasurement('measurement', { type: 'pressure', position: 'upstream' }, (data, child) => this._onUpstream(child))
.onMeasurement('measurement', { type: 'flow' }, (data, child) => this._onFlow(child))
.onRegister('machinegroup', (child) => this._onMgcChild(child));
```
Behaviour is identical (the underlying `childRegistrationUtils` calls are unchanged); the wiring is just declarative.
### Pre-refactor: per-node `getStatusBadge` duplication
The `statusBadge` pure-function helpers replaced 12 copies of slightly different status-text formatters. New domains should use `statusBadge.compose(parts, opts)`, `statusBadge.error(msg)`, `statusBadge.idle(label)` instead of building `{fill, shape, text}` by hand. Text is clipped to 60 chars to fit the Node-RED editor.
### Pre-AssetResolver: `loadCurve` shim
Old code:
```js
const { loadCurve } = require('generalFunctions');
const curve = loadCurve('SomeModel');
```
New code (preferred):
```js
const { assetResolver } = require('generalFunctions');
const curve = assetResolver.resolve('curves', 'SomeModel');
```
The shim still works, but the next API-surface review may remove it. Migrate when next touching the file.
---
## Related pages
| Page | Why |
|:---|:---|
| [Home](Home) | Intuitive overview |
| [Reference &mdash; Contracts](Reference-Contracts) | Full public API surface, per-export stability tags |
| [Reference &mdash; Architecture](Reference-Architecture) | Three-tier rule, `src/` layout, consumer responsibilities |
| [Reference &mdash; Examples](Reference-Examples) | Usage patterns: extending base classes, registering commands, declaring child routes |
| [Platform CONTRACTS.md](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/refactor/CONTRACTS.md) | The authoritative platform base-class + protocol spec |
| [`.claude/rules/general-functions.md`](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/.claude/rules/general-functions.md) | Stability + change-impact rules |