You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Drafted by a LLM-based AI tool (Claude Code/Opus 4.8).
What this promotes
notes/202607241900-findings-word-reading-threshold.md (pending commit) asked whether children need a minimum word-reading level before they can progress in letter sounds, blending or nonword reading. The answer is no minimum for any of the three, but the nonword result is strong enough to deserve a registered model: dropping the period-start word-reading term costs 18 ± 4.4 elpd, the largest effect of any specification choice in the probe. This issue promotes that one fit out of notes/assets/202607241900-wr-threshold-probe.py and into the suite. The letter-sound and blending results are negative and are explicitly not proposed for registration.
The finding, and the shape that matters
Period-start word reading predicts end-of-period nonword reading with diminishing returns, not a threshold. PSIS-LOO over four specifications that differ only in how word reading enters (all sharing own baseline, age, arm, on-intervention status, hearing, speech, and a child random intercept):
Spec
elpd difference
dse
weight
Same, restricted to ≤ 25 words
log (diminishing returns)
0.0
—
1.00
1.00
linear
−4.0
2.6
0.00
−7.0 ± 1.7
hinge (free breakpoint — the prerequisite hypothesis)
−6.0
2.9
0.00
−10.0 ± 2.5
null
−18.0
4.4
0.00
−11.0 ± 3.3
Fitted expected nonword score by period-start words read, covariates at their means: 0.29 (0 words), 0.48 (1), 0.63 (2), 0.98 (5), 1.41 (10), 2.21 (25). Roughly half the climb across 0–40 words happens over the first five. The slope survives adjusting for period-start letter sounds (+0.71 [+0.50, +0.94] → +0.57 [+0.33, +0.81]), so it is not letter-sound knowledge in disguise. The probe fits were clean (0 divergences, max R-hat 1.01, min bulk ESS 581) but bypass the production gate, publish no config.json / diagnostics_summary.json / report, and should not be cited outside the note until this lands.
WR_t → NW_{t+1} is not an edge in dag/dag-language-reading-lagged.dagitty.#428 is the open decision on whether it should be. That decision determines what this model can claim, and there is no point building it twice:
If the edge is adopted — derive the minimal sufficient adjustment set against the amended graph before specifying the module, and confirm it is fittable at n ≈ 52. On the current graph the implied set is 8 nodes on the randomised transition and 12 post-crossover, which is not fittable; an amended graph may or may not improve that. If it does, the model ships as an adjusted association in the usual idiom.
If the edge is rejected — the model still has descriptive value (it is the cleanest statement of a pattern the cohort clearly shows), but it ships as causal_status="none", estimand_type="descriptive", with report prose stating that the quantity is a marginal lagged association whose content includes latent general ability, shared intervention dose, and whatever runs through letter sounds and blending.
Do not start the module until #428 closes. Everything below is the specification to build once it has.
Proposed design
Family.kind="mechanism", mechanism_symbol="W", outcome_symbol="N", using the mechanism_at_pre=True capability salvaged in #423 — this is exactly the lagged readout it was kept for (mechanism_pre → outcome_post ∣ outcome_pre). Id to be confirmed next-free against definitions.MODEL_REGISTRY and docs/models/registry-counts.json; note the mech-19N docstring-alias trap recorded in #430.
Two estimands, and the floored one should lead. Nonword reading is 6 items and floored for 72 / 64 / 52 / 40 % of children at t1–t4, so most of what "progress" means here is floor exit:
Primary — off-floor risk. A Bernoulli on the off-the-floor-at-post indicator, reusing the bernoulli_offfloor likelihood the ITT and gain-factor families already carry for P and N. Reported as an off-floor risk difference across the word-reading range. This is the estimand the descriptive result is in (4/29 at zero words, 10/37 at 1–4, 11/14 at 5–9), and it is the better-powered one.
Secondary — graded count. The Beta-Binomial on the count, flagged as the weaker readout, mirroring the suite's floor-rule convention of an exploratory binary headline plus a flagged graded secondary.
Functional form. The winning form is a straight line in log1p(words) — a fixed concave transform. That is not currently an option on the mechanism factory, which offers an HSGP curve or linear_mechanism=True. Options, in preference order:
add a mechanism_transform option ("identity" | "log1p") to the mechanism factory — small, generic, and the honest representation of what the data prefer;
or fit linear_mechanism=True on a pre-transformed exposure and record the transform in spec_extra.
An HSGP curve is not recommended as primary: mech-072 already established that a nonparametric dose-response is not identifiable on a floored 6-item outcome, #421 applies the same reasoning to its proposed mech-102 / mech-103, and #430 is currently repairing a GP knee test that failed for exactly this reason. If a curve is wanted at all it belongs as a sensitivity, and its divergence behaviour should be checked before it is promised in a report.
Comparators. A null (no word-reading term) companion for the PSIS-LOO contrast, following the mech-072 / mech-172 convention. The linear and hinge specifications do not need registering — their role was to establish the shape, and that belongs in the note, not the suite.
Covariates. Own period-start nonword score, age, arm, on-intervention status, hearing, speech, child random intercept — the probe's set — unless #428's re-derivation says otherwise, in which case the DAG wins.
Module(s) in src/language_reading_predictors/statistical_models/, each a SPEC = ModelSpec(...) + fit(), id confirmed next-free; registered via module auto-discovery; python scripts/check_statistical_documentation.py --write run and registry-counts.json regenerated.
mechanism_transform (or the recorded pre-transform equivalent) implemented with tests.
Off-floor primary and graded secondary both reported, with the floor-rule caveat stated in the report prose.
Thin report template under docs/models/{model_id}/ reusing _results_mechanism; docs/models/README.md mechanism table updated; PSIS-LOO contrast against the no-word-reading companion wired into scripts/compare_statistical_models.py.
--config reporting fit passes the convergence gate (R-hat ≤ 1.01, ESS ≥ 400, BFMI ≥ 0.3, 0 divergences); estimates reported as median + 50 % / 89 % CrI + P(> 0).
Report prose states the three things the note cannot resolve: direction (a child beginning to decode also reads more words), the 6-item floor (a concave curve on a logit link with a floored bounded outcome is partly manufacturable by the instrument), and latent general ability.
notes/202607241900-findings-word-reading-threshold.md updated with the registered model's numbers.
ruff check src/, npm run format:check, npm run spellcheck pass.
Related
Source note notes/202607241900-findings-word-reading-threshold.md and probe notes/assets/202607241900-wr-threshold-probe.py. Blocked on #428 (the WR_t → NW_{t+1} DAG decision). Uses the mechanism_at_pre capability from #423. Sibling follow-ups from the same pair of reviews: #421 (letter-sound → word-reading models, including RW → NW and SP → NW mechanisms this would sit beside), #404, #429, #430. Descriptive antecedent: notes/202607241600-findings-word-reading-bands.md.
Note
Drafted by a LLM-based AI tool (Claude Code/Opus 4.8).
What this promotes
notes/202607241900-findings-word-reading-threshold.md(pending commit) asked whether children need a minimum word-reading level before they can progress in letter sounds, blending or nonword reading. The answer is no minimum for any of the three, but the nonword result is strong enough to deserve a registered model: dropping the period-start word-reading term costs 18 ± 4.4 elpd, the largest effect of any specification choice in the probe. This issue promotes that one fit out ofnotes/assets/202607241900-wr-threshold-probe.pyand into the suite. The letter-sound and blending results are negative and are explicitly not proposed for registration.The finding, and the shape that matters
Period-start word reading predicts end-of-period nonword reading with diminishing returns, not a threshold. PSIS-LOO over four specifications that differ only in how word reading enters (all sharing own baseline, age, arm, on-intervention status, hearing, speech, and a child random intercept):
log(diminishing returns)linearhinge(free breakpoint — the prerequisite hypothesis)nullFitted expected nonword score by period-start words read, covariates at their means: 0.29 (0 words), 0.48 (1), 0.63 (2), 0.98 (5), 1.41 (10), 2.21 (25). Roughly half the climb across 0–40 words happens over the first five. The slope survives adjusting for period-start letter sounds (+0.71 [+0.50, +0.94] → +0.57 [+0.33, +0.81]), so it is not letter-sound knowledge in disguise. The probe fits were clean (0 divergences, max R-hat 1.01, min bulk ESS 581) but bypass the production gate, publish no
config.json/diagnostics_summary.json/ report, and should not be cited outside the note until this lands.Blocked on #428 — read that first
WR_t → NW_{t+1}is not an edge indag/dag-language-reading-lagged.dagitty. #428 is the open decision on whether it should be. That decision determines what this model can claim, and there is no point building it twice:causal_status="none",estimand_type="descriptive", with report prose stating that the quantity is a marginal lagged association whose content includes latent general ability, shared intervention dose, and whatever runs through letter sounds and blending.Do not start the module until #428 closes. Everything below is the specification to build once it has.
Proposed design
Family.
kind="mechanism",mechanism_symbol="W",outcome_symbol="N", using themechanism_at_pre=Truecapability salvaged in #423 — this is exactly the lagged readout it was kept for (mechanism_pre → outcome_post ∣ outcome_pre). Id to be confirmed next-free againstdefinitions.MODEL_REGISTRYanddocs/models/registry-counts.json; note themech-19Ndocstring-alias trap recorded in #430.Two estimands, and the floored one should lead. Nonword reading is 6 items and floored for 72 / 64 / 52 / 40 % of children at t1–t4, so most of what "progress" means here is floor exit:
bernoulli_offfloorlikelihood the ITT and gain-factor families already carry forPandN. Reported as an off-floor risk difference across the word-reading range. This is the estimand the descriptive result is in (4/29 at zero words, 10/37 at 1–4, 11/14 at 5–9), and it is the better-powered one.Functional form. The winning form is a straight line in
log1p(words)— a fixed concave transform. That is not currently an option on the mechanism factory, which offers an HSGP curve orlinear_mechanism=True. Options, in preference order:mechanism_transformoption ("identity"|"log1p") to the mechanism factory — small, generic, and the honest representation of what the data prefer;linear_mechanism=Trueon a pre-transformed exposure and record the transform inspec_extra.An HSGP curve is not recommended as primary:
mech-072already established that a nonparametric dose-response is not identifiable on a floored 6-item outcome, #421 applies the same reasoning to its proposedmech-102/mech-103, and #430 is currently repairing a GP knee test that failed for exactly this reason. If a curve is wanted at all it belongs as a sensitivity, and its divergence behaviour should be checked before it is promised in a report.Comparators. A
null(no word-reading term) companion for the PSIS-LOO contrast, following themech-072/mech-172convention. Thelinearandhingespecifications do not need registering — their role was to establish the shape, and that belongs in the note, not the suite.Covariates. Own period-start nonword score, age, arm, on-intervention status, hearing, speech, child random intercept — the probe's set — unless #428's re-derivation says otherwise, in which case the DAG wins.
Acceptance criteria
WR_t → NW_{t+1}belongs in the lagged DAG (and refresh the stale d-separation asset) #428 closed, and this issue's estimand framing (causal_status,estimand_type) set to match its outcome.src/language_reading_predictors/statistical_models/, each aSPEC = ModelSpec(...)+fit(), id confirmed next-free; registered via module auto-discovery;python scripts/check_statistical_documentation.py --writerun andregistry-counts.jsonregenerated.mechanism_transform(or the recorded pre-transform equivalent) implemented with tests.docs/models/{model_id}/reusing_results_mechanism;docs/models/README.mdmechanism table updated; PSIS-LOO contrast against the no-word-reading companion wired intoscripts/compare_statistical_models.py.--config reportingfit passes the convergence gate (R-hat ≤ 1.01, ESS ≥ 400, BFMI ≥ 0.3, 0 divergences); estimates reported as median + 50 % / 89 % CrI + P(> 0).notes/202607241900-findings-word-reading-threshold.mdupdated with the registered model's numbers.ruff check src/,npm run format:check,npm run spellcheckpass.Related
Source note
notes/202607241900-findings-word-reading-threshold.mdand probenotes/assets/202607241900-wr-threshold-probe.py. Blocked on #428 (theWR_t → NW_{t+1}DAG decision). Uses themechanism_at_precapability from #423. Sibling follow-ups from the same pair of reviews: #421 (letter-sound → word-reading models, includingRW → NWandSP → NWmechanisms this would sit beside), #404, #429, #430. Descriptive antecedent:notes/202607241600-findings-word-reading-bands.md.