Skip to content

Commit 396b860

Browse files
dmealingclaude
andcommitted
test(migrate-ts): green the migrate-ts-pg lane, red on every release tag
The `migrate-ts-pg` job in integration-tests.yml has failed on EVERY release tag back to at least v0.20.0 -- the same 6 tests on v0.21.0 and v0.21.1. It went unnoticed structurally, not carelessly: the lane runs ONLY on `v*` tag push, so the red arrives AFTER publishing, and the same tests `describe.skip` silently without MIGRATE_TS_PG_URL, so local and PR runs look green. A release gate that is permanently red provides no signal, which is how the #279 serial-PK adoption bug reached a release. Both root causes are test-side; no product defect. 1. Sourceless fixtures (4 of 6 failures). `postgres-lenient-inet` and `pg-adversarial-fixes` declared an `object.entity` with NO `source.rdb` child. Persistability derives from a declared/inherited `source.*` (#249), so those entities are non-persistable: no CREATE TABLE is emitted, the table never exists, and the assertions fail -- then cascade as `relation "endpoints"/"readings" does not exist`. Proven, not inferred: adding `source.rdb` alone takes each file from all-fail to all-pass. 2. Stale CHECK-expression spacing (2 of 6). The expectations still carried `'open', 'closed'` with spaces after the commas, but `checkExprs` runs `normalizeCheckExpr`, which deliberately collapses comma spacing outside literals. The normalizer is right; the expectations predate it. Verified against a real Postgres 16: the full integration suite goes 124 pass / 6 fail -> 130 pass / 0 fail. The no-PG path still skips cleanly (688 pass / 19 skip / 0 fail), so PR runs are unaffected. Deliberately NOT changed: the lane's tag-only trigger. Making it run on merge is a workflow policy decision for the maintainer, not a test fix -- but until it does, this lane can silently rot again. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015TqsuDye2SfXGf43vuoD3n
1 parent 35b0250 commit 396b860

3 files changed

Lines changed: 6 additions & 4 deletions

File tree

‎server/typescript/packages/migrate-ts/test/integration/lifecycle-pg.test.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ d("migrate-ts lifecycle against real Postgres", () => {
159159
expect(orders1.indexes.some((i) => i.unique && i.columns.includes("email"))).toBe(true);
160160
// enum + numeric checks present
161161
expect(checkExprs(orders1)).toEqual(
162-
["qty >= 1", "status in 'open', 'closed'"].sort(),
162+
["qty >= 1", "status in 'open','closed'"].sort(),
163163
);
164164

165165
// ---- v2: evolve ---------------------------------------------------------
@@ -189,7 +189,7 @@ d("migrate-ts lifecycle against real Postgres", () => {
189189
expect(orders2.foreignKeys.some((f) => f.refTable === "lc_customers")).toBe(true);
190190
// evolved checks
191191
const c2 = checkExprs(orders2);
192-
expect(c2).toContain("status in 'open', 'closed', 'cancelled'");
192+
expect(c2).toContain("status in 'open','closed','cancelled'");
193193
expect(c2).toContain("qty >= 1 and qty <= 1000");
194194

195195
// ---- rollback v2 → v1 (down) --------------------------------------------
@@ -203,7 +203,7 @@ d("migrate-ts lifecycle against real Postgres", () => {
203203
expect(colNames(ordersBack)).toEqual(["email", "id", "qty", "status"]); // note/customerId dropped
204204
expect(ordersBack.foreignKeys).toHaveLength(0); // fk dropped
205205
expect(checkExprs(ordersBack)).toEqual(
206-
["qty >= 1", "status in 'open', 'closed'"].sort(), // original checks restored
206+
["qty >= 1", "status in 'open','closed'"].sort(), // original checks restored
207207
);
208208

209209
// ---- idempotency: re-diff v1 against the live (rolled-back) DB ----------
@@ -326,7 +326,7 @@ d("migrate-ts lifecycle against real Postgres", () => {
326326
expect(posts.foreignKeys.some((f) => f.refTable === "gf_users")).toBe(true);
327327
expect(comments.foreignKeys.map((f) => f.refTable).sort()).toEqual(["gf_posts", "gf_users"]);
328328
// enum + numeric checks + unique indexes survived the round-trip
329-
expect(checkExprs(gf.find((t) => t.name === "gf_users")!)).toContain("role in 'admin', 'editor', 'viewer'");
329+
expect(checkExprs(gf.find((t) => t.name === "gf_users")!)).toContain("role in 'admin','editor','viewer'");
330330
expect(checkExprs(posts).some((e) => e.includes("views >= 0"))).toBe(true);
331331
expect(gf.find((t) => t.name === "gf_tags")!.indexes.some((i) => i.unique && i.columns.includes("name"))).toBe(true);
332332

‎server/typescript/packages/migrate-ts/test/integration/pg-adversarial-fixes.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const META = JSON.stringify({
3939
"object.entity": {
4040
name: "Reading",
4141
children: [
42+
{ "source.rdb": { "@table": "readings" } },
4243
{ "field.long": { name: "id" } },
4344
// Bug 6 — the scalar @isArray fan-out beyond string/uuid.
4445
{ "field.int": { name: "counts", isArray: true } },

‎server/typescript/packages/migrate-ts/test/integration/postgres-lenient-inet.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const META = JSON.stringify({
3535
"object.entity": {
3636
name: "Endpoint",
3737
children: [
38+
{ "source.rdb": { "@table": "endpoints" } },
3839
{ "field.long": { name: "id" } },
3940
{ "field.inet": { name: "strictIp" } },
4041
{ "field.inet": { name: "lenientIp", "@lenient": true } },

0 commit comments

Comments
 (0)