feat(jobs): recurring cause-agnostic re-enrichment sweep for terminal enriched_no_match rows #254
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Schema shape probe self-test | |
| # Fail-loudly regression detector for `scripts/schema-shape-report.mjs`. | |
| # | |
| # This workflow used to own the PR comment as well. It no longer does: #1982 | |
| # folded the actual data probe into the `migrate-dryrun` job in test.yml, which | |
| # already restores the latest automated prod snapshot into an ephemeral sandbox | |
| # and therefore needs no standing staging credential. `STAGING_DATABASE_URL_RO` | |
| # — the secret this workflow probed for two months — was never provisioned, so | |
| # the report never produced a single row count. Exactly one thing now owns the | |
| # `<!-- wxyc-schema-shape-report -->` marker, and it is test.yml. | |
| # | |
| # What is left here is the half that must stay loud. The probe inside | |
| # migrate-dryrun is deliberately advisory (it must never redden a required | |
| # migration gate), which means a script that cannot start would degrade to a | |
| # warning annotation nobody reads — the exact silent-failure mode of #1982, | |
| # where ESM module resolution was broken from 2026-06-09 and the check stayed | |
| # green across 47 migrations. This job re-runs that startup path with no | |
| # database and no AWS spend, and it FAILS on regression. | |
| # | |
| # Coverage note: `migrate-dryrun` is gated on the `db-init` paths filter, which | |
| # already covers both `shared/database/src/schema.ts` and | |
| # `shared/database/src/migrations/**`. So every PR that can introduce a new | |
| # constraint still gets a real report. The narrowing is limited to edits of the | |
| # probe's own machinery (this file and the script), which change no constraint | |
| # and now get this self-test instead of a live probe. | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| paths: | |
| - 'shared/database/src/schema.ts' | |
| - 'shared/database/src/migrations/*.sql' | |
| - '.github/workflows/schema-shape-report.yml' | |
| - 'scripts/schema-shape-report.mjs' | |
| # No `pull-requests: write` — this job posts nothing. The comment is owned by | |
| # the migrate-dryrun job in test.yml. | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: schema-shape-self-test-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| self-test: | |
| name: Schema shape probe self-test | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - name: Checkout PR head with merge-base history | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| - name: Set up Node | |
| uses: actions/setup-node@v7 | |
| with: | |
| node-version: '24' | |
| cache: 'npm' | |
| - name: Install postgres client | |
| # KEEP IN SYNC with the `Install minimal deps for dryrun script` step | |
| # in test.yml's migrate-dryrun job. The whole point of this self-test | |
| # is to exercise the same module-resolution path the real probe uses; | |
| # if the two installs diverge, this job starts testing something else | |
| # and #1982 can recur undetected. | |
| # | |
| # `--workspaces=false` skips workspace resolution, but npm still reads | |
| # the root manifest and resolves the `@wxyc/shared` dependency against | |
| # GitHub Packages, so NPM_TOKEN is required (verified: without it the | |
| # install dies with E401 on `@wxyc%2fshared`). This replaces the old | |
| # isolated-install-plus-symlink workaround, which existed only because | |
| # Node's ESM loader ignores NODE_PATH. | |
| run: npm install --workspaces=false --no-save --no-package-lock --no-audit --no-fund postgres drizzle-orm | |
| env: | |
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| - name: Verify postgres module resolves (ESM smoke check) | |
| # The #1982 regression detector proper. Node's ESM resolver walks up | |
| # parent node_modules dirs from the importing file, so this is a real | |
| # test of the install above rather than a tautology. | |
| run: | | |
| node -e " | |
| import('postgres') | |
| .then(() => { console.log('postgres module resolves OK'); }) | |
| .catch((err) => { | |
| console.error('postgres module failed to resolve via ESM import:', err.message); | |
| process.exit(1); | |
| }); | |
| " | |
| - name: Run the report script end-to-end with no probe target | |
| # Exercises everything the live probe does except the SQL round-trip: | |
| # module load, diff parse, all five constraint detectors, SELECT | |
| # generation and markdown rendering. With no probe target configured | |
| # the script must still exit 0 and emit a marker-bearing comment body | |
| # (#703's never-throw contract). A non-zero exit or a missing marker | |
| # means the script is broken and the real probe would silently produce | |
| # nothing — which is the failure this job exists to catch. | |
| run: | | |
| set -euo pipefail | |
| mkdir -p .cache | |
| BASE_REF='${{ github.event.pull_request.base.ref }}' | |
| # Full fetch (no --depth=1) plus an explicit merge-base, matching the | |
| # probe step in test.yml. The original workflow shallow-fetched the | |
| # base and used `git diff origin/main...HEAD`, which dies with | |
| # "no merge base" whenever the branch is behind main — a depth-1 | |
| # fetch gets main's tip and nothing else, so there is no common | |
| # ancestor to find. That went unnoticed because the diff was | |
| # suffixed `|| true`, silently yielding an EMPTY diff and a | |
| # "no schema or migration changes detected" comment. | |
| git fetch --no-tags origin "$BASE_REF" | |
| MERGE_BASE=$(git merge-base FETCH_HEAD HEAD) | |
| git diff "$MERGE_BASE" HEAD -- \ | |
| 'shared/database/src/schema.ts' \ | |
| 'shared/database/src/migrations/*.sql' \ | |
| > .cache/pr.diff | |
| node scripts/schema-shape-report.mjs --diff .cache/pr.diff > .cache/comment.md | |
| echo '--- rendered comment (not posted) ---' | |
| cat .cache/comment.md | |
| if ! grep -q '<!-- wxyc-schema-shape-report -->' .cache/comment.md; then | |
| echo 'schema-shape-report.mjs produced no marker-bearing comment body' >&2 | |
| exit 1 | |
| fi |