Updating the catalog was only possible from the admin "Catalog audit" page,
which streams `runCatalogAudit` over SSE and always compares against every
enabled clone source. This adds the same engine to the terminal so it can be run
by hand or from cron:
- `scripts/catalog-sync.ts` — CLI driver around `runCatalogAudit`. Prints the
live progress, the per-source "on the source but not in this hotel" counts and
a summary block; generated catalog SQL is saved to
`storage/catalog-sync/*.sql` (gitignored). Supports `--list-sources`,
`--sources=<a,b>`, `--icons`, `--nitros`, `--furnidata`, `--structure`,
`--check-ids`, `--sql`, `--apply-sql`, `--organize-sql`, `--all`, `--json` and
`--fail-on-errors`.
- `scripts/catalog-sync.sh` — interactive menu (`pnpm catalog:sync`). Lists the
configured sources (so the menu always matches `clone_sources`), lets Habbo
(COM) be taken with Enter, and offers audit-only through full repair +
applying the catalog SQL, each with a distinct confirmation. With no arguments
it needs a terminal; with any flag it passes straight through to the CLI.
- `runCatalogAudit` gains `sourceIds` to restrict which sites are compared;
omitting it keeps the previous "compare against everything enabled" behaviour.
An audit writes nothing, and `--apply-sql` is the only flag that changes the
catalog. Verified against the live DB: 16370 items_base rows, 16479 catalog
items, 2871 Habbo (COM) entries missing from this hotel.
The deploy gate ran e2e specs that depend on live content and data, so a missing
upload (the /help article images) or a legacy malformed avatar figure could turn
a safe code deploy red. Split the suites by what they actually guarantee:
- Blocking gate (`pnpm test:e2e`, `playwright.config.ts`): only checks the CMS
can guarantee itself — anonymous redirects, register form fields, the captcha
DOM contract and the cache-control headers (deterministic origin-direct).
- Advisory suite (`pnpm test:e2e:quality`, `playwright.quality.config.ts`):
broken images, layout overflow and warm-page latency, which depend on live
content/upload state and the host. It runs as a `continue-on-error` CI job
against the public site so a real content problem stays visible without
blocking the pipeline.
Also add `scripts/sync-readme-versions.mjs` (+ tests, docs and a CI check) so
the pinned versions in README.md can never drift from package.json / .nvmrc.