# weightflow 0.2.0

## New features

* **Tidy population totals for `step_calibrate()`.** In addition to the classic
  `margins`/`totals` inputs (which keep working unchanged), calibration targets
  can now be given as tidy data frames, paired with the new `count` argument
  that names the counts column:
    - *Post-stratification*: a data frame with one or more category columns plus
      a counts column. Several category columns are crossed automatically, so
      there is no need to build a collapsed cell variable by hand.
    - *Raking*: a list of data frames, one per margin.
    - *Linear/GREG*: a named list matching the formula terms, with a data frame
      (all categories) for each factor and a single number for each continuous
      total; weightflow builds the model.matrix totals internally, so the user
      never drops a reference category or handles the intercept.
  Calibration also reports clearer diagnostics and warnings: post-stratification
  flags cells in the sample but missing from the totals (error) or in the totals
  but absent from the sample (warning); raking warns on mutually inconsistent
  margins or non-convergence; linear calibration warns when the constraints are
  not fully satisfied; and calibration variables with missing values raise an
  informative error.
* **Subsampling of more than one person per household in `step_select_within()`.**
  A new `n_selected` argument (a single number or an unquoted column) works
  alongside `n_eligible` for simple random selection of a subsample: the weight is
  multiplied by `n_eligible / n_selected` (equivalent to
  `prob = n_selected/n_eligible`). It defaults to 1, so selecting a single person
  keeps working unchanged.
* **External consistency totals for `step_model_calibration()`.** The totals of
  the `x_formula` auxiliaries can now be supplied through the new `x_totals`
  argument, in the same two shapes as `step_calibrate(method = "linear")`: the
  tidy format (a named list with a data frame per factor, paired with `count`,
  and a single number per continuous total) or the classic model-matrix vector.
  This covers the common case where the X control totals come from an external
  source rather than from the frame; the auxiliaries then need to be present only
  in the sample, not in `population`. When `x_totals` is `NULL` (default) the X
  totals are still taken from `population`, so existing code is unchanged.
  `population` remains required, because the model-assisted block predicts each
  outcome over every population unit. Model calibration now also warns, like
  linear calibration, when the achieved totals do not fully satisfy the
  constraints (collinear or ill-conditioned auxiliaries).
* **Delete-a-PSU jackknife variance (recipe-aware).** `jackknife_weights()`
  builds jackknife replicate weights by deleting one PSU at a time and re-running
  the whole recipe on each replicate, so the replicate weights carry the
  variability of every adjustment. It is the stratified jackknife (JKn) with
  `strata`/`psu`, the unstratified jackknife (JK1) with `strata = NULL`, and the
  delete-one-unit jackknife with `psu = NULL`. `jackknife_estimate()` (plus
  `jack_total()` / `jack_mean()`) summarise a statistic with the JKn variance and
  match `survey`'s replicate jackknife for totals. `as_svrepdesign()` now also
  accepts a jackknife object, so the recipe-aware replicate weights flow into
  `survey`/`srvyr` for any estimand and any domain.
* **Domain (partitioned) calibration in `step_calibrate()`.** A new `by`
  argument names a domain (partition) column; the weights are then calibrated
  **independently within each domain**, each to its own totals (partitioned /
  domain calibration). The tidy totals carry the domain as a
  column, and a continuous total becomes a data frame `domain, value` (one total
  per domain); the domain variable does not go in the formula/margins. It
  composes with `calfun`, `bounds`, `penalty` and `equal_within_cluster`, applied
  within each domain, and reproduces every domain's benchmarks. `by = NULL`
  (default) calibrates globally, unchanged.
* **Exponential (raking) distance for `step_calibrate(method = "linear")`.**
  `calfun` now also accepts `"raking"` (the multiplicative distance g = exp(u)),
  next to `"linear"` and `"logit"`. It keeps the calibration weights positive
  without needing explicit `bounds` and still satisfies the constraints exactly,
  and works on mixed categorical and continuous auxiliaries as well as with the
  integrative option (`equal_within_cluster`, one weight per cluster). Matches
  `survey::calibrate(calfun = "raking")`.
* **R-indicator of response representativity (automatic diagnostic).** When the
  recipe includes a nonresponse adjustment, `summary()` and `report_weighting()`
  now report the R-indicator (Schouten, Cobben & Bethlehem), R = 1 - 2*S, with S
  the design-weighted standard deviation of the estimated response propensities
  over the eligible sample: closer to 1 means a more representative response and
  less nonresponse-bias risk. The report also shows the unconditional partial
  R-indicators by auxiliary, pointing to which variable drives the lack of
  representativity. It is computed on the auxiliaries of the nonresponse step and
  needs no new function or user action; recipes without a nonresponse step are
  unaffected.
* **Machine-learning response propensities** (CART, random forest and gradient
  boosting via `xgboost`) for `step_nonresponse()` and `step_model_calibration()`.
* **k-fold cross-fitting** (`crossfit`) to estimate each unit out-of-sample,
  with folds formed by cluster to avoid leakage.
