Skip to content

test(upgrade): pin typed-struct plateau on legacy-origin in-place upgrade (QA-606)#1870

Open
kriszyp wants to merge 1 commit into
mainfrom
kris/qa-promote-upgrade-structgrowth
Open

test(upgrade): pin typed-struct plateau on legacy-origin in-place upgrade (QA-606)#1870
kriszyp wants to merge 1 commit into
mainfrom
kris/qa-promote-upgrade-structgrowth

Conversation

@kriszyp

@kriszyp kriszyp commented Jul 20, 2026

Copy link
Copy Markdown
Member

What this pins

A qa-explorer regression anchor for the §2 G(cross-major-upgrade) × A(width-heterogeneous) interaction — the corner QA-478 explicitly left uncovered.

QA-478 proved a harperdb@4.7.34 → current-main in-place upgrade migrates width-drifting records decode-clean, but it never drove new writes against the upgraded table with randomAccessFields: true active — so it never exercised the unbounded typed-struct minting path (the #1453-class OOM). This spec closes that gap.

Controlled A/B on one instance, identical width-heterogeneous generator + cadence on both arms:

  • upgradedWidthDrift, the v4.7.34-created, in-place-migrated dataset (a table with no persisted randomAccessFields directive, so it follows the global default on open).
  • fresh controlFreshControl, created by current main with an explicit randomAccessFields: true.

Verdict (green): both arms plateau at typedStructs = 38 (cap 256), upgraded/fresh ratio 1.00x — the OOM class does not reproduce on a legacy-origin table; the upgraded arm tracks the fresh-install control.

Provenance & gating

  • Promoted from qa-explorer QA-606 / candidate P-395.
  • Cold-gated GREEN on main 56a2bace9 — 3/3 runs (both arms tailFlat=true, legacy precondition fired, i.e. not a silent skip). oxlint + prettier clean.

⚠️ CI note — legacy provisioning required

This spec skips (like its sibling integrationTests/upgrade/4.x-upgrade.test.ts) unless HARPER_LEGACY_VERSION_PATH points at an installed v4.x harperdb package. It rides the same env var and skip-guard the existing 4.x upgrade suite already uses — no new mechanism — but CI must provision a v4.x harperdb install for it to actually run rather than skip.

🤖 Generated with Claude Code

…rade (QA-606)

Regression anchor for the §2 G(cross-major-upgrade) × A(width-heterogeneous)
interaction: a harperdb@4.7.34 -> current-main in-place-upgraded table, once
`randomAccessFields: true` is active and NEW width-drifting writes are driven
against it, must NOT route onto the unbounded typed-struct minting path
(#1453-class OOM). It must plateau its typedStructs count identically to a
fresh-install control under the same generator.

Controlled A/B on one instance: the "upgraded" arm (WidthDrift, the QA-478
v4-origin migrated dataset) vs a "fresh control" arm (FreshControl, created by
current main with an explicit randomAccessFields directive). Both driven by the
identical width-heterogeneous generator at the same cadence. Verdict: both
plateau at typedStructs=38 (cap 256), ratio 1.00x -> the OOM class does not
reproduce on legacy-origin tables.

Skips (like the sibling 4.x-upgrade.test.ts) unless HARPER_LEGACY_VERSION_PATH
points at a v4.x `harperdb` install -- CI must provision one or this silently
skips.

Promoted from qa-explorer QA-606 / candidate P-395. Cold-gated GREEN on main
56a2bac (3/3 runs).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new integration test suite (qa606-upgrade-structgrowth.test.ts) and its associated custom resource components to verify that an in-place upgraded database table plateaus its typed-struct count under a width-heterogeneous write workload when randomAccessFields is enabled, preventing OOM regressions. The reviewer feedback suggests replacing several instances of the global fetch API with the authenticated client.reqRest helper to ensure consistency, proper authorization, and cleaner response parsing.

);

// ── PRECONDITION 2 (hard): the migrated dataset decodes clean BEFORE we touch it ─
const scan = await fetch(`${ctx.harper.httpURL}/ScanVerify606/?table=WidthDrift`).then((r) => r.json());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the authenticated client.reqRest helper instead of the global fetch API. This ensures consistency with the rest of the test suite, automatically includes the required authorization headers, and avoids potential 401 Unauthorized errors if authentication is enforced on custom resources.

Suggested change
const scan = await fetch(`${ctx.harper.httpURL}/ScanVerify606/?table=WidthDrift`).then((r) => r.json());
const scan = (await client.reqRest('/ScanVerify606/?table=WidthDrift')).body;

Comment on lines +356 to +358
const preFlip = (await (
await fetch(`${ctx.harper.httpURL}/StructReport606/?table=WidthDrift`)
).json()) as StructReportResult;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the authenticated client.reqRest helper instead of the global fetch API to maintain consistency, ensure proper authorization, and simplify the response parsing.

				const preFlip = (await client.reqRest('/StructReport606/?table=WidthDrift')).body as StructReportResult;

Comment on lines +377 to +379
const postFlipWidthDrift = (await (
await fetch(`${ctx.harper.httpURL}/StructReport606/?table=WidthDrift`)
).json()) as StructReportResult;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the authenticated client.reqRest helper instead of the global fetch API to maintain consistency, ensure proper authorization, and simplify the response parsing.

				const postFlipWidthDrift = (await client.reqRest('/StructReport606/?table=WidthDrift')).body as StructReportResult;

Comment on lines +387 to +389
const postFlipFreshControl = (await (
await fetch(`${ctx.harper.httpURL}/StructReport606/?table=FreshControl`)
).json()) as StructReportResult;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use the authenticated client.reqRest helper instead of the global fetch API to maintain consistency, ensure proper authorization, and simplify the response parsing.

				const postFlipFreshControl = (await client.reqRest('/StructReport606/?table=FreshControl')).body as StructReportResult;

@claude

claude Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

@kriszyp
kriszyp marked this pull request as ready for review July 21, 2026 18:43

@cb1kenobi cb1kenobi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand what this pull request is doing.

typedStructs: enc && Array.isArray(enc.typedStructs) ? enc.typedStructs.length : null,
classicStructures: enc && Array.isArray(enc.structures) ? enc.structures.length : null,
maxOwnStructures: enc ? (enc.maxOwnStructures ?? null) : null,
storeCtor: store && store.constructor && store.constructor.name,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could be simplified:

Suggested change
storeCtor: store && store.constructor && store.constructor.name,
storeCtor: store?.constructor?.name,

@Ethan-Arrowood Ethan-Arrowood left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Solid regression anchor — it pins the real invariant (a legacy-origin, in-place-upgraded table plateaus its typed-struct count instead of the #1453 OOM growth under randomAccessFields writes), and it's genuinely CI-exercised rather than dark: the integration workflow installs harperdb@4 and sets HARPER_LEGACY_VERSION_PATH, and the fail-loud preconditions (migration ran, decode-clean, structure flipped) stop it from silent-skipping to a false green. Green across Node 22/24/26.

Two non-blocking notes: worth folding in the fetch→client.reqRest consistency cleanup, and keep an eye on the added CI wall-clock (legacy boot + migrate + 2 restarts + 36k inserts, ~600s timeout) as the upgrade suite grows.

sent with Claude Opus 4.8

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.

3 participants