P5 wave 2: convert rotatingMachine to BaseDomain + extract helper modules
specificClass.js: 1760 → 400 lines.
Machine extends BaseDomain. configure() wires curves + predictors +
drift + pressure + state bindings + measurement handlers + flow
controller. ChildRouter handles pressure/flow/power/temperature
measurement events; custom registerChild override preserves the
dedup + virtual-vs-real pressure tracking the integration tests
pin.
Added small host-aware helper modules to fit the 400-line cap:
src/prediction/predictionMath.js (calcFlow/Power/Ctrl)
src/prediction/efficiencyMath.js (calcCog/EfficiencyCurve/etc.)
src/pressure/pressureSelector.js (getMeasuredPressure source preference)
src/state/sequenceController.js (executeSequence/setpoint/wait helpers)
src/measurement/childRegistrar.js (custom registerChild path)
src/drift/healthRefresh.js (drift status update wrappers)
src/io/output.js (buildOutput + buildStatusBadge)
unitPolicy: live UnitPolicy methods .canonical()/.output()/.curve()
bridged to legacy property-path readers via a frozen view object —
same pattern as MGC. See OPEN_QUESTIONS.md.
nodeClass.js: 433 → 61 lines.
Extends BaseNodeAdapter. tickInterval=null (event-driven on state +
measurement events). buildDomainConfig stamps the rotatingMachine
state + errorMetrics slices on the domain config so configure()
builds them from there.
5 tests adjusted (4 nodeClass-config, 1 error-paths) — pre-refactor
they pinned private methods (_loadConfig, _setupSpecificClass,
_attachInputHandler, _updateNodeStatus) that no longer exist. New
versions drive the public BaseNodeAdapter surface or call extracted
io/state-machine helpers directly. See OPEN_QUESTIONS.md 2026-05-10
"private nodeClass tests" for the deferred rewrite plan.
196 / 196 tests pass (basic 110 + integration ~80 + edge ~6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
47
src/measurement/childRegistrar.js
Normal file
47
src/measurement/childRegistrar.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* registerChild adapter for rotatingMachine. Custom because:
|
||||
* - virtual + real pressure children share the upstream/downstream
|
||||
* position slots; real ones must be tracked for the preference order
|
||||
* - re-registration of the same child must dedup the emitter listener
|
||||
* - non-measurement softwareTypes are no-ops (Machine has no children
|
||||
* other than measurement nodes today)
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
function registerMeasurementChild(host, child, softwareType) {
|
||||
const swType = softwareType || child?.config?.functionality?.softwareType || 'measurement';
|
||||
host.logger.debug(`Setting up child event for softwaretype ${swType}`);
|
||||
if (swType !== 'measurement') return;
|
||||
|
||||
const position = String(child.config.functionality.positionVsParent || 'atEquipment').toLowerCase();
|
||||
const measurementType = child.config.asset.type;
|
||||
const childId = child.config?.general?.id || `${measurementType}-${position}-unknown`;
|
||||
const isVirtual = Object.values(host.virtualPressureChildIds).includes(childId);
|
||||
if (measurementType === 'pressure' && !isVirtual) host.realPressureChildIds[position]?.add(childId);
|
||||
|
||||
const eventName = `${measurementType}.measured.${position}`;
|
||||
const key = `${childId}:${eventName}`;
|
||||
const existing = host.childMeasurementListeners.get(key);
|
||||
if (existing) {
|
||||
if (typeof existing.emitter.off === 'function') existing.emitter.off(existing.eventName, existing.handler);
|
||||
else if (typeof existing.emitter.removeListener === 'function') existing.emitter.removeListener(existing.eventName, existing.handler);
|
||||
}
|
||||
const handler = (eventData) => {
|
||||
host.logger.debug(`🔄 ${position} ${measurementType} from ${eventData.childName}: ${eventData.value} ${eventData.unit}`);
|
||||
host._callMeasurementHandler(measurementType, eventData.value, position, eventData);
|
||||
};
|
||||
child.measurements.emitter.on(eventName, handler);
|
||||
host.childMeasurementListeners.set(key, { emitter: child.measurements.emitter, eventName, handler });
|
||||
}
|
||||
|
||||
function detachAllListeners(host) {
|
||||
if (!host.childMeasurementListeners) return;
|
||||
for (const [, e] of host.childMeasurementListeners) {
|
||||
if (typeof e.emitter?.off === 'function') e.emitter.off(e.eventName, e.handler);
|
||||
else if (typeof e.emitter?.removeListener === 'function') e.emitter.removeListener(e.eventName, e.handler);
|
||||
}
|
||||
host.childMeasurementListeners.clear();
|
||||
}
|
||||
|
||||
module.exports = { registerMeasurementChild, detachAllListeners };
|
||||
Reference in New Issue
Block a user