Hands-on Quick Start

Complete one small change before attempting an entire analysis pipeline. In this exercise, an assistant writes an R function to select the latest valid measurement for each person. You supply the method and check the result against a tiny synthetic fixture.

You need R, a text editor, and a coding assistant of your choice. Git is useful for reviewing and saving the change. The exercise uses base R, requires no package installation, and makes no clinical classification.

1. Create a practice folder

Use a new folder outside any real-data workspace. Run the commands from a terminal; keep that folder as your working directory throughout the exercise.

mkdir genai-practice
cd genai-practice
git init
mkdir R tests

Save the following as tests/fixture.R:

records <- data.frame(
  person_id = c("p01", "p01", "p01", "p02", "p02",
                "p03", "p03", "p04", "p04", "p05"),
  encounter_id = sprintf("e%02d", 1:10),
  date = as.Date(c("2025-01-01", "2025-02-01", "2025-03-01",
                   "2025-01-10", "2025-01-10", "2025-01-01",
                   "2025-02-01", "2025-03-10", "2025-02-01", NA)),
  bmi = c(22, 23, NA, 25, 26, NA, Inf, 0, 28, 24),
  stringsAsFactors = FALSE
)

2. Agree on the result before asking for code

For this exercise, a valid measurement has a nonmissing date and a finite BMI greater than zero. This is a software rule for the exercise, not a clinical plausibility rule. Filter invalid measurements before choosing the latest date. On tied dates, choose the lexically smallest encounter ID. Omit people with no valid measurements, and sort output by person ID.

Check the ten input rows yourself. The expected output is:

person_id encounter_id date bmi Why selected
p01 e02 2025-02-01 23 The later e03 measurement has missing BMI.
p02 e04 2025-01-10 25 e04 wins the date tie with e05.
p04 e09 2025-02-01 28 The later e08 measurement has BMI zero.

People p03 and p05 have no valid measurements under this rule. Deciding these expectations first helps expose a shared mistake in generated code and generated tests [Verification guidance].

3. Give the assistant a bounded task

Open only the practice folder in your coding assistant. If you use a chat-only tool, paste the synthetic fixture and save the returned function yourself.

Implement select_latest_valid(records) in R/select_latest_valid.R.

Inspect tests/fixture.R first. Use base R only.
Input is a data.frame with exactly these columns in this order:
person_id (character), encounter_id (character), date (Date), bmi (numeric).
IDs are nonmissing and encounter_id is unique in this exercise.
Fail with a useful error if a required column is absent.

Keep rows with a nonmissing date and finite bmi > 0, then select the
latest date per person. Break tied dates by the lexically smallest
encounter_id. Return the same four columns and types, sorted by person_id.
Empty input or no valid measurements must return zero rows with that schema.
Do not modify the input or write files from the function.

Expected selected encounters for the fixture: e02, e04, e09.
Implement only this function. Do not change the fixture, expected results,
or tests to make the implementation pass. Run Rscript tests/check.R if
the test file is available; otherwise say that it has not been run.
Report changed files, checks run, and any unresolved assumptions.

For your own task, adapt the full task brief. Give an agent that can edit files access to the checks below; their expected results remain part of your specification.

4. Run checks you can explain

Save this as tests/check.R. It checks the expected records, deterministic selection, missing-column handling, and empty results. For larger projects, named expectations in testthat provide more descriptive failures [testthat expectations].

source("tests/fixture.R")
source("R/select_latest_valid.R")

check_expected <- function(x) {
  stopifnot(
    is.data.frame(x),
    identical(names(x), names(records)),
    identical(x$person_id, c("p01", "p02", "p04")),
    identical(x$encounter_id, c("e02", "e04", "e09")),
    identical(x$date, as.Date(c("2025-02-01", "2025-01-10", "2025-02-01"))),
    identical(x$bmi, c(23, 25, 28))
  )
}

original <- records
check_expected(select_latest_valid(records))
check_expected(select_latest_valid(records[nrow(records):1, ]))
stopifnot(identical(records, original))

for (input in list(records[FALSE, ], records[records$person_id == "p03", ])) {
  empty <- select_latest_valid(input)
  stopifnot(
    is.data.frame(empty), nrow(empty) == 0L,
    identical(names(empty), names(records)),
    identical(vapply(empty, class, character(1)),
              vapply(records, class, character(1)))
  )
}

missing_column_error <- tryCatch({
  select_latest_valid(records[, names(records) != "date"])
  FALSE
}, error = function(e) TRUE)
stopifnot(missing_column_error)

cat("All quick-start checks passed.\n")

Run:

Rscript tests/check.R

The expected output is All quick-start checks passed. If a check fails, compare the actual records with the table before changing code. Ask the assistant to explain one failing case and make a focused correction. Keep the expected result fixed unless you deliberately change the specification.

Passing these checks covers this small contract. It does not validate clinical eligibility, BMI plausibility limits, or the measurement-selection method for a study.

5. Review and save the change

Read the function and confirm the filtering and tie-breaking order. Stage the specific files, then review the staged diff before committing:

git add R/select_latest_valid.R tests/fixture.R tests/check.R
git diff --cached
git commit -m "Add tested synthetic measurement selection example"

Record the R version, command, result, and any decisions in a short README. If you stop before finishing, use a session handoff.

Take it into your research workflow

The repository’s EHR simulator provides larger synthetic inputs for the later chapters. Its schema is richer than this fixture: map fields and document selection rules before reusing the function. The advanced project plan covers a teaching cohort, missingness, and descriptive outputs; a real study needs its own reviewed protocol.

Keep the small fixture as a regression check while adding realistic edge cases. The coding agent playbook explains how to manage context, separate review work, and record a reproducible environment as the project grows.