mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 21:22:28 +03:00
feat(ci): gate the publish on clean-install AND upgrade-over-previous
`check:pack-boot` proves a fresh install boots. It does not prove the path that actually
broke us: installing over an existing version, where ~110 SQLite migrations run against a
populated database. v3.8.48 shipped as a hotfix because the published 3.8.47 crashed on
boot, and the v3.8.49 upgrade path was only ever exercised end-to-end by hand — on VPS .16,
against a real 3.8.48 install with a 165 MB database, AFTER publishing. That is backwards.
New gate (`scripts/check/check-install-upgrade.mjs`), wired into npm-publish.yml as step 12,
BEFORE `npm stage publish` — so a broken upgrade never reaches the registry and a staged
package that is never approved simply expires, with no `npm deprecate` needed:
- Phase A: fresh prefix + fresh DATA_DIR, install the packed tarball, boot, health.
- Phase B: fresh prefix + fresh DATA_DIR, install the PREVIOUS published version, boot it
(creates + migrates the DB), stop, install the tarball over the SAME prefix, boot against
the SAME DATA_DIR. Asserts no table present before the upgrade was dropped.
- Schema convergence, and its DIRECTION is the whole point:
fresh − upgraded ≠ ∅ → FAIL. Structure a clean install creates but an upgrade does not
means every existing user is missing it. Not allowlistable.
upgraded − fresh ≠ ∅ → residue; fails only when NEW (allowlist carries the known ones).
A naive symmetric check would either block every release on harmless residue or, if relaxed,
let the dangerous direction through. Measured on VPS .16 (2026-07-30): a real 3.8.48 install
upgraded to 3.8.49 ended with 117 tables against 116 for a clean 3.8.49 install — the extra
being `cache_metrics`, recorded in config/quality/install-upgrade-allowlist.json with the
measurement. Both installs healthy, zero `no such table` in 150 log lines.
`evaluateConvergence` is exported and pure so the asymmetry is testable without packing,
installing or booting anything (same reason check-test-masking exports its helpers):
tests/unit/check-install-upgrade-convergence.test.ts, 8 cases, ~6ms.
A previous version that fails to boot degrades to a warning — a historically bad publish
must not block the current one. Uses node:sqlite (Node 24, already the publish job's
runtime): no new dependency.
This commit is contained in:
12
.github/workflows/npm-publish.yml
vendored
12
.github/workflows/npm-publish.yml
vendored
@@ -223,6 +223,18 @@ jobs:
|
||||
if: steps.resolve.outputs.skip != 'true'
|
||||
run: npm run check:pack-boot
|
||||
|
||||
# The boot-smoke above proves a CLEAN install boots. It does not prove the path that
|
||||
# actually broke us: installing over an existing version, where ~110 SQLite migrations
|
||||
# run against a populated database. v3.8.48 shipped as a hotfix because the published
|
||||
# 3.8.47 crashed on boot, and the v3.8.49 upgrade path was first exercised end-to-end
|
||||
# by hand on a real 3.8.48 box (VPS .16) — after publishing, which is exactly backwards.
|
||||
# Runs BEFORE `npm stage publish` so a broken upgrade never reaches the registry at all;
|
||||
# a staged package that is never approved simply expires, with no `npm deprecate` needed.
|
||||
- name: Prove clean-install AND upgrade-over-previous both boot
|
||||
if: steps.resolve.outputs.skip != 'true'
|
||||
timeout-minutes: 30
|
||||
run: npm run check:install-upgrade
|
||||
|
||||
# WS1.3 (D2, v3.8.49 plan): STAGED publishing by default — `npm stage publish`
|
||||
# parks the exact bytes on the registry WITHOUT making them installable; the
|
||||
# owner then verifies and approves with 2FA (`npm stage approve`), moving the
|
||||
|
||||
Reference in New Issue
Block a user