diff --git a/src/measurements/MeasurementContainer.js b/src/measurements/MeasurementContainer.js index 9ceb8af..5788f3d 100644 --- a/src/measurements/MeasurementContainer.js +++ b/src/measurements/MeasurementContainer.js @@ -425,16 +425,34 @@ class MeasurementContainer { // Legacy single measurement if (posBucket?.getCurrentValue) return posBucket; - // Child-aware: pick requested child, otherwise fall back to default, otherwise first available + // Child-aware lookup. Two separate sources of "child-id" on the + // container, with DIFFERENT strictness: + // + // _currentChildId : transient, set by .child(name) inside a chain. + // Explicit per-call. STRICT — if the named child + // does not exist, return null. Silent fall-through + // to a sibling would mask a missing-stream read + // as a wrong-stream read (see pumpingStation + // spillPrev bug, 2026-05-06). + // + // this.childId : persistent, set by setChildId(id). HINT only — + // try it first, then fall back to 'default' then + // first available. Containers registered with a + // persistent id (rotatingMachine, etc.) write + // under composed child ids (e.g. 'up-') that + // don't equal the persistent id, and reads must + // still resolve to those writes. if (posBucket && typeof posBucket === 'object') { - const requestedKey = this._currentChildId || this.childId; const keys = Object.keys(posBucket); if (!keys.length) return null; - const measurement = - (requestedKey && posBucket[requestedKey]) || - posBucket.default || - posBucket[keys[0]]; - return measurement || null; + + if (this._currentChildId) { + return posBucket[this._currentChildId] || null; + } + return (this.childId && posBucket[this.childId]) || + posBucket.default || + posBucket[keys[0]] || + null; } return null;