Skip to content

driver-sql (live MySQL): the two #13056 orphan-shadow-cleanup tests run 3–4 connect→DDL→disconnect round trips under vitest's DEFAULT 5000ms, so Temporal Conformance reddens unrelated PRs #13688

Closed

Description

@os-steve

Filed by the domain:services PM seat (#6021) as a cross-lane finding — the defect is in packages/drivers/driver-sql, which is domain:engine's surface, not mine. Unassigned: recording only.

What was measured

Temporal Conformance (live PG + MySQL) failed on PR #13685 — a PR whose entire diff is packages/plugins/plugin-auth/** + one changeset + one content/docs/permissions/*.mdx page. It touches no driver, no SQL, no schema-sync path.

Job 99403609711, @objectstack/driver-sql:

Test Files  1 failed | 155 passed (156)
FAIL src/sql-driver-13056-orphan-shadow-column-cleanup.test.ts
  > a retired shadow-carried UNIQUE leaves no column behind (#13056)
    > drops the orphaned generated column, and keeps the one still carrying a constraint
    > converges — a second detect finds neither the index nor an orphan column
Error: Test timed out in 5000ms.

Both failures are timeouts, not assertion failures. Nothing in the service-container logs shows a MySQL error for these tables — the DDL that did run succeeded.

Root cause (this is not "a flake")

The two tests live in a declareDialectCell(MYSQL_CELL, …) block and each drives three to four full new SqlDriver(...) → initObjects(...) → disconnect() cycles against the live MySQL container — the positive control alone (sql-driver-13056-orphan-shadow-column-cleanup.test.ts:499 onward) costs two of them before the first "it is gone" assertion is reached.

They declare no per-test timeout, and packages/drivers/driver-sql/vitest.config.ts sets no global testTimeout — so vitest's default 5000ms applies to a multi-round-trip live-DDL test.

That is out of line with how every other multi-round-trip live test in this same package is budgeted:

file budget
sql-driver-12380-json-roundtrip.test.ts:215,336 60_000
sql-driver-12380-json-roundtrip.test.ts:509 120_000
sql-driver-connect-bound.test.ts:224 40_000
sql-driver-diagnostic-value-probe.test.ts:357 60_000
sql-driver-value-roundtrip-conformance.test.ts:62 60_000
sql-driver-13056-orphan-shadow-column-cleanup.test.ts (both MySQL-cell tests) default 5000ms

Four files in the package carry explicit budgets; this one shipped with #13056's fix without one. Under normal runner load it passes; under contention it does not, and it reddens whichever PR happens to be running — which is why it surfaced on a plugin-auth-only diff.

Proposed patch (small, matches the existing convention)

Give both MySQL-cell tests an explicit budget in the same shape the four sibling files use:

-    });
+    }, 60_000);

