Skip to content

unobserved: is not verdict-neutral: an elided assignment is missing from the window, so verdicts differ for up to WINDOW_N reads afterwards #1049

Description

@InauguralPhysicist

Found by phugoid rung 4 (the N-aircraft swarm), 2026-08-26, eigenscript v0.41.0.

Title and body corrected. The first version said the divergence persists "forever after". It does not — it is bounded by the window. The measurements below are the corrected ones; see the correction comment for what changed and why.

unobserved: is documented and used as a performance tool — elide the entropy walk on assignments whose history nobody reads. But an elided assignment is not merely uncounted, it is absent from the window, so the verdicts computed from that window differ until the elided sample would have aged out.

Two measurements

(1) An elided initialiser shifts the window-fill boundary. Identical trajectory, identical reads; the only difference is whether b is 0.0 sits inside unobserved::

observed-init   hits=19 at=[9, 10, 11, 13, 14, 17, 18, ...]
unobserved-init hits=18 at=[   10, 11, 13, 14, 17, 18, ...]

They differ at exactly one read — index 9, the window-fill boundary — and are identical at every read after. So the effect is real and the count differs, but it is a one-sample delay, not a permanent divergence.

(2) A mid-stream elision perturbs a bounded run of reads, while the COUNT stays equal. One assignment (read 50 of 80) elided:

observed = 46 hits    one-mid-elided = 46 hits    differing reads = [50, 51, 57, 58]

Same total, four reads where the verdict differs. This is the case a consumer is most likely to miss: comparing counts shows nothing, while a controller acting per-read gets a different answer four times.

Both are consistent with the same mechanism — the elided sample is absent from a 10-deep window, so verdicts can differ until it would have aged out, then re-converge exactly.

How it surfaced

Two channel forms that must agree — four hand-written named locals, and N closures each capturing its own local — disagreed by exactly one hit on every channel ([1,17,17,1] against [0,16,16,0]). The only difference: the closure form built its channels inside unobserved:, because constructing N channels is setup. Moving it out restored agreement exactly.

Why it still matters

unobserved: is the sanctioned workaround for #1046 (any import arms the observer, so it is the only elision tool available). A consumer applying it for speed — to setup, or to a hot inner assignment — silently changes verdicts for a bounded window afterwards, with no diagnostic. Bounded is much better than permanent, but "the performance tool changes the answer" is still a sharp edge on the one mitigation available.

What would resolve it

Either make it neutral — an elided assignment still updates the window (or the sample count) while skipping the entropy computation, so eliding costs less without meaning something different — or document it as semantic, and give consumers a way to ask whether a bindings window is complete.

Related: #1046 (import arming), #1048 (trajectory lives on an environment slot).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions