Versioned analysis job templates for the HVTI CORR group at the Cleveland Clinic.
Start at the template gallery:
every template, what it is for, the add_job() call that adds it to your study,
and the report it produces on a synthetic study. The full reference is at
https://ehrlinger.github.io/hvtiRtemplates/.
hvtiRtemplates is part of the HVTI R family. Install it with the rest of the family through hvtiR:
# install.packages("pak")
pak::pak("ehrlinger/hvtiR")
hvtiR::install()
hvtiR::install() installs every member in one call, so the versions the
members require of one another resolve together. Update later with
hvtiR::update(), from a fresh R session: it will not overwrite a package
that is already loaded.
To install hvtiRtemplates on its own:
# pak::pak("ehrlinger/hvtiRtemplates")
install.packages("hvtiRtemplates", repos = c('https://ehrlinger.r-universe.dev', 'https://cloud.r-project.org'))
In a project that uses renv, install with
renv::install("ehrlinger/hvtiRtemplates") instead, so the package lands in
the project library.
| Directory | Status | Contents |
|---|---|---|
inst/templates/ |
supported | R job templates. See inst/templates/README.md for coverage. |
Everything the package installs is supported: tested, maintained, and intended to be run. There is no reference-only material.
During development this repository also carried the legacy SAS template corpus
(240 files) and the SAS macro library (495 files, with history imported from
2014) as a reference specification. Both were removed before release, and every
path was purged from every commit with git filter-repo — they are not
recoverable from this repository's history by design.
Two consequences worth stating plainly. Parity work against the SAS originals
needs a source outside this repository; the institutional SAS license runs into
2027, so plan accordingly (2027-09-29 is the working date, not yet confirmed).
And a result filed before the migration still cannot say what produced it — that
was already true, because %inc bound late to a mutable directory with no
version, and removing the corpus neither creates nor worsens that gap.
Study analyses were created by copying template files into a new study folder
and editing them. Two things followed: improvements stayed in the study where
they were made, and — the problem that actually hurts — a filed result could
not say what produced it. SAS bound its analysis logic with
%inc kaplan, resolving at run time against a mutable directory with no
version, so the .lst filed in 2006 was produced by a kaplan nobody can now
identify.
The design rule is bind late, to something versioned. Late binding is right;
SAS could not make it safe because there was no version to pin. renv.lock
supplies that, so a study can use the latest while working and pin it on filing.
In practice a study declares hvtiRtemplates in its renv.lock, resolves a
template through template_path("ac") instead of copying one into the study
folder, and pins the version when results are filed. The lock file is then the
answer to "what produced this?" — the question the SAS arrangement could not
answer, because %inc had nothing to pin.
| Function | Returns |
|---|---|
template_catalog() |
all 55 template jobs, including queued work and dependencies |
hvti_taxonomy() |
the analysis prefix table: prefix, name, folder, description |
template_list() |
supported templates: name, prefix, qualifier, folder, file |
template_path(prefix, qualifier = NULL) |
path to one supported template |
hvti_non_prefixes() |
leading name fields that are utilities, not analysis prefixes |
add_job(prefix, subject, type, dir = NULL, qualifier = NULL) |
the scaffolded job's path, invisibly |
open_job(prefix, subject, type, dir = NULL, qualifier = NULL) |
job path; creates a missing job or opens an existing one |
render_job(path, final = FALSE, quiet = FALSE) |
path, invisibly; renders a draft, or with final = TRUE a render that stops on an unfinished job |
migrate_job(source, subject, type, prefix, ...) |
the migrated job's path, invisibly; writes an evidence report beside it |
add_job() also installs idempotent Quarto pre-render and post-render hooks in
the study without replacing existing project settings or user hooks. Every
managed render captures the registered data actually read, embeds its runtime
payload in the completed HTML, and publishes a same-stem
.provenance.json beside Quarto's actual output. A failed render leaves the
prior completed HTML and sidecar together when the output stays untouched. If
publication fails after an output changes, the hooks expose a prior sidecar only
when its recorded output hash still matches. Otherwise they withhold the
sidecar and retain its recovery backup with a warning.
Templates are <prefix>[-<qualifier>].qmd in a numbered directory
(20_distributions/ac.qmd); a job is
<prefix>[.<qualifier>].<subject>.<type>.qmd in the study's matching taxonomy
folder, so a study's jobs sort by template. Jobs scaffolded before 2026-10 keep
their <subject>-<type>-<prefix>[-<qualifier>].qmd names and keep rendering. New studies use numbered folders and existing bare-folder studies keep
their layout. The ordinal that once prefixed filenames was dropped in 1.1.0.
The subject groups a job set. It is a statistical endpoint when the job analyses
one, such as death; it can instead be an endpoint-free topic such as cohort,
treatment, or labs. Each job owns its outcome variables, coding, filters,
and any cohort definition. Dataset registration records the data, not a
study-wide endpoint or cohort.
qualifier names a job type within a prefix. The current qualified families
are dc, dp, rfs, rfc, rfr, and lm. The lm choices are binary,
ordinal, nominal, propensity_binary, propensity_ordinal,
propensity_nominal, checkpred, and balancing_count. It is NULL and the
column is NA for a prefix with a single template. Naming no qualifier where
a prefix carries several is an error listing the choices, never a silent pick
of the first.
For a study with SAS programs already in descriptive/ and graphs/, first
adopt its directory with hvtiRutilities::study_setup(..., adopt = TRUE) and
register its built datasets with register_data(). The tutorial
Set up an hvtiR study for descriptive and EDA work
walks through new-study creation, recoverable legacy cleanup and adoption,
data registration, the EDA analysis set, all five pre-analysis jobs, and
output review using synthetic data.
From that study's root, migrate a descriptive-table job with:
job <- hvtiRtemplates::migrate_job(
source = "descriptive/dc.tables.sas",
subject = "cohort", type = "eda", prefix = "dc", qualifier = "tables",
lst = "descriptive/dc.tables.lst", log = "descriptive/dc.tables.log",
reference = "documents/general.rtf", dir = "."
)
Use your study's source and evidence filenames. lst, log, and reference
are optional; supplied files must exist beneath dir. The call writes
descriptive/dc.tables.cohort.eda.qmd and
descriptive/dc.tables.cohort.eda-migration.md in a study with bare folders.
It preserves the evidence files and refuses to overwrite either output.
Migration supports dc-tables, dc-gfup, dc-trends, and dc-eda.
Each adapter reads a defined source shape. Only deterministic extraction can
remove an EDIT: marker; uncertain choices remain in the job and report for
you to resolve before rendering. Logs, listings, and RTF/DOCX references help
you check the translation but do not supply missing analysis choices.
The table job replaces the SAS RTF output with an editable CORR DOCX through
hv_tbl_summary(), hv_man_table(), hv_man_table_save(), and
hv_check_docx(). It writes beneath documents/<subject>-<type>/ and stops
on a structural finding. Compare the rows, summaries, precision, and footnotes
with the legacy reference before accepting the document; the structural check
does not establish numerical agreement.