P5 wave 1: extract rotatingMachine concerns into focused modules
src/curves/ loader + normalizer (with cross-pressure anomaly
detection) + reverseCurve helper
src/prediction/ predictors (predictFlow/Power/Ctrl) +
groupPredictors (lazy group-scope views) +
OperatingPoint (pressure-driven prediction setpoints)
src/drift/ DriftAssessor (per-metric drift) + PredictionHealth
(composes flow/power/pressure into HealthStatus +
confidence sibling — see OPEN_QUESTIONS 2026-05-10)
src/pressure/ VirtualPressureChildren (dashboard-sim) +
PressureInitialization (real-vs-virtual tracking) +
PressureRouter (dispatches by position)
src/state/ stateBindings (state.emitter listener helper) +
isOperationalState
src/measurement/ measurementHandlers (dispatcher for flow/power/temp/pressure)
src/flow/ flowController (handleInput body — execSequence,
execMovement, flowMovement, emergencystop)
src/display/ workingCurves (showWorkingCurves + showCoG admin)
src/commands/ canonical names: set.mode, cmd.startup/shutdown/estop,
set.setpoint, set.flow-setpoint,
data.simulate-measurement, query.curves, query.cog,
child.register. execSequence demuxes by payload.action
to canonical cmd.* handlers.
CONTRACT.md inputs/outputs/events/children surface
110 basic tests pass (100 new + 10 pre-existing).
specificClass.js / nodeClass.js untouched — integration in P5 wave 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
51
test/basic/groupPredictors.basic.test.js
Normal file
51
test/basic/groupPredictors.basic.test.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const { predict } = require('generalFunctions');
|
||||
const { buildPredictors } = require('../../src/prediction/predictors');
|
||||
const { buildGroupPredictors } = require('../../src/prediction/groupPredictors');
|
||||
|
||||
function makeCanonicalCurve() {
|
||||
return {
|
||||
nq: {
|
||||
100000: { x: [0, 50, 100], y: [0, 0.005, 0.01] },
|
||||
120000: { x: [0, 50, 100], y: [0, 0.006, 0.012] },
|
||||
},
|
||||
np: {
|
||||
100000: { x: [0, 50, 100], y: [0, 500, 1000] },
|
||||
120000: { x: [0, 50, 100], y: [0, 600, 1200] },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('buildGroupPredictors: returns null when source predictors absent', () => {
|
||||
assert.equal(buildGroupPredictors(null), null);
|
||||
assert.equal(buildGroupPredictors({ predictFlow: null, predictPower: null, predictCtrl: null }), null);
|
||||
});
|
||||
|
||||
test('buildGroupPredictors: returns three group-scope Predict instances', () => {
|
||||
const predictors = buildPredictors(makeCanonicalCurve());
|
||||
const group = buildGroupPredictors(predictors);
|
||||
assert.ok(group);
|
||||
assert.ok(group.groupPredictFlow instanceof predict);
|
||||
assert.ok(group.groupPredictPower instanceof predict);
|
||||
assert.ok(group.groupPredictCtrl instanceof predict);
|
||||
});
|
||||
|
||||
test('buildGroupPredictors: group instances share input curves with individuals', () => {
|
||||
const predictors = buildPredictors(makeCanonicalCurve());
|
||||
const group = buildGroupPredictors(predictors);
|
||||
// Predict._adoptInputsFrom copies these refs from the source.
|
||||
assert.equal(group.groupPredictFlow.inputCurve, predictors.predictFlow.inputCurve);
|
||||
assert.equal(group.groupPredictPower.inputCurve, predictors.predictPower.inputCurve);
|
||||
assert.equal(group.groupPredictCtrl.inputCurve, predictors.predictCtrl.inputCurve);
|
||||
});
|
||||
|
||||
test('buildGroupPredictors: group operating-point state is independent of individual', () => {
|
||||
const predictors = buildPredictors(makeCanonicalCurve());
|
||||
const group = buildGroupPredictors(predictors);
|
||||
predictors.predictFlow.fDimension = 100000;
|
||||
group.groupPredictFlow.fDimension = 120000;
|
||||
assert.equal(predictors.predictFlow.currentF, 100000);
|
||||
assert.equal(group.groupPredictFlow.currentF, 120000);
|
||||
});
|
||||
Reference in New Issue
Block a user