test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks - #14212

Merged
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping
Sep 1, 2026
Merged

test(driver-sql): budget the live-DDL work outside #13902's scoping — 4 it() and 2 beforeAll hooks#14212
os-support-ai merged 2 commits into
mainfrom
claude/issue-14100-live-ddl-budgets-outside-scoping

Conversation

@os-support-ai

Copy link
Copy Markdown
Collaborator

Fixes#14100

Adds an explicit 60_000 budget to the six live-DDL sites in packages/drivers/driver-sql
that #13902 / PR #14098 correctly left outside its own scoping. Per-site, per-hook — no
package-level testTimeout, no vitest.config.ts change, no production source.

Diff: 4 test files, 6 budgets, nothing else.

What changed

Population A — 4 it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback:

Site (located by symbol)Driver argument
live-dialect-matrix.isolation.test.ts — "index introspection reports the indexes that exist in the file's schema"PG_CELL.config() + initObjects(...)
live-dialect-matrix.isolation.test.ts — "schema introspection lists a table created in the file's schema"PG_CELL.config() + initObjects(...)
sql-driver-autonumber-cold-race.test.ts — "leaves the surrounding transaction usable after a statement error"pgCell.config() + create/drop probe table
sql-driver-json-binding-without-ddl.test.ts — "§3 a datasource we are a guest in…"PG_CELL.config() plus schemaMode: 'validate-only', builds a SECOND live driver

Population B — the 2 beforeAll hooks in sql-driver-backend-fault-envelope.test.ts
(the declareSweep hook, and the Postgres-only hook), each opening a live driver, running
initObjects(...) and inserting rows. The file's it() blocks stay unbudgeted on purpose:
they only query an already-open connection, so #13902's exclusion of them was right — the
live cost simply lives in the hook.

Correction: hooks do NOT inherit the 5000ms default

The card states both hooks "inherit the 5000ms default". Measured here, that is wrong.
A hook inherits hookTimeout, not testTimeout:

LegShapeResult
A1it(), 6000ms, no budgetexit 1 — Test timed out in 5000ms (5.58s)
A2it(), 6000ms, 60_000exit 0 (6.54s)
B1beforeAll, 6000ms, no budgetexit 0 — passed (6.46s)
B3beforeAll, 11000ms, no budgetexit 1 — Hook timed out in 10000ms (10.56s)
B4beforeAll, 11000ms, 60_000exit 0 (11.52s)
A3it(), 11000ms, 60_000exit 0 (11.50s) — control

So the unbudgeted hooks were on a 10000ms ceiling, not 5000ms. The fix still stands and
still matters (10s is the wrong ceiling for a live connect plus schema-sync DDL plus inserts,
and B4 proves the third argument does lift a hook), but the number is corrected in the code
comment rather than repeated. This package sets no testTimeout or hookTimeout anywhere,
so both defaults are vitest's own.

Ablation discipline: probes were written into the package, their landing on disk proven by
marker and budget occurrence counts (never an editor exit code), each leg run through the
shared verify lock with the exit code captured by redirect before any pipe, and the probes
removed by an EXIT INT TERM trap with absence re-proven and git status shown clean.

The judgement gate (③), answered per site

Question: is any existing red a timeout itself rather than an assertion, and — critically —
does any assertion read elapsed time? Adding a budget to a duration-sensitive test would
change its meaning.

The scan carries a firing control: sql-driver-connect-bound.test.ts holds exactly the
named hazard, elapsed bounded above 8_000 and below 20_000, and the scan finds it.

SiteAssertion reads elapsed time?Existing red that is a timeout?
live-dialect-matrix.isolation.test.ts index introspectionNo — asserts index names/flags against a server-side control readNo red; live-gated, skipped locally
live-dialect-matrix.isolation.test.ts schema introspectionNo — asserts the table appears in introspectSchema()No red; live-gated, skipped locally
sql-driver-autonumber-cold-race.test.tsNo — asserts ok flags, SQLSTATE 23505, a row valueNo red; live-gated, skipped locally
sql-driver-json-binding-without-ddl.test.ts §3No — asserts a rejection type and JSON round-trip valuesNo red; live-gated, skipped locally
backend-fault-envelopedeclareSweep hookNo — a setup hook, it asserts nothingNo red; live-gated
backend-fault-envelope pg-only hookNo — a setup hook, it asserts nothingNo red; live-gated

