Review ask

As a clinical trial statistician or programmer, challenge anything in this benchmark: describe a problem in Comments, or propose a fix with the Edit button on any source file.

  1. Task: Would a real study need this derivation, specified this way? Does it follow CDISC ADaM: variable names, controlled terms, record structure? Flag any rule that is ambiguous or that a sponsor would handle differently.
  2. Inputs: Do they look like data collected in a real trial, and do they include the situations you would expect to meet in one?
  3. Expected output: Would independent QC programming reproduce every value from these inputs and rules?

The other tabs beside Comments are background for assessment, not under review.

Summary

Lifecycle: reviewedEditUnder review
What this benchmark means
README.md

Goal: carry each physical functioning item response into PARAMCD, PARAM, and AVAL, and add a subscale score record coded PFSCORE holding the mean answered-item response multiplied by 25 (mean divided by four, times 100).

Input: collected questionnaire responses for the physical functioning scale, with study, subject, and visit (STUDYID, USUBJID, VISIT), category (QSCAT), test code and test name (QSTESTCD, QSTEST), and numeric result (QSSTRESN) on the zero to four answer scale. One record on the emotional functioning scale is included and excluded from the output, showing that only the physical functioning records feed the dataset.

Variables:

  • PARAMCD: the test code (PF01 through PF04) on an item record, or PFSCORE on the added score record.
  • PARAM: the test name on an item record, or the subscale name on the added score record.
  • AVAL: on an item record, the numeric result on the zero to four answer scale, empty when the item was not answered; on the score record, the mean of the answered items at that visit multiplied by 25, empty when fewer than three of the four items were answered.

Note: every visit with a PF01 item record, answered or not, carries a score record, so a visit with too few answers to score keeps an empty score and stays apart from a visit with no records at all.

Inputs

Under review
1 source file

input/qs.csv

Edit
21 rows
input/qs.csv
STUDYIDUSUBJIDVISITQSSEQQSCATQSTESTCDQSTESTQSSTRESN
PILOT7BASELINE1PHYSICAL FUNCTIONING SCALEPF01Trouble with strenuous activity2
PILOT7BASELINE2PHYSICAL FUNCTIONING SCALEPF02Trouble with a long walk0
PILOT7BASELINE3PHYSICAL FUNCTIONING SCALEPF03Trouble with a short walk2
PILOT7BASELINE4PHYSICAL FUNCTIONING SCALEPF04Needs to stay in bed or a chair1
PILOT7WEEK 125PHYSICAL FUNCTIONING SCALEPF01Trouble with strenuous activity3
PILOT7WEEK 126PHYSICAL FUNCTIONING SCALEPF02Trouble with a long walk3
PILOT7WEEK 127PHYSICAL FUNCTIONING SCALEPF03Trouble with a short walk—
PILOT7WEEK 128PHYSICAL FUNCTIONING SCALEPF04Needs to stay in bed or a chair3
PILOT7BASELINE1PHYSICAL FUNCTIONING SCALEPF01Trouble with strenuous activity1
PILOT7BASELINE2PHYSICAL FUNCTIONING SCALEPF02Trouble with a long walk—
PILOT7BASELINE3PHYSICAL FUNCTIONING SCALEPF03Trouble with a short walk—
PILOT7BASELINE4PHYSICAL FUNCTIONING SCALEPF04Needs to stay in bed or a chair2
PILOT7WEEK 125PHYSICAL FUNCTIONING SCALEPF01Trouble with strenuous activity—
PILOT7WEEK 126PHYSICAL FUNCTIONING SCALEPF02Trouble with a long walk—
PILOT7WEEK 127PHYSICAL FUNCTIONING SCALEPF03Trouble with a short walk—
PILOT7WEEK 128PHYSICAL FUNCTIONING SCALEPF04Needs to stay in bed or a chair—
PILOT7BASELINE1PHYSICAL FUNCTIONING SCALEPF01Trouble with strenuous activity4
PILOT7BASELINE2PHYSICAL FUNCTIONING SCALEPF02Trouble with a long walk4
PILOT7BASELINE3PHYSICAL FUNCTIONING SCALEPF03Trouble with a short walk4
PILOT7BASELINE4PHYSICAL FUNCTIONING SCALEPF04Needs to stay in bed or a chair4
PILOT7BASELINE5EMOTIONAL FUNCTIONING SCALEEF01Feeling tense3

