Skip to content

Fix enrollment pooling that dropped per-stratum periods in simulation inputs#4

Open
lhunt13 wants to merge 1 commit into
johnsonandjohnson:mainfrom
lhunt13:fix/enroll-rate-pooling-by-stratum
Open

Fix enrollment pooling that dropped per-stratum periods in simulation inputs#4
lhunt13 wants to merge 1 commit into
johnsonandjohnson:mainfrom
lhunt13:fix/enroll-rate-pooling-by-stratum

Conversation

@lhunt13

@lhunt13 lhunt13 commented Jul 13, 2026

Copy link
Copy Markdown

Fixes #3.

Problem

get_dist_tite() and get_info_tite() pool arm-level enrollment for ahr_dd()/gsDesign2::ahr() with group_by(rate, duration) |> slice_head(n = 1), which collapses enrollment periods that have identical values in different strata into a single row keeping only the first stratum's label. In multi-stratum designs where strata share period values — e.g. the shared zero-rate lead-in periods of a sub-study that opens late — all but the first stratum lose those periods and are treated as enrolling from time 0. Expected events, information, and the simulated z-statistic means are inflated, so simulated power (Tables 6a/6b) for TTE hypotheses can exceed the full-alpha local power (Table 5). Full analysis in #3.

get_boundaries() already pools correctly, so the design boundaries and local power were unaffected.

Fix

Pool per stratum and enrollment period in both functions, mirroring get_boundaries():

enroll_rate |>
  dplyr::group_by(.data$stratum, .data$rate, .data$duration, .data$index) |>
  dplyr::summarise(rate = sum(.data$arm_rate), .groups = "drop") |>
  dplyr::arrange(.data$index)

With this change, ahr_dd()/ahr() reproduce gs_power_ahr's reference events/information/effect size to machine precision for every TTE hypothesis in the bundled platform_study (e.g. H8 first look: 104.77 events as designed, instead of 142.2). Re-running platform_study (same seed), simulated power changes only for hypotheses in late-opening sub-studies (H3–H11; H8 first-look power 0.55 → 0.43); H1, H2, and H12 are bit-for-bit unchanged. Single-stratum configs are unaffected (the pooling is a no-op there).

Tests

New tests/testthat/test-enroll-pooling.R: a two-stratum sub-study opening at month 14 with 2:1 allocation; asserts get_info_tite() matches gsDesign2::ahr() (independent reference) and get_dist_tite() matches ahr_dd() when both are fed the explicitly correct stratified enrollment. All three assertions fail on main and pass with this change. Full suite passes (98/98); R CMD check clean apart from the two notes already present on main.

Note: a smaller residual difference between simulated power and Table 5 remains after this fix, traced in #3 to the information scale used for the simulated z-statistic means (info vs info0) — left out of this PR pending your input on the intended convention.

🤖 Generated with Claude Code

… inputs

get_dist_tite and get_info_tite pooled arm-level enrollment with
group_by(rate, duration), which collapses enrollment periods with
identical values across DIFFERENT strata into a single row keeping only
the first stratum's label. In multi-stratum designs where strata share
period values — most commonly zero-rate lead-in periods for a sub-study
that opens late — all but the first stratum lost those periods and were
treated as enrolling from time 0. The affected strata then accrued too
much follow-up by each analysis time, inflating expected events,
statistical information, and the simulated z-statistic means, so
simulated power (Tables 6a/6b) exceeded the full-alpha local power for
time-to-event hypotheses (e.g. H8 OS in the bundled platform_study:
~142 events at its first look instead of the correct ~105).

Pool per stratum and enrollment period instead, exactly mirroring the
pooling already used by get_boundaries for the design computations
(which were unaffected). With the corrected pooling, ahr_dd/ahr
reproduce gsDesign2's reference events, information, and effect size to
machine precision for every hypothesis in platform_study.

Adds regression tests comparing get_info_tite and get_dist_tite output
for a two-stratum delayed sub-study against gsDesign2::ahr / ahr_dd fed
the explicitly correct stratified enrollment; they fail before this fix.

Co-Authored-By: Claude Fable 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.

Simulated power inflated for multi-stratum designs: enrollment pooling in get_dist_tite/get_info_tite drops per-stratum periods

1 participant