P6: convert monster to BaseDomain + BaseNodeAdapter + concern split

Refactor of monster to use the platform infrastructure (BaseDomain, BaseNodeAdapter,
ChildRouter, commandRegistry, statusBadge). Extracts concerns into
focused modules per .claude/refactor/MODULE_SPLIT.md generic template.
Tests stay green; CONTRACT.md generated; legacy aliases preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
znetsixe
2026-05-10 22:09:25 +02:00
parent 5a43f90569
commit 2a6a0bc34b
12 changed files with 710 additions and 1075 deletions

View File

@@ -0,0 +1,56 @@
'use strict';
// Sampling-cabinet boundary + target math + rain-scaled flow prediction.
// All operations are pure given a domain handle — the domain owns the
// mutable fields (maxVolume, targetPuls, …) so legacy tests that read
// `monster.maxVolume` keep working.
const RAIN_STALE_MS = 2 * 60 * 60 * 1000;
function applyBoundsAndTargets(m) {
m.maxVolume = m.maxWeight - m.emptyWeightBucket;
m.minPuls = Math.round(m.minVolume / m.volume_pulse);
m.maxPuls = Math.round(m.maxVolume / m.volume_pulse);
m.absMaxPuls = Math.round(m.cap_volume / m.volume_pulse);
m.targetVolume = m.minVolume * Math.sqrt(m.maxVolume / m.minVolume);
m.targetPuls = Math.round(m.targetVolume / m.volume_pulse);
}
function validateFlowBounds(m) {
const min = Number(m.nominalFlowMin);
const max = Number(m.flowMax);
const valid = Number.isFinite(min) && Number.isFinite(max) && min >= 0 && max > 0 && min < max;
m.invalidFlowBounds = !valid;
if (!valid) m.logger.warn(`Invalid flow bounds. nominalFlowMin=${m.nominalFlowMin}, flowMax=${m.flowMax}`);
return valid;
}
function getRainIndex(m) {
if (!m.lastRainUpdate) return 0;
if (Date.now() - m.lastRainUpdate > RAIN_STALE_MS) return 0;
return Number.isFinite(m.avgRain) ? m.avgRain : 0;
}
function getPredictedFlowRate(m) {
const min = Number(m.nominalFlowMin);
const max = Number(m.flowMax);
if (!Number.isFinite(min) || !Number.isFinite(max) || min < 0 || max <= 0 || min >= max) return 0;
const rainIndex = getRainIndex(m);
const scale = Math.max(0, Math.min(1, m.rainMaxRef > 0 ? rainIndex / m.rainMaxRef : 0));
return min + (max - min) * scale;
}
function getSampleCooldownMs(m) {
if (!m.lastSampleTime) return 0;
const remaining = (m.minSampleIntervalSec * 1000) - (Date.now() - m.lastSampleTime);
return Math.max(0, remaining);
}
module.exports = {
applyBoundsAndTargets,
validateFlowBounds,
getRainIndex,
getPredictedFlowRate,
getSampleCooldownMs,
RAIN_STALE_MS,
};