Repository navigation
Commit 4c7dcb4
test(driver-sql): the three live-MySQL NULL-safe shadow suites model a pre-18 store (#25142)
Refs #25131
Clause-②: no (test fixtures only: no response, status, error, outcome or
export moves)
Metadata-protocol: none
`main`'s hourly full run is red in `Temporal Conformance (live PG +
MySQL)`, in the step "Run driver-sql suite against both live servers".
This PR changes only the fixture setup of the three live-MySQL suites
that fail there. No production file moves, and no test or assertion is
narrowed, skipped or deleted.
## What is red, measured on `60b42cd0b7` and on today's `abc25a35`
**7 failures, not the 6 the card names.** The card's count was read on
`fccbd9d0d5`, before #24893 (`d5d8146012`, 18.x step 7b-1 + 7b-2)
landed. The hourly run's own log at `60b42cd0b7` (run 39683348463, job
119511306969) lists 7. My local reproduction below lists the same 7, by
name.
| File | Failing test | What failed |
|---|---|---|
| `sql-driver-12998-shadow-null-safe-key.test.ts` | collides two
NULL-organization rows under an org-scoped shadow unique | the
generation expression has no `coalesce` |
| 12998 | diagnoses existing NULL-org duplicates instead of failing the
boot unexplained | setup insert: `Column 'organization_id' cannot be
null` |
| 12998 | names a NULL-organization duplicate in declared terms, never
as a collision | setup insert: `Field 'organization_id' doesn't have a
default value` |
| 12998 | counts the sixth conflicting group in the shared "more
group(s)" tail | setup insert: `Column 'organization_id' cannot be null`
|
| `sql-driver-13015-shadow-carried-index-drift.test.ts` | survives "os
migrate apply --allow-destructive" over every reported entry | setup
insert: `Column 'organization_id' cannot be null` |
| 13015 | reports and repairs a shadow that hashes the raw columns | no
drift reported for a raw shadow |
| `sql-driver-15479-shadow-plain-unique-duplicates.test.ts` | leaves the
NULL-safe arm saying the NULL-safe thing | setup insert: `Column
'organization_id' cannot be null` |
**There are two causes, not one.**
- **7b-0 (#24940):** `initObjects` creates `organization_id` NOT NULL,
so the suites' NULL-organization seeds are refused. That accounts for 5
of the 7.
- **7b-2 (#24893):** a `unique: 'organization'` declaration now keys the
PLAIN tenant column. On a fresh table this is correct and certified. So
the shadow no longer carries `COALESCE(organization_id, '__global__')`,
and a raw-column shadow is no longer drift. That accounts for the other
2.
- Every one of the 7 pins the NULL-safe hash-shadow arm. Since 7b-2, the
driver reaches that arm only from an index input that already carries
`nullSafeColumns` (`normalizeDeclaredIndex`: "honoured verbatim"), which
is the shape a database built before 18.x holds.
- So `asPre18TenantColumn` alone, the route the claim names, greens 5 of
the 7 at most. The other 2 would still assert a COALESCE form that the
declaration no longer produces.
## The change (fixture setup only, the three files)
- The org-scoped index these tests use is declared in its **18.0 form**:
`fields: ['organization_id', 'v'], unique: true, nullSafeColumns:
['organization_id']`.
- This is the same spelling #24893 itself adopted for the retained
NULL-safe path in `driver-turso`'s
`turso-remote-drift-detection.test.ts` and
`turso-remote-migration-entries.test.ts`.
- The index names are unchanged.
- Where it applies:
- 12998: its `orgUniqueOn`, used by all four org tests.
- 15479: its control `orgUniqueOn`.
- 13015: a new `pre18OrgUniqueOn`, used only by the two failing live
tests. The two passing live tests keep the plain declaration.
- `asPre18TenantColumn(driver, table)` follows each `initObjects` whose
table then receives NULL-organization rows: seven call sites. This is
the pattern 7b-0 wired into the other driver-sql suites.
- In 15479 the call is conditional on the seed row carrying
`organization_id: null`. Only the control does; the plain and global
arms stamp an organization or have no tenant column.
- Every assertion is untouched.
## Measured before the edit
- **The second `initObjects` does not restore NOT NULL.** A scratch
probe against the built driver on live MySQL 8.0 read
`information_schema.COLUMNS.IS_NULLABLE`:
- after the first `initObjects`: `NO`;
- after `asPre18TenantColumn`: `YES`;
- after a second `initObjects` with the index, on the same driver (12998
dirty/tail and the 15479 shape): `YES`;
- after a second `initObjects` on a new driver (the 13015 apply shape):
`YES`;
- `detectManagedDrift` then reports `[]`, and
`applyMigrationEntries(..., { allowDestructive: true })` leaves it
`YES`.
- So no second relax is needed anywhere.
- **Why the PG cell passes:** none of the three suites has a PostgreSQL
cell. The hash-shadow route exists only because MySQL refuses a key part
over its 768-character ceiling; PostgreSQL and SQLite never take it. The
PG-gated suites that seed organization-less rows were wired with
`asPre18TenantColumn` by 7b-0.
- **Census** of the live-gated `driver-sql` suites:
- Static pass: 79 test files use `declareDialectCell`, a dialect cell or
an `OS_TEST_*_URL`. Only these three insert organization-less rows
without the relax. The one other hit,
`sql-driver-tenant-column-not-null.test.ts`, inserts NULL on purpose to
pin 7b-0's refusal.
- Measured pass: the full live run below. 242/242 files are green, so no
fourth file surfaces.
## Verification
Live MySQL 8.0 (`mirror.gcr.io/library/mysql:8.0`, `SET GLOBAL time_zone
= '+08:00'`) and PostgreSQL 16 (`mirror.gcr.io/library/postgres:16`,
timezone `Asia/Shanghai`), both in local containers, with CI's
environment: `TZ=America/New_York`, `OS_TEST_MYSQL_URL`,
`OS_TEST_POSTGRES_URL` and `OS_EXPECT_LIVE_DIALECT_MATRIX=1`.
| Run | Head | Result |
|---|---|---|
| The three files, live, before the edit | `abc25a35` | `Test Files 3
failed (3)`, `Tests 7 failed / 12 passed (19)`: the 7 above |
| The three files, live, after the edit | `e4c6eaf7c` | `Test Files 3
passed (3)`, `Tests 19 passed (19)` |
| `pnpm --filter @objectstack/driver-sql test`, live PG + MySQL (CI's
step) | `e4c6eaf7c` | `Test Files 242 passed (242)`, `Tests 5688 passed
/ 2 skipped (5690)`, exit 0 |
| `pnpm --filter @objectstack/driver-sql test`, default (no live
servers) | `e4c6eaf7c` | `Test Files 230 passed / 12 skipped (242)`,
`Tests 3742 passed / 212 skipped`, exit 0 |
| `pnpm --filter @objectstack/driver-sql typecheck` | `e4c6eaf7c` | exit
0. `tsc --listFiles` lists all three files. |
**Gates on `e4c6eaf7c`.** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` derived 54 families.
- All 54 ran, with each exit code captured before any pipe.
- 52 exited 0. `check:dual-build-cjs-loads` and
`check:lean-entry-closure` exited 3 (PREREQUISITE NOT MET); after `pnpm
exec turbo run build --concurrency=2` (77/77), both exit 0.
- `--ran` reconciliation: "54 derived, 54 run, 0 NOT-MEASURED, 0 UNRUN",
a DERIVED zero.
- `origin/main` was merged before this PR opened: already up to date at
`abc25a35`.
**Changeset.** `skip-changeset`: `@objectstack/driver-sql` ships `files:
[dist, README.md, CHANGELOG.md]`. Built-dist grep: the test fixture
symbols hit 0 files, and the control `relax_not_null` hits 4.
**The hourly run.** `Temporal Conformance (live PG + MySQL)` runs only
on push, schedule and dispatch, never on a PR or in the queue. This PR's
CI therefore does not run the live cell. The local live run above is its
proof here, and the next hourly full run after merge is the proof on
`main`.
## Acceptance notes
- **The claim's fence.** The claim named `asPre18TenantColumn` alone.
The measurement shows that 2 of the 7 failures come from 7b-2's plain
key form, not from 7b-0's NOT NULL. The fix stays in the claim's three
files and in fixture setup, and follows #24893's own Turso precedent for
the retained NULL-safe path.
- **Card arithmetic.** The card body and its triage count 6 failures,
read at `fccbd9d0d5`. At `60b42cd0b7` and later it is 7: the extra one
is 13015's "reports and repairs a shadow that hashes the raw columns".
- **Not in scope:** #25132 remains open, and the NOT NULL itself
(ADR-0131 D1) is untouched.
---
_Generated by [Claude
Code](https://claude.ai/code/session_018gewcgUaNUX9hMkxeP2HE2)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent abc25a3 commit 4c7dcb4
3 files changed
Lines changed: 67 additions & 8 deletions
File tree
- packages/drivers/driver-sql/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
46 | | - | |
47 | | - | |
48 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
49 | 50 | | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
50 | 58 | | |
51 | 59 | | |
52 | 60 | | |
53 | 61 | | |
54 | 62 | | |
55 | 63 | | |
56 | 64 | | |
57 | | - | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
58 | 73 | | |
59 | 74 | | |
60 | 75 | | |
| |||
100 | 115 | | |
101 | 116 | | |
102 | 117 | | |
| 118 | + | |
103 | 119 | | |
104 | 120 | | |
105 | 121 | | |
| |||
184 | 200 | | |
185 | 201 | | |
186 | 202 | | |
| 203 | + | |
187 | 204 | | |
188 | 205 | | |
189 | 206 | | |
| |||
220 | 237 | | |
221 | 238 | | |
222 | 239 | | |
| 240 | + | |
223 | 241 | | |
224 | 242 | | |
225 | 243 | | |
| |||
266 | 284 | | |
267 | 285 | | |
268 | 286 | | |
| 287 | + | |
269 | 288 | | |
270 | 289 | | |
271 | 290 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
56 | 56 | | |
57 | 57 | | |
58 | 58 | | |
| 59 | + | |
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
| |||
230 | 231 | | |
231 | 232 | | |
232 | 233 | | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
233 | 254 | | |
234 | 255 | | |
235 | 256 | | |
| |||
304 | 325 | | |
305 | 326 | | |
306 | 327 | | |
307 | | - | |
| 328 | + | |
308 | 329 | | |
| 330 | + | |
309 | 331 | | |
310 | 332 | | |
311 | 333 | | |
| |||
355 | 377 | | |
356 | 378 | | |
357 | 379 | | |
358 | | - | |
| 380 | + | |
359 | 381 | | |
| 382 | + | |
360 | 383 | | |
361 | 384 | | |
362 | 385 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| |||
73 | 74 | | |
74 | 75 | | |
75 | 76 | | |
76 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
77 | 84 | | |
78 | 85 | | |
79 | 86 | | |
80 | 87 | | |
81 | 88 | | |
82 | 89 | | |
83 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
84 | 98 | | |
85 | 99 | | |
86 | 100 | | |
| |||
130 | 144 | | |
131 | 145 | | |
132 | 146 | | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
133 | 150 | | |
134 | 151 | | |
135 | 152 | | |
| |||
0 commit comments