Ctrl K
ComunidadGuías…

docs/maintainers/upgrade-testing.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Runtime upgrade testing

A release build is only proven upgradeable by installing a real released artifact as N, letting it
stage a real N+1 through the product's own update path, applying it, and checking that the data
before the upgrade is intact afterwards. This page describes that harness and what each kind of row
can honestly claim.

The harness is
[`.github/workflows/upgrade-matrix.yml`](../../.github/workflows/upgrade-matrix.yml), which is
dispatched per release gate with the candidate tag, the candidate commit, the candidate manifest
asset ID and SHA-256, the version to install as N, and a dispatch correlation ID. The driver is
[`scripts/upgrade-matrix/run-upgrade.cjs`](../../scripts/upgrade-matrix/run-upgrade.cjs) with shared
helpers in [`harness.cjs`](../../scripts/upgrade-matrix/harness.cjs).

## What a row does

Every row runs the same two phases.

**Seed**, while release N is running: complete first-run setup, create identifiable data through the
app's own API (an order with a marker note, printer configuration, and settings), opt into the
update channel, wait for the update to be staged, then invoke the same Master-PIN-gated
`restart-and-install` IPC that the **Restart Now** button uses. The row exits once the app begins
quitting to install.

**Verify**, after the upgraded build has launched again: assert the running version equals the
expected N+1, that every seeded record survived, and that the persisted channel preference
survived. On success it prints an evidence JSON document.

Seeding through the app's own API rather than writing to the database directly is what makes the
result meaningful. It proves the data is reachable through the API after the upgrade, not merely
that rows are still present in a SQLite file.

The candidate manifest is verified immediately before the seed phase, so a row cannot pass against
a candidate that is not the one the release gate admitted.

## What each kind of row proves

The matrix has four jobs, and they do not all claim the same thing.

### Self-updating rows: Windows NSIS and Linux AppImage

`windows-nsis-x64` and `linux-appimage` (x64 and arm64) install a real released artifact, upgrade it
through `electron-updater`, and verify version and data. These are the rows that prove a genuine
installed-artifact N to N+1 upgrade. `older-cohort-windows` repeats the Windows row from a much
older N to catch upgrade paths that a single-step test would miss.

A self-updating row must show the old process exiting before the new one is started, and the new
build reaching API readiness. A build that exits before readiness, or stays alive after reporting
ready, fails the row.

### Managed-package gating rows: deb and Snap

`linux-managed-gating` covers deb and Snap, and it is a **gating** check, not an upgrade test.

On Linux, a package-manager install has no in-app update path. The app detects this in
`main/index.ts` and reports an update status of `linux-managed` or `store-managed` instead of
staging anything. The row asserts exactly that: the updater reports a managed status, and the log
contains no `Downloading update`, `beta.yml`, or `latest.yml` line.

This is a bounded check on one branch of the updater's decision. It proves the app correctly
declines to self-update on a managed install. It is **not** evidence that `apt` or `snapd` can
perform the upgrade, and it is not evidence that the database survives one. The Snap row is
additionally marked experimental, so its failure does not fail the matrix.

Do not read a green `linux-managed-gating` row as package-manager upgrade coverage. That would be a
stronger claim than the check makes.

### Platform coverage and the macOS gap

The hosted workflow has no macOS row. macOS rows are run locally, outside this workflow, because
instrumenting a macOS installed build to point it at a candidate release invalidates the app
bundle's Developer ID sealed resources, and the native Squirrel.Mac updater then rejects the staged
update on signature validation. The hosted runners cannot produce that result on demand, so macOS
upgrade evidence comes from a manual run and is recorded against the release rather than produced
by the matrix.

When a manual macOS row is run, it must meet the same bar as a hosted row: a real released N, the
real update path, and a version plus persistence check afterwards.

## Download path and evidence

The updater may reach N+1 by a differential download or by a full download. A differential attempt
that fails and falls back to a full download is still a successful upgrade: what the row asserts is
the resulting version and the surviving data, not which path the bytes took. The AppImage and
Windows rows record which path the updater reported, so a fallback is visible in the evidence
without failing the row.

A differential failure that always falls back is a product finding about the updater, not an
upgrade failure, and it belongs in an issue rather than in this page.

Each job uploads its evidence artifact, and the release summary records the matrix as a single
status. When the matrix is not run, the status is `NOT-RUN` and must not be described as an upgrade
pass. See [releases](releases.md) for how a `NOT-RUN` row is summarized.

## Running the matrix

Dispatch the workflow with:

| Input | Meaning |
| --- | --- |
| `from_version` | The released version to install as N. |
| `candidate_tag` | The exact beta candidate tag to install and test as N+1. |
| `candidate_commit` | The exact commit the candidate manifest binds. |
| `candidate_manifest_asset_id` | Asset ID of `candidate-manifest.json`. |
| `candidate_manifest_sha256` | SHA-256 of the manifest bytes. |
| `to_version` | The expected version after the upgrade. |
| `matrix_dispatch_id` | Correlation ID matching the release gate dispatch. |
| `run_linux` | Whether to run the Linux rows. |

The Windows and Snap rows fetch release N by URL. For a release predating the current naming
contract, they fall back to the older artifact name before failing.