Released: 2026-09-14
waive() gave the spuriously precise estimates it is meant to discount more weight, not less. The second-stage rows are divided by the returned weights, so an estimate's least-squares weight is 1 / weights^2; multiplying by the square root of the exponential-decay weight therefore applied 1 / decay, and an estimate at the 0.05 floor got up to 20 times the weight of an unpenalized one. The rows are now divided by the square root of the decay weight, so the least-squares weight is decay (times the base weight 1 / base_w^2 when weight is 1, 2, or 3). WAIVE estimates, standard errors, and test statistics move whenever the decay weights differ across estimates; maive() is unaffected. On the simulated data in #30 the WAIVE PET intercept goes from 0.381 to 0.223, which is the lm() fit with weights decay. result$weights keeps its meaning as the row divisor (now documented in ?maive), so under waive() with weight = 0 it is 1 / sqrt(decay). get_funnel_plot() sizes WAIVE points by 1 / weights^2, so the downweighted estimates are still drawn smallest (#30).
Study weights (weight = 3) now give an estimate from a study with k estimates the least-squares weight 1/k, so every study carries the same total weight. The second stage divides each row by the weight vector, which makes the regression weight its inverse square, and code 3 returned 1/k, so estimates entered with weight k^2 and large studies dominated. Estimates, standard errors, and Hausman statistics with study weights will move, in maive() and in waive(), which combines its decay weights with the study weights. Codes 0, 1, and 2 are unchanged. The returned weights element is now sqrt(k) for code 3, consistent with codes 1 and 2, which return the standard error each row is divided by (#29).
EK (method = 4) now handles bias on the negative side. The kink location was computed only when the PET-PEESE intercept exceeded 1.96 * sigma_h, so a negative intercept never kinked and EK silently returned PET. It now uses the absolute intercept: the kink location is a distance along the standard-error axis and the kink slope is free, so EK on -bs gives exactly minus EK on bs, the same as reversing the sign, running EK and reversing back. Results for a positive intercept are unchanged; EK estimates move for data with a negative PET-PEESE intercept (#31).
The Anderson-Rubin intervals now use the second stage's own weights, 1 / w^2 of the final weight vector. Previously they were weighted only for weight = 2, so with study weights (weight = 3) and in waive() with weight = 0 or 3 they were computed unweighted, and waive() with weight = 2 dropped the decay. AR_CI and egger_ar_ci from maive() with weight = 0 or 2 are unaffected by this change. AR stays off for weight = 1 (#32).
The subset Anderson-Rubin interval for the Egger slope (egger_ar_ci) scales its intercept by the square root of the weights, like the estimates, the regressor and the instrument. The unscaled intercept absorbed every candidate slope under weight = 2, where the scaled PET regressor is constant, so the weighted Egger AR interval came back as the whole search grid or NA; it is now finite and covers the weighted Egger estimate. Weighted Egger AR intervals (weight = 2 or 3, and waive()) change; unweighted ones do not, since the scaled intercept is then a column of ones (#32).
Released: 2026-09-11
studylevel 1 or 3). With one estimate per study and studylevel 0 or 2, a single exclusion previously aborted an analysis that runs without the study_id column (#24, #23).Released: 2026-09-10
first_stage = 1 in maive() and waive(), and a call that omits first_stage (or passes NULL) fits the log specification. The log stage regresses log(sebs^2) on log(Ns) with a smearing retransformation, so its fitted variance is always positive and no estimate can drop out of the second stage; it also predicts held-out variances better and degrades more gracefully when the instrument is weak. It improves on the published version, and estimates on existing data will move. Pass first_stage = 0 to reproduce the levels first stage from the paper (Irsova et al., 2025); that specification is unchanged and stays under test.first_stage = 0) can fit a negative variance for an individual estimate. Previously sqrt() turned it into NaN, lm() dropped the row from PET but not from PEESE, the F-test, or the Hausman comparison, so the reported statistics used different samples, the AR interval came back NA, adjusted-weight AR aborted, and EK aborted. Such estimates are now excluded explicitly from everything built on the instrumented standard error (weights, PET, PEESE, PET-PEESE, EK, the F-test, the Hausman comparison, the Anderson-Rubin intervals, the wild bootstrap), so every reported statistic uses the same rows. A warning names the count and points to first_stage = 1 (the log first stage), which cannot fit a negative variance. The fitted variance is not floored: a floored value would enter PET as an almost perfectly precise observation and, under weight = 2, as a weight of order 1/eps (#24).maive_from_metafor() refuses metafor::trimfill() fits (class rma.uni.trimfill). They inherit rma.uni, so the imputed studies previously entered MAIVE as observed estimates, each carrying the sample size of the study it mirrors. Pass the original rma() fit (#23).maive_from_metafor() no longer trusts an ni column, the fit's ni slot, or the ni attribute on the effect sizes on length alone. Each is used only when it agrees with n1i + n2i wherever both are present; otherwise it falls through to the two-group total. The attribute does not follow a reorder such as dplyr::arrange(), and rma() copies the stale vector into the fit, so both entry points previously bound every sample size to the wrong estimate (#23).study_id fallback never picks a column already mapped through estimate, se, or n. The fourth column is still used when it is free; when it is mapped, the single remaining column is used instead (the warning then says "the only unmapped column"), and when several remain an error names the candidates and asks for study_id. At studylevel = 0 the ambiguous case is skipped silently, since no identifier is needed (#23).studylevel 1 or 3). A positionally inferred identifier such as a year column no longer aborts an analysis at studylevel = 0 or 2 that never uses it as a fixed effect (#23).studylevel is 1, 2, or 3 and the data has no study identifier, maive() and waive() warn once that the study-level options have no effect instead of silently running as studylevel = 0 (#23).maive() and waive() return n_excluded (the number of excluded estimates, 0 with the log first stage) and excluded_rows (their positions in the input after empty rows are dropped). SE_instrumented and weights keep the input length with NA (never NaN) in the excluded positions.Released: 2026-09-03
maive_from_metafor() converts a metafor escalc data frame or an rma.uni fit into the data frame maive() and waive() expect. It takes the standard error as sqrt(vi), so metafor's sampling variance cannot land in the sebs slot by mistake (which silently shifts the estimate), and it resolves sample sizes from ni, the ni column, the ni attribute escalc() stamps on the effect sizes, or n1i + n2i, never from the variance. rma.uni rows are taken through the fit's subset and missing-value masks so effects, variances, sample sizes, and study identifiers stay aligned. rma.mv, rma.glmm, and other rma subclasses are refused with a message. metafor is a suggested dependency only.Released: 2026-09-03
estimate, se, n, and study_id are resolved before the data frame is validated, so the documented custom column example in the vignette runs (it previously failed with "Missing required columns: bs, sebs, Ns"). Completely empty rows are still dropped before resolution.seed argument now reaches the wild bootstrap (SE = 3). Previously the helper always used seed 123, so different seeds gave identical bootstrap confidence intervals and seed = NULL did not use the current RNG state. The reported SE under SE = 3 is the CR1 cluster-robust SE and is unchanged; only the bootstrap confidence intervals (for example egger_boot_ci) depend on the seed, and a non-default seed now changes them.studylevel = 0 and 1 run, and studylevel = 2 and 3 surface clubSandwich's own message that clustering needs more than one cluster. Results on multi-study data are unchanged.beta_standard at method = 3 (PET-PEESE) now comes from the same conventional fit as SE_standard. It was previously read from the auxiliary PET-PEESE model that uses MAIVE's own weights, so the returned pair mixed two regressions and beta_standard moved with weight while SE_standard did not. This is a deliberate change to the reported value at method = 3; methods 1, 2, and 4 are unaffected, and the Hausman statistic still uses the auxiliary pair and is unchanged.maive() and waive() return ek_structure ("kink", "linear", or "intercept") for method = 4, so an intercept-only degenerate EK fit is identifiable directly rather than inferred from a zero slope coefficient. It is NA for other methods.study_id argument is given and no column is named study_id, using the fourth column as the study identifier now emits a warning naming the column. Pass study_id = "<column>" to confirm the mapping, or drop the column if it is not a study identifier. A column named study_id is used regardless of its position.maive() documents the study_id fallback and the origin of beta_standard and SE_standard.Released: 2026-08-05
Released: 2026-02-04
Released: 2026-02-04
Released: 2026-01-07
Released: 2026-01-07
Released: 2026-01-07
Released: 2026-01-07
Released: 2025-12-18
Released: 2025-12-02
Released: 2025-12-02
Released: 2025-11-27
Released: 2025-11-27
Released: 2025-11-26
maive(): Main function implementing PET, PEESE, PET-PEESE, and Endogenous Kink (EK) methodswaive(): Robust extension with downweighting of spurious precision and outliers