---
title: "Getting Started with hvtiR"
author: "John Ehrlinger"
date: today
format: html
vignette: >
  %\VignetteIndexEntry{Getting Started with hvtiR}
  %\VignetteEngine{quarto::html}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## The problem

The HVTI R package family is twelve packages spread across twelve GitHub
repositories. Setting up a machine used to mean twelve `pak::pak()` calls, in
an order you had to know, against repository names that have not always matched
the package names: `hvtiRpropensity` lived in `ehrlinger/hvtiPropensityScores`
and `TemporalHazard` in `ehrlinger/temporal_hazard` until the 2026-08 renames.

`hvtiR` reduces that to one call, and adds a way to ask whether you are
current.

## The members

The registry is the package's only piece of data. It maps each package to the
repository it installs from:

```{r members}
hvtiR::members()
```

## What you have

`hvtiR::status()` compares what is installed against what is on each
repository's `main` branch. When pak recorded the installed GitHub commit, the
comparison catches new commits even when the package version did not change:

```{r status, eval = FALSE}
hvtiR::status()
```

```
hvtiR 1.2.3 - 12 members

  v hvtiRutilities   1.4.3      1.4.3      ok
  v hvtiRdatabuild   0.2.4      0.2.4      ok
  ! hvtiRtables      1.0.2      1.0.3      stale
  x hvtiPlotR        -          2.8.2      missing
  ...

i 2 members need updating. Run hvtiR::update().
```

The status column takes one of six values:

| Status | Meaning |
|---|---|
| `ok` | installed version and recorded commit are current |
| `stale` | installed version or recorded commit is behind |
| `missing` | not installed |
| `ahead` | you have a local development build |
| `unknown` | GitHub could not be reached |
| `ok-local` | installed; the remote was not consulted |

Packages installed without GitHub commit provenance fall back to the version
comparison. The table stays version-focused; commit SHAs are used internally
only to resolve a tie between equal versions.

`status()` checks `hvtiR` itself separately because the installer is not a
family member. It stays outside the table. When it is behind, the report names
the available version and the command that updates it:

```r
pak::pak("ehrlinger/hvtiR")
```

The object is a plain data frame underneath, so you can use it in a script:

```{r status-df, eval = FALSE}
st <- hvtiR::status()
st$package[st$status == "stale"]
```

On a machine with no outbound network, skip the remote entirely:

```{r status-local, eval = FALSE}
hvtiR::status(remote = FALSE)
```

```
hvtiR 1.2.3 - 12 members

  - hvtiRutilities   1.4.3      -          ok-local
  - hvtiRdatabuild   0.2.4      -          ok-local
  - hvtiRtables      1.0.3      -          ok-local
  - hvtiRtemplates   1.2.2      -          ok-local
  - hvtiPlotR        2.8.2      -          ok-local
  - hvtiRlifetables  0.1.4      -          ok-local
  - hvtiRbootstrap   0.9.4      -          ok-local
  - hvtiRpropensity  0.1.8      -          ok-local
  - hvtiRimputation  0.1.1      -          ok-local
  - ggBoostedTrees   0.0.7      -          ok-local
  - TemporalHazard   1.2.12     -          ok-local
  - ggRandomForests  4.0.0      -          ok-local

i Remote was not consulted; versions shown are installed versions only.
```

## Installing and updating

On a new machine, install everything:

```{r install, eval = FALSE}
hvtiR::install()
```

Thereafter, install only what has fallen behind:

```{r update, eval = FALSE}
hvtiR::update()
```

`hvtiR::update()` reuses the installer check made by `status()`, but it never
installs `hvtiR` itself. Its namespace is already loaded, which is exactly what
the guard below refuses. When the report says it is behind, reinstall it the
way you first installed it:

```{r self, eval = FALSE}
pak::pak("ehrlinger/hvtiR")
```

### Why it may refuse

`hvtiR::update()` warns and installs nothing if a required member is already
loaded in the session:

```
Warning:
Cannot install required hvtiPlotR: already loaded in this session.
i No members were installed. Restart R and run `hvtiR::update()` before anything attaches it.
i Pass `force = TRUE` to install anyway (unsafe on Windows).
```

