# Task list Phased and ordered. The TaskCreate tracker mirrors this list and is the active, mutable view; this file is the durable plan. A task is **done** when: - The code matches the contracts in `CONTRACTS.md`. - All the affected node's tests are green (`node --test test/basic test/integration test/edge`). - A short note is appended in the task tracker if anything was deferred to `OPEN_QUESTIONS.md`. ## Phase 1 — `generalFunctions` additive infra Goal: add the new platform pieces. Nothing is removed; nothing existing changes shape. All existing nodes continue to work unchanged. | # | Task | Notes | |---|---|---| | 1.1 | Add `src/domain/UnitPolicy.js` + tests | Extracted from `rotatingMachine._buildUnitPolicy`. | | 1.2 | Add `src/domain/ChildRouter.js` + tests | Built on existing `childRegistrationUtils`. | | 1.3 | Add `src/domain/LatestWinsGate.js` + tests | Extracted from MGC `_dispatchInFlight`/`_delayedCall`. | | 1.4 | Add `src/domain/HealthStatus.js` + tests | Standardise the `{level, flags, message, source}` shape. | | 1.5 | Add `src/domain/BaseDomain.js` + tests | Constructor boilerplate; calls subclass `configure()`/`_init()`. | | 1.6 | Add `src/nodered/commandRegistry.js` + tests | Topic dispatch + alias warnings. | | 1.7 | Add `src/nodered/statusBadge.js` + tests | `compose`, `error`, `idle`, `byState` helpers. | | 1.8 | Add `src/nodered/statusUpdater.js` + tests | 1 Hz poller calling `source.getStatusBadge()`. | | 1.9 | Add `src/nodered/BaseNodeAdapter.js` + tests | The thing every nodeClass extends. | | 1.10 | Add `src/stats/index.js` + tests | Promote mean/stdDev/median/mad/lerp from `measurement`. | | 1.11 | Update `generalFunctions/index.js` (additive) | New exports under existing pattern. | | 1.12 | Run all 12 nodes' tests against the bumped `generalFunctions` | Sanity gate before phase 2. | Phase-1 commit cadence: one commit per task on the `development` branch of `generalFunctions`. Submodule pointer in parent EVOLV bumps **once** at end of phase. ## Phase 2 — pumpingStation pilot Goal: prove the new infrastructure end-to-end. Pumping station is a mid-complexity node — bigger than measurement, smaller than the curve-driven nodes. | # | Task | Notes | |---|---|---| | 2.1 | Move standalone demo from `specificClass.js` to `examples/standalone-demo.js` | Pure deletion + move; tests unchanged. | | 2.2 | Extract `basin/` (BasinGeometry + thresholdValidator) | Pure functions. | | 2.3 | Extract `measurement/flowAggregator.js` (incl. `_updatePredictedVolume`) | Centerpiece of the tick loop. | | 2.4 | Extract `measurement/measurementRouter.js` + `measurement/calibration.js` | | | 2.5 | Extract `control/` strategies + dispatcher | levelBased, flowBased (stub), manual. | | 2.6 | Extract `safety/safetyController.js` | dryRunRule + overfillRule split internally. | | 2.7 | Add `getStatusBadge()` on `PumpingStation`; remove badge logic from nodeClass | | | 2.8 | Convert `nodeClass.js` to extend `BaseNodeAdapter` | | | 2.9 | Convert `specificClass.js` to extend `BaseDomain` | Use `ChildRouter`, `UnitPolicy`. | | 2.10 | Extract `commands/` registry + handlers | Old topic names become aliases. | | 2.11 | Extract `editor.js` from `pumpingStation.html` (the SVG redraw logic) | Served via a `/pumpingStation/editor.js` admin endpoint. | | 2.12 | Generate `CONTRACT.md` from `commands/` + handwritten events section | | | 2.13 | Tests: 3-tier per extracted module + the existing suite still green | Add edge tests for any regression discovered. | | 2.14 | Docker E2E (deploy `01-basic`/`02-integration`/`03-dashboard` flows on a running Node-RED) | Required for "trial-ready" claim. | ## Phase 3 — measurement | # | Task | Notes | |---|---|---| | 3.1 | Promote stats helpers to `generalFunctions/src/stats/` (already done in 1.10) | | | 3.2 | Convert analog mode to use `Channel` internally (with `key=null`) | Removes the ~400-line inline pipeline duplication. | | 3.3 | Extract `simulation/simulator.js` | | | 3.4 | Extract `calibration/calibrator.js` | | | 3.5 | Add `getStatusBadge()` on `Measurement` | | | 3.6 | Convert `nodeClass.js` to `BaseNodeAdapter`; `specificClass.js` to `BaseDomain` | | | 3.7 | Extract `commands/` | | | 3.8 | `CONTRACT.md` | | | 3.9 | Tests + Docker E2E | | ## Phase 4 — machineGroupControl | # | Task | Notes | |---|---|---| | 4.1 | Extract `groupOps/` (groupOperatingPoint + groupCurves) | The cluster of `_group*` helpers. | | 4.2 | Extract `totals/totalsCalculator.js` | | | 4.3 | Extract `combinatorics/pumpCombinations.js` | | | 4.4 | Extract `optimizer/bestCombination.js` + `optimizer/bepGravitation.js` | | | 4.5 | Extract `efficiency/groupEfficiency.js` | | | 4.6 | Extract `dispatch/demandDispatcher.js` using `LatestWinsGate` | Replaces `_dispatchInFlight`/`_delayedCall` directly. | | 4.7 | Add `getStatusBadge()` | | | 4.8 | Convert nodeClass + specificClass to base classes; use `ChildRouter` | | | 4.9 | `commands/` + `CONTRACT.md` | | | 4.10 | Tests + Docker E2E | | ## Phase 5 — rotatingMachine | # | Task | Notes | |---|---|---| | 5.1 | Extract `curves/` (loader + normalizer + reverseCurve) | | | 5.2 | Extract `prediction/` (predictors + groupPredictors + operatingPoint) | | | 5.3 | Extract `drift/` using `HealthStatus` | | | 5.4 | Extract `pressure/` (virtual children + initialization + router) | | | 5.5 | Extract `state/stateBindings.js` (adapter to existing `generalFunctions/state`) | | | 5.6 | Extract `measurement/measurementHandlers.js` | | | 5.7 | Extract `flow/flowController.js` | | | 5.8 | Extract `display/workingCurves.js` | | | 5.9 | Add `getStatusBadge()` (replaces the 100-line nodeClass version) | | | 5.10 | Convert nodeClass + specificClass | | | 5.11 | `commands/` + `CONTRACT.md` | | | 5.12 | Tests + Docker E2E | | ## Phase 6 — remaining nodes For each: skeleton refactor only — extend `BaseNodeAdapter` + `BaseDomain`, use `ChildRouter`, move the input switch to `commands/`, add `getStatusBadge()`. Domain-specific module split only if `specificClass` > 300 lines after the platform refactor. | # | Task | |---|---| | 6.1 | `valve` | | 6.2 | `valveGroupControl` | | 6.3 | `diffuser` | | 6.4 | `monster` | | 6.5 | `settler` | | 6.6 | `reactor` | | 6.7 | `dashboardAPI` (special — likely no `BaseDomain`, it's a passive HTTP server) | These are parallelisable — each can be its own agent. ## Phase 7 — remove legacy topic aliases > **Note:** canonical names (`set.*`, `cmd.*`, `data.*`, `child.*`, > `query.*`, `evt.*`) are used **from Phase 1 onwards** — see > `CONTRACTS.md §1`. Each `commands/index.js` declares the canonical > name as `topic` and lists pre-refactor names in `aliases`. So Phase 7 > is just the deprecation-window sweep. | # | Task | Notes | |---|---|---| | 7.1 | Audit aliases across all `commands/` files; confirm one release cycle has elapsed | If any alias was added recently, defer that node's removal another cycle. | | 7.2 | Remove `aliases` entries; canonical name only | Each removal is a single PR. | | 7.3 | Update example flows that still used legacy names | Should already have been updated in their phase. | | 7.4 | Document the removal in each `CONTRACT.md` | "Removed legacy topic X (replaced by canonical Y) on YYYY-MM-DD". | ## Phase 8 — promotion to main When every node is on the new infra and Docker E2E green: 1. Bump submodule pointers in parent EVOLV `development`. 2. Open a PR per submodule (`development` → `main`). 3. Open the parent EVOLV PR last (`development` → `main`). 4. Merge in dependency order (`generalFunctions` first, then nodes that depend on it, finally `EVOLV`). ## Phase 8.5 — `generalFunctions` deprecated path cleanup Removes the deprecated paths flagged in `OPEN_QUESTIONS.md`. Runs after promotion to `main` (so callers have stopped depending on the old paths via the platform's own consumers). ### Targets to remove | Path | Replaced by | First flagged | |---|---|---| | `src/helper/menuUtils_DEPRECATED.js` | `src/menu/` (the active menu manager) | pre-refactor | | `loadCurve` export (in `index.js` + `datasets/assetData/curves/`) | `loadModel` | pre-refactor | | Any `*_DEPRECATED.*` file added during the refactor | (per-file note) | refactor | ### Tasks | # | Task | Notes | |---|---|---| | 8.5.1 | Audit consumers of `loadCurve` across all nodes | Should be zero after Phase 5 (rotatingMachine) — verify. | | 8.5.2 | Remove `loadCurve` export + the underlying file | Single PR. Test all nodes. | | 8.5.3 | Remove `menuUtils_DEPRECATED.js` | Verify zero imports first. | | 8.5.4 | Sweep `generalFunctions/src/` for `_DEPRECATED.*` files; remove with consumer audit | One PR per file. | | 8.5.5 | Update `generalFunctions` README to drop deprecated references | | ## Phase 9 — wiki cleanup (post-refactor) Goal: each node's gitea wiki becomes **visual-first**, scannable, and follows one shared template. Today's wiki has lots of prose and varies per node — once the platform is uniform, the wiki should be too. Don't start phase 9 until phase 8 is done (the wiki documents the post-refactor shape, not the in-flight transition). ### Standard wiki template (one file per node, this is the spec) ``` 1. One-paragraph "what is this node" (≤ 60 words). 2. Position in the platform — a Mermaid block showing the node and its typical neighbours (parent + child types, with arrows for data direction). 3. Capability matrix — small table of "what this node can do" with ✅ / ❌ / partial. 4. Topic contract — auto-generated from src/commands/index.js (set.* / cmd.* / evt.* / data.* — payload schema and example). 5. Output payload — a Mermaid sequence-diagram of a typical tick (parent → child → measurement → tick → port-0 emit). 6. Configuration — a Mermaid block diagram of the editor form sections plus a table mapping each form field to the config key it lands at. 7. Examples — links to examples/01-basic, 02-integration, 03-dashboard with one screenshot each. 8. State / mode chart — Mermaid stateDiagram for any node with non-trivial states (rotatingMachine, pumpingStation, MGC). 9. "When you would NOT use this node" — explicit non-goals. 10. Issues / known limitations — single-line items with links to repo issues. ``` ### Tasks | # | Task | Notes | |---|---|---| | 9.1 | Author the canonical wiki template at `.claude/refactor/WIKI_TEMPLATE.md` (or the repo-mem rule path) | Source of truth. | | 9.2 | Build the auto-generator: `commands/index.js` → "Topic contract" markdown section | Run via a small `npm run wiki:contract` script per node. | | 9.3 | Pilot on `pumpingStation` wiki: replace existing pages with the new template | Visual-first, prune prose. | | 9.4 | Apply to other 3 core nodes (`measurement`, `MGC`, `rotatingMachine`) | | | 9.5 | Apply to remaining nodes (one per repo) | | | 9.6 | Update parent EVOLV wiki: top-level platform overview with a Mermaid block of all 13 nodes and how they connect (S88 hierarchy + data direction) | | | 9.7 | Add a wiki style guide (max prose per section, where Mermaid is required, screenshot conventions) | | | 9.8 | Audit pass: every page renders, every Mermaid block compiles, every link resolves | | ### Visual primitives we'll lean on (Mermaid) - `flowchart LR` — node connections (parent ↔ child, data direction). - `sequenceDiagram` — tick-to-port-0 lifecycle. - `stateDiagram-v2` — rotatingMachine / pumpingStation state machines. - `erDiagram` — only if a node has a complex internal data model worth visualising. Skip: classDiagram (we don't expose classes to users); gantt (no schedules in a node's docs). ### Hard rules - Every page leads with the Mermaid platform-position block. No "intro paragraph then later a diagram" — diagram first. - Each section opens with the diagram or table; prose annotates the visual, not the other way round. - No more than 60 words of unbroken prose anywhere on a page. - One canonical source of truth for the topic contract: `commands/index.js`. The wiki page is generated from it. No hand-written drift. ## Phase 10 — test-suite refactor (post-wiki) Goal: bring every node's test layout in line with `CONVENTIONS.md §Testing` now that the platform is uniform. Pre-existing test debt logged in `OPEN_QUESTIONS.md` gets cleaned up here. ### Tasks | # | Task | Notes | |---|---|---| | 10.1 | Audit each node: basic / integration / edge split, naming, helpers | One pass; produce a per-node punch list. | | 10.2 | Convert any Mocha-style tests (`describe`/`it`) to `node:test` | Specifically `dashboardAPI/test/basic/structure-module-load.basic.test.js`. | | 10.3 | Address `reactor` mathjs load (per OPEN_QUESTIONS): tree-shake or hoist | If hoisted, document the pattern as a CONVENTION addition. | | 10.4 | Promote shared test helpers to `generalFunctions/test/helpers/` | Common fakes: fake Node-RED node, fake child, fake RED. | | 10.5 | Add missing edge tests for each refactored module flagged during P2-P5 | Edge cases discovered during refactor land here. | | 10.6 | Make every basic-test runner exit cleanly in batch (`node --test test/basic/`) | No leaked timers, no real `setInterval` outliving the assertions. Mirrors the BaseNodeAdapter test fix. | | 10.7 | Standard CI shape: each node has `npm run test:basic`, `test:integration`, `test:edge` (consistent across nodes) | Allows uniform CI invocation. | | 10.8 | Audit pass: every node's test suite green in batch under one wall-clock budget (≤ 60 s for basic) | The new platform-wide gate. |