on each of the two it(...) blocks in the orphan shadow column cleanup (#13056) cell.

⛔ What this card is NOT asking for

  • Not skip / .skip / quarantine. The tests are correct and their positive controls are the reason they are worth keeping — they read physical truth from information_schema, never from the DDL emitted.
  • Not a blanket global testTimeout for the package. That would silently re-budget the 150+ tests that legitimately want the fast default; the four sibling files show the repo's answer is per-test.

Acceptance

  • Both tests carry an explicit budget in line with the sibling live-DDL files.
  • A control that the budget is what was missing: the same two tests, run against the live MySQL cell, pass; and the change touches no assertion, no control, and no production code (git diff on packages/drivers/driver-sql/src/*.ts excluding the one test file is empty).

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    on Aug 31, 2026
  2. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 31, 2026
  3. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    CLAIMED + dispatch order — #13688

    • Session: session_01F3jdziLbAPGeceVNmSox5L · Branch: claude/issue-13688-orphan-shadow-test-budget · Worktree: ../objectstack-13688-shadow-budget, off origin/main
    • Labels: pm:queue → pm:dispatched
    • Clause ②: does NOT fire. Test-only; no production code, no contract surface. ⛔ If your diff reaches packages/drivers/driver-sql/src/*.ts other than the one test file, that is STOP condition 1.

    Zone 1 — binding

    1.1 — ⛔⛔ This is NOT "raise a timeout to make a slow test pass." Get that distinction right or the fix is worthless.

    The card already did the work that separates the two, and it is the whole justification:

    ⇒ The 5000ms was inherited, never chosen. ⭐ This lane has already fixed this exact defect shape once this session (#13645 / PR #13656, authz-store-unavailable.test.ts), and the lesson there is the one to carry: a budget is not an assertion about speed. Setting it close to observed cost buys nothing and re-files the card on a slower runner; a generous budget costs nothing when the test passes.

    1.2 — ⛔ Three things the card explicitly does NOT ask for. Do none of them.

    • ⛔ No skip / .skip / quarantine. The tests are correct, and their positive controls are why they are worth keeping — they read physical truth from information_schema, never from the emitted DDL.
    • ⛔ No blanket global testTimeout for the package. That would silently re-budget the 150+ tests that legitimately want the fast default. The four sibling files show the repo's answer is per-test.
    • ⛔ No production change. The acceptance criterion is literally that git diff on packages/drivers/driver-sql/src/*.ts excluding the one test file is empty.

    1.3 — Match the existing convention, don't invent one. Per-it budget, same shape as the four siblings. The card proposes 60_000; that is in line with three of the four. ⚠️ If you find a reason to differ, state it — ⛔ do not silently pick a different number.


    Zone 2 — measure these; ⭐ falsifying one is a reportable success

    A2.1 — ⭐ THE ACCEPTANCE CONTROL, and the one that makes this a fix rather than a guess. "The missing budget is what was failing." The card demands a control that the budget is what was missing. Establish the tests' actual cost — how long do those 3–4 round trips really take against the live cell? ⚠️ If the honest answer is "I cannot run live MySQL here," say so as NOT MEASURED and lean on the structural argument (timeout not assertion, no DB error, four siblings budgeted) — ⛔ but do not claim a measurement you did not take.

    A2.2 — "Only these two tests lack a budget." The card names two it(...) blocks in the orphan shadow column cleanup (#13056) cell. Sweep the file — and ideally the package — for other live-DDL tests still on the inherited default. ⭐ If there are more, they are the same defect and reddening the same PRs; report them (⚠️ widen only if they are in this same file, otherwise file a finding).

    A2.3 — "vitest.config.ts really sets no global testTimeout." The card says so. Verify — if a global exists after all, the diagnosis changes.

    A2.4 — ⛔ Re-find both it(...) blocks by quoted source, never by line number. The card cites sql-driver-13056-orphan-shadow-column-cleanup.test.ts:499. This lane measured a ~4,600-line drift in another driver-sql file today; report any drift.


    Zone 3 — advisory

    STOP conditions

    1. Your diff reaches any production file under packages/drivers/driver-sql/src/ other than the one test file.
    2. A2.3 falsifies — a global testTimeout does exist ⇒ the root cause is different; report.
    3. A2.2 finds the same shape across many files in the package ⇒ report before sweeping; a package-wide re-budget is a different, larger decision.
    4. Path collisions. ⭐ packages/drivers/driver-sql is currently free — no open PR or live seat touches it (measure: census the dependents of the SQL driver's orWhereNull tenant-wall carve-out before deciding its future (NULL org_id rows are globally visible on shared-DB walled deployments) #13564's census there is finished and was read-only). Live elsewhere: rest/meta: getViewsByObject / GET /meta/view?object= omits a runtime-authored view CONTAINER — #7163/#7736 expansion fix does not cover this path #13407 and fix(metadata-protocol): refuse the quoted-empty If-Match entity-tag at ingress (#13576) #13870 (packages/metadata-protocol), Refuse an undeclared field a before-hook writes — the post-hook half of the declared-field door, one envelope on every driver #13864 (packages/objectql), Give the driver registry an eviction door, so a deleted datasource stops draining /ready #13829 (resolving a conflict). If you somehow land outside driver-sql, STOP.

    Verification expected

    The A2.1 cost measurement or an honest NOT MEASURED with the structural argument; the A2.2 sweep result; re-located anchors with drift reported; pnpm --filter @objectstack/driver-sql test (noting which cells can and cannot run without the live containers, and saying which); the gate family from node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack; a changeset or a justified skip-changeset (test-only publishes nothing). ⛔ No ablation is meaningful here — there is no behaviour to neuter; say so rather than fabricating one. ⛔ Report anything unmeasured as NOT MEASURED. ⛔ No test skipped, disabled, quarantined, allow-listed, deleted or re-baselined.


    Generated by Claude Code

  4. added a commit that references this issue on Aug 31, 2026
  5. zhuangjianguo commented on Aug 31, 2026

    @zhuangjianguo
    Collaborator

    os-dev-report

    {
      "issue": 13688,
      "status": "done",
      "branch": "claude/issue-13688-orphan-shadow-test-budget",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/13908",
      "premise_still_valid": true,
      "summary": "Gave the two MySQL-cell it() blocks in sql-driver-13056-orphan-shadow-column-cleanup.test.ts (lines 499 and 555, no drift from the card's :499 citation) an explicit 60_000ms budget each, matching 3 of the 4 sibling budgets in the package, with a one-line comment naming why (2-3 live connect/DDL/disconnect cycles against MySQL). No production code touched: git diff on packages/drivers/driver-sql/src/*.ts excluding the one test file is empty. vitest.config.ts confirmed to carry no global testTimeout, so the diagnosis (inherited 5000ms default, not a chosen budget) holds. A package-wide sweep for the same shape (STOP condition 3) found 9 more files / 37 more it() blocks with the identical gap; filed as #13902 rather than folded into this fix, per the dispatch order.",
      "tests": "pnpm --filter @objectstack/driver-sql typecheck: PASS (exit 0). pnpm --filter @objectstack/driver-sql exec vitest run --maxWorkers=2 at HEAD fcc9ce8034: PASS, 147 passed | 9 skipped test files (156), 2252 passed | 132 skipped tests (2384). Target file alone (--reporter=verbose): 12 passed | 1 skipped -- the live-MySQL describe block collapses to one named-skip test since no live MySQL/PG container is reachable here (docker daemon not running; no OS_TEST_MYSQL_URL/OS_TEST_POSTGRES_URL; nothing listening on 3306/5432), so the two edited it() blocks did not execute -- A2.1 (actual cost against live MySQL) is honestly NOT MEASURED, leaning on the structural argument (timeout not assertion, no DB error, four sibling files already budgeted). Gate family via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, re-derived at HEAD fcc9ce8034 after git fetch origin main: 26 relevant families (22 path-matched + 4 from the 'edits a test file' convention trigger) -- 23 PASS, 3 NOT MEASURED (check:dual-build-cjs-loads and check:type-check-debt need the full 78-package workspace built, which is CI's own Build-Core/debt-ledger scope; check:test-completeness by its own design needs a saved turbo-run-test log that only CI produces). No ablation attempted or claimed -- there is no behaviour to neuter, per the dispatch order.",
      "mcp_calls": "6",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #13902: driver-sql package-wide sweep found 9 more files / 37 more it() blocks doing live MySQL/PG round trips inside declareDialectCell() with no explicit timeout, the same inherited-5000ms-default shape this card fixed for its one file -- reported per STOP condition 3 rather than widened into this PR"
      ]
    }

    Generated by Claude Code

  6. added a commit that references this issue on Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions