# Reference &mdash; 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 &mdash; 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` &mdash; 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 &mdash; 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` &mdash; 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()` &mdash; 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 |
