MeasurementContainer.get: strict-resolve explicit .child(name)
A read chain `.child(name).getCurrentValue()` previously fell through
silently to the implicit-default child or the first available sibling
when the named child did not exist. Caller asked for X, got Y, no
warning. Surfaced via pumpingStation spillPrev: a fresh basin's
.child('overflow').getCurrentValue() returned the value of
'manual-qout' (the only existing child at that position).
Split the resolution into two strictness levels:
_currentChildId (per-chain .child(name)) → STRICT, missing = null.
this.childId (persistent setChildId) → HINT, falls back to
'default' then first.
The persistent path is what registered children (rotatingMachine etc.)
rely on: they write under composed ids ('up-<id>') but expect reads
without explicit .child() to still resolve.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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-<id>') 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;
|
||||
|
||||
Reference in New Issue
Block a user