docs: lock in 12 decisions from the 2026-05-11 interview + add Phase 11
OPEN_QUESTIONS.md: summary table of every decision (ramp foot, naming,
isStable fix, monster guard, plain-dicts→declareChildGetter, VGC→
ChildRouter, LatestWinsGate fireAndWait, drop mAbs, per-listener fan-out,
commandRegistry 'none' + description, UnitPolicy dual-shape, Phase 10
test rewrites).
TASKS.md §Phase 11: unit-aware commands. Every numeric setter declares
units: { measure, default }. commandRegistry normalises msg.payload +
msg.unit; warns + lists accepted units for bad input; falls back to
default. New query.units topic returns the spec per node.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,27 @@ Things deferred. Append, don't rewrite history. Add a date when you add
|
|||||||
or resolve an entry. Anyone (human or agent) discovering an unclear
|
or resolve an entry. Anyone (human or agent) discovering an unclear
|
||||||
decision during refactor work writes it here rather than guessing.
|
decision during refactor work writes it here rather than guessing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2026-05-11 — Interview round — resolved decisions
|
||||||
|
|
||||||
|
| Topic | Decision |
|
||||||
|
|---|---|
|
||||||
|
| Ramp foot for run-zone curve (control/levelBased) | `inflowLevel` (current). startLevel is the 0% minimum, not the curve foot. |
|
||||||
|
| `overfillLevel` vs `highVolumeSafetyLevel` | **`highVolumeSafetyLevel` canonical**; drop the legacy alias. |
|
||||||
|
| measurement `isStable` tautology | Fix now with a config-driven absolute threshold (`stabilityThreshold` in scaling-units). Add to schema + editor UI. |
|
||||||
|
| monster cooldown-guard pre-existing fail | Debug + fix the sampling-pulse logic. |
|
||||||
|
| pumpingStation plain child dicts | Migrate to `declareChildGetter`; rewrite affected tests. |
|
||||||
|
| VGC custom `registerChild` overload | Adopt ChildRouter; rewrite disambiguation tests. |
|
||||||
|
| MGC inline dispatch gate vs LatestWinsGate | Extend LatestWinsGate with `fireAndWait(value)` returning the per-fire settlement promise. Migrate MGC. |
|
||||||
|
| measurement legacy `'mAbs'` event | Remove now. |
|
||||||
|
| ChildRouter wildcard emit-patch | Per-listener fan-out using canonical POSITIONS. No more emit patching. |
|
||||||
|
| commandRegistry payload schema | Add `'none'` type + per-command `description` field (wikiGen consumes). |
|
||||||
|
| UnitPolicy property-vs-method shape | Expose both. Frozen property bags alongside the methods. Drop `_unitView` workarounds. |
|
||||||
|
| rotatingMachine + reactor private-method-pinning tests (13 files) | Rewrite all to drive only the public BaseNodeAdapter surface. Phase 10. |
|
||||||
|
| **Unit-aware commands (new)** | Each numeric setter declares `units: { measure, default }`. commandRegistry normalises + warns + lists accepted units. `query.units` topic returns spec. Phase 11. |
|
||||||
|
|
||||||
|
|
||||||
Format:
|
Format:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -253,3 +253,41 @@ now that the platform is uniform. Pre-existing test debt logged in
|
|||||||
| 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.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.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. |
|
| 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