import%20marimo%0A%0A__generated_with%20%3D%20%220.25.0%22%0Aapp%20%3D%20marimo.App(width%3D%22medium%22)%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20pandas%20as%20pd%0A%0A%20%20%20%20from%20increment%20import%20(%0A%20%20%20%20%20%20%20%20Analysis%2C%0A%20%20%20%20%20%20%20%20AnalysisPlan%2C%0A%20%20%20%20%20%20%20%20InferenceSpec%2C%0A%20%20%20%20%20%20%20%20JointReveal%2C%0A%20%20%20%20%20%20%20%20MetricSpec%2C%0A%20%20%20%20%20%20%20%20PredictivePrior%2C%0A%20%20%20%20%20%20%20%20SequentialCell%2C%0A%20%20%20%20%20%20%20%20SequentialCompliancePolicy%2C%0A%20%20%20%20%20%20%20%20SequentialModel%2C%0A%20%20%20%20%20%20%20%20SequentialRegistration%2C%0A%20%20%20%20)%0A%20%20%20%20from%20increment.frame%20import%20synthesise_metric%0A%20%20%20%20from%20increment.semantics.design%20import%20Encouragement%2C%20ExclusionRestriction%2C%20UptakeSpec%0A%20%20%20%20from%20increment.sequential_source%20import%20frame_observation_mapping%2C%20sequential_definition_id%0A%20%20%20%20from%20increment.simulate.dgp%20import%20Scenario%2C%20simulate_raw_logs%0A%0A%20%20%20%20return%20(%0A%20%20%20%20%20%20%20%20Analysis%2C%0A%20%20%20%20%20%20%20%20AnalysisPlan%2C%0A%20%20%20%20%20%20%20%20Encouragement%2C%0A%20%20%20%20%20%20%20%20ExclusionRestriction%2C%0A%20%20%20%20%20%20%20%20InferenceSpec%2C%0A%20%20%20%20%20%20%20%20JointReveal%2C%0A%20%20%20%20%20%20%20%20MetricSpec%2C%0A%20%20%20%20%20%20%20%20PredictivePrior%2C%0A%20%20%20%20%20%20%20%20Scenario%2C%0A%20%20%20%20%20%20%20%20SequentialCell%2C%0A%20%20%20%20%20%20%20%20SequentialCompliancePolicy%2C%0A%20%20%20%20%20%20%20%20SequentialModel%2C%0A%20%20%20%20%20%20%20%20SequentialRegistration%2C%0A%20%20%20%20%20%20%20%20UptakeSpec%2C%0A%20%20%20%20%20%20%20%20frame_observation_mapping%2C%0A%20%20%20%20%20%20%20%20mo%2C%0A%20%20%20%20%20%20%20%20np%2C%0A%20%20%20%20%20%20%20%20pd%2C%0A%20%20%20%20%20%20%20%20sequential_definition_id%2C%0A%20%20%20%20%20%20%20%20simulate_raw_logs%2C%0A%20%20%20%20%20%20%20%20synthesise_metric%2C%0A%20%20%20%20)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%20LATE%20over%20time%0A%0A%20%20%20%20A%20re-engagement%20prompt%20is%20randomized%20once%2C%20but%20real-world%20enrollment%0A%20%20%20%20staggers%20exposure%20over%20the%20following%2020%20days%20--%20each%20unit%20sees%20the%0A%20%20%20%20prompt%20on%20its%20own%20day.%20From%20there%2C%20people%20click%20it%20--%20and%20their%0A%20%20%20%20revenue%20outcome%20resolves%20--%20on%20different%20days%20over%20the%20following%20two%0A%20%20%20%20weeks%2C%20measured%20relative%20to%20each%20unit's%20own%20exposure.%20This%20notebook%0A%20%20%20%20watches%20the%20LATE%20(the%20effect%20of%20clicking%2C%20for%20compliers)%20mature%20as%0A%20%20%20%20that%20window%20fills%20in%2C%20and%20shows%20why%20the%20per-day%20view%20Increment%20offers%0A%20%20%20%20everywhere%20else%20is%20refused%20for%20an%20encouragement%20design.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Simulate%20a%20staggered%20encouragement%20panel%0A%0A%20%20%20%20%60increment.simulate.dgp.simulate_raw_logs%60%20draws%20a%20raw%20event%20log%3A%20one%0A%20%20%20%20%60exposure%60%20row%20per%20unit%2C%20plus%20%60uptake%60%2F%60outcome%60%20rows%20at%20a%20random%20day%0A%20%20%20%20offset%20in%20%60%5B0%2C%20n_days)%60%20for%20each%20unit.%20%60W%60%20bounds%20both%20the%20outcome%0A%20%20%20%20window%20and%20the%20uptake%20window%2C%20so%20every%20simulated%20event%20lands%20strictly%0A%20%20%20%20inside%20the%20window%20the%20analysis%20later%20gates%20on.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Scenario%2C%20simulate_raw_logs)%3A%0A%20%20%20%20W%20%3D%2010%20%20%23%20outcome%2Fuptake%20window%2C%20in%20days%20since%20each%20unit's%20own%20exposure%0A%20%20%20%20scenario%20%3D%20Scenario(%0A%20%20%20%20%20%20%20%20n_units%3D900%2C%0A%20%20%20%20%20%20%20%20n_days%3DW%2C%0A%20%20%20%20%20%20%20%20true_lift%3D%7B%7D%2C%0A%20%20%20%20%20%20%20%20uptake_compliance_t%3D0.55%2C%0A%20%20%20%20%20%20%20%20uptake_compliance_c%3D0.10%2C%0A%20%20%20%20%20%20%20%20tau_complier%3D15.0%2C%0A%20%20%20%20%20%20%20%20seed%3D7%2C%0A%20%20%20%20)%0A%20%20%20%20raw%20%3D%20simulate_raw_logs(scenario).to_pandas()%0A%20%20%20%20return%20W%2C%20raw%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20pd%2C%20raw)%3A%0A%20%20%20%20start%20%3D%20pd.Timestamp(%222025-02-01%22).normalize()%0A%0A%20%20%20%20exposures%20%3D%20(%0A%20%20%20%20%20%20%20%20raw%5Braw%5B%22event%22%5D%20%3D%3D%20%22exposure%22%5D%5B%5B%22unit_id%22%2C%20%22group_id%22%5D%5D%0A%20%20%20%20%20%20%20%20.drop_duplicates()%0A%20%20%20%20%20%20%20%20.reset_index(drop%3DTrue)%0A%20%20%20%20)%0A%20%20%20%20%23%20Stagger%20real-world%20enrollment%20over%2020%20calendar%20days%2C%20independent%20of%20the%0A%20%20%20%20%23%20DGP's%20relative%20day-offsets%20(always%20measured%20from%20each%20unit's%20own%20exposure).%0A%20%20%20%20enroll_offsets%20%3D%20np.arange(len(exposures))%20%25%2020%0A%20%20%20%20exposures%5B%22exposed_on%22%5D%20%3D%20%5Bstart%20%2B%20pd.Timedelta(days%3Dint(o))%20for%20o%20in%20enroll_offsets%5D%0A%20%20%20%20return%20(exposures%2C)%0A%0A%0A%40app.cell%0Adef%20_(exposures%2C%20pd%2C%20raw)%3A%0A%20%20%20%20outcome%20%3D%20raw%5Braw%5B%22event%22%5D%20%3D%3D%20%22outcome%22%5D%5B%5B%22unit_id%22%2C%20%22ts%22%2C%20%22value%22%5D%5D.rename(%0A%20%20%20%20%20%20%20%20columns%3D%7B%22value%22%3A%20%22revenue%22%7D%0A%20%20%20%20)%0A%20%20%20%20outcome%5B%22rel_day%22%5D%20%3D%20(outcome%5B%22ts%22%5D%20-%20pd.Timestamp(%222025-01-01%22)).dt.days%0A%20%20%20%20uptake%20%3D%20raw%5Braw%5B%22event%22%5D%20%3D%3D%20%22uptake%22%5D%5B%5B%22unit_id%22%2C%20%22ts%22%5D%5D%0A%20%20%20%20uptake%5B%22rel_day%22%5D%20%3D%20(uptake%5B%22ts%22%5D%20-%20pd.Timestamp(%222025-01-01%22)).dt.days%0A%20%20%20%20uptake%20%3D%20uptake%5B%5B%22unit_id%22%2C%20%22rel_day%22%5D%5D.assign(clicked%3D1.0)%0A%0A%20%20%20%20outcome_rows%20%3D%20exposures.merge(%0A%20%20%20%20%20%20%20%20outcome%5B%5B%22unit_id%22%2C%20%22rel_day%22%2C%20%22revenue%22%5D%5D%2C%20on%3D%22unit_id%22%2C%20how%3D%22left%22%0A%20%20%20%20)%0A%20%20%20%20outcome_rows%5B%22ds%22%5D%20%3D%20(%0A%20%20%20%20%20%20%20%20outcome_rows%5B%22exposed_on%22%5D%20%2B%20pd.to_timedelta(outcome_rows%5B%22rel_day%22%5D%2C%20unit%3D%22D%22)%0A%20%20%20%20).dt.date%0A%20%20%20%20outcome_rows%5B%22clicked%22%5D%20%3D%200.0%0A%0A%20%20%20%20uptake_rows%20%3D%20exposures.merge(uptake%2C%20on%3D%22unit_id%22%2C%20how%3D%22inner%22)%0A%20%20%20%20uptake_rows%5B%22ds%22%5D%20%3D%20(%0A%20%20%20%20%20%20%20%20uptake_rows%5B%22exposed_on%22%5D%20%2B%20pd.to_timedelta(uptake_rows%5B%22rel_day%22%5D%2C%20unit%3D%22D%22)%0A%20%20%20%20).dt.date%0A%20%20%20%20uptake_rows%5B%22revenue%22%5D%20%3D%200.0%0A%20%20%20%20return%20outcome_rows%2C%20uptake_rows%0A%0A%0A%40app.cell%0Adef%20_(W%2C%20exposures%2C%20outcome_rows%2C%20pd%2C%20uptake_rows)%3A%0A%20%20%20%20completion_rows%20%3D%20exposures.assign(revenue%3D0.0%2C%20clicked%3D0.0)%0A%20%20%20%20completion_rows%5B%22ds%22%5D%20%3D%20(completion_rows%5B%22exposed_on%22%5D%20%2B%20pd.Timedelta(days%3DW)).dt.date%0A%0A%20%20%20%20cols%20%3D%20%5B%22unit_id%22%2C%20%22group_id%22%2C%20%22ds%22%2C%20%22exposed_on%22%2C%20%22revenue%22%2C%20%22clicked%22%5D%0A%20%20%20%20frames%20%3D%20%5B%5D%0A%20%20%20%20for%20source_frame%20in%20(outcome_rows%2C%20uptake_rows%2C%20completion_rows)%3A%0A%20%20%20%20%20%20%20%20source_frame%20%3D%20source_frame.copy()%0A%20%20%20%20%20%20%20%20source_frame%5B%22exposed_on%22%5D%20%3D%20source_frame%5B%22exposed_on%22%5D.dt.date%0A%20%20%20%20%20%20%20%20frames.append(source_frame%5Bcols%5D)%0A%20%20%20%20%23%20from_unit_panel%20expects%20at%20most%20one%20row%20per%20(unit%2C%20day)%3A%20a%20unit%20whose%0A%20%20%20%20%23%20outcome%20and%20uptake%20land%20on%20the%20same%20day%20merges%20here%20before%20it%20is%20seen.%0A%20%20%20%20panel%20%3D%20(%0A%20%20%20%20%20%20%20%20pd.concat(frames%2C%20ignore_index%3DTrue)%0A%20%20%20%20%20%20%20%20.groupby(%5B%22unit_id%22%2C%20%22group_id%22%2C%20%22ds%22%2C%20%22exposed_on%22%5D%2C%20as_index%3DFalse)%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%22revenue%22%2C%20%22clicked%22%5D%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%20%20%20.sum()%0A%20%20%20%20)%0A%20%20%20%20return%20completion_rows%2C%20panel%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Declare%20the%20encouragement%20design%20and%20build%20the%20analysis%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Encouragement%2C%20ExclusionRestriction%2C%20UptakeSpec%2C%20W)%3A%0A%20%20%20%20design%20%3D%20Encouragement(%0A%20%20%20%20%20%20%20%20control_group%3D%22control%22%2C%0A%20%20%20%20%20%20%20%20uptake%3DUptakeSpec(fact%3D%22clicked%22%2C%20window_days%3DW)%2C%0A%20%20%20%20%20%20%20%20exclusion_restriction%3DExclusionRestriction(%0A%20%20%20%20%20%20%20%20%20%20%20%20acknowledged%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20justification%3D%22the%20randomized%20prompt%20affects%20revenue%20only%20through%20the%20click.%22%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20one_sided%3DFalse%2C%0A%20%20%20%20)%0A%20%20%20%20return%20(design%2C)%0A%0A%0A%40app.cell%0Adef%20_(Analysis%2C%20MetricSpec%2C%20W%2C%20design%2C%20panel)%3A%0A%20%20%20%20metrics%20%3D%20%5BMetricSpec(name%3D%22revenue%22%2C%20type%3D%22mean%22%2C%20window_days%3DW)%5D%0A%20%20%20%20analysis%20%3D%20Analysis.from_unit_panel(%0A%20%20%20%20%20%20%20%20panel%2C%0A%20%20%20%20%20%20%20%20unit%3D%22unit_id%22%2C%0A%20%20%20%20%20%20%20%20group%3D%22group_id%22%2C%0A%20%20%20%20%20%20%20%20date%3D%22ds%22%2C%0A%20%20%20%20%20%20%20%20metrics%3Dmetrics%2C%0A%20%20%20%20%20%20%20%20design%3Ddesign%2C%0A%20%20%20%20%20%20%20%20exposure_date%3D%22exposed_on%22%2C%0A%20%20%20%20%20%20%20%20experiment_id%3D%22reengagement_email%22%2C%0A%20%20%20%20)%0A%20%20%20%20return%20analysis%2C%20metrics%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20%60run_daily_lift%60%20refuses%20under%20encouragement%0A%0A%20%20%20%20A%20single%20day's%20clicks%20are%20too%20small%20a%20first%20stage%20to%20divide%20by%3B%20the%0A%20%20%20%20per-day%20LATE%20it%20would%20imply%20is%20not%20statistically%20meaningful.%20Increment%0A%20%20%20%20refuses%20the%20call%20by%20name%20instead%20of%20returning%20a%20noisy%20number.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(analysis)%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20analysis.run_daily_lift()%0A%20%20%20%20%20%20%20%20daily_lift_message%20%3D%20%22no%20error%20raised%22%0A%20%20%20%20except%20ValueError%20as%20daily_lift_error%3A%0A%20%20%20%20%20%20%20%20daily_lift_message%20%3D%20str(daily_lift_error)%0A%20%20%20%20daily_lift_message%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20The%20as-of%20LATE%20trend%0A%0A%20%20%20%20%60run_asof_lift(completed_windows_only%3DTrue)%60%20admits%20each%20unit%20only%20once%0A%20%20%20%20both%20its%20outcome%20and%20uptake%20windows%20have%20closed%2C%20so%20every%20plotted%20date%0A%20%20%20%20reports%20the%20LATE%20over%20units%20mature%20enough%20to%20trust.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(analysis)%3A%0A%20%20%20%20def%20_late_trend(results)%3A%0A%20%20%20%20%20%20%20%20return%20%5Br%20for%20r%20in%20results%20if%20r.estimand%20%3D%3D%20%22late%22%20and%20r.value_scale%20%3D%3D%20%22relative%22%5D%0A%0A%20%20%20%20fixed_late_trend%20%3D%20_late_trend(analysis.run_asof_lift(completed_windows_only%3DTrue))%0A%20%20%20%20return%20(fixed_late_trend%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Monitoring%20relative%20uptake%20instead%3A%20an%20always-valid%20compliance%20trend%0A%0A%20%20%20%20LATE%20itself%20is%20a%20Wald%20ratio%20of%20two%20Gaussian-referenced%20ITTs%2C%20so%20it%20has%0A%20%20%20%20no%20registered%20exact%20likelihood%20to%20monitor%20against.%20Binary%20uptake%20does%3A%0A%20%20%20%20declaring%20a%20%60SequentialRegistration%60%20with%20a%20Bernoulli%2FBeta%20model%20for%0A%20%20%20%20the%20%60uptake%60%20observable%2C%20and%20reading%20%60estimand%3D%22compliance%22%60%20off%20the%0A%20%20%20%20resulting%20rows%2C%20gives%20a%20relative-uptake%20series%20that%20stays%20valid%20no%0A%20%20%20%20matter%20how%20many%20of%20these%20dates%20are%20actually%20inspected%20--%20a%20genuine%0A%20%20%20%20always-valid%20complement%20to%20the%20fixed-horizon%20LATE%20trend%20above%2C%20not%20a%0A%20%20%20%20sequential%20LATE%20itself.%20%60InferenceSpec(kind%3D%22always_valid%22%2C%0A%20%20%20%20registration%3D...)%60%20is%20declared%20on%20the%20source's%20%60AnalysisPlan%60%20before%0A%20%20%20%20any%20outcome%20is%20read%3B%20always-valid%20inference%20is%20read%20from%20that%0A%20%20%20%20declaration%2C%20never%20passed%20at%20call%20time.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(%0A%20%20%20%20Analysis%2C%0A%20%20%20%20AnalysisPlan%2C%0A%20%20%20%20InferenceSpec%2C%0A%20%20%20%20JointReveal%2C%0A%20%20%20%20PredictivePrior%2C%0A%20%20%20%20SequentialCell%2C%0A%20%20%20%20SequentialCompliancePolicy%2C%0A%20%20%20%20SequentialModel%2C%0A%20%20%20%20SequentialRegistration%2C%0A%20%20%20%20W%2C%0A%20%20%20%20completion_rows%2C%0A%20%20%20%20design%2C%0A%20%20%20%20frame_observation_mapping%2C%0A%20%20%20%20metrics%2C%0A%20%20%20%20panel%2C%0A%20%20%20%20sequential_definition_id%2C%0A%20%20%20%20synthesise_metric%2C%0A)%3A%0A%20%20%20%20_prior%20%3D%20PredictivePrior(kind%3D%22beta%22%2C%20a%3D1%2C%20b%3D1)%0A%20%20%20%20registration%20%3D%20SequentialRegistration(%0A%20%20%20%20%20%20%20%20source_id%3D%22reengagement_email%22%2C%0A%20%20%20%20%20%20%20%20control_group%3D%22control%22%2C%0A%20%20%20%20%20%20%20%20committed_before_data%3DTrue%2C%0A%20%20%20%20%20%20%20%20definitions_id%3Dsequential_definition_id(%0A%20%20%20%20%20%20%20%20%20%20%20%20%5Bsynthesise_metric(spec)%20for%20spec%20in%20metrics%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20design%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20transformations%3Dmetrics%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20source_mapping%3Dframe_observation_mapping(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20unit%3D%22unit_id%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20group%3D%22group_id%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20date%3D%22ds%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exposure_date%3D%22exposed_on%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uptake%3D%22clicked%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20reveal%3DJointReveal(%0A%20%20%20%20%20%20%20%20%20%20%20%20filtration_id%3D%22reengagement-finalized-units%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20independent_unit_vectors%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20simultaneous_metrics%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20outcome_independent_order%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20immutable_finalized_outcomes%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20longest_window_days%3DW%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20models%3D(%0A%20%20%20%20%20%20%20%20%20%20%20%20SequentialModel(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20metric%3D%22uptake%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20observable%3D%22uptake%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20law%3D%22bernoulli%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20control_prior%3D_prior%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20treatment_prior%3D_prior%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20positive_population_control%3DTrue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20)%2C%0A%20%20%20%20%20%20%20%20roster%3D(SequentialCell(metric%3D%22uptake%22%2C%20group_id%3D%22treatment%22%2C%20estimand%3D%22compliance%22)%2C)%2C%0A%20%20%20%20)%0A%20%20%20%20av_plan%20%3D%20AnalysisPlan(%0A%20%20%20%20%20%20%20%20inference%3DInferenceSpec(kind%3D%22always_valid%22%2C%20registration%3Dregistration)%2C%0A%20%20%20%20%20%20%20%20compliance%3DSequentialCompliancePolicy(alpha%3Dregistration.roster%5B0%5D.alpha)%2C%0A%20%20%20%20)%0A%20%20%20%20av_analysis%20%3D%20Analysis.from_unit_panel(%0A%20%20%20%20%20%20%20%20panel%2C%0A%20%20%20%20%20%20%20%20unit%3D%22unit_id%22%2C%0A%20%20%20%20%20%20%20%20group%3D%22group_id%22%2C%0A%20%20%20%20%20%20%20%20date%3D%22ds%22%2C%0A%20%20%20%20%20%20%20%20metrics%3Dmetrics%2C%0A%20%20%20%20%20%20%20%20design%3Ddesign%2C%0A%20%20%20%20%20%20%20%20plan%3Dav_plan%2C%0A%20%20%20%20%20%20%20%20exposure_date%3D%22exposed_on%22%2C%0A%20%20%20%20%20%20%20%20experiment_id%3D%22reengagement_email%22%2C%0A%20%20%20%20)%0A%20%20%20%20uptake_trend%20%3D%20%5B%5D%0A%20%20%20%20for%20_day%20in%20sorted(set(completion_rows%5B%22ds%22%5D))%3A%0A%20%20%20%20%20%20%20%20av_analysis.capture_sequential(finalized%3DTrue%2C%20as_of%3D_day)%0A%20%20%20%20%20%20%20%20uptake_trend.extend(%0A%20%20%20%20%20%20%20%20%20%20%20%20av_analysis.run_asof_lift(estimands%3D(%22compliance%22%2C)%2C%20completed_windows_only%3DTrue)%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20return%20(uptake_trend%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(fixed_late_trend%2C%20pd)%3A%0A%20%20%20%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22ds%22%3A%20r.ds%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22late_lift%22%3A%20f%22%7Br.lift.value%3A%2B.2%25%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22lb%22%3A%20f%22%7Br.lift.lb%3A%2B.2%25%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22ub%22%3A%20f%22%7Br.lift.ub%3A%2B.2%25%7D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22inference%22%3A%20r.inference%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20for%20r%20in%20fixed_late_trend%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(pd%2C%20uptake_trend)%3A%0A%20%20%20%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22ds%22%3A%20r.ds%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22compliance_lift%22%3A%20f%22%7Br.lift.value%3A%2B.2%25%7D%22%20if%20r.lift%20is%20not%20None%20else%20None%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22inference%22%3A%20r.inference%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20for%20r%20in%20uptake_trend%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(fixed_late_trend%2C%20mo%2C%20uptake_trend)%3A%0A%20%20%20%20_fixed_last%20%3D%20fixed_late_trend%5B-1%5D%0A%20%20%20%20_uptake_last%20%3D%20uptake_trend%5B-1%5D%0A%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20-%20**Fixed-horizon%20LATE%20(last%20date)%3A**%20%5B%7B_fixed_last.lift.lb%3A%2B.1%25%7D%2C%20%7B_fixed_last.lift.ub%3A%2B.1%25%7D%5D%20--%20repeated-look%20warning%0A%20%20%20%20-%20**Always-valid%20compliance%20(last%20date)%3A**%20%7B_uptake_last.inference%7D%20inference%2C%20safe%20to%20inspect%20on%20any%20date%0A%0A%20%20%20%20The%20two%20series%20answer%20related%20but%20distinct%20questions%3A%20the%20fixed-horizon%0A%20%20%20%20series%20is%20the%20LATE%20trend%20itself%2C%20valid%20at%20the%20one%20date%20you%20commit%20to%20in%0A%20%20%20%20advance%3B%20the%20always-valid%20series%20is%20relative%20uptake%2C%20the%20LATE's%20own%0A%20%20%20%20first%20stage%2C%20and%20stays%20valid%20under%20unlimited%20peeking.%0A%20%20%20%20%22%22%22)%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
557cb1d4535e2ee5287e25c98fcc7d0d