0118 a residual estimate is refused rather than floored - CyrilB1531/lodestar GitHub Wiki
0118 â A residual estimate is refused rather than floored, and the interval width varies
Status: accepted · Date: 2026-09-12 · Applies: 0070, 0095
Context
docs/guides/conformal.md has carried the same admission since the package shipped:
That is a real limitation, not a simplification âĶ this package does not ship one yet.
Every interval SplitConformal produced had the same width for every input, because
AbsoluteResiduals scores each calibration point by |y â Å·| and the quantile of those is one
number. On data whose error varies with the input â most data â that is too wide where the model is
confident and too narrow where it is not, while still carrying the marginal coverage guarantee.
That combination is the trap rather than the inconvenience. The guarantee is what a reader comes
for, and it is exactly what makes a constant width easy to mistake for an adequate one.
#683 is that gap, and it matters more here
than the equivalent gap elsewhere because the survey behind
#441 found no C# implementation of
conformal prediction at all â a sole implementation sets what .NET thinks the technique is.
What MAPIE does, measured
ResidualNormalisedScore's signed score is (y â Å·) / rĖ and its interval is Å· + score · rĖ,
where rĖ is a second model's prediction of |y â Å·|. Reproduced end to end against MAPIE 1.5.0
with both estimators prefit, the bounds agree to 0.0 â not a tolerance, exactly, and the widths
on that fixture ran from 4.01 to 10.11.
One contract is worth writing down because it cost an hour: under prefit=True, MAPIE calls the
residual estimator's predict and uses the result as rĖ. Its own non-prefit path trains on
log |y â Å·| and exponentiates, and a prefit model that returns the log instead of the residual is
silently thresholded at eps â the warning MAPIE raises says so, and the intervals it then
produces are off by eight orders of magnitude rather than wrong by a little.
Decision
NormalisedResiduals and NormalisedInterval, taking rĖ and not the model that produced it.
That follows the shape every member of this package already has: the caller owns the models, and
what is written down is the arithmetic that carries the guarantee. A residual_estimator parameter
would mean an estimator interface, a fit, and a package that suddenly has opinions about where a
model comes from â which is what prefit exists to avoid on the other side.
A non-positive or NaN estimate is refused. MAPIE floors at 1e-8 instead, and the divergence
is deliberate:
- MAPIE floors because its own residual model may predict a negative, and it has nowhere to send the complaint mid-pipeline.
- Here the estimate is the caller's own argument. Flooring would turn their bug into an interval of
width
q · 1e-8, which is not an error and not a wide interval â it reads as certainty, and the reader most likely to hit it is the one who fitted the residual model on the residual rather than on its log.
This is decision 0070's reasoning applied
and its direction reversed, which is worth being explicit about. There, MAPIE raised and this
package returned an infinite interval, because a trivial-but-honest answer beats an exception. Here
MAPIE answers and this package raises â for the same reason read the other way: q · 1e-8 is not
an honest answer, it is a confident one produced from an input that carries no information.
GammaConformityScore waits, under decision 0095's
rule. Nothing has asked; publishing later is always available and unpublishing never is. It is also
a different kind of thing â a multiplicative score for a strictly positive target â rather than the
adaptive-width fix this issue was about.
Options that lost
- Floor at
1e-8, for parity. Decision 0008's rule is parity with the library a user migrates from, and this is a real cost against it: a migrating caller whose pipeline relied on the floor gets an exception here. Refused because the behaviour being matched is a defence against MAPIE's own internals, not a promise to its users â anddocs/equivalence.mdrecords the divergence where a migrating reader will meet it. - Take the residual model instead of its predictions. Closer to MAPIE's surface, and it would
let this package apply the
log/expconvention itself rather than documenting it. Refused: it needs an estimator abstraction that nothing else here has, and the first thing it would have to do is offer aprefitescape hatch. - Return
PositiveInfinityfor a non-positive estimate, the wayQuantiledoes fork > n. Consistent-looking and wrong: an infinite quantile is a correct statement about a calibration set too small to support the level, where a non-positiverĖis an input that cannot be interpreted at all. - One
Intervaloverload taking an optional estimate, rather than a second member. Fewer names, and it would hide the decision: an interval whose width varies is a different promise, and the call site should say which one it made.
Consequences
Lodestar.Conformalreaches 0.2.0 â new members, nothing existing moved.- The corpus grows by three cases, and every one of them has estimates that vary: a constant estimate reduces the score to the absolute residual divided by a number, so a fixture built that way would pass while testing nothing. A test asserts the widths differ by more than a factor of two, which the corpus alone cannot catch.
docs/guides/conformal.md's limitation paragraph becomes a section about choosing between the two scores. The exchangeability caveat keeps leading the guide: a normalised score does not weaken it, and a reader should not be able to infer that it does.- This record is
0117, and#703is open holding a0116that collides with the one already onmain. If that branch renumbers into0117the two collide in turn;0118is free.