docs(notes): record the item-difficulty exchangeability review and likelihood sensitivities - #440
Conversation
…kelihood sensitivities Adds the dated review note (keep the Beta-Binomial working likelihood; diagnose then patch locally), the PPC coverage sweep diagnostic, the age-artefact null-simulation check, and the blending chance-floor / word-reading CMB likelihood prototypes. Key results: the negative word-reading age association is not a difficulty-ladder artefact (null-simulation ladders bias the age slope positive); W's treatment effect is likelihood-robust (CMB nu = 0.50, items-scale AME invariant); B's ~1-item headline halves under the guessing-floor link (promotion decision pending with the education lead); the Rasch/IRT route is assessed and closed (original scoring sheets not readily available). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ngeability-assumptions-43f141 # Conflicts: # config/spellcheck/allow-en.txt
There was a problem hiding this comment.
Pull request overview
This PR records the 2026-07-26 decision and supporting evidence around ordered item difficulty vs the Binomial/Beta-Binomial working likelihoods, and adds standalone scripts to reproduce the key diagnostics/sensitivity checks described in the note.
Changes:
- Add a decision record note documenting the exchangeability/likelihood review, follow-up analyses, and decisions.
- Add three one-off/diagnostic scripts: a PPC coverage pooling sweep, an age “artefact” hinge+simulation check, and likelihood sensitivity prototypes (chance-floor link; Conway–Maxwell-binomial probe).
- Update the spellcheck allow-list with additional terms and some re-ordering/deduplication.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| scripts/ppc_coverage_sweep.py | Aggregates existing ppc_summary.csv artefacts across stored fits to summarise PPC coverage by outcome and model family. |
| scripts/likelihood_sensitivity_prototypes.py | Prototype likelihood/link sensitivity fits mirroring ITT structure (standard vs chance-floor link; standard vs CMB). |
| scripts/age_artefact_check.py | Implements a hinge-term real-data check and null simulations to test whether item-ladder structure could induce a spurious negative age slope. |
| notes/202607261405-binomial-exchangeability-item-difficulty-review.md | Decision record capturing the exchangeability/likelihood review, evidence, and follow-up actions/owners. |
| config/spellcheck/allow-en.txt | Adds/normalises allow-list terms needed for the new prose/scripts. |
Follows the reviewer's note on PR #440 that divergences should be coerced via np.asarray(...).values before summing, matching diagnostics.py, loo_refit.py and the shared dse_research_utils gate. Applying the house convention surfaced the larger issue: az.summary without round_to="none" falls through to rcParams' 2 significant figures, so the prototypes were reporting rounded R-hat (the dseinternational/ research#65 failure mode). Reading unrounded shows max R-hat 1.0018 and 1.0022, not the "1.0000" recorded in the note; min ESS now takes the bulk/tail minimum as the gate does. All four fits remain well inside the gate and every posterior summary is unchanged, so no conclusion moves -- the note's diagnostic lines are corrected to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Note Drafted by an LLM-based AI tool (Claude Code/Fable 5). Thanks — applied in b92bbdc, and following the convention through turned up something more consequential than the narrow point. The comment itself. Correct on the convention: What it surfaced. The house pattern pairs that coercion with Reading unrounded changes the reported diagnostics:
No conclusion moves. All four fits stay well inside the gate (R-hat ≤ 1.01, ESS ≥ 400, 0 divergences), and every posterior summary is byte-identical on a reseeded rerun — τ, the items-scale marginal effects, ν = 0.503, and the PSIS-LOO tie are all unchanged. The affected diagnostic lines in §5 and §6 of the note are corrected in the same commit. The unused |
…epairing the LOO refit gate Adds statistical_models/sampling_quality.py as the single place R-hat, ESS, BFMI and divergences are read off a trace, and routes diagnostics.py, loo_refit.py, scripts/design_analysis.py and the likelihood prototypes through it. This repairs a live defect. `_assert_refit_converged` called `az.summary(idata, round_to=None)`, which rounds to rcParams' "2g" — two significant figures. Every R-hat from 1.011 to 1.049 rounds to 1.0, so the exact-LOO-refit gate's `R-hat <= 1.01` arm was effectively `R-hat < 1.05` and would splice a badly-mixed refit into a comparison it then marked valid. It also took ESS from ess_bulk alone where the gate is defined on the bulk/tail minimum. Both are fixed by construction now that the extraction is shared; the gate's own thresholds and its missing-BFMI policy are unchanged. The helper extracts only — it does not decide pass/fail, because call sites legitimately differ in which variables they gate over and in how they treat a missing BFMI, and homogenising that silently would be a second bug. Tests pin the regression numerically, including that a trace with true R-hat in the collapsing band clears the gate once rounded. METHODS.md now directs all diagnostic reads through the helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Note Drafted by an LLM-based AI tool (Claude Code/Fable 5). Shared helper added in d2b57c0 — and building it surfaced a live defect in The defect
Because two-significant-figure rounding maps the whole band onto
The consequence is not cosmetic: a leave-one-out refit with R-hat up to 1.049 would pass, have its exact density spliced into the elpd, and the comparison then marked I have no evidence any published comparison was actually affected — every refit I can check is far inside the gate — but that is luck, not the gate working. The fix
Deliberate scope limits, since this touches a production gate:
So the only intended behaviour change is that the refit gate now applies the threshold it always documented. Verification
Worth a look from a reviewer who knows #438: the |
Note
Drafted by an LLM-based AI tool (Claude Code/Fable 5).
Summary
Records the 2026-07-26 review of whether ordered item difficulty (later words are harder on the word-reading and vocabulary tests) undermines the Binomial/Beta-Binomial working likelihoods, and adds the diagnostic and sensitivity tooling that grounds it. The decision record is
notes/202607261405-binomial-exchangeability-item-difficulty-review.md.New files
notes/202607261405-binomial-exchangeability-item-difficulty-review.md— the full decision record (questions, assessment, follow-up results, dated decisions with owners)scripts/ppc_coverage_sweep.py— standing diagnostic poolingppc_summary.csvcoverage by outcome/familyscripts/age_artefact_check.py— real-data hinge check + null-ladder simulation (seeded, reproduces the note's table exactly)scripts/likelihood_sensitivity_prototypes.py— the blending chance-floor and word-reading CMB prototype fits (mirror the ITT structure and priors; standard arms reproduce the stored reporting fits, W τ +0.354 to three decimals)config/spellcheck/allow-en.txt— eight new terms; the re-sort also normalised an unsorted tail block and merged duplicates (verified nothing lost)Checks
ruff check src/ scripts/…,npm run format:check, andnpm run spellcheckall pass.🤖 Generated with Claude Code