--- title: "Plan annotation effort, costs, and pilot precision" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{Plan annotation effort, costs, and pilot precision} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE, purl=FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>") options(width = 95) ``` This tutorial illustrates the study-planning workflows in source version 0.5.0. All observations and monetary amounts below are synthetic. No requests are executed and no provider prices are retrieved. | Quantity | Purpose | |---|---| | Distinct pilot items | Information for estimating source variation and coefficients | | Annotations per item | The averaging protocol whose reliability is projected | | Items per request | Shared context and request overhead; not additional repeated measurements | ## Fit a small Gaussian pilot The first example uses independent-item annotations with item, rater and item-by-rater sources. Runs supply replication of those sources through distinct coded cells. This working model defines the example's intended score universe. ```{r pilot} library(Gtheory4LLM) set.seed(2718) panel <- expand.grid(item = 1:24, rater = 1:4, run = 1:3, KEEP.OUT.ATTRS = FALSE) item_rater <- as.integer(interaction(panel$item, panel$rater, drop = TRUE)) panel$quality <- rnorm(24)[panel$item] + rnorm(4, sd = 0.5)[panel$rater] + rnorm(96, sd = 0.4)[item_rater] + rnorm(nrow(panel), sd = 0.8) design <- gt_design("item", c("rater", "run"), random = ~ item + rater + item:rater) control <- gt_control(gaussian = list(extra_tries = 2L, retry_seed = 439L)) fit <- gt_fit(panel, "quality", design, control = control) stopifnot(isTRUE(fit$numerically_accepted)) gt_reliability(fit)$per_trait ``` Acceptance permits the supported projections. It does not establish a global optimum, adequate pilot precision, labeling accuracy or correct source selection for another study. ## Compare costs within a declared allocation grid Here one annotation costs 0.01 illustrative dollars, with a setup cost of two dollars per rater. The cost callback could instead return separate request, token, human-review and expected-retry costs, provided all assumptions use the same currency and are recorded. Costs do not introduce a statistical benefit from review or change the population of raters represented by the fit. ```{r monetary-plan} plan <- gt_plan(fit, candidates = list(rater = c(2, 4, 6), run = c(1, 3, 5)), cost = function(d) list( costs = data.frame(annotation = 0.01 * d$total_annotations, setup = 2 * d$allocation_rater), resources = data.frame(requests = d$total_annotations), assumptions = "Illustrative prices; one item per request."), currency = "USD", cost_date = "2026-10-09", study_items = 1000, target = 0.80, coefficient = "Phi", baseline = 1L, constraints = function(d) data.frame(budget = d$total_cost <= 180)) as.data.frame(plan)[, c("design_id", "total_cost", "screening_value", "feasible", "minimum_cost", "pareto")] head(plan$source_contributions) ``` Minimum cost means minimum among the supplied candidates that meet both the constraints and the selected reliability screen. All candidates remain in the result, including cost ties and infeasible rows. Pareto candidates have no feasible cheaper-or-equal alternative with equal-or-better performance and at least one strict improvement. `screening = "lower"` separately uses an available lower confidence bound. It never replaces a missing bound with a point estimate; these are pointwise intervals, not post-search or future-panel guarantees. `study_items` changes total cost, not the per-item coefficient. Every candidate retains the same declared random/fixed universe. In particular, the planner cannot make a protocol appear more dependable by changing a random facet into a fixed one. ## Make the batch target explicit The next synthetic panel adds a shared shift for each call of six items. Every condition uses the same grouping. A recorded call identifier allows the fit to retain that layout even when rows are reordered. ```{r batch-fit} batched <- panel group <- (batched$item - 1L) %/% 6L + 1L call_index <- as.integer(interaction(group, batched$rater, batched$run, drop = TRUE)) batched$call_id <- paste0("call_", call_index) batched$quality <- batched$quality + rnorm(max(call_index), sd = 0.7)[call_index] batch_design <- gt_design("item", c("rater", "run"), random = ~ item + rater + item:rater, batch = gt_batch(6, id = "call_id")) batch_fit <- gt_fit(batched, "quality", batch_design, control = control) stopifnot(isTRUE(batch_fit$numerically_accepted)) within <- c("1" = 1, "2" = -1) between <- c("1" = 1, "7" = -1) corpus <- setNames(rep(1 / 24, 24), as.character(1:24)) batch_projection <- gt_batch_reliability(batch_fit, contrasts = list(within = within, between = between), aggregate = list(corpus = corpus)) subset(as.data.frame(batch_projection), target_kind != "absolute_item") subset(batch_projection$source_contributions, source == "Call" & target_kind != "absolute_item") ``` A shared call shift cancels from the same-batch difference, remains in the between-batch difference, and contributes to each absolute item score. A corpus mean has another error target: call shifts average over calls, while common rater shifts remain. Weighted aggregates can depend on how weights are spread across groups. None of these effects can be represented by one universal batch penalty. ```{r batch-design-study} batch_study <- gt_batch_dstudy(batch_fit, expand.grid(rater = c(2, 4), run = c(1, 3)), contrasts = list(within = within, between = between), aggregate = list(corpus = corpus)) subset(as.data.frame(batch_study), target_kind == "contrast") ``` The data frame includes `allocation_rater`, `allocation_run`, batch size and uncertainty availability in ordinary columns. These survive CSV export alongside the target and coefficient labels. Save the projection object separately when the complete item grouping and target weights are needed. These are point projections conditional on the fitted grouping. Facet counts change under exchangeability assumptions; item count, grouping, batch size and fitted source covariances do not. All instrumentation facets remain random. Aggregate error is annotation error conditional on the selected items, not uncertainty from sampling a corpus. Contrast and aggregate ratios have explicit names; they are not universal item-ranking G coefficients. Sampling intervals are not provided. Ordinary `gt_reliability()`, `gt_dstudy()` and the monetary `gt_plan()` refuse modelled `Call` fits. The separate batch functions make their target explicit. A fit keeps the compact item-to-batch labels even with data retention disabled; projection objects contain those labels and target weights. Portable `gt_report(fit)` and HTML output exclude them. ## Examine pilot precision for one final protocol More pilot information may improve coefficient estimation without changing the protocol eventually used for every item. The example varies pilot item and rater counts, but every refit estimates the same four-rater, three-run target. ```{r pilot-precision} precision <- gt_pilot_plan(fit, grid = data.frame(n_items = c(16, 24), rater = c(3, 4)), target_counts = c(rater = 4, run = 3), nsim = 2, seed = 2026, coefficient = "Phi", width_target = 0.25) precision$summary precision$replicates[, c("design_id", "replicate_id", "status", "accepted", "interval_available", "interval_conditional", "width", "acceptance_failures", "selected_attempt")] ``` Two simulations per candidate only exercise the software. They cannot support a pilot-size recommendation. Set a predeclared simulation budget and inspect Monte Carlo uncertainty before using the results for planning. Every attempted replicate remains in the ledger. Precision success requires an available interval meeting the width target, so errors, refusals and unavailable intervals are non-successes. Mean widths condition on an available interval and show that denominator. Conditional boundary intervals retain their qualification. Numerically refused rows retain the fit's acceptance-failure codes and selected attempt identifier; errors before a fit is returned have unavailable diagnostics. The data and retry seeds allow an individual attempt to be replayed. The simulator draws new items and new levels of every random facet from a fitted or explicitly supplied Gaussian parameter scenario. It does not calibrate coverage, integrate parameter uncertainty automatically, or provide bootstrap confidence intervals. The initial simulation scope excludes batch declarations and discrete outcomes. A model-based precision exercise does not establish study adequacy when its scenario or facet universe is inappropriate.