# Upgrades and replay Upgrading a dependency means moving a pin forward deliberately: preview what is newer, stage the move, and re-run the affected scenarios to prove the move is safe. This page covers the preview command, the upgrade command with its replay support, and offline repair. Environment: the public `law-v0.1.1` release, run from the root of the [lab bundle](/corpus/lab/#before-you-start). The example continues the lab's [versions exercise](/corpus/lab/solutions/#versions-exercise), after revision `0.2.0` of `labparcels.registry` has been published to `/tmp/lab-work/registry` (see [**Publishing a release**](/corpus/releases/publishing/)). Status letters follow the [legend on the topic index](/corpus/#how-this-topic-marks-confidence). ## Example: move one pin forward All commands and outputs in this section are verbatim from the [versions exercise](/corpus/lab/solutions/#versions-exercise). **Preview.** The currency check flags the new revision and exits 1. The lock stays untouched: ```shell law outdated --project fixtures/parcels-fees --registry lab=/tmp/lab-work/registry ``` ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.1.0 [lab]: published 0.2.0 ``` Each pin is compared only against newer releases of the same package. Here one pin is behind, so one package is a candidate for an upgrade. **Stage.** Copy the consumer (the copy is silent), then run the upgrade with the preview flag: ```shell cp -r fixtures/parcels-fees /tmp/lab-work/fees-upd law update 'labparcels.registry@0.2.0' --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry --dry-run ``` ```text lab ← /tmp/lab-work/registry (--registry) --dry-run: staged and verified, no file changed ~ labparcels.registry 0.1.0 -> 0.2.0 changed: .law/transport.json changed: deps/labparcels.registry.lawir.json changed: law.lock changed: law.toml changed: package.law ``` The staged copy verified, and the `changed:` lines list the files a real run would write. No file changed yet. **Apply and confirm.** Run the same command without the preview flag (its output repeats the list above without the `--dry-run` line), then run the consumer scenarios and the currency check again: ```shell law test /tmp/lab-work/fees-upd | tail -n 1 law outdated --project /tmp/lab-work/fees-upd --registry lab=/tmp/lab-work/registry ``` ```text total: 5 checked, 5 passed, 0 failed, 0 not run; code 0 ``` ```text lab ← /tmp/lab-work/registry (--registry) labparcels.iface@0.1.0 [lab]: up to date labparcels.registry@0.2.0 [lab]: up to date ``` What this result means: the consumer now pins `0.2.0`, all five of its scenarios pass on the new pin, and no pin is behind. That justifies committing the new `law.toml`, `law.lock`, `deps/`, and import line together. A failing scenario at this point would mean the revision changed behavior the consumer relies on; keep the old pin until the cause is understood. ## Preview with outdated, upgrade with update `outdated` compares each pin against the newer stable releases of that same package and checks whether the pinned bytes still match. It never touches the lockfile. The comparison is per package, never against sibling versions: in the lab, `labparcels.fees` sits at `0.2.0` while its siblings sit at `0.1.0`, and the report above still flags only the registry pin. **Available in the public release** (S). `update` moves a pin and can replay saved evaluations as part of the move, so regressions surface before the new lock is accepted. The dry-run flag stages and verifies the move without changing any file. (S) The command reference records this usage for the preview command: ```text law outdated [--project ] [--registry ]… [--json] ``` Observed excerpts from the top-level help, each line verbatim: ```text $ law --help law add [@] [--project ] [--from ] [--registry ]… [--dry-run] [--json] law install [--project ] [--registry ]… [--offline] [--dry-run] [--recover] [--json] law update [@] [--project ] [--registry ]… [--dry-run] [--replay ] [--json] […] --offline exists only for install: add and update must read the registry descriptors to build the closure, and cannot work offline. ``` Note the last lines: `--offline` is an `install` flag. Adding or updating by name requires registry reads, because selection needs the version listing. That is a narrower claim than "only `install` works offline". The flag, registry reads, and needing the network are three different properties: a registry can live on a local path, and a release can cross an air gap inside a container (see [offline transfer with containers](/corpus/releases/publishing/#offline-transfer-with-containers)). (S) `outdated` has no dry-run flag. It never writes, so there is nothing to preview, and passing the flag is refused outright. Verbatim error-stream output, exit code 1: ```text $ law outdated --dry-run law: REFUSAL LPK-E0101: unknown parameter --dry-run → see `law --help`; registry form is ID=LOCATION, version is exact ``` The refusal changes nothing; drop the flag and run the command again. ## Repair and recovery `install` heals a working copy. `--offline` rebuilds from the local cache alone. `--recover` restores a damaged dependency directory without changing pins. Re-run the package scenarios afterwards: a heal that no scenario exercises proves nothing. (S) ## What a replay is made of A version pin plus a semantics line is not a replay. Repeating a saved result needs three more things: - the saved toolchain; - the input artifacts: the release bytes plus the saved evaluations; - the replay mechanism, which re-runs those evaluations and compares the result bytes. A release too old to carry replay records cannot be replayed at all. Standalone releases carry those records in `law.package-replay/0.2`. `eval` replays one saved evaluation directory, as this real run shows (compiler warnings suppressed; both commands exit 0): ```text $ law ask fixtures/parcels-case1 --query-json fixtures/parcels-case1/queries/fee-answered.json --out /tmp/eval-fee > /dev/null 2>&1; echo $? 0 $ law eval /tmp/eval-fee > /dev/null 2>&1; echo $? 0 ``` What this result means: `ask` saved the evaluation of the fee question to `/tmp/eval-fee`, and `eval` re-ran that saved evaluation and finished with exit 0. Run such a replay before you reuse a saved result under a newer toolchain or a moved pin; if it does not finish with exit 0, read its output before relying on the saved result. ## What to read next - [Versions protocol](/protocols/versions/) for what "latest stable" means. - [Command-line reference](/cli/) for the full package command surface. - [Schema catalog](/protocols/schemas/) for the lockfile format that records the upgraded pins.