Skip to content

Stop dist:'exponential' condemning itself on a scale it never estimates - #18

Open
jrosskopf wants to merge 1 commit into
mainfrom
fix/exponential-fixed-scale
Open

Stop dist:'exponential' condemning itself on a scale it never estimates#18
jrosskopf wants to merge 1 commit into
mainfrom
fix/exponential-fixed-scale

Conversation

@jrosskopf

@jrosskopf jrosskopf commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Recorded as a known limitation rather than fixed, on the grounds that the fix was a contract decision. Taking the decision — and the narrower of the two options.

The defect

Under dist: 'exponential' the AFT scale is held at 1 by the definition of the distribution. Its posterior sd is exactly zero, so ess returns 0.0, and the gate condemned the whole fit as degenerate — while every coefficient was estimated correctly and the other three distributions converged on the same data.

An agent reading anofox_bayes_is_actionable was told to ignore a fit that was fine. Same class as the two refusal-contract bugs fixed in #1: a verdict that doesn't match reality.

Measured through SQL, before → after: degenerate / falseconverged / true.

Why it cannot be fixed by looking at the draws

ess returning zero for a parameter that never moves is deliberate — it is what stops a genuinely stuck sampler sailing through an ess >= 400 gate. And a stuck chain is indistinguishable from a constant one by its values alone. Inferring "structurally fixed" from the draws would hand the stuck chain the same exemption, trading a false refusal for a false pass. That is the worse trade.

So the family declares it

CompiledModel::fixed_params names the parameters a model reports but does not estimate. Default is empty — a family that declares nothing gets no exemption. censored_aft returns sigma under exponential and nothing under the other three, so a scale that genuinely fails to mix still condemns the fit it belongs to.

Nothing moves in the draws contract

sigma is still published, still exactly 1. A consumer joining on param = 'sigma' need not branch on dist — which is precisely why the alternative (omitting the row for this dist) was rejected: it would have changed a join surface to fix a grading bug.

The scope is asserted, not described

declaring_a_parameter_fixed_exempts_that_parameter_and_no_other grades one posterior with two dead parameters, three ways:

  • exempt neither → degenerate
  • exempt sigmastill degenerate for beta, and only beta is named
  • exempt both → converged

The interesting case is telling two identical-looking parameters apart, which is exactly what the declaration exists to do.

Verification

cargo test 393 pass · clippy clean · make test 681 assertions · make test_scenario 57 · end-to-end SQL check of the before/after verdict.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Under exponential the AFT scale is held at 1 by the definition of the
distribution, so its posterior sd is exactly zero and ess returns 0.0.
The gate saw a dead parameter and graded the whole fit degenerate while
every coefficient was estimated correctly and the other three
distributions converged on the same data. An agent reading
is_actionable was told to ignore a fit that was fine.

This was recorded as a known limitation rather than fixed because the
fix is a contract decision. Taking it, and taking the narrower option.

It cannot be fixed by looking at the draws. ess returning zero for a
parameter that never moves is deliberate -- it is what stops a stuck
sampler passing an ess >= 400 gate -- and a stuck chain is
indistinguishable from a constant one by its values alone. Inferring
"fixed" from the draws would hand the stuck chain the same exemption.

So the family declares it. CompiledModel::fixed_params names the
parameters a model reports but does not estimate, defaulting to none.
censored_aft returns sigma under exponential and nothing under the
other three, so a scale that genuinely fails to mix still condemns the
fit it belongs to.

Nothing moves in the draws contract: sigma is still published and still
exactly 1, so a consumer joining on param = 'sigma' need not branch on
dist. That is why omitting the row was rejected as the alternative.

The scope is asserted rather than described. Grading a posterior with
two dead parameters three ways: exempting neither condemns, exempting
sigma still condemns for beta and names only beta, exempting both
converges.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant