# EVOLV Agent Guide (AGENTS.md)

## Project Summary
EVOLV is a modular Node-RED package bundling multiple custom control/automation nodes (primarily under `nodes/`) for wastewater/process applications.

## Repository Layout
- `package.json`: Root package metadata + `node-red.nodes` map that tells Node-RED which node entrypoints to load.
- `nodes/<nodeName>/`: A Node-RED node module (often a git submodule).
  - `<nodeName>.js`: Node-RED runtime entry (registers the node and exposes admin endpoints).
  - `<nodeName>.html`: Node-RED editor UI definition for the node.
  - `src/`: Node implementation classes and logic.
- `nodes/generalFunctions/`: Shared utilities used by most nodes (logger/config/menu helpers, etc).
- `node_modules/`: Local install output; do not edit.

## Development Workflow
- Dependencies: prefer `npm ci` at repo root (uses `package-lock.json`). Avoid changing `package.json` without updating the lockfile.
- Node-RED integration (local dev):
  - Ensure Node-RED can see this repo as a nodes directory (e.g., `settings.js` with `nodesDir: './nodes'`) or copy/link the repo into `~/.node-red/nodes/`.
  - Restart Node-RED after changes so nodes reload.

## Node-RED Node Conventions (Important)
- Use CommonJS (`require`, `module.exports`); Node-RED nodes export `module.exports = function(RED) { ... }`.
- Keep names consistent across files:
  - Node type name (used in `RED.nodes.registerType(...)`) must match the `.html` registration and the expected file/module name.
- Keep runtime config <-> editor UI config in sync:
  - If you add/remove a config property, update both `<nodeName>.html` and the runtime parsing in `src/nodeClass.js` (or equivalent).
- Most nodes expose admin endpoints like:
  - `/<nodeName>/menu.js`
  - `/<nodeName>/configData.js`
  Keep these stable unless you also update the editor UI that consumes them.

## Default Node File Layout (Template)
Use `nodes/machineGroupControl/` as the reference implementation for how new nodes should be structured and written.

### Folder / files
Create nodes with this baseline structure:
- `nodes/<nodeName>/`
  - `<nodeName>.js`: Node-RED runtime entrypoint; registers the node and exposes admin endpoints.
  - `<nodeName>.html`: Node-RED editor UI; registers editor defaults and loads dynamic menu/config scripts.
  - `src/nodeClass.js`: Thin Node-RED wrapper around the domain class; handles config mapping, tick loop, message routing, status updates, and lifecycle.
  - `src/specificClass.js`: Domain logic; should be usable outside Node-RED (no direct `RED` usage).
  - `package.json`: Node metadata and `node-red.nodes` map for the submodule package.
  - `README.md`, `LICENSE`: Minimal docs + license (usually present in submodules).
  - `test/`: Required node test suite (see “Testing Policy” below).

### Responsibilities by file (how to write new code)
- `<nodeName>.js` (runtime entry)
  - Keep it small: create the Node-RED node instance and attach `this.nodeClass = new nodeClass(...)`.
  - Add admin endpoints using `MenuManager` and `configManager` from `generalFunctions`, e.g.:
    - `RED.httpAdmin.get(\`/${nameOfNode}/menu.js\`, ...)`
    - `RED.httpAdmin.get(\`/${nameOfNode}/configData.js\`, ...)`
- `<nodeName>.html` (editor UI)
  - Load admin endpoint scripts at the top:
    - `<script src="/<nodeName>/menu.js"></script>`
    - `<script src="/<nodeName>/configData.js"></script>`
  - Register the node with `RED.nodes.registerType('<nodeName>', { ... })` and define `defaults` for all UI properties.
  - Use `oneditprepare` to call `window.EVOLV.nodes.<nodeName>.initEditor(this)` once the dynamic scripts are ready.
  - Prefer placeholder `<div>`s (like `logger-fields-placeholder`, `position-fields-placeholder`) that menus inject into, instead of hardcoding repeated UI blocks.