* **Ridge (penalized) calibration** (`penalty`) to keep weights stable with many
  auxiliaries.
* **Potter MSE-optimal trimming** (`method = "potter"`), a data-driven cutoff.
* **Quality alerts in `prep()`.** `prep()` now computes non-fatal quality alerts
  and stores them on the prepped object (`$alerts`) and per step: negative or
  sub-1 weights and g-factors outside the Deville-Särndal bounds `[0.1, 10]`
  after calibration, small adjustment cells (new `min_cell_n`, default 30,
  following Kalton and Flores-Cervantes 2003) and excessive adjustment factors
  (new `max_factor`, default 2.5). Alerts always appear in the HTML report; set
  `prep(warn = TRUE)` to also raise them as R warnings.
* **Weight distribution and alerts in `report_weighting()`.** The report gains a
  "Weight distribution (final)" summary (min, p1, median, p99, max, max/min ratio,
  and counts of negative, sub-1 and extreme weights) and a per-step "Quality
  alerts" block.
* **New `disposition` column in the `sample_one` example data.** A single factor
  with the full field disposition (eligible respondent, eligible nonrespondent,
  household nonresponse, ineligible, unknown eligibility), recoded from the
  existing indicator columns (which are kept). It gives a tidy single-column view
  of the dispositions and can be used directly via logical conditions in the
  steps.
* **New vignette "Preparing the sample: eligibility and response before
  weighting"**, on how the input sample should be classified (the disposition
  tree), how it is sized (eligibility and response inflation) and how the
  dispositions map to the adjustment steps.

## Bug fixes

* The optional machine-learning engines (`engine = "forest"` via ranger,
  `engine = "boost"` via xgboost) now run single-threaded by default, for
  reproducibility and to respect CRAN's check limits. Set
  `options(weightflow.num_threads = n)` to use `n` threads.

* `report_weighting()` now flags calibration steps that did not converge. When a
  raking, linear or bounded calibration stops without satisfying the requested
  totals (the same condition that already prints a console warning), the HTML
  report shows a "Did not converge" alert on that step and no longer states that
  the step converged. Previously the report always reported convergence,
  regardless of the actual result.

* `step_calibrate(equal_within_cluster = TRUE)` now implements the genuine
  Lemaitre-Dufour (1987) integrative method: each unit's auxiliaries are
  replaced by their household mean before a person-level calibration, so the
  per-household penalty scales with household size. This matches `survey`'s
  `calibrate(aggregate.stage = )` (Vanderhoeft 2001), ReGenesees and Statistics
  Canada's GES. The previous implementation used a household-level distance
  (summed auxiliaries, uniform per-household penalty), a different (non-standard)
  method. Integrative-calibration weights will change; totals are still met
  exactly and weights remain constant within household.

# weightflow 0.1.0

First release.

A dependency-free, pipeable API to compute survey weights from design base
weights through a chain of hierarchical adjustment stages. Build a recipe
lazily, estimate it with `prep()`, and extract the weights with
`collect_weights()`. Separating *define* from *apply* makes the whole process
reproducible and auditable, and lets the bootstrap re-run the entire cascade on
each replicate.

## Adjustment steps

* `step_unknown_eligibility()`: redistribute the weight of unknown-eligibility
  cases to the known ones (person- or household-level via `cluster`).
* `step_drop_ineligible()`: zero out out-of-scope units.
* `step_select_within()`: within-household selection (unequal `prob` or equal
  `n_eligible`).
* `step_nonresponse()`: weighting-class or propensity adjustment, at the person
  or household level (`cluster`).
* `step_calibrate()`: raking, post-stratification and linear/GREG calibration,
  with bounded (Deville-Särndal) and integrative (one weight per household)
  cluster options.
* `step_model_calibration()`: Wu-Sitter model calibration.
* `step_trim()`, `step_trim_weights()`, `step_round()`, `step_rescale()`:
  trimming, rounding and rescaling.
* `step_assert()`: quality checkpoint (deff, weight ratio, effective n).

## Inspection and reporting

* `summary()`, `plot()` and `weight_factors()` for per-stage diagnostics.
* `design_effect()` for the Kish design effect and effective sample size.
* `report_weighting()` builds a self-contained HTML report with a pipeline
  diagram, the variables used, per-stage summaries and per-step visuals.

## Variance estimation

* `bootstrap_weights()` resamples PSUs within strata (Rao-Wu rescaling) and
  re-applies the whole recipe on each replicate, so the replicate weights carry
  the variability of every adjustment.
* `boot_mean()` and `boot_total()` return the estimate, standard error and CI.
* `as_svydesign()`, `as_svrepdesign()` and `collect_replicate_weights()` bridge
  to the `survey` and `srvyr` packages for design-based inference.

## Data

* Bundled example datasets `population`, `sample_survey` (take-all roster) and
  `sample_one` (multistage select-one design), all with stratum, PSU and design
  weight.
