Compare commits
9 Commits
dev-rene
...
80de324b32
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80de324b32 | ||
|
|
c8d5ea0fce | ||
|
|
b871b23c24 | ||
|
|
91b681a74d | ||
|
|
76d2008e52 | ||
|
|
3c304f14e5 | ||
|
|
24c443840b | ||
|
|
c4c8629c01 | ||
| 609c72cedc |
@@ -1,38 +0,0 @@
|
|||||||
# DECISION-20260216-agent-harness-defaults
|
|
||||||
|
|
||||||
## Context
|
|
||||||
- Task/request: Adapt EVOLV agents/skills using Harness Engineering patterns and set owner-controlled operating defaults.
|
|
||||||
- Impacted files/contracts: `AGENTS.md`, `.agents/skills/*/SKILL.md`, `.agents/skills/*/agents/openai.yaml`, decision-log policy.
|
|
||||||
- Why a decision is required now: New harness workflow needs explicit defaults for compatibility, safety bias, and governance discipline.
|
|
||||||
|
|
||||||
## Options
|
|
||||||
1. Compatibility posture
|
|
||||||
- Option A: strict backward compatibility
|
|
||||||
- Option B: controlled compatibility breaks with migration notes
|
|
||||||
|
|
||||||
2. Safety posture
|
|
||||||
- Option A: protection-first
|
|
||||||
- Option B: availability-first
|
|
||||||
|
|
||||||
3. Decision logging scope
|
|
||||||
- Option A: required only for breaking/risky changes
|
|
||||||
- Option B: required for all decision-gate outcomes
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
- Selected option: Compatibility `controlled`; Safety `availability-first`; Decision logging `required for all decision-gate changes`.
|
|
||||||
- Decision owner: User
|
|
||||||
- Date: February 16, 2026
|
|
||||||
- Rationale: Maintain delivery and operational continuity while preserving governance through mandatory, durable decision records.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Compatibility impact: Breaking contract changes are permissible only when migration/deprecation is explicit.
|
|
||||||
- Safety/security impact: Control changes should bias toward continuity with bounded safeguards; critical protections still require explicit constraints.
|
|
||||||
- Data/operations impact: Decision traceability improves cross-turn consistency and auditability.
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
- Required code/doc updates: Set defaults in `AGENTS.md` and orchestrator skill instructions; keep decision-log template active.
|
|
||||||
- Validation evidence required: Presence of defaults in policy docs and this decision artifact under `.agents/decisions/`.
|
|
||||||
|
|
||||||
## Rollback / Migration
|
|
||||||
- Rollback strategy: Update defaults in `AGENTS.md` and orchestrator SKILL; create a superseding decision log entry.
|
|
||||||
- Migration/deprecation plan: For any future hard-break preference, require explicit migration plan and effective date in a new decision entry.
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
# Decision: Shared Modern PID in generalFunctions + PumpingStation Flow-Based Adoption
|
|
||||||
|
|
||||||
- Date: 2026-02-23
|
|
||||||
- Scope: `nodes/generalFunctions/src/pid/*`, `nodes/pumpingStation/src/*`
|
|
||||||
|
|
||||||
## Context
|
|
||||||
Flow-based control in `pumpingStation` needed a production-grade PID with freeze/unfreeze, runtime retuning, and support for cascade/secondary-loop architecture.
|
|
||||||
|
|
||||||
## Options Considered
|
|
||||||
1. Implement PID only inside `pumpingStation`.
|
|
||||||
2. Implement shared PID in `generalFunctions` and consume it from `pumpingStation`.
|
|
||||||
3. Keep current heuristic (non-PID) flow controller.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
Chose option 2.
|
|
||||||
|
|
||||||
## Rationale
|
|
||||||
- PID behavior is cross-domain control functionality and should be reusable across EVOLV nodes.
|
|
||||||
- `generalFunctions` already serves as shared utility/runtime infrastructure.
|
|
||||||
- Reuse reduces drift and duplicated control logic.
|
|
||||||
- PumpingStation can immediately adopt shared PID while preserving existing topic contracts.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Positive:
|
|
||||||
- Single, test-covered PID implementation with modern features.
|
|
||||||
- PumpingStation flow mode becomes true closed-loop control.
|
|
||||||
- Runtime support for freeze/unfreeze and tuning updates without redeploy.
|
|
||||||
- Risks:
|
|
||||||
- Behavioral differences versus prior heuristic flow control.
|
|
||||||
- Requires conservative tuning per site.
|
|
||||||
|
|
||||||
## Safety / Compatibility
|
|
||||||
- No existing topic names were removed.
|
|
||||||
- Added optional control topics for PID runtime management.
|
|
||||||
- Existing non-flowbased modes remain intact.
|
|
||||||
|
|
||||||
## Rollback
|
|
||||||
- Revert `nodes/pumpingStation/src/specificClass.js` flow-based branch to previous heuristic logic.
|
|
||||||
- Keep shared PID module in `generalFunctions` for future use, or revert `nodes/generalFunctions/src/pid/*` if required.
|
|
||||||
|
|
||||||
## Migration Notes
|
|
||||||
- For `flowbased`, start with low `kp/ki`, verify stability in commissioning, then tune upward.
|
|
||||||
- Use `freezeFlowPid` and `setFlowPidMode` during maintenance or manual takeover.
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Decision: Harden NRMSE and Use Metric Profiles in RotatingMachine
|
|
||||||
|
|
||||||
- Date: 2026-02-24
|
|
||||||
- Scope: `nodes/generalFunctions/src/nrmse/*`, `nodes/rotatingMachine/src/specificClass.js`
|
|
||||||
|
|
||||||
## Context
|
|
||||||
Drift analytics were previously single-path and flow-focused with weak input safeguards in NRMSE.
|
|
||||||
Requirement: make NRMSE architecturally robust and apply it across multiple measurements in rotatingMachine.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
Adopt a metric-profile drift architecture:
|
|
||||||
|
|
||||||
1. Harden `generalFunctions/nrmse` with:
|
|
||||||
- strict validation for malformed inputs
|
|
||||||
- timestamp-aware alignment support
|
|
||||||
- per-metric state
|
|
||||||
- configurable rolling window and EWMA long-term trend
|
|
||||||
- point-based API (`assessPoint`) while retaining legacy calls
|
|
||||||
|
|
||||||
2. Rewire rotatingMachine to consume NRMSE per metric:
|
|
||||||
- `flow` model drift
|
|
||||||
- `power` model drift
|
|
||||||
- pressure-quality drift as node-specific plausibility/redundancy assessment
|
|
||||||
|
|
||||||
3. Expose drift and confidence outputs per metric in node output payload.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Drift computations are deterministic and safer under bad inputs.
|
|
||||||
- RotatingMachine confidence now reflects multiple measurement channels.
|
|
||||||
- Output schema expands with power/pressure drift fields.
|
|
||||||
|
|
||||||
## Rollback Notes
|
|
||||||
- Revert `errorMetrics.js` and rotatingMachine drift wiring to return to legacy flow-only drift behavior.
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Decision: RotatingMachine Hydraulic Efficiency Correction and Prediction Confidence
|
|
||||||
|
|
||||||
- Date: 2026-02-24
|
|
||||||
- Scope: `nodes/rotatingMachine/src/specificClass.js`, rotatingMachine integration tests
|
|
||||||
|
|
||||||
## Context
|
|
||||||
Hydraulic efficiency calculation in `rotatingMachine` was dimensionally inconsistent and could over/under-report efficiency KPIs.
|
|
||||||
At the same time, prediction drift tooling (`nrmse`) existed but was not actively connected to rotatingMachine output confidence.
|
|
||||||
|
|
||||||
## Options Considered
|
|
||||||
1. Keep existing formula and only tune thresholds.
|
|
||||||
2. Replace formula with standard hydraulic power/efficiency equations and expose prediction confidence from live pressure source + drift.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
Adopt option 2.
|
|
||||||
|
|
||||||
- Hydraulic power now follows standard engineering relation:
|
|
||||||
- `P_h = Q * Δp` (equivalent to `ρ g Q H`)
|
|
||||||
- `η_h = P_h / P_in`
|
|
||||||
- RotatingMachine now computes flow drift via `nrmse` from measured vs predicted flow windows.
|
|
||||||
- RotatingMachine now exposes prediction confidence fields in output:
|
|
||||||
- `predictionQuality`
|
|
||||||
- `predictionConfidence`
|
|
||||||
- `predictionPressureSource`
|
|
||||||
- `predictionFlags`
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Efficiency KPIs become physically interpretable and traceable to pressure/flow/power inputs.
|
|
||||||
- Prediction trust is now observable by downstream control/dashboard layers.
|
|
||||||
- Output schema is expanded with new prediction confidence fields.
|
|
||||||
|
|
||||||
## Rollback / Migration Notes
|
|
||||||
- Rollback path: revert `specificClass.js` hydraulic block and prediction-health integration.
|
|
||||||
- No mandatory migration required for existing flows unless they choose to consume new prediction confidence fields.
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Decision: Canonical Unit Anchoring and Curve Unit Normalization in RotatingMachine
|
|
||||||
|
|
||||||
- Date: 2026-02-24
|
|
||||||
- Scope: `nodes/rotatingMachine/*`, `nodes/generalFunctions/src/measurements/MeasurementContainer.js`, `nodes/generalFunctions/src/configs/rotatingMachine.json`
|
|
||||||
|
|
||||||
## Context
|
|
||||||
RotatingMachine previously relied on node-local defaults for measurement storage units, with implicit assumptions that loaded machine curves used the same units as runtime configuration. This made unit drift likely when model curves, simulated inputs, and runtime settings differed.
|
|
||||||
|
|
||||||
Owner decision direction:
|
|
||||||
- use a single unit anchor strategy
|
|
||||||
- treat node/UI units as ingress/egress only
|
|
||||||
- add explicit curve unit metadata
|
|
||||||
- reject or flag blank/invalid measurement units
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
1. Extend `MeasurementContainer` with optional canonical-anchor mode:
|
|
||||||
- per-type canonical unit mapping
|
|
||||||
- strict unit validation and required-unit policy
|
|
||||||
- compatibility checks by measure family
|
|
||||||
- requested-unit conversion at flattened output stage
|
|
||||||
|
|
||||||
2. Apply canonical policy in `rotatingMachine` runtime:
|
|
||||||
- internal storage and calculations anchored to SI-like canonical units (`Pa`, `m3/s`, `W`, `K`)
|
|
||||||
- egress payloads converted back to configured output units
|
|
||||||
- ingress `simulateMeasurement` path requires explicit valid units
|
|
||||||
|
|
||||||
3. Add explicit curve unit metadata (`asset.curveUnits`) and normalize loaded curves into canonical units before predictor initialization.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Unit handling is centralized and deterministic for RotatingMachine.
|
|
||||||
- Curve/model-unit mismatch risk is reduced by explicit metadata plus normalization.
|
|
||||||
- Existing output topic/field names remain stable; values are emitted in configured output units while internals stay canonical.
|
|
||||||
- This establishes a migration template for remaining EVOLV nodes.
|
|
||||||
|
|
||||||
## Rollback Notes
|
|
||||||
- Revert `MeasurementContainer` canonical/validation extensions.
|
|
||||||
- Revert RotatingMachine unit-policy and curve-normalization wiring.
|
|
||||||
- Remove `asset.curveUnits` schema entry and restore previous node-local default-unit behavior.
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# Decision: Unit-Anchor Rollout Phase 1 (MachineGroup, PumpingStation, Valve, ValveGroupControl)
|
|
||||||
|
|
||||||
- Date: 2026-02-24
|
|
||||||
- Scope:
|
|
||||||
- `nodes/machineGroupControl/src/nodeClass.js`
|
|
||||||
- `nodes/machineGroupControl/src/specificClass.js`
|
|
||||||
- `nodes/pumpingStation/src/nodeClass.js`
|
|
||||||
- `nodes/pumpingStation/src/specificClass.js`
|
|
||||||
- `nodes/valve/src/nodeClass.js`
|
|
||||||
- `nodes/valve/src/specificClass.js`
|
|
||||||
- `nodes/valveGroupControl/src/nodeClass.js`
|
|
||||||
- `nodes/valveGroupControl/src/specificClass.js`
|
|
||||||
|
|
||||||
## Context
|
|
||||||
After adopting canonical-unit anchoring in `rotatingMachine`, adjacent controller nodes still mixed local units, unitless writes, and implicit conversions. That left cross-node behavior sensitive to registration order and source-unit assumptions.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
1. Apply the same canonical storage policy per node:
|
|
||||||
- internal storage in canonical units (`Pa`, `m3/s`, `W`, `K` where relevant),
|
|
||||||
- preferred/output units for operator-facing status and output payloads.
|
|
||||||
|
|
||||||
2. Enable strict measurement ingress discipline on migrated nodes:
|
|
||||||
- `strictUnitValidation: true`,
|
|
||||||
- `throwOnInvalidUnit: true`,
|
|
||||||
- required unit for physically dimensional types (`flow`, `pressure`, `power`, `temperature`, and node-specific equivalents).
|
|
||||||
|
|
||||||
3. Replace unitless runtime writes/reads with explicit-unit helpers in each node’s domain class, including child-machine/child-valve interactions.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Cross-node calculations now run against a deterministic unit anchor in phase-1 nodes.
|
|
||||||
- Status/output values remain in preferred/output units, while internal math stays canonical.
|
|
||||||
- Legacy paths that send dimensional values without units now fail fast instead of silently coercing.
|
|
||||||
|
|
||||||
## Rollback Notes
|
|
||||||
- Revert the eight files listed in scope.
|
|
||||||
- Restore previous `MeasurementContainer` initialization (non-canonical, non-strict behavior) in each node.
|
|
||||||
- Remove helper-based explicit unit reads/writes and revert to prior direct chain usage.
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# DECISION-20260323-architecture-layering-resilience-and-config-authority
|
|
||||||
|
|
||||||
## Context
|
|
||||||
- Task/request: refine the EVOLV architecture baseline using the current stack drawings and owner guidance.
|
|
||||||
- Impacted files/contracts: architecture documentation, future wiki structure, telemetry/storage strategy, security boundaries, and configuration authority assumptions.
|
|
||||||
- Why a decision is required now: the architecture can no longer stay at a generic "Node-RED plus cloud" level; several operating principles were clarified by the owner and need to be treated as architectural defaults.
|
|
||||||
|
|
||||||
## Options
|
|
||||||
1. Keep the architecture intentionally broad and tool-centric
|
|
||||||
- Benefits: fewer early commitments.
|
|
||||||
- Risks: blurred boundaries for resilience, data ownership, and security; easier to drift into contradictory implementations.
|
|
||||||
- Rollout notes: wiki remains descriptive but not decision-shaping.
|
|
||||||
|
|
||||||
2. Adopt explicit defaults for resilience, API boundary, telemetry layering, and configuration authority
|
|
||||||
- Benefits: clearer target operating model; easier to design stack services and wiki pages consistently; aligns diagrams with intended operational behavior.
|
|
||||||
- Risks: some assumptions may outpace current implementation and therefore create an architecture debt backlog.
|
|
||||||
- Rollout notes: document gaps clearly and treat incomplete systems as planned workstreams rather than pretending they already exist.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
- Selected option: Option 2.
|
|
||||||
- Decision owner: repository owner confirmed during architecture review.
|
|
||||||
- Date: 2026-03-23.
|
|
||||||
- Rationale: the owner clarified concrete architecture goals that materially affect security, resilience, and platform structure. The documentation should encode those as defaults instead of leaving them implicit.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Compatibility impact: low immediate code impact, but future implementations should align to these defaults.
|
|
||||||
- Safety/security impact: improved boundary clarity by making central the integration entry point and keeping edge protected behind site/central mediation.
|
|
||||||
- Data/operations impact: multi-level InfluxDB and smart-storage behavior become first-class design concerns; `tagcodering` becomes the intended configuration backbone.
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
- Required code/doc updates: update the architecture review doc, add visual wiki-ready diagrams, and track follow-up work for incomplete `tagcodering` integration and telemetry policy design.
|
|
||||||
- Validation evidence required: architecture docs reflect the agreed principles and diagrams; no contradiction with current repo evidence for implemented components.
|
|
||||||
|
|
||||||
## Rollback / Migration
|
|
||||||
- Rollback strategy: return to a generic descriptive architecture document without explicit defaults.
|
|
||||||
- Migration/deprecation plan: implement these principles incrementally, starting with configuration authority, telemetry policy, and site/central API boundaries.
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# DECISION-20260323-compose-secrets-via-env
|
|
||||||
|
|
||||||
## Context
|
|
||||||
- Task/request: harden the target-state stack example so credentials are not stored directly in `temp/cloud.yml`.
|
|
||||||
- Impacted files/contracts: `temp/cloud.yml`, deployment/operations practice for target-state infrastructure examples.
|
|
||||||
- Why a decision is required now: the repository contained inline credentials in a tracked compose file, which conflicts with the intended security posture and creates avoidable secret-leak risk.
|
|
||||||
|
|
||||||
## Options
|
|
||||||
1. Keep credentials inline in the compose file
|
|
||||||
- Benefits: simplest to run as a standalone example.
|
|
||||||
- Risks: secrets leak into git history, reviews, copies, and local machines; encourages unsafe operational practice.
|
|
||||||
- Rollout notes: none, but the risk remains permanent once committed.
|
|
||||||
|
|
||||||
2. Move credentials to server-side environment variables and keep only placeholders in compose
|
|
||||||
- Benefits: aligns the manifest with a safer deployment pattern; keeps tracked config portable across environments; supports secret rotation without editing the compose file.
|
|
||||||
- Risks: operators must manage `.env` or equivalent secret injection correctly.
|
|
||||||
- Rollout notes: provide an example env file and document that the real `.env` stays on the server and out of version control.
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
- Selected option: Option 2.
|
|
||||||
- Decision owner: repository owner confirmed during task discussion.
|
|
||||||
- Date: 2026-03-23.
|
|
||||||
- Rationale: the target architecture should model the right operational pattern. Inline secrets in repository-tracked compose files are not acceptable for EVOLV's intended OT/IT deployment posture.
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Compatibility impact: low; operators now need to supply environment variables when deploying `temp/cloud.yml`.
|
|
||||||
- Safety/security impact: improved secret hygiene and lower credential exposure risk.
|
|
||||||
- Data/operations impact: deployment requires an accompanying `.env` on the server or explicit `--env-file` usage.
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
- Required code/doc updates: replace inline secrets in `temp/cloud.yml`; add `temp/cloud.env.example`; keep the real `.env` untracked on the server.
|
|
||||||
- Validation evidence required: inspect compose file for `${...}` placeholders and verify no real credentials remain in tracked files touched by this change.
|
|
||||||
|
|
||||||
## Rollback / Migration
|
|
||||||
- Rollback strategy: reintroduce inline values, though this is not recommended.
|
|
||||||
- Migration/deprecation plan: create a server-local `.env` from `temp/cloud.env.example`, fill in real values, and run compose from that environment.
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# DECISION-YYYYMMDD-<slug>
|
|
||||||
|
|
||||||
## Context
|
|
||||||
- Task/request:
|
|
||||||
- Impacted files/contracts:
|
|
||||||
- Why a decision is required now:
|
|
||||||
|
|
||||||
## Options
|
|
||||||
1. Option A
|
|
||||||
- Benefits:
|
|
||||||
- Risks:
|
|
||||||
- Rollout notes:
|
|
||||||
|
|
||||||
2. Option B
|
|
||||||
- Benefits:
|
|
||||||
- Risks:
|
|
||||||
- Rollout notes:
|
|
||||||
|
|
||||||
## Decision
|
|
||||||
- Selected option:
|
|
||||||
- Decision owner:
|
|
||||||
- Date:
|
|
||||||
- Rationale:
|
|
||||||
|
|
||||||
## Consequences
|
|
||||||
- Compatibility impact:
|
|
||||||
- Safety/security impact:
|
|
||||||
- Data/operations impact:
|
|
||||||
|
|
||||||
## Implementation Notes
|
|
||||||
- Required code/doc updates:
|
|
||||||
- Validation evidence required:
|
|
||||||
|
|
||||||
## Rollback / Migration
|
|
||||||
- Rollback strategy:
|
|
||||||
- Migration/deprecation plan:
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# EVOLV Decision Log
|
|
||||||
|
|
||||||
Use this folder to store high-impact agent/user decisions that affect compatibility, safety, security, schema, or rollout risk.
|
|
||||||
|
|
||||||
Naming:
|
|
||||||
- `DECISION-YYYYMMDD-<slug>.md`
|
|
||||||
|
|
||||||
When to log:
|
|
||||||
- topic/payload/API contract changes
|
|
||||||
- safety envelope or fail-safe strategy changes
|
|
||||||
- security posture/default changes
|
|
||||||
- Influx retention/backfill/schema tradeoffs
|
|
||||||
- explicit acceptance of deferred high-risk debt
|
|
||||||
|
|
||||||
Start from `DECISION_TEMPLATE.md` for new entries.
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# Function Anchors
|
|
||||||
|
|
||||||
This folder stores class-level anchor documents that define EVOLV logic truth for long-term maintainability.
|
|
||||||
|
|
||||||
## Standard
|
|
||||||
1. Start each anchor with a **Connection Map (At a Glance)**.
|
|
||||||
2. Then provide a **Unit Table** as the first data section.
|
|
||||||
3. Cover the class end-to-end: config, I/O contracts, mode/state logic, full function inventory, calculations, safeguards, tests, invariants, and known gaps.
|
|
||||||
4. Keep references tied to file/line evidence.
|
|
||||||
|
|
||||||
## Mandatory Architecture Rule
|
|
||||||
All EVOLV node anchors must use the same folder and artifact structure as `rotatingMachine`.
|
|
||||||
|
|
||||||
Required per node:
|
|
||||||
- `.agents/function-anchors/<nodeName>/ANCHOR-<nodeName>.md`
|
|
||||||
- `.agents/function-anchors/<nodeName>/ANCHOR-<nodeName>.html`
|
|
||||||
- `.agents/function-anchors/<nodeName>/EVIDENCE-<nodeName>-tests.md`
|
|
||||||
- `nodes/<nodeName>/test/basic/*.test.js`
|
|
||||||
- `nodes/<nodeName>/test/integration/*.test.js`
|
|
||||||
- `nodes/<nodeName>/test/edge/*.test.js`
|
|
||||||
|
|
||||||
Enforcement policy:
|
|
||||||
- Do not ship behavioral changes in `nodes/<nodeName>/` without updating the matching anchor and evidence files.
|
|
||||||
- New EVOLV nodes must be created with this structure from day one.
|
|
||||||
- Existing nodes missing this structure are considered incomplete and must be brought to parity.
|
|
||||||
|
|
||||||
## Files
|
|
||||||
- `TEMPLATE.md`: reusable format for all future anchor points.
|
|
||||||
- `rotatingMachine/ANCHOR-rotatingMachine.md`: current rotatingMachine anchor.
|
|
||||||
- `rotatingMachine/EVIDENCE-rotatingMachine-tests.md`: test-evidence companion.
|
|
||||||
- `pumpingStation/ANCHOR-pumpingStation.md`: pumpingStation anchor preparation baseline.
|
|
||||||
- `pumpingStation/ANCHOR-pumpingStation.html`: pumpingStation visual topology anchor baseline.
|
|
||||||
- `pumpingStation/EVIDENCE-pumpingStation-tests.md`: pumpingStation test plan/evidence baseline.
|
|
||||||
- `monster/ANCHOR-monster.md`: monster node anchor baseline with API/report integration context.
|
|
||||||
- `monster/ANCHOR-monster.html`: monster visual topology anchor baseline.
|
|
||||||
- `monster/EVIDENCE-monster-tests.md`: monster test evidence baseline.
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
# Function Anchor Template
|
|
||||||
|
|
||||||
Use this template to document any EVOLV class as a stable "logic truth" anchor.
|
|
||||||
|
|
||||||
## Mandatory File Layout (Required For Every Node)
|
|
||||||
- `.agents/function-anchors/<nodeName>/ANCHOR-<nodeName>.md`
|
|
||||||
- `.agents/function-anchors/<nodeName>/ANCHOR-<nodeName>.html`
|
|
||||||
- `.agents/function-anchors/<nodeName>/EVIDENCE-<nodeName>-tests.md`
|
|
||||||
- `nodes/<nodeName>/test/basic/*.test.js`
|
|
||||||
- `nodes/<nodeName>/test/integration/*.test.js`
|
|
||||||
- `nodes/<nodeName>/test/edge/*.test.js`
|
|
||||||
|
|
||||||
Any deviation from this layout must be treated as technical debt and resolved before closing the work item.
|
|
||||||
|
|
||||||
## 1) Connection Map (At a Glance)
|
|
||||||
- **Node type**:
|
|
||||||
- **Consumes from EVOLV nodes/topics**:
|
|
||||||
- **Publishes to EVOLV nodes/topics**:
|
|
||||||
- **Registers as child to**:
|
|
||||||
- **Accepts child registration from**:
|
|
||||||
- **Admin/UI endpoints**:
|
|
||||||
|
|
||||||
## 2) Unit Table (Always First Data Section)
|
|
||||||
| Signal/Field | Represents | Asset Type | Default Unit | Accepted Units | Source of Truth (file:line) | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|---|---|
|
|
||||||
|
|
||||||
## 3) Class Identity
|
|
||||||
- **Class**:
|
|
||||||
- **Primary files**:
|
|
||||||
- **Runtime responsibility**:
|
|
||||||
- **Editor responsibility**:
|
|
||||||
|
|
||||||
## 4) Configuration Contract
|
|
||||||
| UI Field | Runtime Path | Default | Validation/Coercion | Behavior Impact | Source |
|
|
||||||
|---|---|---|---|---|---|
|
|
||||||
|
|
||||||
## 5) Input/Output Contract
|
|
||||||
### Input topics
|
|
||||||
| Topic | Payload schema | Handler | Side effects | Source |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
|
|
||||||
### Output ports
|
|
||||||
| Port | Message type | Producer method | Typical consumers | Source |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
|
|
||||||
### Admin endpoints
|
|
||||||
| Endpoint | Method | Purpose | Source |
|
|
||||||
|---|---|---|---|
|
|
||||||
|
|
||||||
## 6) Mode, State, and Control Model
|
|
||||||
- **Modes**:
|
|
||||||
- **Allowed actions by mode**:
|
|
||||||
- **Allowed sources by mode**:
|
|
||||||
- **Operational states for prediction**:
|
|
||||||
- **Sequence definitions**:
|
|
||||||
|
|
||||||
## 7) End-to-End Execution Flow
|
|
||||||
1. Constructor and initialization flow.
|
|
||||||
2. Registration and child wiring flow.
|
|
||||||
3. Input routing flow.
|
|
||||||
4. Tick/output emission flow.
|
|
||||||
5. Status update flow.
|
|
||||||
|
|
||||||
## 8) Full Function Inventory
|
|
||||||
| Function | Purpose | Reads | Writes | Calls | Emits/Returns | Failure/Fallback | Source | Covered by tests |
|
|
||||||
|---|---|---|---|---|---|---|---|---|
|
|
||||||
|
|
||||||
## 9) Calculations and Physical Semantics
|
|
||||||
- **Prediction paths** (flow, power, control).
|
|
||||||
- **Pressure selection order**.
|
|
||||||
- **Efficiency, CoG, and BEP distance calculations**.
|
|
||||||
- **Assumptions and plausibility constraints**.
|
|
||||||
|
|
||||||
## 10) Error Handling and Safeguards
|
|
||||||
- Validation guards.
|
|
||||||
- Warning/error paths.
|
|
||||||
- Availability-first behavior.
|
|
||||||
|
|
||||||
## 11) Test Evidence Matrix
|
|
||||||
| Test file | What is covered | Methods/contracts anchored |
|
|
||||||
|---|---|---|
|
|
||||||
|
|
||||||
## 12) Invariants (Anchor Truth)
|
|
||||||
- Non-negotiable behaviors this class must preserve.
|
|
||||||
|
|
||||||
## 13) Known Gaps / Risks
|
|
||||||
- Mismatches, TODOs, or technical debt observed in current implementation.
|
|
||||||
|
|
||||||
## 14) Change Checklist
|
|
||||||
- Required updates when logic changes:
|
|
||||||
- Code sections
|
|
||||||
- Contract docs
|
|
||||||
- Tests
|
|
||||||
- Example flows
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>dashboardAPI Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>dashboardAPI Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# dashboardAPI Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: dashboardAPI
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/dashboardAPI/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/dashboardAPI
|
|
||||||
- Node-RED wrapper: nodes/dashboardAPI/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/dashboardAPI/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/dashboardAPI/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# dashboardAPI Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/dashboardAPI/test/basic/*.test.js
|
|
||||||
- nodes/dashboardAPI/test/integration/*.test.js
|
|
||||||
- nodes/dashboardAPI/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/dashboardAPI/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/dashboardAPI/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/dashboardAPI/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>diffuser Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>diffuser Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# diffuser Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: diffuser
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/diffuser/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/diffuser
|
|
||||||
- Node-RED wrapper: nodes/diffuser/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/diffuser/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/diffuser/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# diffuser Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/diffuser/test/basic/*.test.js
|
|
||||||
- nodes/diffuser/test/integration/*.test.js
|
|
||||||
- nodes/diffuser/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/diffuser/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/diffuser/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/diffuser/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>machineGroupControl Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>machineGroupControl Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# machineGroupControl Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: machineGroupControl
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/machineGroupControl/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/machineGroupControl
|
|
||||||
- Node-RED wrapper: nodes/machineGroupControl/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/machineGroupControl/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/machineGroupControl/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# machineGroupControl Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/machineGroupControl/test/basic/*.test.js
|
|
||||||
- nodes/machineGroupControl/test/integration/*.test.js
|
|
||||||
- nodes/machineGroupControl/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/machineGroupControl/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/machineGroupControl/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/machineGroupControl/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>Measurement Anchor Topology</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; color: #1f2937; background: #f7f8fa; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; margin-bottom: 12px; }
|
|
||||||
.topic { font-family: monospace; color: #0f52a5; }
|
|
||||||
ul { margin: 8px 0 0 20px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Measurement Function Anchor</h1>
|
|
||||||
<div class="card">
|
|
||||||
<h2>Topology</h2>
|
|
||||||
<ul>
|
|
||||||
<li><strong>Node:</strong> <code>measurement</code></li>
|
|
||||||
<li><strong>Runtime:</strong> <code>nodes/measurement/src/nodeClass.js</code></li>
|
|
||||||
<li><strong>Domain:</strong> <code>nodes/measurement/src/specificClass.js</code></li>
|
|
||||||
<li><strong>Admin endpoints:</strong> <code>/measurement/menu.js</code>, <code>/measurement/configData.js</code>, <code>/measurement/asset-reg</code></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<h2>Input Topics</h2>
|
|
||||||
<ul>
|
|
||||||
<li><span class="topic">measurement</span> -> set input value when payload is numeric</li>
|
|
||||||
<li><span class="topic">simulator</span> -> toggle simulation mode</li>
|
|
||||||
<li><span class="topic">outlierDetection</span> -> toggle outlier mode flag</li>
|
|
||||||
<li><span class="topic">calibrate</span> -> run calibration logic</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<h2>Output Ports</h2>
|
|
||||||
<ul>
|
|
||||||
<li>Port 0: process message</li>
|
|
||||||
<li>Port 1: influx message</li>
|
|
||||||
<li>Port 2: parent registration (<code>registerChild</code>)</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Measurement Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- **Node type**: `measurement` (`nodes/measurement/measurement.js:1`, `nodes/measurement/measurement.html:14`)
|
|
||||||
- **Consumes topics**: `measurement`, `simulator`, `outlierDetection`, `calibrate` (`nodes/measurement/src/nodeClass.js:147`)
|
|
||||||
- **Publishes periodic outputs**:
|
|
||||||
- Output `0`: process payload (`nodes/measurement/src/nodeClass.js:137`)
|
|
||||||
- Output `1`: influx payload (`nodes/measurement/src/nodeClass.js:138`)
|
|
||||||
- Output `2`: parent registration (`registerChild`) (`nodes/measurement/src/nodeClass.js:118`)
|
|
||||||
- **Cross-node integrations (direct observed)**:
|
|
||||||
- Registers as child to parent with `positionVsParent` and optional `distance` (`nodes/measurement/src/nodeClass.js:118`)
|
|
||||||
- Emits measurement updates through `MeasurementContainer` in `specificClass` (`nodes/measurement/src/specificClass.js:479`)
|
|
||||||
- **Admin/UI endpoints**:
|
|
||||||
- `GET /measurement/menu.js` (`nodes/measurement/measurement.js:23`)
|
|
||||||
- `GET /measurement/configData.js` (`nodes/measurement/measurement.js:33`)
|
|
||||||
- `POST /measurement/asset-reg` (`nodes/measurement/measurement.js:43`)
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| `inputValue` | raw measurement input | asset-dependent | `nodes/measurement/src/specificClass.js:30` | `measurement` topic or simulator | scaling/smoothing pipeline | defaults to `0` |
|
|
||||||
| `outputAbs` (`mAbs`) | processed absolute output | `config.asset.unit` | `nodes/measurement/src/specificClass.js:472` | `updateOutputAbs()` | process/influx outputs + event emitter | constrained to configured abs range |
|
|
||||||
| `outputPercent` (`mPercent`) | normalized percent-like output | `%` semantic | `nodes/measurement/src/specificClass.js:483` | `updateOutputPercent()` | process/influx outputs | interpolated from abs range or observed min/max |
|
|
||||||
| `storedValues` | smoothing window values | same as processed value | `nodes/measurement/src/specificClass.js:24` | `applySmoothing()` | smoothing and repeatability checks | capped to `smoothWindow` length |
|
|
||||||
| `simulation.enabled` | internal simulated signal mode | boolean | `nodes/measurement/src/specificClass.js:52` | config/topic toggle | `tick()` behavior | off by default |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- **Runtime registration + endpoints**: `nodes/measurement/measurement.js`
|
|
||||||
- **Node-RED wrapper/routing**: `nodes/measurement/src/nodeClass.js`
|
|
||||||
- **Domain measurement logic**: `nodes/measurement/src/specificClass.js`
|
|
||||||
- **Editor UI/defaults**: `nodes/measurement/measurement.html`
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
1. Node label precedence can hide fallback text due to expression order:
|
|
||||||
- `return this.positionIcon + " " + this.assetType || "Measurement";` (`nodes/measurement/measurement.html:63`)
|
|
||||||
2. `success` variable is assigned without declaration in editor save path:
|
|
||||||
- `success = window.EVOLV.nodes.measurement.assetMenu.saveEditor(this);` (`nodes/measurement/measurement.html:131`)
|
|
||||||
3. `toggleOutlierDetection()` mutates config object to boolean:
|
|
||||||
- `this.config.outlierDetection = !this.config.outlierDetection;` (`nodes/measurement/src/specificClass.js:503`)
|
|
||||||
4. Input handler ignores numeric strings for `measurement` topic:
|
|
||||||
- accepts only `typeof msg.payload === 'number'` (`nodes/measurement/src/nodeClass.js:152`)
|
|
||||||
|
|
||||||
## 4) Standardization Plan (Mirror RotatingMachine)
|
|
||||||
1. Keep this anchor pair (`.md` + `.html`) and evidence file maintained with behavior changes.
|
|
||||||
2. Maintain test layout under `nodes/measurement/test/`:
|
|
||||||
- `basic/`, `integration/`, `edge/`, `helpers/`
|
|
||||||
3. Maintain examples package under `nodes/measurement/examples/`:
|
|
||||||
- `README.md`, `basic.flow.json`, `integration.flow.json`, `edge.flow.json`
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Required anchor artifacts exist and map to current behavior.
|
|
||||||
- Test suite runs with node-level command.
|
|
||||||
- Example flow files exist and pass flow-structure tests.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Measurement Test Evidence
|
|
||||||
|
|
||||||
Status: baseline suite created and executed.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- `nodes/measurement/test/basic/*.test.js`
|
|
||||||
- `nodes/measurement/test/integration/*.test.js`
|
|
||||||
- `nodes/measurement/test/edge/*.test.js`
|
|
||||||
- `nodes/measurement/test/helpers/*.js`
|
|
||||||
|
|
||||||
## Test-to-Contract Mapping
|
|
||||||
| Test file | Scope | Primary contracts anchored |
|
|
||||||
|---|---|---|
|
|
||||||
| `nodes/measurement/test/basic/specific-constructor.basic.test.js` | constructor baseline and range derivation | `Measurement` constructor |
|
|
||||||
| `nodes/measurement/test/basic/scaling-and-output.basic.test.js` | scaling constraint and output update path | `calculateInput`, `updateOutputAbs`, `getOutput` |
|
|
||||||
| `nodes/measurement/test/basic/nodeclass-routing.basic.test.js` | topic routing and registration output shape | `nodeClass._attachInputHandler`, `_registerChild` |
|
|
||||||
| `nodes/measurement/test/integration/examples-flows.integration.test.js` | example package integrity and expected topic drivers | `nodes/measurement/examples/*.flow.json` |
|
|
||||||
| `nodes/measurement/test/integration/measurement-event.integration.test.js` | measurement container event emission contract | `updateOutputAbs`, measurement emitter wiring |
|
|
||||||
| `nodes/measurement/test/edge/invalid-payload.edge.test.js` | non-numeric input payload ignored behavior | `nodeClass._attachInputHandler` measurement branch |
|
|
||||||
| `nodes/measurement/test/edge/outlier-toggle.edge.test.js` | current outlier toggle behavior capture | `toggleOutlierDetection` |
|
|
||||||
|
|
||||||
## Executed
|
|
||||||
- Command:
|
|
||||||
- `cd nodes/measurement && npm test`
|
|
||||||
- Result:
|
|
||||||
- `pass: baseline suite` (see latest run in session)
|
|
||||||
- Date:
|
|
||||||
- February 19, 2026
|
|
||||||
|
|
||||||
## Known Gaps Captured by Tests
|
|
||||||
- Outlier toggle currently converts config object to boolean.
|
|
||||||
- Measurement topic currently ignores numeric strings.
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Monster Anchor Map</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f7fb;
|
|
||||||
--panel: #ffffff;
|
|
||||||
--line: #9ab0d9;
|
|
||||||
--text: #14233d;
|
|
||||||
--muted: #4d6084;
|
|
||||||
--monster: #4f8582;
|
|
||||||
--sensor: #eef8e8;
|
|
||||||
--api: #fff5e5;
|
|
||||||
--ops: #e9f1ff;
|
|
||||||
}
|
|
||||||
body { margin: 0; font-family: "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
|
||||||
.wrap { max-width: 1100px; margin: 24px auto; padding: 0 16px 24px; }
|
|
||||||
.panel { background: var(--panel); border: 1px solid #dde5f5; border-radius: 12px; padding: 16px; }
|
|
||||||
h1 { margin: 0 0 8px; font-size: 24px; }
|
|
||||||
p { margin: 0 0 12px; color: var(--muted); }
|
|
||||||
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
|
|
||||||
.chip { border: 1px solid #d1ddf5; border-radius: 999px; padding: 4px 10px; background: #f7faff; font-size: 12px; }
|
|
||||||
svg { width: 100%; height: auto; border-radius: 10px; background: #f9fbff; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="wrap">
|
|
||||||
<div class="panel">
|
|
||||||
<h1>Monster Function Anchor</h1>
|
|
||||||
<p>External APIs are orchestrated by surrounding flows; the `monster` node computes sampling state and report fields.</p>
|
|
||||||
<div class="chips">
|
|
||||||
<span class="chip">input: input_q / i_start / monsternametijden / rain_data</span>
|
|
||||||
<span class="chip">output: pulse, m3Total, m3PerPuls, bucketVol, running</span>
|
|
||||||
<span class="chip">report path: Z-Info import + operator m3/pulse reference</span>
|
|
||||||
</div>
|
|
||||||
<svg viewBox="0 0 980 380" role="img" aria-label="Monster integration topology">
|
|
||||||
<defs>
|
|
||||||
<marker id="arr" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
|
|
||||||
<path d="M0,0 L0,6 L9,3 z" fill="#6f85aa"></path>
|
|
||||||
</marker>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<rect x="390" y="150" width="190" height="80" rx="10" fill="var(--monster)"></rect>
|
|
||||||
<text x="485" y="192" text-anchor="middle" fill="#fff" font-size="16">monster</text>
|
|
||||||
|
|
||||||
<rect x="40" y="45" width="220" height="56" rx="9" fill="var(--sensor)" stroke="#b7d89e"></rect>
|
|
||||||
<text x="150" y="79" text-anchor="middle" fill="#2e5a22" font-size="13">PLC/measurement flow input</text>
|
|
||||||
|
|
||||||
<rect x="40" y="290" width="220" height="56" rx="9" fill="var(--api)" stroke="#e9c589"></rect>
|
|
||||||
<text x="150" y="324" text-anchor="middle" fill="#634319" font-size="13">Open-Meteo + Aquon schedule</text>
|
|
||||||
|
|
||||||
<rect x="720" y="45" width="220" height="56" rx="9" fill="var(--ops)" stroke="#aac0ef"></rect>
|
|
||||||
<text x="830" y="79" text-anchor="middle" fill="#244271" font-size="13">Dashboard / Influx / Grafana</text>
|
|
||||||
|
|
||||||
<rect x="720" y="290" width="220" height="56" rx="9" fill="#e7faf5" stroke="#9edcca"></rect>
|
|
||||||
<text x="830" y="324" text-anchor="middle" fill="#1e5244" font-size="13">PLC pulse + Z-Info report tooling</text>
|
|
||||||
|
|
||||||
<line x1="260" y1="73" x2="390" y2="160" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="260" y1="318" x2="390" y2="220" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="580" y1="160" x2="720" y2="75" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="580" y1="220" x2="720" y2="318" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
|
|
||||||
<text x="294" y="125" fill="var(--muted)" font-size="12">input_q / i_start / registerChild</text>
|
|
||||||
<text x="285" y="277" fill="var(--muted)" font-size="12">rain_data / monsternametijden</text>
|
|
||||||
<text x="610" y="124" fill="var(--muted)" font-size="12">process + influx streams</text>
|
|
||||||
<text x="607" y="278" fill="var(--muted)" font-size="12">pulse + m3Total + m3PerPuls</text>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
# Monster Function Anchor (Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- **Node type**: `monster` (`nodes/monster/monster.js:1`, `nodes/monster/monster.html:5`)
|
|
||||||
- **Consumes control/input topics**: `input_q`, `i_start`, `monsternametijden`, `rain_data`, `registerChild` (`nodes/monster/src/nodeClass.js:202`)
|
|
||||||
- **Publishes periodic outputs**:
|
|
||||||
- Output `0`: process payload (`nodes/monster/src/nodeClass.js:185`)
|
|
||||||
- Output `1`: influx payload (`nodes/monster/src/nodeClass.js:186`)
|
|
||||||
- Output `2`: parent registration (`registerChild`) (`nodes/monster/src/nodeClass.js:158`)
|
|
||||||
- **Cross-node integrations**:
|
|
||||||
- Accepts measurement children of type `flow` (`nodes/monster/src/specificClass.js:300`)
|
|
||||||
- Common external orchestration pattern around this node:
|
|
||||||
- Open-Meteo -> `rain_data`
|
|
||||||
- Aquon schedule feed -> `monsternametijden`
|
|
||||||
- PLC/MQTT pulse sink fed by `output.pulse`
|
|
||||||
- Z-Info/report tooling fed by `m3Total` + `m3PerPuls`
|
|
||||||
- Dashboard API/Grafana and Influx consumers
|
|
||||||
- **Admin/UI endpoints**:
|
|
||||||
- `GET /monster/menu.js`
|
|
||||||
- `GET /monster/configData.js` (`nodes/monster/monster.js:17`, `nodes/monster/monster.js:27`)
|
|
||||||
|
|
||||||
## 1) Unit Table (Always First Data Section)
|
|
||||||
| Signal/Field | Represents | Asset Type | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|---|
|
|
||||||
| `input_q.payload.value` | influent flow command | manual/control input | `m3/h` (normalized in wrapper) | `nodes/monster/src/nodeClass.js:216` | upstream control flow | sampling calculation loop | invalid/unit conversion failure is warned and ignored |
|
|
||||||
| `flow.measured.*` | measured flow from child sensors | measurement child | `m3/h` | `nodes/monster/src/specificClass.js:300` | measurement nodes | effective flow selection | if missing, manual flow or 0 is used |
|
|
||||||
| `q` | effective flow used by model | derived | `m3/h` | `nodes/monster/src/specificClass.js:775` | `tick()` | pulse and volume progression | defaults to `0` if no measured/manual flow |
|
|
||||||
| `m3PerPuls` | reporting conversion factor for sampler pulse | derived/report field | `m3/pulse` | `nodes/monster/src/specificClass.js:660` | `sampling_program()` | Z-Info/report tooling, operations | `0` when not running |
|
|
||||||
| `m3Total` | accumulated volume during active run | derived/report field | `m3` | `nodes/monster/src/specificClass.js:687` | `sampling_program()` | Z-Info/report tooling | reset to `0` when sampling window ends |
|
|
||||||
| `pulse` | pulse command signal | control output | boolean | `nodes/monster/src/specificClass.js:707` | `sampling_program()` | PLC/MQTT pulse output paths | forced `false` under cooldown/capacity/end-of-run |
|
|
||||||
| `bucketVol` | sampled bucket fill volume | derived/state | `L` | `nodes/monster/src/specificClass.js:712` | pulse accumulation | dashboard/operator checks | reset to `0` after run |
|
|
||||||
| `predictedRateM3h` | rain-scaled prediction reference | derived | `m3/h` | `nodes/monster/src/specificClass.js:367` | `getOutput()` | dashboards/diagnostics | falls back to measured/manual effective rate |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- **Runtime registration + endpoints**: `nodes/monster/monster.js`
|
|
||||||
- **Node-RED wrapper/routing**: `nodes/monster/src/nodeClass.js`
|
|
||||||
- **Domain sampling logic**: `nodes/monster/src/specificClass.js`
|
|
||||||
- **Editor UI/defaults**: `nodes/monster/monster.html`
|
|
||||||
- **Default config schema**: `nodes/generalFunctions/src/configs/monster.json`
|
|
||||||
|
|
||||||
## 3) Configuration Contract (Key)
|
|
||||||
| UI Field | Runtime Path | Default | Behavior Impact | Source |
|
|
||||||
|---|---|---|---|---|
|
|
||||||
| `samplingtime` | `constraints.samplingtime` | `0` | sampling window hours | `nodes/monster/monster.html:16`, `nodes/monster/src/nodeClass.js:68` |
|
|
||||||
| `minvolume` | `constraints.minVolume` | `5` | min valid sample volume | `nodes/monster/monster.html:17`, `nodes/monster/src/nodeClass.js:69` |
|
|
||||||
| `maxweight` | `constraints.maxWeight` | `22` | max bucket load before invalid sample | `nodes/monster/monster.html:18`, `nodes/monster/src/nodeClass.js:70` |
|
|
||||||
| `nominalFlowMin` / `flowMax` | `constraints.nominalFlowMin` / `constraints.flowMax` | `0` / `0` | prediction bounds and start guard | `nodes/monster/monster.html:19`, `nodes/monster/src/specificClass.js:226` |
|
|
||||||
| `minSampleIntervalSec` | `constraints.minSampleIntervalSec` | `60` | pulse cooldown protection | `nodes/monster/monster.html:22`, `nodes/monster/src/specificClass.js:693` |
|
|
||||||
| `emptyWeightBucket` | `asset.emptyWeightBucket` | `3` | max bucket volume derivation | `nodes/monster/monster.html:23`, `nodes/monster/src/specificClass.js:378` |
|
|
||||||
| `aquon_sample_name` | `aquonSampleName` | `"112100"` internal default | schedule selector key | `nodes/monster/monster.html:24`, `nodes/monster/src/nodeClass.js:96` |
|
|
||||||
|
|
||||||
## 4) I/O and Integration Notes
|
|
||||||
- Node-level output is process/influx/parent only.
|
|
||||||
- External APIs are normally handled by surrounding flows, not by the node class itself.
|
|
||||||
- Report tooling integration should read from process payload fields:
|
|
||||||
- `m3Total`
|
|
||||||
- `m3PerPuls`
|
|
||||||
- `running`
|
|
||||||
- `pulse`
|
|
||||||
- Reference examples:
|
|
||||||
- dashboard baseline: `nodes/monster/examples/monster-dashboard.flow.json`
|
|
||||||
- full API + dashboard template: `nodes/monster/examples/monster-api-dashboard.flow.json`
|
|
||||||
|
|
||||||
## 5) Current Gaps / Risks
|
|
||||||
1. Wrapper exposes topics (`setMode`, `execSequence`, `execMovement`, `flowMovement`, `emergencystop`) that are not implemented in `Monster.handleInput` contract.
|
|
||||||
2. `showWorkingCurves`/`CoG` routes in wrapper call methods that are not present in `Monster`.
|
|
||||||
3. Existing legacy tests were not organized in required `basic/integration/edge` folders before this update.
|
|
||||||
4. External API credentials/tokens must remain outside committed example flows.
|
|
||||||
|
|
||||||
## 6) Test Evidence Matrix (Current Baseline)
|
|
||||||
| Test file | What is covered | Methods/contracts anchored |
|
|
||||||
|---|---|---|
|
|
||||||
| `nodes/monster/test/basic/constructor.basic.test.js` | constructor + output field contract | `constructor`, `set_boundries_and_targets`, `getOutput` |
|
|
||||||
| `nodes/monster/test/integration/flow-and-schedule.integration.test.js` | flow averaging, rain/schedule ingestion | `registerChild`, `handleInput`, `tick`, `updateRainData`, `regNextDate` |
|
|
||||||
| `nodes/monster/test/edge/sampling-guards.edge.test.js` | invalid-bound guard + cooldown behavior | `validateFlowBounds`, `sampling_program`, cooldown gate |
|
|
||||||
|
|
||||||
## 7) Change Checklist
|
|
||||||
- When `monster` behavior changes, update:
|
|
||||||
- `nodes/monster/src/nodeClass.js`
|
|
||||||
- `nodes/monster/src/specificClass.js`
|
|
||||||
- `nodes/monster/monster.html`
|
|
||||||
- `nodes/monster/test/basic|integration|edge/*`
|
|
||||||
- `.agents/function-anchors/monster/ANCHOR-monster.md`
|
|
||||||
- `.agents/function-anchors/monster/ANCHOR-monster.html`
|
|
||||||
- `.agents/function-anchors/monster/EVIDENCE-monster-tests.md`
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Monster Test Evidence
|
|
||||||
|
|
||||||
## Executed Baseline
|
|
||||||
- Command:
|
|
||||||
- `node --test test/basic/*.test.js test/integration/*.test.js test/edge/*.test.js`
|
|
||||||
- Working directory:
|
|
||||||
- `nodes/monster`
|
|
||||||
- Result:
|
|
||||||
- `pass: 6`, `fail: 0`
|
|
||||||
|
|
||||||
## Test Matrix
|
|
||||||
| Test file | Scope | Contracts anchored |
|
|
||||||
|---|---|---|
|
|
||||||
| `nodes/monster/test/basic/constructor.basic.test.js` | initialization and output field contract | constructor, boundary setup, report output fields |
|
|
||||||
| `nodes/monster/test/basic/structure-module-load.basic.test.js` | required structure/module load guard | baseline architecture compliance |
|
|
||||||
| `nodes/monster/test/integration/flow-and-schedule.integration.test.js` | flow aggregation + rain/schedule ingestion | measured/manual flow merge, `handleInput`, schedule update path |
|
|
||||||
| `nodes/monster/test/integration/structure-examples.integration.test.js` | required examples contract guard | example flow presence/shape |
|
|
||||||
| `nodes/monster/test/edge/sampling-guards.edge.test.js` | sampling safety guards | invalid flow bounds guard, cooldown pulse throttling |
|
|
||||||
| `nodes/monster/test/edge/structure-examples-node-type.edge.test.js` | node-type structure guard | example includes `monster` node usage |
|
|
||||||
|
|
||||||
## Coverage Notes
|
|
||||||
- Structure guards now require both dashboard examples:
|
|
||||||
- `nodes/monster/examples/monster-dashboard.flow.json`
|
|
||||||
- `nodes/monster/examples/monster-api-dashboard.flow.json`
|
|
||||||
- Focused on the most operationally critical report fields:
|
|
||||||
- `m3Total`
|
|
||||||
- `m3PerPuls`
|
|
||||||
- `pulse`
|
|
||||||
- `running`
|
|
||||||
- Additional contract tests are still recommended for wrapper topic routes that currently map to unsupported domain handlers.
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>PumpingStation Anchor Map</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f5f7fb;
|
|
||||||
--panel: #ffffff;
|
|
||||||
--line: #9ab0d9;
|
|
||||||
--text: #14233d;
|
|
||||||
--muted: #4d6084;
|
|
||||||
--pump: #0c99d9;
|
|
||||||
--child: #e7faf5;
|
|
||||||
--sensor: #eef8e8;
|
|
||||||
--dash: #fff5e5;
|
|
||||||
}
|
|
||||||
body { margin: 0; font-family: "Segoe UI", sans-serif; background: var(--bg); color: var(--text); }
|
|
||||||
.wrap { max-width: 1100px; margin: 24px auto; padding: 0 16px 24px; }
|
|
||||||
.panel { background: var(--panel); border: 1px solid #dde5f5; border-radius: 12px; padding: 16px; }
|
|
||||||
h1 { margin: 0 0 8px; font-size: 24px; }
|
|
||||||
p { margin: 0 0 12px; color: var(--muted); }
|
|
||||||
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
|
|
||||||
.chip { border: 1px solid #d1ddf5; border-radius: 999px; padding: 4px 10px; background: #f7faff; font-size: 12px; }
|
|
||||||
svg { width: 100%; height: auto; border-radius: 10px; background: #f9fbff; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="wrap">
|
|
||||||
<div class="panel">
|
|
||||||
<h1>PumpingStation Function Anchor</h1>
|
|
||||||
<p>Preparation baseline map. Keep this topology in sync with `ANCHOR-pumpingStation.md` and runtime contracts.</p>
|
|
||||||
<div class="chips">
|
|
||||||
<span class="chip">input: registerChild / calibrate* / q_in / changemode</span>
|
|
||||||
<span class="chip">output[0]: process</span>
|
|
||||||
<span class="chip">output[1]: influx</span>
|
|
||||||
<span class="chip">output[2]: registerChild</span>
|
|
||||||
</div>
|
|
||||||
<svg viewBox="0 0 900 360" role="img" aria-label="PumpingStation integration map">
|
|
||||||
<defs>
|
|
||||||
<marker id="arr" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
|
|
||||||
<path d="M0,0 L0,6 L9,3 z" fill="#6f85aa"></path>
|
|
||||||
</marker>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<rect x="360" y="140" width="180" height="72" rx="10" fill="var(--pump)"></rect>
|
|
||||||
<text x="450" y="182" text-anchor="middle" fill="#fff" font-size="16">pumpingStation</text>
|
|
||||||
|
|
||||||
<rect x="40" y="40" width="210" height="56" rx="9" fill="var(--child)" stroke="#9edcca"></rect>
|
|
||||||
<text x="145" y="74" text-anchor="middle" fill="#1e5244" font-size="13">machine / machineGroupControl</text>
|
|
||||||
|
|
||||||
<rect x="40" y="250" width="210" height="56" rx="9" fill="var(--sensor)" stroke="#b7d89e"></rect>
|
|
||||||
<text x="145" y="284" text-anchor="middle" fill="#2e5a22" font-size="13">measurement (level/flow/pressure)</text>
|
|
||||||
|
|
||||||
<rect x="650" y="40" width="210" height="56" rx="9" fill="var(--dash)" stroke="#e9c589"></rect>
|
|
||||||
<text x="755" y="74" text-anchor="middle" fill="#634319" font-size="13">dashboard / manual control</text>
|
|
||||||
|
|
||||||
<rect x="650" y="250" width="210" height="56" rx="9" fill="#e9f1ff" stroke="#aac0ef"></rect>
|
|
||||||
<text x="755" y="284" text-anchor="middle" fill="#244271" font-size="13">parent process / orchestrator</text>
|
|
||||||
|
|
||||||
<line x1="250" y1="68" x2="360" y2="152" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="250" y1="278" x2="360" y2="198" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="650" y1="68" x2="540" y2="150" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
<line x1="540" y1="202" x2="650" y2="278" stroke="var(--line)" stroke-width="2" marker-end="url(#arr)"></line>
|
|
||||||
|
|
||||||
<text x="268" y="128" fill="var(--muted)" font-size="12">flow.predicted.* / control handoff</text>
|
|
||||||
<text x="260" y="240" fill="var(--muted)" font-size="12">*.measured.<position></text>
|
|
||||||
<text x="566" y="128" fill="var(--muted)" font-size="12">q_in / calibrate / mode</text>
|
|
||||||
<text x="560" y="240" fill="var(--muted)" font-size="12">registerChild + process/influx consumers</text>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# Pumping Station Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- **Node type**: `pumpingStation` (`nodes/pumpingStation/pumpingStation.js:1`, `nodes/pumpingStation/pumpingStation.html:15`)
|
|
||||||
- **Consumes parent/control topics**: `changemode`, `registerChild`, `calibratePredictedVolume`, `calibratePredictedLevel`, `q_in` (`nodes/pumpingStation/src/nodeClass.js:209`)
|
|
||||||
- **Publishes periodic outputs**:
|
|
||||||
- Output `0`: process payload (`nodes/pumpingStation/src/nodeClass.js:197`)
|
|
||||||
- Output `1`: influx payload (`nodes/pumpingStation/src/nodeClass.js:198`)
|
|
||||||
- Output `2`: parent registration/control plumbing (`registerChild`) (`nodes/pumpingStation/src/nodeClass.js:114`)
|
|
||||||
- **Cross-node integrations (direct observed)**:
|
|
||||||
- Registers `measurement` children and listens for `*.measured.<position>` events (`nodes/pumpingStation/src/specificClass.js:73`)
|
|
||||||
- Registers `machine`, `machinegroup`, `pumpingstation` children and listens for predicted flow (`nodes/pumpingStation/src/specificClass.js:59`)
|
|
||||||
- Commands child machines/stations/groups during control/safety transitions (`nodes/pumpingStation/src/specificClass.js:258`, `nodes/pumpingStation/src/specificClass.js:528`)
|
|
||||||
- **Admin/UI endpoints**:
|
|
||||||
- `GET /pumpingStation/menu.js`
|
|
||||||
- `GET /pumpingStation/configData.js` (`nodes/pumpingStation/pumpingStation.js:22`, `nodes/pumpingStation/pumpingStation.js:33`)
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| `flow.measured.*` / `flow.predicted.*` | inflow/outflow streams | `m3/s` preferred | `nodes/pumpingStation/src/specificClass.js:24` | measurement/machine/machinegroup children | net-flow selection + predicted volume integration | falls back to level-rate estimate when unavailable (`nodes/pumpingStation/src/specificClass.js:458`) |
|
|
||||||
| `level.measured.*` / `level.predicted.*` | wet well level | `m` | `nodes/pumpingStation/src/specificClass.js:24` | measurement or pressure conversion path | control decisions + remaining-time estimate | if no level available, remaining time becomes null (`nodes/pumpingStation/src/specificClass.js:487`) |
|
|
||||||
| `volume.predicted.atequipment` | integrated basin volume | `m3` | `nodes/pumpingStation/src/specificClass.js:393` | tick-based integration | safety + status + output | if volume unreadable, station shuts down machines availability-first (`nodes/pumpingStation/src/specificClass.js:503`) |
|
|
||||||
| `volumePercent.*.atequipment` | normalized fill percentage | `%` | `nodes/pumpingStation/src/specificClass.js:424` | level/volume conversion | status + dashboards | not emitted until level/volume is known |
|
|
||||||
| `netFlowRate.*.atequipment` | selected net flow | measured unit or `m3/s` | `nodes/pumpingStation/src/specificClass.js:454` | `_selectBestNetFlow()` | status + remaining-time + safety | defaults to `0` with `steady` direction (`nodes/pumpingStation/src/specificClass.js:466`) |
|
|
||||||
| `timeleft` | estimated seconds to empty/full limit | `s` | `nodes/pumpingStation/src/specificClass.js:470` | `_computeRemainingTime()` | safety logic + output | null if insufficient data |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- **Runtime registration + endpoints**: `nodes/pumpingStation/pumpingStation.js`
|
|
||||||
- **Node-RED wrapper/routing**: `nodes/pumpingStation/src/nodeClass.js`
|
|
||||||
- **Domain/station logic**: `nodes/pumpingStation/src/specificClass.js`
|
|
||||||
- **Editor UI/defaults**: `nodes/pumpingStation/pumpingStation.html`
|
|
||||||
- **Default config schema/validation rules**: `nodes/generalFunctions/src/configs/pumpingStation.json`
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
1. Topic/mode mismatch:
|
|
||||||
- UI default uses `controlMode: "none"` (`nodes/pumpingStation/pumpingStation.html:59`)
|
|
||||||
- runtime switch expects `manual` not `none` (`nodes/pumpingStation/src/specificClass.js:234`)
|
|
||||||
2. Position token mismatch risk:
|
|
||||||
- code mixes `atEquipment` and `atequipment` variants (`nodes/pumpingStation/src/nodeClass.js:122`, `nodes/pumpingStation/src/specificClass.js:103`)
|
|
||||||
3. Child softwareType mismatch risk:
|
|
||||||
- checks for `'pumpingstation'`/`'machinegroup'` lowercase (`nodes/pumpingStation/src/specificClass.js:61`, `nodes/pumpingStation/src/specificClass.js:63`)
|
|
||||||
- other configs generally use camelCase (`nodes/generalFunctions/src/configs/pumpingStation.json:48`)
|
|
||||||
4. Missing guards in input registration path:
|
|
||||||
- no null check after `RED.nodes.getNode` (`nodes/pumpingStation/src/nodeClass.js:217`)
|
|
||||||
5. Test baseline exists but is not yet full parity:
|
|
||||||
- basic/edge/integration scaffolding is present; additional safety/control math coverage is still pending.
|
|
||||||
|
|
||||||
## 4) Standardization Plan (Mirror RotatingMachine)
|
|
||||||
1. Create `ANCHOR-pumpingStation.html` with:
|
|
||||||
- always-visible topology map
|
|
||||||
- unit/signal catalog table
|
|
||||||
- control and safety flow diagram
|
|
||||||
- known invariants and risk list
|
|
||||||
2. Expand the current unit/integration/edge test suite under `nodes/pumpingStation/test/`:
|
|
||||||
- config defaults/overrides
|
|
||||||
- topic routing and child registration
|
|
||||||
- predicted volume integration and remaining-time math
|
|
||||||
- safety triggers and control actions
|
|
||||||
- regression for string casing mismatches and missing child node IDs
|
|
||||||
3. Add evidence companion doc:
|
|
||||||
- `EVIDENCE-pumpingStation-tests.md` with fail-before/pass-after references.
|
|
||||||
4. Keep this anchor and tests updated on every pumpingStation behavior change.
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor markdown complete to template parity with rotatingMachine.
|
|
||||||
- Anchor HTML visualization added and aligned with actual contracts.
|
|
||||||
- Test suite runnable with `node --test nodes/pumpingStation/test/**/*.test.js`.
|
|
||||||
- Evidence file links each test file to anchored behavior.
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# PumpingStation Test Evidence (Preparation)
|
|
||||||
|
|
||||||
Status: baseline suite created and executed.
|
|
||||||
|
|
||||||
## Executed
|
|
||||||
- Command:
|
|
||||||
- `node --test test/basic/*.test.js test/edge/*.test.js test/integration/*.test.js`
|
|
||||||
- Working directory:
|
|
||||||
- `nodes/pumpingStation`
|
|
||||||
- Result:
|
|
||||||
- `pass: 4`, `fail: 0`
|
|
||||||
|
|
||||||
## Planned Test Matrix
|
|
||||||
| Planned test file | Scope | Primary contracts anchored |
|
|
||||||
|---|---|---|
|
|
||||||
| `nodes/pumpingStation/test/basic/constructor.basic.test.js` | config initialization, basin property derivation | constructor, `initBasinProperties`, config defaults |
|
|
||||||
| `nodes/pumpingStation/test/basic/nodeClass-routing.basic.test.js` | topic routing and registration handling | `nodeClass._attachInputHandler`, `registerChild`, calibration topics, `q_in` parsing |
|
|
||||||
| `nodes/pumpingStation/test/integration/registration-normalization.integration.test.js` | softwareType/position normalization and listener dedupe | `registerChild`, `_registerPredictedFlowChild`, `_registerMeasurementChild` |
|
|
||||||
| `nodes/pumpingStation/test/edge/mode-alias.edge.test.js` | mode alias normalization | `_normalizeMode`, `changeMode` compatibility path |
|
|
||||||
| `nodes/pumpingStation/test/integration/flow-balance.integration.test.js` | inflow/outflow aggregation and predicted volume update | `_updatePredictedVolume`, `_selectBestNetFlow`, `_computeRemainingTime` |
|
|
||||||
| `nodes/pumpingStation/test/integration/measurement.integration.test.js` | level/pressure measurement handling and conversions | `_onLevelMeasurement`, `_onPressureMeasurement` |
|
|
||||||
| `nodes/pumpingStation/test/integration/safety.integration.test.js` | dry-run/overfill/time threshold behavior | `_safetyController` |
|
|
||||||
| `nodes/pumpingStation/test/integration/control-levelbased.integration.test.js` | level-based machine command dispatch behavior | `_controlLevelBased`, `_applyMachineLevelControl` |
|
|
||||||
| `nodes/pumpingStation/test/edge/status.edge.test.js` | status output formatting under sparse data | `_updateNodeStatus` |
|
|
||||||
|
|
||||||
## Execution Target
|
|
||||||
- Preferred command (after suite exists): `node --test nodes/pumpingStation/test/**/*.test.js`
|
|
||||||
|
|
||||||
## Coverage Goal
|
|
||||||
- Match rotatingMachine discipline:
|
|
||||||
- config contract coverage
|
|
||||||
- topic routing coverage
|
|
||||||
- control/safety path coverage
|
|
||||||
- regression cases for known risk patterns
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>reactor Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>reactor Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# reactor Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: reactor
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/reactor/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/reactor
|
|
||||||
- Node-RED wrapper: nodes/reactor/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/reactor/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/reactor/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# reactor Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/reactor/test/basic/*.test.js
|
|
||||||
- nodes/reactor/test/integration/*.test.js
|
|
||||||
- nodes/reactor/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/reactor/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/reactor/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/reactor/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,810 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en" data-theme="light">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>EVOLV RotatingMachine Anchor</title>
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg: #f3f6fb;
|
|
||||||
--bg-grad: radial-gradient(circle at 0% 0%, #e8efff 0%, #f3f6fb 42%);
|
|
||||||
--panel: #ffffff;
|
|
||||||
--text: #172435;
|
|
||||||
--muted: #5c6a7c;
|
|
||||||
--line: #d7e0ee;
|
|
||||||
--line-strong: #a9bad7;
|
|
||||||
--blue: #2059d8;
|
|
||||||
--teal: #0d9f9e;
|
|
||||||
--green: #0fa57d;
|
|
||||||
--amber: #cf8a11;
|
|
||||||
--red: #d63f50;
|
|
||||||
--chip: #f7faff;
|
|
||||||
--chip-border: #d4deef;
|
|
||||||
--mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
||||||
--sans: "Segoe UI", "Avenir Next", "Helvetica Neue", Arial, sans-serif;
|
|
||||||
--shadow: 0 8px 24px rgba(14, 25, 42, 0.08);
|
|
||||||
--radius: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[data-theme="dark"] {
|
|
||||||
--bg: #0d1420;
|
|
||||||
--bg-grad: radial-gradient(circle at 0% 0%, #1a2538 0%, #0d1420 44%);
|
|
||||||
--panel: #131c2a;
|
|
||||||
--text: #e6edf9;
|
|
||||||
--muted: #9eb0cb;
|
|
||||||
--line: #26344a;
|
|
||||||
--line-strong: #355079;
|
|
||||||
--blue: #4b86ff;
|
|
||||||
--teal: #25c9c4;
|
|
||||||
--green: #24c794;
|
|
||||||
--amber: #e9ad42;
|
|
||||||
--red: #ff6f7b;
|
|
||||||
--chip: #172234;
|
|
||||||
--chip-border: #324968;
|
|
||||||
--shadow: 0 8px 24px rgba(0, 0, 0, 0.34);
|
|
||||||
}
|
|
||||||
|
|
||||||
* { box-sizing: border-box; }
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
background: var(--bg-grad), var(--bg);
|
|
||||||
color: var(--text);
|
|
||||||
font-family: var(--sans);
|
|
||||||
line-height: 1.42;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrap { max-width: 1240px; margin: 0 auto; padding: 18px; }
|
|
||||||
|
|
||||||
.toolbar {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
border: 1px solid var(--line-strong);
|
|
||||||
background: var(--panel);
|
|
||||||
color: var(--text);
|
|
||||||
padding: 7px 11px;
|
|
||||||
border-radius: 9px;
|
|
||||||
font-size: 0.82rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.15s ease, border-color 0.15s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover { border-color: var(--blue); }
|
|
||||||
.btn.active { background: var(--blue); color: #fff; border-color: var(--blue); }
|
|
||||||
|
|
||||||
.hero {
|
|
||||||
background: linear-gradient(128deg, #1e47ac 0%, #1f5ad6 48%, #1a8eb9 100%);
|
|
||||||
color: #fff;
|
|
||||||
border-radius: var(--radius);
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
padding: 20px;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1.4fr 1fr;
|
|
||||||
gap: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero h1 { margin: 0 0 7px; font-size: 1.58rem; letter-spacing: 0.2px; }
|
|
||||||
.hero p { margin: 0; opacity: 0.94; font-size: 0.93rem; }
|
|
||||||
|
|
||||||
.badge-row { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 7px; }
|
|
||||||
.badge {
|
|
||||||
padding: 4px 9px;
|
|
||||||
border: 1px solid rgba(255,255,255,0.3);
|
|
||||||
background: rgba(255,255,255,0.12);
|
|
||||||
border-radius: 999px;
|
|
||||||
font-size: 0.77rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, minmax(0,1fr));
|
|
||||||
gap: 8px;
|
|
||||||
align-content: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric {
|
|
||||||
border: 1px solid rgba(255,255,255,0.28);
|
|
||||||
background: rgba(255,255,255,0.13);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metric .k { font-size: 0.7rem; text-transform: uppercase; opacity: 0.86; letter-spacing: 0.45px; }
|
|
||||||
.metric .v { font-size: 1rem; font-weight: 700; margin-top: 2px; }
|
|
||||||
|
|
||||||
.grid { margin-top: 14px; display: grid; gap: 12px; }
|
|
||||||
|
|
||||||
.panel {
|
|
||||||
background: var(--panel);
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: var(--shadow);
|
|
||||||
padding: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel h2 { margin: 0 0 10px; font-size: 1.03rem; }
|
|
||||||
.muted { color: var(--muted); font-size: 0.84rem; }
|
|
||||||
|
|
||||||
.split { display: grid; grid-template-columns: 1.2fr 1fr; gap: 12px; }
|
|
||||||
|
|
||||||
.chip-list { display: flex; flex-wrap: wrap; gap: 7px; }
|
|
||||||
.chip {
|
|
||||||
border: 1px solid var(--chip-border);
|
|
||||||
background: var(--chip);
|
|
||||||
color: var(--text);
|
|
||||||
border-radius: 999px;
|
|
||||||
font-size: 0.77rem;
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kpi-cards {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, minmax(0,1fr));
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kpi {
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 10px;
|
|
||||||
background: var(--panel);
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.kpi .label { color: var(--muted); font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.38px; }
|
|
||||||
.kpi .value { font-size: 1.15rem; font-weight: 700; margin-top: 4px; }
|
|
||||||
|
|
||||||
.table-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
|
|
||||||
|
|
||||||
table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
|
|
||||||
th, td {
|
|
||||||
text-align: left;
|
|
||||||
vertical-align: top;
|
|
||||||
border-bottom: 1px solid var(--line);
|
|
||||||
border-right: 1px solid color-mix(in srgb, var(--line) 82%, transparent);
|
|
||||||
padding: 7px 6px;
|
|
||||||
}
|
|
||||||
th:last-child, td:last-child { border-right: 0; }
|
|
||||||
th {
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 0.75rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.35px;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.group-row td {
|
|
||||||
background: color-mix(in srgb, var(--panel) 80%, var(--line));
|
|
||||||
color: var(--text);
|
|
||||||
font-weight: 700;
|
|
||||||
border-bottom: 1px solid var(--line-strong);
|
|
||||||
border-top: 1px solid var(--line-strong);
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 0.72rem;
|
|
||||||
letter-spacing: 0.45px;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: var(--mono);
|
|
||||||
background: color-mix(in srgb, var(--blue) 10%, transparent);
|
|
||||||
color: var(--text);
|
|
||||||
border-radius: 6px;
|
|
||||||
padding: 1px 5px;
|
|
||||||
font-size: 0.76rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.svg-box {
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
background: color-mix(in srgb, var(--panel) 92%, var(--line));
|
|
||||||
}
|
|
||||||
|
|
||||||
.graph-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
|
|
||||||
|
|
||||||
.timeline { display: grid; gap: 8px; }
|
|
||||||
.step { display: grid; grid-template-columns: 28px 1fr; gap: 8px; align-items: start; }
|
|
||||||
.dot {
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 999px;
|
|
||||||
color: #fff;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
font-size: 0.78rem;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
.d1 { background: var(--blue); }
|
|
||||||
.d2 { background: var(--teal); }
|
|
||||||
.d3 { background: var(--amber); }
|
|
||||||
.d4 { background: var(--green); }
|
|
||||||
|
|
||||||
details {
|
|
||||||
border: 1px solid var(--line);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 8px 10px;
|
|
||||||
background: color-mix(in srgb, var(--panel) 96%, var(--line));
|
|
||||||
}
|
|
||||||
|
|
||||||
details + details { margin-top: 8px; }
|
|
||||||
summary {
|
|
||||||
cursor: pointer;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--text);
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.risk {
|
|
||||||
border-left: 4px solid var(--amber);
|
|
||||||
background: color-mix(in srgb, var(--amber) 10%, transparent);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 8px 10px;
|
|
||||||
margin-top: 7px;
|
|
||||||
font-size: 0.82rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.risk.ok { border-left-color: var(--green); background: color-mix(in srgb, var(--green) 10%, transparent); }
|
|
||||||
.risk.bad { border-left-color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
|
|
||||||
|
|
||||||
.foot {
|
|
||||||
font-size: 0.76rem;
|
|
||||||
color: var(--muted);
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1040px) {
|
|
||||||
.hero, .split, .graph-grid { grid-template-columns: 1fr; }
|
|
||||||
.kpi-cards { grid-template-columns: repeat(2, minmax(0,1fr)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
|
||||||
.kpi-cards { grid-template-columns: 1fr; }
|
|
||||||
.table-tools { flex-wrap: wrap; }
|
|
||||||
table { font-size: 0.78rem; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main class="wrap">
|
|
||||||
<div class="toolbar">
|
|
||||||
<button id="themeToggle" class="btn" type="button">Toggle Dark Mode</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section class="hero">
|
|
||||||
<div>
|
|
||||||
<h1>RotatingMachine Engineering Anchor</h1>
|
|
||||||
<p>Function-design truth source for runtime behavior, control contracts, units/signals, and integration boundaries.</p>
|
|
||||||
<div class="badge-row">
|
|
||||||
<span class="badge">Node Type: <code>rotatingMachine</code></span>
|
|
||||||
<span class="badge">Domain Class: <code>specificClass.js</code></span>
|
|
||||||
<span class="badge">Wrapper: <code>nodeClass.js</code></span>
|
|
||||||
<span class="badge">Ports: <code>3</code></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="metric-grid">
|
|
||||||
<div class="metric"><div class="k">Control Topics In</div><div class="v">9</div></div>
|
|
||||||
<div class="metric"><div class="k">Signal Rows Catalogued</div><div class="v">31</div></div>
|
|
||||||
<div class="metric"><div class="k">Anchored Tests</div><div class="v">9</div></div>
|
|
||||||
<div class="metric"><div class="k">Known Risks</div><div class="v">4</div></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="grid">
|
|
||||||
<section class="panel">
|
|
||||||
<h2>Connection Map (Always Visible)</h2>
|
|
||||||
<div class="split">
|
|
||||||
<div>
|
|
||||||
<div class="muted">Primary integrations and contracts</div>
|
|
||||||
<div class="chip-list" style="margin-top:8px; margin-bottom:10px">
|
|
||||||
<span class="chip">machineGroupControl -> parent command source</span>
|
|
||||||
<span class="chip">pumpingStation -> orchestration source</span>
|
|
||||||
<span class="chip">measurement -> real pressure child via registerChild</span>
|
|
||||||
<span class="chip">dashboard flows -> simulateMeasurement + chart consumers</span>
|
|
||||||
<span class="chip">output[2] -> registerChild to parent</span>
|
|
||||||
<span class="chip">/rotatingMachine/menu.js</span>
|
|
||||||
<span class="chip">/rotatingMachine/configData.js</span>
|
|
||||||
</div>
|
|
||||||
<div class="kpi-cards">
|
|
||||||
<div class="kpi"><div class="label">Pressure Policy</div><div class="value">Real > Virtual > 0</div></div>
|
|
||||||
<div class="kpi"><div class="label">Mode Gate</div><div class="value">Action + Source</div></div>
|
|
||||||
<div class="kpi"><div class="label">Tick Rate</div><div class="value">1s</div></div>
|
|
||||||
<div class="kpi"><div class="label">Operational States</div><div class="value">4 Active</div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="svg-box">
|
|
||||||
<svg viewBox="0 0 540 230" width="100%" role="img" aria-label="integration topology">
|
|
||||||
<defs>
|
|
||||||
<marker id="arr" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
|
|
||||||
<path d="M0,0 L0,6 L9,3 z" fill="#6f85aa"></path>
|
|
||||||
</marker>
|
|
||||||
</defs>
|
|
||||||
<rect x="200" y="86" width="140" height="52" rx="10" fill="#2059d8"/>
|
|
||||||
<text x="270" y="117" text-anchor="middle" fill="#fff" font-size="13" font-family="Segoe UI">rotatingMachine</text>
|
|
||||||
|
|
||||||
<rect x="18" y="20" width="160" height="44" rx="9" fill="#e9f1ff" stroke="#aac0ef"/>
|
|
||||||
<text x="98" y="46" text-anchor="middle" fill="#244271" font-size="12">machineGroupControl</text>
|
|
||||||
|
|
||||||
<rect x="18" y="164" width="160" height="44" rx="9" fill="#e7faf5" stroke="#9edcca"/>
|
|
||||||
<text x="98" y="190" text-anchor="middle" fill="#1e5244" font-size="12">pumpingStation</text>
|
|
||||||
|
|
||||||
<rect x="360" y="24" width="160" height="44" rx="9" fill="#fff5e5" stroke="#e9c589"/>
|
|
||||||
<text x="440" y="50" text-anchor="middle" fill="#634319" font-size="12">dashboard / examples</text>
|
|
||||||
|
|
||||||
<rect x="360" y="156" width="160" height="44" rx="9" fill="#eef8e8" stroke="#b7d89e"/>
|
|
||||||
<text x="440" y="182" text-anchor="middle" fill="#2e5a22" font-size="12">measurement</text>
|
|
||||||
|
|
||||||
<line x1="178" y1="44" x2="200" y2="96" stroke="#6f85aa" stroke-width="2" marker-end="url(#arr)"/>
|
|
||||||
<line x1="178" y1="186" x2="200" y2="130" stroke="#6f85aa" stroke-width="2" marker-end="url(#arr)"/>
|
|
||||||
<line x1="360" y1="45" x2="338" y2="97" stroke="#6f85aa" stroke-width="2" marker-end="url(#arr)"/>
|
|
||||||
<line x1="341" y1="130" x2="360" y2="50" stroke="#8ea4c8" stroke-dasharray="4 4" stroke-width="2" marker-end="url(#arr)"/>
|
|
||||||
<line x1="360" y1="178" x2="340" y2="126" stroke="#6f85aa" stroke-width="2" marker-end="url(#arr)"/>
|
|
||||||
|
|
||||||
<text x="184" y="66" fill="#5c7091" font-size="11">setMode / exec*</text>
|
|
||||||
<text x="182" y="162" fill="#5c7091" font-size="11">station-level dispatch</text>
|
|
||||||
<text x="334" y="78" fill="#5c7091" font-size="11">simulateMeasurement</text>
|
|
||||||
<text x="350" y="94" fill="#5c7091" font-size="11">process + influx out</text>
|
|
||||||
<text x="342" y="168" fill="#5c7091" font-size="11">registerChild + pressure.measured.*</text>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel">
|
|
||||||
<h2>Engineering Unit & Signal Catalog</h2>
|
|
||||||
<div class="table-tools">
|
|
||||||
<button id="btnInput" class="btn active" type="button">Input</button>
|
|
||||||
<button id="btnOutput" class="btn" type="button">Output</button>
|
|
||||||
<span class="muted" id="tableMeta">Showing input topics/signals grouped by engineering function.</span>
|
|
||||||
</div>
|
|
||||||
<table id="signalTable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Group</th>
|
|
||||||
<th>Signal / Topic</th>
|
|
||||||
<th>Direction</th>
|
|
||||||
<th>Unit</th>
|
|
||||||
<th>Typical Range</th>
|
|
||||||
<th>Criticality</th>
|
|
||||||
<th>Meaning</th>
|
|
||||||
<th>Primary Source</th>
|
|
||||||
<th>Conversion Hints</th>
|
|
||||||
<th>Fallback / Notes</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody></tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel">
|
|
||||||
<h2>Functional Parameter Sheet (Template + Example)</h2>
|
|
||||||
<div class="muted">Engineering-oriented parameter table for BEP/curve/mechanical context. Example values are placeholders and scenario-dependent.</div>
|
|
||||||
<table id="paramTable" style="margin-top:10px">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Parameter</th>
|
|
||||||
<th>Symbool</th>
|
|
||||||
<th>Eenheid</th>
|
|
||||||
<th>Waarde (+/-)</th>
|
|
||||||
<th>Toelichting</th>
|
|
||||||
<th>Node Mapping</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="paramBody"></tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel">
|
|
||||||
<h2>True Graphs (Data-Derived)</h2>
|
|
||||||
<div class="muted">Curves below are drawn from repository data in <code>nodes/rotatingMachine/misc/measured_curve.json</code> (pressure slice <code>175</code>), plus derived efficiency ratio.</div>
|
|
||||||
<div class="graph-grid" style="margin-top:10px">
|
|
||||||
<div class="svg-box">
|
|
||||||
<div class="muted" style="margin-bottom:6px">Flow vs Control (pressure=175)</div>
|
|
||||||
<svg id="flowChart" viewBox="0 0 520 280" width="100%" role="img" aria-label="flow vs control"></svg>
|
|
||||||
</div>
|
|
||||||
<div class="svg-box">
|
|
||||||
<div class="muted" style="margin-bottom:6px">Power vs Control (pressure=175)</div>
|
|
||||||
<svg id="powerChart" viewBox="0 0 520 280" width="100%" role="img" aria-label="power vs control"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="graph-grid" style="margin-top:10px">
|
|
||||||
<div class="svg-box">
|
|
||||||
<div class="muted" style="margin-bottom:6px">Derived Efficiency Index (flow/power) vs Control</div>
|
|
||||||
<svg id="effChart" viewBox="0 0 520 280" width="100%" role="img" aria-label="efficiency index vs control"></svg>
|
|
||||||
</div>
|
|
||||||
<div class="svg-box">
|
|
||||||
<div class="muted" style="margin-bottom:6px">Allowed Actions by Mode (config defaults)</div>
|
|
||||||
<svg id="modeChart" viewBox="0 0 520 280" width="100%" role="img" aria-label="allowed actions by mode"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel">
|
|
||||||
<h2>Execution Flow (Core Open)</h2>
|
|
||||||
<div class="timeline">
|
|
||||||
<div class="step"><div class="dot d1">1</div><div><strong>Construct</strong><div class="muted">Load defaults and model, initialize predictors/state/measurement containers, attach state listeners.</div></div></div>
|
|
||||||
<div class="step"><div class="dot d2">2</div><div><strong>Connect</strong><div class="muted">Register virtual pressure children, listen to real/virtual measurement streams, register self to parent.</div></div></div>
|
|
||||||
<div class="step"><div class="dot d3">3</div><div><strong>Control</strong><div class="muted">Route topics, validate mode/source/action, execute movement or sequence transitions.</div></div></div>
|
|
||||||
<div class="step"><div class="dot d4">4</div><div><strong>Compute + Emit</strong><div class="muted">Pressure basis selection -> flow/power prediction -> efficiency/CoG/BEP -> output formatting and status update.</div></div></div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="panel">
|
|
||||||
<h2>Extended Sections (Selective Collapse)</h2>
|
|
||||||
<details>
|
|
||||||
<summary>Function Inventory Snapshot</summary>
|
|
||||||
<div class="muted" style="margin-top:8px">Anchored files: <code>rotatingMachine.js</code>, <code>src/nodeClass.js</code>, <code>src/specificClass.js</code>. 44+ callable methods/paths inventoried in markdown anchor.</div>
|
|
||||||
<div class="chip-list" style="margin-top:8px">
|
|
||||||
<span class="chip">constructor + init</span>
|
|
||||||
<span class="chip">registerChild + handler dispatch</span>
|
|
||||||
<span class="chip">handleInput + setMode + sequences</span>
|
|
||||||
<span class="chip">calcFlow/calcPower/calcCtrl</span>
|
|
||||||
<span class="chip">calcEfficiency + calcCog + getOutput</span>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Risks And Invariants</summary>
|
|
||||||
<div class="risk bad"><strong>Risk:</strong> <code>CoG</code> input path calls <code>showCoG()</code> but method is not present in current <code>specificClass.js</code>.</div>
|
|
||||||
<div class="risk bad"><strong>Risk:</strong> emergency sequence key mismatch (<code>emergencyStop</code> vs config <code>emergencystop</code>).</div>
|
|
||||||
<div class="risk"><strong>Risk:</strong> <code>eneableLog</code> typo in state logging mapping.</div>
|
|
||||||
<div class="risk"><strong>Risk:</strong> node label expression precedence may render unexpected labels.</div>
|
|
||||||
<div class="risk ok"><strong>Invariant:</strong> mechanical truth remains in <code>specificClass.js</code>; wrapper remains routing/lifecycle.</div>
|
|
||||||
<div class="risk ok"><strong>Invariant:</strong> pressure selection order stays real sensor > virtual sensor > fallback 0.</div>
|
|
||||||
<div class="risk ok"><strong>Invariant:</strong> output channels remain process/influx/parent registration separation.</div>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Test Evidence</summary>
|
|
||||||
<div class="chip-list" style="margin-top:8px">
|
|
||||||
<span class="chip">constructor.basic.test.js</span>
|
|
||||||
<span class="chip">mode-and-input.basic.test.js</span>
|
|
||||||
<span class="chip">error-paths.edge.test.js</span>
|
|
||||||
<span class="chip">nodeClass-routing.edge.test.js</span>
|
|
||||||
<span class="chip">sequences.integration.test.js</span>
|
|
||||||
<span class="chip">registration.integration.test.js</span>
|
|
||||||
<span class="chip">pressure-initialization.integration.test.js</span>
|
|
||||||
<span class="chip">coolprop.integration.test.js</span>
|
|
||||||
<span class="chip">basic-flow-dashboard.integration.test.js</span>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<div class="foot">
|
|
||||||
Iteration 3: engineering-grade signal table (ranges, criticality, conversion hints), functional parameter sheet, input/output filters, dark mode toggle, selective collapsible sections, and data-derived graphs.
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
(function () {
|
|
||||||
const signalRows = [
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:registerChild", unit: "n/a", meaning: "Attach child node source by node id", source: "nodeClass.js:268", notes: "Warns if child/source not found" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:setMode", unit: "enum", meaning: "Set current command policy mode", source: "nodeClass.js:278", notes: "Validated by setMode()" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:execSequence", unit: "json payload", meaning: "Execute named transition sequence", source: "nodeClass.js:281", notes: "Mode + source gated" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:execMovement", unit: "json payload", meaning: "Move to explicit setpoint", source: "nodeClass.js:285", notes: "Setpoint coerced to Number" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:flowMovement", unit: "json payload", meaning: "Convert desired flow to control setpoint", source: "nodeClass.js:289", notes: "Uses calcCtrl()" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:emergencystop", unit: "json payload", meaning: "Emergency stop command path", source: "nodeClass.js:294", notes: "Sequence-name mismatch risk in logic" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:simulateMeasurement", unit: "json payload", meaning: "Inject measured values from dashboard/test flow", source: "nodeClass.js:298", notes: "Finite numeric value required" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:showWorkingCurves", unit: "n/a", meaning: "Request current curve and CoG diagnostics", source: "nodeClass.js:336", notes: "Immediate response on output[0]" },
|
|
||||||
{ dir: "input", group: "Control Topic", signal: "topic:CoG", unit: "n/a", meaning: "Request CoG diagnostics", source: "nodeClass.js:339", notes: "Calls showCoG() method" },
|
|
||||||
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "pressure.measured.upstream", unit: "mbar (default)", meaning: "Upstream pressure input", source: "specificClass.js:52,703", notes: "Real child preferred over virtual" },
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "pressure.measured.downstream", unit: "mbar (default)", meaning: "Downstream pressure input", source: "specificClass.js:52,703", notes: "Combined with upstream for differential" },
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "flow.measured.upstream", unit: "config general.unit", meaning: "Measured inflow reference", source: "specificClass.js:727", notes: "Used for reconciliation when present" },
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "flow.measured.downstream", unit: "config general.unit", meaning: "Measured discharge reference", source: "specificClass.js:727", notes: "Accepted only in operational states" },
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "temperature.measured.atEquipment", unit: "C (init), K used", meaning: "Fluid temperature for density/efficiency path", source: "specificClass.js:149,858", notes: "Starts at 15 C" },
|
|
||||||
{ dir: "input", group: "Measured Signal", signal: "power.measured.atEquipment", unit: "kW", meaning: "Measured power if provided by child", source: "specificClass.js:686", notes: "Read helper exists" },
|
|
||||||
|
|
||||||
{ dir: "output", group: "Port Contract", signal: "output[0]", unit: "process msg", meaning: "Process payload from flattened output", source: "nodeClass.js:250", notes: "Formatted by outputUtils" },
|
|
||||||
{ dir: "output", group: "Port Contract", signal: "output[1]", unit: "influx msg", meaning: "InfluxDB payload", source: "nodeClass.js:251", notes: "Formatted by outputUtils" },
|
|
||||||
{ dir: "output", group: "Port Contract", signal: "output[2]", unit: "registerChild msg", meaning: "Parent registration plumbing", source: "nodeClass.js:222", notes: "Topic registerChild" },
|
|
||||||
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "flow.predicted.downstream", unit: "config general.unit", meaning: "Predicted discharge flow", source: "specificClass.js:423", notes: "0 when inactive/no curve" },
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "flow.predicted.atEquipment", unit: "config general.unit", meaning: "Predicted flow at equipment", source: "specificClass.js:424", notes: "0 when inactive/no curve" },
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "flow.predicted.min", unit: "config general.unit", meaning: "Curve min flow at current pressure", source: "specificClass.js:156", notes: "Seeded in init/fallback paths" },
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "flow.predicted.max", unit: "config general.unit", meaning: "Curve max flow at current pressure", source: "specificClass.js:155", notes: "Seeded in init/fallback paths" },
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "power.predicted.atEquipment", unit: "kW", meaning: "Predicted power draw", source: "specificClass.js:448", notes: "0 when inactive/no curve" },
|
|
||||||
{ dir: "output", group: "Predicted Signal", signal: "ctrl.predicted.atEquipment", unit: "unitless (%)", meaning: "Predicted control setpoint", source: "specificClass.js:482", notes: "From requested flow" },
|
|
||||||
|
|
||||||
{ dir: "output", group: "Derived KPI", signal: "efficiency.predicted.atEquipment", unit: "flow/power ratio", meaning: "Specific flow proxy", source: "specificClass.js:881", notes: "Computed when power and flow non-zero" },
|
|
||||||
{ dir: "output", group: "Derived KPI", signal: "specificEnergyConsumption.predicted.atEquipment", unit: "power/flow", meaning: "Specific energy proxy", source: "specificClass.js:882", notes: "Computed when power and flow non-zero" },
|
|
||||||
{ dir: "output", group: "Derived KPI", signal: "nHydraulicEfficiency.predicted.atEquipment", unit: "unitless", meaning: "Hydraulic-efficiency-like metric", source: "specificClass.js:887", notes: "Uses pressure diff + density + conversions" },
|
|
||||||
{ dir: "output", group: "Derived KPI", signal: "cog / NCog / NCogPercent", unit: "unitless / %", meaning: "Best efficiency operating index", source: "specificClass.js:796,950", notes: "Used by higher-level optimization" },
|
|
||||||
{ dir: "output", group: "Derived KPI", signal: "effDistFromPeak / effRelDistFromPeak", unit: "unitless", meaning: "Distance from best-efficiency point", source: "specificClass.js:924,962", notes: "Absolute + relative" },
|
|
||||||
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "state", unit: "enum", meaning: "Current movement/state-machine state", source: "specificClass.js:943", notes: "Exposed in output object" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "mode", unit: "enum", meaning: "Current command mode", source: "specificClass.js:947", notes: "auto/virtualControl/fysicalControl" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "ctrl", unit: "%", meaning: "Current position setpoint", source: "specificClass.js:945", notes: "From state module" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "runtime", unit: "h", meaning: "Accumulated runtime", source: "specificClass.js:944", notes: "From state module" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "moveTimeleft", unit: "s", meaning: "Time remaining for movement", source: "specificClass.js:946", notes: "From state module" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "maintenanceTime", unit: "h", meaning: "Maintenance counter", source: "specificClass.js:951", notes: "From state module" },
|
|
||||||
{ dir: "output", group: "Runtime State", signal: "flowNrmse / flowLongterNRMSD / flowImmediateLevel / flowLongTermLevel", unit: "mixed", meaning: "Drift diagnostics when available", source: "specificClass.js:953", notes: "Present only when flowDrift exists" }
|
|
||||||
];
|
|
||||||
|
|
||||||
const tbody = document.querySelector("#signalTable tbody");
|
|
||||||
const btnInput = document.getElementById("btnInput");
|
|
||||||
const btnOutput = document.getElementById("btnOutput");
|
|
||||||
const tableMeta = document.getElementById("tableMeta");
|
|
||||||
const paramBody = document.getElementById("paramBody");
|
|
||||||
let activeDir = "input";
|
|
||||||
|
|
||||||
function inferTypicalRange(r) {
|
|
||||||
if (r.signal.indexOf("pressure.measured.upstream") >= 0) return "200-1500 mbar";
|
|
||||||
if (r.signal.indexOf("pressure.measured.downstream") >= 0) return "400-2500 mbar";
|
|
||||||
if (r.signal.indexOf("flow.measured") >= 0) return "0-2.5 m3/s or project unit";
|
|
||||||
if (r.signal.indexOf("flow.predicted") >= 0) return "Curve-bound min-max";
|
|
||||||
if (r.signal.indexOf("power.measured") >= 0) return "0-250 kW";
|
|
||||||
if (r.signal.indexOf("power.predicted") >= 0) return "Curve-bound min-max";
|
|
||||||
if (r.signal.indexOf("temperature.measured") >= 0) return "5-40 C (278-313 K)";
|
|
||||||
if (r.signal.indexOf("ctrl") >= 0) return "0-100% (project may scale)";
|
|
||||||
if (r.signal.indexOf("runtime") >= 0 || r.signal.indexOf("maintenanceTime") >= 0) return "0+ h";
|
|
||||||
if (r.signal.indexOf("moveTimeleft") >= 0) return "0+ s";
|
|
||||||
if (r.signal.indexOf("efficiency") >= 0 || r.signal.indexOf("nHydraulicEfficiency") >= 0) return "0-1+ (index)";
|
|
||||||
if (r.signal.indexOf("NCog") >= 0 || r.signal.indexOf("cog") >= 0) return "0-1 (NCog), 0-100% (NCogPercent)";
|
|
||||||
if (r.group === "Control Topic") return "Discrete commands";
|
|
||||||
if (r.group === "Port Contract") return "Per tick / event message";
|
|
||||||
return "Project-specific";
|
|
||||||
}
|
|
||||||
|
|
||||||
function inferCriticality(r) {
|
|
||||||
if (r.signal.indexOf("emergencystop") >= 0) return "High";
|
|
||||||
if (r.signal.indexOf("setMode") >= 0 || r.signal.indexOf("execSequence") >= 0 || r.signal.indexOf("execMovement") >= 0 || r.signal.indexOf("flowMovement") >= 0) return "High";
|
|
||||||
if (r.signal.indexOf("pressure.measured") >= 0) return "High";
|
|
||||||
if (r.signal.indexOf("power.predicted") >= 0 || r.signal.indexOf("flow.predicted") >= 0 || r.signal.indexOf("output[") >= 0) return "High";
|
|
||||||
if (r.signal.indexOf("temperature.measured") >= 0 || r.signal.indexOf("power.measured") >= 0) return "Medium";
|
|
||||||
if (r.signal.indexOf("efficiency") >= 0 || r.signal.indexOf("NCog") >= 0 || r.signal.indexOf("flowNrmse") >= 0) return "Medium";
|
|
||||||
if (r.signal.indexOf("showWorkingCurves") >= 0 || r.signal.indexOf("CoG") >= 0) return "Low";
|
|
||||||
return "Medium";
|
|
||||||
}
|
|
||||||
|
|
||||||
function inferConversionHints(r) {
|
|
||||||
if (r.signal.indexOf("pressure") >= 0) return "mbar <-> Pa (1 mbar = 100 Pa)";
|
|
||||||
if (r.signal.indexOf("flow") >= 0) return "m3/h <-> m3/s (divide/multiply by 3600); l/s <-> m3/s (x/1000)";
|
|
||||||
if (r.signal.indexOf("power") >= 0) return "kW <-> W (x1000)";
|
|
||||||
if (r.signal.indexOf("temperature") >= 0) return "C <-> K (+/-273.15)";
|
|
||||||
if (r.signal.indexOf("ctrl") >= 0) return "Unitless ratio <-> % (x100)";
|
|
||||||
if (r.signal.indexOf("runtime") >= 0 || r.signal.indexOf("maintenanceTime") >= 0) return "h <-> s (x3600)";
|
|
||||||
return "No conversion required / message contract";
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderParameterSheet() {
|
|
||||||
const params = [
|
|
||||||
{ p: "Nominaal toerental", s: "n", u: "t/min", v: "1477 (voorbeeld)", t: "50 Hz in bedrijf", m: "Not directly output; machine/asset datasheet parameter" },
|
|
||||||
{ p: "Debiet bij BEP", s: "Q", u: "L/s", v: "86 (voorbeeld)", t: "Beste efficientiepunt", m: "Derivable from curve + CoG/efficiency path" },
|
|
||||||
{ p: "Opvoerhoogte", s: "H", u: "m", v: "11 (voorbeeld)", t: "Bij Q = 86 L/s", m: "Related to pressure differential conversion path" },
|
|
||||||
{ p: "Opgenomen vermogen", s: "P2", u: "kW", v: "13-15 (voorbeeld)", t: "Inclusief mechanische verliezen", m: "output: power.predicted.atEquipment / measured power path" },
|
|
||||||
{ p: "Rendement", s: "η", u: "%", v: "73 (voorbeeld)", t: "Maximaal rendement", m: "output: efficiency.* and nHydraulicEfficiency.*" },
|
|
||||||
{ p: "Benodigde NPSH", s: "NPSHr", u: "m", v: "2-3 (voorbeeld)", t: "Lage cavitatie gevoeligheid", m: "Not explicit in current output; candidate future anchor metric" },
|
|
||||||
{ p: "Persaansluiting", s: "-", u: "DN150 / PN16", v: "-", t: "Horizontale uitlaat", m: "Asset/mechanical metadata (datasheet-level)" },
|
|
||||||
{ p: "Zuigaansluiting", s: "-", u: "DN200 / PN10", v: "-", t: "Instroomzijde pomp", m: "Asset/mechanical metadata (datasheet-level)" },
|
|
||||||
{ p: "Pomphuismateriaal", s: "-", u: "EN-GJL-250", v: "-", t: "Gietijzer", m: "Asset/mechanical metadata (datasheet-level)" },
|
|
||||||
{ p: "Waaiermateriaal", s: "-", u: "1.4122 RVS", v: "-", t: "Schroefcentrifugaalwaaier", m: "Asset/mechanical metadata (datasheet-level)" },
|
|
||||||
{ p: "Pompgewicht", s: "-", u: "kg", v: "183 (voorbeeld)", t: "Droge uitvoering", m: "Asset/mechanical metadata (datasheet-level)" }
|
|
||||||
];
|
|
||||||
|
|
||||||
paramBody.innerHTML = params.map(function (row) {
|
|
||||||
return "<tr>" +
|
|
||||||
"<td>" + row.p + "</td>" +
|
|
||||||
"<td><code>" + row.s + "</code></td>" +
|
|
||||||
"<td>" + row.u + "</td>" +
|
|
||||||
"<td>" + row.v + "</td>" +
|
|
||||||
"<td>" + row.t + "</td>" +
|
|
||||||
"<td>" + row.m + "</td>" +
|
|
||||||
"</tr>";
|
|
||||||
}).join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderRows() {
|
|
||||||
const rows = signalRows.filter((r) => r.dir === activeDir);
|
|
||||||
const groups = [...new Set(rows.map((r) => r.group))];
|
|
||||||
tbody.innerHTML = "";
|
|
||||||
|
|
||||||
groups.forEach((group) => {
|
|
||||||
const gtr = document.createElement("tr");
|
|
||||||
gtr.className = "group-row";
|
|
||||||
const gtd = document.createElement("td");
|
|
||||||
gtd.colSpan = 10;
|
|
||||||
gtd.textContent = group;
|
|
||||||
gtr.appendChild(gtd);
|
|
||||||
tbody.appendChild(gtr);
|
|
||||||
|
|
||||||
rows.filter((r) => r.group === group).forEach((r) => {
|
|
||||||
const typicalRange = inferTypicalRange(r);
|
|
||||||
const criticality = inferCriticality(r);
|
|
||||||
const conversionHints = inferConversionHints(r);
|
|
||||||
const tr = document.createElement("tr");
|
|
||||||
tr.innerHTML = "<td>" + r.group + "</td>" +
|
|
||||||
"<td><code>" + r.signal + "</code></td>" +
|
|
||||||
"<td>" + r.dir + "</td>" +
|
|
||||||
"<td>" + r.unit + "</td>" +
|
|
||||||
"<td>" + typicalRange + "</td>" +
|
|
||||||
"<td>" + criticality + "</td>" +
|
|
||||||
"<td>" + r.meaning + "</td>" +
|
|
||||||
"<td><code>" + r.source + "</code></td>" +
|
|
||||||
"<td>" + conversionHints + "</td>" +
|
|
||||||
"<td>" + r.notes + "</td>";
|
|
||||||
tbody.appendChild(tr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
tableMeta.textContent = activeDir === "input"
|
|
||||||
? "Showing input topics/signals grouped by engineering function."
|
|
||||||
: "Showing output ports/signals/KPIs grouped by engineering function.";
|
|
||||||
}
|
|
||||||
|
|
||||||
btnInput.addEventListener("click", function () {
|
|
||||||
activeDir = "input";
|
|
||||||
btnInput.classList.add("active");
|
|
||||||
btnOutput.classList.remove("active");
|
|
||||||
renderRows();
|
|
||||||
});
|
|
||||||
|
|
||||||
btnOutput.addEventListener("click", function () {
|
|
||||||
activeDir = "output";
|
|
||||||
btnOutput.classList.add("active");
|
|
||||||
btnInput.classList.remove("active");
|
|
||||||
renderRows();
|
|
||||||
});
|
|
||||||
|
|
||||||
const themeToggle = document.getElementById("themeToggle");
|
|
||||||
const root = document.documentElement;
|
|
||||||
const storedTheme = localStorage.getItem("rm_anchor_theme");
|
|
||||||
if (storedTheme === "dark") {
|
|
||||||
root.setAttribute("data-theme", "dark");
|
|
||||||
}
|
|
||||||
|
|
||||||
themeToggle.addEventListener("click", function () {
|
|
||||||
const isDark = root.getAttribute("data-theme") === "dark";
|
|
||||||
const next = isDark ? "light" : "dark";
|
|
||||||
root.setAttribute("data-theme", next);
|
|
||||||
localStorage.setItem("rm_anchor_theme", next);
|
|
||||||
drawAllCharts();
|
|
||||||
});
|
|
||||||
|
|
||||||
function drawLineChart(svgId, options) {
|
|
||||||
const svg = document.getElementById(svgId);
|
|
||||||
const w = 520;
|
|
||||||
const h = 280;
|
|
||||||
const m = { top: 20, right: 16, bottom: 44, left: 56 };
|
|
||||||
const iw = w - m.left - m.right;
|
|
||||||
const ih = h - m.top - m.bottom;
|
|
||||||
|
|
||||||
const xMin = Math.min.apply(null, options.x);
|
|
||||||
const xMax = Math.max.apply(null, options.x);
|
|
||||||
const yMinRaw = Math.min.apply(null, options.y);
|
|
||||||
const yMaxRaw = Math.max.apply(null, options.y);
|
|
||||||
const yPad = (yMaxRaw - yMinRaw) * 0.12 || 1;
|
|
||||||
const yMin = Math.max(0, yMinRaw - yPad);
|
|
||||||
const yMax = yMaxRaw + yPad;
|
|
||||||
|
|
||||||
function sx(v) { return m.left + ((v - xMin) / (xMax - xMin || 1)) * iw; }
|
|
||||||
function sy(v) { return m.top + ih - ((v - yMin) / (yMax - yMin || 1)) * ih; }
|
|
||||||
|
|
||||||
const textColor = getComputedStyle(document.documentElement).getPropertyValue("--muted").trim() || "#627489";
|
|
||||||
const lineColor = options.color;
|
|
||||||
const axisColor = getComputedStyle(document.documentElement).getPropertyValue("--line-strong").trim() || "#96accb";
|
|
||||||
const gridColor = getComputedStyle(document.documentElement).getPropertyValue("--line").trim() || "#d7e0ee";
|
|
||||||
|
|
||||||
let path = "";
|
|
||||||
options.x.forEach(function (xv, i) {
|
|
||||||
const px = sx(xv);
|
|
||||||
const py = sy(options.y[i]);
|
|
||||||
path += (i === 0 ? "M" : " L") + px + " " + py;
|
|
||||||
});
|
|
||||||
|
|
||||||
const yTicks = 5;
|
|
||||||
let tickEls = "";
|
|
||||||
for (let i = 0; i <= yTicks; i++) {
|
|
||||||
const val = yMin + ((yMax - yMin) * i) / yTicks;
|
|
||||||
const py = sy(val);
|
|
||||||
tickEls += '<line x1="' + m.left + '" y1="' + py + '" x2="' + (w - m.right) + '" y2="' + py + '" stroke="' + gridColor + '" stroke-width="1" />';
|
|
||||||
tickEls += '<text x="' + (m.left - 8) + '" y="' + (py + 4) + '" text-anchor="end" fill="' + textColor + '" font-size="11">' + val.toFixed(2) + '</text>';
|
|
||||||
}
|
|
||||||
|
|
||||||
let pointEls = "";
|
|
||||||
options.x.forEach(function (xv, i) {
|
|
||||||
pointEls += '<circle cx="' + sx(xv) + '" cy="' + sy(options.y[i]) + '" r="3.8" fill="' + lineColor + '" />';
|
|
||||||
});
|
|
||||||
|
|
||||||
let xTickEls = "";
|
|
||||||
options.x.forEach(function (xv) {
|
|
||||||
xTickEls += '<line x1="' + sx(xv) + '" y1="' + (h - m.bottom) + '" x2="' + sx(xv) + '" y2="' + (h - m.bottom + 5) + '" stroke="' + axisColor + '"/>';
|
|
||||||
xTickEls += '<text x="' + sx(xv) + '" y="' + (h - m.bottom + 18) + '" text-anchor="middle" fill="' + textColor + '" font-size="11">' + xv + '</text>';
|
|
||||||
});
|
|
||||||
|
|
||||||
svg.innerHTML = '' +
|
|
||||||
'<rect x="0" y="0" width="520" height="280" fill="transparent" />' +
|
|
||||||
tickEls +
|
|
||||||
'<line x1="' + m.left + '" y1="' + (h - m.bottom) + '" x2="' + (w - m.right) + '" y2="' + (h - m.bottom) + '" stroke="' + axisColor + '" stroke-width="1.4" />' +
|
|
||||||
'<line x1="' + m.left + '" y1="' + m.top + '" x2="' + m.left + '" y2="' + (h - m.bottom) + '" stroke="' + axisColor + '" stroke-width="1.4" />' +
|
|
||||||
'<path d="' + path + '" fill="none" stroke="' + lineColor + '" stroke-width="2.3" />' +
|
|
||||||
pointEls +
|
|
||||||
xTickEls +
|
|
||||||
'<text x="260" y="272" text-anchor="middle" fill="' + textColor + '" font-size="12">' + options.xLabel + '</text>' +
|
|
||||||
'<text x="16" y="140" transform="rotate(-90 16 140)" text-anchor="middle" fill="' + textColor + '" font-size="12">' + options.yLabel + '</text>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawModeBarChart(svgId) {
|
|
||||||
const svg = document.getElementById(svgId);
|
|
||||||
const modes = [
|
|
||||||
{ mode: "auto", count: 6 },
|
|
||||||
{ mode: "virtualControl", count: 6 },
|
|
||||||
{ mode: "fysicalControl", count: 4 }
|
|
||||||
];
|
|
||||||
|
|
||||||
const w = 520, h = 280;
|
|
||||||
const m = { top: 20, right: 16, bottom: 52, left: 52 };
|
|
||||||
const iw = w - m.left - m.right;
|
|
||||||
const ih = h - m.top - m.bottom;
|
|
||||||
const max = 6;
|
|
||||||
const barW = iw / modes.length * 0.58;
|
|
||||||
const gap = iw / modes.length * 0.42;
|
|
||||||
|
|
||||||
const textColor = getComputedStyle(document.documentElement).getPropertyValue("--muted").trim() || "#627489";
|
|
||||||
const axisColor = getComputedStyle(document.documentElement).getPropertyValue("--line-strong").trim() || "#96accb";
|
|
||||||
const blue = getComputedStyle(document.documentElement).getPropertyValue("--blue").trim() || "#2059d8";
|
|
||||||
const teal = getComputedStyle(document.documentElement).getPropertyValue("--teal").trim() || "#0d9f9e";
|
|
||||||
const amber = getComputedStyle(document.documentElement).getPropertyValue("--amber").trim() || "#cf8a11";
|
|
||||||
const colors = [blue, teal, amber];
|
|
||||||
|
|
||||||
let bars = "";
|
|
||||||
modes.forEach(function (d, i) {
|
|
||||||
const x = m.left + i * (barW + gap) + gap * 0.5;
|
|
||||||
const bh = (d.count / max) * ih;
|
|
||||||
const y = m.top + ih - bh;
|
|
||||||
bars += '<rect x="' + x + '" y="' + y + '" width="' + barW + '" height="' + bh + '" rx="6" fill="' + colors[i] + '" />';
|
|
||||||
bars += '<text x="' + (x + barW / 2) + '" y="' + (y - 6) + '" text-anchor="middle" fill="' + textColor + '" font-size="12">' + d.count + '</text>';
|
|
||||||
bars += '<text x="' + (x + barW / 2) + '" y="' + (h - m.bottom + 18) + '" text-anchor="middle" fill="' + textColor + '" font-size="11">' + d.mode + '</text>';
|
|
||||||
});
|
|
||||||
|
|
||||||
svg.innerHTML = '' +
|
|
||||||
'<line x1="' + m.left + '" y1="' + (h - m.bottom) + '" x2="' + (w - m.right) + '" y2="' + (h - m.bottom) + '" stroke="' + axisColor + '" stroke-width="1.4" />' +
|
|
||||||
'<line x1="' + m.left + '" y1="' + m.top + '" x2="' + m.left + '" y2="' + (h - m.bottom) + '" stroke="' + axisColor + '" stroke-width="1.4" />' +
|
|
||||||
bars +
|
|
||||||
'<text x="260" y="272" text-anchor="middle" fill="' + textColor + '" font-size="12">Mode</text>' +
|
|
||||||
'<text x="16" y="140" transform="rotate(-90 16 140)" text-anchor="middle" fill="' + textColor + '" font-size="12">Allowed actions (count)</text>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawAllCharts() {
|
|
||||||
const ctrl = [0, 350, 550, 600, 1000];
|
|
||||||
const flow = [0, 0.9294287109, 0.941, 1.05, 1.9220000000];
|
|
||||||
const power = [5.0760000000, 39.1178710938, 64.8, 76.4, 169.2000000000];
|
|
||||||
const eff = flow.map(function (q, i) { return q / (power[i] || 1); });
|
|
||||||
|
|
||||||
drawLineChart("flowChart", {
|
|
||||||
x: ctrl,
|
|
||||||
y: flow,
|
|
||||||
xLabel: "Control setpoint",
|
|
||||||
yLabel: "Flow",
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue("--teal").trim() || "#0d9f9e"
|
|
||||||
});
|
|
||||||
|
|
||||||
drawLineChart("powerChart", {
|
|
||||||
x: ctrl,
|
|
||||||
y: power,
|
|
||||||
xLabel: "Control setpoint",
|
|
||||||
yLabel: "Power (kW)",
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue("--blue").trim() || "#2059d8"
|
|
||||||
});
|
|
||||||
|
|
||||||
drawLineChart("effChart", {
|
|
||||||
x: ctrl,
|
|
||||||
y: eff,
|
|
||||||
xLabel: "Control setpoint",
|
|
||||||
yLabel: "Efficiency index (flow/power)",
|
|
||||||
color: getComputedStyle(document.documentElement).getPropertyValue("--green").trim() || "#0fa57d"
|
|
||||||
});
|
|
||||||
|
|
||||||
drawModeBarChart("modeChart");
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRows();
|
|
||||||
renderParameterSheet();
|
|
||||||
drawAllCharts();
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
# Rotating Machine Function Anchor
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- **Node type**: `rotatingMachine` (`nodes/rotatingMachine/rotatingMachine.js:1`, `nodes/rotatingMachine/rotatingMachine.html:16`)
|
|
||||||
- **Consumes parent/control topics**: `setMode`, `execSequence`, `execMovement`, `flowMovement`, `emergencystop`, `simulateMeasurement`, `registerChild`, `showWorkingCurves`, `CoG` (`nodes/rotatingMachine/src/nodeClass.js:267`)
|
|
||||||
- **Publishes periodic outputs**:
|
|
||||||
- Output `0`: process payload (`nodes/rotatingMachine/src/nodeClass.js:249`)
|
|
||||||
- Output `1`: influx payload (`nodes/rotatingMachine/src/nodeClass.js:251`)
|
|
||||||
- Output `2`: registration/control plumbing (`registerChild`) (`nodes/rotatingMachine/src/nodeClass.js:222`)
|
|
||||||
- **Cross-node integrations (direct observed)**:
|
|
||||||
- Registered/managed by `machineGroupControl` as `machine`, which then commands each machine via `handleInput('parent', ...)` (`nodes/machineGroupControl/src/specificClass.js:50`, `nodes/machineGroupControl/src/specificClass.js:711`, `nodes/machineGroupControl/src/specificClass.js:1028`)
|
|
||||||
- Can be orchestrated by `pumpingStation` via `execSequence` and movement commands (`nodes/pumpingStation/src/specificClass.js:296`, `nodes/pumpingStation/src/specificClass.js:297`)
|
|
||||||
- Dashboard/test flows inject `simulateMeasurement` and consume process output topics (`nodes/rotatingMachine/examples/basic.flow.json:380`, `nodes/rotatingMachine/examples/basic.flow.json:412`)
|
|
||||||
- **Admin/UI endpoints**:
|
|
||||||
- `GET /rotatingMachine/menu.js`
|
|
||||||
- `GET /rotatingMachine/configData.js` (`nodes/rotatingMachine/rotatingMachine.js:17`, `nodes/rotatingMachine/rotatingMachine.js:27`)
|
|
||||||
|
|
||||||
## 1) Unit Table (Anchor Starts Here)
|
|
||||||
| Signal/Field | Represents | Asset Type | Default Unit | Accepted Units | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|---|---|
|
|
||||||
| `pressure.measured.*` | pressure input (upstream/downstream) | measurement child (`pressure`) | `mbar` | any convertible via `MeasurementContainer` | `nodes/rotatingMachine/src/specificClass.js:48`, `nodes/rotatingMachine/src/specificClass.js:708` | real child sensors and virtual dashboard child | pressure dimension for curve selection (`predict*.fDimension`) | if missing, pressure dimension forced to minimum (`0`) (`nodes/rotatingMachine/src/specificClass.js:552`) |
|
|
||||||
| `flow.predicted.downstream` | predicted flow at discharge | rotating machine | `general.unit` from config | convertible (`m3/h`, `l/s`, etc.) | `nodes/rotatingMachine/src/specificClass.js:53`, `nodes/rotatingMachine/src/specificClass.js:423` | `calcFlow()` | output formatting, status text, parent/group logic | forced `0` if non-operational or no curve (`nodes/rotatingMachine/src/specificClass.js:415`, `nodes/rotatingMachine/src/specificClass.js:429`) |
|
|
||||||
| `flow.predicted.atEquipment` | same flow at equipment point | rotating machine | `general.unit` | convertible | `nodes/rotatingMachine/src/specificClass.js:53`, `nodes/rotatingMachine/src/specificClass.js:424` | `calcFlow()` | efficiency calculations | forced `0` if non-operational/no curve |
|
|
||||||
| `power.predicted.atEquipment` | predicted power draw | rotating machine | `kW` | convertible (`W`, `kW`) | `nodes/rotatingMachine/src/specificClass.js:54`, `nodes/rotatingMachine/src/specificClass.js:448` | `calcPower()` | efficiency calculations, status text | forced `0` if non-operational/no curve |
|
|
||||||
| `ctrl.predicted.atEquipment` | predicted control position for requested flow | rotating machine | unitless (%) semantic | numeric | `nodes/rotatingMachine/src/specificClass.js:482` | `calcCtrl()` | `flowmovement` command path | returns `0` if no curve |
|
|
||||||
| `temperature.measured.atEquipment` | process temp for density lookup | machine fluid context | `C` default, converted to `K` when used | convertible | init at `15 C` (`nodes/rotatingMachine/src/specificClass.js:149`) | init + measurement updates | CoolProp density input | if missing conversion, efficiency can degrade silently |
|
|
||||||
| `atmPressure.measured.atEquipment` | atmospheric pressure for density lookup | machine fluid context | `Pa` | convertible | init at `101325 Pa` (`nodes/rotatingMachine/src/specificClass.js:151`) | init | CoolProp density input | fallback density `1000 kg/m3` on CoolProp error (`nodes/rotatingMachine/src/specificClass.js:867`) |
|
|
||||||
| `efficiency.*` | specific flow (`flow/power`) | derived metric | implicit unitless ratio | numeric | `nodes/rotatingMachine/src/specificClass.js:878`, `nodes/rotatingMachine/src/specificClass.js:881` | `calcEfficiency()` | output and BEP distance metrics | unchanged if power/flow are zero |
|
|
||||||
| `specificEnergyConsumption.*` | power per flow | derived metric | implicit | numeric | `nodes/rotatingMachine/src/specificClass.js:879`, `nodes/rotatingMachine/src/specificClass.js:882` | `calcEfficiency()` | output consumers | unchanged if power/flow zero |
|
|
||||||
| `nHydraulicEfficiency.*` | hydraulic-efficiency-like metric | derived metric | unitless | numeric | `nodes/rotatingMachine/src/specificClass.js:884` | `calcEfficiency()` | diagnostic output | skipped if pressure/flow/power conversions unavailable |
|
|
||||||
| `cog`, `NCog`, `NCogPercent` | efficiency-curve peak indicators | derived curve metrics | unitless | numeric | `nodes/rotatingMachine/src/specificClass.js:796`, `nodes/rotatingMachine/src/specificClass.js:948` | `calcCog()`, `getOutput()` | group optimization, dashboards | retains last computed values |
|
|
||||||
| `effDistFromPeak`, `effRelDistFromPeak` | distance from best-efficiency point | derived | unitless | numeric | `nodes/rotatingMachine/src/specificClass.js:924`, `nodes/rotatingMachine/src/specificClass.js:962` | `calcDistanceBEP()` | output consumers | remains last computed value |
|
|
||||||
| `runtime`, `maintenanceTime`, `moveTimeleft`, `state` | movement/state telemetry | state machine | `h`/`s`/enum | numeric/string | `nodes/rotatingMachine/src/specificClass.js:943` | `state` module | output/status/parent control | depends on `state` module behavior |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- **Runtime registration + endpoints**: `nodes/rotatingMachine/rotatingMachine.js`
|
|
||||||
- **Node-RED wrapper/routing**: `nodes/rotatingMachine/src/nodeClass.js`
|
|
||||||
- **Domain/mechanical logic**: `nodes/rotatingMachine/src/specificClass.js`
|
|
||||||
- **Editor UI/defaults**: `nodes/rotatingMachine/rotatingMachine.html`
|
|
||||||
- **Default config schema/validation rules**: `nodes/generalFunctions/src/configs/rotatingMachine.json`
|
|
||||||
|
|
||||||
## 3) Configuration Contract
|
|
||||||
| UI Field | Runtime Path | Default | Validation/Coercion | Behavior Impact | Source |
|
|
||||||
|---|---|---|---|---|---|
|
|
||||||
| `speed` | `stateConfig.movement.speed` | `1` | `Number(uiConfig.speed)` | movement progression speed | `nodes/rotatingMachine/rotatingMachine.html:22`, `nodes/rotatingMachine/src/nodeClass.js:91` |
|
|
||||||
| `startup/warmup/shutdown/cooldown` | `stateConfig.time.*` | `0` | `Number(...)` | sequence transition durations | `nodes/rotatingMachine/rotatingMachine.html:23`, `nodes/rotatingMachine/src/nodeClass.js:95` |
|
|
||||||
| `movementMode` | `stateConfig.movement.mode` | `staticspeed` | raw string | state movement model selection | `nodes/rotatingMachine/rotatingMachine.html:27`, `nodes/rotatingMachine/src/nodeClass.js:92` |
|
|
||||||
| `unit` | `config.general.unit` + `config.asset.unit` | UI empty, config default `l/s` | direct assign then config init | base flow unit for measurements and outputs | `nodes/rotatingMachine/src/nodeClass.js:50`, `nodes/generalFunctions/src/configs/rotatingMachine.json:18` |
|
|
||||||
| `model` | `config.asset.model` | UI empty, config default `Unknown` | direct assign | curve loading via `loadCurve(model)` | `nodes/rotatingMachine/src/nodeClass.js:62`, `nodes/rotatingMachine/src/specificClass.js:18` |
|
|
||||||
| logging fields | `config.general.logging.*` | `enableLog=false`, `logLevel=error` in UI; config default enabled/info | direct assign | runtime verbosity | `nodes/rotatingMachine/rotatingMachine.html:39`, `nodes/rotatingMachine/src/nodeClass.js:51` |
|
|
||||||
| `positionVsParent` | `config.functionality.positionVsParent` | UI empty, config default `atEquipment` | direct assign + default in schema | registration topology to parent | `nodes/rotatingMachine/src/nodeClass.js:66`, `nodes/generalFunctions/src/configs/rotatingMachine.json:74` |
|
|
||||||
| Mode/action/source rules | `config.mode.*` | schema defaults | configUtils validation into `Set` semantics | command gating | `nodes/generalFunctions/src/configs/rotatingMachine.json:231`, `nodes/rotatingMachine/src/specificClass.js:269` |
|
|
||||||
| Sequences | `config.sequences.*` | schema defaults | configUtils validation | machine state transitions | `nodes/generalFunctions/src/configs/rotatingMachine.json:360`, `nodes/rotatingMachine/src/specificClass.js:363` |
|
|
||||||
|
|
||||||
## 4) Input/Output Contract
|
|
||||||
### 4.1 Input topics (`nodeClass`)
|
|
||||||
| Topic | Payload schema | Handler | Side effects |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `registerChild` | `payload=<nodeId>`, optional `positionVsParent` | registers child source via `childRegistrationUtils` | starts measurement event wiring (`nodes/rotatingMachine/src/nodeClass.js:268`) |
|
|
||||||
| `setMode` | `payload=<mode>` | `setMode()` | updates command policy mode |
|
|
||||||
| `execSequence` | `{source, action, parameter}` | `handleInput()` | executes state sequence |
|
|
||||||
| `execMovement` | `{source, action, setpoint}` | `handleInput()` | moves position |
|
|
||||||
| `flowMovement` | `{source, action, setpoint}` | `handleInput()` | converts flow->ctrl then moves |
|
|
||||||
| `emergencystop` | `{source, action}` | `handleInput()` | emergency sequence attempt |
|
|
||||||
| `simulateMeasurement` | `{type, position, value, unit, timestamp?}` | measurement update handlers | updates virtual pressure or measured values |
|
|
||||||
| `showWorkingCurves` | any | immediate response on output 0 | emits curve/cog debug payload |
|
|
||||||
| `CoG` | any | immediate response on output 0 | calls `m.showCoG()` (method currently not defined in `specificClass`) |
|
|
||||||
|
|
||||||
### 4.2 Output ports
|
|
||||||
| Port | Message type | Source |
|
|
||||||
|---|---|---|
|
|
||||||
| `0` | formatted process message from flattened measurements + state fields | `nodes/rotatingMachine/src/nodeClass.js:250` |
|
|
||||||
| `1` | formatted influxdb message | `nodes/rotatingMachine/src/nodeClass.js:251` |
|
|
||||||
| `2` | registration to parent: `{topic:'registerChild', payload:id, positionVsParent}` | `nodes/rotatingMachine/src/nodeClass.js:222` |
|
|
||||||
|
|
||||||
### 4.3 Admin endpoints
|
|
||||||
| Endpoint | Purpose | Source |
|
|
||||||
|---|---|---|
|
|
||||||
| `/rotatingMachine/menu.js` | dynamic editor menu script (`asset`, `logger`, `position`) | `nodes/rotatingMachine/rotatingMachine.js:17` |
|
|
||||||
| `/rotatingMachine/configData.js` | dynamic default/config script | `nodes/rotatingMachine/rotatingMachine.js:27` |
|
|
||||||
|
|
||||||
## 5) Mode, State, and Control Model
|
|
||||||
- **Modes**: `auto`, `virtualControl`, `fysicalControl` (`nodes/generalFunctions/src/configs/rotatingMachine.json:233`)
|
|
||||||
- **Mode gate enforcement**:
|
|
||||||
- `isValidActionForMode(action, mode)` (`nodes/rotatingMachine/src/specificClass.js:279`)
|
|
||||||
- `isValidSourceForMode(source, mode)` (`nodes/rotatingMachine/src/specificClass.js:269`)
|
|
||||||
- **Actions supported by handler**: `execsequence`, `execmovement`, `flowmovement`, `entermaintenance`, `exitmaintenance`, `emergencystop`, `statuscheck` (`nodes/rotatingMachine/src/specificClass.js:303`)
|
|
||||||
- **Operational states for active prediction**: `operational`, `warmingup`, `accelerating`, `decelerating` (`nodes/rotatingMachine/src/specificClass.js:739`)
|
|
||||||
- **Sequence defaults**: startup/shutdown/emergencystop/maintenance flows defined in config schema (`nodes/generalFunctions/src/configs/rotatingMachine.json:365`)
|
|
||||||
|
|
||||||
## 6) End-to-End Execution Flow
|
|
||||||
1. Node registration instantiates `nodeClass`, then `Specific` (`Machine`).
|
|
||||||
2. `Machine` constructor loads model curve, initializes predictors/state/measurements, creates virtual pressure children, and subscribes to state events.
|
|
||||||
3. `nodeClass` starts delayed child registration (`output 2`) and 1-second tick/status loops.
|
|
||||||
4. Incoming topics route through `switch(msg.topic)` to mode changes, movement/sequence commands, child registration, and simulated measurements.
|
|
||||||
5. Child measurement events update parent measurement container and dispatch typed handlers.
|
|
||||||
6. Pressure updates set predictor dimension, recompute flow/power/efficiency/CoG/BEP metrics.
|
|
||||||
7. Each tick emits formatted process + influx messages.
|
|
||||||
|
|
||||||
## 7) Full Function Inventory
|
|
||||||
### 7.1 `nodes/rotatingMachine/rotatingMachine.js`
|
|
||||||
| Function | Purpose | Source |
|
|
||||||
|---|---|---|
|
|
||||||
| module export init | register Node-RED node type and admin endpoints | `nodes/rotatingMachine/rotatingMachine.js:5` |
|
|
||||||
|
|
||||||
### 7.2 `nodes/rotatingMachine/src/nodeClass.js`
|
|
||||||
| Function | Purpose | Key effects | Source |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `constructor` | boot wrapper lifecycle | load config, create source, start loops/handlers | `nodes/rotatingMachine/src/nodeClass.js:16` |
|
|
||||||
| `_loadConfig` | map UI config to runtime config | builds `general/asset/functionality`; builds `outputUtils` | `nodes/rotatingMachine/src/nodeClass.js:44` |
|
|
||||||
| `_setupSpecificClass` | build `Machine` with movement/time state config | instantiates `Specific`; stores on `node.source` | `nodes/rotatingMachine/src/nodeClass.js:77` |
|
|
||||||
| `_bindEvents` | placeholder | no-op currently | `nodes/rotatingMachine/src/nodeClass.js:112` |
|
|
||||||
| `_updateNodeStatus` | compose Node-RED status icon/text | warns once for missing pressure init; includes flow/power/state | `nodes/rotatingMachine/src/nodeClass.js:116` |
|
|
||||||
| `_registerChild` | announce self to parent | sends `registerChild` on output 2 after 100ms | `nodes/rotatingMachine/src/nodeClass.js:217` |
|
|
||||||
| `_startTickLoop` | periodic work | 1s `_tick`; 1s status refresh | `nodes/rotatingMachine/src/nodeClass.js:230` |
|
|
||||||
| `_tick` | periodic output generation | `formatMsg(process)` + `formatMsg(influxdb)` send to outputs 0/1 | `nodes/rotatingMachine/src/nodeClass.js:246` |
|
|
||||||
| `_attachInputHandler` | route inbound topics | dispatches all command/simulation/register/show topics | `nodes/rotatingMachine/src/nodeClass.js:260` |
|
|
||||||
| `_attachCloseHandler` | shutdown cleanup | clears intervals | `nodes/rotatingMachine/src/nodeClass.js:357` |
|
|
||||||
|
|
||||||
### 7.3 `nodes/rotatingMachine/src/specificClass.js`
|
|
||||||
| Function | Purpose | Key effects | Source |
|
|
||||||
|---|---|---|---|
|
|
||||||
| `constructor` | initialize machine domain object | config/curve/predictors/state/measurement/events/virtual children | `nodes/rotatingMachine/src/specificClass.js:7` |
|
|
||||||
| `_initVirtualPressureChildren` | create simulated upstream/downstream pressure children | registers virtual measurement children | `nodes/rotatingMachine/src/specificClass.js:104` |
|
|
||||||
| `_init` | seed base measurements and min/max flow | sets temperature, atmPressure, curve min/max | `nodes/rotatingMachine/src/specificClass.js:147` |
|
|
||||||
| `_updateState` | enforce non-operational flow = 0 | overwrites predicted flow when inactive | `nodes/rotatingMachine/src/specificClass.js:163` |
|
|
||||||
| `registerChild` | subscribe to child measurement events | stores real pressure child IDs, updates measurements, calls handlers | `nodes/rotatingMachine/src/specificClass.js:173` |
|
|
||||||
| `_callMeasurementHandler` | typed measurement dispatch | pressure/flow/temp handlers + fallback | `nodes/rotatingMachine/src/specificClass.js:212` |
|
|
||||||
| `assessDrift` | compare measured vs predicted windows | delegates to `nrmse.assessDrift` | `nodes/rotatingMachine/src/specificClass.js:237` |
|
|
||||||
| `reverseCurve` | flip x/y arrays | used for flow->ctrl predictor | `nodes/rotatingMachine/src/specificClass.js:252` |
|
|
||||||
| `updateConfig` | apply validated config patch | merges via `configUtils` | `nodes/rotatingMachine/src/specificClass.js:264` |
|
|
||||||
| `isValidSourceForMode` | mode source gate | checks configured allowed set | `nodes/rotatingMachine/src/specificClass.js:269` |
|
|
||||||
| `isValidActionForMode` | mode action gate | checks configured allowed set | `nodes/rotatingMachine/src/specificClass.js:279` |
|
|
||||||
| `handleInput` | main command dispatcher | executes sequence/movement/status commands | `nodes/rotatingMachine/src/specificClass.js:289` |
|
|
||||||
| `abortMovement` | cancel current movement | delegates to state abort if available | `nodes/rotatingMachine/src/specificClass.js:345` |
|
|
||||||
| `setMode` | update current mode | validates against schema enum values | `nodes/rotatingMachine/src/specificClass.js:351` |
|
|
||||||
| `executeSequence` | run state sequence | transitions through configured states; updatePosition at end | `nodes/rotatingMachine/src/specificClass.js:363` |
|
|
||||||
| `setpoint` | move to numeric target | validates non-negative number then `state.moveTo` | `nodes/rotatingMachine/src/specificClass.js:394` |
|
|
||||||
| `calcFlow` | predict flow from current curve and ctrl position | writes predicted flow measurements | `nodes/rotatingMachine/src/specificClass.js:413` |
|
|
||||||
| `calcPower` | predict power from current curve and ctrl position | writes predicted power measurement | `nodes/rotatingMachine/src/specificClass.js:438` |
|
|
||||||
| `inputFlowCalcPower` | estimate power from requested flow | flow->ctrl->power chained prediction | `nodes/rotatingMachine/src/specificClass.js:460` |
|
|
||||||
| `calcCtrl` | estimate ctrl for desired flow | writes predicted ctrl | `nodes/rotatingMachine/src/specificClass.js:478` |
|
|
||||||
| `getMeasuredPressure` | choose pressure basis for prediction | differential preferred; then downstream; then upstream; else 0 | `nodes/rotatingMachine/src/specificClass.js:496` |
|
|
||||||
| `_getPreferredPressureValue` | pressure source priority resolver | real child > virtual child > aggregated position value | `nodes/rotatingMachine/src/specificClass.js:570` |
|
|
||||||
| `getPressureInitializationStatus` | pressure readiness status model | upstream/downstream/differential flags | `nodes/rotatingMachine/src/specificClass.js:600` |
|
|
||||||
| `updateSimulatedMeasurement` | write dashboard-sim values | pressure route via virtual child; others dispatch typed handler | `nodes/rotatingMachine/src/specificClass.js:617` |
|
|
||||||
| `handleMeasuredFlow` | reconcile measured flow availability/consistency | returns matched/single measurement or null | `nodes/rotatingMachine/src/specificClass.js:644` |
|
|
||||||
| `handleMeasuredPower` | read measured power | returns value or null with error | `nodes/rotatingMachine/src/specificClass.js:685` |
|
|
||||||
| `updateMeasuredTemperature` | temp update hook | currently log-only | `nodes/rotatingMachine/src/specificClass.js:698` |
|
|
||||||
| `updateMeasuredPressure` | pressure update hook | stores pressure, recomputes pressure basis and position metrics | `nodes/rotatingMachine/src/specificClass.js:703` |
|
|
||||||
| `updateMeasuredFlow` | flow update hook | stores measured flow if operational; mirrors predicted flow value | `nodes/rotatingMachine/src/specificClass.js:718` |
|
|
||||||
| `_isOperationalState` | operational predicate | active states used by prediction guards | `nodes/rotatingMachine/src/specificClass.js:737` |
|
|
||||||
| `updatePosition` | core recompute pipeline on movement/state changes | calc flow/power -> efficiency -> cog -> BEP distance | `nodes/rotatingMachine/src/specificClass.js:745` |
|
|
||||||
| `calcDistanceFromPeak` | abs distance metric | absolute efficiency delta | `nodes/rotatingMachine/src/specificClass.js:767` |
|
|
||||||
| `calcRelativeDistanceFromPeak` | normalized distance metric | interpolation to [0,1] | `nodes/rotatingMachine/src/specificClass.js:771` |
|
|
||||||
| `showWorkingCurves` | debugging snapshot of current curve context | returns current curves + metrics | `nodes/rotatingMachine/src/specificClass.js:779` |
|
|
||||||
| `calcCog` | compute peak efficiency point on current curve | updates `cog`, `NCog`, indexes, minEfficiency | `nodes/rotatingMachine/src/specificClass.js:796` |
|
|
||||||
| `calcEfficiencyCurve` | derive efficiency curve and peak/min | from aligned power/flow arrays | `nodes/rotatingMachine/src/specificClass.js:817` |
|
|
||||||
| `calcFlowPower` | convenience combined prediction | calls `calcFlow` and `calcPower` | `nodes/rotatingMachine/src/specificClass.js:845` |
|
|
||||||
| `calcEfficiency` | compute efficiency family metrics | CoolProp density path + fallback + writes derived metrics | `nodes/rotatingMachine/src/specificClass.js:854` |
|
|
||||||
| `updateCurve` | replace machine curve at runtime | validates config and updates predictors | `nodes/rotatingMachine/src/specificClass.js:897` |
|
|
||||||
| `getCompleteCurve` | return full loaded curves | power+flow input curves | `nodes/rotatingMachine/src/specificClass.js:910` |
|
|
||||||
| `getCurrentCurves` | return currently selected pressure curve slices | current flow/power curves | `nodes/rotatingMachine/src/specificClass.js:916` |
|
|
||||||
| `calcDistanceBEP` | write BEP distance metrics | updates `absDistFromPeak`, `relDistFromPeak` | `nodes/rotatingMachine/src/specificClass.js:924` |
|
|
||||||
| `getOutput` | flatten and enrich output object | adds state/runtime/ctrl/mode/cog/drift/eff-distance | `nodes/rotatingMachine/src/specificClass.js:936` |
|
|
||||||
|
|
||||||
## 8) Calculations and Capability Matrix
|
|
||||||
- **Curve-backed capabilities**:
|
|
||||||
- flow prediction (`nq`) via `predictFlow`
|
|
||||||
- power prediction (`np`) via `predictPower`
|
|
||||||
- control inversion (flow->ctrl) via reversed `nq`
|
|
||||||
- **Pressure basis selection order**:
|
|
||||||
1. real differential (`downstream - upstream`)
|
|
||||||
2. real/virtual downstream only
|
|
||||||
3. real/virtual upstream only
|
|
||||||
4. fallback `0` (minimum pressure behavior)
|
|
||||||
- **Availability-first behavior**:
|
|
||||||
- missing pressure does not stop operation; it degrades predictions and warns.
|
|
||||||
- CoolProp failure does not stop operation; density fallback is used.
|
|
||||||
- non-operational states force predicted flow/power to zero.
|
|
||||||
- **BEP indicators**:
|
|
||||||
- computes peak efficiency index and normalized CoG (`NCog`) for optimization usage by parent/group controllers.
|
|
||||||
|
|
||||||
## 9) Error Handling and Safeguards
|
|
||||||
- Invalid actions/sources are rejected by mode gates, with warnings (`nodes/rotatingMachine/src/specificClass.js:297`).
|
|
||||||
- Invalid setpoint (`<0` or non-number) is rejected in `setpoint()` (`nodes/rotatingMachine/src/specificClass.js:398`).
|
|
||||||
- Missing curve model disables predictor objects but keeps class alive (`nodes/rotatingMachine/src/specificClass.js:27`).
|
|
||||||
- Missing pressure initialization surfaces Node-RED warning ring status (`nodes/rotatingMachine/src/nodeClass.js:126`).
|
|
||||||
- `simulateMeasurement` rejects non-finite values and unsupported types (`nodes/rotatingMachine/src/nodeClass.js:312`).
|
|
||||||
|
|
||||||
## 10) Test Evidence Matrix
|
|
||||||
| Test file | Covered behavior |
|
|
||||||
|---|---|
|
|
||||||
| `nodes/rotatingMachine/test/basic/constructor.basic.test.js` | constructor curve/no-curve behavior and output shape |
|
|
||||||
| `nodes/rotatingMachine/test/basic/mode-and-input.basic.test.js` | `setMode`, `handleInput` validation, operational-state predicate |
|
|
||||||
| `nodes/rotatingMachine/test/edge/error-paths.edge.test.js` | negative setpoint resilience, status failure path |
|
|
||||||
| `nodes/rotatingMachine/test/edge/nodeClass-routing.edge.test.js` | input-topic routing, pressure initialization status warning, curve/CoG reply routing |
|
|
||||||
| `nodes/rotatingMachine/test/integration/sequences.integration.test.js` | startup sequence and movement execution |
|
|
||||||
| `nodes/rotatingMachine/test/integration/registration.integration.test.js` | child registration and pressure event propagation |
|
|
||||||
| `nodes/rotatingMachine/test/integration/pressure-initialization.integration.test.js` | explicit pressure init combinations and real-vs-virtual pressure priority |
|
|
||||||
| `nodes/rotatingMachine/test/integration/coolprop.integration.test.js` | efficiency path with CoolProp and medium-pressure initialization behavior |
|
|
||||||
| `nodes/rotatingMachine/test/integration/basic-flow-dashboard.integration.test.js` | example-flow parser/wiring contracts for dashboard topics |
|
|
||||||
|
|
||||||
## 11) Invariants (Anchor Truth)
|
|
||||||
- `specificClass` is the mechanical/logic source of truth; `nodeClass` is routing/lifecycle only.
|
|
||||||
- Prediction calculations must be curve-backed when curve exists, and availability-first fallback when it does not.
|
|
||||||
- Pressure selection priority is **real sensor > virtual dashboard > aggregated fallback**.
|
|
||||||
- Command execution must remain mode-gated by both action and source.
|
|
||||||
- Output shape must keep process/influx separation and parent registration on output port 2.
|
|
||||||
- Operational-state gating must continue to prevent active prediction outputs in inactive states.
|
|
||||||
|
|
||||||
## 12) Known Gaps / Risks (Current Implementation)
|
|
||||||
- `nodeClass` routes topic `CoG` to `m.showCoG()`, but `showCoG` is not present in `specificClass` (runtime risk on that topic): `nodes/rotatingMachine/src/nodeClass.js:340`.
|
|
||||||
- `handleInput('emergencystop')` calls sequence `"emergencyStop"`, but config default key is `"emergencystop"` (case/name mismatch risk): `nodes/rotatingMachine/src/specificClass.js:327`, `nodes/generalFunctions/src/configs/rotatingMachine.json:381`.
|
|
||||||
- `_setupSpecificClass` uses `machineConfig.eneableLog` (typo) for state logging config; likely not intended: `nodes/rotatingMachine/src/nodeClass.js:86`.
|
|
||||||
- Label expression can evaluate unexpectedly because `+` and `||` precedence are mixed: `nodes/rotatingMachine/rotatingMachine.html:58`.
|
|
||||||
|
|
||||||
## 13) Change Checklist
|
|
||||||
When changing rotatingMachine logic, update all of:
|
|
||||||
1. Runtime logic in `nodes/rotatingMachine/src/specificClass.js`.
|
|
||||||
2. Node-RED routing/lifecycle in `nodes/rotatingMachine/src/nodeClass.js`.
|
|
||||||
3. UI defaults/fields in `nodes/rotatingMachine/rotatingMachine.html`.
|
|
||||||
4. Config schema and mode/action/source/sequence defaults in `nodes/generalFunctions/src/configs/rotatingMachine.json`.
|
|
||||||
5. Example flow contracts in `nodes/rotatingMachine/examples/*.flow.json`.
|
|
||||||
6. Tests under `nodes/rotatingMachine/test/` (basic, edge, integration).
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Rotating Machine Test Evidence
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
Evidence source for `ANCHOR-rotatingMachine.md`.
|
|
||||||
|
|
||||||
## Test-to-Contract Mapping
|
|
||||||
| Test file | Contract/Behavior Anchored |
|
|
||||||
|---|---|
|
|
||||||
| `nodes/rotatingMachine/test/basic/constructor.basic.test.js` | Constructor should tolerate missing model curve and still return output object with core fields. |
|
|
||||||
| `nodes/rotatingMachine/test/basic/mode-and-input.basic.test.js` | Mode validation, source/action gating behavior, and active-state definition (`warmingup` active). |
|
|
||||||
| `nodes/rotatingMachine/test/edge/error-paths.edge.test.js` | Error path resilience in `setpoint()` and status update exception fallback (`Status Error`). |
|
|
||||||
| `nodes/rotatingMachine/test/edge/nodeClass-routing.edge.test.js` | Topic routing for control and simulation commands, pressure init warning behavior, and debug topic reply routing. |
|
|
||||||
| `nodes/rotatingMachine/test/integration/sequences.integration.test.js` | End-to-end state transitions for startup and movement command paths. |
|
|
||||||
| `nodes/rotatingMachine/test/integration/registration.integration.test.js` | Child measurement registration pipeline stores measured pressure in parent container. |
|
|
||||||
| `nodes/rotatingMachine/test/integration/pressure-initialization.integration.test.js` | Pressure initialization matrix (none/upstream/downstream/both) and preference for real child pressure over virtual dashboard pressure. |
|
|
||||||
| `nodes/rotatingMachine/test/integration/coolprop.integration.test.js` | Efficiency calculation path passes through CoolProp logic and verifies pressure dimension initialization behavior. |
|
|
||||||
| `nodes/rotatingMachine/test/integration/basic-flow-dashboard.integration.test.js` | Example dashboard parser wiring and topic/index contracts for flow/power/pressure charts. |
|
|
||||||
|
|
||||||
## Remaining Coverage Gaps
|
|
||||||
- No direct test proves `handleInput('emergencystop')` sequence-name alignment with config key.
|
|
||||||
- No direct test for `CoG` input topic when `showCoG` is absent.
|
|
||||||
- No direct test for UI label precedence behavior in `rotatingMachine.html`.
|
|
||||||
- No direct test for typo path `machineConfig.eneableLog` in `_setupSpecificClass`.
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>settler Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>settler Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# settler Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: settler
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/settler/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/settler
|
|
||||||
- Node-RED wrapper: nodes/settler/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/settler/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/settler/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# settler Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/settler/test/basic/*.test.js
|
|
||||||
- nodes/settler/test/integration/*.test.js
|
|
||||||
- nodes/settler/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/settler/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/settler/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/settler/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>valve Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>valve Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# valve Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: valve
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/valve/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/valve
|
|
||||||
- Node-RED wrapper: nodes/valve/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/valve/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/valve/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# valve Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/valve/test/basic/*.test.js
|
|
||||||
- nodes/valve/test/integration/*.test.js
|
|
||||||
- nodes/valve/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/valve/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/valve/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/valve/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<title>valveGroupControl Anchor</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: Arial, sans-serif; margin: 24px; background: #f7f8fa; color: #1f2937; }
|
|
||||||
.card { background: #fff; border: 1px solid #d1d5db; border-radius: 8px; padding: 14px; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>valveGroupControl Function Anchor</h1>
|
|
||||||
<div class="card">Baseline topology placeholder. Expand during functional changes.</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
# valveGroupControl Function Anchor (Preparation Baseline)
|
|
||||||
|
|
||||||
## 0) Connection Map (At a Glance)
|
|
||||||
- Node type: valveGroupControl
|
|
||||||
- Scope: baseline anchor scaffold to satisfy EVOLV required architecture.
|
|
||||||
|
|
||||||
## 1) Unit Table (Initial Baseline)
|
|
||||||
| Signal/Field | Represents | Default Unit | Source of Truth | Produced By | Consumed By | Fallback/Degraded Behavior |
|
|
||||||
|---|---|---|---|---|---|---|
|
|
||||||
| TBD | TBD | TBD | nodes/valveGroupControl/src/* | TBD | TBD | TBD |
|
|
||||||
|
|
||||||
## 2) Class Identity
|
|
||||||
- Runtime registration: nodes/valveGroupControl
|
|
||||||
- Node-RED wrapper: nodes/valveGroupControl/src/nodeClass.js (when present)
|
|
||||||
- Domain logic: nodes/valveGroupControl/src/specificClass.js (when present)
|
|
||||||
- Editor UI: nodes/valveGroupControl/*.html (when present)
|
|
||||||
|
|
||||||
## 3) Current Gaps To Resolve Before Declaring Anchor Complete
|
|
||||||
- Replace placeholder sections with full contract mapping on first functional change.
|
|
||||||
|
|
||||||
## 4) Standardization Plan
|
|
||||||
1. Maintain this anchor and evidence docs with behavior changes.
|
|
||||||
2. Maintain tests under test/basic, test/integration, test/edge.
|
|
||||||
3. Maintain examples package (README, basic.flow.json, integration.flow.json, edge.flow.json).
|
|
||||||
|
|
||||||
## 5) Acceptance Criteria For Completion
|
|
||||||
- Anchor/evidence artifacts exist.
|
|
||||||
- Test structure exists.
|
|
||||||
- Example structure exists.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# valveGroupControl Test Evidence
|
|
||||||
|
|
||||||
Status: baseline structure scaffolded.
|
|
||||||
|
|
||||||
## Required Test Layout
|
|
||||||
- nodes/valveGroupControl/test/basic/*.test.js
|
|
||||||
- nodes/valveGroupControl/test/integration/*.test.js
|
|
||||||
- nodes/valveGroupControl/test/edge/*.test.js
|
|
||||||
|
|
||||||
## Baseline Mapping
|
|
||||||
| Test file | Scope |
|
|
||||||
|---|---|
|
|
||||||
| nodes/valveGroupControl/test/basic/structure-module-load.basic.test.js | module load smoke |
|
|
||||||
| nodes/valveGroupControl/test/integration/structure-examples.integration.test.js | examples package integrity |
|
|
||||||
| nodes/valveGroupControl/test/edge/structure-examples-node-type.edge.test.js | node-type presence in basic example |
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
# EVOLV Example Flow Template Standard
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Every EVOLV node MUST have example flows in its `examples/` directory. Node-RED automatically discovers these and shows them in **Import > Examples > EVOLV**.
|
|
||||||
|
|
||||||
## Naming Convention
|
|
||||||
|
|
||||||
```
|
|
||||||
examples/
|
|
||||||
01 - Basic Manual Control.json # Tier 1: inject-based, zero deps
|
|
||||||
02 - Integration with Parent Node.json # Tier 2: parent-child wiring
|
|
||||||
03 - Dashboard Visualization.json # Tier 3: FlowFuse dashboard (optional)
|
|
||||||
```
|
|
||||||
|
|
||||||
The filename (minus `.json`) becomes the menu label in Node-RED.
|
|
||||||
|
|
||||||
## Tier 1: Basic (inject-based, zero external dependencies)
|
|
||||||
|
|
||||||
**Purpose:** Demonstrate all key functionality using only core Node-RED nodes.
|
|
||||||
|
|
||||||
**Required elements:**
|
|
||||||
- 1x `comment` node (top-left): title + 2-3 line description of what the flow demonstrates
|
|
||||||
- 1x `comment` node (near inputs): "HOW TO USE: 1. Deploy flow. 2. Click inject nodes..."
|
|
||||||
- `inject` nodes for each control action (labeled clearly)
|
|
||||||
- The EVOLV node under test with **realistic, working configuration**
|
|
||||||
- 3x `debug` nodes: "Port 0: Process", "Port 1: InfluxDB", "Port 2: Parent"
|
|
||||||
- Optional: 1x `function` node to format output readably (keep under 20 lines)
|
|
||||||
|
|
||||||
**Forbidden:** No dashboard nodes. No FlowFuse widgets. No HTTP nodes. No third-party nodes.
|
|
||||||
|
|
||||||
**Config rules:**
|
|
||||||
- All required config fields filled with realistic values
|
|
||||||
- Model/curve fields set to existing models in the library
|
|
||||||
- `enableLog: true, logLevel: "info"` so users can see what happens
|
|
||||||
- Unit fields explicitly set (not empty strings)
|
|
||||||
|
|
||||||
**Layout rules:**
|
|
||||||
- Comment nodes: top-left
|
|
||||||
- Input section: left side (x: 100-400)
|
|
||||||
- EVOLV node: center (x: 500-600)
|
|
||||||
- Debug/output: right side (x: 700-900)
|
|
||||||
- Y spacing: ~60px between nodes
|
|
||||||
|
|
||||||
## Tier 2: Integration (parent-child relationships)
|
|
||||||
|
|
||||||
**Purpose:** Show how nodes connect as parent-child via Port 2.
|
|
||||||
|
|
||||||
**Required elements:**
|
|
||||||
- 1x `comment` node: what relationship is being demonstrated
|
|
||||||
- Parent node + child node(s) properly wired
|
|
||||||
- Port 2 of child → Port 0 input of parent (registration pathway)
|
|
||||||
- `inject` nodes to send control commands to parent
|
|
||||||
- `inject` nodes to send measurement/state to children
|
|
||||||
- `debug` nodes on all ports of both parent and children
|
|
||||||
|
|
||||||
**Node-specific integration patterns:**
|
|
||||||
- `machineGroupControl` → 2x `rotatingMachine`
|
|
||||||
- `pumpingStation` → 1x `rotatingMachine` + 1x `measurement` (assetType: "flow")
|
|
||||||
- `valveGroupControl` → 2x `valve`
|
|
||||||
- `reactor` → `settler` (downstream cascade)
|
|
||||||
- `measurement` → any parent node
|
|
||||||
|
|
||||||
## Tier 3: Dashboard Visualization (optional)
|
|
||||||
|
|
||||||
**Purpose:** Rich interactive demo with FlowFuse dashboard.
|
|
||||||
|
|
||||||
**Allowed additional dependencies:** FlowFuse dashboard nodes only (`@flowfuse/node-red-dashboard`).
|
|
||||||
|
|
||||||
**Required elements:**
|
|
||||||
- 1x `comment` node: "Requires @flowfuse/node-red-dashboard"
|
|
||||||
- Auto-initialization: `inject` node with "Inject once after 1 second" for default mode/state
|
|
||||||
- Dashboard controls clearly labeled
|
|
||||||
- Charts with proper axis labels and units
|
|
||||||
- Keep parser/formatter functions under 40 lines (split if needed)
|
|
||||||
- No null message outputs (filter before sending to charts)
|
|
||||||
|
|
||||||
## Comment Node Standard
|
|
||||||
|
|
||||||
Every comment node must use this format:
|
|
||||||
|
|
||||||
```
|
|
||||||
Title: [Node Name] - [Flow Tier]
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
[2-3 line description]
|
|
||||||
|
|
||||||
Prerequisites: [list any requirements]
|
|
||||||
```
|
|
||||||
|
|
||||||
## ID Naming Convention
|
|
||||||
|
|
||||||
Use predictable, readable IDs for all nodes (not random hex):
|
|
||||||
|
|
||||||
```
|
|
||||||
{nodeName}_{tier}_{purpose}
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
- rm_basic_tab (rotatingMachine, basic flow, tab)
|
|
||||||
- rm_basic_node (the actual rotatingMachine node)
|
|
||||||
- rm_basic_debug_port0 (debug on port 0)
|
|
||||||
- rm_basic_inject_start (inject for startup)
|
|
||||||
- rm_basic_comment_title (title comment)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
|
|
||||||
Before committing an example flow:
|
|
||||||
|
|
||||||
- [ ] Can be imported into clean Node-RED + EVOLV (no other packages needed for Tier 1/2)
|
|
||||||
- [ ] All nodes show correct status after deploy (no red triangles)
|
|
||||||
- [ ] Comment nodes present and descriptive
|
|
||||||
- [ ] All 3 output ports wired to something (debug at minimum)
|
|
||||||
- [ ] IDs follow naming convention (no random hex)
|
|
||||||
- [ ] Node config uses realistic values (not empty strings or defaults)
|
|
||||||
- [ ] File named per convention (01/02/03 prefix)
|
|
||||||
|
|
||||||
## Gitea Wiki Integration
|
|
||||||
|
|
||||||
Each node's wiki gets an "Examples" page that:
|
|
||||||
1. Lists all available example flows with descriptions
|
|
||||||
2. Links to the raw .json file in the repo
|
|
||||||
3. Describes prerequisites and step-by-step usage
|
|
||||||
4. Shows expected behavior after deploy
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# Improvements Backlog
|
|
||||||
|
|
||||||
Purpose:
|
|
||||||
- Capture functional and architectural improvements discovered during analysis runs where functionality is not changed.
|
|
||||||
- Keep an implementation queue outside active feature work.
|
|
||||||
|
|
||||||
Lifecycle:
|
|
||||||
- Add item when discovered.
|
|
||||||
- When implemented, remove the item from this file and record the fix in session notes/PR.
|
|
||||||
|
|
||||||
## Open Items (Beyond Current Top 10)
|
|
||||||
|
|
||||||
| ID | Date | Area | Summary | Evidence | Status |
|
|
||||||
|---|---|---|---|---|---|
|
|
||||||
| IMP-20260219-004 | 2026-02-19 | measurement editor | Label expression precedence can hide fallback label text. | `nodes/measurement/measurement.html:63` | open |
|
|
||||||
| IMP-20260219-005 | 2026-02-19 | measurement editor | `success` assigned without declaration in editor save path. | `nodes/measurement/measurement.html:131` | open |
|
|
||||||
| IMP-20260219-016 | 2026-02-19 | generalFunctions/state | `movementManager` constructor writes startup `console.log` on runtime path, adding noisy non-structured logs. | `nodes/generalFunctions/src/state/movementManager.js:16` | open |
|
|
||||||
| IMP-20260219-018 | 2026-02-19 | generalFunctions/helper | Legacy menu endpoint still uses generated class source (`menuUtils.legacy.js`) as compatibility fallback; plan removal after UI validation of stable bootstrap/data path. | `nodes/generalFunctions/src/helper/endpointUtils.js:113`, `nodes/generalFunctions/src/helper/menuUtils.js:575` | open |
|
|
||||||
| IMP-20260219-019 | 2026-02-19 | generalFunctions/menu | `menuUtils.js` embeds extensive runtime `console.*` and inline API/debug logging in generated client scripts, increasing noise and making prod diagnostics harder. | `nodes/generalFunctions/src/helper/menuUtils.js:35` | open |
|
|
||||||
| IMP-20260219-020 | 2026-02-19 | generalFunctions/predict | `interpolation.js` contains raw runtime debug log (`console.log(this.interpolationtype)`), leaking internal state in production paths. | `nodes/generalFunctions/src/predict/interpolation.js:127` | open |
|
|
||||||
| IMP-20260219-021 | 2026-02-19 | generalFunctions/menu | Two active menu utility implementations (`menuUtils.js` and `menuUtils_DEPRECATED.js`) still coexist, increasing drift risk and maintenance overhead. | `nodes/generalFunctions/src/helper/menuUtils.js:1`, `nodes/generalFunctions/src/helper/menuUtils_DEPRECATED.js:1` | open |
|
|
||||||
| IMP-20260219-022 | 2026-02-19 | generalFunctions/outliers | `DynamicClusterDeviation.update()` emits verbose `console.log` traces on each call with no log-level guard, unsafe for production telemetry volume. | `nodes/generalFunctions/src/outliers/outlierDetection.js:7` | open |
|
|
||||||
| IMP-20260224-006 | 2026-02-24 | rotatingMachine prediction fallback | When only one pressure side is available, predictor uses absolute pressure as surrogate differential, which can materially bias flow prediction under varying suction/discharge conditions. | `nodes/rotatingMachine/src/specificClass.js:573`, `nodes/rotatingMachine/src/specificClass.js:588` | open |
|
|
||||||
| IMP-20260224-012 | 2026-02-24 | cross-node unit architecture | Canonical unit-anchor strategy is implemented in rotatingMachine plus phase-1 controllers (`machineGroupControl`, `pumpingStation`, `valve`, `valveGroupControl`); continue rollout to remaining nodes so all runtime paths use canonical storage + explicit ingress/egress units. | `nodes/machineGroupControl/src/specificClass.js:42`, `nodes/pumpingStation/src/specificClass.js:48`, `nodes/valve/src/specificClass.js:87`, `nodes/valveGroupControl/src/specificClass.js:78` | open |
|
|
||||||
| IMP-20260323-001 | 2026-03-23 | architecture/security | `temp/cloud.yml` stores environment credentials directly in a repository-tracked target-state stack example; replace with env placeholders/secret injection and split illustrative architecture from deployable manifests. | `temp/cloud.yml:1` | open |
|
|
||||||
| IMP-20260323-002 | 2026-03-23 | architecture/configuration | Intended database-backed configuration authority (`tagcodering`) is not yet visibly integrated as the primary runtime config backbone in this repository; define access pattern, schema ownership, and rollout path for edge/site/central consumers. | `architecture/stack-architecture-review.md:1` | open |
|
|
||||||
| IMP-20260323-003 | 2026-03-23 | architecture/telemetry | Multi-level smart-storage strategy is a stated architecture goal, but signal classes, reconstruction guarantees, and authoritative-layer rules are not yet formalized; define telemetry policy before broad deployment. | `architecture/stack-architecture-review.md:1` | open |
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Top 10 Production Priorities (Round 2, Availability-First)
|
|
||||||
|
|
||||||
Context:
|
|
||||||
- Generated after implementing the first top-10 and follow-up items `IMP-20260219-011/012/013`.
|
|
||||||
- Focus remains: keep runtime up, prefer degraded/null outputs over hard failures.
|
|
||||||
|
|
||||||
## Priority List
|
|
||||||
|
|
||||||
1. Fix measurement outlier toggle corruption.
|
|
||||||
- Why: toggling replaces the outlier config object with a boolean, breaking later config reads.
|
|
||||||
- Evidence: `nodes/measurement/src/specificClass.js:509`.
|
|
||||||
|
|
||||||
2. Fix rotating machine pressure-difference unit request API mismatch.
|
|
||||||
- Why: `difference('Pa')` no longer matches container API; requested unit is ignored, risking incorrect efficiency basis.
|
|
||||||
- Evidence: `nodes/rotatingMachine/src/specificClass.js:856`, `nodes/generalFunctions/src/measurements/MeasurementContainer.js:436`.
|
|
||||||
|
|
||||||
3. Guard reactor PFR state indexing at boundary conditions.
|
|
||||||
- Why: known edge behavior can overrun index mapping near exact reactor length and destabilize updates.
|
|
||||||
- Evidence: `nodes/reactor/src/specificClass.js:326`.
|
|
||||||
|
|
||||||
4. Make dashboard template resolution fail-soft.
|
|
||||||
- Why: missing template currently throws and aborts dashboard generation path.
|
|
||||||
- Evidence: `nodes/dashboardAPI/src/specificClass.js:91`.
|
|
||||||
|
|
||||||
5. Make dashboard input path skip invalid children instead of throwing.
|
|
||||||
- Why: missing child source/config currently throws; should warn and continue in availability-first mode.
|
|
||||||
- Evidence: `nodes/dashboardAPI/src/nodeClass.js:55`.
|
|
||||||
|
|
||||||
6. Harden shared config merge semantics for arrays/types.
|
|
||||||
- Why: recursive merge mutates destination and treats arrays as objects, risking config drift.
|
|
||||||
- Evidence: `nodes/generalFunctions/src/helper/configUtils.js:77`.
|
|
||||||
|
|
||||||
7. Fix machineGroupControl child position source path.
|
|
||||||
- Why: reads `positionVsParent` from `general` instead of `functionality`, causing inconsistent routing metadata.
|
|
||||||
- Evidence: `nodes/machineGroupControl/src/specificClass.js:53`.
|
|
||||||
|
|
||||||
8. Accept numeric-string measurement payloads safely.
|
|
||||||
- Why: measurement node currently ignores numeric strings common in PLC/edge integrations.
|
|
||||||
- Evidence: `nodes/measurement/src/nodeClass.js:167`.
|
|
||||||
|
|
||||||
9. Fix reactor editor save wiring mismatch.
|
|
||||||
- Why: editor save hook references the wrong node helpers, risking mis-saved position settings.
|
|
||||||
- Evidence: `nodes/reactor/reactor.html:133`.
|
|
||||||
|
|
||||||
10. Replace raw `structuredClone` usage with compatibility-safe clone strategy.
|
|
||||||
- Why: runtime portability risk across constrained Node-RED deployments.
|
|
||||||
- Evidence: `nodes/settler/src/specificClass.js:34`, `nodes/settler/src/specificClass.js:45`.
|
|
||||||
|
|
||||||
## Implementation Status
|
|
||||||
|
|
||||||
- Implemented on 2026-02-19 in current session.
|
|
||||||
- Verification: tests passed for `generalFunctions`, `measurement`, `reactor`, `rotatingMachine`, `dashboardAPI`, `machineGroupControl`, `settler`, `pumpingStation`, `valve`, `valveGroupControl`, `monster`.
|
|
||||||
- Follow-up architectural items are tracked in `.agents/improvements/IMPROVEMENTS_BACKLOG.md`.
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# Top 10 Production Priorities (Availability-First)
|
|
||||||
|
|
||||||
Context:
|
|
||||||
- Scope reviewed: all nodes under `nodes/*` plus shared `nodes/generalFunctions/*`.
|
|
||||||
- Target posture: keep runtime alive; emit `null`/degraded outputs instead of crashing.
|
|
||||||
|
|
||||||
## Priority List
|
|
||||||
|
|
||||||
1. Remove import-time executable code from machine group runtime module.
|
|
||||||
- Why: `makeMachines()` runs at module load and can execute demo logic in production runtime.
|
|
||||||
- Evidence: `nodes/machineGroupControl/src/specificClass.js:1294`, `nodes/machineGroupControl/src/specificClass.js:1399`.
|
|
||||||
- Availability target: no side effects on `require`; test/demo code must be isolated from runtime path.
|
|
||||||
|
|
||||||
2. Guard `registerChild` in node wrappers to prevent null dereference crashes.
|
|
||||||
- Why: multiple wrappers dereference `childObj.source` without checking child existence.
|
|
||||||
- Evidence: `nodes/reactor/src/nodeClass.js:54`, `nodes/settler/src/nodeClass.js:39`, `nodes/valve/src/nodeClass.js:256`, `nodes/valveGroupControl/src/nodeClass.js:178`, `nodes/machineGroupControl/src/nodeClass.js:215`.
|
|
||||||
- Availability target: if child missing, log warning and continue.
|
|
||||||
|
|
||||||
3. Harden shared child registration utility contract checks.
|
|
||||||
- Why: shared helper destructures `child.config.*` without validation.
|
|
||||||
- Evidence: `nodes/generalFunctions/src/helper/childRegistrationUtils.js:9`, `nodes/generalFunctions/src/helper/childRegistrationUtils.js:10`.
|
|
||||||
- Availability target: reject invalid child payload with warning, no throw.
|
|
||||||
|
|
||||||
4. Add global input-handler error boundary pattern across nodes.
|
|
||||||
- Why: many handlers do work without `try/catch`; one thrown error can bubble and destabilize node behavior.
|
|
||||||
- Evidence: `nodes/measurement/src/nodeClass.js:156`, `nodes/valve/src/nodeClass.js:250`, `nodes/valveGroupControl/src/nodeClass.js:169`, `nodes/settler/src/nodeClass.js:32`.
|
|
||||||
- Availability target: wrap topic routing; map failures to warning + safe `done(err)`/`done()` handling.
|
|
||||||
|
|
||||||
5. Normalize `done` callback handling for Node-RED compatibility.
|
|
||||||
- Why: several nodes call `done()` unguarded; older/inconsistent runtime callbacks can fail.
|
|
||||||
- Evidence: `nodes/measurement/src/nodeClass.js:167`, `nodes/valve/src/nodeClass.js:280`, `nodes/valveGroupControl/src/nodeClass.js:201`, `nodes/machineGroupControl/src/nodeClass.js:257`.
|
|
||||||
- Availability target: `if (typeof done === 'function') done();` everywhere.
|
|
||||||
|
|
||||||
6. Fix reactor runtime routing and setup defects.
|
|
||||||
- Why: `Temperature` topic routes to missing setter path and default reactor warning references wrong variable.
|
|
||||||
- Evidence: `nodes/reactor/src/nodeClass.js:46`, `nodes/reactor/src/nodeClass.js:140`.
|
|
||||||
- Availability target: unknown/unsupported control topics fail soft with warning; setup path cannot throw from bad references.
|
|
||||||
|
|
||||||
7. Fix valve mode-selection bug using undefined config source.
|
|
||||||
- Why: `setMode` references `defaultConfig` instead of instance config; can throw or silently break mode changes.
|
|
||||||
- Evidence: `nodes/valve/src/specificClass.js:142`.
|
|
||||||
- Availability target: invalid mode inputs are rejected safely, valid mode changes deterministic.
|
|
||||||
|
|
||||||
8. Replace hard-throw chain semantics in measurement container with safe-return options.
|
|
||||||
- Why: chain API currently throws for sequence misuse; upstream callers can crash control loops.
|
|
||||||
- Evidence: `nodes/generalFunctions/src/measurements/MeasurementContainer.js:99`, `nodes/generalFunctions/src/measurements/MeasurementContainer.js:109`.
|
|
||||||
- Availability target: invalid chain usage logs and returns no-op/null path in production mode.
|
|
||||||
|
|
||||||
9. Remove noisy console/debug/test logging from runtime paths.
|
|
||||||
- Why: heavy `console.log/error` in control and shared code adds noise and can hide real failures.
|
|
||||||
- Evidence: `nodes/reactor/src/nodeClass.js:58`, `nodes/measurement/src/nodeClass.js:90`, `nodes/pumpingStation/src/nodeClass.js:87`, `nodes/valve/src/specificClass.js:207`.
|
|
||||||
- Availability target: use structured logger with levels; disable debug by default.
|
|
||||||
|
|
||||||
10. Standardize output contract for unchanged state to explicit `null` output.
|
|
||||||
- Why: `formatMsg` returns `undefined` when no change; behavior differs by node send implementation.
|
|
||||||
- Evidence: `nodes/generalFunctions/src/helper/outputUtils.js:37`, `nodes/generalFunctions/src/helper/outputUtils.js:62`.
|
|
||||||
- Availability target: unchanged outputs always return `null` to keep port contract deterministic.
|
|
||||||
|
|
||||||
## Implementation Status
|
|
||||||
|
|
||||||
- Implemented on 2026-02-19 in current session.
|
|
||||||
- Verification: node test suites passed for modified runtime nodes (`measurement`, `reactor`, `valve`, `valveGroupControl`, `machineGroupControl`, `settler`, `pumpingStation`, `dashboardAPI`, `monster`, `rotatingMachine`).
|
|
||||||
- Remaining follow-up items are tracked in `.agents/improvements/IMPROVEMENTS_BACKLOG.md`.
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-alarms-interlocks-permissives
|
|
||||||
description: Design and review alarms, interlocks, and permissive logic for EVOLV control nodes. Use when implementing trip conditions, permissive checks, startup/shutdown guards, alarm priorities, latching/reset behavior, and operator-facing fault handling.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Alarms Interlocks Permissives
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Make alarm and interlock behavior explicit, testable, and operationally safe while preserving availability-first policy bounds.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Build alarm/interlock map from current node contracts and state logic.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- trips/permissives are deterministic
|
|
||||||
- latching/reset behavior is explicit
|
|
||||||
- operator-visible diagnostics are preserved
|
|
||||||
- Validate with sequence and fail-state tests.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/pumpingStation/`
|
|
||||||
- `nodes/machineGroupControl/`
|
|
||||||
- `nodes/rotatingMachine/`
|
|
||||||
- Any node with mode/state transitions and protective actions
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Enumerate alarm conditions and priority/severity.
|
|
||||||
2. Define interlock and permissive truth tables.
|
|
||||||
3. Verify startup/shutdown/emergency sequences.
|
|
||||||
4. Confirm reset, auto-recovery, and manual acknowledgement behavior.
|
|
||||||
5. Ensure outputs expose actionable fault context.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Avoid hidden permissives; every gate should be observable.
|
|
||||||
- Keep alarm naming stable and semantically clear.
|
|
||||||
- Separate advisory warnings from trip-level protection.
|
|
||||||
- Preserve controlled compatibility for released fault topics.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- trip activation and reset/latch behavior
|
|
||||||
- permissive-denied and permissive-restored transitions
|
|
||||||
- out-of-order signal handling in sequence transitions
|
|
||||||
- degraded sensor quality paths and alarm escalation
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- alarm/interlock/permissive matrix
|
|
||||||
- changed files/tests and evidence
|
|
||||||
- unresolved protection-vs-availability tradeoffs
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- changed trip thresholds or permissive logic with operational impact
|
|
||||||
- altered reset authority (auto vs manual)
|
|
||||||
- alarm contract changes affecting external consumers
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Alarms Interlocks Permissives"
|
|
||||||
short_description: "Protective logic and operator alarm specialist"
|
|
||||||
default_prompt: "Map alarm/interlock/permissive behavior in the impacted EVOLV nodes, define deterministic trip and reset rules, validate sequence edge cases, and return test-backed recommendations with clear operational tradeoffs."
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-biological-process-engineering
|
|
||||||
description: Engineer biological wastewater process behavior for EVOLV nodes. Use when implementing or reviewing reactor/settler biology, ASM-style kinetics, oxygen demand, nitrification/denitrification, sludge behavior, calibration assumptions, and biologically plausible constraints.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Biological Process Engineering
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Keep EVOLV biological process models physically plausible, calibratable, and operationally useful.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Ground changes in current biology/state variables and connected control topics.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- biological mass-balance intent is preserved
|
|
||||||
- model assumptions remain explicit and traceable
|
|
||||||
- degraded behavior remains availability-first and bounded
|
|
||||||
- Validate with deterministic tests and representative operating scenarios.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/reactor/`
|
|
||||||
- `nodes/settler/`
|
|
||||||
- `nodes/pumpingStation/` (where biology interacts with flow/retention assumptions)
|
|
||||||
- Related reaction modules and utilities under `nodes/*/src/`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Identify biological state variables, units, and expected ranges.
|
|
||||||
2. Map kinetic pathways (growth, decay, transfer, conversion) and rate constraints.
|
|
||||||
3. Verify oxygen/temperature dependencies and fallback behavior.
|
|
||||||
4. Check integration stability for configured time-step and resolution choices.
|
|
||||||
5. Confirm outputs remain interpretable for control and dashboard consumers.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Keep state vectors explicit and index mappings documented.
|
|
||||||
- Avoid silent clipping/coercion without test coverage and rationale.
|
|
||||||
- Preserve topic/payload compatibility unless migration is defined.
|
|
||||||
- Record calibration assumptions and required field data.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- kinetic branch behavior under representative and boundary conditions
|
|
||||||
- non-negativity and boundedness safeguards
|
|
||||||
- temperature and oxygen transfer sensitivity
|
|
||||||
- time-step/resolution edge behavior and stability warnings
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- biological assumptions and constraints used
|
|
||||||
- changed files/tests and evidence
|
|
||||||
- calibration notes and unresolved biological uncertainties
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- altered biology assumptions that can change plant behavior
|
|
||||||
- parameter/default changes with startup or compliance impact
|
|
||||||
- compatibility breaks in biological outputs or topic contracts
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Biological Process Engineering"
|
|
||||||
short_description: "Wastewater biology and kinetics specialist"
|
|
||||||
default_prompt: "Map biological state variables and kinetics in the impacted EVOLV nodes, define non-negotiable biological invariants, validate oxygen/temperature/time-step behavior, and return test-backed recommendations with calibration assumptions and risks."
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-commissioning-validation
|
|
||||||
description: Plan and verify EVOLV commissioning readiness. Use when defining FAT/SAT test plans, acceptance criteria, loop checks, simulation-to-field validation, startup sequencing evidence, and rollout gates for operational deployment.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Commissioning Validation
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Convert implementation changes into deployment-ready evidence with clear acceptance gates.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from impacted contracts, modes, and site-operational constraints.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- validation criteria are measurable and reproducible
|
|
||||||
- startup and failover behavior is proven, not assumed
|
|
||||||
- rollback path is explicit
|
|
||||||
- Produce evidence artifacts tied to concrete tests/checks.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Cross-node behavior spanning control, measurement, and integrations
|
|
||||||
- Test plans and validation docs under repository documentation paths
|
|
||||||
- Node-level suites where commissioning evidence is derived
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Build FAT/SAT matrix from impacted contracts and risk areas.
|
|
||||||
2. Define pass/fail criteria and required instrumentation visibility.
|
|
||||||
3. Execute or script reproducible validation checks.
|
|
||||||
4. Capture evidence with timestamps, commands, and outcomes.
|
|
||||||
5. Define rollout gates and rollback triggers.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Prefer deterministic replayable checks over ad-hoc validation.
|
|
||||||
- Include negative-path and recovery-path tests.
|
|
||||||
- Tie each acceptance criterion to a concrete artifact.
|
|
||||||
- Keep operator handoff notes concise and actionable.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- startup/shutdown commissioning sequences
|
|
||||||
- failover and reconnect scenarios
|
|
||||||
- alarm/interlock behavior under commissioning cases
|
|
||||||
- post-deploy smoke checks and regression shortlist
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- FAT/SAT-style validation matrix
|
|
||||||
- executed evidence summary
|
|
||||||
- go/no-go risks and mitigations
|
|
||||||
- rollback plan and monitoring checklist
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- reduced commissioning scope under schedule pressure
|
|
||||||
- acceptance of unresolved high-severity risks
|
|
||||||
- rollout sequencing choices with operational impact
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Commissioning Validation"
|
|
||||||
short_description: "FAT/SAT and deployment-readiness specialist"
|
|
||||||
default_prompt: "Create a commissioning evidence plan from impacted EVOLV contracts, define measurable FAT/SAT acceptance criteria, verify failure and recovery paths, and return go/no-go risks with rollback guidance."
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-database-influx-architecture
|
|
||||||
description: Design and review EVOLV data modeling and storage architecture for telemetry and dashboard consumption. Use when deciding InfluxDB measurement/tag/field schemas, retention/downsampling strategy, write/read payload structures, and Grafana query compatibility for Node-RED outputs.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Database Influx Architecture
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Shape telemetry data so it is queryable, performant, and maintainable for operations dashboards and analytics.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from current measurement/tag/field usage and dashboard queries.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- query compatibility for existing Grafana/consumer flows
|
|
||||||
- bounded tag cardinality
|
|
||||||
- explicit units and timestamp policy
|
|
||||||
- Provide validation evidence using representative payloads and queries.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Output payload structure from EVOLV nodes
|
|
||||||
- InfluxDB write model: measurement, tags, fields, timestamp policy
|
|
||||||
- Retention/downsampling implications for Grafana visualization
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Classify data by usage:
|
|
||||||
- real-time control
|
|
||||||
- operator dashboarding
|
|
||||||
- long-term analytics
|
|
||||||
2. Define stable schema conventions:
|
|
||||||
- measurement naming
|
|
||||||
- tag cardinality controls
|
|
||||||
- numeric fields and units
|
|
||||||
3. Validate that node outputs map cleanly to write model.
|
|
||||||
4. Check query ergonomics for expected Grafana panels.
|
|
||||||
5. Specify retention/downsampling and backfill behavior.
|
|
||||||
|
|
||||||
## Design Rules
|
|
||||||
- Avoid high-cardinality tags for volatile identifiers.
|
|
||||||
- Keep units explicit and consistent over time.
|
|
||||||
- Prefer additive schema evolution; document breaking changes.
|
|
||||||
- Include timestamps that are consistent across nodes.
|
|
||||||
|
|
||||||
## Test/Validation Expectations
|
|
||||||
- Verify sample payloads produce intended point shape.
|
|
||||||
- Check representative queries for latency and result correctness.
|
|
||||||
- Include migration strategy when schema changes are unavoidable.
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- proposed schema (measurement/tags/fields)
|
|
||||||
- rationale tied to dashboard and analytics use
|
|
||||||
- changed files/tests
|
|
||||||
- migration and retention plan
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- schema changes that break existing queries/panels
|
|
||||||
- retention/downsampling policies with data-loss tradeoffs
|
|
||||||
- backfill rules that alter historical comparability
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Database + Influx Architect"
|
|
||||||
short_description: "Design telemetry schema for Influx and Grafana"
|
|
||||||
default_prompt: "Define EVOLV telemetry schema from current payload/query usage, enforce cardinality and compatibility invariants, validate with representative queries, and escalate decision-gate tradeoffs for retention/backfill or breaking schema changes."
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-frontend-node-red
|
|
||||||
description: Design and implement Node-RED node editor UI and runtime-facing configuration for EVOLV. Use when editing node HTML editor files, `RED.nodes.registerType(...)` defaults, admin endpoint-driven menus/config scripts, and config mapping into `src/nodeClass.js` in JavaScript/CommonJS nodes.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Frontend Node-RED
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Implement robust Node-RED editor experiences that keep UI defaults, runtime config parsing, and behavior in lockstep.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from impacted files and active runtime/editor contracts.
|
|
||||||
- Define invariants before editing:
|
|
||||||
- `.html` defaults and runtime parsing parity
|
|
||||||
- endpoint path stability (`/<nodeName>/menu.js`, `/<nodeName>/configData.js`)
|
|
||||||
- released topic/output compatibility unless migration is declared
|
|
||||||
- Provide evidence for changed behavior (tests or smoke checks).
|
|
||||||
|
|
||||||
## Repo-Specific Rules
|
|
||||||
- Use CommonJS patterns in runtime files.
|
|
||||||
- Keep node names aligned across `RED.nodes.registerType('<nodeName>', ...)`, runtime registration in `<nodeName>.js`, and package/node mapping.
|
|
||||||
- Keep admin endpoint paths stable unless editor consumers are updated: `/<nodeName>/menu.js` and `/<nodeName>/configData.js`.
|
|
||||||
- Prefer placeholder-driven UI composition when matching EVOLV patterns.
|
|
||||||
|
|
||||||
## Node Layout Standard
|
|
||||||
Use `nodes/machineGroupControl/` as the template baseline for new nodes.
|
|
||||||
|
|
||||||
- `nodes/<nodeName>/<nodeName>.js`
|
|
||||||
- Keep runtime entry small.
|
|
||||||
- Create Node-RED instance and attach `this.nodeClass = new nodeClass(...)`.
|
|
||||||
- Register admin endpoints via shared managers.
|
|
||||||
- `nodes/<nodeName>/<nodeName>.html`
|
|
||||||
- Register defaults in `RED.nodes.registerType(...)`.
|
|
||||||
- Load `/<nodeName>/menu.js` and `/<nodeName>/configData.js`.
|
|
||||||
- Use `oneditprepare` to call `window.EVOLV.nodes.<nodeName>.initEditor(this)`.
|
|
||||||
- `nodes/<nodeName>/src/nodeClass.js`
|
|
||||||
- Normalize `uiConfig` into runtime config.
|
|
||||||
- Keep Node-RED concerns here: input routing, tick loop, output formatting, status.
|
|
||||||
- `nodes/<nodeName>/src/specificClass.js`
|
|
||||||
- Keep domain logic here with minimal/no direct Node-RED coupling.
|
|
||||||
|
|
||||||
## Implementation Workflow
|
|
||||||
1. Inspect current node trio: `.html`, `.js`, `src/nodeClass.js`.
|
|
||||||
2. Define required config properties and defaults.
|
|
||||||
3. Update `.html` defaults and form controls.
|
|
||||||
4. Update runtime config normalization in `src/nodeClass.js`.
|
|
||||||
5. Confirm `msg.topic` command handling is still coherent.
|
|
||||||
6. Add tests under `nodes/<nodeName>/test/` with focus on config defaults/overrides and topic routing.
|
|
||||||
7. If creating a new node, add entry under root `package.json` `node-red.nodes` map.
|
|
||||||
|
|
||||||
## Quality Gates
|
|
||||||
- Every UI property has corresponding runtime handling.
|
|
||||||
- Numeric inputs are validated/coerced consistently.
|
|
||||||
- Node status and output shape remain predictable.
|
|
||||||
- No Node-RED runtime dependency required for domain tests.
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- changed config fields and mapping table
|
|
||||||
- changed files
|
|
||||||
- tests added and what they prove
|
|
||||||
- migration notes if backward compatibility changed
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- form or default changes that alter existing deployed behavior
|
|
||||||
- endpoint contract/path changes
|
|
||||||
- UI/runtime migration that could break saved Node-RED flows
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Frontend + Node-RED"
|
|
||||||
short_description: "Build EVOLV Node-RED editor/runtime UX safely"
|
|
||||||
default_prompt: "Implement EVOLV Node-RED editor/runtime changes from a file-level impact map, preserve UI/runtime parity and stable endpoint contracts, provide verification evidence, and ask decision-gate questions before compatibility-breaking edits."
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-instrumentation-assets
|
|
||||||
description: Engineer measurement and instrumentation behavior for EVOLV assets. Use when defining sensor mappings, tag semantics, data quality checks, measurement container behavior, calibration assumptions, and measurement-driven node logic in `measurement` and related assets.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Instrumentation Assets
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Ensure measurements are trustworthy, well-modeled, and usable by control and analytics logic.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Ground changes in current measurement definitions and downstream consumers.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- unit consistency and conversion transparency
|
|
||||||
- explicit quality-state handling
|
|
||||||
- no silent coercion that hides sensor faults
|
|
||||||
- Provide evidence for data-quality transitions and fallback behavior.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/measurement/`
|
|
||||||
- `nodes/generalFunctions/src/helper/measurement*`
|
|
||||||
- `nodes/generalFunctions/datasets/assetData/measurement.json`
|
|
||||||
- Any node consuming measurement topics or quality flags
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Inventory required measurements by asset/function.
|
|
||||||
2. Define tag semantics and expected units.
|
|
||||||
3. Add validation rules for bounds, type, and missing values.
|
|
||||||
4. Specify handling for stale/noisy/bad-quality signals.
|
|
||||||
5. Ensure downstream nodes receive consistent payload structure.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Prefer explicit unit naming and conversion points.
|
|
||||||
- Separate raw sensor value from engineered value when possible.
|
|
||||||
- Avoid hidden coercions that mask instrumentation faults.
|
|
||||||
- Record assumptions around calibration and sensor placement.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- missing/invalid payloads
|
|
||||||
- unit conversion correctness
|
|
||||||
- quality/state transitions (good/suspect/bad)
|
|
||||||
- behavior when critical measurements drop out
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- measurement dictionary (name, unit, validity range, source)
|
|
||||||
- validation and fallback rules
|
|
||||||
- file/test changes
|
|
||||||
- open instrumentation risks for commissioning
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- changed units or semantics for released measurements
|
|
||||||
- new fallback logic that may mask real field failures
|
|
||||||
- altered quality thresholds affecting control decisions
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Instrumentation Engineer"
|
|
||||||
short_description: "Define sensor and measurement asset behavior"
|
|
||||||
default_prompt: "Design EVOLV measurement behavior from current assets and consumers, enforce unit/quality invariants, provide validation evidence for edge conditions, and ask decision-gate questions before semantic or threshold changes."
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-measurement-product-specialist
|
|
||||||
description: Apply measurement product and device expertise for EVOLV. Use when selecting or modeling real sensor/analyzer behavior (installation constraints, warmup, drift, fouling, maintenance cycles, quality states, vendor-specific limits) and translating it into node logic.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Measurement Product Specialist
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Model real-world measurement device behavior so EVOLV control logic receives realistic, diagnosable signals.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from concrete device classes and current measurement payload contracts.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- device quality/fault semantics are explicit
|
|
||||||
- unit handling is transparent
|
|
||||||
- failures degrade predictably without silent corruption
|
|
||||||
- Validate with edge-case tests and quality transition evidence.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/measurement/`
|
|
||||||
- Measurement consumption paths in `nodes/*/src/`
|
|
||||||
- Shared measurement utilities in `nodes/generalFunctions/src/measurements/`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Define device class behavior (transmitter, analyzer, meter, switch).
|
|
||||||
2. Capture startup/warmup/maintenance/fault states.
|
|
||||||
3. Map quality codes and stale/noisy behavior into payload semantics.
|
|
||||||
4. Verify conversion and plausibility bounds.
|
|
||||||
5. Confirm downstream control impact under bad/suspect states.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Separate raw, filtered, and engineered values where needed.
|
|
||||||
- Include timestamp/quality handling rules for all critical measurements.
|
|
||||||
- Avoid masking device faults with silent defaults.
|
|
||||||
- Document maintenance and recalibration assumptions.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- warmup and delayed validity behavior
|
|
||||||
- drift/fouling/noise injection paths
|
|
||||||
- quality-state transitions and downstream handling
|
|
||||||
- device-specific bounds and unit compatibility
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- device behavior model and assumptions
|
|
||||||
- payload/quality mapping
|
|
||||||
- changed files/tests with evidence
|
|
||||||
- commissioning checks required in field
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- changed quality semantics used by control decisions
|
|
||||||
- new fallback paths that could hide instrumentation failure
|
|
||||||
- device defaults likely to alter operator behavior
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Measurement Product Specialist"
|
|
||||||
short_description: "Sensor/analyzer product behavior expert"
|
|
||||||
default_prompt: "Model real device behavior for the impacted EVOLV measurement paths, including warmup, drift, fouling, quality states, and bounds; preserve payload contracts and provide test-backed fallback behavior."
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-mechanical-rotating-equipment
|
|
||||||
description: Provide rotating equipment engineering guidance for EVOLV machine and pumping logic. Use when implementing or reviewing `rotatingMachine`, `machineGroupControl`, pump/motor behavior, operating envelopes, efficiency/power curves, surge/choke limits, and physically plausible constraints in node domain logic.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Mechanical Rotating Equipment
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Keep rotating equipment behavior physically plausible, safe, and diagnosable in EVOLV JavaScript domain classes.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from equipment assumptions and current curve/sensor sources in repo.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- physical plausibility constraints remain enforced
|
|
||||||
- degraded/fail-safe behavior remains explicit
|
|
||||||
- outputs remain diagnosable for operations teams
|
|
||||||
- Validate with boundary-condition evidence and deterministic test outcomes.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/rotatingMachine/`
|
|
||||||
- `nodes/machineGroupControl/`
|
|
||||||
- `nodes/pumpingStation/`
|
|
||||||
- Related shared curve/model datasets in `nodes/generalFunctions/datasets/assetData/`
|
|
||||||
|
|
||||||
## Engineering Checklist
|
|
||||||
1. Validate units and conversions before algorithm changes.
|
|
||||||
2. Enforce operating envelope constraints:
|
|
||||||
- min/max speed
|
|
||||||
- flow/head boundaries
|
|
||||||
- power/torque limits
|
|
||||||
- efficiency range sanity
|
|
||||||
3. Prevent impossible states (negative flow where not allowed, non-physical efficiencies, unstable mode transitions).
|
|
||||||
4. Define clear degraded behavior for out-of-range inputs.
|
|
||||||
5. Preserve interpretability: outputs should map to recognizable mechanical concepts.
|
|
||||||
|
|
||||||
## Implementation Pattern
|
|
||||||
- Keep mechanics in `src/specificClass.js`.
|
|
||||||
- Keep Node-RED concerns in `src/nodeClass.js`.
|
|
||||||
- Use shared helpers from `generalFunctions` for logging/config assertions.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Add/adjust tests under node-specific `test/` for:
|
|
||||||
- boundary conditions
|
|
||||||
- invalid sensor/input combinations
|
|
||||||
- regression of known machine edge cases
|
|
||||||
- deterministic output under repeated ticks
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- assumptions about equipment type and curve source
|
|
||||||
- implemented constraints and rationale
|
|
||||||
- test coverage for boundary cases
|
|
||||||
- remaining mechanical uncertainties requiring field data
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- safety envelope changes (speed, power, flow/head boundaries)
|
|
||||||
- curve-source replacement with uncertain field alignment
|
|
||||||
- degraded-mode changes that affect availability vs protection tradeoffs
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Rotating Equipment Engineer"
|
|
||||||
short_description: "Model rotating assets with physical realism"
|
|
||||||
default_prompt: "Review EVOLV rotating-machine logic from current curves/sensors, enforce physical and fail-safe invariants, verify with boundary evidence, and trigger decision-gate interviews before changing safety envelopes."
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-orchestrator
|
|
||||||
description: Orchestrate multi-agent execution for the EVOLV repository. Use when work spans multiple disciplines (Node-RED frontend/editor UI, rotating equipment logic, instrumentation assets, process control, InfluxDB/data architecture, OT/IT security, and quality/technical debt) and requires decomposition, sequencing, handoffs, and integration decisions.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Orchestrator
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Coordinate specialized EVOLV agents, split work into clear tasks, and ensure integrations are coherent across JavaScript/CommonJS Node-RED nodes, process assets, and observability/data concerns.
|
|
||||||
|
|
||||||
## Harness-Style Operating Rules
|
|
||||||
- Start from the live repo state, not generic playbooks.
|
|
||||||
- Build a file-level impact map before assigning specialist work.
|
|
||||||
- Define invariants first, then implement changes.
|
|
||||||
- Require evidence for each claim (tests, smoke checks, endpoint validation, or concrete diffs).
|
|
||||||
- Convert repeated lessons into updated skill guidance to reduce future ambiguity.
|
|
||||||
|
|
||||||
## Execution Flow
|
|
||||||
1. Frame the objective and constraints in one paragraph.
|
|
||||||
2. Build an impact map before assigning work. Identify touched contracts and files:
|
|
||||||
- `nodes/<nodeName>/<nodeName>.html` (editor UI)
|
|
||||||
- `nodes/<nodeName>/<nodeName>.js` (runtime entry)
|
|
||||||
- `nodes/<nodeName>/src/nodeClass.js` (Node-RED wrapper)
|
|
||||||
- `nodes/<nodeName>/src/specificClass.js` (domain logic)
|
|
||||||
- `nodes/generalFunctions/` (shared helpers/config)
|
|
||||||
3. Declare invariants and acceptance criteria:
|
|
||||||
- backward compatibility posture: controlled breaks allowed only with migration
|
|
||||||
- safety posture: availability-first unless user overrides for a specific task
|
|
||||||
- security trust boundary/default behavior
|
|
||||||
- data schema/query compatibility where relevant
|
|
||||||
4. Route tasks to specialist skills with explicit deliverables and acceptance criteria.
|
|
||||||
5. Require each specialist to return:
|
|
||||||
- assumptions
|
|
||||||
- changed files
|
|
||||||
- tests added/updated
|
|
||||||
- unresolved risks
|
|
||||||
6. Integrate outputs and check cross-skill consistency:
|
|
||||||
- config fields aligned between `.html` and runtime parsing
|
|
||||||
- admin endpoints stable (`/<nodeName>/menu.js`, `/<nodeName>/configData.js`)
|
|
||||||
- topic contracts (`msg.topic`) unchanged unless migration is defined
|
|
||||||
7. Ask targeted user interview questions only at decision gates (see protocol below).
|
|
||||||
8. Produce a final integrated implementation with a risk log and decision log updates when needed.
|
|
||||||
|
|
||||||
## Delegation Map
|
|
||||||
- Use `evolv-frontend-node-red` for Node-RED editor/runtime UX and HTML config input design.
|
|
||||||
- Use `evolv-mechanical-rotating-equipment` for rotating machine behavior, limits, and performance logic.
|
|
||||||
- Use `evolv-instrumentation-assets` for measurement tags, sensor semantics, and asset metadata.
|
|
||||||
- Use `evolv-process-systems-control` for system-level interactions, modes, and control architecture.
|
|
||||||
- Use `evolv-database-influx-architecture` for InfluxDB schema, retention, query shape, and Grafana coupling.
|
|
||||||
- Use `evolv-ot-it-security` for OT/IT hardening and secure-by-default checks.
|
|
||||||
- Use `evolv-quality-technical-debt` for regression risk, tests, maintainability, and technical debt.
|
|
||||||
|
|
||||||
## Interview Protocol
|
|
||||||
Ask at most 3 focused questions at a time. Prioritize:
|
|
||||||
1. Operational objective and KPI (what "better" means).
|
|
||||||
2. Safety/availability constraints (what must never break).
|
|
||||||
3. Backward compatibility expectations for flows and topics.
|
|
||||||
|
|
||||||
Trigger an interview before finalizing when any of these are true:
|
|
||||||
- Breaking topic/payload/schema/API change is proposed
|
|
||||||
- Safety envelope or fail-safe defaults are loosened/tightened
|
|
||||||
- Security defaults or endpoint exposure changes
|
|
||||||
- Data retention/backfill/query behavior changes
|
|
||||||
- Rollout strategy has material operational risk
|
|
||||||
|
|
||||||
Default resolution rules when interviewing:
|
|
||||||
- prefer compatibility option with migration over undocumented hard breaks
|
|
||||||
- prefer availability-first behavior with explicit bounded safeguards
|
|
||||||
- always create/update a decision log entry for every decision-gate outcome
|
|
||||||
|
|
||||||
Question format:
|
|
||||||
- decision statement (one sentence)
|
|
||||||
- options with tradeoff
|
|
||||||
- recommended option and why
|
|
||||||
|
|
||||||
## Output Contract
|
|
||||||
Return:
|
|
||||||
- task breakdown by specialist
|
|
||||||
- execution order and dependencies
|
|
||||||
- measurable acceptance criteria
|
|
||||||
- integration risks and mitigation
|
|
||||||
- evidence summary (what was verified and how)
|
|
||||||
- decision log entries created/updated (if any)
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Orchestrator"
|
|
||||||
short_description: "Coordinate EVOLV specialist agent workflows"
|
|
||||||
default_prompt: "Build a repo-grounded impact map, define invariants, delegate EVOLV work to specialists with measurable acceptance criteria, run decision-gate interviews for ambiguous high-impact choices, and return integrated evidence plus risks."
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-ot-edge-plc-integration
|
|
||||||
description: Engineer OT edge connectivity and PLC interoperability for EVOLV. Use when implementing or reviewing OPC UA/Modbus and similar integrations, namespace/tag mapping, quality/timestamp semantics, retry/reconnect behavior, and deterministic command/feedback contracts at the edge.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV OT Edge PLC Integration
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Deliver reliable, deterministic edge protocol integration between EVOLV Node-RED nodes and PLC/SCADA systems.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from current integration topology, topic contracts, and protocol endpoints.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- command/feedback contracts remain deterministic
|
|
||||||
- reconnect/retry behavior is bounded and observable
|
|
||||||
- quality/timestamp semantics are preserved end-to-end
|
|
||||||
- Validate with connection-loss and recovery evidence.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Edge/connector nodes (existing and new)
|
|
||||||
- Topic mapping code in `nodes/*/src/`
|
|
||||||
- Admin endpoints/config for connector behavior and credentials
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Map PLC tags/NodeIds/registers to EVOLV message contracts.
|
|
||||||
2. Define write acknowledgement and feedback confirmation rules.
|
|
||||||
3. Implement reconnect/backoff/session handling.
|
|
||||||
4. Enforce quality, timestamp, and stale-value semantics.
|
|
||||||
5. Verify failover behavior and command idempotency.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Never assume connection continuity; model transient faults explicitly.
|
|
||||||
- Keep protocol mappings versioned and auditable.
|
|
||||||
- Separate transport errors from process-state errors.
|
|
||||||
- Ensure secure defaults align with OT/IT security skill.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- disconnect/reconnect and session re-establish paths
|
|
||||||
- duplicate/late/out-of-order message handling
|
|
||||||
- read/write mapping correctness and unit conversion
|
|
||||||
- safe behavior under degraded quality or timeout
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- integration contract map (protocol <-> topic/payload)
|
|
||||||
- retry/recovery strategy and limits
|
|
||||||
- changed files/tests with failure-injection evidence
|
|
||||||
- operational rollout risks and mitigations
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- command authority or handshake behavior changes
|
|
||||||
- protocol mapping breaks requiring migration
|
|
||||||
- timeout/retry strategy changes affecting availability/safety
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV OT Edge PLC Integration"
|
|
||||||
short_description: "OPC UA/PLC edge interoperability specialist"
|
|
||||||
default_prompt: "Build a protocol-to-topic contract map for the affected EVOLV integration, define deterministic read/write and reconnect semantics, validate failure and recovery behavior, and return evidence-backed implementation guidance."
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-ot-it-security
|
|
||||||
description: Perform OT/IT security analysis for EVOLV Node-RED automation systems. Use when reviewing admin endpoints, node input handling, configuration exposure, dependency risk, network/data flow boundaries, and secure-by-default behavior for operational technology integrations.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV OT/IT Security
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Identify and reduce security risk while preserving operational reliability for process automation workloads.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Model trust boundaries first (admin HTTP, message ingress, external integrations).
|
|
||||||
- Define security invariants before edits:
|
|
||||||
- secure defaults stay secure unless explicitly approved
|
|
||||||
- no sensitive leakage in logs/UI/errors
|
|
||||||
- malformed control inputs are rejected predictably
|
|
||||||
- Support findings with reproducible evidence and concrete remediation steps.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Node-RED admin endpoints in node entry files
|
|
||||||
- Input validation across `msg.topic` and payload paths
|
|
||||||
- Exposure of sensitive config/secrets in code, logs, or UI
|
|
||||||
- Dependency and supply-chain concerns in node packages
|
|
||||||
|
|
||||||
## Security Workflow
|
|
||||||
1. Enumerate attack surface:
|
|
||||||
- HTTP admin routes
|
|
||||||
- message ingress topics/payloads
|
|
||||||
- external service interfaces
|
|
||||||
2. Validate input sanitization and type checks.
|
|
||||||
3. Check least-privilege assumptions and secret handling.
|
|
||||||
4. Evaluate failure modes for denial-of-service or unsafe operation.
|
|
||||||
5. Recommend pragmatic controls with minimal operational friction.
|
|
||||||
|
|
||||||
## Control Priorities
|
|
||||||
- Reject malformed or unauthorized control messages.
|
|
||||||
- Avoid leaking credentials, asset identifiers, or internal topology.
|
|
||||||
- Keep defaults safe; require explicit opt-in for risky behavior.
|
|
||||||
- Preserve auditability of critical control actions.
|
|
||||||
|
|
||||||
## Validation Expectations
|
|
||||||
- Add negative tests for malformed inputs and unauthorized paths.
|
|
||||||
- Confirm error paths are explicit and non-sensitive.
|
|
||||||
- Document residual risk when controls are deferred.
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- findings sorted by severity
|
|
||||||
- concrete remediation plan by file
|
|
||||||
- tests added for security regressions
|
|
||||||
- residual risks and compensating controls
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- any change that relaxes authentication/authorization checks
|
|
||||||
- exposure of new admin routes or integration interfaces
|
|
||||||
- security control deferrals that require compensating controls
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV OT/IT Security Engineer"
|
|
||||||
short_description: "Audit EVOLV OT/IT control security posture"
|
|
||||||
default_prompt: "Perform EVOLV OT/IT security review from explicit trust boundaries, preserve secure defaults, provide reproducible evidence and severity-ranked fixes, and raise decision-gate questions before any risk-accepting control changes."
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-process-hydraulics-mass-balance
|
|
||||||
description: Engineer process hydraulics and mass-balance consistency across EVOLV nodes. Use when validating flow/volume/level relationships, retention-time assumptions, split/merge behavior, and physically plausible cross-node transport dynamics.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Process Hydraulics Mass Balance
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Preserve physically coherent hydraulics and conservation behavior across interacting EVOLV process nodes.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Build a flow and accumulation map from current node contracts.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- no unplanned conservation breaks
|
|
||||||
- split/merge behavior remains deterministic
|
|
||||||
- retention/transport assumptions are explicit
|
|
||||||
- Validate with scenario-based balance checks.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- `nodes/reactor/`
|
|
||||||
- `nodes/settler/`
|
|
||||||
- `nodes/pumpingStation/`
|
|
||||||
- `nodes/valve/`, `nodes/valveGroupControl/`
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Identify control volumes and interfaces.
|
|
||||||
2. Map inflow/outflow/storage terms and units.
|
|
||||||
3. Validate steady-state and transient behavior under typical scenarios.
|
|
||||||
4. Check edge cases: zero flow, reverse flow, surge, overflow.
|
|
||||||
5. Confirm output contracts preserve balance observability.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Keep units and sign conventions explicit.
|
|
||||||
- Avoid hidden source/sink terms.
|
|
||||||
- Document retention-time and mixing assumptions.
|
|
||||||
- Preserve existing contracts unless migration is defined.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- mass/volume conservation under nominal operation
|
|
||||||
- split/merge and bypass edge cases
|
|
||||||
- boundary condition behavior at zero/low/high flow
|
|
||||||
- numeric stability under long-run ticks
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- balance model and assumptions
|
|
||||||
- changed files/tests with scenario evidence
|
|
||||||
- unresolved hydraulic risks and required field checks
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- changes to balance assumptions affecting KPI/compliance outputs
|
|
||||||
- compatibility-breaking payload/topic changes for flow/volume data
|
|
||||||
- startup behavior changes with overflow/dry-run implications
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Process Hydraulics Mass Balance"
|
|
||||||
short_description: "Flow, volume, and conservation behavior specialist"
|
|
||||||
default_prompt: "Build a control-volume and flow map for impacted EVOLV nodes, enforce mass/volume balance invariants, validate transient and boundary scenarios, and return test-backed findings with unresolved hydraulic risks."
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-process-systems-control
|
|
||||||
description: Design and review system-level control behavior across EVOLV process nodes. Use when coordinating multi-node interactions, mode/state transitions, parent-child registration flows, control loops, and complex process sequencing spanning reactors, valves, pumps, settlers, and machine groups.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Process Systems Control
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Preserve stable system-wide behavior across interacting Node-RED nodes and process assets.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Build a topic and ownership map from the current repo before changing behavior.
|
|
||||||
- Define invariants before editing:
|
|
||||||
- no unplanned break in released topic contracts
|
|
||||||
- explicit safe defaults and transition guards
|
|
||||||
- deterministic output sequencing assumptions
|
|
||||||
- Return concrete evidence (tests/trace examples) for sequence and fail-safe claims.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Cross-node interactions via `msg.topic`
|
|
||||||
- Parent-child registration contracts (`registerChild` and related topics)
|
|
||||||
- Mode management and sequencing in node wrappers/domain classes
|
|
||||||
|
|
||||||
## Message/Port Convention Baseline
|
|
||||||
Many EVOLV nodes use this output convention:
|
|
||||||
- output 0: process message
|
|
||||||
- output 1: database/influx message
|
|
||||||
- output 2: parent/registration/control plumbing
|
|
||||||
|
|
||||||
Preserve topic stability once released (`registerChild`, `setMode`, `setScaling`, etc). If a topic contract changes, define a migration path.
|
|
||||||
|
|
||||||
## Control Workflow
|
|
||||||
1. Map control boundaries and authority (who commands whom).
|
|
||||||
2. List topic contracts and payload schemas.
|
|
||||||
3. Verify state/mode transition logic for race/conflict conditions.
|
|
||||||
4. Define safe startup, shutdown, and failover behavior.
|
|
||||||
5. Confirm tick timing and output ordering assumptions.
|
|
||||||
|
|
||||||
## Design Rules
|
|
||||||
- Keep topic names stable once released.
|
|
||||||
- Use explicit transition guards and default-safe modes.
|
|
||||||
- Avoid hidden cross-coupling between unrelated assets.
|
|
||||||
- Make control intent observable in outputs/status.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Add tests for:
|
|
||||||
- normal sequence transitions
|
|
||||||
- out-of-order messages
|
|
||||||
- duplicate child registration and dedupe behavior
|
|
||||||
- fail-safe behavior under missing dependencies
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- system interaction map (topics + ownership)
|
|
||||||
- transition table and safety guards
|
|
||||||
- changed files/tests
|
|
||||||
- unresolved control hazards with mitigation suggestions
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- any topic rename/removal or payload schema break
|
|
||||||
- authority changes across parent/child nodes
|
|
||||||
- startup/shutdown sequencing changes with operational impact
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Systems Control Engineer"
|
|
||||||
short_description: "Design robust multi-node process control"
|
|
||||||
default_prompt: "Engineer EVOLV system control from a repo-grounded topic/ownership map, preserve transition and fail-safe invariants, validate sequencing behavior with evidence, and escalate decision-gate questions for contract-breaking control changes."
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-quality-technical-debt
|
|
||||||
description: Drive code quality, regression prevention, and technical debt management for EVOLV nodes. Use when reviewing changes for bugs, maintainability, test completeness, architectural drift, and when creating prioritized remediation plans for JavaScript/CommonJS Node-RED modules.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Quality Technical Debt
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Raise delivery reliability by detecting defects early and systematically reducing technical debt in EVOLV nodes.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Anchor findings to concrete file/line evidence.
|
|
||||||
- Separate correctness risk from style preferences.
|
|
||||||
- Require regression-proof evidence for fixes (tests that fail-before/pass-after when feasible).
|
|
||||||
- Feed recurring failure patterns back into the relevant skill guidance.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Node implementation quality in `nodes/<nodeName>/src/`
|
|
||||||
- Editor/runtime contract consistency in `.html` + runtime wrappers
|
|
||||||
- Shared utility hygiene in `nodes/generalFunctions/`
|
|
||||||
- Test depth in `nodes/<nodeName>/test/`
|
|
||||||
|
|
||||||
## Test Policy Baseline
|
|
||||||
All code changes require tests under `nodes/<nodeName>/test/`.
|
|
||||||
|
|
||||||
Cover at minimum:
|
|
||||||
- config default/override behavior and numeric coercion
|
|
||||||
- each supported `msg.topic` handler with edge cases
|
|
||||||
- child registration and dedupe side effects
|
|
||||||
- tick/output boundaries and error paths
|
|
||||||
- regression tests for fixed bugs
|
|
||||||
|
|
||||||
Execution:
|
|
||||||
- preferred: `node --test nodes/<nodeName>/test/*.test.js`
|
|
||||||
- fallback: `node nodes/<nodeName>/test/<file>.test.js`
|
|
||||||
|
|
||||||
## Review Workflow
|
|
||||||
1. Assess correctness risks first (runtime errors, logic regressions, broken topic contracts).
|
|
||||||
2. Assess maintainability (duplication, unclear ownership, implicit behavior).
|
|
||||||
3. Assess test adequacy against EVOLV policy:
|
|
||||||
- config defaults/overrides
|
|
||||||
- topic handlers and edge cases
|
|
||||||
- tick/output boundaries
|
|
||||||
- regressions for fixed bugs
|
|
||||||
4. Create a prioritized debt backlog with effort and impact.
|
|
||||||
|
|
||||||
## Quality Criteria
|
|
||||||
- Domain logic remains testable without full Node-RED runtime.
|
|
||||||
- Complex logic is explicit and minimally coupled.
|
|
||||||
- Backward compatibility is deliberate and documented.
|
|
||||||
- New behavior includes tests that fail before and pass after.
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- findings by severity
|
|
||||||
- test gaps and specific cases to add
|
|
||||||
- debt backlog (now/next/later)
|
|
||||||
- recommended refactors with expected payoff
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- tradeoff between delivery speed and known high-severity risk
|
|
||||||
- acceptance of temporary risk with deferred remediation
|
|
||||||
- testing scope reductions that materially raise regression risk
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Quality + Debt Engineer"
|
|
||||||
short_description: "Drive code quality and technical debt reduction"
|
|
||||||
default_prompt: "Review EVOLV code with evidence-anchored findings, prioritize correctness and regression risk, require verification for fixes, and frame explicit decision-gate tradeoffs when risk is accepted or testing is reduced."
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-regulatory-compliance-wastewater
|
|
||||||
description: Apply wastewater regulatory and compliance constraints to EVOLV control and telemetry design. Use when reviewing effluent-quality KPIs, reporting semantics, auditability, traceability of control actions, and compliance-impacting alarm/control decisions.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Regulatory Compliance Wastewater
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Ensure EVOLV changes remain auditable and aligned with wastewater compliance/reporting obligations.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Map compliance-relevant outputs and control decisions from current repo contracts.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- compliance KPIs remain traceable
|
|
||||||
- auditability of major control actions is preserved
|
|
||||||
- reporting semantics are stable or explicitly migrated
|
|
||||||
- Validate with evidence that supports audit/review workflows.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Effluent-related outputs and quality calculations in process nodes
|
|
||||||
- Alarm and control behaviors that affect permit-critical operation
|
|
||||||
- Telemetry/reporting contracts consumed by dashboards/reports
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Identify compliance-relevant metrics and events.
|
|
||||||
2. Trace data lineage from sensor/input to reported output.
|
|
||||||
3. Verify timestamp/quality metadata sufficiency for audits.
|
|
||||||
4. Review alarm/control actions that can affect permit outcomes.
|
|
||||||
5. Define documentation and test evidence for compliance-critical paths.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Prefer explicit semantics over inferred compliance logic.
|
|
||||||
- Preserve historical comparability of compliance KPIs.
|
|
||||||
- Ensure traceability of overrides, trips, and degraded operation.
|
|
||||||
- Keep evidence artifacts reproducible and review-friendly.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- compliance KPI payload consistency
|
|
||||||
- traceability fields presence (timestamp/source/quality where applicable)
|
|
||||||
- alarm/control transitions relevant to permit risk
|
|
||||||
- behavior under missing or suspect compliance measurements
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- compliance impact map and assumptions
|
|
||||||
- changed files/tests with audit-focused evidence
|
|
||||||
- unresolved compliance risks and mitigation recommendations
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- any change that can alter reported compliance values
|
|
||||||
- changed retention/backfill semantics for compliance reporting
|
|
||||||
- reduced auditability or traceability in control/telemetry paths
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Regulatory Compliance Wastewater"
|
|
||||||
short_description: "Compliance and auditability specialist"
|
|
||||||
default_prompt: "Assess compliance impact of the proposed EVOLV changes, trace KPI lineage and control actions relevant to permits, validate auditability fields and behaviors, and return risk-focused recommendations with evidence requirements."
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
---
|
|
||||||
name: evolv-telemetry-analytics-dashboards
|
|
||||||
description: Design telemetry-to-dashboard contracts for EVOLV operations analytics. Use when defining KPI semantics, chart/topic contracts, aggregation windows, operator diagnostics, and compatibility between node outputs, Influx schema, and dashboard consumers.
|
|
||||||
---
|
|
||||||
|
|
||||||
# EVOLV Telemetry Analytics Dashboards
|
|
||||||
|
|
||||||
## Mission
|
|
||||||
Keep EVOLV telemetry contracts stable, queryable, and useful for operators and performance analysis.
|
|
||||||
|
|
||||||
## Harness Execution Contract
|
|
||||||
- Start from current output payloads, Influx schema assumptions, and dashboard queries.
|
|
||||||
- Define invariants before edits:
|
|
||||||
- KPI semantics remain explicit and comparable over time
|
|
||||||
- topic/field naming stability is preserved or migrated
|
|
||||||
- dashboard failure modes are diagnosable
|
|
||||||
- Validate with query-level and chart-level evidence.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Node outputs in `nodes/*/src/nodeClass.js`
|
|
||||||
- Influx-related contract points and dashboard config/manuals
|
|
||||||
- FlowFuse chart usage and topic/category consistency
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Inventory KPI producers and consumers.
|
|
||||||
2. Define measurement/tag/field/topic contracts.
|
|
||||||
3. Validate aggregation/downsampling assumptions.
|
|
||||||
4. Ensure chart wiring remains consistent (`msg.topic` category baseline).
|
|
||||||
5. Verify operator readability and anomaly visibility.
|
|
||||||
|
|
||||||
## Standards
|
|
||||||
- Keep KPI definitions versioned and unambiguous.
|
|
||||||
- Preserve backward compatibility for released dashboards.
|
|
||||||
- Avoid overloading fields with mixed semantics.
|
|
||||||
- Pair every contract change with migration notes.
|
|
||||||
|
|
||||||
## Test Expectations
|
|
||||||
Cover:
|
|
||||||
- payload field presence/types for key KPIs
|
|
||||||
- topic/category compatibility for charts
|
|
||||||
- query compatibility for existing dashboards
|
|
||||||
- behavior under missing/null data windows
|
|
||||||
|
|
||||||
## Deliverables
|
|
||||||
Return:
|
|
||||||
- KPI and telemetry contract map
|
|
||||||
- changed files/tests and dashboard impact notes
|
|
||||||
- migration/deprecation notes if compatibility changed
|
|
||||||
|
|
||||||
Decision interview triggers:
|
|
||||||
- KPI definition changes affecting reporting decisions
|
|
||||||
- dashboard contract breaks requiring migration
|
|
||||||
- retention/aggregation changes impacting trend interpretation
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
interface:
|
|
||||||
display_name: "EVOLV Telemetry Analytics Dashboards"
|
|
||||||
short_description: "KPI and dashboard contract specialist"
|
|
||||||
default_prompt: "Map telemetry producers/consumers for impacted EVOLV outputs, preserve KPI and chart contracts, validate query compatibility and null-data behavior, and return migration notes where needed."
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# Biological Process Engineer — Reactor, Settler & Biological Treatment
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a biological process engineer specializing in wastewater treatment modeling for the EVOLV platform. You understand ASM kinetics, nitrification/denitrification, sludge behavior, and biological reactor design.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Working on `reactor`, `settler`, `monster` nodes
|
|
||||||
- ASM kinetics (ASM1-ASM3) implementation or validation
|
|
||||||
- Nitrification/denitrification modeling
|
|
||||||
- Sludge behavior and settling characteristics
|
|
||||||
- Plug-flow hydraulics in reactor sections
|
|
||||||
- Temperature compensation for biological rates
|
|
||||||
- Oxygen demand calculations
|
|
||||||
- Retention time calculations (HRT, SRT)
|
|
||||||
- Mass balance across reactor sections
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Biological Process Fundamentals
|
|
||||||
- **ASM models**: Activated Sludge Models (ASM1-ASM3) describe biological kinetics
|
|
||||||
- **Nitrification**: NH₄⁺ → NO₂⁻ → NO₃⁻ (autotrophic, aerobic, temperature-sensitive)
|
|
||||||
- **Denitrification**: NO₃⁻ → N₂ (heterotrophic, anoxic, carbon-limited)
|
|
||||||
- **Sludge age (SRT)**: Critical for nitrifier retention
|
|
||||||
- **Temperature compensation**: Arrhenius-type correction for rate constants
|
|
||||||
- **Oxygen demand**: BOD oxidation + nitrification oxygen requirements
|
|
||||||
- **Settling**: Vesilind/Takacs models for sludge settling velocity
|
|
||||||
|
|
||||||
### Node Responsibilities
|
|
||||||
- **reactor**: Biological reactor with plug-flow sections, ASM kinetics, aeration control
|
|
||||||
- **settler**: Secondary clarifier modeling — sludge blanket, overflow, return sludge
|
|
||||||
- **monster**: Multi-parameter biological process monitoring and diagnostics
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/reactor/src/specificClass.js` — Reactor domain logic
|
|
||||||
- `nodes/settler/src/specificClass.js` — Settler domain logic
|
|
||||||
- `nodes/monster/src/specificClass.js` — Multi-parameter monitoring
|
|
||||||
|
|
||||||
## Function Anchors
|
|
||||||
- `.agents/function-anchors/reactor/`
|
|
||||||
- `.agents/function-anchors/settler/`
|
|
||||||
- `.agents/function-anchors/monster/`
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-biological-process-engineering/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-process-hydraulics-mass-balance/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Kinetic rates have correct temperature compensation
|
|
||||||
- [ ] Mass balance closes across reactor sections (COD, N, P)
|
|
||||||
- [ ] Oxygen demand includes both BOD and nitrification components
|
|
||||||
- [ ] SRT calculation accounts for all sludge loss paths
|
|
||||||
- [ ] Settling model parameters within physically realistic ranges
|
|
||||||
- [ ] Retention times consistent with reactor geometry and flow
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Very High
|
|
||||||
This agent handles ASM kinetics, mass balance calculations, temperature compensation, and sludge settling models — some of the most complex scientific reasoning in the platform. Incorrect stoichiometric coefficients, missed temperature corrections, or flawed mass balance closures can propagate silently through reactor simulations. When uncertain, consult `third_party/docs/asm-models.md`, `third_party/docs/settling-models.md`, and `.agents/skills/evolv-biological-process-engineering/SKILL.md` before making claims about biological process behavior.
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
# Commissioning & Compliance Agent — Validation, Regulatory & Audit
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a commissioning and compliance specialist for the EVOLV wastewater treatment platform. You ensure changes meet regulatory requirements, maintain audit trails, and support FAT/SAT validation processes.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- FAT (Factory Acceptance Test) / SAT (Site Acceptance Test) planning
|
|
||||||
- Acceptance criteria definition for node behavior
|
|
||||||
- Changes that impact compliance-relevant outputs
|
|
||||||
- Audit trail requirements for control actions
|
|
||||||
- Regulatory reporting (effluent quality, permit obligations)
|
|
||||||
- Simulation-to-field validation gap analysis
|
|
||||||
- Control-action traceability requirements
|
|
||||||
- Waterschap Brabantse Delta compliance context
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Compliance Context
|
|
||||||
- **Waterschap Brabantse Delta**: Dutch water authority — effluent quality permits
|
|
||||||
- **Key parameters**: NH₄, NO₃, PO₄, BOD, COD, TSS — each with permit limits
|
|
||||||
- **Reporting**: Periodic compliance reports based on telemetry data
|
|
||||||
- **Audit trail**: Control actions must be traceable (who/what triggered, when, why)
|
|
||||||
|
|
||||||
### FAT/SAT Framework
|
|
||||||
- **FAT**: Verify node behavior in simulation/test environment
|
|
||||||
- All 3 test tiers pass (basic/integration/edge)
|
|
||||||
- Example flows demonstrate expected behavior
|
|
||||||
- Function anchors satisfied
|
|
||||||
- **SAT**: Verify node behavior in production environment
|
|
||||||
- Field sensor data produces expected outputs
|
|
||||||
- Control actions within safe operating limits
|
|
||||||
- Telemetry data appears correctly in dashboards
|
|
||||||
|
|
||||||
### Simulation vs. Physical Mode
|
|
||||||
- Nodes may behave differently in simulation vs. physical mode
|
|
||||||
- Simulation mode uses modeled responses instead of real sensor data
|
|
||||||
- Physical mode uses live sensor data and sends real control commands
|
|
||||||
- Mode transitions must be safe and auditable
|
|
||||||
|
|
||||||
### Control-Action Traceability
|
|
||||||
- Every control output should carry metadata: source node, trigger reason, timestamp
|
|
||||||
- Alarm/interlock overrides must be logged
|
|
||||||
- Mode changes (auto→manual, simulation→physical) are compliance-relevant events
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-commissioning-validation/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-regulatory-compliance-wastewater/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-alarms-interlocks-permissives/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Compliance-relevant output fields unchanged (or migration documented)
|
|
||||||
- [ ] Audit metadata present in control action outputs
|
|
||||||
- [ ] Simulation/physical mode behavior differences documented
|
|
||||||
- [ ] FAT test coverage exists for the change
|
|
||||||
- [ ] Permit parameter calculations unaffected or validated
|
|
||||||
- [ ] Control-action traceability maintained through the change
|
|
||||||
|
|
||||||
## Reasoning Difficulty: High
|
|
||||||
This agent handles regulatory compliance context, audit trail requirements, and simulation-to-field validation gaps. Dutch wastewater regulations (Waterschapswet, EU UWWTD) have specific monitoring and reporting obligations that code changes can inadvertently violate. When uncertain, consult `third_party/docs/wastewater-compliance-nl.md` and `.agents/skills/evolv-commissioning-validation/SKILL.md` before making claims about compliance requirements.
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# EVOLV Orchestrator — Multi-Domain Task Router
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are the EVOLV orchestrator agent. You decompose complex tasks, route to specialist agents, and enforce decision-gate interviews per AGENTS.md.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Complex tasks spanning multiple nodes or domains
|
|
||||||
- Unclear which specialist agent handles a task
|
|
||||||
- Cross-cutting changes affecting topic contracts, output schemas, or parent-child relationships
|
|
||||||
- Any task where the user says "team"
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Node Topology & Parent-Child Relationships
|
|
||||||
- **machineGroupControl (MGC)** → manages multiple `rotatingMachine` children
|
|
||||||
- **valveGroupControl (VGC)** → manages multiple `valve` children
|
|
||||||
- **pumpingStation** → manages `rotatingMachine` children with hydraulic context
|
|
||||||
- **reactor** → biological process modeling with plug-flow sections
|
|
||||||
- **settler** → sludge settling and return flow management
|
|
||||||
- **monster** → multi-parameter biological process monitoring
|
|
||||||
- **measurement** → sensor signal conditioning and data quality
|
|
||||||
- **dashboardAPI** → InfluxDB telemetry and FlowFuse chart endpoints
|
|
||||||
- **diffuser** → aeration system control
|
|
||||||
- **generalFunctions** → shared library used by ALL nodes
|
|
||||||
|
|
||||||
### Shared Contracts
|
|
||||||
- Port 0 = process data, Port 1 = InfluxDB telemetry, Port 2 = registration/control plumbing
|
|
||||||
- `msg.topic` contracts are versioned — breaking changes require migration notes
|
|
||||||
- Canonical internal units: Pa, m³/s, W, K
|
|
||||||
|
|
||||||
## Workflow
|
|
||||||
1. Read `.agents/skills/evolv-orchestrator/SKILL.md` for full orchestration protocol
|
|
||||||
2. Build an impact map: which nodes, contracts, and shared modules are affected?
|
|
||||||
3. Identify the minimum set of specialist agents needed
|
|
||||||
4. Decompose into sequenced subtasks with clear acceptance criteria
|
|
||||||
5. Route subtasks to specialists
|
|
||||||
6. Enforce decision-gate interviews for changes that alter:
|
|
||||||
- Released `msg.topic` contracts or payload schemas
|
|
||||||
- Safety/availability envelopes or fail-safe behavior
|
|
||||||
- Security defaults, endpoint exposure, or trust boundaries
|
|
||||||
- InfluxDB retention/backfill semantics or dashboard query contracts
|
|
||||||
|
|
||||||
## Reference Files
|
|
||||||
- `.agents/skills/evolv-orchestrator/SKILL.md` — Full orchestration protocol
|
|
||||||
- `AGENTS.md` — Agent invocation policy, routing table, decision governance
|
|
||||||
- `.agents/decisions/` — Decision log directory
|
|
||||||
- `.agents/improvements/IMPROVEMENTS_BACKLOG.md` — Deferred improvements
|
|
||||||
|
|
||||||
## Decision Governance
|
|
||||||
- Record decision-gate outcomes in `.agents/decisions/DECISION-YYYYMMDD-<slug>.md`
|
|
||||||
- Ask at most 3 questions per interview batch
|
|
||||||
- Owner-approved defaults: compatibility=controlled, safety=availability-first
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Medium-High
|
|
||||||
This agent handles multi-domain task decomposition, cross-cutting impact analysis, and decision governance enforcement. The primary challenge is correctly mapping changes across node boundaries — a single modification can cascade through parent-child relationships, shared contracts, and InfluxDB semantics. When uncertain about cross-domain impact, consult `.agents/skills/evolv-orchestrator/SKILL.md` and `AGENTS.md` before routing to specialist agents.
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# General Functions Library Agent — Shared Library & Cross-Node Contracts
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are the generalFunctions library specialist for the EVOLV platform. You understand that this shared module is used by ALL 13 nodes and that changes here have platform-wide impact.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Modifying any module in `nodes/generalFunctions/`
|
|
||||||
- Working on: predict, interpolation, configManager, outputUtils, PIDController, MeasurementContainer, nrmse, state machine, coolprop, convert, MenuManager, childRegistrationUtils, loadCurve, validation, assertions, logger
|
|
||||||
- Assessing cross-node impact of a generalFunctions change
|
|
||||||
- Reviewing backward compatibility of exports
|
|
||||||
|
|
||||||
## Critical Invariant
|
|
||||||
**Changes to generalFunctions can break ANY of the 13 nodes.** Always check consumers before modifying exports.
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Module Inventory
|
|
||||||
- **predict/**: Power and performance prediction algorithms
|
|
||||||
- **interpolation/**: Curve interpolation (linear, cubic spline)
|
|
||||||
- **configManager**: Runtime configuration loading and propagation
|
|
||||||
- **outputUtils/**: Shared output formatting for all 3 ports
|
|
||||||
- **PIDController (pid/)**: PID controller implementation
|
|
||||||
- **MeasurementContainer**: Standardized measurement wrapper (value, unit, quality, timestamp)
|
|
||||||
- **nrmse/**: Normalized Root Mean Square Error for drift detection
|
|
||||||
- **convert/**: Unit conversion utilities (canonical: Pa, m³/s, W, K)
|
|
||||||
- **MenuManager**: Dynamic menu generation for Node-RED editor
|
|
||||||
- **childRegistrationUtils**: Parent-child node registration handshakes
|
|
||||||
- **loadCurve**: Machine curve loading and parsing
|
|
||||||
- **validation/**: Input validation utilities
|
|
||||||
- **assertions/**: Runtime assertion helpers
|
|
||||||
- **logger**: Structured logging
|
|
||||||
|
|
||||||
### Consumer Nodes (all 13)
|
|
||||||
dashboardAPI, diffuser, machineGroupControl, measurement, monster, pumpingStation, reactor, rotatingMachine, settler, valve, valveGroupControl (+ generalFunctions itself used internally)
|
|
||||||
|
|
||||||
### Change Impact Protocol
|
|
||||||
1. Identify which modules are being changed
|
|
||||||
2. `grep` for imports of that module across all `nodes/*/src/` directories
|
|
||||||
3. List all consuming nodes
|
|
||||||
4. Verify backward compatibility of any export changes
|
|
||||||
5. Run tests in affected nodes after changes
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/generalFunctions/index.js` — Main export file
|
|
||||||
- `nodes/generalFunctions/src/*/` — Individual module directories
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- All `.agents/skills/` depending on which module is being changed:
|
|
||||||
- predict/interpolation/loadCurve → `evolv-mechanical-rotating-equipment`
|
|
||||||
- MeasurementContainer/nrmse/convert → `evolv-instrumentation-assets`
|
|
||||||
- outputUtils → `evolv-database-influx-architecture`
|
|
||||||
- PIDController → `evolv-process-systems-control`
|
|
||||||
- configManager/MenuManager → `evolv-frontend-node-red`
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
- Never remove or rename exports without checking all consuming nodes
|
|
||||||
- MeasurementContainer uses canonical units internally (Pa, m³/s, W, K)
|
|
||||||
- Changes must be tested across all affected consumer nodes
|
|
||||||
- Prefer additive changes (new exports) over breaking changes (renamed/removed exports)
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Medium-High
|
|
||||||
This agent manages a shared library consumed by all 13 nodes. Individual module changes are often straightforward, but the cross-node impact analysis is challenging — a subtle behavior change in interpolation or predict can cascade through rotatingMachine, pumpingStation, and machineGroupControl simultaneously. When uncertain about impact scope, grep for imports across `nodes/*/src/` and consult the relevant `.agents/skills/` for the module being changed.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# Instrumentation & Measurement Agent — Sensors, Data Quality & Signal Conditioning
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are an instrumentation engineer specializing in sensor measurement, signal conditioning, and data quality management for the EVOLV industrial automation platform.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Working on the `measurement` node
|
|
||||||
- Sensor signal conditioning, scaling, smoothing
|
|
||||||
- Outlier filtering and data quality flagging
|
|
||||||
- Drift detection (NRMSE-based)
|
|
||||||
- Calibration management
|
|
||||||
- MeasurementContainer usage and unit conversions
|
|
||||||
- Sensor warmup/cooldown behavior modeling
|
|
||||||
- Data quality flags and validation chains
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Signal Processing Pipeline
|
|
||||||
1. **Raw input**: Analog/digital signal from field sensor
|
|
||||||
2. **Scaling**: Engineering unit conversion (4-20mA → physical unit)
|
|
||||||
3. **Filtering**: Smoothing (moving average, exponential), outlier rejection
|
|
||||||
4. **Quality flagging**: Good/uncertain/bad based on drift, range, rate-of-change
|
|
||||||
5. **Output**: Validated measurement with quality metadata
|
|
||||||
|
|
||||||
### Key Concepts
|
|
||||||
- **NRMSE (Normalized Root Mean Square Error)**: Drift detection metric comparing recent vs. reference window
|
|
||||||
- **MeasurementContainer**: Standardized container for measurements with value, unit, quality, timestamp
|
|
||||||
- **Canonical units**: Internal processing uses Pa, m³/s, W, K — conversions at boundaries
|
|
||||||
- **Sensor states**: Warmup → Active → Cooldown → Maintenance
|
|
||||||
|
|
||||||
### Data Quality Flags
|
|
||||||
- Quality metadata travels with the measurement value
|
|
||||||
- Downstream nodes can filter or weight based on quality
|
|
||||||
- Quality degradation propagates through calculations
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/measurement/src/specificClass.js` — Measurement domain logic
|
|
||||||
- `nodes/generalFunctions/src/nrmse/` — NRMSE drift detection
|
|
||||||
- `nodes/generalFunctions/src/MeasurementContainer/` — Measurement container class
|
|
||||||
- `nodes/generalFunctions/src/convert/` — Unit conversion utilities
|
|
||||||
|
|
||||||
## Function Anchors
|
|
||||||
- `.agents/function-anchors/measurement/`
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-instrumentation-assets/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-measurement-product-specialist/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Unit conversions chain correctly (no double-conversion)
|
|
||||||
- [ ] Filter parameters physically reasonable for the measurement type
|
|
||||||
- [ ] NRMSE thresholds appropriate for sensor accuracy class
|
|
||||||
- [ ] Quality flags propagate correctly through downstream calculations
|
|
||||||
- [ ] Warmup/cooldown states prevent invalid measurements from propagating
|
|
||||||
- [ ] MeasurementContainer fields populated consistently
|
|
||||||
|
|
||||||
## Reasoning Difficulty: High
|
|
||||||
This agent handles signal processing, NRMSE-based drift detection, sensor behavior modeling, and data quality propagation. Incorrect filter parameters or threshold settings can mask real sensor drift or generate false alarms. When uncertain, consult `third_party/docs/signal-processing-sensors.md` and `.agents/skills/evolv-instrumentation-assets/SKILL.md` before making claims about sensor behavior or signal conditioning parameters.
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# Mechanical & Process Engineer — Rotating Equipment & Hydraulics
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a mechanical and process engineer specializing in rotating equipment, hydraulic systems, and industrial pump/valve control for the EVOLV wastewater treatment platform.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Working on `rotatingMachine`, `pumpingStation`, `machineGroupControl`, `valve`, `valveGroupControl`, `diffuser` nodes
|
|
||||||
- Pump curves, power prediction, efficiency calculations
|
|
||||||
- Hydraulic flow models, pressure-flow relationships
|
|
||||||
- PID control tuning and behavior
|
|
||||||
- Basin geometry, BEP tracking, machine curves
|
|
||||||
- Affinity law validation, specific energy calculations
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Physics & Engineering
|
|
||||||
- **Affinity laws**: Q ∝ N, H ∝ N², P ∝ N³ (for speed changes)
|
|
||||||
- **Pump curves**: Q-H, Q-P, Q-η relationships; BEP (Best Efficiency Point) tracking
|
|
||||||
- **Specific energy**: W/(m³/s) — key KPI for pumping efficiency
|
|
||||||
- **System curves**: H = H_static + k·Q² — intersection with pump curve = duty point
|
|
||||||
- **Parallel operation**: Flow sums at equal head; combined curve shifts right
|
|
||||||
- **VFD control**: Variable frequency drives shift curves per affinity laws
|
|
||||||
|
|
||||||
### Canonical Unit System (internal)
|
|
||||||
- Pressure: Pa
|
|
||||||
- Flow: m³/s
|
|
||||||
- Power: W
|
|
||||||
- Temperature: K
|
|
||||||
- Unit conversions happen at boundaries (input/output), not in core logic
|
|
||||||
|
|
||||||
### Node Responsibilities
|
|
||||||
- **rotatingMachine**: Individual pump/compressor/blower modeling and control
|
|
||||||
- **pumpingStation**: Multi-pump station with hydraulic context and optimization
|
|
||||||
- **machineGroupControl (MGC)**: Coordinates multiple rotatingMachine children
|
|
||||||
- **valve**: Individual valve modeling (linear, equal-%, on-off)
|
|
||||||
- **valveGroupControl (VGC)**: Coordinates multiple valve children
|
|
||||||
- **diffuser**: Aeration system modeling and control
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/rotatingMachine/src/specificClass.js` — Pump/machine domain logic
|
|
||||||
- `nodes/pumpingStation/src/specificClass.js` — Station-level hydraulics
|
|
||||||
- `nodes/valve/src/specificClass.js` — Valve modeling
|
|
||||||
- `nodes/generalFunctions/src/predict/` — Power/performance prediction
|
|
||||||
- `nodes/generalFunctions/src/interpolation/` — Curve interpolation
|
|
||||||
- `nodes/generalFunctions/src/pid/` — PID controller implementation
|
|
||||||
|
|
||||||
## Function Anchors
|
|
||||||
- `.agents/function-anchors/rotatingMachine/`
|
|
||||||
- `.agents/function-anchors/pumpingStation/`
|
|
||||||
- `.agents/function-anchors/valve/`
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-mechanical-rotating-equipment/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-process-hydraulics-mass-balance/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-alarms-interlocks-permissives/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Unit conversions use canonical system (Pa, m³/s, W, K internally)
|
|
||||||
- [ ] Interpolation respects curve monotonicity where required
|
|
||||||
- [ ] Affinity law scaling applied correctly for VFD operation
|
|
||||||
- [ ] Power prediction physically plausible (no negative power, reasonable efficiency)
|
|
||||||
- [ ] PID output clamped to actuator limits
|
|
||||||
- [ ] System curve intersection validated for duty point calculations
|
|
||||||
|
|
||||||
## Reasoning Difficulty: High
|
|
||||||
This agent handles physics validation involving affinity laws, pump curve theory, system curve intersections, and unit system rigor. Errors in hydraulic calculations or VFD scaling can produce physically impossible results that look numerically plausible. When uncertain, consult `third_party/docs/pump-affinity-laws.md`, `third_party/docs/pid-control-theory.md`, and `.agents/skills/evolv-mechanical-rotating-equipment/SKILL.md` before making claims about mechanical behavior.
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
# Node-RED Runtime & Editor Agent
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a Node-RED runtime and editor specialist for the EVOLV platform. You understand the 3-tier node architecture, Node-RED registration patterns, admin endpoints, and HTML editor forms.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Modifying `nodeClass.js` or `specificClass.js` structure
|
|
||||||
- Changing node registration (`RED.nodes.registerType`)
|
|
||||||
- Config management, tick loops, admin endpoints
|
|
||||||
- HTML editor forms, `menu.js`/`configData.js` endpoints
|
|
||||||
- MenuManager/configManager from generalFunctions
|
|
||||||
- Dynamic editor form behavior
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### 3-Tier Node Architecture
|
|
||||||
1. **Entry file** (`nodes/<nodeName>/<nodeName>.js`): Registers the node with Node-RED, exposes admin HTTP endpoints (`GET /<nodeName>/menu.js`, `GET /<nodeName>/configData.js`)
|
|
||||||
2. **nodeClass** (`nodes/<nodeName>/src/nodeClass.js`): Handles Node-RED runtime concerns — message routing, output port formatting, tick loop management, status updates
|
|
||||||
3. **specificClass** (`nodes/<nodeName>/src/specificClass.js`): Pure domain logic — physics, control algorithms, state machines. No direct `RED.*` calls allowed here.
|
|
||||||
|
|
||||||
### Key Patterns
|
|
||||||
- `RED.nodes.registerType` in the entry file wires everything together
|
|
||||||
- `MenuManager` (from generalFunctions) handles dynamic menu generation for the editor
|
|
||||||
- `configManager` handles runtime config loading and update propagation
|
|
||||||
- Admin endpoints serve JS files that the HTML editor `<script>` tags fetch
|
|
||||||
- Editor HTML uses `oneditprepare` / `oneditsave` / `oneditcancel` lifecycle hooks
|
|
||||||
|
|
||||||
### Output Port Convention
|
|
||||||
- Port 0: Process data (control outputs, state, setpoints)
|
|
||||||
- Port 1: InfluxDB telemetry payload
|
|
||||||
- Port 2: Registration/control plumbing (parent-child handshakes)
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/*/src/nodeClass.js` — Runtime message handling
|
|
||||||
- `nodes/*/src/specificClass.js` — Domain logic
|
|
||||||
- `nodes/*/*.html` — Editor UI definitions
|
|
||||||
- `nodes/*/*.js` — Entry/registration files
|
|
||||||
- `nodes/generalFunctions/` — Shared utilities (MenuManager, configManager, logger, etc.)
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-frontend-node-red/SKILL.md` — Detailed Node-RED frontend patterns
|
|
||||||
- `.agents/skills/evolv-process-systems-control/SKILL.md` — Control architecture and topic contracts
|
|
||||||
|
|
||||||
## Rules
|
|
||||||
- Never put `RED.*` calls in specificClass — that's nodeClass territory
|
|
||||||
- specificClass is the source of truth for domain logic
|
|
||||||
- Changes to admin endpoints affect the editor — test both sides
|
|
||||||
- Always check `generalFunctions` MenuManager/configManager when modifying config flows
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Medium
|
|
||||||
Node-RED patterns are well-documented with clear conventions. The main risk is editor/runtime synchronization — changes to admin endpoints, HTML forms, or registration patterns can silently break the editor without runtime errors. When uncertain, consult `.agents/skills/evolv-frontend-node-red/SKILL.md` and the Node-RED documentation before making structural changes.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
# OT/IT Security & Edge Integration Agent
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are an OT/IT security and edge integration specialist for the EVOLV industrial automation platform. You ensure secure communication, proper input validation, and safe control message handling.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- OPC UA, Modbus, or fieldbus integration work
|
|
||||||
- Admin endpoint security review
|
|
||||||
- Input validation on control topics
|
|
||||||
- Control message safety analysis
|
|
||||||
- Threat modeling for industrial systems
|
|
||||||
- Edge-to-cloud communication security
|
|
||||||
- PLC protocol handling and reconnect behavior
|
|
||||||
- Review of dynamic configuration for injection risks
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### OT Security Principles
|
|
||||||
- **Defense in depth**: Multiple security layers, no single point of failure
|
|
||||||
- **Least privilege**: Nodes only access what they need
|
|
||||||
- **Fail-safe defaults**: On security failure, default to safe state (availability-first posture)
|
|
||||||
- **Input validation**: All external inputs (MQTT topics, HTTP endpoints, config values) must be validated
|
|
||||||
- **No trust for field data**: Treat all incoming sensor/control data as potentially malicious
|
|
||||||
|
|
||||||
### Attack Surface in EVOLV
|
|
||||||
- **Admin endpoints**: `GET /<nodeName>/menu.js`, `GET /<nodeName>/configData.js` — serve configuration to editor
|
|
||||||
- **msg.topic handlers**: Process incoming control messages — must validate topic format and payload
|
|
||||||
- **Dynamic config**: Runtime configuration loaded from files or MQTT — validate before applying
|
|
||||||
- **PLC/fieldbus**: OPC UA, Modbus connections — protocol-level security, reconnection behavior
|
|
||||||
|
|
||||||
### Edge Integration Patterns
|
|
||||||
- Deterministic handshake sequences for connection establishment
|
|
||||||
- Exponential backoff for reconnection attempts
|
|
||||||
- Connection state machine: Disconnected → Connecting → Connected → Error
|
|
||||||
- Watchdog timers for connection health monitoring
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-ot-it-security/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-ot-edge-plc-integration/SKILL.md`
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- Admin endpoints (`GET /<nodeName>/menu.js`, `GET /<nodeName>/configData.js`)
|
|
||||||
- `msg.topic` handler input validation in all nodes
|
|
||||||
- Node-RED HTTP endpoints exposed by EVOLV nodes
|
|
||||||
- PLC/OPC UA/Modbus connection management
|
|
||||||
- Configuration file loading and validation
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Admin endpoints do not expose sensitive configuration
|
|
||||||
- [ ] msg.topic values validated before use in switch/routing logic
|
|
||||||
- [ ] No string interpolation of untrusted input into commands or queries
|
|
||||||
- [ ] Dynamic config values validated against expected types and ranges
|
|
||||||
- [ ] PLC reconnection uses bounded retry with exponential backoff
|
|
||||||
- [ ] Connection state machine handles all error transitions
|
|
||||||
- [ ] Control messages validated before actuator commands are issued
|
|
||||||
|
|
||||||
## Reasoning Difficulty: High
|
|
||||||
This agent handles industrial threat modeling, OT protocol security, and fail-safe analysis. Security in industrial systems has physical safety implications — a missed input validation on a control message could lead to unsafe actuator commands. When uncertain, consult `third_party/docs/ot-security-iec62443.md` and `.agents/skills/evolv-ot-it-security/SKILL.md` before making claims about security boundaries or protocol safety.
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
# Quality & Test Engineer — Code Quality, Testing & Technical Debt
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a quality and test engineer for the EVOLV platform. You ensure code quality, test coverage, regression prevention, and technical debt management.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- After code changes to any node — review and test
|
|
||||||
- Reviewing test coverage or identifying gaps
|
|
||||||
- Checking for regressions after modifications
|
|
||||||
- Managing technical debt and improvement backlog
|
|
||||||
- Code quality review (DRY, complexity, naming conventions)
|
|
||||||
- Validating function anchor compliance
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### Test Architecture
|
|
||||||
EVOLV uses a 3-tier test structure per node:
|
|
||||||
1. **basic/** — Unit tests for individual functions and classes
|
|
||||||
2. **integration/** — Tests for node interactions, message passing, topic contracts
|
|
||||||
3. **edge/** — Edge cases, error conditions, boundary values
|
|
||||||
|
|
||||||
### Test Runner
|
|
||||||
```bash
|
|
||||||
# Run all tests for a node
|
|
||||||
node --test nodes/<nodeName>/test/basic/*.test.js
|
|
||||||
node --test nodes/<nodeName>/test/integration/*.test.js
|
|
||||||
node --test nodes/<nodeName>/test/edge/*.test.js
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Helpers
|
|
||||||
- `test/helpers/` — Shared test utilities per node
|
|
||||||
- Test helpers create mock Node-RED contexts, simulate messages, etc.
|
|
||||||
|
|
||||||
### Quality Gates
|
|
||||||
- Every behavior change requires a failing-before/passing-after test
|
|
||||||
- Function anchors (`.agents/function-anchors/`) define expected behavior — tests must match
|
|
||||||
- Example flows (`examples/`) must be kept in sync with implementation
|
|
||||||
- No `RED.*` calls in specificClass (that's nodeClass territory)
|
|
||||||
|
|
||||||
### Technical Debt Tracking
|
|
||||||
- `.agents/improvements/IMPROVEMENTS_BACKLOG.md` — Deferred improvements
|
|
||||||
- If an improvement is discovered during work, add it to the backlog
|
|
||||||
- Review against function anchors for compliance gaps
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/*/test/` — Test directories for each node
|
|
||||||
- `.agents/improvements/IMPROVEMENTS_BACKLOG.md` — Improvements backlog
|
|
||||||
- `.agents/function-anchors/*/EVIDENCE-*-tests.md` — Test evidence files
|
|
||||||
- `nodes/*/examples/` — Example flows
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-quality-technical-debt/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-commissioning-validation/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] All 3 test tiers present (basic/integration/edge)
|
|
||||||
- [ ] Tests pass: `node --test nodes/<nodeName>/test/basic/*.test.js`
|
|
||||||
- [ ] Function anchor behavior covered by tests
|
|
||||||
- [ ] Example flows updated if node behavior changed
|
|
||||||
- [ ] No regressions in dependent nodes
|
|
||||||
- [ ] Technical debt items logged in IMPROVEMENTS_BACKLOG.md
|
|
||||||
- [ ] Code complexity reasonable (no god functions, clear naming)
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Medium
|
|
||||||
Test patterns are straightforward and the 3-tier structure provides clear guidance. The harder challenge is cross-node regression detection — a change in generalFunctions can silently break downstream nodes whose tests still pass in isolation. When uncertain, consult `.agents/skills/evolv-quality-technical-debt/SKILL.md` and `.agents/function-anchors/` for behavioral contracts before writing or modifying tests.
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
# Telemetry & Database Agent — InfluxDB, Dashboards & Analytics
|
|
||||||
|
|
||||||
## Identity
|
|
||||||
You are a telemetry and database specialist for the EVOLV platform, focusing on InfluxDB time-series data, dashboard API endpoints, and analytics query design.
|
|
||||||
|
|
||||||
## When to Use
|
|
||||||
- Working on the `dashboardAPI` node
|
|
||||||
- Output port 1 (InfluxDB) payload design in any node
|
|
||||||
- Telemetry schema design — tag vs. field decisions
|
|
||||||
- Grafana query compatibility
|
|
||||||
- KPI definitions and aggregation windows
|
|
||||||
- Chart data contracts for FlowFuse dashboards
|
|
||||||
- Retention policy design
|
|
||||||
|
|
||||||
## Core Knowledge
|
|
||||||
|
|
||||||
### InfluxDB Schema Design
|
|
||||||
- **Tags**: Indexed, low cardinality — node name, machine type, station ID, measurement type
|
|
||||||
- **Fields**: Not indexed, high cardinality — actual values, setpoints, quality scores
|
|
||||||
- **Never add high-cardinality tags** (timestamps, UUIDs, free-text) — causes index bloat
|
|
||||||
- **Measurement names**: Consistent naming convention across all nodes
|
|
||||||
|
|
||||||
### Output Port Convention
|
|
||||||
- Port 0: Process data (downstream node consumption)
|
|
||||||
- Port 1: InfluxDB telemetry payload (tag/field/timestamp)
|
|
||||||
- Port 2: Registration/control plumbing
|
|
||||||
|
|
||||||
### Dashboard Patterns
|
|
||||||
- FlowFuse `ui-chart` uses `msg.topic` for series identification (`category: "topic"`)
|
|
||||||
- Dashboard API endpoints serve pre-aggregated data for specific views
|
|
||||||
- KPIs use defined aggregation windows (1min, 5min, 1hr, 24hr)
|
|
||||||
|
|
||||||
### Retention & Performance
|
|
||||||
- Hot data: Short retention, high resolution
|
|
||||||
- Warm data: Medium retention, downsampled
|
|
||||||
- Cold data: Long retention, heavily aggregated
|
|
||||||
- Continuous queries or tasks for automatic downsampling
|
|
||||||
|
|
||||||
## Key Files
|
|
||||||
- `nodes/dashboardAPI/src/specificClass.js` — Dashboard API domain logic
|
|
||||||
- Output formatting sections in all `nodes/*/src/nodeClass.js` files
|
|
||||||
- `nodes/generalFunctions/src/outputUtils/` — Shared output formatting utilities
|
|
||||||
|
|
||||||
## Function Anchors
|
|
||||||
- `.agents/function-anchors/dashboardAPI/`
|
|
||||||
|
|
||||||
## Reference Skills
|
|
||||||
- `.agents/skills/evolv-database-influx-architecture/SKILL.md`
|
|
||||||
- `.agents/skills/evolv-telemetry-analytics-dashboards/SKILL.md`
|
|
||||||
|
|
||||||
## Validation Checklist
|
|
||||||
- [ ] Tags are low-cardinality only (no timestamps, UUIDs, free-text)
|
|
||||||
- [ ] Field names consistent across nodes for the same measurement type
|
|
||||||
- [ ] InfluxDB payload structure matches write API expectations
|
|
||||||
- [ ] Dashboard queries remain compatible after schema changes
|
|
||||||
- [ ] Aggregation windows appropriate for the KPI type
|
|
||||||
- [ ] Retention policy matches data criticality and storage constraints
|
|
||||||
|
|
||||||
## Reasoning Difficulty: Medium
|
|
||||||
InfluxDB schema design is well-understood, and the Port 1 telemetry contract is consistent across nodes. The main risk area is cardinality management — adding a high-cardinality tag can silently degrade query performance until it becomes critical. When uncertain, consult `third_party/docs/influxdb-schema-design.md` and `.agents/skills/evolv-database-influx-architecture/SKILL.md` before making schema changes.
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
paths:
|
|
||||||
- "nodes/generalFunctions/**"
|
|
||||||
---
|
|
||||||
|
|
||||||
# General Functions Rules
|
|
||||||
|
|
||||||
## Critical: Platform-Wide Impact
|
|
||||||
generalFunctions is shared by ALL 13 nodes. Any change here can break any node.
|
|
||||||
|
|
||||||
## Before Modifying
|
|
||||||
1. Identify which module(s) you're changing
|
|
||||||
2. Search for imports across all `nodes/*/src/` directories
|
|
||||||
3. List all consuming nodes
|
|
||||||
4. Verify backward compatibility
|
|
||||||
|
|
||||||
## Export Stability
|
|
||||||
- Never remove or rename exports without checking all consumers
|
|
||||||
- Prefer additive changes (new exports) over breaking changes
|
|
||||||
- If a breaking change is necessary, it requires a decision-gate interview
|
|
||||||
|
|
||||||
## Canonical Units
|
|
||||||
MeasurementContainer and internal processing use canonical units:
|
|
||||||
- Pressure: Pa
|
|
||||||
- Flow: m³/s
|
|
||||||
- Power: W
|
|
||||||
- Temperature: K
|
|
||||||
|
|
||||||
Unit conversions happen at system boundaries (input/output), not in core logic.
|
|
||||||
|
|
||||||
## Testing After Changes
|
|
||||||
Run tests in ALL affected consumer nodes, not just generalFunctions itself.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
paths:
|
|
||||||
- "nodes/*/src/**"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Node Architecture Rules
|
|
||||||
|
|
||||||
## 3-Tier Structure
|
|
||||||
Every node follows entry → nodeClass → specificClass:
|
|
||||||
|
|
||||||
1. **Entry file** (`nodes/<nodeName>/<nodeName>.js`): Registers with Node-RED via `RED.nodes.registerType`, exposes admin HTTP endpoints.
|
|
||||||
2. **nodeClass** (`nodes/<nodeName>/src/nodeClass.js`): Handles Node-RED runtime concerns — message routing, output formatting, tick loops, status updates, `RED.*` API calls.
|
|
||||||
3. **specificClass** (`nodes/<nodeName>/src/specificClass.js`): Pure domain logic — physics, control algorithms, state machines.
|
|
||||||
|
|
||||||
## Separation Rules
|
|
||||||
- **specificClass must never call `RED.*` directly** — all Node-RED interaction goes through nodeClass.
|
|
||||||
- specificClass is the source of truth for domain behavior.
|
|
||||||
- nodeClass is the adapter between Node-RED and domain logic.
|
|
||||||
- Entry file is minimal — registration and admin endpoints only.
|
|
||||||
|
|
||||||
## Output Port Convention
|
|
||||||
- Port 0: Process data (control outputs, state, setpoints)
|
|
||||||
- Port 1: InfluxDB telemetry payload
|
|
||||||
- Port 2: Registration/control plumbing (parent-child handshakes)
|
|
||||||
|
|
||||||
## Admin Endpoints
|
|
||||||
- `GET /<nodeName>/menu.js` — Dynamic menu configuration for editor
|
|
||||||
- `GET /<nodeName>/configData.js` — Runtime configuration for editor
|
|
||||||
|
|
||||||
## Submodule Awareness
|
|
||||||
Most `nodes/*` directories are git submodules. Keep edits scoped to the target node's directory.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
---
|
|
||||||
paths:
|
|
||||||
- "nodes/*/src/nodeClass.js"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Telemetry Rules
|
|
||||||
|
|
||||||
## Output Port Convention
|
|
||||||
- Port 0: Process data (downstream node consumption)
|
|
||||||
- Port 1: InfluxDB telemetry payload
|
|
||||||
- Port 2: Registration/control plumbing
|
|
||||||
|
|
||||||
## InfluxDB Payload Structure
|
|
||||||
Port 1 payloads must follow InfluxDB line protocol conventions:
|
|
||||||
- **Tags**: Low-cardinality indexed fields (node name, machine type, station ID)
|
|
||||||
- **Fields**: High-cardinality values (measurements, setpoints, quality scores)
|
|
||||||
|
|
||||||
## Cardinality Rules
|
|
||||||
- **Never add high-cardinality tags** — no timestamps, UUIDs, or free-text values as tags
|
|
||||||
- Tags are for grouping/filtering; fields are for values
|
|
||||||
- New tags require review for index impact
|
|
||||||
|
|
||||||
## FlowFuse Dashboard Compatibility
|
|
||||||
- Charts use `msg.topic` for series identification (`category: "topic"`)
|
|
||||||
- Dashboard API endpoints serve pre-aggregated data
|
|
||||||
- Changes to Port 0 `msg.topic` format can break downstream dashboards
|
|
||||||
|
|
||||||
## Consistency
|
|
||||||
- Field names for the same measurement type must be consistent across all nodes
|
|
||||||
- Measurement names follow a documented naming convention
|
|
||||||
- Aggregation windows (1min, 5min, 1hr, 24hr) are standardized
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
---
|
|
||||||
paths:
|
|
||||||
- "nodes/*/test/**"
|
|
||||||
---
|
|
||||||
|
|
||||||
# Testing Rules
|
|
||||||
|
|
||||||
## 3-Tier Test Structure
|
|
||||||
Every node must have:
|
|
||||||
- `test/basic/*.test.js` — Unit tests for individual functions
|
|
||||||
- `test/integration/*.test.js` — Node interaction and message passing tests
|
|
||||||
- `test/edge/*.test.js` — Edge cases, error conditions, boundary values
|
|
||||||
- `test/helpers/` (optional) — Shared test utilities for this node
|
|
||||||
|
|
||||||
## Test Runner
|
|
||||||
```bash
|
|
||||||
node --test nodes/<nodeName>/test/basic/*.test.js
|
|
||||||
node --test nodes/<nodeName>/test/integration/*.test.js
|
|
||||||
node --test nodes/<nodeName>/test/edge/*.test.js
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test Requirements
|
|
||||||
- Every behavior change requires a failing-before/passing-after test
|
|
||||||
- Tests must validate against function anchor expected behavior
|
|
||||||
- Example flows (`examples/`) must stay in sync with implementation
|
|
||||||
|
|
||||||
## Example Flows
|
|
||||||
Each node must maintain:
|
|
||||||
- `examples/README.md`
|
|
||||||
- `examples/basic.flow.json`
|
|
||||||
- `examples/integration.flow.json`
|
|
||||||
- `examples/edge.flow.json`
|
|
||||||
|
|
||||||
## No Node-RED Runtime in Unit Tests
|
|
||||||
Basic tests should test specificClass domain logic without requiring a running Node-RED instance.
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
{
|
|
||||||
"permissions": {
|
|
||||||
"allow": [
|
|
||||||
"Bash(node --test:*)",
|
|
||||||
"Bash(node -c:*)",
|
|
||||||
"Bash(npm:*)",
|
|
||||||
"Bash(git:*)",
|
|
||||||
"Bash(ls:*)",
|
|
||||||
"Bash(tree:*)",
|
|
||||||
"Bash(wc:*)",
|
|
||||||
"Bash(head:*)",
|
|
||||||
"Bash(tail:*)",
|
|
||||||
"Bash(sort:*)",
|
|
||||||
"Bash(find:*)",
|
|
||||||
"Bash(echo:*)",
|
|
||||||
"Bash(cat:*)",
|
|
||||||
"Bash(cut:*)",
|
|
||||||
"Bash(xargs:*)",
|
|
||||||
"WebSearch",
|
|
||||||
"WebFetch(domain:nodered.org)",
|
|
||||||
"WebFetch(domain:docs.influxdata.com)",
|
|
||||||
"WebFetch(domain:github.com)",
|
|
||||||
"WebFetch(domain:docs.anthropic.com)",
|
|
||||||
"WebFetch(domain:nodejs.org)",
|
|
||||||
"WebFetch(domain:www.npmjs.com)",
|
|
||||||
"WebFetch(domain:developer.mozilla.org)",
|
|
||||||
"WebFetch(domain:flowfuse.com)",
|
|
||||||
"WebFetch(domain:www.coolprop.org)",
|
|
||||||
"WebFetch(domain:en.wikipedia.org)",
|
|
||||||
"WebFetch(domain:www.engineeringtoolbox.com)",
|
|
||||||
"mcp__ide__getDiagnostics",
|
|
||||||
"Bash(chmod +x:*)",
|
|
||||||
"Bash(docker compose:*)",
|
|
||||||
"Bash(docker:*)",
|
|
||||||
"Bash(npm run docker:*)",
|
|
||||||
"Bash(sh:*)",
|
|
||||||
"Bash(curl:*)",
|
|
||||||
"Bash(# Check Node-RED context for the parse function to see if it received data\ndocker compose exec -T nodered sh -c 'curl -sf \"http://localhost:1880/context/node/demo_fn_ps_west_parse\" 2>/dev/null' | python3 -c \"\nimport json, sys\ntry:\n data = json.load\\(sys.stdin\\)\n print\\(json.dumps\\(data, indent=2\\)[:800]\\)\nexcept Exception as e: print\\(f'Error: {e}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Check what the deployed flow looks like for link out type nodes\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\n# All node types and their counts\nfrom collections import Counter\ntypes = Counter\\(n.get\\('type',''\\) for n in flows if 'type' in n\\)\nfor t, c in sorted\\(types.items\\(\\)\\):\n if 'link' in t.lower\\(\\):\n print\\(f'{t}: {c}'\\)\nprint\\('---'\\)\n# Show existing link out nodes\nfor n in flows:\n if n.get\\('type'\\) == 'link out':\n print\\(f' {n[\\\\\"id\\\\\"]}: links={n.get\\(\\\\\"links\\\\\",[]\\)}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Full count of all deployed node types\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfrom collections import Counter\ntypes = Counter\\(n.get\\('type',''\\) for n in flows if 'type' in n\\)\nfor t, c in sorted\\(types.items\\(\\)\\):\n print\\(f'{t:30s}: {c}'\\)\nprint\\(f'Total nodes: {len\\(flows\\)}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Check exact registered node type names\ncurl -sf http://localhost:1880/nodes 2>/dev/null | python3 -c \"\nimport json, sys\nnodes = json.load\\(sys.stdin\\)\nfor mod in nodes:\n if 'EVOLV' in json.dumps\\(mod\\) or 'evolv' in json.dumps\\(mod\\).lower\\(\\):\n if isinstance\\(mod, dict\\) and 'types' in mod:\n for t in mod['types']:\n print\\(f'Registered type: {t}'\\)\n elif isinstance\\(mod, dict\\) and 'nodes' in mod:\n for n in mod['nodes']:\n for t in n.get\\('types', []\\):\n print\\(f'Registered type: {t}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Get node types from the /nodes endpoint properly\ndocker compose exec -T nodered sh -c 'curl -sf http://localhost:1880/nodes' | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\n# Find EVOLV node types\nfor module in data:\n if isinstance\\(module, dict\\):\n name = module.get\\('name', module.get\\('module', ''\\)\\)\n if 'EVOLV' in str\\(name\\).upper\\(\\) or 'evolv' in str\\(name\\).lower\\(\\):\n print\\(f'Module: {name}'\\)\n for node_set in module.get\\('nodes', []\\):\n for t in node_set.get\\('types', []\\):\n print\\(f' Type: {t}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Get raw flow data directly from inside the container\ndocker compose exec -T nodered sh -c 'curl -sf http://localhost:1880/flows 2>/dev/null' | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\nprint\\(f'Total entries: {len\\(data\\)}'\\)\nprint\\(f'Type: {type\\(data\\)}'\\)\nif isinstance\\(data, list\\):\n print\\('First 3:'\\)\n for n in data[:3]:\n print\\(f' {n.get\\(\\\\\"id\\\\\",\\\\\"?\\\\\"\\)}: type={n.get\\(\\\\\"type\\\\\",\\\\\"?\\\\\"\\)}'\\)\n # Count\n from collections import Counter\n types = Counter\\(n.get\\('type',''\\) for n in data\\)\n for t, c in sorted\\(types.items\\(\\)\\):\n print\\(f' {t}: {c}'\\)\nelif isinstance\\(data, dict\\):\n print\\(f'Keys: {list\\(data.keys\\(\\)\\)}'\\)\n if 'flows' in data:\n flows = data['flows']\n print\\(f'Flows count: {len\\(flows\\)}'\\)\n from collections import Counter\n types = Counter\\(n.get\\('type',''\\) for n in flows\\)\n for t, c in sorted\\(types.items\\(\\)\\):\n print\\(f' {t}: {c}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(# Check individual tab flows\ndocker compose exec -T nodered sh -c 'curl -sf http://localhost:1880/flow/demo_tab_wwtp' | python3 -c \"\nimport json, sys\ndata = json.load\\(sys.stdin\\)\nif isinstance\\(data, dict\\):\n print\\(f'Tab: {data.get\\(\\\\\"label\\\\\",\\\\\"?\\\\\"\\)}'\\)\n nodes = data.get\\('nodes', []\\)\n print\\(f'Nodes: {len\\(nodes\\)}'\\)\n from collections import Counter\n types = Counter\\(n.get\\('type',''\\) for n in nodes\\)\n for t, c in sorted\\(types.items\\(\\)\\):\n print\\(f' {t}: {c}'\\)\nelse:\n print\\(data\\)\n\" 2>&1)",
|
|
||||||
"Bash(sleep 5:*)",
|
|
||||||
"Bash(sleep 15:*)",
|
|
||||||
"Bash(# Get all dashboard UIDs and update the bucket variable from lvl2 to telemetry\ncurl -sf -H \"Authorization: Bearer glsa_4tbdInvrkQ6c7J6N3InjSsH8de83vZ66_9db7efa3\" \\\\\n \"http://localhost:3000/api/search?type=dash-db\" | python3 -c \"\nimport json, sys\ndashboards = json.load\\(sys.stdin\\)\nfor d in dashboards:\n print\\(d['uid']\\)\n\" 2>&1)",
|
|
||||||
"Bash(sleep 20:*)",
|
|
||||||
"Bash(# Check reactor parse function context\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\n# Find parse functions by name\nfor n in flows:\n if n.get\\('type'\\) == 'function' and 'reactor' in n.get\\('name',''\\).lower\\(\\):\n print\\(f\\\\\"Reactor parse: id={n['id']}, name={n.get\\('name'\\)}\\\\\"\\)\" 2>&1)",
|
|
||||||
"Bash(# Check if reactor node is sending output — look at debug info\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\n# Find the reactor node and its wires\nfor n in flows:\n if n.get\\('type'\\) == 'reactor':\n print\\(f\\\\\"Reactor: id={n['id']}, name={n.get\\('name',''\\)}\\\\\"\\)\n wires = n.get\\('wires', []\\)\n for i, port in enumerate\\(wires\\):\n print\\(f' Port {i}: {port}'\\)\n if n.get\\('type'\\) == 'link out' and 'reactor' in n.get\\('name',''\\).lower\\(\\):\n print\\(f\\\\\"Link-out reactor: id={n['id']}, name={n.get\\('name',''\\)}, links={n.get\\('links',[]\\)}\\\\\"\\)\" 2>&1)",
|
|
||||||
"Bash(# Check measurement node wiring and output\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('type'\\) == 'measurement':\n print\\(f\\\\\"Measurement: id={n['id']}, name={n.get\\('name',''\\)}\\\\\"\\)\n wires = n.get\\('wires', []\\)\n for i, port in enumerate\\(wires\\):\n print\\(f' Port {i}: {port}'\\)\n if n.get\\('type'\\) == 'link out' and 'meas' in n.get\\('name',''\\).lower\\(\\):\n print\\(f\\\\\"Link-out meas: id={n['id']}, name={n.get\\('name',''\\)}, links={n.get\\('links',[]\\)}\\\\\"\\)\" 2>&1)",
|
|
||||||
"Bash(# Check reactor node config and measurement configs\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('type'\\) == 'reactor':\n print\\('=== REACTOR CONFIG ==='\\)\n for k,v in sorted\\(n.items\\(\\)\\):\n if k not in \\('wires','x','y','z'\\):\n print\\(f' {k}: {v}'\\)\n if n.get\\('type'\\) == 'measurement' and n.get\\('id'\\) == 'demo_meas_flow':\n print\\('=== MEASUREMENT FT-001 CONFIG ==='\\)\n for k,v in sorted\\(n.items\\(\\)\\):\n if k not in \\('wires','x','y','z'\\):\n print\\(f' {k}: {v}'\\)\" 2>&1)",
|
|
||||||
"Bash(# Check what inject/input nodes target the measurement nodes\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\n\n# Find all nodes that wire INTO the measurement nodes\nmeas_ids = {'demo_meas_flow', 'demo_meas_do', 'demo_meas_nh4'}\nfor n in flows:\n wires = n.get\\('wires', []\\)\n for port_idx, port_wires in enumerate\\(wires\\):\n for target in port_wires:\n if target in meas_ids:\n print\\(f'{n.get\\(\\\\\"type\\\\\"\\)}:{n.get\\(\\\\\"name\\\\\",\\\\\"\\\\\"\\)} \\(id={n.get\\(\\\\\"id\\\\\"\\)}\\) port {port_idx} → {target}'\\)\n\n# Check inject nodes that send to measurements \nprint\\(\\)\nprint\\('=== Inject nodes ==='\\)\nfor n in flows:\n if n.get\\('type'\\) == 'inject':\n wires = n.get\\('wires', []\\)\n all_targets = [t for port in wires for t in port]\n print\\(f'inject: {n.get\\(\\\\\"name\\\\\",\\\\\"\\\\\"\\)} id={n.get\\(\\\\\"id\\\\\"\\)} → targets={all_targets} repeat={n.get\\(\\\\\"repeat\\\\\",\\\\\"\\\\\"\\)} topic={n.get\\(\\\\\"topic\\\\\",\\\\\"\\\\\"\\)}'\\)\" 2>&1)",
|
|
||||||
"Bash(# Check the simulator function code for measurements\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('id'\\) in \\('demo_fn_sim_flow', 'demo_fn_sim_do', 'demo_fn_sim_nh4'\\):\n print\\(f'=== {n.get\\(\\\\\"name\\\\\"\\)} ==='\\)\n print\\(n.get\\('func',''\\)\\)\n print\\(\\)\" 2>&1)",
|
|
||||||
"Bash(# Check what the reactor tick inject sends\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('id'\\) == 'demo_inj_reactor_tick':\n print\\('=== Reactor tick inject ==='\\)\n for k,v in sorted\\(n.items\\(\\)\\):\n if k not in \\('x','y','z','wires'\\):\n print\\(f' {k}: {v}'\\)\n if n.get\\('id'\\) == 'demo_inj_meas_flow':\n print\\('=== Flow sensor inject ==='\\)\n for k,v in sorted\\(n.items\\(\\)\\):\n if k not in \\('x','y','z','wires'\\):\n print\\(f' {k}: {v}'\\)\" 2>&1)",
|
|
||||||
"Bash(# Check measurement parse function code\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('id'\\) == 'demo_fn_reactor_parse':\n print\\('=== Parse Reactor ==='\\)\n print\\(n.get\\('func',''\\)\\)\n print\\(\\)\n if n.get\\('id'\\) == 'demo_fn_meas_parse':\n print\\('=== Parse Measurements ==='\\)\n print\\(n.get\\('func',''\\)\\)\n print\\(\\)\n if n.get\\('type'\\) == 'function' and 'meas' in n.get\\('name',''\\).lower\\(\\) and 'parse' in n.get\\('name',''\\).lower\\(\\):\n print\\(f'=== {n.get\\(\\\\\"name\\\\\"\\)} \\(id={n.get\\(\\\\\"id\\\\\"\\)}\\) ==='\\)\n print\\(n.get\\('func',''\\)\\)\n print\\(\\)\" 2>&1)",
|
|
||||||
"Bash(# Check the link node pairs are properly paired\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nnodes = {n['id']: n for n in flows if 'id' in n}\n\nlink_outs = [n for n in flows if n.get\\('type'\\) == 'link out']\nlink_ins = [n for n in flows if n.get\\('type'\\) == 'link in']\n\nprint\\('=== Link-out nodes ==='\\)\nfor lo in link_outs:\n links = lo.get\\('links', []\\)\n targets = [nodes.get\\(l, {}\\).get\\('name', f'MISSING:{l}'\\) for l in links]\n tab = nodes.get\\(lo.get\\('z',''\\), {}\\).get\\('label', '?'\\)\n print\\(f' [{tab}] {lo.get\\(\\\\\"name\\\\\",\\\\\"\\\\\"\\)} \\(id={lo[\\\\\"id\\\\\"]}\\) → {targets}'\\)\n\nprint\\(\\)\nprint\\('=== Link-in nodes ==='\\) \nfor li in link_ins:\n links = li.get\\('links', []\\)\n tab = nodes.get\\(li.get\\('z',''\\), {}\\).get\\('label', '?'\\)\n print\\(f' [{tab}] {li.get\\(\\\\\"name\\\\\",\\\\\"\\\\\"\\)} \\(id={li[\\\\\"id\\\\\"]}\\) links={links}'\\)\" 2>&1)",
|
|
||||||
"Bash(sleep 8:*)",
|
|
||||||
"Bash(# Check the InfluxDB convert function and HTTP request config\ncurl -sf http://localhost:1880/flows 2>/dev/null | python3 -c \"\nimport json, sys\nflows = json.load\\(sys.stdin\\)\nfor n in flows:\n if n.get\\('id'\\) == 'demo_fn_influx_convert':\n print\\('=== InfluxDB Convert Function ==='\\)\n print\\(f'func: {n.get\\(\\\\\"func\\\\\",\\\\\"\\\\\"\\)}'\\)\n print\\(f'wires: {n.get\\(\\\\\"wires\\\\\",[]\\)}'\\)\n print\\(\\)\n if n.get\\('id'\\) == 'demo_http_influx':\n print\\('=== Write InfluxDB HTTP ==='\\)\n for k,v in sorted\\(n.items\\(\\)\\):\n if k not in \\('x','y','z','wires'\\):\n print\\(f' {k}: {v}'\\)\n print\\(f' wires: {n.get\\(\\\\\"wires\\\\\",[]\\)}'\\)\n\" 2>&1)",
|
|
||||||
"Bash(echo Grafana API not accessible:*)",
|
|
||||||
"Bash(python3 -c \":*)",
|
|
||||||
"Bash(__NEW_LINE_6565c53f4a65adcb__ echo \"\")",
|
|
||||||
"Bash(__NEW_LINE_43bd4a070667d63e__ echo \"\")",
|
|
||||||
"Bash(node:*)",
|
|
||||||
"Bash(python3:*)",
|
|
||||||
"WebFetch(domain:dashboard.flowfuse.com)",
|
|
||||||
"Bash(do echo:*)",
|
|
||||||
"Bash(__NEW_LINE_5a355214e3d8caae__ git:*)",
|
|
||||||
"Bash(git add:*)",
|
|
||||||
"Bash(__NEW_LINE_4762b8ca1fb65139__ for:*)",
|
|
||||||
"Bash(docker.exe ps:*)",
|
|
||||||
"Bash(docker.exe logs:*)",
|
|
||||||
"Bash(docker.exe compose:*)",
|
|
||||||
"Bash(docker.exe exec:*)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
# Dependencies (rebuilt in container)
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Git
|
|
||||||
.git/
|
|
||||||
.gitmodules
|
|
||||||
|
|
||||||
# Build artifacts
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Agent/Claude metadata (not needed at runtime)
|
|
||||||
.agents/
|
|
||||||
.claude/
|
|
||||||
manuals/
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
*~
|
|
||||||
|
|
||||||
# OS
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Documentation (not needed at runtime)
|
|
||||||
third_party/
|
|
||||||
FUNCTIONAL_ISSUES_BACKLOG.md
|
|
||||||
AGENTS.md
|
|
||||||
README.md
|
|
||||||
LICENSE
|
|
||||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,10 +1,3 @@
|
|||||||
# EVOLV/.gitignore
|
# EVOLV/.gitignore
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
|
|
||||||
# Secrets / tokens
|
|
||||||
.env
|
|
||||||
.env.*
|
|
||||||
|
|
||||||
# Build artifacts
|
|
||||||
*.tgz
|
|
||||||
74
.gitmodules
vendored
74
.gitmodules
vendored
@@ -1,37 +1,37 @@
|
|||||||
|
|
||||||
[submodule "nodes/machineGroupControl"]
|
[submodule "nodes/machineGroupControl"]
|
||||||
path = nodes/machineGroupControl
|
path = nodes/machineGroupControl
|
||||||
url = https://gitea.wbd-rd.nl/RnD/machineGroupControl.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/machineGroupControl.git
|
||||||
[submodule "nodes/generalFunctions"]
|
[submodule "nodes/generalFunctions"]
|
||||||
path = nodes/generalFunctions
|
path = nodes/generalFunctions
|
||||||
url = https://gitea.wbd-rd.nl/RnD/generalFunctions.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/generalFunctions.git
|
||||||
[submodule "nodes/valveGroupControl"]
|
[submodule "nodes/valveGroupControl"]
|
||||||
path = nodes/valveGroupControl
|
path = nodes/valveGroupControl
|
||||||
url = https://gitea.wbd-rd.nl/RnD/valveGroupControl.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/valveGroupControl.git
|
||||||
[submodule "nodes/valve"]
|
[submodule "nodes/valve"]
|
||||||
path = nodes/valve
|
path = nodes/valve
|
||||||
url = https://gitea.wbd-rd.nl/RnD/valve.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/valve.git
|
||||||
[submodule "nodes/rotatingMachine"]
|
[submodule "nodes/rotatingMachine"]
|
||||||
path = nodes/rotatingMachine
|
path = nodes/rotatingMachine
|
||||||
url = https://gitea.wbd-rd.nl/RnD/rotatingMachine.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/rotatingMachine.git
|
||||||
[submodule "nodes/monster"]
|
[submodule "nodes/monster"]
|
||||||
path = nodes/monster
|
path = nodes/monster
|
||||||
url = https://gitea.wbd-rd.nl/RnD/monster.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/monster.git
|
||||||
[submodule "nodes/measurement"]
|
[submodule "nodes/measurement"]
|
||||||
path = nodes/measurement
|
path = nodes/measurement
|
||||||
url = https://gitea.wbd-rd.nl/RnD/measurement.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/measurement.git
|
||||||
[submodule "nodes/diffuser"]
|
[submodule "nodes/diffuser"]
|
||||||
path = nodes/diffuser
|
path = nodes/diffuser
|
||||||
url = https://gitea.wbd-rd.nl/RnD/diffuser.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/diffuser.git
|
||||||
[submodule "nodes/dashboardAPI"]
|
[submodule "nodes/dashboardAPI"]
|
||||||
path = nodes/dashboardAPI
|
path = nodes/dashboardAPI
|
||||||
url = https://gitea.wbd-rd.nl/RnD/dashboardAPI.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/dashboardAPI.git
|
||||||
[submodule "nodes/reactor"]
|
[submodule "nodes/reactor"]
|
||||||
path = nodes/reactor
|
path = nodes/reactor
|
||||||
url = https://gitea.wbd-rd.nl/RnD/reactor.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/reactor.git
|
||||||
[submodule "nodes/pumpingStation"]
|
[submodule "nodes/pumpingStation"]
|
||||||
path = nodes/pumpingStation
|
path = nodes/pumpingStation
|
||||||
url = https://gitea.wbd-rd.nl/RnD/pumpingStation
|
url = https://gitea.centraal.wbd-rd.nl/RnD/pumpingStation
|
||||||
[submodule "nodes/settler"]
|
[submodule "nodes/settler"]
|
||||||
path = nodes/settler
|
path = nodes/settler
|
||||||
url = https://gitea.wbd-rd.nl/RnD/settler.git
|
url = https://gitea.centraal.wbd-rd.nl/RnD/settler.git
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
# Ignore test files
|
# Ignore test files
|
||||||
node_modules/
|
node_modules/
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user