feat(analysis): reachability levels L0/L1/L2 for the oracle ceiling (ORACLE §2.2) - #417
Merged
Merged
Conversation
This was referenced Jul 22, 2026
fix(analysis): resolve unresolved merge-conflict markers in __init__ (package failed to import)
#405
Merged
…ORACLE §2.2) ORACLE §2.2 names the diagnostic's false-negative failure mode: TRINITY is (model, role) decisions over up to 5 turns, so an oracle computed from single-turn Worker correctness alone is a STRICT LOWER BOUND on the reachable ceiling. A thin gap measured that way can read as "routing is hopeless" when multi-turn collaboration would in fact have helped. §9's defense table lists the fix as "L0/L1/L2 reachability; L0 is a lower bound". That fix was never built, and the shipped code says so twice: - scripts/oracle_ceiling.py exposes --level with choices=["L0"] and the help text "L1/L2 are future". - Its verdict's INCONCLUSIVE branch advises "Widen the reachability level (L1/L2)" — advice nothing can currently act on. Meanwhile §6 defines the deciding quantity as H = routing_headroom measured "at the widest reachability level (L2 if run, else L1)". Since neither can be run, every verdict today rests on L0 while the decision rule believes it is reading something wider. This supplies the missing layer. `analysis/reachability.py` computes the oracle per supplied level and applies the §2.2/§6 rule literally: only the WIDEST MEASURED level can rule routing out. A thin L0 (or L1) yields LOWER_BOUND_ONLY and names the next level to measure, rather than POOL_BOUND. Two correctness points worth calling out: - **Only the oracle is monotone, not the headroom.** Each level's option set contains the one below it, so routing_oracle and best_single can only grow with the level; their DIFFERENCE is under no such constraint. The integrity guard therefore flags a drop in the ORACLE (mathematically impossible → a collection bug) and never assumes the headroom moves either way. A collection bug outranks every routing conclusion (INCONSISTENT). - **A sampled level needs a CI.** §2.2 requires L2 be "reported with its own CI"; a point estimate from a handful of sequences cannot establish absence of headroom, so L2 without a CI yields NEEDS_CI rather than a verdict. Thinness is gated on the CI upper bound (§6's <= 0.02), not the point estimate. Reuses the canonical `union_oracle.oracle_from_matrix` decoder rather than reimplementing it, so this cannot drift from the on-disk schema — an L1 matrix is just composite "model/role" keys in the SAME oracle_matrix schema, no new format. Scope, stated honestly: this is the ANALYSIS layer and is fully offline. Collecting an L1/L2 matrix needs live role-loop / trajectory calls, exactly as collecting L0 already does; that is out of scope here and unchanged. Purely additive — no existing caller changes behaviour. Full suite: 1844 passed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
James-CUDA
force-pushed
the
minion_reachability
branch
from
July 23, 2026 11:38
32e9fcf to
c979a8f
Compare
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.
The gap
docs/ORACLE_CEILING_DIAGNOSTIC.md§2.2 names the diagnostic's false-negative failure mode: TRINITY is not "pick one model", it is(model, role)decisions over up to 5 turns. So an oracle computed from single-turn Worker correctness alone is a strict lower bound on the reachable ceiling — a thin gap measured that way can read as "routing is hopeless" when multi-turn collaboration would in fact have helped. §9's defense table lists the fix as "L0/L1/L2 reachability; L0 is a lower bound".That fix was never built, and the shipped code says so in two places:
scripts/oracle_ceiling.py:858exposes--levelwithchoices=["L0"]and the help text "L1/L2 are future".scripts/oracle_ceiling.py:564— the verdict's INCONCLUSIVE branch advises "Widen the reachability level (L1/L2) or collect more samples", advice nothing can currently act on.Meanwhile §6 defines the deciding quantity as
H = routing_headroommeasured "at the widest reachability level (L2 if run, else L1)". Since neither can be run, every verdict today rests on L0 while the decision rule believes it is reading something wider. This PR supplies the missing layer.What's here
analysis/reachability.pycomputes the oracle at each supplied level and applies the §2.2/§6 rule literally: only the widest measured level can rule routing out.L0L1L2A thin L0 (or L1) now yields
LOWER_BOUND_ONLYand names the next level to measure, instead of thePOOL_BOUNDconclusion the data cannot support.Two correctness points worth review
1. Only the oracle is monotone — the headroom is not. Each level's option set contains the one below it (L1 lets a model answer in any role, Worker included). A max over a superset can only grow, so
routing_oracleandbest_singleare both non-decreasing in the level — and their difference is therefore under no such constraint. Widening reachability can lift the best single answerer as much as it lifts the ceiling.So the integrity guard flags a drop in the oracle (mathematically impossible → a collection bug) and never assumes the headroom moves in a particular direction. This matters because §2.2's phrasing ("only rules out routing if L1 and L2 are also thin") invites comparing headrooms across levels; that comparison is not well-founded, so each level's own headroom is read instead.
test_headroom_may_fall_as_the_level_widens_without_being_a_violationpins this.A detected collection bug outranks every routing conclusion (
INCONSISTENT) — a bad matrix must not be reported as a finding about routing.2. A sampled level needs a CI. §2.2 requires L2 be "reported with its own CI": a point estimate from a handful of sequences cannot establish absence of headroom. L2 without a CI yields
NEEDS_CI, not a verdict. Thinness is gated on the CI upper bound (§6's<= 0.02), not the point estimate — so a headroom of 0.0 with a CI of[-0.01, 0.30]is correctly not thin.Why it's low-risk
oracle_ceiling.pyis untouched. The widest-level rule only engages when several level reports are supplied.union_oracle.oracle_from_matrixis called rather than reimplemented, so this cannot drift from the on-disk schema. An L1 matrix is just composite"model/role"keys in the sameoracle_matrixschema — no new format to keep in lockstep.Scope, stated honestly
This is the analysis layer and is fully offline. Actually collecting an L1 or L2 matrix needs live role-loop / trajectory calls, exactly as collecting L0 already does — that is out of scope here and unchanged. This PR makes the levels analyzable and verdict-safe; it does not claim to have measured L1 or L2 on real data.
I also deliberately did not add exports to
analysis/__init__.py: that file currently holds the unresolved conflict markers #402/#405 are fixing, and touching it would create exactly the three-way conflict that broke it. Happy to add the export in a follow-up once main is repaired.Verification
pytest tests/ -q→ 1844 passed, 0 failed (28 new)ruff check src/ scripts/repo_governance/→ clean;mypyon the new module → clean🤖 Generated with Claude Code