- `src/nodeClass.js` (Node-RED wrapper)
  - Map Node-RED UI config (`uiConfig`) into a normalized `this.config` object by merging UI settings over defaults from `generalFunctions/configManager`.
  - Instantiate the domain class (`src/specificClass.js`) and keep Node-RED concerns here:
    - input handler routing on `msg.topic`
    - periodic `_tick()` loop and output formatting (often via `generalFunctions/outputUtils`)
    - node status updates (`node.status(...)`)
    - registration messages for parent/child wiring (commonly `msg.topic = "registerChild"`)
- `src/specificClass.js` (domain class)
  - Implement the actual behaviour and calculations; prefer no Node-RED coupling.
  - Use the shared helpers from `generalFunctions` where applicable (`logger`, `configUtils`, `MeasurementContainer`, `childRegistrationUtils`, etc).
  - Avoid side effects at import time: export the class via `module.exports = <ClassName>` and do not start timers / run simulations automatically.

### Ports & message conventions (observed pattern)
Many EVOLV nodes follow this convention (see `nodes/machineGroupControl/mgc.html` and `nodes/machineGroupControl/src/nodeClass.js`):
- Outputs are commonly:
  - output 0: process message
  - output 1: database/influx message
  - output 2: parent/registration/control plumbing (e.g., `registerChild`)
- `msg.topic` is used as the command selector (`registerChild`, `setMode`, `setScaling`, etc). Keep topic names stable once released.

## Adding A New Node (Checklist)
- Add `nodes/<nodeName>/` using the template above (prefer creating it as its own repo/submodule if that’s the project norm).
- Add the node entrypoint to the root `package.json` under `node-red.nodes` so Node-RED can discover it.
- Keep `<nodeName>.js`, `<nodeName>.html`, and `RED.nodes.registerType('<nodeName>', ...)` naming aligned.
- If the editor uses menus/config endpoints, ensure the endpoint paths match what `<nodeName>.html` loads.

## Testing Policy (Required)
All code changes must be accompanied by tests, stored per node in a dedicated folder:
- Location: `nodes/<nodeName>/test/`
- Tests must be runnable locally without Node-RED and without network access.
- Prefer testing the domain logic in `src/specificClass.js` directly; test `src/nodeClass.js` only with lightweight stubs (do not require a full Node-RED runtime).

### What to test (aim for exhaustive coverage)
- Config: default/override behaviour, required fields, type coercion for numeric UI values.
- Topics: each supported `msg.topic` path and its edge cases (missing payload, invalid types).
- Child registration: registering/deduping children and verifying expected side-effects on state.
- Tick/output: `tick()`/`getOutput()` behaviour (or equivalent) including boundary values and error paths.
- Regression cases: any bug fixed must get a test that fails before and passes after.

### How to run
Use the simplest possible runner:
- Prefer Node’s built-in test runner when available: `node --test nodes/<nodeName>/test/*.test.js`
- Otherwise keep tests executable via plain Node: `node nodes/<nodeName>/test/<file>.test.js` using `assert`.

## Submodules
Many `nodes/*` directories are git submodules.
- Prefer making changes in the appropriate submodule directory and keep edits scoped to that node.
- Avoid editing `nodes/*/.git` files directly.
- If the task is “update a node submodule”, update the submodule pointer in this repo rather than copying code across nodes.

## Safety / Hygiene
- Do not modify generated or vendored content unless explicitly requested:
  - `node_modules/`
  - `EVOLV-*.tgz`
- Exclude `node_modules/` when searching or refactoring (`rg --glob '!**/node_modules/**'`).
- Network access may be restricted in automated runs; avoid installing from git/NPM without approval.

## Validation
No centralized test runner is configured at the root.
- Prefer targeted smoke checks: Node-RED starts, nodes load, node editor renders, and admin endpoints respond.
- If a node has its own `package.json` scripts, run them from that node directory only when they actually execute in your environment.
