                     Changes in version 3.11.1.9028                     

Breaking changes

  - Harm spending for test.type = 7 and 8 is now calibrated ignoring
    futility stopping, while retaining efficacy stopping. Reported harm
    probabilities still assume all active stopping rules are followed
    and can be below the spending targets. This also applies to type 8
    exact binomial conversion. Harm remains capped at futility where
    both are active.

  - Harm designs now default to total spending astar = 0.1 (also
    selected by input astar = 0) and sfharm = sfLDPocock, including
    survival interfaces. Types 5 and 6 retain their astar = 0 convention
    of 1 - alpha. Explicit harm spending choices are preserved.

  - Follow-up now refers to all planned participants, with dropout and
    optional event stopping. Use medianFollowUp() for a forward
    calculation; minMedianFollowUp() now solves for cutoff time with a
    named target. The plot uses the revised definition (#281).

  - Absent lower and harm bounds now use -Inf, and absent upper bounds
    use Inf, instead of the finite -20/20 sentinel. This includes zero
    spending and skipped analyses. Use is.finite() to identify active
    bounds. gsBoundCP() returns NA at an absent bound (#242, #321).

New features

  - gsPPFutilitySpending() now defaults to the same normal prior as
    gsBoundSummary(), while continuing to accept user-specified priors.

  - All six spending calibration functions accept survival designs from
    gsSurv(), gsSurvCalendar(), and gsSurvPower(), retaining survival
    classes and rebuilding enrollment and event summaries (#345).

  - toBinomialExact() supports fixed survival designs and single
    observed event counts for them; gsBinomialExact() supports
    one-analysis probabilities (#222).

  - Added opt-in Gauss-Legendre quadrature for boundary crossing
    calculations via options(gsDesign.quadrature = "gl"). The node count
    adapts to the continuation region and neighboring information
    increments, with r controlling resolution. Research benchmarks show
    faster calculations and smaller integration errors. The default
    Jennison and Turnbull grid ("jt") is unchanged; see the numerical
    integration section of ?gsDesign (#323).

  - Unified conditional POS spending calibration in
    gsCPOSFutilitySpending() with mode = "preserve_power" or
    "fixed_information"; retained gsCAFutilitySpending() as a
    backward-compatible wrapper (#328, #329).

  - Added gsEffectSpending() to calibrate efficacy, futility and harm
    spending to natural scale effect targets separately or jointly, with
    difference, risk ratio and explicitly specified event scale hazard
    ratio mappings (#331).

  - Added power-preserving unconditional POS calibration with
    gsPOSFutilitySpending() (#330).

  - Added gsPPFutilitySpending() to calibrate futility spending to
    posterior predictive power targets using a fixed discrete or
    continuous grid prior, sharing the CP calibration solver. The
    futility spending vignette compares CP- and PP-targeted survival
    designs using the default summary prior (#326).

  - Added gsCPFutilitySpending() to calibrate beta spending futility
    parameters and statistical information to conditional power targets
    at one or more interim analyses for test.type 3, 4, 7, and 8 (#318).

  - Added exact conditional power, fixed look Clopper--Pearson,
    repeated, and sequential confidence intervals for vaccine or
    prevention efficacy, plus VEtable() summaries and automatic lt()
    formatting for exact binomial spending designs (#316).

Performance

  - Accelerated futility calibration by searching near reference
    parameters first, avoiding unnecessary optimizer restarts, and
    deferring rate-scaled survival reconstruction until the final fit.
    Target tolerances remain enforced on the returned design, with full
    reconstruction as a fallback. Earlier stopping can slightly change
    fitted spending parameters compared with previous versions while
    retaining the requested probability accuracy.

  - Reduced repeated work in the C density update and boundary searches
    while retaining the Jennison and Turnbull grid and numerical
    results. Research benchmarks measured roughly 20% to 35% faster core
    routines. R's normal tail calculations remain the default;
    -DGS_USE_ERFC enables an optional C-library alternative (#322).

Bug fixes

  - Futility calibration retries unsuccessful deferred survival searches
    with full reconstruction and preserves internal sfLinear warm starts
    near spending limits. Starting diagnostics remain available when the
    backward sweep is skipped, and scalar root searches bracket
    consecutive valid grid points even when an intermediate grid point
    is infeasible.

  - PP, CA, CPOS, and POS futility calibration now inherit the reference
    futility spending function by default, matching CP calibration. This
    fixes multi-target PP calibration with a two-parameter reference
    family; explicit spending overrides and the one-parameter
    requirement for POS remain supported.

  - Log scale HR summaries recover missing null and alternative hazard
    ratios from retained delta0 and delta1, avoiding a spurious warning
    after survival designs are reconstructed with gsDesign() and
    preserving non-unit null ratios and effect direction, including
    alternate alpha summaries (#347).

  - Survival interim event calculations now use the experimental arm
    dropout rate for experimental events, keeping calendar calibration
    consistent when dropout differs between arms (#345).

  - Power plots omit curves and annotations for inactive boundaries
    while retaining cumulative probabilities and original analysis
    numbers. Use showSkipped = TRUE to include skipped looks (#349).

  - print.gsSurv() no longer truncates spending function parameters with
    decimal values, such as the t-distribution parameters printed as a =
    -1.63774, b = 2.96683, df = 3 (#307).

  - gsCPFutilitySpending() inherits the reference design's futility
    spending function when sfl is omitted; explicit overrides remain
    supported (#318).

  - Exact binomial conversion preserves skipped futility looks without
    invalid provisional boundaries during beta spending calibration
    (#333).

  - Information-based boundary plots label actual information as I= with
    two decimal places, rather than rounding it to a sample size (#315).

  - Survival calculation methods are reported in summary(), not boundary
    tables. gsBoundSummary() keeps all analysis annotations when POS or
    excluded statistics require unequal block sizes (#332).

  - Guarded the Newton boundary search against 0/0 updates and separated
    its iteration limit and finite iterate clamp from the absent bound
    values (#242, #321).

  - Updated the R interfaces and convergence checks to handle infinite
    bounds, and fixed gsDensity() for one-sided designs (#242, #321).

  - Fixed gsBoundCP() to return NA at absent harm bounds, including
    bounds with zero spending. This also fixes gsBoundSummary() when
    conditional power is requested for selective harm bound designs
    (#335).

  - gsBoundSummary() now skips conditional power calculations separately
    for excluded CP and CP H1 rows (#335).

Major changes

  - Replaced gt with the lightweight lt package (>= 0.3) as the default
    table-rendering framework throughout gsDesign. The package now
    re-exports lt(), and its table-output workflows use lt functions.
    Package-specific support includes an lt() method for
    gsBinomialExactTable objects. as_gt() remains available for
    compatibility but is deprecated and requires the suggested gt
    package.

Documentation

  - Removed unnecessary hyphens introduced in 2026 across help text,
    vignettes, navigation, comments, and messages, preserving wording
    used before 2026.

  - Reorganized the pkgdown reference index by workflow, highlighting
    spending calibration and keeping shared help topics together. The
    Articles menu now lists every article directly under category
    headings.

  - Clarified that all six spending calibrators hold analysis
    information fractions (x$timing) fixed, separately from spending
    times. Defined CP targets in the argument documentation as total
    future efficacy probabilities and added a verified two-target
    example (#346).

  - Added a sparse-event mortality example using type 6 non-binding harm
    monitoring without separate futility, exact binomial integer
    boundaries, harm detection sensitivity, and a fixed analysis
    precision illustration. Distinguished detecting harm from ruling it
    out and corrected the FDA reference to the August 2025 draft
    guidance.

  - Explained harm calibration versus actual stopping probabilities in
    the help and harm/selective monitoring vignettes, with a worked
    skipped-look example. Documented the 0.1/Pocock rationale, nominal
    harm tail p-values, and the tradeoff in increasing total harm
    spending when more analyses are planned.

  - Added a historical vignette covering the package's statistical
    foundations, contributors, software modernization, and recent
    development (#304).

  - Added an effect spending vignette using the public interface for
    joint boundaries, risk differences and HRs explicitly scaled to
    events (#331).

  - Added a separate vignette comparing conditional assurance and
    unconditional POS spending calibration, including the Dragalin fixed
    information benchmark and operating characteristic checks (#330).

  - Added a futility spending calibration vignette comparing all six
    two-parameter families and piecewise linear spending with three
    conditional power targets, including reconstructed designs and
    practical guidance on early futility and sample size inflation.
    Examples cover risk differences, normal means, survival designs, and
    calibrated spending curves with interpretation of effects at the
    bounds (#318).

  - Documented all gsCPFutilitySpending() solver controls, defaults, and
    spending family restrictions, with a tighter CP tolerance example
    (#318).

  - Updated the gsCPFutilitySpending() example to target conditional
    power 0.3 under the observed effect, reuse fitted futility spending
    parameters in gsDesign() and gsSurv() with matching test type,
    timing, and spending, and verify conditional power using
    gsBoundSummary(). The example uses sfLDOF efficacy spending and
    futility testing only at IA 1 (#318).

  - Updated package vignettes to use lt consistently for formatted data
    frame and matrix output, with compact row spacing for long tables
    and no significant changes to the rendered HTML tables.

  - Remastered the hex sticker logo with a reproducible parametric logo
    generation script (#327).

  - Reduced rendered HTML size in selected vignettes with figures by
    switching from the base R SVG device to PNG device with optimized
    parameters (#325, #344).

Testing

  - Verify survival CP calibration retains the 0.1/Pocock harm defaults
    and harm calibration independent of futility stopping (#345).

  - Update RTF summary tests to expect no warning when log scale HR
    metadata can be recovered, retaining the existing output snapshots
    (#347).

  - Added harm calibration checks against an independent boundary solver
    and bivariate integration, plus default propagation, selective
    bound, and exact binomial checks. Regenerated only the four affected
    harm design numerical fixtures for the intentional new calibration
    and defaults.

  - Declare svglite as a test dependency for information label rendering
    checks (#315).

  - Added tests for natural effect calibration, joint boundary targets,
    HR allocation/direction handling and design replay (#331).

  - Added regression fixtures, multivariate normal reference checks, and
    print snapshots for the numerical integration routines and their R
    interfaces (#242, #320).

  - Reduced default test suite runtime by using smaller stress-test
    grids, fewer Monte Carlo iterations, and toy exact binomial p-value
    event counts. Set GSDESIGN_RUN_STRESS_TESTS=true to run the larger
    stress-test settings.

                 Changes in version 3.11.0 (2026-08-29)                 

New features

  - gsSurvPower() results now have primary class "gsSurvPower" while
    retaining inheritance from "gsSurv" and "gsDesign". They also retain
    evaluated, replayable arguments in inputs, enabling downstream
    packages to identify and reproduce power calculations (#313).
  - gsSurvPower() now aligns its expected analysis cut grammar with
    simtrial::get_analysis_date(): overall and per-stratum event and
    enrollment requirements can be combined, maxCalendarTime provides an
    absolute cap, and spending = "min_planned_actual" supports reference
    design planned-versus-actual spending. Existing unstratified
    targetEvents, minN, and relative maxExtension behavior is retained
    (#303).
  - All gsSurv objects now include N, the cumulative total expected
    enrollment at each analysis. nSurv objects retain scalar n and also
    return identical scalar N as a non-breaking alias (#299).
  - Added survival enrollment planning documentation for four-period
    ramp-up, the three combinations of fixed or solved enrollment and
    follow-up duration, calendar time analyses, power sensitivity,
    integer conversion, and stratified designs. gsSurv(T = NULL, minfup
    = ...) now consistently keeps enrollment rates fixed and solves
    enrollment duration (#300).
  - Added minMedianFollowUp() and plotMinMedianFollowUp() to compute and
    plot minimum median follow-up at any calendar time from the
    piecewise enrollment assumptions in an nSurv or gsSurv design. The
    plot accepts arbitrary time unit labels through timename; month and
    year labels default to x-axis breaks every 6 months and 0.5 years,
    respectively, while other units use automatic breaks (#281).
  - Sequential p-values, including exact binomial repeated and
    sequential efficacy p-values, now support test.type = 8 by ignoring
    its non-binding futility and harm bounds. toBinomialExact() now
    provides full exact conversion for non-binding test types 1, 4, 6,
    and 8. For type 6, the upper event count boundary targets lower
    bound spending under the null hypothesis. For type 8, exact upper
    event count stops are partitioned into mutually exclusive futility
    and harm regions, targeting beta spending under the alternative and
    harm spending under the null, respectively (#287).

Documentation

  - Expanded the main gsDesign() help discussion to describe binding and
    non-binding futility plus harm monitoring for test.type = 7 and 8
    (#308).
  - Clarified the two intended uses of gsSurvPower(), expanded guidance
    for scenario and combined timing rule analyses, including mixed-NA
    rules by analysis, added survival workflow routing, and documented
    that expected value calculations do not replace simulation of
    stochastic trial execution (#303).
  - Clarified beta spending in gsSurvPower() scenario analyses,
    distinguishing design beta from achieved beta and defining
    informationRates as planned information fraction caps used to derive
    effective spending time (#303).
  - Expanded the gsSurvPower() vignette with common timing pitfalls for
    explicit minfup, targetN, maxExtension, and minN + minFollowUp
    workflows (#291, #293, #295, #296).
  - Explained why skipping futility while retaining harm monitoring can
    recalibrate earlier harm bounds, and documented recommended final
    analysis testing schedules using common event-driven survival design
    assumptions for all selective bound examples (#306).

Testing

  - Added gsSurvPower() tests for combined overall and per-stratum
    timing rules, absolute and relative caps on stratified event waits,
    and planned-versus-actual spending with mixed cuts and delayed
    information (#303).

Bug fixes

  - gsSurvPower() now validates mixed-NA timing inputs consistently,
    rejects missing testing indicators and spending times with
    informative messages, and detects analyses without an active timing
    rule or follow-up values without a corresponding enrollment
    requirement (#303).
  - A matrix supplied to gsSurvPower(targetEvents = ...) is now treated
    as a deprecated alias for targetEventsPerStratum and its entries are
    enforced as per-stratum requirements. Previously, the rows were
    reduced to overall sums, which did not enforce the documented
    stratified cut (#303).
  - gsSurvPower() now respects an explicitly supplied minfup as a final
    analysis timing floor for event-driven designs, so the final
    analysis is not scheduled before the end of enrollment plus minimum
    follow-up (#291).
  - gsSurvPower(targetN = ...) now works when R is omitted by expanding
    and rescaling enrollment period durations to match the supplied
    gamma periods. Documentation now clarifies that targetN changes
    enrollment duration; for fixed duration enrollment, specify R and
    scale gamma directly (#293).
  - gsSurvPower() now gives an informative error when maxExtension is
    used without a floor timing criterion such as plannedCalendarTime,
    minN, or minTimeFromPreviousAnalysis (#295).
  - gsSurvPower() can now use minN plus minFollowUp as the primary
    timing criterion, solves for the earliest time at which enrollment
    reaches minN, and reports a clear error if the criteria do not
    produce strictly increasing analyses (#296).
  - gsSurvPower() now retains exact event totals when targetEvents
    determines an analysis, rather than exposing small root finding
    residuals that could make gsBoundSummary() round an integer event
    target up by one (#294).
  - Survival sample size outputs now normalize machine-precision
    representations of integers before applying display rounding, so
    gsSurvPower() and gsBoundSummary() preserve exact arm and total
    sample sizes (#290).
  - Single-analysis survival designs now use a fixed design nSurv() path
    in gsSurv(k = 1) and gsSurvPower(k = 1). The resulting objects work
    with toInteger() and gsBoundSummary(), including alternate alpha
    summaries and use all alpha at the sole analysis without displaying
    an irrelevant spending function in summary(). An nSurv() object can
    now also be passed directly to toInteger() and is returned as an
    nSurv object with integer event and sample size targets (#289).
  - Power plots for test types 7 and 8 now treat crossing the futility
    threshold as the union of futility-only and harm stops. The separate
    harm curve remains harm-only, and the mutually exclusive
    probabilities stored on the design are unchanged (#287).
  - Sample size derivation now accounts for analyses where efficacy,
    futility, or harm testing is skipped, avoiding power above the
    requested target. Harm, futility, and efficacy crossing
    probabilities are reported as mutually exclusive outcomes. Alternate
    alpha summaries and power calculations retain the planned efficacy
    testing schedule, and survival design inputs retain the applicable
    testing flags. gsBoundSummary() reports every characteristic,
    including cumulative crossing probability, as NA when its bound is
    not tested at an analysis (#287).
  - Alternate alpha summaries are now limited to one-sided and
    non-binding test types 1, 4, 6, and 8. Binding test type 7 is no
    longer presented as compatible with the Maurer--Bretz graphical
    multiple testing framework (#287).

                 Changes in version 3.10.1 (2026-07-20)                 

Bug fixes

  - Futility and harm bounds can now be skipped independently at an
    analysis; skipping futility no longer also removes an active harm
    bound (#284).

                 Changes in version 3.10.0 (2026-07-03)                 

New features

  - Added testUpper, testLower, and testHarm parameters to gsDesign(),
    gsSurv(), and gsSurvCalendar() for selective bound testing at
    interim analyses. Each accepts a logical scalar or vector of length
    k specifying which analyses should include that boundary. Inactive
    bounds are set to extreme values (±20 on Z-scale) and displayed as
    NA in print() and gsBoundSummary() output. This enables designs such
    as futility-only at early interims, deferred efficacy testing, or
    selective harm monitoring (@keaven, #141).
  - Added test.type = 7 (binding futility and binding harm bounds) and
    test.type = 8 (non-binding futility and non-binding harm bounds) to
    gsDesign(), gsSurv(), and gsSurvCalendar(). These three-boundary
    designs support monitoring for efficacy, futility, and potential
    harm simultaneously, motivated by FDA guidance on overall survival
    monitoring in oncology trials (@keaven, #237).
  - New sfharm and sfharmparam parameters control the spending function
    for the harm bound independently from efficacy and futility spending
    (@keaven, #237).
  - All six plot() types, gsBoundSummary(), print(), summary(), and
    xtable() methods support the new three-boundary designs (@keaven,
    #237).
  - Added HarmBound vignette demonstrating harm bound design and
    interpretation (@keaven, #237).
  - Survival design functions (nEvents(), nSurv(), gsSurv(),
    gsSurvCalendar()) now support hr > hr0 for time-to-event designs
    where a larger hazard ratio is the alternative hypothesis. This
    enables direct specification of designs for time-to-response, safety
    endpoints, or reversed HR conventions. All sample size methods
    (Lachin-Foulkes, Schoenfeld, Freedman, Bernstein-Lagakos) and
    plotting functions handle both directions symmetrically (@keaven,
    #251).
  - New gsSurvPower() function computes power for a group sequential
    survival design with specified enrollment, dropout, treatment
    effect, and analysis timing. Unlike gsSurv() and gsSurvCalendar()
    which solve for sample size, gsSurvPower() takes fixed assumptions
    and computes power. Supports calendar time and event-driven timing,
    stratified designs, all test types (1--8 including harm bounds), and
    flexible analysis timing criteria (targetEvents,
    plannedCalendarTime, maxExtension, minTimeFromPreviousAnalysis,
    minN, minFollowUp). When an existing gsSurv design is provided via
    x, parameters can be selectively overridden for "what-if"
    sensitivity analyses. Changing alpha preserves original futility
    bounds (following gsBoundSummary() convention) while recomputing
    efficacy bounds (@keaven, #109).
  - gsSurvPower() now supports informationRates to cap spending at
    planned versus realized information fractions and
    fullSpendingAtFinal to force the final spending fraction to 1 when
    desired. This makes it easier to evaluate delayed event accrual
    while keeping spending tied to a planned information schedule. It
    also preserves the original one-sided versus two-sided design
    convention when inheriting defaults from an existing gsSurv object
    (#258).
  - New vignette "Power Computation for Group Sequential Survival
    Designs" (vignette("gsSurvPower")) with worked examples for
    sensitivity analysis, alpha reallocation, biomarker subgroup to
    stratified design, and event-driven timing (@keaven, #109).
  - Added repeatedPValueBinomialExact() and
    sequentialPValueBinomialExact() to compute repeated and sequential
    exact binomial p-values under spending function designs derived from
    gsSurv() objects (#264).
  - Added simBinomialSeasonalExact() to run fixed and blinded-adaptive
    seasonal rare-event simulations with exact binomial efficacy
    monitoring summaries (#264).
  - toBinomialExact() now supports explicit spending time overrides via
    usTime and lsTime (for test.type = 4) to align with gsDesign() and
    gsSurv() conventions when updating bounds with observedEvents
    (#264).
  - toBinomialExact() now accepts an alpha override for deriving updated
    exact efficacy bounds (#167).
  - simBinomialSeasonalExact() now supports usTime/lsTime inputs and
    reports futility stopping probabilities (futility_stop_rate with
    futility_mc_se) in scenario summaries (#264).
  - simBinomialSeasonalExact() now accepts ve = 0 and ve < 0, allowing
    null hypothesis (ve = 0) and non-inferiority margin (ve < 0)
    scenarios. Validation now requires only that ve values are finite
    and less than 1. A feasibility check verifies that the implied
    experimental arm event rates (control_event_rate * (1 - ve)) remain
    in [0, 1) (#267).

Bug fixes

  - gsBoundSummary() now warns before defaulting missing hr0 to 1 for
    hazard ratio boundary summaries (#42).
  - nSurv() and gsSurv() now validate fixed survival timing inputs
    before enrollment periods are adjusted, giving a clear error when
    R/gamma imply accrual beyond T - minfup instead of failing later
    while assigning row names (#274).
  - Power.ssrCP() now uses the interim efficacy bound when integrating
    the region without sample size re-estimation and when falling back
    to the upper conditional power changepoint (#213).
  - nSurv() and gsSurv() now use the requested survival sample size
    method when either T or minfup is NULL. gsSurv() also uses the input
    accrual rate and duration when both T and minfup are NULL, solving
    follow-up duration against the final group sequential event
    requirement. This allows Schoenfeld survival designs to reproduce
    SAS PROC SEQDESIGN's fixed accrual follow-up solve (#270).
  - simBinomialSeasonalExact() now stops simulated trials at the first
    efficacy or futility boundary crossing for reporting stopping time,
    total events, and total enrollment, while preserving the non-binding
    futility convention for efficacy crossing probability. The
    simulation also updates exact binomial bounds within each trial
    using the observed total event counts and defaults fixed per-season
    enrollment to the design's planned seasonal enrollment (#264).
  - toInteger() now preserves selective bound flags (testUpper,
    testLower, testHarm) and harm bound spending (sfharm, sfharmparam
    for test.type 7 or 8) when recomputing the design after integer
    sample size or event count rounding. Previously the internal
    gsDesign() call omitted these settings, so inactive looks could
    incorrectly become active (#261).
  - toInteger() now preserves the intended survival design behavior that
    roundUpFinal = TRUE rounds the final event count up. If the
    independently rounded final sample size, using the usual ratio + 1
    allocation multiple, cannot support the integer event target,
    toInteger() adjusts sample size by allocation multiples, with a
    warning, until the target is achievable. Designs where the rounded
    sample size already supports the integer event target retain the
    previous behavior (#264).
  - toInteger() survival integerization now keeps the calendar design
    fixed while deriving interim integer events from timing and final
    integer event target. Enrollment is inflated minimally by scaling
    accrual rates and then rounded to allocation multiples, avoiding
    unnecessary enrollment increases driven by calendar extensions for
    small final event rounding changes. A variable-duration fallback is
    retained with a warning when fixed calendar inflation is infeasible
    (#271).
  - Fixed sign inconsistency in hrn2z() which used sign(hr0 - hr1) while
    zn2hr() used sign(hr1 - hr0), preventing correct round-trip
    conversion. Both now use sign(hr1 - hr0) (@keaven, #251).
  - Fixed toBinomialExact() one-sided (test.type = 1) updating with
    observedEvents so futility adjustment code is only executed when
    test.type = 4 (#264).
  - toBinomialExact() now respects selective futility testing
    (testLower) when present on a gsSurv object by flattening lower
    spending at inactive looks (#264).

Documentation

  - Clarified the SeqDesignSurvival vignette scope as a SAS PROC
    SEQDESIGN sample size translation, with upfront guidance on gsSurv()
    enrollment and follow-up workflows versus gsSurvPower() power
    calculations (#271).
  - Updated the SeqDesignSurvival vignette to use the one-sided gsSurv()
    alpha convention when reproducing SAS PROC SEQDESIGN fractional time
    survival output (#264).
  - Corrected and generalized the multi-season rare-event vignette so
    enrollment timing, planned counts, and simulation event rate inputs
    are derived from the stated design specifications, with
    calendar-timed seasonal analyses, piecewise seasonal failure
    hazards, and cross-references to the exact binomial vaccine efficacy
    vignette (#264).
  - Expanded toInteger() help and vignette guidance for survival design
    final event rounding, final sample size feasibility adjustment, and
    seasonal designs with a final zero event rate period (#264).
  - Documented test.type restriction in toBinomialExact(): only
    test.type = 1 and 4 are supported; other types (including 7 and 8)
    produce an error (@keaven, #109).
  - Consolidated shared roxygen2 @param documentation using
    @inheritParams so that test.type, spending function parameters, and
    other shared arguments are defined once in gsDesign() or nSurv() and
    inherited by gsSurv() and gsSurvCalendar() (@keaven, #237).
  - New vignette "Selective bound testing at interim analyses"
    (vignette("SelectiveBoundTesting")) with worked examples for all
    supported scenarios (@keaven, #255).
  - Expanded gsSurvPower() documentation and vignette guidance for
    informationRates, calendar spending, and fullSpendingAtFinal,
    including a corrected worked example of the spending fractions used
    at the final analysis (#258).
  - Clarified the PROC SEQDESIGN survival vignette comparison by using
    test.type = 2, alpha = 0.025, method = "Schoenfeld", and T = minfup
    = NULL to match SAS's symmetric two-sided fixed accrual design, with
    guidance on fractional time information schedules (#270).
  - Added vignette "Multi-season studies for rare events"
    (vignette("MultiSeasonRareEvents")) demonstrating exact binomial
    seasonal monitoring, analysis time bound updates via
    toBinomialExact(observedEvents = ...), and blinded
    information-adaptive enrollment scenarios (#264).
  - Expanded the multi-season vignette with: initial gsBoundSummary()
    output, IA1-only futility illustration, VE and nominal one-sided
    p-values at exact binomial bounds, and clearer simulation tables
    including efficacy and futility stopping probabilities with
    non-binding Type I interpretation notes (#264).
  - Reorganized pkgdown article sections to separate general materials,
    exact binomial workflows, and multiple hypothesis testing content
    (#264).

Testing

  - Added toInteger() regression tests for selective bound preservation
    on gsDesign and gsSurv objects, including test.type 8 with custom
    harm spending (#261).
  - Added focused gsSurvPower() regression tests for informationRates,
    fullSpendingAtFinal, and inherited sidedness behavior from existing
    time-to-event designs (#258).
  - Added independent tests for exact binomial repeated/sequential
    p-values and for simBinomialSeasonalExact() input validation,
    reproducibility, and adaptive enrollment behavior (#264).
  - Added regression test confirming toBinomialExact() one-sided
    (test.type = 1) updates with observedEvents (#264).
  - Added regression tests for toBinomialExact() usTime/lsTime overrides
    and selective futility behavior, plus tests for new futility
    stopping summary outputs from simBinomialSeasonalExact() (#264).
  - Added regression tests for simBinomialSeasonalExact() stopping
    summaries, design-based fixed enrollment defaults, and the
    rare-event toInteger() equal allocation path (#264).
  - Expanded nSurv() and gsSurv() regression tests across the supported
    T/minfup timing combinations for Schoenfeld, Freedman, and
    Bernstein-Lagakos methods (#270).

                 Changes in version 3.9.0 (2026-02-15)                  

Breaking changes

  - The R native pipe operator |> is now used throughout the code and
    documentation, so R >= 4.1.0 is now required (@nanxstats, #236).

New features

  - nSurv() and gsSurv() now incorporate Schoenfeld and Freedman methods
    for sample size and power for time-to-event studies with
    proportional hazards. This allows matching versus other software
    (@keaven, #243).

Improvements

  - Corrected weighting for stratified time-to-event studies with
    proportional hazards. This was done for Lachin-Foulkes method, but
    we also added Bernstein and Lagakos method (@keaven, #243).
  - print.nSurv() and print.gsSurv() now use refreshed output formatting
    (@keaven, #243).
  - C code under src/ is now consistently formatted with clang-format,
    and C function comments now use Doxygen blocks with clearer
    parameter and return documentation (@nanxstats, #238).
  - C normal density calculations now use a shared gs_inv_sqrt_2pi
    constant from src/gsDesign.h, which now also has include guards,
    replacing duplicated magic numbers and repeated division
    (@nanxstats, #241).
  - Time-to-event design code is now split into focused R/gsSurv-*.R
    files, improving maintainability and future extension without
    changing user-facing behavior (@nanxstats, #240).

Bug fixes

  - gsBound() now prints the last two lower boundary values correctly in
    an internal diagnostic message (atem and atem2) when printerr is
    enabled (@nanxstats, #238).

Testing

  - Added regression tests for gsBound(), gsBound1(), gsDensity(), and
    gsProbability() to verify stable behavior after normal density
    constant refactoring (@nanxstats, #241).
  - Increased unit test coverage across core gsDesign, spending, and
    binomial utilities (@keaven, #243).
  - Updated as_gt() snapshots for gt 1.3.0 LaTeX output changes so tests
    pass reliably across environments (@nanxstats, #239).

                 Changes in version 3.8.0 (2025-12-07)                  

New features

  - gsBoundSummary() now displays calendar time for gsNB objects from
    the gsDesignNB package when analysis times are provided (@keaven,
    #229, #233).

Improvements

  - plotgsPower() now uses linewidth instead of deprecated size
    aesthetic for geom_line() calls, avoiding ggplot2 (>= 3.4.0)
    warnings (@nanxstats, #217).

Bug fixes

  - sfXG3() now correctly reports its name as "Xi-Gallo, method 3"
    instead of "Xi-Gallo, method 1" (@DMuriuki, #223).
  - Fixed base plotting for conditional power (plottype = 4) so labels
    passed to text() match the plotted points. This prevents r-devel
    (R 4.6.0) truncation warnings and keeps vdiffr snapshots bitwise
    reproducible across R versions (@nanxstats, #231).

Testing

  - Added independent unit tests for sfXG1(), sfXG2(), and sfXG3()
    (@DMuriuki, #223).
  - Added independent unit tests for toBinomialExact() and xtable()
    (@DMuriuki, #224).
  - Updated as_gt() snapshot tests for gt 1.1.0 compatibility
    (@nanxstats, #221).
  - Snapshot files are now included in the built package to satisfy
    testthat (>= 3.3.0) requirements (@jdblischak, #227).
  - Reduced visual regression test output verbosity by wrapping base
    graphics plotting expressions in capture.output() (@nanxstats,
    #217).

Documentation

  - nNormal() now links to vignette("nNormal") in its See Also section
    for the full derivation and examples (@keaven, #220).

Maintenance

  - Added workflow_dispatch trigger to R CMD check workflow for easier
    testing on forks (@jdblischak, #225).

                 Changes in version 3.7.0 (2025-08-25)                  

Breaking changes

  - hGraph() has been formally removed from gsDesign (@nanxstats, #215).
    It was soft-deprecated in gsDesign 3.4.0 and moved to gMCPLite. Use
    gMCPLite::hGraph() instead.
    
    This change also preemptively fixes an R CMD check issue with
    ggplot2 (>= 4.0.0) that would otherwise require declaring MASS as an
    explicit dependency (tidyverse/ggplot2#6578).

Testing

  - Added independent unit tests for gsAdaptSim() and gsSimulate()
    (@DMuriuki, #212).
  - Added independent unit tests for binomialPowerTable() (@DMuriuki,
    #214).

                 Changes in version 3.6.9 (2025-06-25)                  

Documentation

  - Added new vignette vignette("binomialTwoSample") for binomial
    two-arm trial design and analysis (@keaven, #202). Covers
    superiority, non-inferiority, and super-superiority designs using
    risk-difference methods. Includes sample size calculations, power
    analysis, and protocol wording with both asymptotic approximations
    and simulation approaches.

New features

  - New function binomialPowerTable() generates power tables across
    control rates and treatment effects. Supports both analytical
    calculations and fast simulation for exact results.

                 Changes in version 3.6.8 (2025-05-21)                  

Bug fixes

  - gsBoundSummary() (as updated in gsDesign 3.6.6) did not consider
    spending time for alternate alpha levels when the alpha argument was
    specified. This issue has been resolved; lsTime and usTime are now
    correctly used for updated bounds with these alternate alpha levels
    (@keaven, #203).

Testing

  - Added independent unit tests for as_gt() (@DMuriuki, #196).

Documentation

  - Switched the pkgdown math renderer from KaTeX to MathJaX for
    improved compatibility, as the MathJaX support was improved in
    pkgdown 2.1.2 (@nanxstats, #200).
  - Added Research Organization Registry (ROR) ID to DESCRIPTION
    (@jdblischak, #201).

                 Changes in version 3.6.7 (2025-03-03)                  

Improvements

  - All plots in vignettes are now generated by the native SVG device
    for sharper appearance and fewer package dependencies (@nanxstats,
    #188).

Testing

  - Add independent unit tests for toInteger() (@DMuriuki, #186).

                 Changes in version 3.6.6 (2025-02-11)                  

New features

  - gsBoundSummary() gains a new argument alpha to assemble a summary
    table with multiple efficacy boundaries (@keaven, #183).

Testing

  - Add essential unit tests for gsSurvCalendar() (@keaven, #178).
  - Refactor graphical tests with vdiffr::expect_doppelganger()
    (@nanxstats, #176).
  - Use CODECOV_TOKEN to fix code coverage uploads (@jdblischak, #179).

Documentation

  - Add more details to the parameter r for controlling numerical
    integration grid points (@nanxstats, #181).

                 Changes in version 3.6.5 (2024-11-14)                  

Improvements

  - toInteger() (introduced in gsDesign 3.5.0) is updated to match
    broader, non-gsDesign conventions for deriving integer sample size
    and event counts (@keaven, #172).
    
    This update may result in different outputs compared to previous
    versions. Users who use this function should review the updated
    function documentation (?toInteger) and vignette("toInteger") for
    details.

Testing

  - Add snapshot tests for as_rtf() methods (@DMuriuki, #168).

Documentation

  - Add the cph role to the Authors@R field following best practices
    (@nanxstats, #166).

                 Changes in version 3.6.4 (2024-07-26)                  

Improvements

We have made the spending function summary output more readable and
informative.

  - Text summaries for spending functions with multiple parameters are
    now properly formatted. For instance, a b = 0.5 1.5 is now displayed
    as a = 0.5, b = 1.5 (@jdblischak, #162).
  - The summary() method for sfLDOF() no longer includes the redundant
    none = 1 in its output (@jdblischak, #159).

Documentation

  - Added a note about using a positive scalar for sfupar in sfLDOF() to
    create a generalized O'Brien-Fleming spending function (@keaven,
    52cc711, 99996b).
  - Improved math rendering in our pkgdown site vignettes by switching
    to KaTeX, which is now supported in pkgdown 2.1.0 (@nanxstats,
    #161).
  - Standardized vignette titles and headings by using h2 as the base
    level and adopting sentence case throughout (@nanxstats, #158).

                 Changes in version 3.6.3 (2024-07-09)                  

New features

  - Implemented conditional error spending functions sfXG1(), sfXG2(),
    and sfXG3() based on Xi and Gallo (2019). See
    vignette("ConditionalErrorSpending") for details and reproduced
    examples from the literature (@keaven, #147. Thanks, @xidongdxi, for
    comments on vignette).

Improvements

  - Enhanced eEvents() with input validation to ensure lambda is not
    NULL (@keaven, 97f629d).

Testing

  - Added independent testing for gsSurvCalendar() (@myeongjong, #144).
  - Expanded test coverage for gsBinomialExact() (@menglu2, #143).

                 Changes in version 3.6.2 (2024-04-09)                  

Documentation

  - Add new vignette on conditional power and conditional error, see
    vignette("ConditionalPowerPlot") (beb2957, 727fe20, 57394fe).
  - Fix roxygen2 warning and use magrittr pipes in vignette for
    consistency (#131).

Testing

  - Move independently programmed functions for validation as standard
    test helper files (#130).

                 Changes in version 3.6.1 (2024-02-13)                  

New features

  - gsBoundSummary() now has the as_rtf() method implemented to generate
    RTF outputs for bound summary tables (@wangben718, #107).
  - plotgsPower() gets new arguments offset and titleAnalysisLegend to
    enable more flexible and accurate power plots (plottype = 2)
    (@jdblischak, #121, #123).

Improvements

  - The plotting functions now use dplyr::reframe() to replace
    dplyr::summarize() when performing grouped cumsum() (@jdblischak,
    #114).
  - The plotting functions are updated to use the .data pronoun from
    rlang with ggplot2::aes(). This simplifies the code and follows the
    recommended practice when using ggplot2 in packages (@jdblischak,
    #124).
  - hGraph() now uses named guide argument in the scale_fill_manual()
    call to be compatible with ggplot2 3.5.0 (@teunbrand, #115). Note:
    this function has been deprecated and moved to gMCPLite since
    gsDesign 3.4.0. It will be removed from gsDesign in a future
    version. Please use gMCPLite::hGraph() instead.

Documentation

  - vignettes("SurvivalOverview") is updated with more details and minor
    corrections (@keaven, #126).
  - Fix equation syntax in plotting function documentation to render
    math symbols properly (@keaven, #118).

                 Changes in version 3.6.0 (2023-11-12)                  

Breaking changes

  - gsSurv() and nSurv() have updated default values for T and minfup so
    that function calls with no arguments will run. Legacy code with T
    or minfup not explicitly specified could break (#105).

New features

  - gsSurvCalendar() function added to enable group sequential design
    for time-to-event outcomes using calendar timing of interim analysis
    specification (#105).
  - as_rtf() method for gsBinomialExact() objects added, enable RTF
    table outputs for standard word processing software (#102).

Improvements

  - toBinomialExact() and gsBinomialExact(): fix error checking in bound
    computations, improve documentation and error messages (#105).
  - print.gsSurv(): Improve the display of targeted events (very minor).
    The boundary crossing probability computations did not change. The
    need is made evident by the addition of the toInteger() function
    (#105).
  - toInteger(): Fix the documentation and execution based on the ratio
    argument (#105).
  - Update the vaccine efficacy, Poisson mixture model, and toInteger
    vignettes (#105).
  - Standardize and improve roxygen2 documentation (#104).

                 Changes in version 3.5.0 (2023-07-19)                  

  - sfPower() now allows a wider parameter range (0, 15].
  - toInteger() function added to convert gsDesign or gsSurv classes to
    integer sample size and event counts.
  - toBinomialExact() function added to convert time-to-event bounds to
    exact binomial for low event rate studies.
  - Added "A Gentle Introduction to Group Sequential Design" vignette
    for an introduction to asymptotics for group sequential design.
  - as_table() and as_gt() methods for gsBinomialExact objects added, as
    described in the new "Binomial SPRT" vignette.
  - In plot.ssrCP(), the hat syntax in the mathematical expression is
    revised, resolving labeling issues.
  - ggplot2::qplot() usage replaced due to its deprecation in
    ggplot2 3.4.0.
  - Link update for the gsDesign manual in the documentation, now
    directly pointing to the gsDesign technical manual bookdown project.
  - Introduced a new hex sticker logo.

                 Changes in version 3.4.0 (2022-10-12)                  

  - Removed restriction on gsCP() interim test statistic zi (#63).
  - Removed gMCP dependency. Updated vignettes and linked to vignettes
    in gMCPLite (#69).
  - Added deprecation warning to hGraph() and suggested using
    gMCPLite::hGraph() instead (#70).
  - Moved ggplot2 from Depends to Imports (#56).

                 Changes in version 3.3.0 (2022-05-27)                  

  - Addition of vignettes
      - Demonstrate cure model and calendar-based analysis timing for
        time-to-event endpoint design
      - Vaccine efficacy design using spending bounds and exact binomial
        boundary crossing probabilities
  - Minor fix to labeling in print.gsProbability
  - Fixed error in sfStep
  - Updates to reduce R CMD check and other minor issues

                 Changes in version 3.2.2 (2022-02-02)                  

  - Use inherits() instead of is() to determine if an object is an
    instance of a class, when appropriate
  - Correctly close graphics device in unit tests to avoid plot output
    file not found issues
  - Minor fixes to hGraph() for multiplicity graphs
  - Minor fix to nBinomial() when odds-ratio scale specified to resolve
    user issue
  - Minor changes to vignettes

                 Changes in version 3.2.1 (2021-07-12)                  

  - Changed gt package usage in a vignette due to deprecated gt function
  - Replied to minor comments from CRAN reviewer (no functionality
    impact)
  - Minor update to DESCRIPTION citing Jennison and Turnbull reference

                 Changes in version 3.2.0 (2021-03-13)                  

  - Substantially updated unit testing to increase code coverage
    above 80%
  - Updated error checking messages to print function where check fails
  - Removed dependencies on plyr packages
  - Updated github actions

                 Changes in version 3.1.1 (2020-05-07)                  

  - Vignettes updated
  - Added hGraph() to support ggplot2 versions of multiplicity graphs
  - Eliminated unnecessary check from sequentialPValue
  - Targeted release to CRAN
  - Removed dependencies on reshape2, plyr
  - Updated continuous integration
  - Updated license

                        Changes in version 3.1.0                        

  - Addition of pkgdown web site
  - Updated unit testing to from RUnit to testthat
  - Converted to roxygen2 generation of help files
  - Converted vignettes to R Markdown
  - Added Travis-CI and Appveyor support
  - Added sequentialPValue function
  - Backwards compatible addition of spending time capabilities to
    gsDesign and gsSurv

                        Changes in version 3.0-5                        

  - Registered C routines
  - Fixed "gsbound"
  - Replaced "array" by "rep" calls to avoid R CMD check warnings

                        Changes in version 3.0-4                        

  - First Github-based release
  - Cleaned up documentation for nBinomial1Sample()
  - Updated documentation and code (including one default value for an
    argument) for nBinomial1Sample() to improve error handling and
    clarity
  - Updated sfLDOF() to generalize with rho parameter; still backwards
    compatible for Lan-DeMets O'Brien-Fleming

                        Changes in version 3.0-3                        

  - Introduced spending time as a separate concept from information time
    to enable concepts such as calendar-based spending functions. The
    only user function changed is the gsDesign() function and the change
    is the addition of the parameters usTime and lsTime; default
    behavior is backwards compatible.

                        Changes in version 3.0-2                        

  - Simplified conditional power section of gsDesignManual.pdf in doc
    directory
  - Corrected basic calculation in gsCP()
  - Eliminated deprecated ggplot2 function opts()

                 Changes in version 3.0-1 (2016-02-01)                  

  - More changes to comply with R standards (in NAMESPACE - importFrom
    statements - and DESCRIPTION - adding plyr to imports) ensuring
    appropriate references.
  - Deleted link in documentation that no longer exists
    (gsBinomialExact.Rd).
  - Last planned RForge-based release; moving to Github.

                        Changes in version 3.0-0                        

  - Updated xtable extension to meet R standards for extensions.
  - Fixed xtable.gsSurv and print.gsSurv to work with 1-sided designs
  - Update to calls to ggplot to replace show_guide (deprecated) with
    show.legend arguments where used in ggplot2::geom_text calls; no
    user impact
  - Minor typo fixed in sfLogistic help file
  - Cleaned up "imports" and "depends" in an effort to be an R "good
    citizen"
  - Registered S3 methods in NAMESPACE

                        Changes in version 2.9-4                        

  - Minor edit to package description to comply with R standards

                 Changes in version 2.9-3 (2014-11-10)                  

  - Added sfTrimmed as likely preferred spending function approach to
    skipping early or all interim efficacy analyses; this also can
    adjust bound when final analysis is performed with less than maximum
    planned information. Updated help(sfTrimmed) to demonstrate these
    capabilities.
  - Added sfGapped, which is primarily intended to eliminate futility
    analyses later in a study; see help(sfGapped) for an example
  - Added summary.spendfn() to provide textual summary of spending
    functions; this simplified the print function for gsDesign objects
  - Added sfStep() which can be used to set an interim spend when the
    exact amount of information is unknown; an example of how this can
    be misused is provided in the help file
  - Fixed rounding so that gsBoundSummary, xtable.gsSurv and
    summary.gsDesign are consistent for gsSurv objects
