# LISTC — Large-scale Item-response Statistical Table Constructor

LISTC turns assessment/survey sample data (demographics, weights, scores,
ability estimates theta with individual IRT standard errors, item responses)
into pivot-style statistical tables. Every cell carries an estimate and a
standard error combining sampling variance and measurement variance
propagated from individual IRT SEs.

## Recommended interface for agents

Generate a YAML or JSON configuration and call:

    library(LISTC)
    result <- lst_run("config.yml")

Config schema: inst/schema/config.schema.json (validate before running).
Minimal config:

    data: students.sav          # csv/xlsx/sav/dta/sas7bdat
    roles:
      id: student_id
      weight: w_final
      group: [region, gender]
      theta: {math: th_math}
      theta_se: {math: se_math}
    tables:
      - name: mean_by_region
        rows: [region]
        cols: [gender]
        values:
          mean: {stat: st_mean, var: math}
          excellent: {stat: st_prop_above, var: math, cutoff: 1.2,
                      method: prob}
        format: est_se
    output:
      xlsx: results.xlsx
      json: results.json

The JSON output contains: tidy long results (group combination x statistic
x estimate/se_sampling/se_measurement/se_total), per-statistic metadata
(method, n, sum of weights), and an `interpretation` field with rule-based
plain-language conclusions.

Config can also be an Excel workbook filled from the bundled template
(lst_config_template() writes it); same structure as YAML.

## Function-level API (alternative)

    d <- lst_data(df, id=, group=, weight=, theta=, theta_se=, resp=, key=)
    tab <- lst_table(d, rows=, cols=, values=list(...), format="est_se")
    as_long(tab); as_wide(tab)
    lst_to_excel(tab, "out.xlsx"); lst_to_json(tab)
    read_winsteps_pfile("p.txt"); read_conquest_person("c.wle")
    lst_join_person(d, person, dim = "math")

Statistics: st_mean, st_prop_above, st_level_prop, st_quantile, st_sd,
st_count, st_wcount, st_pvalue (item p-values), st_option_dist.
method="prob" uses each person's theta SE for probabilistic classification.
correction: use "none" when theta is an EAP estimate with posterior SD
(already calibrated); use "latent" when theta is a WLE/ML estimate with
sampling SE (empirical-Bayes shrinkage to the latent distribution;
supply rho or let LISTC estimate reliability from the data).

## Replicate weights (v0.3)

For PISA/TIMSS-style cluster samples, declare replicate weights and the
sampling variance switches to the replicate engine (measurement variance
from individual SEs is still added on top):

    roles:
      rep_weights: W_FSTR     # prefix -> W_FSTR1..80, or explicit array
      rep_method: fay         # fay (PISA) | brr | jk1 | jk2 (TIMSS)
      fay_k: 0.5              # fay only, default 0.5

## Plausible values (v0.4)

Declare PVs and all statistics on that dimension use Rubin combination
(total variance = sampling U + (1+1/M)*B imputation). Combine with
rep_weights for the full PISA variance recipe:

    roles:
      pv: {math: "PV#MATH"}   # '#' = PV number, expands to PV1MATH..
      pv_sampling: first      # first (PISA manual) | average
      rep_weights: W_FSTR
      rep_method: fay

Do NOT use method: prob on PV dimensions (they already carry
measurement uncertainty; use hard classification, Rubin handles the
rest). Output option `html:` writes a styled standalone report
(lst_to_html, dependency-free).

## Cautions

- theta and theta_se must be paired per dimension.
- correction="latent" is for WLE/ML estimates only; EAP needs "none".
- SEs assume independent measurement errors across persons; replicate
  weights and plausible values are planned for later versions.
