# Audit/reporting tests based on small, explicitly constructed results. # The minimal frozen-rule object is a test fixture, not calibration evidence. report_test_rule <- function() { structure( list( rule_id = "illustrative_test_rule", thresholds = list( p_risk_min = 0.10, n_risk_min = 10, p_support_min = 0.95 ), simulation_settings = list(source = "constructed test fixture") ), class = "ahtau_support_rule" ) } report_test_summary <- function(clinical_pass = FALSE) { data.frame( scenario_id = c("reference", "reference"), tau = c(24, 36), n_sim = c(100L, 100L), min_mean_p_risk = c(0.3, 0.15), min_mean_n_risk = c(20, if (clinical_pass) 12 else 8), p_support = c(1, 1), p_numeric = c(1, 1), Stage1_pass = c(TRUE, clinical_pass), Stage1_failed_reason = c("none", if (clinical_pass) "none" else "low_absolute_support"), power_overall = c(0.514, 0.559), mean_theta_support = c(-0.5, -0.3), empirical_sd_support = c(0.3, 0.3), mean_se_support = c(0.29, 0.28) ) } report_test_spec <- function() { list(scenario_id = "reference", tau_clin = 36, clinical_window = c(24, 36), power_target = 0.80) } test_that("Reporting keeps a supported clinical horizon even if power is insufficient", { s <- report_test_summary(clinical_pass = TRUE) selection <- stage2_select(s, tau_clin = 36, clinical_window = c(24, 36)) report <- planning_report( trial_spec = report_test_spec(), frozen_rule = report_test_rule(), stage1_result = s, stage2_result = selection ) expect_s3_class(report, "ahtau_planning_report") expect_true(report$decision_summary$Stage1_pass) expect_false(report$decision_summary$meets_power_target) expect_equal(report$decision_summary$tau_star, 36) expect_identical(report$decision_summary$stage2_decision, "Not entered: Stage 1 Pass") printed <- capture.output(print(report)) expect_true(any(grepl("Support is separate from power.", printed, fixed = TRUE))) }) test_that("Reporting a Stage 2 alternative prints its signed power difference", { s <- report_test_summary(clinical_pass = FALSE) selected <- stage2_select(s, tau_clin = 36, clinical_window = c(24, 36)) evaluated <- stage2_evaluate(selected, s) report <- planning_report( trial_spec = report_test_spec(), frozen_rule = report_test_rule(), stage1_result = s, stage2_result = selected, stage2_evaluation = evaluated, simulation_diagnostics = list(selection_seed = 202612, evaluation_seed = 202613) ) expect_identical(report$decision_summary$stage2_decision, "Utility-driven alternative") expect_equal(report$decision_summary$tau_star, 24) expect_equal(report$stage2_evaluation$power_difference, -0.045) expect_equal(report$simulation_diagnostics$supplied$evaluation_seed, 202613) printed <- capture.output(print(report)) expect_true(any(grepl("power difference = -0.045", printed, fixed = TRUE))) expect_false(any(grepl("IR_eval|absolute_power_change|signed_power_change", printed))) }) test_that("Reporting indicates missing optional Stage 2 evaluation", { s <- report_test_summary(clinical_pass = FALSE) selected <- stage2_select(s, 36, c(24, 36)) report <- planning_report( report_test_spec(), report_test_rule(), s, stage2_result = selected ) expect_null(report$stage2_evaluation) printed <- capture.output(print(report)) expect_true(any(grepl("Independent evaluation: not supplied", printed, fixed = TRUE))) }) test_that("Reporting rejects a different frozen rule or mismatched evaluation", { s <- report_test_summary(clinical_pass = FALSE) changed_rule <- report_test_rule() changed_rule$thresholds$n_risk_min <- 7 expect_error(planning_report(report_test_spec(), changed_rule, s), "Stage 1 decisions disagree with the frozen rule") selected <- stage2_select(s, 36, c(24, 36)) evaluated <- stage2_evaluate(selected, s) supported_s <- report_test_summary(clinical_pass = TRUE) expect_error( planning_report(report_test_spec(), report_test_rule(), supported_s, stage2_evaluation = evaluated), "Independent Stage 2 evaluation requires a selected alternative" ) }) test_that("Reporting keeps raw and isotonic Part II powers separate", { rule <- report_test_rule() feasible <- list( N_req = 120, status = "validated_boundary", settings = list(F_followup = 6, tau = 36, N_upper = 200, power_target = 0.8, thresholds = rule$thresholds), validation_results = data.frame( N = c(110, 120, 130), power_overall = c(0.79, 0.81, 0.799), power_overall_iso = c(0.79, 0.8045, 0.8045), Stage1_pass = c(TRUE, TRUE, TRUE), final_feasible = c(FALSE, TRUE, TRUE) ), search_results = data.frame(), trace = list() ) no_feasible <- list( N_req = NA_real_, status = "no_feasible_within_range", settings = list(F_followup = 0, tau = 36, N_upper = 200, power_target = 0.8, thresholds = rule$thresholds), validation_results = data.frame( N = 200, power_overall = 0.76, power_overall_iso = 0.76, Stage1_pass = TRUE, final_feasible = FALSE ), search_results = data.frame(), trace = list() ) report <- planning_report( report_test_spec(), rule, report_test_summary(clinical_pass = TRUE), part2_results = list(feasible = feasible, no_feasible = no_feasible) ) required <- report$part2_requirements expect_equal(nrow(required), 2) expect_equal(required$N_req[1], 120) expect_equal(required$raw_power[1], 0.81) expect_equal(required$isotonic_power[1], 0.8045) expect_equal(required$n_validation_points[1], 3) expect_true(is.na(required$N_req[2])) expect_equal(required$validated_at_N[2], 200) expect_equal(required$raw_power[2], 0.76) })