From 92c9260b2896fb505ec6b3780b434ffdbbc18591 Mon Sep 17 00:00:00 2001 From: HynLcc Date: Fri, 19 Jun 2026 00:42:55 +0800 Subject: [PATCH] Migrate table-delete + table-restore onto lifecycle driver Add framework/runners/table-lifecycle.ts (runTableSamplesLifecycle), the non-link sibling of runTableLinkSamplesLifecycle. The driver owns the shared archive/restore sample loop for plain tables: fixture prep, the per-sample iteration, aggregation through buildTableLifecycleSamplesResult, the diagnostic error path, and the cleanup short-circuit. The table-delete and table-restore runners now declare only what varies for each kind (per-sample request + verification, success-only details, cleanup policy). This mirrors the already-migrated link family (table-delete-link / table-restore-link on table-link-lifecycle.ts); two members justify the generic non-link family driver. Behavior is artifact-identical, proven by the G1 diff over both cases x v1/v2: baselineA<->baselineB and baselineA<->candidate all pass; perturbing phases[0].name or thresholds[0].metric fails the diff. pnpm check passes. Co-Authored-By: Claude Opus 4.8 --- framework/runners/table-delete.runner.ts | 301 ++++++++++---------- framework/runners/table-lifecycle.ts | 118 ++++++++ framework/runners/table-restore.runner.ts | 321 ++++++++++------------ tasks/runner-migration-tracker.md | 8 +- 4 files changed, 413 insertions(+), 335 deletions(-) create mode 100644 framework/runners/table-lifecycle.ts diff --git a/framework/runners/table-delete.runner.ts b/framework/runners/table-delete.runner.ts index d118401..deef602 100644 --- a/framework/runners/table-delete.runner.ts +++ b/framework/runners/table-delete.runner.ts @@ -2,195 +2,177 @@ import { permanentDeleteTable } from "../../../utils/init-app"; import { isExecuteDbIsolated } from "../env"; import { measureAsync } from "../metrics"; import { withPerfTraceStep } from "../trace-collector"; -import type { - PerfCase, - PerfRunContext, - PerfRunResult, - TableDeleteCaseConfig, -} from "../types"; -import { PerfRunDiagnosticError } from "../types"; -import { - waitForRowsRestored, - type Measurement, - type RecordReplayVerification, -} from "./record-undo-redo.shared"; +import type { PerfCase, PerfRunContext, PerfRunResult } from "../types"; +import { waitForRowsRestored } from "./record-undo-redo.shared"; +import { runTableSamplesLifecycle } from "./table-lifecycle"; import { archiveTable, assertTableNotListed, buildTableLifecycleSampleResult, - buildTableLifecycleSamplesResult, findTableTrashId, formatTableLifecycleSample, - prepareTableLifecycleFixtures, restoreTableTrash, seedTableLifecycleCase, + type TableLifecycleCaseConfig, type TableLifecycleCleanupSample, type TableLifecycleFixtureSample, - type TableLifecycleRequestSample, - type TableLifecycleVerifySample, + type TableTrashLookup, } from "./table-lifecycle.shared"; +// Restore the archived table and confirm its full row count, so a reusable seed +// stays intact for the next run; the restore is recorded as a cleanup sample. +const restoreDeletedSample = async ({ + context, + perfCase, + config, + sample, + trashId, + cleanupSamples, +}: { + context: PerfRunContext; + perfCase: PerfCase; + config: TableLifecycleCaseConfig; + sample: TableLifecycleFixtureSample; + trashId: string; + cleanupSamples: TableLifecycleCleanupSample[]; +}) => { + const sampleLabel = formatTableLifecycleSample(sample.iteration); + const restoreMeasurement = await withPerfTraceStep( + context, + perfCase, + `cleanupRestoreTable-${sampleLabel}`, + () => + measureAsync(`cleanupRestoreTable-${sampleLabel}`, () => + restoreTableTrash(trashId), + ), + ); + const verifyMeasurement = await measureAsync( + `cleanupFullScan-${sampleLabel}`, + () => waitForRowsRestored(sample.fixture, config), + ); + cleanupSamples.push({ + iteration: sample.iteration, + restoreMeasurement, + verifyMeasurement, + }); +}; + export const runTableDeleteCase = async ( perfCase: PerfCase, context: PerfRunContext, -): Promise => { - const config = perfCase.config as TableDeleteCaseConfig; - const baseId = globalThis.testConfig.baseId; - let fixtureSamples: TableLifecycleFixtureSample[] = []; - const requestSamples: TableLifecycleRequestSample[] = []; - const verifySamples: TableLifecycleVerifySample[] = []; - const cleanupSamples: TableLifecycleCleanupSample[] = []; - - const restoreDeletedSample = async ( - sample: TableLifecycleFixtureSample, - trashId: string, - ) => { - const sampleLabel = formatTableLifecycleSample(sample.iteration); - const restoreMeasurement = await withPerfTraceStep( - context, - perfCase, - `cleanupRestoreTable-${sampleLabel}`, - () => - measureAsync(`cleanupRestoreTable-${sampleLabel}`, () => - restoreTableTrash(trashId), - ), - ); - const verifyMeasurement = await measureAsync( - `cleanupFullScan-${sampleLabel}`, - () => waitForRowsRestored(sample.fixture, config), - ); - cleanupSamples.push({ - iteration: sample.iteration, - restoreMeasurement, - verifyMeasurement, - }); - return verifyMeasurement; - }; - - try { - fixtureSamples = await prepareTableLifecycleFixtures( - baseId, - config, - perfCase, - "table-delete", - ); +): Promise => + runTableSamplesLifecycle(perfCase, context, { + runner: "table-delete", + includeCleanupSamples: true, + buildDetails: ({ config, state, error }): Record => + error + ? {} + : { + cleanup: { + restoredSamples: state.cleanupSamples.filter( + (sample) => + sample.verifyMeasurement?.result.scannedRecords === + config.rowCount, + ).length, + fullScans: state.cleanupSamples.map((sample) => ({ + iteration: sample.iteration, + restoreStatus: sample.restoreMeasurement?.result.status, + restoreRequestMs: sample.restoreMeasurement?.durationMs, + fullScan: sample.verifyMeasurement?.result, + })), + }, + verification: { + metric: "verifyMs", + checks: [ + "tableAbsentFromBaseTableList", + "trashItemPresent", + "cleanupRestoreFullRowCountScan", + ], + participatesInThreshold: false, + }, + }, + runSample: async ({ perfCase, context, config, baseId, sample, state }) => { + const sampleLabel = formatTableLifecycleSample(sample.iteration); + const requestMeasurement = await withPerfTraceStep( + context, + perfCase, + `deleteTable-${sampleLabel}`, + () => + measureAsync(`deleteTable-${sampleLabel}`, () => + archiveTable(baseId, sample.fixture.tableId), + ), + ); - try { - for (const sample of fixtureSamples) { - const sampleLabel = formatTableLifecycleSample(sample.iteration); - const requestMeasurement = await withPerfTraceStep( + const verifyMeasurement = await withPerfTraceStep( + context, + perfCase, + `deleteTableVerify-${sampleLabel}`, + () => + measureAsync(`deleteTableVerify-${sampleLabel}`, async () => { + const listing = await assertTableNotListed( + baseId, + sample.fixture.tableId, + ); + const trashLookup = await findTableTrashId( + baseId, + sample.fixture.tableId, + ); + return { ...listing, trashLookup }; + }), + ); + const { trashLookup } = verifyMeasurement.result as { + trashLookup: TableTrashLookup; + }; + state.requestSamples.push( + buildTableLifecycleSampleResult( + sample.iteration, + sample.fixture, + requestMeasurement, + "deleteTable", context, - perfCase, - `deleteTable-${sampleLabel}`, - () => - measureAsync(`deleteTable-${sampleLabel}`, () => - archiveTable(baseId, sample.fixture.tableId), - ), - ); + trashLookup, + ), + ); + state.verifySamples.push({ + iteration: sample.iteration, + measurement: verifyMeasurement, + }); - const verifyMeasurement = await withPerfTraceStep( + if (!isExecuteDbIsolated()) { + await restoreDeletedSample({ context, perfCase, - `deleteTableVerify-${sampleLabel}`, - () => - measureAsync(`deleteTableVerify-${sampleLabel}`, async () => { - const listing = await assertTableNotListed( - baseId, - sample.fixture.tableId, - ); - const trashLookup = await findTableTrashId( - baseId, - sample.fixture.tableId, - ); - return { ...listing, trashLookup }; - }), - ); - const { trashLookup } = verifyMeasurement.result as { - trashLookup: Awaited>; - }; - requestSamples.push( - buildTableLifecycleSampleResult( - sample.iteration, - sample.fixture, - requestMeasurement, - "deleteTable", - context, - trashLookup, - ), - ); - verifySamples.push({ - iteration: sample.iteration, - measurement: verifyMeasurement, + config, + sample, + trashId: trashLookup.trashId, + cleanupSamples: state.cleanupSamples, }); - - if (!isExecuteDbIsolated()) { - await restoreDeletedSample(sample, trashLookup.trashId); - } } - } catch (error) { - throw new PerfRunDiagnosticError( - error instanceof Error ? error.message : String(error), - buildTableLifecycleSamplesResult({ - config, - runner: "table-delete", - fixtureSamples, - requestSamples, - verifySamples, - cleanupSamples, - error, - }), - ); - } + }, + cleanup: async ({ perfCase, context, config, baseId, state }) => { + if (isExecuteDbIsolated()) { + return; + } - return buildTableLifecycleSamplesResult({ - config, - runner: "table-delete", - fixtureSamples, - requestSamples, - verifySamples, - cleanupSamples, - details: { - cleanup: { - restoredSamples: cleanupSamples.filter( - (sample) => - sample.verifyMeasurement?.result.scannedRecords === - config.rowCount, - ).length, - fullScans: cleanupSamples.map((sample) => ({ - iteration: sample.iteration, - restoreStatus: sample.restoreMeasurement?.result.status, - restoreRequestMs: sample.restoreMeasurement?.durationMs, - fullScan: sample.verifyMeasurement?.result, - })), - }, - verification: { - metric: "verifyMs", - checks: [ - "tableAbsentFromBaseTableList", - "trashItemPresent", - "cleanupRestoreFullRowCountScan", - ], - participatesInThreshold: false, - }, - }, - }); - } finally { - if (!isExecuteDbIsolated()) { - for (const sample of fixtureSamples) { - const requestSample = requestSamples.find( + for (const sample of state.fixtureSamples) { + const requestSample = state.requestSamples.find( (item) => item.iteration === sample.iteration, ); - const cleanupSample = cleanupSamples.find( + const cleanupSample = state.cleanupSamples.find( (item) => item.iteration === sample.iteration, ); let restored = Boolean(cleanupSample?.verifyMeasurement); if (!restored && requestSample?.trashLookup) { try { - await restoreDeletedSample( + await restoreDeletedSample({ + context, + perfCase, + config, sample, - requestSample.trashLookup.trashId, - ); + trashId: requestSample.trashLookup.trashId, + cleanupSamples: state.cleanupSamples, + }); restored = true; } catch (error) { console.warn( @@ -211,9 +193,8 @@ export const runTableDeleteCase = async ( } } } - } - } -}; + }, + }); export const seedTableDeleteCase = async ( perfCase: PerfCase, diff --git a/framework/runners/table-lifecycle.ts b/framework/runners/table-lifecycle.ts new file mode 100644 index 0000000..885c503 --- /dev/null +++ b/framework/runners/table-lifecycle.ts @@ -0,0 +1,118 @@ +import type { PerfCase, PerfRunContext, PerfRunResult } from "../types"; +import { PerfRunDiagnosticError } from "../types"; +import { + buildTableLifecycleSamplesResult, + prepareTableLifecycleFixtures, + type TableLifecycleCaseConfig, + type TableLifecycleCleanupSample, + type TableLifecycleFixtureSample, + type TableLifecycleRequestSample, + type TableLifecycleRunnerKind, + type TableLifecycleVerifySample, +} from "./table-lifecycle.shared"; + +// Non-link sibling of `runTableLinkSamplesLifecycle`: the shared archive/restore +// sample loop for plain (linkless) tables. Both `table-delete` and +// `table-restore` prepare N reusable fixtures, run a per-sample request + +// verification, and aggregate through `buildTableLifecycleSamplesResult`; only +// the per-sample work, the success-only details, and the cleanup policy vary. + +export type TableSamplesLifecycleState = { + fixtureSamples: TableLifecycleFixtureSample[]; + setupSamples: TableLifecycleVerifySample[]; + requestSamples: TableLifecycleRequestSample[]; + verifySamples: TableLifecycleVerifySample[]; + cleanupSamples: TableLifecycleCleanupSample[]; +} & TExtra; + +export type TableSamplesLifecycleRunArgs = { + perfCase: PerfCase; + context: PerfRunContext; + config: TableLifecycleCaseConfig; + baseId: string; + sample: TableLifecycleFixtureSample; + state: TableSamplesLifecycleState; +}; + +export type TableSamplesLifecycleSpec = { + runner: TableLifecycleRunnerKind; + includeSetupSamples?: boolean; + includeCleanupSamples?: boolean; + createState?: () => TExtra; + runSample: (args: TableSamplesLifecycleRunArgs) => Promise; + buildDetails?: (args: { + config: TableLifecycleCaseConfig; + state: TableSamplesLifecycleState; + error?: unknown; + }) => Record; + cleanup?: (args: { + perfCase: PerfCase; + context: PerfRunContext; + config: TableLifecycleCaseConfig; + baseId: string; + state: TableSamplesLifecycleState; + }) => Promise; +}; + +export const runTableSamplesLifecycle = async ( + perfCase: PerfCase, + context: PerfRunContext, + spec: TableSamplesLifecycleSpec, +): Promise => { + const config = perfCase.config as TableLifecycleCaseConfig; + const baseId = globalThis.testConfig.baseId; + const state = { + fixtureSamples: [], + setupSamples: [], + requestSamples: [], + verifySamples: [], + cleanupSamples: [], + ...(spec.createState?.() ?? {}), + } as TableSamplesLifecycleState; + + const buildResult = (error?: unknown) => + buildTableLifecycleSamplesResult({ + config, + runner: spec.runner, + fixtureSamples: state.fixtureSamples, + requestSamples: state.requestSamples, + setupSamples: spec.includeSetupSamples ? state.setupSamples : undefined, + verifySamples: state.verifySamples, + cleanupSamples: spec.includeCleanupSamples + ? state.cleanupSamples + : undefined, + error, + details: spec.buildDetails?.({ config, state, error }), + }); + + try { + state.fixtureSamples = await prepareTableLifecycleFixtures( + baseId, + config, + perfCase, + spec.runner, + ); + + try { + for (const sample of state.fixtureSamples) { + await spec.runSample({ + perfCase, + context, + config, + baseId, + sample, + state, + }); + } + } catch (error) { + throw new PerfRunDiagnosticError( + error instanceof Error ? error.message : String(error), + buildResult(error), + ); + } + + return buildResult(); + } finally { + await spec.cleanup?.({ perfCase, context, config, baseId, state }); + } +}; diff --git a/framework/runners/table-restore.runner.ts b/framework/runners/table-restore.runner.ts index f432a65..f1d7dc4 100644 --- a/framework/runners/table-restore.runner.ts +++ b/framework/runners/table-restore.runner.ts @@ -2,30 +2,24 @@ import { permanentDeleteTable } from "../../../utils/init-app"; import { isExecuteDbIsolated } from "../env"; import { measureAsync } from "../metrics"; import { withPerfTraceStep } from "../trace-collector"; -import type { - PerfCase, - PerfRunContext, - PerfRunResult, - TableRestoreCaseConfig, -} from "../types"; -import { PerfRunDiagnosticError } from "../types"; +import type { PerfCase, PerfRunContext, PerfRunResult } from "../types"; import { waitForRowsRestored, type RecordReplayVerification, } from "./record-undo-redo.shared"; +import { runTableSamplesLifecycle } from "./table-lifecycle"; import { archiveTable, assertSampleTextValues, assertTableNotListed, buildTableLifecycleSampleResult, - buildTableLifecycleSamplesResult, findTableTrashId, formatTableLifecycleSample, - prepareTableLifecycleFixtures, restoreTableTrash, seedTableLifecycleCase, + type TableLifecycleCaseConfig, type TableLifecycleFixtureSample, - type TableLifecycleRequestSample, + type TableLifecycleSampleVerification, type TableLifecycleVerifySample, type TableTrashLookup, } from "./table-lifecycle.shared"; @@ -34,185 +28,171 @@ type RestoreSetupSample = TableLifecycleVerifySample & { trashLookup: TableTrashLookup; }; -type RestoreVerifySample = TableLifecycleVerifySample & { - result: { - fullScan: RecordReplayVerification; - samples: Awaited>; - }; +type RestoreLifecycleState = { + setupSamples: RestoreSetupSample[]; +}; + +type RestoreVerifyResult = { + fullScan: RecordReplayVerification; + samples: TableLifecycleSampleVerification; +}; + +const restoreArchivedSample = async ({ + context, + perfCase, + config, + sample, + trashLookup, +}: { + context: PerfRunContext; + perfCase: PerfCase; + config: TableLifecycleCaseConfig; + sample: TableLifecycleFixtureSample; + trashLookup: TableTrashLookup; +}) => { + const sampleLabel = formatTableLifecycleSample(sample.iteration); + await withPerfTraceStep( + context, + perfCase, + `cleanupRestoreTable-${sampleLabel}`, + () => restoreTableTrash(trashLookup.trashId), + ); + await waitForRowsRestored(sample.fixture, config); }; export const runTableRestoreCase = async ( perfCase: PerfCase, context: PerfRunContext, -): Promise => { - const config = perfCase.config as TableRestoreCaseConfig; - const baseId = globalThis.testConfig.baseId; - let fixtureSamples: TableLifecycleFixtureSample[] = []; - const setupSamples: RestoreSetupSample[] = []; - const requestSamples: TableLifecycleRequestSample[] = []; - const verifySamples: RestoreVerifySample[] = []; - - const restoreArchivedSample = async ( - sample: TableLifecycleFixtureSample, - trashLookup: TableTrashLookup, - ) => { - const sampleLabel = formatTableLifecycleSample(sample.iteration); - await withPerfTraceStep( - context, - perfCase, - `cleanupRestoreTable-${sampleLabel}`, - () => restoreTableTrash(trashLookup.trashId), - ); - await waitForRowsRestored(sample.fixture, config); - }; - - try { - fixtureSamples = await prepareTableLifecycleFixtures( - baseId, - config, - perfCase, - "table-restore", - ); - - try { - for (const sample of fixtureSamples) { - const sampleLabel = formatTableLifecycleSample(sample.iteration); - const setupMeasurement = await withPerfTraceStep( - context, - perfCase, - `deleteSetup-${sampleLabel}`, - () => - measureAsync(`deleteSetup-${sampleLabel}`, async () => { - const archive = await archiveTable( - baseId, - sample.fixture.tableId, - ); - const listing = await assertTableNotListed( - baseId, - sample.fixture.tableId, - ); - const trashLookup = await findTableTrashId( - baseId, - sample.fixture.tableId, - ); +): Promise => + runTableSamplesLifecycle(perfCase, context, { + runner: "table-restore", + includeSetupSamples: true, + createState: () => ({ setupSamples: [] }), + buildDetails: ({ state, error }): Record => + error + ? {} + : { + fullScans: state.verifySamples.map((sample) => { + const result = sample.measurement.result as RestoreVerifyResult; + return { iteration: sample.iteration, fullScan: result.fullScan }; + }), + verifiedSamples: state.verifySamples.map((sample) => { + const result = sample.measurement.result as RestoreVerifyResult; return { - archiveStatus: archive.status, - ...listing, - trashLookup, + iteration: sample.iteration, + samples: result.samples.verifiedSamples, }; }), - ); - const { trashLookup } = setupMeasurement.result as { - trashLookup: TableTrashLookup; - }; - setupSamples.push({ - iteration: sample.iteration, - measurement: setupMeasurement, - trashLookup, - }); + verification: { + metric: "verifyMs", + checks: [ + "fullRowCountScan", + "sampleTextValues(Title,External ID)", + ], + participatesInThreshold: false, + }, + }, + runSample: async ({ perfCase, context, config, baseId, sample, state }) => { + const sampleLabel = formatTableLifecycleSample(sample.iteration); + const setupMeasurement = await withPerfTraceStep( + context, + perfCase, + `deleteSetup-${sampleLabel}`, + () => + measureAsync(`deleteSetup-${sampleLabel}`, async () => { + const archive = await archiveTable(baseId, sample.fixture.tableId); + const listing = await assertTableNotListed( + baseId, + sample.fixture.tableId, + ); + const trashLookup = await findTableTrashId( + baseId, + sample.fixture.tableId, + ); + return { + archiveStatus: archive.status, + ...listing, + trashLookup, + }; + }), + ); + const { trashLookup } = setupMeasurement.result as { + trashLookup: TableTrashLookup; + }; + state.setupSamples.push({ + iteration: sample.iteration, + measurement: setupMeasurement, + trashLookup, + }); - const requestMeasurement = await withPerfTraceStep( - context, - perfCase, - `restoreTable-${sampleLabel}`, - () => - measureAsync(`restoreTable-${sampleLabel}`, () => - restoreTableTrash(trashLookup.trashId), - ), - ); - requestSamples.push( - buildTableLifecycleSampleResult( - sample.iteration, - sample.fixture, - requestMeasurement, - "restoreTable", - context, - trashLookup, + const requestMeasurement = await withPerfTraceStep( + context, + perfCase, + `restoreTable-${sampleLabel}`, + () => + measureAsync(`restoreTable-${sampleLabel}`, () => + restoreTableTrash(trashLookup.trashId), ), - ); - - const verifyMeasurement = await withPerfTraceStep( + ); + state.requestSamples.push( + buildTableLifecycleSampleResult( + sample.iteration, + sample.fixture, + requestMeasurement, + "restoreTable", context, - perfCase, - `restoreTableVerify-${sampleLabel}`, - () => - measureAsync(`restoreTableVerify-${sampleLabel}`, async () => { - const fullScan = await waitForRowsRestored( - sample.fixture, - config, - { - timeoutMs: 60_000, - pollIntervalMs: 1_000, - }, - ); - const samples = await assertSampleTextValues( - sample.fixture, - config, - ); - return { fullScan, samples }; - }), - ); - verifySamples.push({ - iteration: sample.iteration, - measurement: verifyMeasurement, - result: verifyMeasurement.result as RestoreVerifySample["result"], - }); - } - } catch (error) { - throw new PerfRunDiagnosticError( - error instanceof Error ? error.message : String(error), - buildTableLifecycleSamplesResult({ - config, - runner: "table-restore", - fixtureSamples, - setupSamples, - requestSamples, - verifySamples, - error, - }), + trashLookup, + ), + ); + + const verifyMeasurement = await withPerfTraceStep( + context, + perfCase, + `restoreTableVerify-${sampleLabel}`, + () => + measureAsync(`restoreTableVerify-${sampleLabel}`, async () => { + const fullScan = await waitForRowsRestored(sample.fixture, config, { + timeoutMs: 60_000, + pollIntervalMs: 1_000, + }); + const samples = await assertSampleTextValues( + sample.fixture, + config, + ); + return { fullScan, samples }; + }), ); - } + state.verifySamples.push({ + iteration: sample.iteration, + measurement: verifyMeasurement, + }); + }, + cleanup: async ({ perfCase, context, config, baseId, state }) => { + if (isExecuteDbIsolated()) { + return; + } - return buildTableLifecycleSamplesResult({ - config, - runner: "table-restore", - fixtureSamples, - setupSamples, - requestSamples, - verifySamples, - details: { - fullScans: verifySamples.map((sample) => ({ - iteration: sample.iteration, - fullScan: sample.result.fullScan, - })), - verifiedSamples: verifySamples.map((sample) => ({ - iteration: sample.iteration, - samples: sample.result.samples.verifiedSamples, - })), - verification: { - metric: "verifyMs", - checks: ["fullRowCountScan", "sampleTextValues(Title,External ID)"], - participatesInThreshold: false, - }, - }, - }); - } finally { - if (!isExecuteDbIsolated()) { - for (const sample of fixtureSamples) { - const requestSample = requestSamples.find( + for (const sample of state.fixtureSamples) { + const requestSample = state.requestSamples.find( (item) => item.iteration === sample.iteration, ); - const setupSample = setupSamples.find( + const setupSample = state.setupSamples.find( + (item) => item.iteration === sample.iteration, + ) as RestoreSetupSample | undefined; + const verifiedAfterRestore = state.verifySamples.some( (item) => item.iteration === sample.iteration, - ); - const verifiedAfterRestore = Boolean( - verifySamples.find((item) => item.iteration === sample.iteration), ); let tableIsSeedReady = !setupSample || verifiedAfterRestore; if (!tableIsSeedReady && setupSample && !requestSample) { try { - await restoreArchivedSample(sample, setupSample.trashLookup); + await restoreArchivedSample({ + context, + perfCase, + config, + sample, + trashLookup: setupSample.trashLookup, + }); tableIsSeedReady = true; } catch (error) { console.warn( @@ -233,9 +213,8 @@ export const runTableRestoreCase = async ( } } } - } - } -}; + }, + }); export const seedTableRestoreCase = async ( perfCase: PerfCase, diff --git a/tasks/runner-migration-tracker.md b/tasks/runner-migration-tracker.md index 4f585d7..5d4ac50 100644 --- a/tasks/runner-migration-tracker.md +++ b/tasks/runner-migration-tracker.md @@ -4,9 +4,9 @@ Tracks which runner kinds have been moved onto lifecycle drivers and which are still legacy. Migration is **per runner kind**; a kind's row covers every case that uses it, because migrating a runner means re-verifying all of its cases. -Status as of 2026-06-18 on `main`. +Status as of 2026-06-19 on `main`. -**Migrated: 8 / 35 runner kinds · 10 / 55 cases.** +**Migrated: 10 / 35 runner kinds · 12 / 55 cases.** ## Migrated (✅ on the driver) @@ -18,6 +18,8 @@ Status as of 2026-06-18 on `main`. | record-delete-link | `table-link-lifecycle.ts` (single fixture) | record-delete/link-trash-1k | ✅ v1+v2 pass (local) | | record-undo | `record-replay-lifecycle.ts` (delete setup) | record-undo/delete-1k | ✅ v1+v2 pass (local) | | record-redo | `record-replay-lifecycle.ts` (delete+undo setup) | record-redo/delete-1k | ✅ v1+v2 pass (local) | +| table-delete | `table-lifecycle.ts` (sampled archive + restore-back) | table-delete/10k-20f | ✅ v1+v2 pass (local) | +| table-restore | `table-lifecycle.ts` (archive setup + sampled restore) | table-restore/10k-20f | ✅ v1+v2 pass (local) | | table-delete-link | `table-link-lifecycle.ts` (sampled foreign-table delete) | table-delete/10k-20f-link-detach | ✅ v1+v2 pass (local) | | table-restore-link | `table-link-lifecycle.ts` (sampled table restore) | table-restore/10k-20f-link-1k | ✅ v1+v2 pass (local) | @@ -50,8 +52,6 @@ Status as of 2026-06-18 on `main`. | selection-clear | 1 | selection-clear/flat-1k-20fields-cell-clear-stream | | selection-duplicate | 1 | record-duplicate/grid-block-duplicate-1k | | table-create | 2 | table-create/10x-20f-no-records, table-create/1x-20f-1k-records | -| table-delete | 1 | table-delete/10k-20f | -| table-restore | 1 | table-restore/10k-20f | ## How migration proceeds