### Task B2: Registry validator script **Files:** - Create: `local/validate-patches.R` **Interfaces:** - Consumes: `local/patches/registry.json`. - Produces: a script that exits non-zero on schema violations, missing patch files, or ambiguous overlapping entries. - [ ] **Step 1: Write the validator** ```r #!/usr/bin/env Rscript # Validate local/patches/registry.json: schema, referenced patch files, and # ambiguous overlaps. Exits 1 on any problem. Used by pre-commit and CI. dir <- "local/patches" registry_file <- file.path(dir, "registry.json") if (!file.exists(registry_file)) { cat("No registry.json found; nothing to validate.\n") quit(status = 0L) } reg <- jsonlite::fromJSON(registry_file, simplifyVector = FALSE) required <- c("package", "versions", "platforms", "reason") errs <- character(0L) for (i in seq_along(reg)) { e <- reg[[i]] missing <- setdiff(required, names(e)) if (length(missing) > 0L) { errs <- c(errs, sprintf( "entry %d (%s): missing %s", i, if (is.null(e$package)) "?" else e$package, toString(missing) )) } if (!is.null(e$patch)) { p <- file.path(dir, e$patch) if (!file.exists(p)) { errs <- c(errs, sprintf("entry %d (%s): patch file '%s' missing", i, e$package, p)) } } } # Ambiguous overlap: two entries for the same package with identical platforms # and versions. keys <- vapply(reg, function(e) { sprintf("%s|%s|%s", e$package, paste(sort(as.character(unlist(e$platforms))), collapse = ","), e$versions) }, character(1L)) dups <- keys[duplicated(keys)] if (length(dups) > 0L) { errs <- c(errs, sprintf("ambiguous duplicate entries: %s", toString(unique(dups)))) } if (length(errs) > 0L) { cat("Patch registry validation FAILED:\n") cat(paste0(" - ", errs, "\n")) quit(status = 1L) } cat(sprintf("Patch registry OK (%d entrie(s)).\n", length(reg))) ``` - [ ] **Step 2: Run it (expect success on the B1 registry)** Run: `Rscript local/validate-patches.R` Expected: `Patch registry OK (1 entrie(s)).` and exit 0. - [ ] **Step 3: Run it against a broken registry (expect failure)** Run: ```bash cp local/patches/registry.json /tmp/reg.bak Rscript -e 'writeLines("[{\"package\":\"X\"}]", "local/patches/registry.json")' Rscript local/validate-patches.R; echo "exit=$?" cp /tmp/reg.bak local/patches/registry.json ``` Expected: prints `validation FAILED` with a missing-field message and `exit=1`. - [ ] **Step 4: Commit** ```bash git add local/validate-patches.R git commit -m "feat(patches): add registry validator script" ``` ---