This is not fussiness. A package whose namespace is loaded cannot be safely
overwritten — on Windows the write fails outright and leaves a half-installed
library. The returned empty character vector carries a `blocked` attribute
with the loaded package names. Restart R and run the update before you attach
anything.

## Set up a study

```{r setup-study, eval = FALSE}
install.packages("pak")
pak::pak("ehrlinger/hvtiR")
hvtiR::setup(
  study = "EDIT: the Study Tracker title",
  study_tracker_id = 0L,  # EDIT: the Study Tracker ID
  root = "EDIT: the study directory"
)
```

Run this once per study, before anything else, from an R session started
outside any project, passing `root =`. From inside the study's RStudio project
it stops before installing anything and names the command to run: it replaces
packages that session has loaded. It also stops the study using renv's
per-user cache, so the shared library holds real copies a teammate can read,
and reinstalls any package that was only a link into someone's home. It cleans
up template copies first and only then locks the packages, so the lockfile records what the study declares and not what the templates
happened to mention. For an existing (legacy) study pass `adopt = TRUE`, which
is what cleans up its template copies. A study that already has a `renv.lock`
keeps its locked versions unless the declared family needs newer ones, in which case
`setup()` moves them, lists each move and records them (`upgrade = TRUE`, the default; pass
`upgrade = FALSE` for a study in revision, whose versions must not move), and every package that lockfile recorded is declared
on first conversion, so none drop out. No personal GitHub token is needed: the packages are installed with
pak, which carries a shared token, and renv keeps the environment (lockfile,
restore, snapshot). It is safe to rerun.

## Reproducible installs

`hvtiR::install()` resolves every member from GitHub `main`, so it gives you
the newest code rather than a fixed one. Two people running it a week apart can
end up on different commits under the same version number. When an analysis has
to be reproducible, pin the versions with
[renv](https://rstudio.github.io/renv/):

```{r renv, eval = FALSE}
renv::init()      # once per project
hvtiR::install()  # installs into the project library
renv::snapshot()  # records every package, and each member's commit
```

`renv.lock` then names the exact commit behind each member, and
`renv::restore()` rebuilds that library on another machine. This works because
pak records the commit it installed from, which is the field renv reads.

A member installed from a local working copy rather than from GitHub carries no
such commit, so renv has none to record for it.

## When something will not install

```{r doctor, eval = FALSE}
hvtiR::doctor()
```

The doctor reports on your environment ahead of the status table: the
installed `hvtiR` version, your R version against the family's strictest
requirement, your platform, whether `pak` is installed to install members
with, the package repositories R is configured to use, and whether an `renv`
project is active.

`ggRandomForests` and `hvtiRlifetables` both need R 4.4.0 or newer, which is
the single most common reason a member will not install. Note that `hvtiR`
itself requires only R 4.1.0 — deliberately, so that the diagnostic still runs
on a machine whose R is too old for the members it is reporting on.

The second most common reason is a repository that is frozen in time. RStudio
Server sites often point R at a dated Posit Package Manager snapshot, and a
dependency released after the snapshot date is invisible to pak. The install
then fails with "Could not solve package dependencies". The doctor warns when
a configured repository is such a snapshot, and its "Dependency floors"
section names each requirement the repositories cannot meet: `ggRandomForests`
needs `varPro (>= 3.3.0)`, for example, which reached CRAN on 2026-09-22.
Reading those floors takes the network, so `hvtiR::doctor(remote = FALSE)`
skips that section.

## Why GitHub and not CRAN

Every member installs from GitHub `main`, including `ggRandomForests`, which is
also published on CRAN.

Development flows from the family repositories to CRAN, not the other way
around. GitHub `main` is therefore the leading release source, while CRAN is a
downstream republication for members that are published there.

One consequence is worth knowing: because `ggRandomForests` came from GitHub, a
later `update.packages()` can quietly downgrade it to the CRAN version. If a
version looks wrong, run `hvtiR::status()`.

The same replacement can happen to `TemporalHazard`, and there it may not be
harmless. `hvtiRlifetables` requires `TemporalHazard (>= 1.2.0)` in its
`Imports:` field, a requirement R enforces when the namespace loads. If a CRAN
downgrade no longer satisfies that requirement, `hvtiRlifetables` will not
load until `hvtiR::update()` puts the GitHub release back.
