Skip to content

Commit 730cbca

Browse files
committed
fix(metadata-protocol): migration, boot and protocol log lines state each decision in words instead of a tracker number (stage 2, log lines)
The kernel:ready index migrations, the seed/API tenancy repair and its receipt, the three migration-skipped warnings, and the protocol's warn and error lines no longer cite a tracker number. Where the sentence already said what was decided, only the citation goes; the three skipped warnings now say what the migration that did not run would have ensured. Two tests that pinned a number now pin the sentence. Text only. The ledger is recomputed; only metadata-protocol rows move. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
1 parent dc8a1a1 commit 730cbca

10 files changed

Lines changed: 40 additions & 73 deletions

‎packages/metadata-protocol/src/migrations/overlay-index.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ export async function ensureOverlayStateIndex(
271271
logger,
272272
`[metadata-protocol] could not create '${indexName}' on "${OVERLAY_TABLE}" after the probe ` +
273273
`succeeded — the table may currently have NO unique index over ` +
274-
`(${overlayIndexKeyParts().join(', ')}) among state='${state}' rows. Restart to retry (#6418).`,
274+
`(${overlayIndexKeyParts().join(', ')}) among state='${state}' rows. Restart to retry.`,
275275
detail,
276276
);
277277
return { status: 'failed', detail, fallback: 'not-attempted' };
@@ -374,7 +374,7 @@ function reportDegradation(
374374
`(${columns}) is enforced only as far as it was before; ADR-0005 overlay uniqueness is NOT ` +
375375
`enforced until the duplicates are resolved, and getMetaItem has no defined answer for ` +
376376
`which of the colliding rows wins. List them with: ${duplicateQuery} — or run ` +
377-
`"os migrate duplicates" — then restart (ADR-0120 D4, #6418, #8725).`,
377+
`"os migrate duplicates" — then restart (ADR-0120 D4).`,
378378
detail,
379379
);
380380
return;
@@ -390,7 +390,7 @@ function reportDegradation(
390390
`[metadata-protocol] could not rebuild '${indexName}' on "${OVERLAY_TABLE}" as the ` +
391391
`state='${state}' partial UNIQUE index; the existing index is unchanged, so two ${state} ` +
392392
`overlay rows for one (${columns}) can still coexist while everything else looks healthy. ` +
393-
`Fix the cause below and restart (#6418).`,
393+
`Fix the cause below and restart.`,
394394
detail,
395395
);
396396
}

