Skip to content

Switch PG to wxyc-postgres image; add F0000 precheck to migration 0003 #41

@jakebromberg

Description

@jakebromberg

Problem

The CREATE TEXT SEARCH DICTIONARY wxyc_unaccent step in migrations/0003_wxyc_identity_match_functions.sql requires wxyc_unaccent.rules to be present at $SHAREDIR/tsearch_data/ on the destination PG. Today, CI provisions this via docker cp into the postgres:16-alpine service container; production Railway PG has no provisioning step in rebuild-cache.yml. The next workflow_dispatch run against a fresh Railway PG will fail at sqlx migrate run with ConfigFileError.

Sibling defect to WXYC/discogs-etl#223. Closed deploy ticket #37 was a paper tiger — the migration applied via CI but the production Railway destination has never been exercised against a fresh DB. Verified 2026-05-20 (against postgres:16-alpine): /usr/local/share/postgresql/tsearch_data/ is root:root 0755, so no in-migration write strategy can self-provision the file. SQLSTATE for the missing-rules-file error is F0000 (config_file_error).

Desired end state

Switch local + production PG to the new ghcr.io/wxyc/wxyc-postgres:pg16 image (built + published by WXYC/wxyc-etl — see the blocking issue, filed alongside this one). Migration 0003 gets a fail-fast precheck for SQLSTATE F0000 that re-raises with an actionable error pointing operators at the wxyc-postgres runbook when the rules file is missing.

Where

  • docker-compose.ymlimage: postgres:16-alpineimage: ghcr.io/wxyc/wxyc-postgres:pg16
  • .github/workflows/ci.yml — drop the Install wxyc_unaccent rules into the PG service container step; update PG service image: to ghcr.io/wxyc/wxyc-postgres:pg16
  • migrations/0003_wxyc_identity_match_functions.sql — wrap CREATE TEXT SEARCH DICTIONARY in a plpgsql DO block that catches SQLSTATE 'F0000' and re-raises with an actionable error including the runbook URL
  • tests/wxyc_identity_match_parity_test.rs — add a negative-path test that runs the migration against a stock postgres:16-alpine (no rules file), asserts the exception message contains wxyc_unaccent.rules and the runbook URL
  • CLAUDE.md — note the wxyc-postgres image dependency in the migration/CI section

Plpgsql precheck shape

DO $$
BEGIN
    CREATE TEXT SEARCH DICTIONARY wxyc_unaccent (
        TEMPLATE = unaccent,
        RULES = 'wxyc_unaccent'
    );
EXCEPTION
    WHEN SQLSTATE 'F0000' THEN
        RAISE EXCEPTION USING
            MESSAGE = 'wxyc_unaccent.rules is missing from $SHAREDIR/tsearch_data/. '
                      'The destination PG must run the wxyc-postgres image '
                      '(ghcr.io/wxyc/wxyc-postgres:pg16). Runbook: '
                      'https://github.com/WXYC/wxyc-etl/blob/main/docs/wxyc-postgres-image.md',
            ERRCODE = 'F0000';
END;
$$;

Other SQLSTATEs propagate unchanged.

Constraints

  • Don't regress the existing parity test against the dictionary-functional path (file present → dictionary works → byte-equality holds).
  • Operator action (Railway PG service swap) is one-time, documented in the wxyc-postgres runbook. This issue covers the per-repo code changes only.
  • Don't bump migration numbers; edit 0003_wxyc_identity_match_functions.sql in place. The migration is idempotent and re-applying after the precheck is added against an already-stamped DB is a no-op.

Acceptance criteria

  • Local docker-compose.yml uses ghcr.io/wxyc/wxyc-postgres:pg16
  • CI workflow drops the docker-cp step; uses the wxyc-postgres image as the PG service
  • Migration 0003 plpgsql precheck catches F0000 → actionable error with runbook URL
  • Negative test: stock postgres:16-alpine + sqlx migrate run → expected message
  • Positive test: existing parity test still passes against the wxyc-postgres image
  • Operator: Railway PG service swapped to ghcr.io/wxyc/wxyc-postgres:pg16 (manual, tracked in the wxyc-etl runbook checklist)
  • workflow_dispatch of rebuild-cache.yml against post-swap Railway PG succeeds end-to-end

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingconcern:schema-migrationPR ships a Drizzle / sqlx / alembic migrationcross-cache-identityProject tag for the cross-cache-identity initiative (library hook + identity record + normalization)epic:e3-normalizationParent epic E3 — standardize and document the normalization functionphase:0Phase 0 — prerequisites (audits, schema bumps, doc prereqs)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions