Skip to content

generate-patch.ts is a partial mirror of build-sqlite.ts and would corrupt a patched database if wired up #657

Description

@jeffreylouden

Surfaced while adding hardware_capabilities in #653. None of this is a live outage: pnpm patch appears in no workflow and is referenced nowhere outside package.json, so the distribution path is the full pnpm build in CI and nothing published goes stale by this route today. It is a trap for whoever eventually wires it up, which is exactly when it stops being cheap to fix.

generate-patch.ts presents itself as an incremental equivalent of build-sqlite.ts, but it only ever handled hardware, hardware_categories and hardware_fts. Three distinct defects follow from that, in rough order of how badly they bite.

1. Thirteen child tables are never synchronized

build-sqlite.ts writes these on a full build. generate-patch.ts neither deletes nor re-inserts them, so on a modified entry a patched database silently keeps the old rows:

hardware_io, hardware_prices, hardware_links, hardware_versions, hardware_variants, hardware_variant_links, hardware_variant_prices, hardware_variant_videos, hardware_videos, hardware_search_terms, hardware_translations, hardware_links_localized, hardware_videos_localized, hardware_io_translations

I/O is the one that matters most in practice, since the setup graph reads it and a stale port list is worse than an absent one.

The same question applies to the software, content, accessory and manufacturer generators in that file, which I have not audited.

2. Categories are inserted without normalization or dedup

build-sqlite.ts normalizes category aliases, dedups the canonical values, and warns on Duplicate category "..." (after normalization). generate-patch.ts does neither, so it inserts raw aliases. Two consequences:

  • A patched database can hold an alias where a rebuilt one holds the canonical value, so the same query returns different rows depending on how the database was produced.
  • Two distinct aliases collapsing to one canonical value is a real case in this data, which is why build-sqlite.ts warns about it. Through the patch path that becomes a UNIQUE constraint failed on hardware_categories, aborting the whole patch.

Deduping without normalizing is not a fix here, it just changes which of the two failures you get. hardware_capabilities needed dedup only because its vocabulary is closed with no aliases by design.

3. The version stamp is unconditional

// Update version metadata
sql.push(`UPDATE catalog_meta SET value = '${toVersion}' WHERE key = 'version';`);

This runs after the change loop regardless of what the loop produced. A change whose category falls through the switch, or whose file fails to parse, contributes no statements while the patch still stamps a new version, so the database claims to be at a version whose content it does not have.

Suggested shape

Deriving the child-table writes from one shared description of hardware, used by both scripts, would be better than adding fourteen more hand-written blocks to a file that has already drifted once per table. If that is too large, the minimum viable fix is (3) first, since a wrong version stamp is what makes the other two hard to diagnose after the fact.

Metadata

Metadata

Assignees

No one assigned

    Labels

    scriptsChanges to build/validation scripts

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions