test: score the convergence predicates against an external oracle (#861) - #891
Merged
Conversation
#889 closed #861's reproducer, not its defect. I wrote that fix; this is the correction. The saturation gate lands at |v| >= 1e308. The false `converged` starts ~305 decades earlier: x *= 1.5 first certifies `converged` at x = 287,626 (~1e5) x *= 2.0 first certifies `converged` at x = 8,388,608 h_low = 0.1 against H(x) = H_b(1/(1+|x|)) puts every |x| > ~76 under the entropy floor, so `converged` fires across [77, 1e307]. A linear runaway `y is y + 1.0` exits `loop while not (converged of y)` at y = 88. The boundary is a region; #889 closed one point at the top of it. ## The oracle tests/test_convergence_oracle.eigs — 27 sequences whose behaviour is known analytically, no implementation consulted. This is the one component in the project that never had an external reference to be wrong against; every other subsystem has one (Blargg ROMs, the Go liferaft, drat-trim, POSIX, the C compiler), and every other subsystem is correct. ENTROPY CHANNEL (what converged/report use): 19/27 FP=3 FN=5 VALUE CHANNEL (report_value) : 25/27 FP=2 FN=0 Cases 25-27 are the cleanest single result: the same computation (halve the distance each step) targeting 5000, 5 and 0.005 returns converged / equilibrium / converged. Identical mathematics, verdict decided by units. ## Two corrections made while landing it Ground truth was wrong on three labels. Cases 6, 7 and 8 (1 + 1/n, (-1)^n/n, Basel partial sums) were labelled "settles", but their tails decay like 1/n, so at step 60 they sit 1.6e-2, 1.6e-2 and 9.9e-3 from their limits — outside the file's own 1e-9 criterion. They converge; they have not arrived. Verified against the closed forms. This moves entropy 16->19 and value 26->25: two of the value channel's wins were against mislabelled truth, and are really false positives. Aggregate scores alone are too coarse a gate. Planting a real semantics change (h_low 0.1 -> 0.5, which makes a held 10.0 certify converged) left both scores unmoved while flipping cases 7 and 13 from `stable` to `moving` — offsetting changes cancel in a count. The per-case bands are pinned too, and that version names the drifting cases. ## Green, not red The baseline is pinned rather than failing: a permanently red suite erodes every other gate, and [99c] is the existing precedent for inverting an expected failure into a pass. Movement in EITHER direction fails, so a fix must land as a deliberate edit here. ## test_observer_saturation.eigs Case 4 asserted "1e307 constant should still converge". A constant does converge, so the assertion was not false — but the entropy channel cannot distinguish it from a runaway that flattened there, so pinning the verdict pinned the region. It now asserts only that the saturation gate is tight to the ceiling, which is the property that is actually defensible. Gates: release 3787/3787, ASan+UBSan detect_leaks=1 3785/3785 with the LeakSanitizer tally at its 0 floor. Re-opens #861. Related: #862, #865. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a pinned, external-oracle regression test for the observer convergence predicates (issue #861), and adjusts the existing saturation test so it no longer implicitly endorses the currently-defective “large constant” convergence region below the saturation ceiling. This fits the codebase’s testing philosophy by anchoring observer behavior to an implementation-independent reference and preventing silent semantics drift.
Changes:
- Add
tests/test_convergence_oracle.eigs, scoringreport/converged(entropy channel) andreport_value(value channel) against 27 analytically-understood sequences, and pin both aggregate scores and per-case bands. - Update
tests/test_observer_saturation.eigscase 4 to only assert that the saturation gate does not fire below1e308(rather than assertingconvergedis “correct” at1e307). - Register the new oracle suite in
tests/run_all_tests.shas a pinned baseline gate.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tests/test_observer_saturation.eigs | Narrows the below-ceiling assertion to “not saturated” (no longer pins the defective converged region). |
| tests/test_convergence_oracle.eigs | Introduces an external-oracle baseline that pins current predicate performance and per-case verdict bands. |
| tests/run_all_tests.sh | Adds the oracle suite as a single-slot gate in the observer section. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reopens #861. I wrote #889; this is a correction to its scope, not a new finding.
The defect is a region, not a point
The saturation gate lands at
|v| >= 1e308. The falseconvergedstarts ~305 decades earlier:h_low = 0.1againstH(x) = H_b(1/(1+|x|))puts every|x| > ~76under the entropy floor:reportconvergedA linear runaway
y is y + 1.0exitsloop while not (converged of y)at y = 88. #889 closed one point at the top of[77, 1e307].The oracle
tests/test_convergence_oracle.eigs— 27 sequences whose behaviour is known analytically, no implementation consulted. The observer is the one component in this project that never had an external reference to be wrong against; every other subsystem has one (Blargg ROMs, the Go liferaft, drat-trim, POSIX, the C compiler), and every other subsystem is correct.Cases 25–27 are the cleanest single result — the same computation (halve the distance each step) targeting 5000, 5 and 0.005:
reportIdentical mathematics, identical convergence rate, verdict decided by the units you measured in.
Two corrections made while landing it
1 — Ground truth was wrong on three labels. Cases 6, 7 and 8 (
1 + 1/n,(-1)ⁿ/n, Basel partial sums) were labelled "settles", but their tails decay like1/n, so at step 60 they sit 1.6e-2, 1.6e-2 and 9.9e-3 from their limits — outside the file's own 1e-9 criterion. They converge; they have not arrived. Verified against the closed forms.This moves entropy 16→19 and value 26→25: two of the value channel's apparent wins were scored against mislabelled truth and are really false positives. The direction of the argument is unchanged, but the "26/27, zero FP" headline was flattered.
2 — Aggregate scores alone are too coarse a gate. Planting a real semantics change (
h_low0.1→0.5, which makes a held10.0certify converged) left both scores unmoved while flipping cases 7 and 13 fromstabletomoving— offsetting changes cancel in a count. Per-case bands are pinned too; that version catches it and names the cases:Green, not red
The baseline is pinned, not failing. A permanently red suite erodes every other gate, and
[99c]is the existing precedent for inverting an expected failure into a pass. Movement in either direction fails, so a fix must land as a deliberate, reviewed edit here rather than silently changing what a green suite means. The file header states plainly that it pins a defect baseline, not a target.test_observer_saturation.eigsCase 4 asserted "1e307 constant should still converge". A constant sequence does converge, so the assertion was not false — but the entropy channel cannot distinguish it from a runaway that flattened there, so pinning the verdict pinned the region. It now asserts only that the saturation gate is tight to the ceiling, which is the property that is actually defensible.
Gates
detect_leaks=1Not in scope
The fix this corpus argues for — routing the predicates to the value channel, dropping
h_lowfromconverged, and making tolerance visible and scale-relative — touches the entropy-constant fence and the language's headline vocabulary. That is a design decision, not a runtime-engineering one, and it is deliberately not in this PR. This PR only makes the defect measurable and prevents it from drifting.Related: #862 (the
H(x) ≡ H(1/x)level sets), #865 (saturation indistinguishability).🤖 Generated with Claude Code