docs: standards cleanup — single front-door CONTRACTS.md + archive stale plan artifacts
Establish CONTRACTS.md at the EVOLV root as the canonical map of where every contract, rule, and standard lives. Surface it from CLAUDE.md so every fresh agent or colleague lands there first. Reshape .claude/refactor/ to reflect that the platform refactor is done: live standards stay at the top level; the plan artifacts (CONTINUE_HERE.md, TASKS.md) move into Archive/ with WARNING banners. Drop content that drifted out of date or duplicated the new standards stack: - docs/DEVELOPER_GUIDE.md (pre-refactor walkthrough; superseded by wiki/Architecture, wiki/Getting-Started, .claude/rules/node-architecture, .claude/refactor/MODULE_SPLIT + per-node CONTRACT.md + src/commands/). - .agents/decisions/ (15 DECISION files): load-bearing decisions belong in commit messages and PR descriptions; live open items in OPEN_QUESTIONS.md. - .agents/improvements/TOP10_*.md: moved to Archive/. Bump generalFunctions to 49c77f2 — adds CONTRACT.md inside the library: different shape from per-node CONTRACT.md files (library API, not msg.topic), with stability tags and pointers to .claude/refactor/CONTRACTS.md §N. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
299
.claude/refactor/Archive/TASKS.md
Normal file
299
.claude/refactor/Archive/TASKS.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# Task list — ARCHIVED
|
||||
|
||||
> [!WARNING]
|
||||
> **ARCHIVED — Phases 1–11 landed on `development` in May 2026.**
|
||||
> This file is the original phased plan and is retained for history. For
|
||||
> deferred / open work, see [`../OPEN_QUESTIONS.md`](../OPEN_QUESTIONS.md).
|
||||
> For current standards, start at [`../../../CONTRACTS.md`](../../../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** — 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. |
|
||||
|
||||
## 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 |
|
||||
Reference in New Issue
Block a user