Files
rotatingMachine/wiki/Reference-Limitations.md
znetsixe 5ea0b0bda6 feat(state): honor sequenceAbortToken so external aborts cleanly break sequences
Consumer half of the abort-token mechanism added in generalFunctions
state.js. executeSequence captures host.state.sequenceAbortToken at
entry, then re-checks before every state transition and after the
optional ramp-down. If MGC (or any external caller) bumps the token
mid-sequence, the loop bails out cleanly — no more barge-through where
a pre-empted shutdown advances through stopping → coolingdown after a
fresh demand has already engaged the pump.

Without this the MGC rendezvous planner can't reliably re-dispatch a
pump that's mid-shutdown: the new flowmovement claims the gate, but
the old shutdown's for-loop keeps running on microtasks and steps the
FSM into idle/off underneath it.

Also: wiki regen following the same visual-first 14-section template as
the other EVOLV nodes — Reference-{Architecture,Contracts,Examples,
Limitations}.md split with _Sidebar.md index.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 19:44:48 +02:00

106 lines
6.9 KiB
Markdown

# Reference &mdash; Limitations
![code-ref](https://img.shields.io/badge/code--ref-394a972-blue)
> [!NOTE]
> What `rotatingMachine` does not do, current rough edges, and open questions. Open items live in `.agents/improvements/IMPROVEMENTS_BACKLOG.md` in the superproject.
---
## When you would not use this node
| Scenario | Use instead |
|:---|:---|
| A passive non-return / check valve (no motor) | `valve` &mdash; no curve, no FSM-driven motor. |
| A valve actuator (motorised, no characteristic curve) | `valve` (and `valveGroupControl` if grouped). |
| A group of 2&nbsp;+ pumps load-sharing on a header | `machineGroupControl` &mdash; instantiate this as a child. |
| A curve-less asset | Predictions degrade to zero, drift becomes meaningless, status badge falls into `predictionQuality: 'invalid'`. There is no fallback model. |
| A compressor with significant gas compressibility | Predictor uses an incompressible-flow curve; output is qualitatively right but quantitatively biased. Tracked. |
---
## Known limitations
### Single-side pressure degrades silently
`pressureSelector.getMeasuredPressure` accepts only-upstream or only-downstream readings as a fallback when the differential is unknown. It logs a warn (`Using downstream pressure only for prediction: …. Prediction accuracy is degraded; inject upstream pressure too.`) but proceeds. The predictor uses the absolute pressure as a surrogate differential, which can materially bias flow predictions under varying suction conditions. The warn is one-shot per state transition, not per tick &mdash; it can be missed in long-running deployments. Tracked.
### Multi-parent registration
`childRegistrationUtils` accepts registration under multiple parents. The pump emits child-register messages to each, and parents listen in parallel. Teardown ordering (parent gone first vs pump gone first) is not test-covered; observed behaviour in production is "fine, mostly". If you wire one pump to two MGCs and remove one MGC mid-deployment, the pump's listener set may keep a stale reference. Open question.
### `data.simulate-measurement` doesn't clear stale values
If you toggle a virtual pressure off (stop sending the inject), the last-known value persists in the MeasurementContainer. There is no TTL and no explicit clear topic. Workaround: send `value: null` or `0` explicitly. Tracked.
### `execSequence` legacy umbrella
The `execSequence` topic (with `payload.action = "startup" | "shutdown"`) is kept alive for legacy flows. The handler demuxes to the canonical topic; both emit a one-time deprecation warning. Scheduled for removal in a later phase. Use `cmd.startup` / `cmd.shutdown` instead.
### Drift confidence collapses on long pressure-source outages
`predictionHealth.refresh` reduces `predictionConfidence` to 0 when no pressure source has produced a reading in &gt; 30 s. The quality string flips to `invalid` &mdash; downstream consumers should treat this as "predictor is offline, ignore values" rather than "predictor is broken". The recovery is automatic: as soon as a pressure measurement lands, health climbs back. Open question whether to model this as a discrete "stale" quality state instead.
### `state` stays in residue after a routine abort
`abortCurrentMovement` with default options (the kind MGC fires) does **not** auto-transition the FSM back to `operational`. The pump stays parked in `accelerating` / `decelerating` until the next `moveTo` arrives &mdash; at which point the residue handler in `state.moveTo` runs the transition synchronously. By design (a previous version auto-transitioned and created a bounce loop where every tick aborted, returned, re-moved, aborted again). See the comment in `state.js` `moveTo` line 76 for the historical detail.
### Editor cosmetics don't reflect `asset` derivation
The editor form still has visual sections for supplier / category / type even though the registry derives them. They're read-only and informational; some fields render as blank until you select a model. Cosmetic; the registry is the source of truth.
---
## Open questions (tracked)
| Question | Where it lives |
|:---|:---|
| Should the predictor use an explicit "stale" quality state instead of collapsing to `invalid` when pressure data dries up? | Internal &mdash; not yet ticketed |
| Multi-parent teardown ordering | Internal |
| Add an explicit `data.clear-simulated-measurement` topic for sim cleanup | Internal |
| Compressor / gas-flow curve handling | Internal (long-term) |
| Phase 7 removal of `execSequence` umbrella + legacy aliases | Internal |
| Curve loader robustness: warn / refuse mismatched curve units instead of best-effort normalising | `OPEN_QUESTIONS.md` (rotatingMachine entry) |
---
## Migration notes
### From pre-AssetResolver
Old flows saved with `supplier`, `category`, or `assetType` fields will throw on deploy:
```
rotatingMachine: legacy asset field(s) [supplier, category] are saved on this node.
After the AssetResolver refactor these are derived from the model id.
Open the node in the editor, re-select the model, and save to migrate.
```
The fix is mechanical: open each rotatingMachine node, re-pick the model from the asset menu, save. No data is lost &mdash; the registry has the same supplier / category / type the old flow carried.
### From pre-sequence-abort-token
Before 2026-05-15 a mid-decel re-engage was a race &mdash; sometimes the shutdown's for-loop won and parked the pump at `idle` with an orphaned `delayedMove`. With the `sequenceAbortToken` mechanism in `state.js` + `sequenceController.js` (from `394a972` onward), the new-dispatch's `abortCurrentMovement` always wins: the shutdown's for-loop breaks out before its next transition.
If you have an integration test that relied on the older "shutdown always completes" behaviour, expect to see `Sequence 'shutdown' interrupted ... by external abort` warnings instead. That's the intended new state.
### From `setpoint` topic name (pre-canonical)
The old `setpoint` topic without a `set.` prefix has been retired. Use `set.setpoint` (alias `execMovement`) for control-% setpoints and `set.flow-setpoint` (alias `flowMovement`) for flow setpoints.
### From `execMovement` payload shape change
Legacy payloads were `{source, action: "execMovement", setpoint: number}`. The current shape is the same minus `action` (the handler dispatches via topic). Both are accepted.
---
## Related pages
| Page | Why |
|:---|:---|
| [Home](Home) | Intuitive overview |
| [Reference &mdash; Contracts](Reference-Contracts) | Topic + config + child filters (alias map at the end) |
| [Reference &mdash; Architecture](Reference-Architecture) | Code map, FSM (including sequence-abort token), prediction + drift |
| [Reference &mdash; Examples](Reference-Examples) | Shipped flows + debug recipes |
| [machineGroupControl &mdash; Limitations](https://gitea.wbd-rd.nl/RnD/machineGroupControl/wiki/Reference-Limitations) | Where the parent's planner currently bypasses priority mode |