Skip to content

Migrate field-convert + field-convert-link onto a lifecycle driver#56

Merged
HynLcc merged 1 commit into
mainfrom
migrate-field-convert-lifecycle
Jun 19, 2026
Merged

Migrate field-convert + field-convert-link onto a lifecycle driver#56
HynLcc merged 1 commit into
mainfrom
migrate-field-convert-lifecycle

Conversation

@HynLcc

@HynLcc HynLcc commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Tightly-coupled family migration. field-convert and field-convert-link
share the convertField endpoint and the same lifecycle, so they move onto one
new family-shaped driver.

Scope

  • Runner kinds: field-convert (2 cases) + field-convert-link (2 cases)
  • Cases: field-convert/10k-multi-select-to-text, field-convert/10k-text-to-formula,
    field-convert/10k-link-to-text, field-convert/10k-text-to-link

Change

  • New field-convert-lifecycle.ts owns the repeated protocol: prepare(seed) →
    seedReady → measured convert+readiness → build result (twice: diagnostic
    catch + success) → finally keep-or-delete cleanup. It owns the shared
    keepFixture decision (Class D — the convert rewrites the column in place, so
    keep only when the execute DB is isolated or a reusable seed was never
    converted); the runner declares which table(s) to drop (field-convert: host;
    field-convert-link: host + foreign).
  • Both runners keep only case-specific diff logic (seed-cache fixture carrying
    its own create/seed measurements, seed assertion, the measured convert +
    routing + readiness bundle, result assembly, cleanup target) and wire into the
    driver via a spec.

G1 mask additions (scripts/diff-artifacts.mjs)

These cases were never G1-diffed before; baseline A vs B surfaced
generated-field-id noise the comparator did not yet mask. All genuinely volatile
on unchanged code, none semantic:

  • details.convert.sourceFieldId (→ GENERATED_ID_KEYS; sourceFieldName stays visible)
  • details.convertedField.id (scoped; convertedField.name/type stay visible)
  • details.verifiedSamples[].actual.id for text-to-link (scoped; the linked
    cell's actual.title stays visible and asserted)

Verification

  • pnpm check: green.
  • Local v1+v2 baseline A, baseline B, candidate for all 4 cases: all pass.
  • G1 diff: baseline A↔B and A↔candidate pass for all 4 cases × both engines
    (with the noted mask additions, confirmed sufficient by A↔B).
  • Negative battery: perturbing convertedField.type, convert.targetType,
    convert.sourceFieldName, verifiedSamples[].actual.title,
    fullScan.scannedRecords, or phases[0].name all fail the diff; the 3
    masked id fields correctly pass.
  • The updated comparator still passes for the already-migrated record-reorder
    artifacts (no comparator regression).
  • Candidate routing matched (feature=convertField), operation field-convert /
    field-convert-link, fullScan scannedRecords=10000.

Protected case-contract surface (cases/**, registry.ts, framework/types.ts
config, framework/artifacts.ts schema, ../teable-ee) untouched. The
scripts/diff-artifacts.mjs mask change is task-sanctioned and masks only
run-to-run-volatile generated ids.

🤖 Generated with Claude Code

Tightly-coupled family migration: both runner kinds share the convertField
endpoint and the same lifecycle, so add one family-shaped driver
field-convert-lifecycle.ts that owns the repeated protocol:
  prepare(seed) -> seedReady -> measured convert+readiness -> build result
  (twice: diagnostic catch + success) -> finally keep-or-delete cleanup.
The driver owns the shared keepFixture decision (Class D: convert rewrites the
column in place, so keep only when the execute DB is isolated or a reusable
seed was never converted); the runner declares which table(s) to drop
(field-convert: host table; field-convert-link: host + foreign table).

field-convert.runner.ts / field-convert-link.runner.ts keep only their
case-specific diff logic (seed-cache fixture with its own create/seed
measurements, seed assertion, the measured convert + routing + readiness
bundle, result assembly, cleanup target) and wire into the driver via a spec.

G1 mask additions (scripts/diff-artifacts.mjs): these cases were never
G1-diffed before; baseline A vs B surfaced generated-field-id noise the
comparator did not yet mask. All genuinely volatile on unchanged code, none
semantic:
  - details.convert.sourceFieldId (added to GENERATED_ID_KEYS; sourceFieldName
    stays visible),
  - details.convertedField.id (scoped; convertedField name/type stay visible),
  - details.verifiedSamples[].actual.id for text-to-link (scoped; the linked
    cell's actual.title stays visible and asserted).
Semantic proofs stay caught: perturbing convertedField.type, convert.targetType,
convert.sourceFieldName, verifiedSamples[].actual.title, fullScan.scannedRecords,
or phases[0].name all still fail the diff.

Verification: pnpm check green; baseline A/B and A↔candidate pass for all 4
cases x v1+v2; full negative battery (6 semantic fails, 3 masked-id passes);
updated comparator still passes for the migrated record-reorder artifacts.

Tracker: field-convert + field-convert-link Not migrated -> Migrated. Counts
15->17 / 35 runner kinds, 17->21 / 55 cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HynLcc HynLcc merged commit 07d35d9 into main Jun 19, 2026
6 checks passed
@HynLcc HynLcc deleted the migrate-field-convert-lifecycle branch June 19, 2026 13:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant