All 11 nodes' wiki/Home.md regenerated with the Unit column +
per-topic descriptions. rotatingMachine + reactor private-method
test files rewritten to the public BaseNodeAdapter surface.
OPEN_QUESTIONS: rotatingMachine + reactor private-test entries
marked RESOLVED.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scripts/test-platform.js iterates each submodule, runs npm test, shows
a per-node pass/fail summary, exits non-zero if any node fails.
Wired as `npm run test:platform` in the parent package.json.
Submodule pointer bumps:
dashboardAPI 2874608 → 92d7eba (Mocha → node:test conversion for edge+integration)
diffuser 0ec9dd1 → 15cfb22 (P10.7a test script fix)
generalFunctions 8ebf31d → 95c5e68 (P10.7a test script fix + remove 5 broken Mocha dupes)
pumpingStation 52d3889 → d2384b1 (P10.7a test script fix)
Current platform-wide gate: 729 pass / 5 fail across 12 submodules
(5 failures are all pre-existing AssertionErrors logged in
OPEN_QUESTIONS.md for Phase 10.5).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pump-shutdown deadlock fix split across two submodules:
- rotatingMachine@8f9150e: shutdown sequence clears state.delayedMove
so the abort-and-return-to-operational path doesn't auto-pickup the
queued setpoint and re-engage the pump.
- machineGroupControl@ea2857f: turnOffAllMachines clears MGC's
_delayedCall and serializes per-pump shutdown so PS's 2 s tick loop
can't interrupt an in-flight shutdown.
Live verification on pumpingstation-complete-example demo: basin now
shuts pumps off at stopLevel cleanly, reverses to fill, completes the
hysteresis cycle.
Also disable the trends page in the demo flow (build_flow.py + regen
flow.json). FlowFuse ui-chart's per-series server-side history buffer
(7 charts × ~20 series × 3600-point retention) was saturating the
Node-RED event loop at 129% CPU, making the dashboard freeze on every
click. Trends remain available — just disabled by default; flip the
ui_page_trends "d" key to false to re-enable.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WARN now fires only when force-aborting an actually in-flight pump
movement (gate-bypass safety net), not on every no-op tick.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the _dispatchInFlight gate that mirrors rotatingMachine
state.delayedMove. Before this, PS at 1 Hz overran in-flight pump
ramps via concurrent handleInput entries, producing the live thrash:
120 aborts / 2 min, pump_b clamped at minFlow.
Includes regression test:
test/mgc-overactive-demand-serialization.integration.test.js
covering concurrent-burst serialization (30 calls → ≤ 5 aborts) and
latest-wins semantic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- nodes/machineGroupControl@69bdf11 makes DOWNSTREAM single-writer
(handlePressureChange = live aggregate; optimizer target moved to
AT_EQUIPMENT). Closes the ps-mgc-flow-contract failure.
- test/inflow-overcapacity-stability now starts the basin at maxLevel
so PS percControl is immediately 100 % (the actual storm condition)
and uses real-time waits between ticks so movementManager intervals
fire — the previous setImmediate yield was too fast for moves to
progress, making pumps look perma-parked even when behaviour was OK.
Park observations dropped from 83 to 3 across the sim window; final
ctrl converges to ~88 % across all 3 pumps.
All 82 cross-node + node integration tests now pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Submodule bumps land the deadlock fix (state.js residue unpark + MGC
optimalControl dispatch reorder) and pumpingStation stopLevel hysteresis.
- Renames examples/pumpingstation-3pumps-dashboard →
pumpingstation-complete-example with regenerated flow.json. New
dashboard groups, demand-broadcast wiring, S88 placement rule
applied, ui-chart trend-split and link-channel naming follow
.claude/rules/node-red-flow-layout.md.
- New cross-node test harness under test/: end-to-end-pumpingstation
drives PS + MGC + 3 pumps + physics simulator end-to-end and
verifies the ~5/15 min cycle.
- Adds Grafana provisioning dashboards (pumping-station.json) and a
helper sync-example.sh script for export/import to live Node-RED.
- Docker entrypoint + settings + compose tweaks for the persistent
user dir layout used by the demo.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- package.json: remove @tensorflow/tfjs and @tensorflow/tfjs-node.
Monster's TF code was already stripped; the deps were stale and kept
pulling a heavy native binary back into every install.
- .gitignore: ignore .repo-mem/ regenerable indexes and per-session
.claude/*.lock runtime files.
- CLAUDE.md: prepend READ-FIRST pointer to .claude/rules/repo-mem.md;
collapse the 'three outputs' bullet to a pointer at node-architecture.
- .claude/rules/telemetry.md: drop Port 0/1/2 duplication; reference
node-architecture.md.
- .claude/rules/testing.md: stop requiring a separate test/edge tier and
the basic/integration/edge example flow trio. Reflects what nodes
actually do.
- .claude/rules/repo-mem.md (new): when-to-call-which guide for the
per-repo memory MCP, anti-patterns, refresh model.
- .mcp.json (new): wire repo-mem stdio server.
- docs/DEVELOPER_GUIDE.md (new): step-by-step guide for adding a new
EVOLV node under the three-layer pattern.
- Bump nodes/pumpingStation to 6ab585b (docs + simulations refresh,
spill-flow path renames consistent with d8490aa).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pumpingStation: predicted-volume hard-floor at 0; spill flow refactored
from flow.predicted.out.<child=overflow> to its own position
flow.predicted.overflow. Drops the spillPrev self-subtraction. New
underflowVolume diagnostic for flow-balance errors. 70/70 tests pass.
generalFunctions: MeasurementContainer.get() strict-resolves explicit
.child(name) — missing named child now returns null instead of falling
through to a sibling. Persistent setChildId remains a hint (no
behavioural change for registered children).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Integrator now clamps predicted volume to [dryRunSafetyVol,
maxVolAtOverflow], records cumulative spill as overflowVolume and
exposes a synthetic flow.predicted.out.overflow rate so net flow
balances to ~0 while pinned. _selectBestNetFlow holds the last
level-rate net flow during overflow so dashboards keep a usable
reading. Top-level predictedOverflowVolume / predictedOverflowRate
fields added to getOutput.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- bounds.js sets HTML5 min/max on every level + percent input so the
spinner can't push values past the basin hierarchy.
- Basin-level violations now surface in a visible ribbon above the
basin diagram and block Deploy via oneditsave.
- Layout polish: widened side panel, tightened basin viewBox, dropped
mode-preview axis labels, moved datum below the tank.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- pumpingStation: hold-then-ramp shift hysteresis driven by
shiftArmPercent (% output threshold for arming) instead of by level.
New e2e integration test exercises the full fill→arm→hold→ramp-down
cycle. Editor preview gains the arming-% horizontal line.
- generalFunctions: add shiftArmPercent to the pumpingStation schema;
add prominent doc block on MeasurementContainer documenting the
`${type}.${variant}.${position}.${childId}` flatten format and the
implicit 'default' childId convention so dashboards don't drop it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- rotatingMachine@399e0a8: editor hygiene (name default, status
clear on close), remove redundant idle-position clamp in
flow/power predictions.
- machineGroupControl@9c79dac: bug fix — stale flow/power cache
now cleared on MGC shutdown so parent pumpingStation sees the
drop immediately. Also awaits shutdown promises correctly and
corrects the NCog integration tests to match centrifugal-pump
physics (Q/P monotonic → NCog=0 → fallback to equal distribution).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follows pumpingStation@3e13512 (rename eval/ → simulations/). The
decision log file is renamed to match the new folder name; an
addendum in the body explains that the rename was a naming
clarification, not a rationale change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four decisions recorded under .agents/decisions/ per project convention
(DECISION-YYYYMMDD-slug.md) to close the loop on today's pumpingStation
refactor + eval + docs work:
- wiki-in-code-repo — why docs+diagrams+code now live in one package
- 5-threshold-naming — old/new field mapping + breaking-change rationale
- mode-tier-template — Tier 1/2/3 classification for mode pages
- eval-harness — why eval/ exists alongside test/
Also bumps nodes/pumpingStation to 66fd3fe (eval harness + Tier 2/3
template pages).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follows pumpingStation@a218945 + generalFunctions@4252292 rename:
- Bump pumpingStation and generalFunctions submodule pointers.
- Update examples/pumpingstation-3pumps-dashboard/ (build_flow.py,
flow.json, README.md) to use the new threshold names. Collapsed
minFlowLevel into startLevel; reshuffled order to match the basin
bottom-to-top: minLevel, startLevel, maxLevel.
- wiki/manuals/README.md: drop the stale pumpingStation.md line and
point readers at pumpingStation/wiki instead (docs have moved into
the node's own repo).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
pumpingStation 5e2ebe4: overfill safety no longer shuts down machine
groups or blocks level control. Pumps keep running during overfill
(sewer can't stop receiving). Only upstream equipment is shut down.
Demo config: minHeightBasedOn=inlet (not outlet). The minimum height
reference for the basin is the inlet pipe elevation — sewage flows
in by gravity and the basin level can't go below the inlet without
the sewer backing up.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sinus inflow: 54-270 m³/h (base 0.015 + amplitude 0.06 m³/s), 4 min
period. Peak needs 1-2 pumps, never all 3 = realistic headroom.
PS control: continuous proportional demand when level > stopLevel, not
just when > startLevel && filling. Pumps now ramp down smoothly as
basin drains toward stopLevel instead of staying stuck at last setpoint.
pumpingStation e8dd657: dead zone elimination
build_flow.py: sinus tuned for gradual pump scaling visibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three fixes:
1. PS outflow triple-counted (pumpingStation c62d8bc): MGC registered
twice + individual pumps registered alongside MGC + dual event
subscription per child. Now: one registration per aggregation level,
one event per child. Volume integration tracks correctly.
2. All 3 pumps always on: minFlowLevel was 1.0 m but startLevel was
2.0 m, so at the moment pumps started the percControl was already
40% → MGC mapped to 356 m³/h → all 3 pumps. Fixed: minFlowLevel
= startLevel (2.0 m) so percControl starts at 0% and ramps
linearly. Now pumps graduate: 1-2 pumps at low level, 3 at high.
3. Generalizable registration rule added as code comments: when a group
aggregator exists (MGC), subscribe to it, not its children. Pick
one event name per measurement type per child.
E2E verified: 2/3 pumps active at 56% fill, volume draining correctly,
pump C at 5.2% ctrl delivering 99 m³/h while pump A stays off.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
generalFunctions 29b78a3 -> 086e5fe:
Schema default machineCurve.nq had a dummy pressure slice at key "1"
with fake data. Deep merge injected it alongside real curve data,
pulling the pressure-dimension spline negative at low pressures.
Fix: default to empty {nq: {}, np: {}}.
rotatingMachine 26e253d -> 510a423:
Tests updated for corrected fValues.min (70000 vs old 1).
Trace instrumentation removed. 91/91 green.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Architecture change: demo is now driven by a sinusoidal inflow into the
pumping station basin, rather than a random demand generator. The basin
fills from the sinus, and PS's levelbased control should start/stop
pumps via MGC when level crosses start/stop thresholds.
Changes:
- Demo Drivers tab: sinus generator (period 120s, base 0.005 + amp 0.03
m³/s) replaces the random demand. Sends q_in to PS via link channel.
- PS config: levelbased mode, 10 m³ basin, startLevel 1.2 m / stopLevel
0.6 m. Volume-based safeties on, time-based off.
- MGC scaling = normalized (was absolute) so PS's percent-based level
control maps correctly.
- Dashboard mode toggle now drives PS mode (levelbased ↔ manual) instead
of per-pump setMode. Slider sends Qd to PS (only effective in manual).
- PS code (committed separately): _controlLevelBased now calls
_applyMachineGroupLevelControl + new Qd topic + forwardDemandToChildren.
KNOWN ISSUE: Basin fills correctly (visible on dashboard), but pumps
don't start when level exceeds startLevel. Likely cause: _pickVariant
for 'level' in _controlLevelBased may not be resolving the predicted
level correctly, or the safetyController is interfering despite
time-threshold being 0. Needs source-level tracing of the PS tick →
_safetyController → _controlLogic → _controlLevelBased path with
logging enabled. To be debugged in the next session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each node repo now has a CLAUDE.md that declares its S88 hierarchy
level (Control Module / Equipment Module / Unit / Process Cell), the
associated S88 colour, and the placement lane per the superproject's
flow-layout rule set (.claude/rules/node-red-flow-layout.md).
The rule set lives in the superproject only (single source of truth).
Per-node repos reference it. When Claude Code opens a node repo, it
reads the local CLAUDE.md and knows which lane / colour / group to
use when building a multi-node demo or production flow.
Submodule pointer bumps for all 11 nodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>