Expected output

Under review
25 expected rows

expected/adqs.csv

Edit
25 rows
expected/adqs.csv
STUDYIDUSUBJIDVISITPARAMCDPARAMAVAL
PILOT7BASELINEPF01Trouble with strenuous activity2
PILOT7BASELINEPF02Trouble with a long walk0
PILOT7BASELINEPF03Trouble with a short walk2
PILOT7BASELINEPF04Needs to stay in bed or a chair1
PILOT7WEEK 12PF01Trouble with strenuous activity3
PILOT7WEEK 12PF02Trouble with a long walk3
PILOT7WEEK 12PF03Trouble with a short walk—
PILOT7WEEK 12PF04Needs to stay in bed or a chair3
PILOT7BASELINEPF01Trouble with strenuous activity1
PILOT7BASELINEPF02Trouble with a long walk—
PILOT7BASELINEPF03Trouble with a short walk—
PILOT7BASELINEPF04Needs to stay in bed or a chair2
PILOT7WEEK 12PF01Trouble with strenuous activity—
PILOT7WEEK 12PF02Trouble with a long walk—
PILOT7WEEK 12PF03Trouble with a short walk—
PILOT7WEEK 12PF04Needs to stay in bed or a chair—
PILOT7BASELINEPF01Trouble with strenuous activity4
PILOT7BASELINEPF02Trouble with a long walk4
PILOT7BASELINEPF03Trouble with a short walk4
PILOT7BASELINEPF04Needs to stay in bed or a chair4
PILOT7BASELINEPFSCOREPhysical Functioning Subscale Score31.25
PILOT7WEEK 12PFSCOREPhysical Functioning Subscale Score75
PILOT7BASELINEPFSCOREPhysical Functioning Subscale Score—
PILOT7WEEK 12PFSCOREPhysical Functioning Subscale Score—
PILOT7BASELINEPFSCOREPhysical Functioning Subscale Score100
Shaded columns are derived— = missing value

Comments and assessment materials

Comments

Signed in with GitHub; saved in repository Discussions

Mapping spec

Generated from the benchmark YAML; do not edit by hand

Dataset NameVariable NameVariable LabelTypeCodelist/Controlled TermsCoreComputational MethodOrigin
ADQSSTUDYIDStudy IdentifiercharacterCopy value from QS.STUDYID.Predecessor
ADQSUSUBJIDUnique Subject IdentifiercharacterCopy value from QS.USUBJID.Predecessor
ADQSVISITVisit NamecharacterCopy value from QS.VISIT.Predecessor
ADQSPARAMCDParameter CodecharacterPF01, PF02, PF03, PF04, PFSCORESet per constructed row; see the Row construction sheet.Derived
ADQSPARAMParametercharacterSet per constructed row; see the Row construction sheet.Derived
ADQSAVALAnalysis ValuenumericIf PARAMCD = 'PFSCORE' AND ITEMANS >= 3 then compute 100 * (ITEMSUM / ITEMANS) / 4; If PARAMCD = 'PFSCORE' then "None"; otherwise "ITEMRESN".Derived
TemplateInclude whenPARAMCDPARAMITEMRESN
itemQS.QSCAT = 'PHYSICAL FUNCTIONING SCALE'Copy QS.QSTESTCDCopy QS.QSTESTCopy QS.QSSTRESN
subscaleQS.QSCAT = 'PHYSICAL FUNCTIONING SCALE' AND QS.QSTESTCD = 'PF01'Constant "PFSCORE"Constant "Physical Functioning Subscale Score"Constant "None"
VariablePermitted values
PARAMCDPF01, PF02, PF03, PF04, PFSCORE
VersionDateAuthorDescriptionReviewerSign-off
1.32026-09-29yamaa docs buildShow study codelist names, external dictionaries, and ISO 8601 formats in variable rows; list the document's codelist values and metadata
1.22026-09-29yamaa docs buildClassify ADaM copies from a declared input as Predecessor and recodes as Derived, and SDTM recodes of locally derived columns as Derived
1.12026-09-29yamaa docs buildResolve lookups into the donor record they select, and give every derivation shape a plain-language rule instead of its raw YAML
1.0yamaa docs buildInitial generation from spec.yaml

