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:
znetsixe
2026-05-10 21:38:45 +02:00
parent 8f9150e160
commit c5bb375dd0
34 changed files with 3036 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const { showWorkingCurves, showCoG } = require('../../src/display/workingCurves');
function makePredictors(overrides = {}) {
return {
hasCurve: true,
cog: 0.65,
cogIndex: 7,
NCog: 0.5,
minEfficiency: 0.4,
currentEfficiencyCurve: { x: [0, 1], y: [0.4, 0.8] },
absDistFromPeak: 0.15,
relDistFromPeak: 0.3,
calcCog: () => ({ cog: 0.65, cogIndex: 7, NCog: 0.5, minEfficiency: 0.4 }),
getCurrentCurves: () => ({
powerCurve: { x: [0, 1], y: [10, 20] },
flowCurve: { x: [0, 1], y: [0, 5] },
}),
...overrides,
};
}
test('showWorkingCurves returns the expected shape when curves exist', () => {
const p = makePredictors();
const out = showWorkingCurves(p);
assert.deepEqual(out.powerCurve, { x: [0, 1], y: [10, 20] });
assert.deepEqual(out.flowCurve, { x: [0, 1], y: [0, 5] });
assert.equal(out.cog, 0.65);
assert.equal(out.cogIndex, 7);
assert.equal(out.NCog, 0.5);
assert.equal(out.minEfficiency, 0.4);
assert.deepEqual(out.currentEfficiencyCurve, { x: [0, 1], y: [0.4, 0.8] });
assert.equal(out.absDistFromPeak, 0.15);
assert.equal(out.relDistFromPeak, 0.3);
});
test('showWorkingCurves returns error envelope when hasCurve is false', () => {
const out = showWorkingCurves(makePredictors({ hasCurve: false }));
assert.deepEqual(out, { error: 'No curve data available' });
});
test('showWorkingCurves handles null predictors safely', () => {
const out = showWorkingCurves(null);
assert.equal(out.error, 'No curve data available');
});
test('showCoG returns CoG data with rounded NCogPercent when curves exist', () => {
const p = makePredictors();
const out = showCoG(p);
assert.equal(out.cog, 0.65);
assert.equal(out.cogIndex, 7);
assert.equal(out.NCog, 0.5);
// 0.5 * 100 = 50.0, rounded *100 /100 still 50
assert.equal(out.NCogPercent, 50);
assert.equal(out.minEfficiency, 0.4);
assert.deepEqual(out.currentEfficiencyCurve, { x: [0, 1], y: [0.4, 0.8] });
assert.equal(out.absDistFromPeak, 0.15);
assert.equal(out.relDistFromPeak, 0.3);
});
test('showCoG rounds NCogPercent to 2 decimal places', () => {
const p = makePredictors({
calcCog: () => ({ cog: 0.1, cogIndex: 1, NCog: 0.123456, minEfficiency: 0.2 }),
});
const out = showCoG(p);
assert.equal(out.NCogPercent, 12.35);
});
test('showCoG returns degraded shape when hasCurve is false', () => {
const out = showCoG(makePredictors({ hasCurve: false }));
assert.equal(out.error, 'No curve data available');
assert.equal(out.cog, 0);
assert.equal(out.NCog, 0);
assert.equal(out.cogIndex, 0);
});
test('showCoG handles null predictors safely', () => {
const out = showCoG(null);
assert.equal(out.error, 'No curve data available');
assert.equal(out.cog, 0);
});