No site's meaning changes. Zero of the six carry a duration-dependent assertion; the three
numeric comparisons anywhere in these files are a test-file count, an identifier-length
limit, and an index count.

Per ruling ④: these six were found structurally, by an AST walk. ⛔ None is known to
time out. The only measured instance of the defect shape remains #13688.

What was deliberately left alone

Classification is by reading each new SqlDriver(...)argument, never the filename or
directory. A per-site AST walk over all 159 test files in the package finds 193
driver-constructing sites:

  • 39 unbudgeted embedded-SQLite it()/test() sites left on the fast 5000ms default.
    These use dialectCell('sqlite').config() or a better-sqlite3 in-memory literal and are
    correctly fast. A blanket change would have silently loosened every one of them — the exact
    failure ruling ② exists to prevent. (The card's count for this population is 42; my walk
    counts 39 by a per-site denominator, counting it() blocks that construct a driver directly
    in their own body. I did not re-derive the card's number — the discrepancy is a denominator
    difference, not a disagreement about which sites are embedded.)
  • The walk finds exactly 4 LIVE-argument it() sites in the whole package, and they are
    Population A. Independent confirmation that the card's population is complete and exact.

Verification

All at 193b345f, the final commit.

  • pnpm --filter '@objectstack/driver-sql^...' build — VERDICT command-exit 0.
  • The 4 affected test files: 4 passed, 31 tests passed, 13 skipped. The 13 skipped are the
    live-cell sites; OS_TEST_POSTGRES_URL and OS_TEST_MYSQL_URL are both unset in this
    container, so the six sites themselves are a legitimate NOT MEASURED — no green is
    claimed for them.
  • pnpm --filter @objectstack/driver-sql typecheck — exit 0, and tsc --listFiles confirms
    all four edited files are in the program (1 occurrence each), so that green really covers
    the edits.
  • Gate family derived at the actual diff by scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, re-derived at the final commit and unchanged:
    26 commands — 23 pass, 3 NOT MEASURED. The three print PREREQUISITE NOT MET in their
    own verdict text and exit 3, the code reserved for it, distinct from a finding's 1:
    check-test-completeness (needs a saved turbo run test log), check:dual-build-cjs-loads
    and check:type-check-debt (both need a full-repo pnpm build). Not reds, and CI runs
    them on this PR.

Changeset

This PR carries the skip-changeset label rather than a changeset, which departs from the
dispatch instruction. The reason is mechanical: the diff is four *.test.ts files and
releases nothing from any package. An empty-frontmatter changeset is rejected outright by
scripts/check-empty-changeset.mjs, and a non-empty one would bump @objectstack/driver-sql
and write a CHANGELOG entry for a change no user can observe. Flagged for the PM rather than
decided silently.

Out of scope

The same AST walk found 7 unbudgeted hooks whose driver argument is unconditionally live,
in four files, none of them named by #14100 — plus the hookTimeout correction above, which
reframes the whole defect class. Filed separately rather than folded in, following this
card's own "separate card rather than a rider" precedent; #14100 is not the place for them.


Generated by Claude Code

Four it() blocks that build a live-Postgres SqlDriver outside a
declareDialectCell(...) callback, and the two beforeAll hooks in
sql-driver-backend-fault-envelope.test.ts that open a live driver, run
initObjects(...) and insert rows, all inherited vitest's 5000ms default.
Each now carries an explicit 60_000, per-site — no package-level
testTimeout, and the 39 embedded-SQLite sites are left on the fast
default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
An unbudgeted beforeAll inherits hookTimeout (measured: 10000ms in this
package's config), not testTimeout's 5000ms. Ablation legs B1/B3/B4 in
the PR body.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5WBDtaUnoz5XuJ6jk8pQ5
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 1, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json b992b1d64671296ef9355fc93e23b6efe1e38102packageMentionDocs.

@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 13:24
@os-support-ai
os-support-ai added this pull request to the merge queueSep 1, 2026
Merged via the queue into main with commit 1134e47Sep 1, 2026
37 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-14100-live-ddl-budgets-outside-scoping branch September 1, 2026 13:50
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gatetests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

driver-sql: live-DDL work still on vitest's 5000ms default outside #13902's scoping — 4 it() blocks beyond declareDialectCell, and 2 beforeAll hooks

2 participants

@os-support-ai@claude