Agent prompt

The request an agent receives with the input files; each tier states no more than the one above

prompts/adam-adqs-subscale-score/full.md

Edit
22 lines

Following CDISC ADaM standards, use the provided QS dataset to create an ADQS dataset with one record per subject per visit per item, plus one score record per visit.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL

Carry each physical functioning item response into PARAMCD (PF01 through PF04), PARAM, and AVAL, keeping the numeric result on its zero to four answer scale, empty when the item was not answered. Records from any other scale leave no records.

Add one score record per visit that has a PF01 item record, answered or not, with PARAMCD "PFSCORE" and PARAM "Physical Functioning Subscale Score". Its value is the mean of the answered items at that visit, reported on a zero to one hundred scale; it has no value when fewer than three of the four items were answered. A visit with too few answers still gets its score record, with no value, while a visit with no records at all gets none.

Read the source datasets from /app/input and save the completed dataset as /app/output/adqs.csv.

prompts/adam-adqs-subscale-score/conventions.md

Edit
16 lines

Following CDISC ADaM standards, use the provided QS dataset to create an ADQS dataset with one record per subject per visit per item, plus one score record per visit.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL

The physical functioning items are PARAMCD PF01 through PF04, with AVAL on their zero to four answer scale.

The score record has PARAMCD "PFSCORE" and PARAM "Physical Functioning Subscale Score", and its value is reported on a zero to one hundred scale.

Read the source datasets from /app/input and save the completed dataset as /app/output/adqs.csv.

prompts/adam-adqs-subscale-score/brief.md

Edit
9 lines

Following CDISC ADaM standards, use the provided QS dataset to create an ADQS dataset with one record per subject per visit per item, plus one score record per visit.

The output dataset should contain the following columns in this order: STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL

Read the source datasets from /app/input and save the completed dataset as /app/output/adqs.csv.

yamaa code

Runs the yamaa specification; its result must match the expected output

run.R

Edit
4 lines
library(yamaa)adqs <- yamaa_domain("spec.yaml")$outputadqs

run.py

Edit
4 lines
import yamaaadqs = yamaa.yamaa_domain("spec.yaml").outputadqs

Solution without yamaa

Written from the full prompt and the inputs alone; CI checks it reproduces the expected output

solutions/adam-adqs-subscale-score/result.R

Edit
60 lines
# Reference solution for the yamaa benchmark adam-adqs-subscale-score (R track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.library(dplyr, warn.conflicts = FALSE)library(readr)qs <- read_csv(  "/app/input/qs.csv",  col_types = cols(    QSSEQ = col_integer(),    QSSTRESN = col_double(),    .default = col_character()  ))# Each physical functioning item response, on its zero to four scale.items <- qs |>  filter(QSTESTCD %in% c("PF01", "PF02", "PF03", "PF04")) |>  mutate(PARAMCD = QSTESTCD, PARAM = QSTEST, AVAL = QSSTRESN) |>  select(STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL)# One score record per visit with a PF01 item record: the mean of the# answered items on a zero to one hundred scale, with no value when fewer# than three of the four items were answered.visits <- items |>  filter(PARAMCD %in% "PF01") |>  distinct(STUDYID, USUBJID, VISIT)stats <- items |>  group_by(STUDYID, USUBJID, VISIT) |>  summarise(    n_answered = sum(!is.na(AVAL)),    mean_answered = mean(AVAL, na.rm = TRUE),    .groups = "drop"  ) |>  mutate(    mean_answered = if_else(      n_answered < 3 | is.nan(mean_answered),      NA_real_,      mean_answered * 25    )  )scores <- visits |>  left_join(stats, by = c("STUDYID", "USUBJID", "VISIT")) |>  mutate(    PARAMCD = "PFSCORE",    PARAM = "Physical Functioning Subscale Score",    AVAL = mean_answered  ) |>  select(STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL)adqs <- bind_rows(items, scores) |>  arrange(STUDYID, USUBJID, VISIT, PARAMCD)dir.create("/app/output", showWarnings = FALSE)write_csv(adqs, "/app/output/adqs.csv", na = "")

