Skip to content

Commit 9ef44b5

Browse files
committed
test(dogfood): pin the equivalence on a store 18.0.0 created from empty (birth-marked, nullable, COALESCE)
Claude-Session: https://claude.ai/code/session_01NnXVu3vF2TKFLMi5Me4CUd Co-authored-by: Claude <noreply@anthropic.com>
1 parent de01287 commit 9ef44b5

1 file changed

Lines changed: 80 additions & 0 deletions

File tree

‎packages/qa/dogfood/test/upgrade-18x-index-equivalence.dogfood.test.ts‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
3030
import type { VerifyStack } from '@objectstack/verify';
3131
import { ceremoniedFixture } from './upgrade-harness/ceremony.js';
3232
import { bootFixture } from './upgrade-harness/populate-fixture.js';
33+
import { relaxTenantColumns } from './pre-18-tenant-column.testkit.js';
3334

3435
const fixtureSql = readFileSync(new URL('./upgrade-harness/fixture-18.0/database.sql', import.meta.url), 'utf8');
3536

@@ -176,6 +177,85 @@ describe('[18.x step 7b] the organization key part across the 18.0 → HEAD upgr
176177
});
177178
});
178179

180+
describe('a store 18.0.0 created from empty: birth-marked, nullable tenant columns, COALESCE organization indexes', () => {
181+
// 18.0.0 (published) births a store with its ownership marker at shape
182+
// generation 1 — the generation HEAD still requires — while it still built
183+
// every tenant column nullable and keyed organization uniques through the
184+
// COALESCE form. Measured on the published 18.0.0 for this part: 34 tenant
185+
// columns, none NOT NULL; 10 of 14 organization uniques in the COALESCE
186+
// form; then HEAD booted it with no refusal and `os migrate plan` read
187+
// 0 changes. This leg models that store from a HEAD birth (same marker),
188+
// the tenant columns relaxed through the drift door and the indexes
189+
// re-spelled exactly as 18.0.0 wrote them, so the CERTIFICATION is the
190+
// only witness: no tenant column here is NOT NULL.
191+
const born = join(dir, 'born-18.0.0.db');
192+
let stack: VerifyStack | undefined;
193+
let respelled: Array<{ name: string; sql: string }> = [];
194+
195+
beforeAll(async () => {
196+
const first = await bootFixture(born);
197+
try {
198+
const ql = (await first.kernel.getServiceAsync('objectql')) as { getDriverForObject(object: string): unknown };
199+
// The tables whose organization unique 18.0.0 keyed through COALESCE —
200+
// the ones whose equivalence is under test. (`sys_setting`'s identity
201+
// index is its runtime migration's, rebuilt every boot.)
202+
const tenantTables = [
203+
...new Set(organizationUniqueIndexes(born).map((i) => i.table).filter((t) => t !== 'sys_setting')),
204+
];
205+
await relaxTenantColumns(ql, tenantTables);
206+
} finally {
207+
await first.stop();
208+
}
209+
const db = new DatabaseSync(born);
210+
try {
211+
for (const index of organizationUniqueIndexes(born)) {
212+
// `sys_setting`'s identity index is its runtime migration's, rebuilt every boot.
213+
if (index.table === 'sys_setting') continue;
214+
const sql = index.sql.replace(/\(\s*([`"]?)organization_id\1\s*([,)])/, "(COALESCE($1organization_id$1, '__global__')$2")
215+
.replace(/,\s*([`"]?)organization_id\1\s*([,)])/, ", COALESCE($1organization_id$1, '__global__')$2");
216+
if (sql === index.sql) continue;
217+
db.exec(`DROP INDEX "${index.name}"`);
218+
db.exec(sql);
219+
respelled.push({ name: index.name, sql });
220+
}
221+
} finally {
222+
db.close();
223+
}
224+
stack = await bootFixture(born);
225+
}, 600_000);
226+
227+
afterAll(async () => {
228+
await stack?.stop();
229+
});
230+
231+
it('is the 18.0.0 shape: a verified generation-1 birth marker, no NOT NULL tenant column, COALESCE indexes', () => {
232+
const db = new DatabaseSync(born, { readOnly: true });
233+
try {
234+
const marker = db.prepare('SELECT verified_at, details FROM sys_migration WHERE id = ?').get(
235+
'adr-0131-organization-ownership',
236+
) as { verified_at: unknown; details: string } | undefined;
237+
expect(marker?.verified_at).toBeTruthy();
238+
expect(JSON.parse(marker!.details).birth?.shapeGeneration).toBe(1);
239+
} finally {
240+
db.close();
241+
}
242+
expect(respelled.length, 'the store holds COALESCE organization indexes').toBeGreaterThanOrEqual(10);
243+
for (const index of respelled) {
244+
const table = organizationUniqueIndexes(born).find((i) => i.name === index.name)!.table;
245+
expect(organizationNotNull(born, table), `${table}.organization_id`).toBe(false);
246+
}
247+
});
248+
249+
it("HEAD boots it, and its differ reports zero recreate_index and zero destructive drift", async () => {
250+
expectNoDestructiveIndexDrift(await managedDrift(stack!));
251+
});
252+
253+
it('every COALESCE index survives the HEAD boot byte for byte', () => {
254+
const after = new Map(organizationUniqueIndexes(born).map((i) => [i.name, i.sql]));
255+
for (const index of respelled) expect(after.get(index.name), index.name).toBe(index.sql);
256+
});
257+
});
258+
179259
describe('a store HEAD creates from empty', () => {
180260
const fresh = join(dir, 'fresh.db');
181261
let stack: VerifyStack | undefined;

0 commit comments

Comments
 (0)