- Delete .mcp.json + .claude/rules/repo-mem.md; drop .repo-mem from .gitignore - Remove repo-mem / substrate_score / repo_search references from all .md - Move 15 EVOLV skills from .agents/skills/ to .claude/skills/ so they are auto-discovered by the Claude Code harness and invokable via the Skill tool - Retire .agents/skills/evolv-orchestrator (duplicate of the subagent at .claude/agents/evolv-orchestrator.md); orchestrator lives as a subagent only - Drop OpenAI-format agent yaml metadata from each skill (not needed for CC) - Update CLAUDE.md, CONTRACTS.md, AGENTS.md to point at the new locations and disambiguate skills (.claude/skills/) vs subagents (.claude/agents/) - Fix CLAUDE.md tick-loop wording (opt-in per-node, not a fixed 1000ms) - Widen .claude/rules/ paths frontmatter so node-architecture and telemetry rules trigger on more relevant files; add frontmatter to flow-layout rule - Bump CONTRACTS.md review date to 2026-05-19; add step 7 to the contract- change workflow (review example flows when topic usage changes) - Bump nodes/generalFunctions pin (Home.md substrate_score reference removed) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
16 KiB
Task list — ARCHIVED
Warning
ARCHIVED — Phases 1–11 landed on
developmentin May 2026. This file is the original phased plan and is retained for history. For deferred / open work, see../OPEN_QUESTIONS.md. For current standards, start at../../../CONTRACTS.md(EVOLV root).
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 — seeCONTRACTS.md §1. Eachcommands/index.jsdeclares the canonical name astopicand lists pre-refactor names inaliases. 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:
- Bump submodule pointers in parent EVOLV
development. - Open a PR per submodule (
development→main). - Open the parent EVOLV PR last (
development→main). - Merge in dependency order (
generalFunctionsfirst, then nodes that depend on it, finallyEVOLV).
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 |
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. |
Phase 11 — unit-aware commands
Goal: every numeric setter / data topic carries an explicit unit; the user can supply any compatible unit and the commandRegistry normalises before the handler runs. Unknown units warn + list accepted alternatives.
Tasks
| # | Task | Notes |
|---|---|---|
| 11.1 | generalFunctions/src/convert/: add possibilities(measure) helper |
Returns the list of accepted unit names for a measure (volumeFlowRate, pressure, etc.). |
| 11.2 | generalFunctions/src/nodered/commandRegistry.js: handle descriptor.units |
Normalisation pipeline: extract value+unit from msg, validate against units.measure, convert to units.default, warn + fall back on bad input. Tests for all 4 paths (no-unit / valid / wrong-measure / unknown). |
| 11.3 | generalFunctions/src/nodered/BaseNodeAdapter.js: auto-wire query.units topic |
Returns { topic → { measure, default, accepted: [...] } } from the registry. No per-node wiring needed. |
| 11.4 | generalFunctions/scripts/wikiGen.js: render units column |
Topic-contract auto-gen table grows a Unit column showing measure (default <unit>). |
| 11.5 | Per-node src/commands/index.js: declare units on every numeric setter |
~10 nodes. See proposed default-units table in interview reply. |
| 11.6 | Regenerate every CONTRACT.md + wiki Home.md via npm run wiki:all |
Automated. |
| 11.7 | Tests: commandRegistry unit-handling paths | 4 scenarios per the validation table. |
Default units per topic (proposed)
| Topic | Default | Why |
|---|---|---|
pumpingStation set.inflow |
m3/h |
Operator-friendly scale |
pumpingStation set.demand |
m3/h |
same |
pumpingStation set.outflow |
m3/h |
symmetric |
pumpingStation cmd.calibrate.volume |
m3 |
basin volume |
pumpingStation cmd.calibrate.level |
m |
basin height |
MGC set.demand |
m3/h |
matches PS |
rotatingMachine set.setpoint |
% |
control% |
rotatingMachine set.flow-setpoint |
m3/h |
flow target |
rotatingMachine data.simulate-measurement |
per payload.type |
dispatch by sensor type |
valve set.position |
% |
valve open-% |
measurement data.measurement |
mode-dependent | analog → Channel scaling; digital → per-channel cfg |
monster data.flow |
m3/h |
already enforced |
reactor data.influent |
flow=m3/h, concentrations=mg/L | engine internals |
settler data.influent |
flow=m3/h, concentrations=mg/L | matches reactor |
diffuser data.flow |
m3/h |
air flow scale |