This does not fix the failure and does not guess at it.#154 has been wrong twice from reasoning ahead of evidence; this adds the measurement it identified in August and never took, so the next occurrence answers the question instead of reopening it.
Why the previous explanations are all dead
The observation that kills them: the schema comes back. A suite fails because orders does not exist, and a later suite truncating that same table passes. A dropped database does not un-drop itself.
Run 895 shows the same impossible pattern — PASS adminGate, FAIL schemaLoss, PASS adminVersion, with categoriesTags failing on missing tables in between.
So this was never one database losing its schema. More than one server answering to one name produces exactly this, and Docker's embedded DNS round-robins every container sharing an alias — a leftover service container from an earlier run fits every observation, including the empty dmesg that killed the OOM theory.
What this adds
globalSetup logs every address the database host resolves to. More than one is the answer outright. One address means this reading is wrong too, and the next suspect is a single container restarted with a fresh data directory.
Both globalSetup and a failing assertSchemaPresent record which server actually answered.pg_postmaster_start_time() is what settles that, and needs no special rights: two Postgres instances cannot share one. Differing values within a single run are proof, where a differing inet_server_addr alone could be argued to be one container that moved.
The failure message now tells the reader to compare the two, rather than leaving them to work out that this is the interesting comparison.
Three deliberate choices
Logged on passing runs too. A failing run's addresses mean nothing without a passing run's to compare against, and this issue has twice suffered from having only the failure to look at.
Neither probe can throw. A diagnostic that fails the run it was added to explain is worse than none — both are wrapped and degrade to a printed reason.
The failure path costs one extra round trip, taken only when the schema is already known to be missing. assertSchemaPresent is not on the hot path; resetDb calls it only after its TRUNCATE has already failed.
Why now
Run 895 reproduced this on main — 38 integration failures, 20 e2e, with relation "items" does not exist37 times underneath assertion errors about tags and price filters. The same misdirection the issue documents.
Today is also the best case yet for the leftover-container theory: the runner had a six-deep backlog, and run 893 was killed mid-execution, which is precisely how a service container gets orphaned while keeping the postgres alias.
Verification
tsc clean · typecheck:tests clean · lint 0 errors, no new warnings.
Checked specifically: all four message patterns schemaLoss.integration.test.ts asserts on are still present, and the probe reads only pg_catalog functions — so it still answers against the dropped schema that suite deliberately creates.
Not verified by running the integration suite, which needs a database this machine cannot provide. The next CI run is what produces the measurement.
**This does not fix the failure and does not guess at it.** #154 has been wrong twice from reasoning ahead of evidence; this adds the measurement it identified in August and never took, so the next occurrence answers the question instead of reopening it.
## Why the previous explanations are all dead
The observation that kills them: **the schema comes back.** A suite fails because `orders` does not exist, and a later suite truncating that same table passes. A dropped database does not un-drop itself.
Run 895 shows the same impossible pattern — `PASS adminGate`, `FAIL schemaLoss`, `PASS adminVersion`, with `categoriesTags` failing on missing tables in between.
So this was never one database losing its schema. **More than one server answering to one name** produces exactly this, and Docker's embedded DNS round-robins every container sharing an alias — a leftover service container from an earlier run fits every observation, including the empty `dmesg` that killed the OOM theory.
## What this adds
**`globalSetup` logs every address the database host resolves to.** More than one is the answer outright. One address means this reading is wrong too, and the next suspect is a single container restarted with a fresh data directory.
**Both `globalSetup` and a failing `assertSchemaPresent` record which server actually answered.** `pg_postmaster_start_time()` is what settles that, and needs no special rights: two Postgres instances cannot share one. Differing values within a single run are proof, where a differing `inet_server_addr` alone could be argued to be one container that moved.
The failure message now tells the reader to compare the two, rather than leaving them to work out that this is the interesting comparison.
## Three deliberate choices
- **Logged on passing runs too.** A failing run's addresses mean nothing without a passing run's to compare against, and this issue has twice suffered from having only the failure to look at.
- **Neither probe can throw.** A diagnostic that fails the run it was added to explain is worse than none — both are wrapped and degrade to a printed reason.
- **The failure path costs one extra round trip**, taken only when the schema is already known to be missing. `assertSchemaPresent` is not on the hot path; `resetDb` calls it only after its `TRUNCATE` has already failed.
## Why now
Run 895 reproduced this on `main` — 38 integration failures, 20 e2e, with `relation "items" does not exist` **37 times** underneath assertion errors about tags and price filters. The same misdirection the issue documents.
Today is also the best case yet for the leftover-container theory: the runner had a six-deep backlog, and **run 893 was killed mid-execution**, which is precisely how a service container gets orphaned while keeping the `postgres` alias.
## Verification
`tsc` clean · `typecheck:tests` clean · lint 0 errors, no new warnings.
Checked specifically: all four message patterns `schemaLoss.integration.test.ts` asserts on are still present, and the probe reads only `pg_catalog` functions — so it still answers against the dropped schema that suite deliberately creates.
**Not verified by running the integration suite**, which needs a database this machine cannot provide. The next CI run is what produces the measurement.
Refs #154
🤖 Generated with [Claude Code](https://claude.com/claude-code)
This adds the measurement #154 has needed twice and never had. It does not fix the failure and does not guess at it: the issue has been wrong twice from reasoning ahead of evidence, and the point here is to make the next occurrence answer the question rather than reopen it.
The observation that rules out every explanation so far is that the schema comes back. A suite fails because orders does not exist, and a later suite truncating that same table passes. A dropped database does not un-drop itself, so this was never one database losing its schema. More than one server answering to one name produces exactly this, and Docker embedded DNS round-robins every container sharing an alias, so a leftover service container from an earlier run fits every observation including the empty dmesg that killed the OOM theory.
globalSetup now logs every address the database host resolves to. More than one is the answer outright. One address means this reading is wrong too, and the next suspect is a single container restarted with a fresh data directory.
Alongside it, both globalSetup and a failing assertSchemaPresent record which server actually answered. pg_postmaster_start_time is what settles that and needs no special rights: two Postgres instances cannot share one, so differing values within a single run are proof, where a differing inet_server_addr alone could be argued to be one container that moved. The failure message now says to compare the two rather than leaving the reader to know that is the interesting comparison.
Logged on a passing run as well as a failing one, deliberately. A failing run's addresses mean nothing without a passing run's to compare them against, and this issue has twice suffered from having only the failure to look at.
Neither can throw. A diagnostic that fails the run it was added to explain is worse than no diagnostic, so both are wrapped and both degrade to a printed reason.
The failure path costs one extra round trip, taken only when the schema is already known to be missing. assertSchemaPresent is not on the hot path — resetDb calls it only when its TRUNCATE has already failed.
Verified: tsc clean, typecheck:tests clean, lint 0 errors with no new warnings, and the four message patterns schemaLoss.integration.test.ts asserts on are all still present. The probe reads only pg_catalog functions, so it still answers against the dropped schema that suite creates.
Refs #154
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
This does not fix the failure and does not guess at it. #154 has been wrong twice from reasoning ahead of evidence; this adds the measurement it identified in August and never took, so the next occurrence answers the question instead of reopening it.
Why the previous explanations are all dead
The observation that kills them: the schema comes back. A suite fails because
ordersdoes not exist, and a later suite truncating that same table passes. A dropped database does not un-drop itself.Run 895 shows the same impossible pattern —
PASS adminGate,FAIL schemaLoss,PASS adminVersion, withcategoriesTagsfailing on missing tables in between.So this was never one database losing its schema. More than one server answering to one name produces exactly this, and Docker's embedded DNS round-robins every container sharing an alias — a leftover service container from an earlier run fits every observation, including the empty
dmesgthat killed the OOM theory.What this adds
globalSetuplogs every address the database host resolves to. More than one is the answer outright. One address means this reading is wrong too, and the next suspect is a single container restarted with a fresh data directory.Both
globalSetupand a failingassertSchemaPresentrecord which server actually answered.pg_postmaster_start_time()is what settles that, and needs no special rights: two Postgres instances cannot share one. Differing values within a single run are proof, where a differinginet_server_addralone could be argued to be one container that moved.The failure message now tells the reader to compare the two, rather than leaving them to work out that this is the interesting comparison.
Three deliberate choices
assertSchemaPresentis not on the hot path;resetDbcalls it only after itsTRUNCATEhas already failed.Why now
Run 895 reproduced this on
main— 38 integration failures, 20 e2e, withrelation "items" does not exist37 times underneath assertion errors about tags and price filters. The same misdirection the issue documents.Today is also the best case yet for the leftover-container theory: the runner had a six-deep backlog, and run 893 was killed mid-execution, which is precisely how a service container gets orphaned while keeping the
postgresalias.Verification
tscclean ·typecheck:testsclean · lint 0 errors, no new warnings.Checked specifically: all four message patterns
schemaLoss.integration.test.tsasserts on are still present, and the probe reads onlypg_catalogfunctions — so it still answers against the dropped schema that suite deliberately creates.Not verified by running the integration suite, which needs a database this machine cannot provide. The next CI run is what produces the measurement.
Refs #154
🤖 Generated with Claude Code