Repository navigation
test(client): pay the auth-envelope suite's cold start at module scope, outside every clocked window - #20272
Merged
objectstack-fleet[bot] merged 2 commits intoSep 27, 2026
Conversation
…e, outside every clocked window The first case of auth-login-register-envelope.test.ts paid the worker's one-time cold start (better-auth's lazily imported module graph, sql.js's WASM compile, first-use costs on the sign-up path) inside vitest's 5000 ms testTimeout. A module-scope await of one throwaway scenario now pays it during collection, which vitest clocks against nothing. Every case still builds its own fresh engine, AuthManager and first sign-up. A new case pins the placement. Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP Co-authored-by: Claude <noreply@anthropic.com>
…tart Claude-Session: https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckNothing 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
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
objectstack-fleet
Bot
deleted the
claude/issue-20242-client-auth-envelope-cold-start
branch
September 27, 2026 18:29
This was referenced Sep 27, 2026
Merged
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Sep 28, 2026
…de every clocked window (objectstack-ai#20366) Fixes objectstack-ai#20327 Clause-②: no Four `packages/client` suites paid the worker's one-time cold start inside their first clocked test window: better-auth's lazily imported module graph, the sql.js WASM compile, and the first-use costs of the sync and the sign-up. One of them, `auth-get-session-envelope.test.ts`, timed out at 5000 ms on the required `Test Core (5/6)` shard of PR objectstack-ai#20325, whose diff does not reach the package. This PR ports PR objectstack-ai#20272's shape to all four: each file pays its own arrangement once at module scope, during collection, which no vitest clock covers, and pins that placement. `auth-rotated-session-token.test.ts` also loses its seven explicit `60_000` per-case timeouts. No other number is raised, and there is no retry, skip or quarantine. The diff is four test files. This card carries the family (triage note 2): the census below covers all 50 `packages/client/src/*.test.ts` files. ## Premise check (on `origin/main` at `c74de10a9`) Holds. In `auth-get-session-envelope.test.ts`, the first case calls `await signedIn()` inside its `it` (`:262`-`:264`), and every case builds a fresh `SqliteWasmDriver` engine, a real `AuthManager`, and five of the seven perform a real sign-up. `premise_still_valid: true`. The red CI run itself (job `108717176436`) shows the same shape in two more files of the family: | suite, in the red `Test Core (5/6)` run | first case | later cases doing the same arrangement | |:---|---:|---:| | `auth-get-session-envelope` | timed out at 5000 ms | 583-1255 ms | | `organization-invitation-resend-team-placement` | 3599 ms | 486-820 ms | | `organization-invite-role-default` | 2849 ms | 497-820 ms | ## Census: every `packages/client/src/*.test.ts` (50 files) The criterion (dispatch, Zone 2): a suite that boots an engine (a `SqliteWasmDriver` engine, a real `AuthManager`, or a real sign-up) inside its first clocked `it`, or in a `beforeAll`/`beforeEach`. | files | shape | verdict | |:---|:---|:---| | `auth-get-session-envelope` | 7 cases, all through `signedIn()`/`anonymous()`: fresh engine + real `AuthManager`; default 5000 ms; the first case paid the cold start | **included** | | `auth-rotated-session-token` | 7 cases, all through `signedIn()`; an explicit `60_000` on all 7 cases, which widened the first case's window instead of moving the cost out | **included**; the `60_000`s removed | | `organization-invitation-resend-team-placement` | 5 of 11 cases through `arrange()` (fresh engine, real `AuthManager`, real sign-up, an org and a team); default 5000 ms; `①` paid the cold start | **included** | | `organization-invite-role-default` | 3 of 6 cases through `arrange()`; default 5000 ms; `①` paid the cold start | **included** | | `auth-login-register-envelope` | same shape | already fixed by PR objectstack-ai#20272 (`80c29a14`); not edited | | `client.hono`, `client.batch-transaction`, `client.data-prefix`, `client.environment-scoping`, `client.metadata-prefix` | a `LiteKernel` + ObjectQL + `SqliteWasmDriver` REST/Hono server booted ONCE per file (per describe in the two `*-prefix` files) as a shared fixture in a `beforeAll` with an explicit `30_000` hookTimeout; no `AuthManager`, no sign-up | **excluded**: the claim's file surface is suites that boot inside their first clocked `it`, and a hook-booted shared fixture is a different shape (the boot IS the fixture). Reach: in the red CI run all five passed; under 24 busy loops on this box all five passed (1 run). Their hook duration is NOT MEASURED: vitest's JSON file span does not include it. Noted, not filed. | | `meta-delete-item-carriers` | a `SqliteWasmDriver` engine + the real protocol + `RestServer` booted inside `it`, but only from the 14th case on (Part 2); its first 13 cases are mock-fetch; an explicit `60_000` on all 7 engine cases; no `AuthManager`, no sign-up | **excluded**: its first clocked `it` is a mock case, so it is outside the claim's file surface as written. Its first engine case is not where a cold start sits heavily: 137 ms idle against 38-194 ms for the later engine cases, and 810 ms against 312-1204 ms under 24 busy loops. Its `60_000`s widen windows that measured under 1.3 s. Noted, not filed. | | `i18n-wire-dialect` | a `LiteKernel` + `HonoServerPlugin` in a `beforeAll`, no driver, no auth | **excluded**: boots no engine | | the other 38 | mock `fetch`, source-text reads, or type-level assertions; `client.test.ts`'s sign-up cases are fetch-level; `oauth-applications-*` and `organization-get-active-member-addressing` drive doubles | **excluded**: no engine | Count: 4 included, 1 already fixed, 45 excluded. ## What changed Per file, the same three moves as PR objectstack-ai#20272: - A module-scope warm-up that runs the file's OWN arrangement, not a list of loads: - `auth-get-session-envelope`: `await signedIn(); await closeEngines();` - `auth-rotated-session-token`: `await signedIn(); await closeEngines();` - the two organization suites: `process.env.OS_TENANCY_POSTURE = 'isolated';` then `await arrange().finally(restorePosture);`. `arrange()` needs the posture the file's `beforeAll` sets for its cases, and the module scope runs before any hook, so the warm-up holds the posture itself and `.finally` puts back what it found, even if it throws. - The teardown the warm-up reuses is extracted without changing it: `closeEngines` is the old `afterEach` loop byte for byte (in `auth-rotated-session-token` the `afterEach` keeps its `vi.restoreAllMocks()` and calls `closeEngines`); `restorePosture` is the old `afterAll` body byte for byte. - A placement pin per file (`⑥`, or `④` in `auth-rotated-session-token`), read off the file's own text: - exactly one column-0 warm-up line, so it sits in no function body; - in `auth-get-session-envelope`, no `before*` hook at all (as in PR objectstack-ai#20272's `⑦`); - in the three files that keep a legitimate hook (the console-spy `beforeEach`, the posture `beforeAll`), exactly one hook, and no hook body calls the arrangement. A hook indented inside a `describe` is read on to that block's column-0 close, so it cannot hide one; - in `auth-rotated-session-token`, also no `}, N);` per-case timeout, so the widened posture cannot come back. - A header section per file with that file's own readings. No assertion in an existing case changed. The warm-up shares nothing a case asserts on: every case still builds a fresh engine, a fresh `AuthManager` and a fresh sign-up. What it leaves warm is process-level (the module registry, sql.js's compiled WASM, the JIT), which the first case used to leave to every later case. In the two organization suites the warm-up's engine stays open, as every case's does there (`arrange()` hands none back and those files close none), so no case runs in a state no case ran in before. Why module scope and not a hook or a timeout: `@vitest/runner@4.1.11`, as installed here, wraps hooks and test bodies in `withTimeout(...)` (`dist/chunk-artifact.js:672`, `:724`, `:1787`) and awaits `runner.importFile(filepath, "collect")` bare (`:2457`). The repo's rule is "clocked windows measure behaviour, never loading" (AGENTS.md, Build & Test; `check:test-source-alias`). ## Before / after, at CI's own 5000 ms budget Idle (4 vCPU, the box otherwise quiet), first case against the later cases of the same file: | suite | base `c74de10a9` | fix `49bd6fdfa` | |:---|---:|---:| | `auth-get-session-envelope` | 1035 vs 110-330 ms | 316 vs 90-277 ms | | `auth-rotated-session-token` | 1713 vs 302-665 ms | 809 vs 278-581 ms | | `organization-invitation-resend-team-placement` | 1245 vs 307-411 ms | 332 vs 284-399 ms | | `organization-invite-role-default` | 968 vs 310-336 ms | 382 vs 329-340 ms | Under load, PR objectstack-ai#20272's method: CPU-bound `node -e 'for(;;){}'` loops on 4 vCPU, PIDs recorded and killed by trap. One vitest run per leg over the four files, `--maxWorkers=2`. On the base tree, 24 loops gave CI's exact signature, `Test timed out in 5000ms` on the first case, in all three default-budget suites (1 run); `auth-rotated-session-token`'s first case took 10314 ms there, green only because of its `60_000`. Measured as interleaved pairs: an ABLATED leg (the four warm-ups deleted from the committed files) and a FIX leg (the committed files), same command, same load, order alternated between pairs. The box is shared, so interleaving puts its drift on both sides. ``` ./node_modules/.bin/vitest run --maxWorkers=2 --reporter=verbose --reporter=json --outputFile.json=RUN.json FOUR_FILES ``` | 24 busy loops, N = 4 pairs | ablated: first-case timeouts | fix: first-case timeouts | fix: first case | fix: heaviest other case | |:---|---:|---:|---:|---:| | `auth-get-session-envelope` | 4 / 4 | **0 / 4** | 1969-2536 ms | 1979-2751 ms | | `auth-rotated-session-token` | 4 / 4 | **4 / 4** (see below) | 5034-5319 ms | 3440-4771 ms | | `organization-invitation-resend-team-placement` | 4 / 4 | **0 / 4** | 1577-3095 ms | 2523-3086 ms | | `organization-invite-role-default` | 4 / 4 | **0 / 4** | 2359-2575 ms | 2056-2271 ms | | 16 busy loops, N = 2 pairs | ablated: first-case timeouts | fix: first-case timeouts | fix: first case | |:---|---:|---:|---:| | `auth-get-session-envelope` | 1 / 2 (4816, 5134 ms) | 0 / 2 | 1320-1523 ms | | `auth-rotated-session-token` | 2 / 2 (5053, 5229 ms) | 0 / 2 | 4125-4185 ms | | `organization-invitation-resend-team-placement` | 1 / 2 (4752, 5113 ms) | 0 / 2 | 1853-1904 ms | | `organization-invite-role-default` | 0 / 2 (4663, 4903 ms) | 0 / 2 | 1429-1611 ms | Every ablated leg also reddened all four placement pins (4 of 4, in all 6 ablated legs). Every fix leg's pins passed. In one ablated leg, `organization-invitation-resend-team-placement`'s second case also timed out (5121 ms): vitest does not cancel a timed-out body, so the first case's orphaned body was still running beside it. No fix leg showed that. ## `auth-rotated-session-token`: the `60_000`s are gone, and its first case is heavy by its own work Triage note 3 and the dispatch both rule out a raised timeout, so all seven `60_000`s are removed. With the cold start moved out, six of the seven cases fit the default budget at both loads. The first case (`①`) does not fit at 24 busy loops, and that is its own behaviour, not loading: - `①` is the card's whole probe: a sign-up plus five more calls that each check a password or a TOTP code (login, enable, verifyTotp, disable, deleteUser). - A throwaway variant whose module-scope warm-up ran that WHOLE probe left `①` no faster: 637-716 ms against 690-709 ms for the committed warm-up (3 runs each, idle, the file alone). So no loading is left in its window. | basis | `①` | margin to 5000 ms | |:---|---:|---:| | idle, fix | 690-809 ms | 6.2-7.2x | | the red CI run's own slowdown on warm cases (`auth-get-session-envelope`'s same-work cases ran 2.9-5.9x their idle time) | about 2.0-4.8 s (inferred, not measured) | about 1.0-2.5x | | 16 busy loops, fix (2 runs) | 4125-4185 ms | 1.2x | | 24 busy loops, fix (4 runs) | 5034-5319 ms | reached, 4 of 4 | Before this PR the same case held a 10.3 s window at 24 busy loops (cold start plus this work) under its `60_000`. The file's header records this residual and names the lever: the case's own work, not a timeout. The open question in the report asks the seat whether to accept it as is. ## Ablation (fix committed first, restore proven) The fix was committed (`49bd6fdfa`) before any mutation. Each ablated leg nested four `node scripts/ablation-replace.mjs --file ABS_PATH --anchor ANCHOR --delete -- ...` calls (WRAP mode, restore armed on EXIT, INT and TERM), one per file: - `auth-get-session-envelope`, `auth-rotated-session-token`: the anchor `await signedIn();` + newline + `await closeEngines();` + newline; - the two organization suites: the posture line + newline + `await arrange().finally(restorePosture);` + newline. In every leg the tool reported, per file, anchor x1 to x0, a changed blob, and "ok mutation landed" (24 of 24), and the leg printed `warm-up lines=0 (of 4 files)` read off the disk before vitest started. After every leg the tool proved each restore by blob hash against `HEAD` and an empty `git diff HEAD` (24 of 24), and a second check after each leg read `4/4 blob == HEAD blob, git diff HEAD = 0 bytes` (12 of 12 legs). The files run from source, so no `dist/` preflight applies. ## Verification All at `220735eb3`: the fix `49bd6fdfa`, two commits that only edit header comments, and a merge of `origin/main` at `d498113b5`. The branch delta against it is exactly the four test files, +321 / -23. Every exit code was captured before any pipe. The union below was first run at `5a9a01d00` and then run again in full at `220735eb3`, after the last commit corrected a count in a comment. Both runs gave the same verdicts. - After the merge: `pnpm install --frozen-lockfile`, then the dependency closure `pnpm turbo run build --filter='@objectstack/client...' --concurrency=2`, 33 of 33 tasks. - `pnpm --filter @objectstack/client exec vitest run --maxWorkers=2`: `Test Files 50 passed (50)`, `Tests 641 passed (641)` (637 before, plus the 4 pins), exit 0. - `pnpm --filter @objectstack/client typecheck`: exit 0, `check:test-typecheck: OK`, 0 files / 0 errors. `tsc -p tsconfig.test.json --listFilesOnly` compiles all four files (4 hits), so that green covers them. - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran RAN_LIST` (every line with its recorded exit code): `53 derived famil(ies) accounted for — 51 run, 2 NOT-MEASURED`, 0 UNRUN, and each of the 51 run exited 0. - NOT MEASURED: `check:dual-build-cjs-loads` and `check:type-check-debt`. Both exited 3 (PREREQUISITE NOT MET): they need every package's `dist/`, the whole `./packages/*` build. A declared narrowing; CI runs both. This diff is four test files, which no build emits (the `dist/` check is under Changeset), and `@objectstack/client`'s test-layer debt ledger is empty and re-measured just above at 0 errors. - `check:skill-examples` exited 3 until its prerequisite was met: first `packages/client-react/dist` was absent, then `packages/client/dist` was older than an edited `src/` file. After `pnpm turbo run build --filter=@objectstack/client-react` and `pnpm --filter @objectstack/client build`, the same command exited 0: 259 prose examples across 3 surfaces. - `node scripts/check-issue-citations.mjs --base origin/main`: exit 0. It judged 0 files: test files are on its deferred list. - `pnpm lint` (`eslint . --no-inline-config`, the whole repo, not a narrowing): exit 0. - Control-byte self-scan of the four files: no hits (`check:nul-bytes` also exit 0). ## Changeset `skip-changeset`. The diff is four `*.test.ts` files. `@objectstack/client`'s `files[]` is `dist`, `README.md`, `CHANGELOG.md`. After `pnpm --filter @objectstack/client build` at `220735eb3`, strings unique to these test files (`closeEngines`, `restorePosture`, `cold start stays outside`, `OS_TENANCY_POSTURE`) have 0 hits under `packages/client/dist/`, while the positive control `ObjectStackClient` hits all 4 emitted artifacts (`index.js`, `index.mjs`, `index.d.ts`, `index.d.mts`). No published byte changes. ## Acceptance notes - **`auth-rotated-session-token.test.ts` `①` residual** (section above): at 24 busy loops it reaches the 5000 ms budget on its own work, 4 of 4 runs; at 16 loops it fits with 1.2x. CI has not run it on the default budget before this PR. If CI reds it, the lever is that case's own work (for example splitting the probe, which would change the card's own probe and needs a ruling), not a timeout. Its second-heaviest cases (`changePassword` with `revokeOtherSessions`, and `twoFactor.disable`) reached 4.7-4.8 s at 24 loops. - **`meta-delete-item-carriers.test.ts`** carries an explicit `60_000` on all 7 of its engine cases, the posture the clocked-window rule warns relocates a cliff. Measured, those windows are small (under 1.3 s at 24 busy loops) and its first engine case holds little one-time cost, so it is no timeout risk today. Outside this card's surface. Noted, not filed. - **The five hook-booted `client.*` suites** boot a shared server in a `beforeAll` with an explicit `30_000` hookTimeout. They passed in the red CI run and under 24 busy loops here. Their hook time is not measured. Outside this card's surface. Noted, not filed. - The two organization suites never close their engines, before or after this PR (`arrange()` hands none back). The warm-up adds one more open in-memory engine per file, as each of their cases does. Noted, not filed. - The measurement box was shared: the verify lock serialises locked runs only, and other worktrees' work ran beside some legs (the one-minute load average read 2.1-26 at pair starts). The interleaved pairs, with the order alternated, are what keep the before/after comparison fair under that drift. --- _Generated by [Claude Code](https://claude.ai/code/session_01UYBdGBzWSrAMzpW8ah3GbP)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #20242
Clause-②: no
The first case of
packages/client/src/auth-login-register-envelope.test.tspaid the worker's one-time cold start inside vitest's 5000 mstestTimeout. It timed out onTest Core (5/6)(run36320810893, head3d14f9e75), on a PR whose diff does not reach this suite. This PR moves that cost out of every clocked window. No budget changes. The diff is one test file, +81 / -2.Premise check (done first, on
origin/mainatfdb26698f)Holds. Every case builds a fresh
ObjectQLover a newSqliteWasmDriver(':memory:'), runssyncSchemas, constructs a realAuthManager, and performs a real better-auth sign-up. The file set no timeout and had no warm-up.premise_still_valid: true.Where the first case's time went
Phase probe (a throwaway file, never committed): four successive scenarios in one worker, idle, 4 vCPU, at
fdb26698f.getAuthInstance()(better-auth's lazily imported module graph)engine.init()(sql.js compiles its WASM once)syncSchemas()So about 850 ms of the first case's window was one-time cost that no other case pays. Idle, the first case took 855-964 ms, against 222-249 ms for the two other cases doing the same single sign-up.
The failing CI run's own totals point the same way. Against this tree idle (
--maxWorkers=2), its client package readtests 38.71svs23.39sandimport 202.17svs102.68s. Test bodies ran about 1.5x slower there, while the first case ran more than 5x slower. The term that crossed the budget was cold loading, not the behaviour the case asserts.The route, and why it is neither of the two the dispatch offered
The dispatch offered (a) a
beforeAllwarm-up with its own explicit timeout, or (b) an explicit per-case timeout. Both keep the cost inside a clock.@vitest/runner@4.1.11, as installed in this tree, wraps hooks and test bodies inwithTimeout(...), whilecollectTests()awaitsrunner.importFile(filepath, "collect")bare (dist/chunk-artifact.js).The repo already recorded what (a) costs.
scripts/check-test-source-alias.mjs's clocked-window section describes a cold load moved into abeforeAll(hookTimeout 10000) that then hit 20.26 s on a merge-queue shard. Its rule, repeated in AGENTS.md (Build & Test), is "clocked windows measure behaviour, never loading".packages/cli/src/commands/datasource/envelope-unwrap.test.tsis the in-repo precedent for the same class. So the cost is now paid by a module-scopeawait, during collection, which no vitest clock covers.What the warm-up runs: one whole throwaway scenario, the file's own
registered(), not a list of loads. A load-only warm-up (engine plusgetAuthInstance()) left the next scenario at 344-409 ms against 212-269 ms, because the sign-up path has first-use costs of its own. The full scenario left none: 258-284 ms against 214-289 ms. Naming the file's own arrangement also avoids a specifier list that could drift.What changed
await registered(); await closeEngines();.afterEachbody becomescloseEngines, byte-for-byte the same loop, reused by the warm-up.⑦, a placement pin. It reads this file's own text and asserts exactly one column-0await registered();and nobefore*hook. So "do not move it into a hook" is an assertion.No assertion in cases ①-⑥ changed. There is no skip, no retry, no quarantine and no timeout anywhere.
The warm-up shares nothing a case asserts on. Its engine and manager are its own and are closed before collection ends. Every case still builds a fresh engine, a fresh
AuthManagerand a fresh first sign-up. What it leaves warm is process-level: the module registry, sql.js's compiled WASM and the JIT. The first case used to leave exactly that to the fourteen after it. Before the fix every other case was already a "warm" case, so no case now runs in a state no case ran in before.Before / after at CI's own budget
The failure reproduces at the real 5000 ms budget under CPU contention: 24 CPU-bound
node -e 'for(;;){}'loops on 4 vCPU, their PIDs recorded and killed by trap. On the unmodified base tree (fdb26698f) this load gave CI's exact signature,1 failed | 14 passed, on the first case,Test timed out in 5000ms, in 2 of 2 runs.Measured as 10 interleaved pairs: an ABLATED leg (the fix deleted), then the FIX leg (the committed file), same command, same load. The box is shared and its background load drifts, so interleaving puts the drift on both sides equally.
⑦pin x10, one⑤case x1 (pair 10)a05c2e2da)⑤cases, pair 10 onlyPair 10 ran on a heavier box: vitest wall 196-203 s against 129-141 s for pairs 1-9. Unlocked work belonging to another worktree was running beside it (read from the process table, not killed). There, the ablated leg failed the first case plus one
⑤case.A separate, unpaired series of 10 fix runs under the same 24 loops shows the same split. Runs 1-5, at the calibration's box load (wall 130-151 s), were 5 of 5 green. Runs 6-10, with that extra unlocked load present (wall 185-200 s), were 5 of 5 red, every one on the two
⑤cases (5002-5124 ms) and none on the first case (case 1 there: 1851-2936 ms).Idle, after the fix, 10 of 10 runs are green (16 tests). The first case takes 238-352 ms, level with its same-work siblings at 197-291 ms.
Margin, and its basis
Each case's window now holds only its own behaviour: a fresh-engine sync plus real scrypt sign-ups and logins. The heaviest cases are the first two in
⑤, each doing two sign-ups and a login.So this does not raise a number that the next slower runner will exceed: no number was raised. The fix takes about 850 ms idle of one-time loading out of the first case's window. Under the synthetic CPU starvation that reproduces the failure, that is more than 3 s. The first case, with 0 timeouts in 20 loaded fix runs, is no longer where the file fails.
What a much slower runner reaches next is the
⑤cases' own behaviour. On this box that took about 1.4x more load than the load that reproduces CI's failure. That is a real per-case cost the case exists to pay, and it is recorded in Acceptance notes rather than papered over.Ablation (commit first, restore proven)
The fix was committed (
a05c2e2da) before any mutation. Each ablated leg went throughnode scripts/ablation-replace.mjs --file ABS_PATH --anchor 'await registered();\nawait closeEngines();\n' --delete -- ...(WRAP mode, restore armed on EXIT, INT and TERM).For every leg the tool reported: anchor x1 -> x0, blob
261d72a2e->dbec8e3fc, and "ok mutation landed". The wrapped command itself printedwarm-up lines=0read off the disk before vitest started.After every leg, and at the end of each chunk, the restore was proven by blob hash (
git hash-objectof the file ==git rev-parse HEAD:PATH==261d72a2e, an empty hash reading as failure) and bygit diff HEAD= 0 bytes. That is 14 of 14 proofs. The tree was clean before and after. The test file is run from source, so nodist/preflight applies.Verification
All at
6b7a46bbc(after mergingorigin/main; the branch delta against it is exactly this one file, +81 / -2). Every command's exit code was captured before any pipe.pnpm turbo run build --filter='@objectstack/client...' --concurrency=2, 33 of 33 tasks.pnpm --filter @objectstack/client exec vitest run --maxWorkers=2 src/auth-login-register-envelope.test.ts:Tests 16 passed (16), exit 0.pnpm --filter @objectstack/client exec vitest run --maxWorkers=2:Test Files 50 passed (50),Tests 637 passed (637), exit 0.pnpm --filter @objectstack/client typecheck: exit 0,check:test-typecheck: OK, 0 files / 0 errors.tsc -p tsconfig.test.json --listFilesOnlydoes compile this file (1 hit), so that green covers it.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran:52 derived famil(ies) accounted for — 50 run, 2 NOT-MEASURED, and every one of the 50 run exited 0.check:dual-build-cjs-loadsandcheck:type-check-debt. Both exited 3 (PREREQUISITE NOT MET) because they need every package'sdist/, i.e. the whole./packages/*build. This is a declared narrowing, and CI runs both.dist/check is under Changeset below), and@objectstack/clientis in neither type-check debt ledger. Its own test-layer ledger is empty and was re-measured just above at 0 errors.check:skill-examplesfirst exited 3 becausepackages/client-react/distwas absent. Afterpnpm turbo run build --filter=@objectstack/client-reactthe same command exited 0: 259 prose examples across 3 surfaces.node scripts/check-issue-citations.mjs --base origin/main(the real board check): exit 0. 4 citations judged, all resolve.pnpm lint(eslint . --no-inline-config, the whole repo, not a narrowing): exit 0.Changeset
skip-changeset. The diff is one*.test.tsfile.@objectstack/client'sfiles[]isdist,README.md,CHANGELOG.md. Afterpnpm turbo run build --filter='@objectstack/client...', strings unique to this test file (closeEngines, the⑦title) have 0 hits underpackages/client/dist/, while the positive controlObjectStackClienthits all 4 emitted artifacts (index.js,index.mjs,index.d.ts,index.d.mts). No published byte changes.Acceptance notes
packages/clientsuites that build a fresh engine plus a real sign-up per case. None of them is edited here.src/auth-get-session-envelope.test.ts: 7 cases, all 7 throughsignedIn()/anonymous()on a freshSqliteWasmDriverengine withsyncSchemasand a realAuthManager. Timeout posture: vitest default 5000 ms, no warm-up. Its first case pays the same cold start this PR moves; same exposure.src/auth-rotated-session-token.test.ts: 7 cases, all 7 throughsignedIn(). Timeout posture: an explicit60_000on all 7 cases. The cold start still sits in its first case's window, widened rather than moved, which is the posturecheck:test-source-alias's header says relocates the cliff.src/organization-invitation-resend-team-placement.test.ts: 11 cases, 5 of them througharrange()(fresh engine, realAuthManager, real sign-up). Default 5000 ms. ItsbeforeAll/afterAllonly set and restoreOS_TENANCY_POSTUREand load nothing. The first case,①, callsarrange()and so pays the cold start.src/organization-invite-role-default.test.ts: 6 cases, 3 througharrange(), same shape and posture as the one above; its first case①pays the cold start.client.hono/client.batch-transaction/client.data-prefix/client.environment-scoping/client.metadata-prefixsuites build aSqliteWasmDriverengine but perform no sign-up.client.test.tshas no realAuthManager(its sign-up cases are fetch-level). Out of this shape.⑤cases each build two scenarios (registered()thensignedIn(), i.e. two sign-ups plus a login), which makes them the file's heaviest windows. Under 24 busy loops plus extra unlocked load they reached 5002-5138 ms (6 of 20 loaded fix runs). CI has not shown them failing. If it ever does, the lever is that case's own work, becausesignedIn()already contains a registration. ⛔ Not a timeout. Noted, not filed.afterEachhad already closed, and logged[ObjectQL] No driver available for object 'sys_session'(seen only in loaded runs where a⑤case had already timed out). It is noise after a timeout, not a second failure. Noted, not filed.Generated by Claude Code