docs← Back to article

Markdown for LLMs

Upgrades and replay

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# 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 <dir>] [--registry <ID=LOCATION>]… [--json]
```

Observed excerpts from the top-level help, each line verbatim:

```text
$ law --help
  law add <name>[@<version>] [--project <dir>] [--from <registryId>]
          [--registry <ID=LOCATION>]… [--dry-run] [--json]
  law install [--project <dir>] [--registry <ID=LOCATION>]… [--offline]
          [--dry-run] [--recover] [--json]
  law update <name>[@<version>] [--project <dir>] [--registry <ID=LOCATION>]…
          [--dry-run] [--replay <dir>] [--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.