Migrate formula-table, record-update-attachment, duplicate-table onto lifecycle drivers#63
Merged
Merged
Conversation
formula-table now delegates to field-add-lifecycle.ts as the family's fourth
member: prepareFixture seeds the numeric source table (parking its
createTable/seedRecords measurements on the fixture), assertSeedReady waits for
source-row readability, runPrimary creates the formula field(s) and waits for
the computed backfill + full scan, and cleanup restores the reusable seed by
deleting the added formula fields (or drops the table). The shared driver is
unchanged: the source-ready phase relabel (sourceReady on execute vs seedReady
on seed) and the trailing formulaReady phase append are expressed in the spec,
reusing the unchanged buildFormulaCaseResult so artifacts stay byte-equivalent.
G1: formula/10k-calc and formula/10k-5-concurrent x v1,v2 diff clean vs baseline.
Masks: details.seed.seedTableName (the hash-suffixed seed name, a seedHash-family
content address that only appears in G1, never in baseline A<->B) and
details.{formula,formulas[],formulaResults[]}.compiledExpression (generated
A/B/C field ids embedded in the compiled form; uncompiled expression stays
visible).
Co-Authored-By: Claude <noreply@anthropic.com>
…river record-update-attachment now delegates to record-mutation-lifecycle.ts (the record-update family, useRecordWindow:false): prepareFixture seeds the Title + empty-Attachment table, assertSeedReady asserts the cells are empty, and the measured operation uploads the attachment tokens (execute-only — the seed->execute cache carries no storage volume, so tokens must never be cached), warms up, p95-samples the idempotent bulk attachment-cell update, asserts routing, and verifies. uploadSetupMs is parked on the fixture so buildResult still reports it on the diagnostic path. The shared driver is unchanged and the unchanged result-assembly keeps artifacts byte-equivalent. G1: record-update/attachment-insert-100 x v1,v2 diff clean vs baseline with no new seedHash mask (its seed hash already nests under details.seed.cache). Masks: details.request.attachmentFieldId and details.update.expectedTokens (generated field id + random upload tokens, noise confirmed by baseline A<->B). Co-Authored-By: Claude <noreply@anthropic.com>
No existing driver fits "duplicate an entire seeded entity", so this adds a new, minimal framework/runners/duplicate-lifecycle.ts as the duplicate family's FIRST member (duplicate-base is the deferred second member). Its skeleton mirrors field-add-lifecycle (prepare/seedReady -> measured primary -> diagnostic wrap -> cleanup in finally) but its cleanup DROPS the created copy (read from the mutable fixture) and the source unless it is a reusable cached seed — drop-the-copy, not restore-by-delete. Per runner-framework.md it is intentionally family-shaped, not universal. duplicate-table delegates to it: prepareFixture seeds/restores the source table (parking its "prepare" measurement), assertSeedReady full-scans the source, and runPrimary runs the trace-wrapped duplicateTableTotalReady measurement (request + copy-readiness scan), parking the created copy id for cleanup. The unchanged buildDuplicateTableCaseResult keeps artifacts byte-equivalent. G1: duplicate-table/10k-20f and duplicate-table/10k-25f-5formula x v1,v2 diff clean vs baseline with no new seedHash mask (its seed hash already nests under details.prepare.cache). Masks: details.sourceFields[].id, details.sourceFormulas[].id, details.duplicate.duplicatedFormulaFields[].id (generated field ids, noise confirmed by baseline A<->B; names stay visible). Co-Authored-By: Claude <noreply@anthropic.com>
Move formula-table, record-update-attachment, and duplicate-table to Migrated (field-add-lifecycle, record-mutation-lifecycle, and the new duplicate-lifecycle respectively) and drop them from Not migrated. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Migrate three legacy runner kinds onto lifecycle drivers, taking the tracker
from 23/35 → 26/35 runner kinds (31/55 → 36/55 cases). Each migrated runner
delegates the repeated protocol to a driver and reuses its UNCHANGED
result-assembly, proven byte-equivalent by the G1 artifact diff over every
case × engine.
formula-tablefield-add-lifecycle.ts(4th member)formulaReadyphase append are expressed in the spec; driver unchanged.record-update-attachmentrecord-mutation-lifecycle.ts(useRecordWindow:false)duplicate-tableduplicate-lifecycle.ts(1st member)No shared driver was modified —
field-add-lifecycle.tsandrecord-mutation-lifecycle.tsstay byte-stable, so their existing members(conditional-lookup, field-duplicate, field-create / record-update,
record-create, record-reorder, selection-clear, record-update-link) need no
re-validation.
G1 evidence (baseline A on unmodified
main↔ candidate, local v1+v2)All 10 case × engine artifacts diff CLEAN. result=pass, error=null on every one.
Baseline A↔B noise check is clean with the existing + added noise masks; the
seedHash-family difference appears ONLY in G1 (never in A↔B), as expected.
Mask deltas (
scripts/diff-artifacts.mjs)details.seedrule to maskseedTableName(its suffix IS the hash; already masked seedHash/seedHashShort).Noise:
details.{formula,formulas[],formulaResults[]}.compiledExpression(embeds generated A/B/C field ids).
already-masked
details.seed.cache). Noise:details.request.attachmentFieldId,details.update.expectedTokens.details.prepare.cache). Noise:details.sourceFields[].id,details.sourceFormulas[].id,details.duplicate.duplicatedFormulaFields[].id.Every noise mask is justified by the baseline A↔B diff (volatile on UNCHANGED
code); field NAMES, expected values, counts, routing, and verification evidence
stay visible.
Negative tests (diff has teeth) — all 9 behaved correctly
verifiedSamples[].expected,duplicate
rowCount, attachmentrowCounteach made the diff FAIL.seed.seedTableName, duplicatesourceFields[].id, attachmentupdate.expectedTokenseach kept the diff PASS.seed.seedNamePrefix(sibling of masked seedHash/seedTableName), duplicate
sourceFields[].name(sibling of masked id), attachment
update.updatedRecords(sibling of maskedexpectedTokens) each still made the diff FAIL.
Verification
pnpm checkpasses.traceRefCount== baseline on every case;savedTraceCount=0locally — no Jaeger — CI is where saved==ref holds).🤖 Generated with Claude Code