- 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>
48 lines
2.0 KiB
Markdown
48 lines
2.0 KiB
Markdown
# @evolv/flow-lint
|
|
|
|
Lint Node-RED flow JSON against the EVOLV flow-layout rule
|
|
(`.claude/rules/node-red-flow-layout.md`).
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# every examples/*.flow.json across all nodes
|
|
node tools/flow-lint/bin/flow-lint.js
|
|
|
|
# one flow
|
|
node tools/flow-lint/bin/flow-lint.js nodes/rotatingMachine/examples/01-Basic.flow.json
|
|
|
|
# CI / JSON output (one line per flow)
|
|
node tools/flow-lint/bin/flow-lint.js --json
|
|
```
|
|
|
|
Exit code `1` on any `error`-severity finding; `0` otherwise (warnings do
|
|
not fail).
|
|
|
|
## Rules
|
|
|
|
| Rule | Severity | Catches |
|
|
|---|---|---|
|
|
| `UI_XY` | error | `ui-*` nodes with both `x` and `y` at 0 — pile up at canvas origin. |
|
|
| `UI_CHART_PROP` | error | `ui-chart` missing one of the required-or-it-renders-blank properties (interpolation, yAxisProperty, …). |
|
|
| `UI_CHART_TYPE` | warn | `width` / `height` as string instead of number. |
|
|
| `UI_CHART_PALETTE` | warn | `colors` array with fewer than 3 entries. |
|
|
| `INJECT_JSON_PROPS` | error | `inject` with `payloadType:"json"` but missing `props[]` — silently treated as string. |
|
|
| `LINK_CHANNEL_NAME` | warn | `link out` / `link in` without a `cmd:` / `evt:` / `setup:` prefix. |
|
|
| `LINK_BROKEN` | error | `link out` / `link in` referencing a non-existent node id. |
|
|
| `LINK_PAIR_TYPE` | error | `link out` paired with anything other than `link in`, or vice versa. |
|
|
| `LINK_PAIR_ASYMMETRIC` | error | One side references the other but the partner does not link back. |
|
|
| `DEBUG_LOG_IN_FLOW` | warn | `enableLog:"debug"` shipped in a flow — fills container log. |
|
|
| `SELF_LOOP` | error | Any node wired to itself. |
|
|
| `GROUP_WIDTH_SUM` | warn | `ui-group` widths on a `ui-page` summing to non-multiple of 12 — leaves grid gaps. |
|
|
|
|
## Why use it
|
|
|
|
Every rule corresponds to a bug we've actually hit:
|
|
- `UI_XY` and `UI_CHART_PROP` — the dashboard pile-up + blank-chart bugs.
|
|
- `INJECT_JSON_PROPS` — the silent-string inject bug.
|
|
- `LINK_PAIR_ASYMMETRIC` — drift between named channels.
|
|
- `SELF_LOOP` — the 250k-msg/s `replace_all` incident.
|
|
|
|
Run before committing any flow change.
|