%22%22%22Results%20notebook%20for%20the%20MSSP%20early-renewal%20study%20(marimo).%0A%0AReporting%20only%3A%20it%20reads%20results%2F*.json%20through%20dashboard_data.build()%20and%20recomputes%20nothing%2C%20so%20it%20is%20outside%20the%0Apaths%20DEVIATIONS.md%20covers.%20Charts%20are%20matplotlib%20images%2C%20so%20the%20.ipynb%20and%20PDF%20exports%20need%20no%20JavaScript.%0A%0ARun%20and%20export%20from%20the%20repository%20root.%20None%20of%20these%20tools%20are%20in%20uv.lock%2C%20so%20their%20versions%20are%20pinned%20here%3B%0APlaywright%201.61.0%20is%20the%20version%20whose%20Chromium%20the%20PDF%20export%20uses%3A%0A%0A%20%20%20%20uv%20run%20--with%20marimo%3D%3D0.25.2%20--with%20matplotlib%3D%3D3.11.2%20--with%20nbformat%3D%3D5.11.1%20%5C%0A%20%20%20%20%20%20%20%20--with%20'nbconvert%5Bwebpdf%5D%3D%3D7.17.2'%20--with%20playwright%3D%3D1.61.0%20%5C%0A%20%20%20%20%20%20%20%20marimo%20export%20html%20analysis%2Fmssp-benchmark-ratchet%2Freport%2Fresults_notebook.py%20-o%20results.html%0A%0AFor%20the%20other%20two%20exports%2C%20replace%20%60html%60%20with%20%60ipynb%20--include-outputs%60%20(outputs%20are%20off%20by%20default)%20or%20%60pdf%60.%0A%22%22%22%0A%0A%23%20A%20marimo%20cell%20shows%20its%20last%20expression%2C%20so%20a%20bare%20%60_fig%60%20at%20the%20end%20of%20a%20cell%20is%20its%20output.%0A%23%20ruff%3A%20noqa%3A%20B018%0A%0Aimport%20marimo%0A%0A__generated_with%20%3D%20%220.25.2%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22%2C%20app_title%3D%22MSSP%20early%20renewal%3A%20results%22)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%20Why%20did%20Medicare%20ACOs%20reset%20their%20benchmarks%20early%3F%20Results%0A%0A%20%20%20%20This%20notebook%20reports%20the%20results%20of%20the%20pre-registered%20study%0A%20%20%20%20(%5BOSF%20registration%20c53w9%5D(https%3A%2F%2Fosf.io%2Fc53w9%2F)%2C%20DOI%2010.17605%2FOSF.IO%2FC53W9%3B%20plan%20and%20code%20at%20commit%20%60a4064f5%60).%0A%20%20%20%20It%20only%20reads%20the%20pipeline's%20results%20files%20in%20%60analysis%2Fmssp-benchmark-ratchet%2Fresults%2F%60%20and%20recomputes%20nothing.%0A%20%20%20%20The%20blog%20post%20is%20the%20authoritative%20report%3B%20the%20verdicts%20below%20use%20the%20same%20wording%20as%20its%20dashboard.%0A%0A%20%20%20%20Units%3A%20%22pp%22%20is%20percentage%20points.%20Benchmark%20components%20are%20in%20percentage%20points%20of%20the%20ACO's%20benchmark.%0A%20%20%20%20Intervals%20are%2095%25%20equal-tailed%20intervals%3B%20p-values%20are%20two-sided.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20hashlib%0A%20%20%20%20import%20json%0A%20%20%20%20import%20sys%0A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20sys.path.insert(0%2C%20str(mo.notebook_dir()))%0A%20%20%20%20import%20dashboard_data%0A%0A%20%20%20%20return%20dashboard_data%2C%20hashlib%2C%20json%2C%20mo%2C%20plt%0A%0A%0A%40app.cell%0Adef%20_(dashboard_data)%3A%0A%20%20%20%20results_dir%20%3D%20dashboard_data.DEFAULT_RESULTS%0A%20%20%20%20data%20%3D%20dashboard_data.build(results_dir)%0A%20%20%20%20raw%20%3D%20dashboard_data.load(results_dir)%0A%20%20%20%20return%20data%2C%20raw%2C%20results_dir%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20colors%20%3D%20%7B%22ink%22%3A%20%22%231f2933%22%2C%20%22muted%22%3A%20%22%235f6b7a%22%2C%20%22grid%22%3A%20%22%23d9dee5%22%2C%20%22mark%22%3A%20%22%232b5c9e%22%7D%0A%0A%20%20%20%20def%20num(x%2C%20digits%3D1)%3A%0A%20%20%20%20%20%20%20%20if%20x%20is%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%22%22%0A%20%20%20%20%20%20%20%20text%20%3D%20f%22%7Bx%3A.%7Bdigits%7Df%7D%22%0A%20%20%20%20%20%20%20%20return%20text.lstrip(%22-%22)%20if%20float(text)%20%3D%3D%200%20else%20text.replace(%22-%22%2C%20%22%5Cu2212%22)%0A%0A%20%20%20%20def%20pval(p)%3A%0A%20%20%20%20%20%20%20%20return%20%22%22%20if%20p%20is%20None%20else%20%22%3C%200.001%22%20if%20p%20%3C%200.001%20else%20f%22%7Bp%3A.3f%7D%22%0A%0A%20%20%20%20def%20interval(r%2C%20digits%3D1)%3A%0A%20%20%20%20%20%20%20%20return%20%22%22%20if%20r.get(%22lo%22)%20is%20None%20else%20f%22%7Bnum(r%5B'lo'%5D%2C%20digits)%7D%20to%20%7Bnum(r%5B'hi'%5D%2C%20digits)%7D%22%0A%0A%20%20%20%20def%20table(header%2C%20rows)%3A%0A%20%20%20%20%20%20%20%20lines%20%3D%20%5B%22%7C%20%22%20%2B%20%22%20%7C%20%22.join(header)%20%2B%20%22%20%7C%22%2C%20%22%7C%22%20%2B%20%22---%7C%22%20*%20len(header)%5D%0A%20%20%20%20%20%20%20%20lines%20%2B%3D%20%5B%22%7C%20%22%20%2B%20%22%20%7C%20%22.join(str(c)%20for%20c%20in%20row)%20%2B%20%22%20%7C%22%20for%20row%20in%20rows%5D%0A%20%20%20%20%20%20%20%20return%20%22%5Cn%22.join(lines)%0A%0A%20%20%20%20return%20colors%2C%20interval%2C%20num%2C%20pval%2C%20table%0A%0A%0A%40app.cell%0Adef%20_(colors%2C%20plt)%3A%0A%20%20%20%20def%20forest(ax%2C%20rows%2C%20xlabel%2C%20band%3DNone)%3A%0A%20%20%20%20%20%20%20%20%22%22%22One%20interval%20per%20row%2C%20top%20to%20bottom%2C%20with%20a%20zero%20line%3B%20band%20shades%20a%20prior's%2095%25%20range.%22%22%22%0A%20%20%20%20%20%20%20%20ys%20%3D%20list(range(len(rows)))%5B%3A%3A-1%5D%0A%20%20%20%20%20%20%20%20if%20band%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.axvspan(-band%2C%20band%2C%20color%3Dcolors%5B%22grid%22%5D%2C%20alpha%3D0.5%2C%20lw%3D0)%0A%20%20%20%20%20%20%20%20ax.axvline(0%2C%20color%3Dcolors%5B%22muted%22%5D%2C%20lw%3D1)%0A%20%20%20%20%20%20%20%20for%20y%2C%20r%20in%20zip(ys%2C%20rows%2C%20strict%3DTrue)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20r.get(%22lo%22)%20is%20not%20None%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ax.plot(%5Br%5B%22lo%22%5D%2C%20r%5B%22hi%22%5D%5D%2C%20%5By%2C%20y%5D%2C%20color%3Dcolors%5B%22mark%22%5D%2C%20lw%3D2%2C%20solid_capstyle%3D%22round%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.plot(r%5B%22mean%22%5D%2C%20y%2C%20%22o%22%2C%20color%3Dcolors%5B%22mark%22%5D%2C%20ms%3D6%2C%20mec%3D%22white%22%2C%20mew%3D1.5)%0A%20%20%20%20%20%20%20%20ax.set_yticks(ys%2C%20%5Br%5B%22label%22%5D%20for%20r%20in%20rows%5D%2C%20color%3Dcolors%5B%22ink%22%5D)%0A%20%20%20%20%20%20%20%20ax.set_xlabel(xlabel%2C%20color%3Dcolors%5B%22ink%22%5D)%0A%20%20%20%20%20%20%20%20ax.tick_params(colors%3Dcolors%5B%22muted%22%5D%2C%20length%3D0)%0A%20%20%20%20%20%20%20%20ax.grid(axis%3D%22x%22%2C%20color%3Dcolors%5B%22grid%22%5D%2C%20lw%3D0.8)%0A%20%20%20%20%20%20%20%20ax.set_axisbelow(True)%0A%20%20%20%20%20%20%20%20for%20side%20in%20(%22top%22%2C%20%22right%22%2C%20%22left%22)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.spines%5Bside%5D.set_visible(False)%0A%20%20%20%20%20%20%20%20ax.spines%5B%22bottom%22%5D.set_color(colors%5B%22grid%22%5D)%0A%20%20%20%20%20%20%20%20ax.set_ylim(-0.6%2C%20len(rows)%20-%200.4)%0A%0A%20%20%20%20def%20figure(n_rows%2C%20height_per_row%3D0.45)%3A%0A%20%20%20%20%20%20%20%20fig%2C%20ax%20%3D%20plt.subplots(figsize%3D(7.5%2C%200.8%20%2B%20height_per_row%20*%20n_rows)%2C%20layout%3D%22constrained%22)%0A%20%20%20%20%20%20%20%20return%20fig%2C%20ax%0A%0A%20%20%20%20return%20figure%2C%20forest%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20hashlib%2C%20mo%2C%20raw%2C%20results_dir%2C%20table)%3A%0A%20%20%20%20_rows%20%3D%20%5B%5D%0A%20%20%20%20for%20_stage%20in%20data%5B%22stages%22%5D%3A%0A%20%20%20%20%20%20%20%20_path%20%3D%20results_dir%20%2F%20f%22%7B_stage%5B'name'%5D%7D.json%22%0A%20%20%20%20%20%20%20%20_rows.append(%5B_stage%5B%22name%22%5D%2C%20f%22%60%7Braw%5B_stage%5B'name'%5D%5D%5B'git_commit'%5D%5B%3A7%5D%7D%60%22%2C%20f%22%60%7Bhashlib.sha256(_path.read_bytes()).hexdigest()%5B%3A16%5D%7D%60%22%5D)%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%5Cn%5Cn%22.join(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%23%23%20Provenance%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Results%20are%20%7B'**synthetic**'%20if%20data%5B'synthetic'%5D%20else%20'from%20the%20real%20CMS%20data'%7D.%20Each%20stage%20records%20the%20commit%20it%20ran%20at%3B%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22all%20of%20them%20contain%20the%20registered%20code%20unchanged%20(see%20%60DEVIATIONS.md%60).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20table(%5B%22Stage%22%2C%20%22Commit%22%2C%20%22sha256%20of%20results%20file%20(first%2016)%22%5D%2C%20_rows)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(dashboard_data%2C%20data%2C%20json%2C%20mo)%3A%0A%20%20%20%20%23%20The%20site's%20dashboard%20is%20built%20from%20the%20same%20function%3B%20confirm%20the%20committed%20copy%20matches%20these%20results.%0A%20%20%20%20_committed%20%3D%20json.loads((dashboard_data.DEFAULT_OUT).read_text())%0A%20%20%20%20_same%20%3D%20%7Bk%3A%20v%20for%20k%2C%20v%20in%20_committed.items()%20if%20k%20!%3D%20%22built%22%7D%20%3D%3D%20%7Bk%3A%20v%20for%20k%2C%20v%20in%20data.items()%20if%20k%20!%3D%20%22built%22%7D%0A%20%20%20%20mo.md(f%22The%20post's%20dashboard%20data%20(%60data.json%60)%20%7B'matches'%20if%20_same%20else%20'**does%20not%20match**'%7D%20these%20results.%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20mo%2C%20num)%3A%0A%20%20%20%20_v%20%3D%20data%5B%22validation%22%5D%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20f%22%22%22%0A%20%20%20%20%20%20%20%20%23%23%20Validation%20of%20the%20benchmark%20approximation%0A%0A%20%20%20%20%20%20%20%20Passed%3A%20**%7B%22yes%22%20if%20_v%5B%22passed%22%5D%20else%20%22no%22%7D**.%20Calibration%20applied%3A%20%7B%22yes%22%20if%20_v%5B%22calibrated%22%5D%20else%20%22no%22%7D.%0A%20%20%20%20%20%20%20%20Measurement-error%20SD%20used%20in%20the%20decision%20model%20(pp%20of%20benchmark)%3A%20%7Bnum(_v%5B%22sigma_v_model%22%5D%2C%202)%7D.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20interval%2C%20mo%2C%20num%2C%20pval%2C%20table)%3A%0A%20%20%20%20_c%20%3D%20data%5B%22comparisons%22%5D%5B%22rows%22%5D%0A%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22label%22%5D%2C%20r%5B%22role%22%5D%2C%20f%22%7Br%5B'n_early'%5D%7D%20%2F%20%7Br%5B'n_stayer'%5D%7D%22%2C%20num(r%5B%22mean%22%5D)%2C%20interval(r)%2C%20pval(r%5B%22p%22%5D)%2C%20num(r%5B%22mde%22%5D)%2C%20r%5B%22verdict%22%5D%20or%20%22%22%5D%20for%20r%20in%20_c%5D%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%5Cn%5Cn%22.join(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%23%23%20Who%20renewed%20early%20(H2b%2C%20H2a%2C%20H1)%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Early%20renewers%20minus%20stayers%20(Bayesian%20bootstrap%3B%20p-values%20from%20stratified%20permutation).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20table(%5B%22Comparison%22%2C%20%22Role%22%2C%20%22n%20early%20%2F%20stayers%22%2C%20%22Difference%22%2C%20%2295%25%20interval%22%2C%20%22p%22%2C%20%22MDE%22%2C%20%22Verdict%22%5D%2C%20_rows)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data%2C%20figure%2C%20forest)%3A%0A%20%20%20%20_c%20%3D%20%7Br%5B%22key%22%5D%3A%20r%20for%20r%20in%20data%5B%22comparisons%22%5D%5B%22rows%22%5D%7D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20figure(4)%0A%20%20%20%20forest(_ax%2C%20%5B_c%5Bk%5D%20for%20k%20in%20(%22H2b_pull%22%2C%20%22H2a_own%22%2C%20%22regional_comp%22%2C%20%22gain%22)%5D%2C%20%22Early%20renewers%20minus%20stayers%2C%20pp%20of%20benchmark%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data%2C%20figure%2C%20forest)%3A%0A%20%20%20%20_c%20%3D%20%7Br%5B%22key%22%5D%3A%20r%20for%20r%20in%20data%5B%22comparisons%22%5D%5B%22rows%22%5D%7D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20figure(2)%0A%20%20%20%20forest(_ax%2C%20%5B_c%5Bk%5D%20for%20k%20in%20(%22H1_sav_rate_2020%22%2C%20%22H1_sav_rate_2021%22)%5D%2C%20%22Early%20renewers%20minus%20stayers%2C%20savings%20rate%20(pp)%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20mo%2C%20num%2C%20pval%2C%20table)%3A%0A%20%20%20%20_h3%20%3D%20data%5B%22h3%22%5D%0A%20%20%20%20_rows%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20r%5B%22label%22%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20r%5B%22predicted%22%5D%20or%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20num(r%5B%22mean%22%5D%2C%202)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20f%22%7Bnum(r%5B'lo'%5D%2C%202)%7D%20to%20%7Bnum(r%5B'hi'%5D%2C%202)%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20num(r%5B%22p_positive%22%5D%2C%203)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20pval(r%5B%22test%22%5D%5B%22p%22%5D)%20if%20r%5B%22test%22%5D%20else%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20r%5B%22test%22%5D%5B%22decision%22%5D%20if%20r%5B%22test%22%5D%20else%20%22%22%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20for%20r%20in%20_h3%5B%22posterior%22%5D%5B%22normal%22%5D%0A%20%20%20%20%5D%0A%20%20%20%20_o%20%3D%20_h3%5B%22overall_test%22%5D%0A%20%20%20%20_s%20%3D%20_h3%5B%22sample%22%5D%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%5Cn%5Cn%22.join(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%23%23%20H3%3A%20the%20decision%20model%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Bayesian%20logistic%20regression%20of%20early%20renewal%2C%20with%20measurement%20error%20on%20the%20own-spending%20component%3B%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%7B_s%5B'n'%5D%7D%20ACOs%2C%20%7B_s%5B'early'%5D%7D%20early%20renewers%20(%7B_s%5B'excluded'%5D%5B'early'%5D%7D%20early%20renewers%20and%20%7B_s%5B'excluded'%5D%5B'stayer'%5D%7D%20stayers%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22excluded%20for%20a%20missing%20predictor).%20Converged%3A%20%7B'yes'%20if%20_h3%5B'converged'%5D%20else%20'no'%7D.%20Coefficients%20are%20log-odds%20per%202%20SD%20of%20a%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22continuous%20predictor%3B%20tests%20are%20by%20direct%20simulation%20under%20the%20reduced%20model.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20table(%5B%22Coefficient%22%2C%20%22Predicted%22%2C%20%22Posterior%20mean%22%2C%20%2295%25%20interval%22%2C%20%22P(%3E%200)%22%2C%20%22p%22%2C%20%22Decision%22%5D%2C%20_rows)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Overall%20test%20(%7B_o%5B'statistic'%5D%7D)%3A%20observed%20%7Bnum(_o%5B'observed'%5D%2C%202)%7D%2C%20p%20%3D%20%7Bpval(_o%5B'p_value'%5D)%7D%20(%7B_o%5B'n_shuffles'%5D%3A%2C%7D%20shuffles).%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Power%20to%20detect%20the%20planned%20effects%3A%20%7B_h3%5B'power_note'%5D%7D.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data%2C%20figure%2C%20forest)%3A%0A%20%20%20%20_rows%20%3D%20data%5B%22h3%22%5D%5B%22posterior%22%5D%5B%22normal%22%5D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20figure(len(_rows))%0A%20%20%20%20forest(_ax%2C%20_rows%2C%20%22Posterior%20coefficient%2C%20log-odds%20(shaded%3A%20the%20Normal(0%2C%201)%20prior's%2095%25%20range)%22%2C%20band%3Ddata%5B%22h3%22%5D%5B%22prior_band%22%5D%5B%22normal%22%5D)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20interval%2C%20mo%2C%20num%2C%20pval%2C%20table)%3A%0A%20%20%20%20_h4%20%3D%20data%5B%22h4%22%5D%0A%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22label%22%5D%2C%20r%5B%22role%22%5D%2C%20num(r%5B%22mean%22%5D)%2C%20interval(r)%2C%20pval(r%5B%22p%22%5D)%5D%20for%20r%20in%20_h4%5B%22estimates%22%5D%5D%0A%20%20%20%20_pre%2C%20_eq%20%3D%20_h4%5B%22pre_trend%22%5D%2C%20_h4%5B%22equivalence%22%5D%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%5Cn%5Cn%22.join(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%23%23%20H4%3A%20spending%20after%20renewal%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Difference-in-differences%20in%20per-capita%20spending%2C%20in%20percent%3B%20%7B_h4%5B'sample'%5D%5B'early'%5D%7D%20early%20renewers%20and%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%7B_h4%5B'sample'%5D%5B'comparison'%5D%7D%20comparison%20ACOs.%20Verdict%3A%20**%7B_h4%5B'verdict'%5D%7D**%20(MDE%20%7Bnum(_h4%5B'mde_percent'%5D)%7D%25).%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20table(%5B%22Estimate%22%2C%20%22Role%22%2C%20%22Percent%22%2C%20%2295%25%20interval%22%2C%20%22p%22%5D%2C%20_rows)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Pre-trend%20slope%20difference%3A%20%7Bnum(_pre%5B'mean'%5D%2C%203)%7D%20(%7Bnum(_pre%5B'lo'%5D%2C%203)%7D%20to%20%7Bnum(_pre%5B'hi'%5D%2C%203)%7D)%2C%20p%20%3D%20%7Bpval(_pre%5B'p'%5D)%7D.%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22Equivalence%20condition%3A%20the%20pre-trend%20bound%20scaled%20to%20the%20post%20period%20is%20%7Bnum(_eq%5B'scaled_bound'%5D%2C%203)%7D%20against%20%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20f%22%7CH4%7C%20%3D%20%7Bnum(_eq%5B'abs_h4'%5D%2C%203)%7D%2C%20so%20it%20%7B'holds'%20if%20_eq%5B'holds'%5D%20else%20'does%20not%20hold'%7D.%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(data%2C%20figure%2C%20forest)%3A%0A%20%20%20%20_rows%20%3D%20data%5B%22h4%22%5D%5B%22estimates%22%5D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20figure(len(_rows))%0A%20%20%20%20forest(_ax%2C%20_rows%2C%20%22Early%20renewers%20minus%20comparison%3A%20change%20in%20per-capita%20spending%20growth%20(%25)%22)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(colors%2C%20data%2C%20plt)%3A%0A%20%20%20%20_pts%20%3D%20data%5B%22h4%22%5D%5B%22event_study%22%5D%0A%20%20%20%20_fig%2C%20_ax%20%3D%20plt.subplots(figsize%3D(7.5%2C%203.2)%2C%20layout%3D%22constrained%22)%0A%20%20%20%20_ax.axhline(0%2C%20color%3Dcolors%5B%22muted%22%5D%2C%20lw%3D1)%0A%20%20%20%20for%20_p%20in%20_pts%3A%0A%20%20%20%20%20%20%20%20if%20not%20_p%5B%22reference%22%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20_ax.plot(%5B_p%5B%22year%22%5D%2C%20_p%5B%22year%22%5D%5D%2C%20%5B_p%5B%22lo%22%5D%2C%20_p%5B%22hi%22%5D%5D%2C%20color%3Dcolors%5B%22mark%22%5D%2C%20lw%3D2%2C%20solid_capstyle%3D%22round%22)%0A%20%20%20%20%20%20%20%20_ax.plot(_p%5B%22year%22%5D%2C%20_p%5B%22mean%22%5D%2C%20%22o%22%2C%20color%3Dcolors%5B%22muted%22%5D%20if%20_p%5B%22reference%22%5D%20else%20colors%5B%22mark%22%5D%2C%20ms%3D6%2C%20mec%3D%22white%22%2C%20mew%3D1.5)%0A%20%20%20%20_ax.set_xticks(%5Bp%5B%22year%22%5D%20for%20p%20in%20_pts%5D)%0A%20%20%20%20_ax.margins(x%3D0.05%2C%20y%3D0.1)%0A%20%20%20%20_ax.set_ylabel(%22Percent%2C%20relative%20to%202021%22%2C%20color%3Dcolors%5B%22ink%22%5D)%0A%20%20%20%20_ax.set_title(%22Two-way%20fixed%20effects%20event%20study%20(2021%20is%20the%20reference%20year)%22%2C%20color%3Dcolors%5B%22ink%22%5D%2C%20fontsize%3D10%2C%20loc%3D%22left%22)%0A%20%20%20%20_ax.tick_params(colors%3Dcolors%5B%22muted%22%5D%2C%20length%3D0)%0A%20%20%20%20_ax.grid(axis%3D%22y%22%2C%20color%3Dcolors%5B%22grid%22%5D%2C%20lw%3D0.8)%0A%20%20%20%20_ax.set_axisbelow(True)%0A%20%20%20%20for%20_side%20in%20(%22top%22%2C%20%22right%22%2C%20%22left%22)%3A%0A%20%20%20%20%20%20%20%20_ax.spines%5B_side%5D.set_visible(False)%0A%20%20%20%20_ax.spines%5B%22bottom%22%5D.set_color(colors%5B%22grid%22%5D)%0A%20%20%20%20_fig%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20mo%2C%20table)%3A%0A%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22claim%22%5D%2C%20r%5B%22confirmatory%22%5D%2C%20r%5B%22conventional%22%5D%2C%20%22yes%22%20if%20r%5B%22agree%22%5D%20else%20%22**no**%22%5D%20for%20r%20in%20data%5B%22agreement%22%5D%5D%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%23%23%20Registered%20and%20conventional%20methods%5Cn%5Cn%22%0A%20%20%20%20%20%20%20%20%2B%20table(%5B%22Claim%22%2C%20%22Registered%20method%22%2C%20%22Conventional%20method%22%2C%20%22Agree%22%5D%2C%20_rows)%0A%20%20%20%20%20%20%20%20%2B%20%22%5Cn%5CnThe%20plan's%20agreement%20table%20(section%205.7)%20calls%20H4%20undetermined%20unless%20p%20%3C%200.05%20in%20a%20direction%3B%20%22%0A%20%20%20%20%20%20%20%20'that%20is%20the%20same%20verdict%20as%20%22no%20detectable%20difference%22%20in%20the%20H4%20section%20(section%207%2C%20rule%205).'%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20interval%2C%20mo%2C%20num%2C%20pval%2C%20table)%3A%0A%20%20%20%20_rob%20%3D%20data%5B%22robustness%22%5D%0A%20%20%20%20_parts%20%3D%20%5B%5D%0A%20%20%20%20for%20_g%20in%20_rob%5B%22groups%22%5D%20%2B%20_rob%5B%22h3%22%5D%3A%0A%20%20%20%20%20%20%20%20_digits%20%3D%202%20if%20_g%5B%22unit%22%5D%20%3D%3D%20%22log-odds%22%20else%201%0A%20%20%20%20%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22label%22%5D%2C%20num(r%5B%22mean%22%5D%2C%20_digits)%2C%20interval(r%2C%20_digits)%2C%20pval(r%5B%22p%22%5D)%2C%20%22%22%20if%20r.get(%22converged%22%2C%20True)%20else%20%22not%20converged%22%5D%20for%20r%20in%20_g%5B%22rows%22%5D%5D%0A%20%20%20%20%20%20%20%20_parts.append(f%22**%7B_g%5B'label'%5D%7D**%20(%7B_g%5B'unit'%5D%7D)%5Cn%5Cn%22%20%2B%20table(%5B%22Analysis%22%2C%20%22Estimate%22%2C%20%2295%25%20interval%22%2C%20%22p%22%2C%20%22%22%5D%2C%20_rows))%0A%20%20%20%20mo.md(%0A%20%20%20%20%20%20%20%20%22%23%23%20Robustness%5Cn%5CnThe%20plan's%20section%205.5%20items%20that%20rerun%20each%20confirmatory%20estimate.%20They%20do%20not%20change%20the%20%22%0A%20%20%20%20%20%20%20%20%22decisions.%20H3%20rows%20are%20the%20coefficient%20in%20each%20refit.%5Cn%5Cn%22%20%2B%20%22%5Cn%5Cn%22.join(_parts)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(data%2C%20interval%2C%20mo%2C%20num%2C%20pval%2C%20table)%3A%0A%20%20%20%20_exp%20%3D%20data%5B%22exploratory%22%5D%0A%20%20%20%20_parts%20%3D%20%5B%5D%0A%20%20%20%20for%20_g%20in%20_exp%5B%22alternative_exposures%22%5D%3A%0A%20%20%20%20%20%20%20%20_digits%20%3D%202%20if%20_g%5B%22unit%22%5D%20%3D%3D%20%22log-odds%22%20else%201%0A%20%20%20%20%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22label%22%5D%2C%20num(r%5B%22mean%22%5D%2C%20_digits)%2C%20interval(r%2C%20_digits)%2C%20pval(r%5B%22p%22%5D)%5D%20for%20r%20in%20_g%5B%22rows%22%5D%5D%0A%20%20%20%20%20%20%20%20_parts.append(f%22**%7B_g%5B'label'%5D%7D**%20(%7B_g%5B'unit'%5D%7D)%5Cn%5Cn%22%20%2B%20table(%5B%22Measure%22%2C%20%22Estimate%22%2C%20%2295%25%20interval%22%2C%20%22p%22%5D%2C%20_rows))%0A%20%20%20%20if%20_exp%5B%22region%22%5D%3A%0A%20%20%20%20%20%20%20%20_rows%20%3D%20%5B%5Br%5B%22label%22%5D%2C%20num(r%5B%22mean%22%5D%2C%202)%2C%20interval(r%2C%202)%5D%20for%20r%20in%20_exp%5B%22region%22%5D%5B%22rows%22%5D%5D%0A%20%20%20%20%20%20%20%20_parts.append(%22**Census%20region%20in%20the%20H3%20model**%20(log-odds)%5Cn%5Cn%22%20%2B%20table(%5B%22Region%22%2C%20%22Posterior%20mean%22%2C%20%2295%25%20interval%22%5D%2C%20_rows))%0A%20%20%20%20_groups%20%3D%20_exp%5B%22groups%22%5D%0A%20%20%20%20_rows%20%3D%20%5B%5Blabel%5D%20%2B%20%5Bf%22%7Bnum(_groups%5Bg%5D%5Bv%5D%5B'mean'%5D)%7D%20(n%20%3D%20%7B_groups%5Bg%5D%5Bv%5D%5B'n'%5D%7D)%22%20for%20g%20in%20_groups%5D%20for%20v%2C%20label%20in%20_exp%5B%22described%22%5D.items()%5D%0A%20%20%20%20_names%20%3D%20%7B%22early%22%3A%20%22Early%20renewers%22%2C%20%22leaver%22%3A%20%22Leavers%22%2C%20%22stayer%22%3A%20%22Stayers%22%7D%0A%20%20%20%20_parts.append(%22**Means%20by%20group**%5Cn%5Cn%22%20%2B%20table(%5B%22Variable%22%5D%20%2B%20%5B_names.get(g%2C%20g)%20for%20g%20in%20_groups%5D%2C%20_rows))%0A%20%20%20%20mo.md(%22%23%23%20Exploratory%5Cn%5CnLabeled%20exploratory%20in%20the%20plan%20(section%205.6)%3A%20no%20verdicts.%5Cn%5Cn%22%20%2B%20%22%5Cn%5Cn%22.join(_parts))%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
2ba49578729b4c58558724dffe9a2ffa