solutions/adam-adqs-subscale-score/result.py

Edit
56 lines
# Reference solution for the yamaa benchmark adam-adqs-subscale-score (Python track).## Written from the benchmark's full prompt and its inputs alone, as an agent# would write it. Harbor's oracle agent runs it to check that the prompt can# be solved and that the grader scores a correct answer 1.from pathlib import Pathimport polars as plqs = pl.read_csv("/app/input/qs.csv", infer_schema=False).with_columns(    pl.col("QSSEQ").cast(pl.Int64),    pl.col("QSSTRESN").cast(pl.Float64),)# Each physical functioning item response, on its zero to four scale.items = (    qs.filter(pl.col("QSTESTCD").is_in(["PF01", "PF02", "PF03", "PF04"]))    .with_columns(        PARAMCD=pl.col("QSTESTCD"), PARAM=pl.col("QSTEST"), AVAL=pl.col("QSSTRESN")    )    .select("STUDYID", "USUBJID", "VISIT", "PARAMCD", "PARAM", "AVAL"))# One score record per visit with a PF01 item record: the mean of the# answered items on a zero to one hundred scale, with no value when fewer# than three of the four items were answered.visits = items.filter(pl.col("PARAMCD") == "PF01").select(    "STUDYID", "USUBJID", "VISIT").unique(maintain_order=True)stats = items.group_by(["STUDYID", "USUBJID", "VISIT"]).agg(    n_answered=pl.col("AVAL").drop_nulls().len(),    mean_answered=pl.col("AVAL").mean(),)scores = (    visits.join(stats, on=["STUDYID", "USUBJID", "VISIT"], how="left")    .with_columns(        AVAL=pl.when(pl.col("n_answered") >= 3)        .then(pl.col("mean_answered") * 25)        .otherwise(None)    )    .with_columns(        PARAMCD=pl.lit("PFSCORE"),        PARAM=pl.lit("Physical Functioning Subscale Score"),    )    .select("STUDYID", "USUBJID", "VISIT", "PARAMCD", "PARAM", "AVAL"))adqs = pl.concat([items, scores], how="diagonal").sort(    ["STUDYID", "USUBJID", "VISIT", "PARAMCD"])Path("/app/output").mkdir(exist_ok=True)adqs.write_csv("/app/output/adqs.csv")

solutions/adam-adqs-subscale-score/result.sas

Edit
22 lines
/* opensas reference solution for the yamaa benchmark adam-adqs-subscale-score.   Reads the benchmark inputs and derives the requested output.   Execute with the existing opensas runtime: opensas /app/output/result.sas. */data qs;  length STUDYID USUBJID VISIT QSCAT QSTESTCD QSTEST $1024;  infile "/app/input/qs.csv" dsd dlm="," firstobs=2 truncover lrecl=32767;  input STUDYID : $char1024. USUBJID : $char1024. VISIT : $char1024. QSSEQ QSCAT : $char1024. QSTESTCD : $char1024. QSTEST : $char1024. QSSTRESN;run;proc sql;  create table collected as select STUDYID,USUBJID,VISIT,QSTESTCD as PARAMCD,QSTEST as PARAM,QSSTRESN as AVAL from qs where QSTESTCD in ('PF01','PF02','PF03','PF04');  create table anchors as select distinct STUDYID,USUBJID,VISIT from collected where PARAMCD='PF01';  create table scores as select a.STUDYID,a.USUBJID,a.VISIT,'PFSCORE' as PARAMCD,'Physical Functioning Subscale Score' as PARAM,    case when count(b.AVAL)>=3 then 25*mean(b.AVAL) else . end as AVAL from anchors as a left join collected as b on a.STUDYID=b.STUDYID and a.USUBJID=b.USUBJID and a.VISIT=b.VISIT group by a.STUDYID,a.USUBJID,a.VISIT;quit;data result; set collected scores; run;proc sql;  create table final as select STUDYID, USUBJID, VISIT, PARAMCD, PARAM, AVAL from result;quit;proc export data=final outfile="/app/output/adqs.csv" dbms=csv replace; run;