Skip to content

feat(observer): raw-step signals (#422) + trajectory snapshots across calls (#421)#540

Merged
InauguralPhysicist merged 1 commit into
mainfrom
observer-pair-421-422
Jul 10, 2026
Merged

feat(observer): raw-step signals (#422) + trajectory snapshots across calls (#421)#540
InauguralPhysicist merged 1 commit into
mainfrom
observer-pair-421-422

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

The pair

Designed together because they interlock: #422 makes the value-channel classifier honest; #421 makes it reachable from the other side of a call boundary. Closes #421, closes #422 — the last two observer-semantics issues from the 2026-07-04 survey.

#422 — the two blind spots, one missing signal

Relative normalization (Δv/(1+|v|)) erased exactly two classes, and both misread as accepting regimes:

Trajectory Before After
x → x + 5000 seeded at 4e5 (linear runaway) stable/converged diverging
x → -x seeded at 4e-4 (perpetual oscillation) stable/converged oscillating
1e6 ↔ 1e6+500 fixed swing converged oscillating
x → 2x (geometric runaway) moving diverging
damped oscillation / halving / settled constant converged converged (unchanged)

The insight: both blind spots are the same missing question. The slot now keeps a parallel window of raw steps and asks whether they are non-vanishing (recent-half mean ≥ half the older-half mean, above a 4·ε·(1+|v|) fp-noise floor). Non-vanishing same-sign steps sum without bound → diverging; non-vanishing alternating steps → oscillating; decaying steps settle exactly as before. The relative step stays the primary contract.

Contracts upgraded to match: expect_converging fails fast on a mid-run diverging, invariant_stable throws on it, and lib/contract.eigs's documented blind-spot caveats are deleted because the instrument no longer has them.

#421 — trajectories as values

Observer state is binding-identity, so a value passed into a function arrives with no history — the naive two-arg contract could never work. Now:

  • trajectory of x (special form, two ABI-appended opcodes) snapshots the binding's observer windows into a plain, inspectable dict
  • classify of t / classify of [t, "entropy"] (builtin, sandbox-allowed) classifies the snapshot through the same slot machinery report_value/report use — no mirror to drift
  • classify of a non-snapshot raises type_mismatch: a bare value never silently classifies as "no trajectory"
  • lib/contract.eigs gains the snapshot form expect_regime of [trajectory of x, expected, msg]
  • lint knows trajectory as a special form (E003 + the shadow set)

Verification

  • Both issue repros pinned red→green in new suite section [50j2] (tests/test_trajectory.eigs, 20 checks), plus no-regression pins for damped/settled/halving, both channels from one snapshot, the loud error paths, and expect_regime
  • Release suite 2725/2725; ASan + detect_leaks=1 2725/2725, leak tally 0; both tiers verified (JIT on / EIGS_JIT_OFF)
  • SPEC.md + COMPARISON.md gain byte-pinned examples (doc-examples gate green); OBSERVER.md documents the raw-step signal + snapshot model; BUILTINS.md gate green
  • test_lint.sh's fixture renamed its classify function — a true-positive W013 now that the name is a registered builtin. Bump-train note: the next consumer sweep should check for user-defined classify/trajectory shadows.
  • AOT note: ouroboros pins releases; its aot_rt observer mirror picks this up at the next EIGS_REF bump, per the Observer surface coherence: implement or remove 'how'; decide |x|=1.0; fold in #383 #412 precedent.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm

… calls (#421)

The observer pair, designed together because they interlock: #422 makes
the value-channel classifier honest, #421 makes it reachable from the
other side of a call.

#422 — relative normalization (dv/(1+|v|)) erased exactly two classes,
both misreading as ACCEPTING regimes: additive/polynomial runaway read
converged/stable, and sub-deadband perpetual oscillation read stable.
The value channel now keeps a parallel raw-step window and asks one
structural question — are the steps non-vanishing (recent-half mean >=
half the older-half mean, above a 4*eps*(1+|v|) fp-noise floor)?
Non-vanishing same-sign => diverging (first use of the label on the
value channel; geometric runaway upgrades from 'moving' too).
Non-vanishing alternating => oscillating. Decaying steps settle as
before — damped oscillation still reads converged. Contracts upgraded:
expect_converging fails FAST on mid-run diverging, invariant_stable
throws on it, and lib/contract.eigs's documented blind-spot caveats are
deleted because the instrument no longer has them.

#421 — observer state is binding-identity; a passed value arrives with
no history. New special form 'trajectory of x' (OP_TRAJECTORY_SLOT/NAME,
ABI-appended) snapshots the binding's windows into a transparent dict;
new builtin 'classify of t' / 'classify of [t, "entropy"]' classifies
it through the SAME slot machinery report_value/report use. classify of
a non-snapshot raises type_mismatch — a bare value never silently
classifies. lib/contract.eigs gains the snapshot-form expect_regime;
lint.c learns 'trajectory' as a special form (E003 + shadow set).

Suite [50j2] (test_trajectory.eigs, 20 checks) pins both issue repros
red-then-green, the no-regressions, the call-boundary crossing, both
channels, and the loud error paths. test_lint.sh's feature-rich fixture
renamed its 'classify' fn — a true-positive W013 now that the name is a
registered builtin (consumer sweep note: check for the same at the next
pin bump). SPEC.md + COMPARISON.md gain byte-pinned examples; OBSERVER.md
documents the raw-step signal and the snapshot model; BUILTINS.md gate
green (214 builtins documented).

Release suite 2725/2725; ASan+detect_leaks 2725/2725, leak tally 0;
both tiers (JIT on / EIGS_JIT_OFF) verified on the new tests.

Closes #422
Closes #421

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GdDAVfZHgoQ2UNP63FYUXm
@InauguralPhysicist InauguralPhysicist merged commit 13f5100 into main Jul 10, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the observer-pair-421-422 branch July 10, 2026 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant