← All posts

2026-08-25 · 6 min read

Double Programming Without the Duplication: AI-Generated QC Code

#qc-programming#clinical-trials#llm-agents#adam#validation

Every statistical programmer knows this scene. Production finishes the ADaM dataset. Then a second programmer — the QC programmer — opens the same specification and writes the same derivations again, from scratch, deliberately without looking at the production code. Both parse identical specs. Both implement the same edge-case handling. QC effort scales linearly with production, at an estimated 30–50% of total clinical programming effort (Lyons & Bae, PharmaSUG 2023).

That duplication is the price of independence. In our PharmaSUG 2026 paper (AI-201, with Jason Zhang), we asked whether an AI agent can generate the QC side of that pair — while keeping the operational independence that makes double programming worth paying for.

TL;DR — A Claude-based workflow generates independent QC code in Python directly from ADaM specifications, using a QC Trace Tree, a Decision Router, and an automated code review engine. On the CDISCPilot01 benchmark it matched 97.1%–100.0% of variables across five ADaM domains and passed all 13 property-based assertions — with the human QC programmer kept as the genuinely independent judgment layer.

Why “just have AI write the QC code” fails

Two failure modes kill the naive version. The obvious one: if the QC instance sees the production code, it is not independent QC — it is copy-editing. The subtler one: if both instances share model weights, they tend toward the same systematic misreadings of the spec. That is the common-cause failure problem from the N-version programming literature, applied to LLMs.

The framework therefore enforces operational separation at the infrastructure level, not as a prompting convention:

One point the paper is explicit about: the human QC programmer is the genuinely independent judgment layer. The second AI instance is not what mitigates same-model bias — the human reviewer is.

Three mechanisms that make the output auditable

Before any code is written, three author-built components shape the agent’s work:

The trace tree looks like this in practice (ADSL excerpt):

ADSL QC Trace Tree (31 nodes)
|-- TRTSDT [Spec: 3.1 Row 10] (standard)
|   |-- Source: SDTM.EX.EXSTDTC
|   |-- Logic: MIN(datepart(EXSTDTC)) per USUBJID
|   |-- Edge cases: partial dates -> FLAGGED (spec silent)
|   |-- Ambiguities: 1 (partial date handling)
|   +-- Verify: type=date, TRTSDT <= TRTEDT

The human reviews the tree, resolves flagged ambiguities, and only then does code generation proceed — with code comments referencing tree nodes.

The four-gate Decision Router routing datasets to full AI generation, AI with enhanced review, or manual QC

Figure 1: The Decision Router’s four gates and three routing outcomes, with benchmark routing results annotated.

What the benchmark showed

We evaluated against the CDISCPilot01 eSubmission Benchmark: 254 ITT subjects and five ADaM domains, across 138 trace tree nodes and 51,294 matched records.

MetricResult
ADaM domains5 — ADSL, ADAE, ADADAS, ADLBC, ADTTE
Variable-level match vs ground truth97.1%–100.0% (ADTTE 6/6; ADADAS lowest at 97.1%)
Property-based assertions13/13 passed (TRTSDT ≤ TRTEDT, BASE = AVAL at baseline, CNSR ∈ {0,1}, …)
Router decisions4 datasets to full AI generation; ADSL to enhanced review (5 complex variables, 6 ambiguities)
Code review findings207 across 7 SOP categories, including 1 high-severity data leakage risk
End-to-end run time~84 minutes, of which 46 (55%) was human trace-tree review

Table 1: CDISCPilot01 benchmark outcomes for the AI-generated QC workflow.

The single high-severity finding deserves a pause. The review engine caught the agent reading the ground-truth ADSL to infer an unspecified SITEGR1 pooling threshold — exactly the independence violation the engine exists to catch. The mechanism worked on the failure it was built for.

Every remaining mismatch traced to a specification ambiguity the trace tree had already flagged before code generation: visit windowing rules (ADADAS AVISITN at 90.9%), baseline visit selection (WEIGHTBL at 93.7%), and coding conventions (ANRIND at 96.2%).

On efficiency: practitioners familiar with these datasets estimate manual QC at 3–5 programmer-days. The full run was roughly one day of human–AI collaboration. That comparison needs real-world validation before anyone budgets against it.

Where the framework fell short

The manuscript is honest about the limits, and so am I:

Key takeaways

FAQ

Does AI-generated QC code still count as independent QC?

Only if independence is enforced structurally. In this framework the QC instance runs in a separate API session, receives only specifications and SDTM data, and is blocked from production artifacts — with a human QC programmer as the final independent judgment. If the QC instance can see production code, it is copy-editing, not QC.

What happens when the specification is ambiguous?

The QC Trace Tree forces the agent to flag ambiguities before any code is written, and the human resolves them at tree-review time. In the benchmark, every residual mismatch traced back to one of these flagged ambiguities — visit windowing, baseline selection, and coding conventions.

How much time does this actually save compared with manual QC?

On CDISCPilot01, the full run took about 84 minutes for five datasets, 46 of them human review, against an estimated 3–5 programmer-days for manual QC. That is one clean benchmark with one model, so treat it as a directional signal, not a planning number.


Full details, including the decision router breakdown and the complete code review rule reference, are in the full paper from PharmaSUG 2026. The experiment code is public at github.com/yanmingyu92/ai-qc-code-generation.

Originally published at jaimeyan.com.