Skip to content

feat(analysis): reachability levels L0/L1/L2 for the oracle ceiling (ORACLE §2.2) - #417

Merged
James-CUDA merged 1 commit into
James-CUDA:mainfrom
minion1227:minion_reachability
Jul 23, 2026
Merged

feat(analysis): reachability levels L0/L1/L2 for the oracle ceiling (ORACLE §2.2)#417
James-CUDA merged 1 commit into
James-CUDA:mainfrom
minion1227:minion_reachability

Conversation

@minion1227

@minion1227 minion1227 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

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:

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 PR supplies the missing layer.

What's here

analysis/reachability.py computes the oracle at each supplied level and applies the §2.2/§6 rule literally: only the widest measured level can rule routing out.

Level What it measures
L0 single-turn Worker — cheapest; a strict lower bound
L1 best-role-per-model — each model as a single answerer in any role
L2 short multi-turn probe — sampled, so it carries its own CI

A thin L0 (or L1) now yields LOWER_BOUND_ONLY and names the next level to measure, instead of the POOL_BOUND conclusion 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_oracle and best_single are 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_violation pins 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

  • Purely additive. No existing caller changes behaviour; the existing single-matrix verdict path in oracle_ceiling.py is untouched. The widest-level rule only engages when several level reports are supplied.
  • Reuses the canonical decoder. union_oracle.oracle_from_matrix is called rather than reimplemented, 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 to keep in lockstep.
  • Pure stdlib + the existing numpy path. No network, no GPU, no torch.

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/ -q1844 passed, 0 failed (28 new)
  • ruff check src/ scripts/repo_governance/ → clean; mypy on the new module → clean

Note on CI: main has unresolved merge-conflict markers in src/trinity/analysis/__init__.py (introduced by dc15f97), so the package does not import and this PR is red on the merge commit. This branch adds a new module and touches no existing file in analysis/, and the 1844-passed run above was taken with those markers resolved locally.

The fix is not contested: #402, #405, #407, #408 and #403 all rewrite that file to the byte-identical result (every one is index 9916618..6865bc2), so merging any one of them repairs main and the rest become no-ops on that file. Note that #407 / #408 / #403 are already green — they touch that file for their own feature and resolved it in passing. Only PRs that don't touch it (this one, #415, #416, #412) are red.

🤖 Generated with Claude Code

…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
James-CUDA force-pushed the minion_reachability branch from 32e9fcf to c979a8f Compare July 23, 2026 11:38
@James-CUDA
James-CUDA merged commit 5dcbb1c into James-CUDA:main Jul 23, 2026
1 of 2 checks passed
@minion1227
minion1227 deleted the minion_reachability branch July 23, 2026 11: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

Development

Successfully merging this pull request may close these issues.

2 participants