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>
46 lines
2.0 KiB
JavaScript
46 lines
2.0 KiB
JavaScript
/**
|
|
* Composes the per-tick pressure-drift status + the PredictionHealth
|
|
* shape used by the orchestrator. Lives separately from
|
|
* DriftAssessor/PredictionHealth so the orchestrator only calls one
|
|
* function per refresh.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const PredictionHealth = require('./predictionHealth');
|
|
|
|
function updatePressureDriftStatus(host) {
|
|
const status = host.getPressureInitializationStatus();
|
|
const flags = [];
|
|
let level = 0;
|
|
if (!status.initialized) { level = 2; flags.push('no_pressure_input'); }
|
|
else if (!status.hasDifferential) { level = 1; flags.push('single_side_pressure'); }
|
|
if (status.hasDifferential) {
|
|
const diff = Number(host._getPreferredPressureValue('downstream')) - Number(host._getPreferredPressureValue('upstream'));
|
|
if (Number.isFinite(diff) && diff < 0) { level = Math.max(level, 3); flags.push('negative_pressure_differential'); }
|
|
}
|
|
host.pressureDrift = { level, source: status.source, flags: flags.length ? flags : ['nominal'] };
|
|
return host.pressureDrift;
|
|
}
|
|
|
|
function updatePredictionHealth(host) {
|
|
const pressureDrift = updatePressureDriftStatus(host);
|
|
const helper = new PredictionHealth({
|
|
getPressureInitializationStatus: () => host.getPressureInitializationStatus(),
|
|
isOperational: () => host._isOperationalState(),
|
|
applyDriftPenalty: (d, c, f, p) => host._applyDriftPenalty(d, c, f, p),
|
|
resolveSetpointBounds: () => host._resolveSetpointBounds(),
|
|
getCurrentPosition: () => host.state?.getCurrentPosition?.(),
|
|
});
|
|
const { health, confidence } = helper.evaluate({ flow: host.flowDrift, power: host.powerDrift, pressure: pressureDrift });
|
|
const quality = confidence >= 0.8 ? 'high' : confidence >= 0.55 ? 'medium' : confidence >= 0.3 ? 'low' : 'invalid';
|
|
host.predictionHealth = {
|
|
quality, confidence,
|
|
pressureSource: health.source ?? pressureDrift.source ?? null,
|
|
flags: Array.isArray(health.flags) && health.flags.length ? [...health.flags] : ['nominal'],
|
|
};
|
|
return host.predictionHealth;
|
|
}
|
|
|
|
module.exports = { updatePressureDriftStatus, updatePredictionHealth };
|