Larger margins ensure the size-14 rim and floor captions never overlap
the topmost or bottommost threshold line in the tank.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lines now have a minimum 3.7% gap so labels never collide with adjacent
threshold lines, regardless of how close the underlying levels are.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Canvas elements now use 'constraint: { horizontal: scale, vertical: scale }'
with percentage-based margin placement so the tank fills the card edge to
edge and stays centered as the panel resizes. Threshold labels split
left/right with a gap and at font size 14 for readability.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tank vertically centered in canvas frame. Labels for thresholds at the
very bottom of the tank (small dryRunThresholdPercent) no longer extend
below the visible card area.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Threshold labels now sit above or below their lines (never on top) and
are centered horizontally inside the tank.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds .claude/settings.json with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
so every contributor gets the `team` keyword + TeamCreate tool on clone,
without each person having to set the env var locally.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Canvas frame stretched vertically to match the card's aspect ratio so
the tank visual fills the entire card height with no letterboxing below.
Redundant in-canvas readouts dropped.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tank Layout visual now fills the Canvas card edge-to-edge. Each
threshold's name + value live INSIDE the tank near its line instead of
in external label columns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Canvas card shrunk to w:6 and frame to 400 px so the basin visual fills
the card edge-to-edge. Level/Volume timeseries widen to w:14 to absorb
the freed columns. Right value labels and bottom readouts no longer clip.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tank Layout canvas + bar gauge + Level/Volume timeseries grow to h:20
so the basin visual occupies more vertical space and reads at a glance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces Heights/Volume-Limits/Fill% stats with an integrated basin visual:
vertical bar gauge bound to live level + threshold markers, plus Canvas
showing tank zones, threshold lines, named labels, and live readouts.
Level + Volume timeseries reflow next to the basin in the renamed Basin row.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- machineGroupControl f18f3cc: fn_chart_pump_a/b/c emit -1 OFF sentinel on the
per-pump % control chart when state is off/idle/maintenance; ui_chart_pumps_ctrl
ymin=-5; new per-pump-ctrl-fanout output-coverage test + manifest update.
- pumpingStation e041877: revert canonical flow to m³/s (platform convention),
keep output m³/h for dashboard parity. No demand smoothing/hysteresis — that
belongs in a dedicated intermediate node per design review.
Also cleaned stale InfluxDB series (out-of-tree): dropped "MGC Isolated" and
"MGC — Pump Group" measurements and the category="undefined" rows in
"Machine Group" (135,416 stale rows; live untagged data preserved).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
machineGroupControl 2af6c90, generalFunctions 5c091cd. Rendezvous lock verified
live on the isolated rig: clean monotonic 1→2 pump staging, no wait/hunt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Bumps nodes/dashboardAPI submodule to slice/34-walking-skeleton@7fdab73
(credentials block for bearer token, folderUid config field, basic tests).
- Pins grafana/grafana to 11.3.0 — legacy /api/dashboards/db is the
generator target; G12 K8s-style API is out of scope (PRD constraint).
Refs #34
Bumps machineGroupControl (e1e1977) and pumpingStation (ef07f2a) — example
dashboard JSON tweaks committed on each submodule's development branch.
Adds docs/research/ and docs/prd/ for the dashboardAPI v2 graph-aware Grafana
generator workflow (Gitea issues #32-#43). Ignores .prototypes/ — throwaway
spike code lives there per the /prototype skill.
Bumps:
- rotatingMachine 455f15d refactor: route unit conversions through UnitPolicy.convert
- pumpingStation 2d68a4f refactor + fix(level): UnitPolicy adoption, level-rate timestamp fix, integration test rewire
- machineGroupControl ddf2b07 refactor: _canonicalToOutputFlow + setDemand via UnitPolicy.convert, structure test rewire
- generalFunctions bc79de1 fix(influx): accept tagCode camelCase + emit positionVsParent tag
- measurement 36eaa2f test(edge): align with object-payload accept behaviour
The UnitPolicy bump finishes the §6 contract migration the refactor
plan named (drop _convertUnitValue / hardcoded m3/h<->m3/s scalars in
favour of policy.convert at every site).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the old 3-panel coresync-frost-demo.json with a 13-panel dashboard
designed for at-a-glance verification of CoreSync's compression behaviour.
Dashboard rebuild (docker/grafana/provisioning/dashboards/coresync-frost-demo.json):
- Header "How to read" text panel: definitions table + sanity checks so
every metric is line-of-sight to its Flux source.
- Scoreboard row (4 stats): raw samples / CoreSync knots / reduction % /
approx. bytes saved over the selected time range.
- Per-stream verification table: one row per CoreSync stream with raw,
knots, and reductionPct (gradient-coloured). Each line's math is
mentally checkable: raw × (1 − reductionPct/100) = knots.
- Signal-reconstruction overlays: flow (m³/h) and pressure (mbar)
rendered as a thin raw line plus fat red knot points so you can see
knots snap to the raw signal at direction changes. Fixes the previous
panels which mislabelled both as `flowm3h` regardless of units.
- Diagnostics row: per-stream knot-interarrival timeseries and a
full-math compression-health table (raw, knots, kept fraction with
gradient bar, savedPct with colour background).
Bumps coresync submodule to 21d77a8 which lands the FROST demo flow plus
the burst-window reducer fix that was driving cog/efficiency/SEC to ~0%
compression. Verified end-to-end on the live stack: headline reduction
went from 33% to 83%, broken streams from 0.6%-14% to 78%-93%.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Front-loads gap discovery before /grill-me by adding two skills:
research MOSTLY fans out Explore + WebSearch agents in parallel,
synthesizes findings into a brief, names open
unknowns explicitly (which become /prototype targets)
prototype MOSTLY builds a throwaway spike to test ONE falsifiable
assumption; code lives in .prototypes/ (gitignored),
never promoted; output is evidence — verdict, numbers,
observed behavior — that feeds /prd
Full chain now:
/research → /prototype → /grill-me → /prd → /prd-to-issues → /ship-it
Chain rationale: /research and /prototype surface knowledge gaps and falsify
risky assumptions while the cost of changing direction is still cheap; the
TOGETHER phases (grill-me, prd) lock down the contract; the AFK phase
(ship-it) only executes against contracts already on paper.
The chain is a default, not a mandate — README covers when to skip
upstream skills for small or stack-familiar work.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four workflow skills that take a feature from fuzzy idea to merged code.
Two human-in-the-loop phases (grill-me, prd), one mostly-together (prd-to-issues
files only on explicit 'create'), and one AFK (ship-it).
grill-me TOGETHER pressure-test the idea with hard interview questions
prd TOGETHER synthesize PRD; gaps stay explicit, not papered over
prd-to-issues MOSTLY thin vertical-slice issues with coverage matrix +
per-issue Slice check; self-audits before showing
ship-it AFK shell loop ships each slice end-to-end with one
commit per issue, status streams to terminal,
Ctrl-C-able, survives session close
Vertical-slice principle throughout: every issue cuts end-to-end through every
integration layer (no horizontal "do all the DB work first" issues). The
AFK loop only ships against acceptance criteria already locked in by the PRD
phase — autonomous code never runs against undefined contracts.
ship-it tracker support: gh (GitHub) and tea (Gitea). For this repo, set
SHIP_IT_TRUNK=development to override the main default.
See .claude/skills/README.md for the full how-to and a worked example.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PALETTE REDESIGN (2026-05-21)
Sidebar swatches switched from S88 level (all blue) to domain-hue per node.
Family hue = function (rotating=orange, valves=teal, biology=green/olive,
sampling=violet, sensor=amber, aeration=sky-blue, infrastructure=slate);
within a family, darker = higher S88 / "more controller-ish."
Editor-group rectangles in flow.json still follow S88 — only the
registerType colour changed.
Submodule bumps for palette: rotatingMachine, machineGroupControl,
pumpingStation, valve, valveGroupControl, reactor, settler, monster,
measurement, diffuser, dashboardAPI.
Docs touched:
- CLAUDE.md: palette swatch vs. editor-group bullets split out.
- .claude/rules/node-red-flow-layout.md: new §10.0 introduces the two
color systems, full 12-row palette table, and explicit warning not to
mix the two hexes.
- .claude/refactor/MODULE_SPLIT.md: per-node headers annotated with
both `group #XXX` and `palette #XXX`.
- .claude/refactor/WIKI_HOME_TEMPLATE.md + WIKI_TEMPLATE.md: clarify
Mermaid classDefs visualize hierarchy, not palette swatches.
- .claude/refactor/OPEN_QUESTIONS.md: dated decision entry with
rationale, file list, and follow-ups.
CORESYNC SUBMODULE (new)
nodes/coresync added pointing at https://gitea.wbd-rd.nl/RnD/coresync.
FROST/SensorThings handoff path — first version forwards FROST-ready HTTP
request messages on the dbase output; a downstream http-request node
performs the POST and feeds responses back on msg.topic = "frost.response".
Lazy stream resolver, latest-wins queue (keep first + latest, drop middle),
knot-emit on slope change, provenance preserved in Observation parameters.
- .gitmodules: add nodes/coresync entry.
- package.json: register coresync as a Node-RED node.
- generalFunctions bump: new frostFormatter + 4 node config schemas
expose the dbase format option.
- measurement bump: "frost" option added to dbaseOutputFormat dropdown
(plus the in-flight data.measurement unit-handling work).
- machineGroupControl bump: small editor compact-fields tweak alongside
the palette change.
- CORESYNC_FROST_INTERVIEW_HANDOFF.md added at root with interview state
(Q20 open: slope angle vs. relative delta comparison).
DASHBOARDAPI MODULE_NOT_FOUND FIX
package.json: dashboardapi entry path corrected to
nodes/dashboardAPI/dashboardAPI.js. Commit e04c4a1 renamed the files to
camelCase but missed package.json; on case-sensitive filesystems
(Linux/Docker, where the tarball lands) the require resolved to nothing
and the node showed MODULE_NOT_FOUND in the Node-RED palette.
MISC CLEANUP
- examples/README.md + examples/pumpingstation-complete-example/ removal
(build_flow.py, flow.json, README.md superseded by per-node examples).
- jest.config.js: in-progress tweak.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Submodule pointer:
- rotatingMachine @ 8c5822c
style(editor): drop fixed max-width on rotor SVG — let it fill the panel
Repo hygiene:
- Add .repo-mem/, .codex, CLAUDE.local.md to .gitignore. These are
per-developer Claude Code state (memory store, IDE marker, per-machine
conventions) that shouldn't ever land in the repo. .repo-mem alone is
hundreds of MB on disk.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The root EVOLV package was 175.8 MB because npm pack at the parent walks
the full file tree and IGNORES per-submodule .npmignore files. The
.gitignore fallback wasn't enough — it left .repo-mem/ (838 MB on disk),
.claude/, .agents/, .codex, every submodule's wiki + tests + simulation
harness, and the per-submodule CLAUDE.md files in the tarball.
This .npmignore mirrors .gitignore for the dev-artifact baseline and then
adds two more layers:
1. Repo-level dev tooling that .gitignore doesn't cover (tools/,
docker/, scripts/, test/, wiki/, .repo-mem/, .claude/, …).
2. Per-submodule dev-only trees under nodes/*/ — necessary because npm
pack at the root doesn't honour the submodule's own .npmignore.
After: 1.6 MB tarball, 498 files, runtime content only (entry .js + .html,
src/, package.json, examples/, generalFunctions datasets + coolprop.wasm,
per-node README/LICENSE/CONTRACT). Removes the
"npm warn gitignore-fallback" warning.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Submodule pointer updates:
- generalFunctions @ ae30cef
feat(pumpingStation schema): add holdLevel + deadZoneKeepAlivePercent;
slim npm pack
- machineGroupControl @ aeb938c
feat(setDemand): surface specificClass.setDemand(value, unit='%')
+ slim npm pack
- pumpingStation @ 2e4ad8d
fix(levelBased): drop hold zone, route through MGC.setDemand, add
holdLevel + integrator variant pick; slim npm pack
Cross-submodule summary:
- pumpingStation level-based control now sends percent demand to MGC via
the new MGC.setDemand entry point — was calling handleInput with a raw
percent, which the dispatcher interpreted as canonical m³/s and pegged
the group at 100 %.
- Ramp foot is no longer pinned at inflowLevel. Default is startLevel
(0 % at startLevel = MGC flow.min, matching operator mental model). New
optional holdLevel raises the 0 %-foot for an explicit hold band.
- Predicted-volume integrator now picks the best-available variant per
side (measured first, then predicted) so a real upstream sensor +
predicted pump outflow both feed the basin balance.
- Each submodule grew a .npmignore mirroring its .gitignore plus the
dev-only trees (test/, wiki/, .claude/, …). Per-submodule pack sizes
dropped — pumpingStation went 1.5 MB → 57 kB.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two trailing items the prior commits missed:
- .mcp.json was rm'd from the working tree in commit d4e72f2 (repo-mem
cleanup) but never staged for deletion; git status kept showing
' D .mcp.json' as a result. Properly removed now.
- nodes/pumpingStation pin bumps to pull in the wiki-gen regen commit
that kept Reference-Contracts.md in sync with the tool's canonical
output.
User WIP intentionally not touched: examples/README.md zeroed-out,
examples/pumpingstation-complete-example/* removed, and
nodes/rotatingMachine working-tree change to rotatingMachine.html.
Those belong to the user; the harness only re-flagged them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Superproject:
- CLAUDE.md: legacy-drift table loses the dashboardAPI row (migrated);
drift section notes the type-id-preservation strategy for the
remaining mgc / vgc renames.
- CONTRACTS.md: canonical-unit rule explicitly carves out reactor as
an approved ASM-textbook exception with the conversion boundary.
Submodules:
- nodes/valve @ 167b102: CONTRACT documents valve's lack of an FSM
maintenance state (schema mode enum accepts `maintenance` but no
enter/exit sequences exist). Limits made explicit instead of being
hidden as a wiki TODO.
- nodes/reactor @ 75d0413: CONTRACT now declares the approved ASM-unit
divergence (mg/L, m³/d, °C, 1/h) with the conversion boundary spelled
out. Closes the canonical-unit drift surfaced by the wiki audit.
- nodes/dashboardAPI @ ......: file rename (preserves type id).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- nodes/generalFunctions @ 8252a5f: schemas drop dead `calculationMode`
(RM/valve/VGC — never read) and dead `allowedActions` (valve/VGC —
flowController only checks isValidSourceForMode, never the action
allow-list). Kept allowedActions in RM/MGC where it IS enforced.
- nodes/{rotatingMachine,machineGroupControl,valve,valveGroupControl}:
set.mode descriptions in commands/index.js were generic "auto /
manual" but each node's schema declares 3–4 specific modes. Now
enumerate the actual allowed values and point at the schema.
- nodes/machineGroupControl CONTRACT.md additionally fixed: old
`prioritycontrol`, `optimalcontrol`, `dynamiccontrol` list was wrong
(lowercase + nonexistent dynamiccontrol); now matches the schema.
- nodes/monster: reframed from "multi-parameter biological process
monitor" to "sampling-cabinet pulse counter" — the code only emits
volumetric pulse + bucket state, no constituent analysis. Old
framing was misleading. examples/README also cleaned of references
to 4 flow files that don't exist on disk.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two cross-submodule fixes for the reactor unit-confusion drift the wiki
uplift surfaced:
- nodes/generalFunctions @ 4f715e8: reactor schema timeStep.unit now "s"
(was "h"), default 1 (was 0.001). Matches reactor.html label [s] and
baseEngine.js's seconds→days conversion. Description warns future
readers off changing the unit without updating the engine.
- nodes/reactor @ 346a3ce: HTML X_A_init default 0.001 → 200 (operational
nitrifying biomass; 0.001 disabled nitrification per the memory note).
Factory updated to match. New regression test
test/basic/timestep-units.basic.test.js locks in the seconds contract
and schema agreement. 49/49 reactor tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tools/physics-sanity/ — JS library of cross-node balance helpers
(mass / hydraulic / hydraulic-power / oxygen-transfer / energy) with
7 unit tests + a CLI demo. Designed for `require()` from per-node
integration tests where shape-based unit tests miss physically-
impossible plant states.
- tools/docker-compose.yml + tools/mcp/{node-red-admin,influxdb,browser}
scaffolding — placeholder Dockerfiles + a ROADMAP.md for the Node-RED
admin MCP. Compose file is the target shape for the Q3-2026 migration
to the central MCP server; the per-service Dockerfile stays in this
repo as the canonical definition either way. Implementations are TODO.
- tools/README.md — top-level tooling index; documents the CI order for
running every tool on a PR.
- .gitignore: ignore tools/.env (developer-specific MCP endpoints).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tools/output-manifest-verify/ — enforces .claude/rules/output-coverage.md
§3: every node ships test/_output-manifest.md and every declared key
is referenced by at least one test file. First run shows only
machineGroupControl has the manifest (16 keys covered); all other nodes
warn. --strict escalates "missing manifest" to an error for CI gating.
- flow-lint gains two rules from the same output-coverage rule:
* FN_OUTPUT_WIRES_MISMATCH — function declares outputs=N but wires has
M arrays (causes silent dropped or duplicate emissions).
* FN_PAYLOAD_NULL_LITERAL — function source contains `payload: null`
literal (the η-null ui-chart crash pattern from 2026-05-14).
First run found 1 instance in mgc/02-Dashboard.json.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the placeholder topic tables in Reference-Contracts.md (left by
the wiki uplift agents) with authoritative content generated from each
node's src/commands/index.js. CI gate: `node tools/wiki-gen/bin/wiki-gen.js --check`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generates the markdown table inside <!-- BEGIN AUTOGEN: topic-contract -->
blocks in nodes/<n>/wiki/Reference-Contracts.md from the canonical registry
at src/commands/index.js. Replaces the agent-written placeholders the wiki
uplift left behind.
- Accepts both labelled and unlabelled END markers; rewrites to canonical
'<!-- END AUTOGEN: topic-contract -->' on regeneration so future runs are
consistent.
- --check mode for CI (exit 1 if any block is out of date).
- Out of scope for now: data-model AUTOGEN block (requires instantiating
the domain; the 9 agent-written placeholders for that block stay until
a follow-up tool lands).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each node's wiki now matches the rotatingMachine reference: Home +
Reference-{Architecture,Contracts,Examples,Limitations} + _Sidebar.
Total ≈ 9 000 lines of wiki content. Topic-contract and data-model
sections wrapped in <!-- BEGIN AUTOGEN --> markers for the future
wiki-gen tool.
Each agent surfaced real source-vs-spec drift rather than inventing
content:
- measurement: digital-mode notifyOutputChanged path uncertain;
buildDomainConfig drops several editor fields; position case
preserved by child.register payload
- valve: flowController gates by source only (action allow-list dead);
no enter/exit maintenance sequences; sequence-abort token status TBD
- reactor: timeStep unit confusion (HTML s, schema h, engine /86400);
X_A default disagreement (0.001 vs 200 mg/L); doesn't honour the
canonical-unit rule (m³/d not m³/s, °C not K)
- valveGroupControl: 4 CONTRACT/source drifts incl. set.mode covers
4 modes not 2, calculationMode + mode.allowedActions dead config,
maintenance source allow-list undefined
- settler: icon colour #e4a363 conflicts S88 Unit #50a8d9; Port 2
emits null in _emitOutputs (init-only registration)
- diffuser: stale test/README claiming "no runtime" — runtime exists
(284-line specificClass with full OTR/ΔP model); update README
- monster: superproject docs frame as multi-parameter biological
monitor (NH4/NO3/COD/TSS), but source emits only volumetric pulse +
bucket state; 4 example flows referenced but missing on disk
- dashboardAPI: dashboardapi.{js,html} lowercase entry vs folder
convention; logging.enabled default mismatch (false vs true)
- generalFunctions: full library API restructure preserved; module
map + consumer graph + extension examples retained
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- tools/contract-verify/ — diffs CONTRACT.md ## Inputs table vs
src/commands/index.js registry. First run found 3 real drifts:
MGC has `set.scaling` in CONTRACT (not in registry); monster + settler
registry has `child.register` (not in CONTRACT); pumpingStation registry
has `set.outflow` (not in CONTRACT).
- tools/flow-lint/ — lints examples/*.flow.json against the rules in
.claude/rules/node-red-flow-layout.md. First run flagged the
monster/basic flow (4 ui-* at 0,0 + ui-chart missing interpolation
property) and rotatingMachine/edge.flow.json (6 ui-* at 0,0).
- Both tools are read-only, single-binary npm packages with a `--json`
output mode for CI, exit code 1 on drift. Encode the rules so we
don't have to re-discover the bugs that motivated them.
Per CLAUDE.md tooling doctrine: prefer these over ad-hoc grep/jq.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 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>