‎packages/metadata-protocol/src/migrations/seed-tenancy-backfill.ts‎

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,15 +1147,15 @@ export async function recordSeedTenancyReceipt(
11471147
): Promise<void> {
11481148
const ledger = seam?.ledger;
11491149
const notRecorded =
1150-
`[metadata-protocol] the seed/API tenancy repair (#8686) ran and rewrote stored rows, but this ` +
1150+
`[metadata-protocol] the seed/API tenancy repair ran and rewrote stored rows, but this ` +
11511151
`deployment has NO durable record that it did`;
11521152
if (!ledger) {
11531153
// Functional absence, not a durability failure: this host is not an engine
11541154
// (a raw seam built by hand, a test double), so there is no ledger to miss.
11551155
// `warn` per AGENTS.md — the system is visibly smaller, not silently lying.
11561156
logger?.warn?.(
11571157
`${notRecorded} — no engine was resolved beside the raw-SQL seam, so ${DATA_MIGRATION_FLAG_OBJECT} ` +
1158-
`could not be written. Capture this boot's log before restarting (#9451).`,
1158+
`could not be written. Capture this boot's log before restarting.`,
11591159
);
11601160
return;
11611161
}
@@ -1164,15 +1164,15 @@ export async function recordSeedTenancyReceipt(
11641164
logger?.warn?.(
11651165
`${notRecorded} — ${DATA_MIGRATION_FLAG_OBJECT} is not registered on this kernel, so the ` +
11661166
`deployment ledger does not exist here. Compose PlatformObjectsPlugin (it carries the ledger ` +
1167-
`every served kernel gets) or capture this boot's log before restarting (#9451).`,
1167+
`every served kernel gets) or capture this boot's log before restarting.`,
11681168
);
11691169
return;
11701170
}
11711171
const flag = buildSeedTenancyReceipt(result, new Date().toISOString());
11721172
const outcome = await persistSeedTenancyReceiptRow(ledger, flag);
11731173
logger?.info?.(
11741174
`[metadata-protocol] seed/API tenancy repair recorded in ${DATA_MIGRATION_FLAG_OBJECT} ` +
1175-
`(id '${SEED_TENANCY_MIGRATION_ID}', ${outcome}) — the run survives this process (#9451).`,
1175+
`(id '${SEED_TENANCY_MIGRATION_ID}', ${outcome}) — the run survives this process.`,
11761176
{ id: SEED_TENANCY_MIGRATION_ID, outcome, details: flag.details },
11771177
);
11781178
} catch (e: unknown) {
@@ -1184,7 +1184,7 @@ export async function recordSeedTenancyReceipt(
11841184
`Nothing else reports it: capture this boot's log NOW, before the container is replaced. Fix: make ` +
11851185
`${DATA_MIGRATION_FLAG_OBJECT} writable on this deployment (it is provisioned by ` +
11861186
`PlatformObjectsPlugin) and verify with ` +
1187-
`SELECT * FROM ${DATA_MIGRATION_FLAG_OBJECT} WHERE id = '${SEED_TENANCY_MIGRATION_ID}' (#9451).`;
1187+
`SELECT * FROM ${DATA_MIGRATION_FLAG_OBJECT} WHERE id = '${SEED_TENANCY_MIGRATION_ID}'.`;
11881188
if (logger?.error) logger.error(message, e instanceof Error ? e : new Error(detail));
11891189
else logger?.warn?.(message, { error: detail });
11901190
}
@@ -1291,7 +1291,7 @@ export async function backfillSeedTenancy(
12911291
if (postureEnforcesWall(resolveTenancyPosture())) {
12921292
logger?.warn?.(
12931293
`[metadata-protocol] seed/API tenancy split detected on a MULTI-ORGANIZATION install — ` +
1294-
`backfill skipped (#8686). Affected: ${affected}. ` +
1294+
`backfill skipped. Affected: ${affected}. ` +
12951295
`Seed rows carry ${ORGANIZATION_FIELD} = NULL while API rows carry a real organization, so each ` +
12961296
`object runs two autonumber counters and can mint the same "unique" identifier twice — the ` +
12971297
`partitioned unique index (COALESCE(${ORGANIZATION_FIELD}, '${GLOBAL_TENANT}'), <field>) does not ` +
@@ -1369,7 +1369,7 @@ export async function backfillSeedTenancy(
13691369
if (organizationIds.length === 0 && organizationProbeError === undefined) {
13701370
logger?.info?.(
13711371
`[metadata-protocol] seed/API tenancy split detected on an install with no organization yet — ` +
1372-
`nothing to adopt, and nothing at risk (#8686). Affected: ${affected}. ` +
1372+
`nothing to adopt, and nothing at risk. Affected: ${affected}. ` +
13731373
`${ORGANIZATION_TABLE} is empty, so each of these objects runs exactly ONE counter (its ` +
13741374
`'${GLOBAL_TENANT}' row) and no "unique" identifier can be minted twice while there is only ` +
13751375
`one partition. No operator action: this self-heals at the first sign-up, when the ` +
@@ -1384,7 +1384,7 @@ export async function backfillSeedTenancy(
13841384
if (organizationIds.length !== 1) {
13851385
logger?.warn?.(
13861386
`[metadata-protocol] seed/API tenancy split detected but the target organization is not ` +
1387-
`derivable — backfill skipped (#8686). Affected: ${affected}. ` +
1387+
`derivable — backfill skipped. Affected: ${affected}. ` +
13881388
`The install reports tenancy posture 'single' but holds ${organizationIds.length} rows in ` +
13891389
`${ORGANIZATION_TABLE} (exactly 1 is required to adopt one without guessing). Until this is ` +
13901390
`resolved these objects run two autonumber counters and can mint the same "unique" identifier ` +
@@ -1399,7 +1399,7 @@ export async function backfillSeedTenancy(
13991399
`NOTE: the ${ORGANIZATION_TABLE} probe FAILED` +
14001400
(organizationProbeError === '' ? '' : ` (${organizationProbeError})`) +
14011401
`, so the count above is "unknown", not a measured zero — an unreadable probe is ` +
1402-
`reported here rather than through the benign no-organization-yet path (#9261). `) +
1402+
`reported here rather than through the benign no-organization-yet path. `) +
14031403
SNAPSHOT_CAVEAT,
14041404
// `organizationProbeError` is `undefined` — and so serializes AWAY — when
14051405
// the probe answered; a probe that failed carries its text, `''` and all.
@@ -1431,7 +1431,7 @@ export async function backfillSeedTenancy(
14311431
} catch (e) {
14321432
logger?.warn?.(
14331433
`[metadata-protocol] could not list already-minted duplicates for ${split.object}.${split.field} ` +
1434-
`(#8686) — the backfill continues; verify manually with: ` +
1434+
`— the backfill continues; verify manually with: ` +
14351435
`${buildCollisionProbeSql(split.object, split.field, client)}`,
14361436
{ error: operatorFacingErrorText(e) },
14371437
);
@@ -1456,7 +1456,7 @@ export async function backfillSeedTenancy(
14561456
} catch (e) {
14571457
stampFailures.push(object);
14581458
logger?.warn?.(
1459-
`[metadata-protocol] seed tenancy backfill could not stamp ${object} (#8686) — its rows keep ` +
1459+
`[metadata-protocol] seed tenancy backfill could not stamp ${object} — its rows keep ` +
14601460
`${ORGANIZATION_FIELD} = NULL and the counter merge below is SKIPPED for it, so the split ` +
14611461
`survives and the next boot retries. Nothing was lost; nothing was repaired for this object.`,
14621462
{ error: operatorFacingErrorText(e) },
@@ -1490,7 +1490,7 @@ export async function backfillSeedTenancy(
14901490
} catch (e) {
14911491
logger?.warn?.(
14921492
`[metadata-protocol] seed tenancy backfill could not merge the counter for ` +
1493-
`${split.object}.${split.field} (#8686) — the '${GLOBAL_TENANT}' counter is left in ` +
1493+
`${split.object}.${split.field} — the '${GLOBAL_TENANT}' counter is left in ` +
14941494
`place, so the high-water mark is intact and the next boot retries the repair`,
14951495
{ error: operatorFacingErrorText(e) },
14961496
);
@@ -1499,8 +1499,8 @@ export async function backfillSeedTenancy(
14991499

15001500
if (objectsStamped > 0) {
15011501
logger?.info?.(
1502-
`[metadata-protocol] seed/API tenancy split repaired for ${objectsStamped} object(s) ` +
1503-
`(#8686): untenanted seed rows adopted organization ${organizationId} and the ` +
1502+
`[metadata-protocol] seed/API tenancy split repaired for ${objectsStamped} object(s): ` +
1503+
`untenanted seed rows adopted organization ${organizationId} and the ` +
15041504
`'${GLOBAL_TENANT}' counter was merged into the organization-scoped one` +
15051505
(collisions.length > 0
15061506
? `. ${collisions.length} row(s) could NOT be adopted because their identifier is already ` +
@@ -1517,7 +1517,7 @@ export async function backfillSeedTenancy(
15171517
// will NOT rewrite, so an operator has to decide what happens to them.
15181518
logger?.warn?.(
15191519
`[metadata-protocol] ${collisions.length} business identifier(s) were already minted TWICE before ` +
1520-
`this repair (#8686) — reported, NOT renumbered. These values each exist on both a seeded row and ` +
1520+
`this repair — reported, NOT renumbered. These values each exist on both a seeded row and ` +
15211521
`an API-created row: ` +
15221522
collisions.map((c) => `${c.object}.${c.field}=${c.value} (${c.rows} rows)`).join(', ') +
15231523
`. The platform does not renumber them: a record number that has already appeared on a document, ` +

‎packages/metadata-protocol/src/migrations/sys-setting-identity-index.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ export async function ensureSysSettingIdentityIndex(
534534
logger,
535535
`[metadata-protocol] could not create '${SYS_SETTING_IDENTITY_INDEX_NAME}' on ` +
536536
`"${SYS_SETTING_TABLE}" after the probe succeeded — the table may currently have NO unique ` +
537-
`index on (${sysSettingIdentityKeyParts().join(', ')}). Restart to retry (#8629).`,
537+
`index on (${sysSettingIdentityKeyParts().join(', ')}). Restart to retry.`,
538538
detail,
539539
);
540540
return { status: 'failed', detail };
@@ -592,7 +592,7 @@ function reportDegradation(
592592
`over (${columns}). The system keeps looking healthy while the declared row identity is void on ` +
593593
`every row that is not scope='user' — user_id is NULL there — so two tenant-scope rows for one ` +
594594
`(namespace, key) in ONE organization, or two platform defaults on the global layer, can coexist ` +
595-
`and SettingsService has no defined answer for which one wins (#8629). MySQL/MariaDB before ` +
595+
`and SettingsService has no defined answer for which one wins. MySQL/MariaDB before ` +
596596
`8.0.13 has no functional key parts, so there is no in-dialect fix: run this platform on ` +
597597
`SQLite/PostgreSQL for the guarantee, and meanwhile watch for duplicates with this MySQL ` +
598598
`statement: ${buildSysSettingDuplicateProbeSqlMysql()}`,
@@ -615,7 +615,7 @@ function reportDegradation(
615615
`enforced until the duplicates are resolved: settings rows are admin-authored configuration, so ` +
616616
`no row is discarded automatically and this migration will keep refusing until an operator ` +
617617
`decides which row survives. List them with: ${duplicateQuery} — or run "os migrate duplicates" — ` +
618-
`then restart (ADR-0120 D4, #8629).`,
618+
`then restart (ADR-0120 D4).`,
619619
detail,
620620
);
621621
return;
@@ -631,7 +631,7 @@ function reportDegradation(
631631
`[metadata-protocol] could not rebuild '${SYS_SETTING_IDENTITY_INDEX_NAME}' on ` +
632632
`"${SYS_SETTING_TABLE}" as the NULL-safe row-identity index; the existing index is unchanged, so ` +
633633
`duplicate tenant-scope and global-scope settings rows can still be created while everything else ` +
634-
`looks healthy. Fix the cause below and restart (#8629).`,
634+
`looks healthy. Fix the cause below and restart.`,
635635
detail,
636636
);
637637
}

‎packages/metadata-protocol/src/migrations/view-definition-active-index.test.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,8 @@ describe('sys_view_definition active-row uniqueness (#5839) on a NULL-safe key (
339339
const note = String(logger.error.mock.calls[0]![0]);
340340
expect(note).toContain('UNRESTRICTED and NULL-distinct');
341341
expect(note).toContain('keeps looking healthy');
342-
expect(note).toContain('#5839');
343-
expect(note).toContain('#6417');
342+
expect(note).toContain('an archived view keeps occupying its name slot');
343+
expect(note).toContain('two same-name ACTIVE shared views (owner NULL)');
344344
// The fix, and the query that surfaces the duplicates meanwhile.
345345
expect(note).toContain('SQLite/PostgreSQL');
346346
expect(note).toContain(buildDuplicateProbeSql());

‎packages/metadata-protocol/src/migrations/view-definition-active-index.ts‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ export async function ensureViewDefinitionActiveIndex(
327327
logger,
328328
`[metadata-protocol] could not create '${VIEW_ACTIVE_INDEX_NAME}' on ` +
329329
`"${VIEW_DEFINITION_TABLE}" after the probe succeeded — the table may currently have NO ` +
330-
`unique index on (${viewActiveIndexKeyParts().join(', ')}). Restart to retry (#5839).`,
330+
`unique index on (${viewActiveIndexKeyParts().join(', ')}). Restart to retry.`,
331331
detail,
332332
);
333333
return { status: 'failed', detail };
@@ -378,9 +378,9 @@ function reportDegradation(
378378
`'${VIEW_ACTIVE_INDEX_NAME}' on "${VIEW_DEFINITION_TABLE}" stays UNRESTRICTED and NULL-distinct ` +
379379
`over (${columns}), the bare-composite degradation of ADR-0120 D3. The system keeps looking ` +
380380
`healthy while two consequences hold on this dialect: an archived view keeps occupying its ` +
381-
`name slot (#5839), and two same-name ACTIVE shared views (owner NULL) or environment-level ` +
382-
`views (organization_id NULL) can still coexist even though the platform states they cannot ` +
383-
`(#6417). MySQL/MariaDB has no partial indexes, so there is no in-dialect fix: run this ` +
381+
`name slot, and two same-name ACTIVE shared views (owner NULL) or environment-level ` +
382+
`views (organization_id NULL) can still coexist even though the platform states they cannot. ` +
383+
`MySQL/MariaDB has no partial indexes, so there is no in-dialect fix: run this ` +
384384
`platform on SQLite/PostgreSQL for the guarantee, and meanwhile watch for duplicates with: ` +
385385
`${buildDuplicateProbeSql()}`,
386386
detail,
@@ -402,7 +402,7 @@ function reportDegradation(
402402
`existing rows violate (${keyParts}) among state='active'. The previous index is left in ` +
403403
`place, so (${columns}) is enforced only as far as it was before; the NULL-safe key is NOT ` +
404404
`enforced until the duplicates are resolved. List them with: ${buildDuplicateProbeSql()} — or ` +
405-
`run "os migrate duplicates" — then restart (ADR-0120 D4, #6417, #8725).`,
405+
`run "os migrate duplicates" — then restart (ADR-0120 D4).`,
406406
detail,
407407
);
408408
return;
@@ -416,8 +416,7 @@ function reportDegradation(
416416
logger,
417417
`[metadata-protocol] could not rebuild '${VIEW_ACTIVE_INDEX_NAME}' on "${VIEW_DEFINITION_TABLE}" as ` +
418418
`the active-row NULL-safe index; the existing index is unchanged, so two same-name ACTIVE shared ` +
419-
`views can still coexist while everything else looks healthy. Fix the cause below and restart ` +
420-
`(#5839 / #6417).`,
419+
`views can still coexist while everything else looks healthy. Fix the cause below and restart.`,
421420
detail,
422421
);
423422
}

‎packages/metadata-protocol/src/plugin.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ export function assembleMetadataProtocol(
313313
await ensureViewDefinitionActiveIndex(resolveIndexExec(ql), ctx.logger);
314314
} catch (e: unknown) {
315315
ctx.logger.warn(
316-
'[metadata-protocol] sys_view_definition active-row index migration skipped (#5839)',
316+
'[metadata-protocol] sys_view_definition active-row index migration skipped — the index that keeps a view name unique among ACTIVE rows only (an archived view frees its name) was not ensured this boot',
317317
{ error: e instanceof Error ? e.message : String(e) },
318318
);
319319
}
@@ -330,7 +330,7 @@ export function assembleMetadataProtocol(
330330
});
331331
} catch (e: unknown) {
332332
ctx.logger.warn(
333-
'[metadata-protocol] sys_setting row-identity index migration skipped (#8629)',
333+
'[metadata-protocol] sys_setting row-identity index migration skipped — the NULL-safe index that enforces the declared row identity on tenant and global rows (user_id NULL there) was not ensured this boot',
334334
{ error: e instanceof Error ? e.message : String(e) },
335335
);
336336
}
@@ -351,7 +351,7 @@ export function assembleMetadataProtocol(
351351
await backfillSeedTenancy(resolveSeedTenancySeam(ql), ctx.logger);
352352
} catch (e: unknown) {
353353
ctx.logger.warn(
354-
'[metadata-protocol] seed/API tenancy backfill skipped (#8686)',
354+
'[metadata-protocol] seed/API tenancy backfill skipped — the repair that adopts untenanted seed rows into the install\'s one organization and merges their autonumber counter did not run this boot',
355355
{ error: e instanceof Error ? e.message : String(e) },
356356
);
357357
}

‎packages/metadata-protocol/src/protocol.batch-row-driver-text.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ describe('[#8502] section 4 — the operator half: withheld, not discarded', ()
393393

394394
expect(warn).toHaveBeenCalledTimes(1);
395395
const [line, cause] = warn.mock.calls[0];
396-
expect(line).toContain('#8502');
396+
expect(line).toContain('must not be quoted back on response data');
397397
expect(line).toContain('withheld from the response');
398398
// The ORIGINAL error object, not a re-spelling of it, so a log reader
399399
// gets the stack too.

0 commit comments

Comments
 (0)