--- title: "Verified, outcome-blind weighting in WFC 2.0" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Verified, outcome-blind weighting in WFC 2.0} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", message = FALSE) ``` This workflow keeps study outcomes out of target selection, cell merging, and weight planning. It has two entry styles: - practitioners can use `wf_guided_plan()` to compose the safe planning steps; - statisticians and AI Agents can call each lower-level step and inspect every intermediate object. Both styles stop before approval. A separate human attestation is required to execute a plan. Decision makers can receive a compact report, while statisticians can receive the complete evidence tables. ## Start with design-only and analysis data The design table contains only fields with declared sampling or calibration roles. Outcomes remain in a separate table joined later by a unique ID. ```{r} library(WFC) dims_safe <- wf_dims( sex = c("F", "M"), age = c("18-34", "35+") ) design_frame <- data.frame( id = sprintf("r%02d", 1:16), sex = rep(c("F", "M"), 8), age = rep(c("18-34", "18-34", "35+", "35+"), 4), base_weight = 1, stringsAsFactors = FALSE ) analysis_frame <- data.frame( id = design_frame$id, satisfaction = seq(40, 70, length.out = 16), approved = rep(c(0, 1), 8), stringsAsFactors = FALSE ) design <- wf_prepare_design( design_frame, id = "id", calibration = c("sex", "age"), base_weight = "base_weight" ) design ``` If `analysis_frame` or either outcome column were passed to `wf_prepare_design()`, construction would stop with `wf_error_safety` because the outcome column has no permitted design role. ## Import a target with its own evidence record WFC installs matching synthetic CSV and Excel examples: - `safe-target-example.csv` and `safe-target-example.csv.source.dcf`; - `safe-target-example.xlsx` and `safe-target-example.xlsx.source.dcf`. Each data file has a distinct SHA-256, even though the tables have identical content. The DCF record names the publisher, dataset, citation, reference period, population scope, retrieval date, license, transformation, selection timing, and demo status. ```{r} csv_file <- system.file( "extdata", "safe-target-example.csv", package = "WFC" ) csv_source <- paste0(csv_file, ".source.dcf") cat(paste(readLines(csv_source, warn = FALSE), collapse = "\n")) target_verified <- wf_import_target( csv_file, csv_source, dims_safe, key_map = c(sex = "sex", age = "age"), count = "count", production = FALSE ) target_verified$identity ``` `production = FALSE` is required only because the bundled file is explicitly a demo. Do not use that setting to import an authoritative production source that has incomplete evidence. Excel uses the same import form and its own companion evidence file: ```{r} xlsx_file <- system.file( "extdata", "safe-target-example.xlsx", package = "WFC" ) if (requireNamespace("openxlsx", quietly = TRUE)) { target_from_excel <- wf_import_target( xlsx_file, paste0(xlsx_file, ".source.dcf"), dims_safe, key_map = c(sex = "sex", age = "age"), count = "count", production = FALSE ) identical(target_verified$groups, target_from_excel$groups) } ``` Use `wf_target_template()` to create a blank data file and companion DCF for a new source. Blank metadata and `selected_before_outcomes: false` deliberately block import until an accountable person completes the evidence record and updates the checksum. ## Plan without calculating weights The bundled example stops here by design: a `demo_only` target can demonstrate import and checksum verification but cannot enter planning. The remaining code is a runnable template after `csv_file` and `csv_source` are replaced with a completed, authoritative external source and `wf_import_target()` is called with its default `production = TRUE`. It is not evaluated during vignette build because no synthetic file may impersonate that authority. Cell planning uses only sample support, base weights, declared category order or an explicit ladder, and the verified target. It cannot receive outcomes or a custom score. It never crosses the target boundary or widens limits. ```{r controlled-plan, eval=FALSE} cell_plan <- wf_plan_cells( design, target_verified, dims_safe, min_cell = 5, max_weight_ratio = 4 ) plan <- wf_plan_weights( design, target_verified, dims_safe, method = "raking", bounds = c(0.3, 3), min_cell = 5, cell_plan = cell_plan ) plan$precheck is.null(plan$weights) ``` The practitioner composition produces the same kind of reviewable plan and still computes no weights: ```{r guided-plan, eval=FALSE} guided <- wf_guided_plan( design_frame, id = "id", calibration = c("sex", "age"), dims = dims_safe, target_file = csv_file, source_file = csv_source, source_type = "population", key_map = c(sex = "sex", age = "age"), count = "count", base_weight = "base_weight", production = FALSE ) wf_report(guided, audience = "decision")$table names(wf_report(guided, audience = "statistician")$sections) ``` ## Keep approval separate from execution The next lines are intentionally not run while building this vignette. They represent two accountable actions: a human reviewer attests approval, then the approved plan is executed exactly once. Replace the illustrative identity with the actual reviewer; an automated process must not fill it in. ```{r approval-and-execution, eval=FALSE} approval <- wf_approve_plan( plan, approver = "Reviewer name", role = "statistician" ) locked <- wf_execute_plan( plan, approval, design, target_verified ) ``` An AI Agent can prepare and inspect the plan but cannot attest its own approval: ```{r agent-refusal, eval=FALSE} agent_refusal <- tryCatch( wf_approve_plan( plan, approver = "Agent", role = "assistant", actor_type = "agent" ), wf_error_safety = function(condition) condition$data ) agent_refusal[c("code", "severity", "next_actions")] ``` There are no force, bypass, ignore-source, auto-approve, auto-relax, auto-widen, or silent method-switch flags. ## Attach outcomes only after locking After execution, attach the immutable weight by exact ID. Impact assessment computes fixed descriptive means or proportions and never calls planning or calibration code. ```{r post-lock, eval=FALSE} analysis_ready <- wf_attach_weights( analysis_frame, locked, id = "id", weight_name = ".weight" ) impact <- wf_assess_impact( locked, analysis_frame, id = "id", outcomes = c("satisfaction", "approved") ) wf_report(locked, audience = "decision") wf_report(impact, audience = "statistician") wf_audit_export(impact, "impact-audit.json") ``` ## Agent contract Non-interactive callers should catch `wf_error_safety` and read its stable payload fields: `code`, `severity`, `field`, `evidence`, and `next_actions`. They should report the condition, preserve the identities already produced, and request the listed human action. They must not edit object fields, manufacture an approval, retry with wider limits, or select a new target after seeing study outcomes.