Repository navigation
test(rest): pay the state route's objectql load at collection, so the multi-kernel case stops timing out on the hourly run - #21925
Merged
objectstack-fleet[bot] merged 3 commits intoOct 6, 2026
Conversation
… the multi-kernel case The first case to get past the gate with a schema paid the cold load of `@objectstack/objectql` that `GET /meta/object/:name/state/:field` reaches through a dynamic import: 3.6 s of the 5000 ms budget idle, and a timeout on every run confined to one contended core. A module-top import moves that cost into collection, which vitest does not clock. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
… ms budget The case is the file's first to reach the state route's objectql import, so it is where a load moved back into a clocked window would land. Its own work measures 3 ms idle and at most 23 ms on a fifth of one core; the load measured 893-3661 ms. A 500 ms budget reads that regression red on an idle box. Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU Co-Authored-By: Claude <noreply@anthropic.com>
… against Claude-Session: https://claude.ai/code/session_01RWZbGvPFcRKvUqASZtunCU 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-21920-meta-state-route-timeout
branch
October 6, 2026 01:44
This was referenced Oct 9, 2026
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.
Part of #21920
Clause-②: no
What stays open on #21920 after this merges: the card's own evidence bullet, "the case's timing in
Test Core's timing artifacts across several hourly runs after the fix", which only post-merge hourly runs can supply, and the card's family enumeration. This PR does not close it.Measured cause: a harness module load, not a production first-request cost
The
[#15405] §0multi-kernel wiring case (meta-state-route-engine-outage.test.ts:296onorigin/main3dbd0842) is the file's first case to get past the anonymous-deny gate with a schema. That makes it the first to reach the state route's dynamicawait import('@objectstack/objectql')inrest-server.ts.@objectstack/rest's tests resolve that specifier throughdist/(it is in this package'sKNOWN_UNALIASED_TEST_IMPORTSrow), so the first request to reach that line pays a cold vite transform and evaluation of objectql's whole module graph. That load ran inside the case's 5000 ms clocked window.All readings below are from a 4-vCPU container. The box was shared with sibling agents, so "idle" means the verify lock was free and the load average was about 1.5. The file-alone runs used
vitest run --project local --maxWorkers=1 FILE, plus a JSON reporter for the per-case durations.3dbd0842)1c0800d8)Test timed out in 5000ms, 3 of 3 (5014-5023 ms)@objectstack/restlocalsuite, 3 workersteststotal for the file, idleA phase-timed probe (a temporary test file, deleted and never committed) separated the parts of the case. Idle, cold, its parts were:
kernelHost()wiring: 0.6 msRestServerconstruct plusregisterRoutes(): 0.6 msOn the cold multi-kernel branch, a request answering 404 before it reaches the import cost 1.5 ms. With
import('@objectstack/objectql')paid first, the handler took 1.8-1.9 ms. The import itself cost 2643.6 ms at module top and 2660.2 ms in a test body.kernelHost()construction, and it lands on whichever case first reaches that import line.import('@objectstack/objectql')of the built package costs 1010-1046 ms alone, and 619 ms on top of the@objectstack/coreand@objectstack/specthatrest-server.tsalready loads statically. A host whose engine is objectql has the module loaded before its first request anyway. The production call stays as it is: it is dynamic on purpose, because objectql is a devDependency of@objectstack/restand a host without it degrades to 501.The fix (test-only)
import '@objectstack/objectql';in the test file. vitest pays it during collection, which it does not clock. The dynamic call inrest-server.tsis unchanged.driveStateOnKernelHost(providerHealthy)timed withperformance.now(), must stay under 500 ms. The budget is sized from the readings above:No global
testTimeoutchange, no per-case timeout, no skip,retryor.todo, and nothing outsidepackages/rest/src/meta-state-route-engine-outage.test.ts.Deviation from the card's letter, declared rather than chosen silently
For a harness cost, the card says to move it "into a hook with its own explicit, measured budget". This PR moves it to module top instead, into collection, where no budget applies at all. Two reasons:
pnpm check:test-source-aliasgates it."packages/plugins/plugin-dev/src/dev-plugin-security-enforcement-warning.test.ts, record the measured failure of the hook shape. AbeforeAllwithhookTimeout10000 ms took the same kind of load toHook timed out in 10000mson heavier queue shards, because every budget the cost is moved into can be exhausted by a heavier shard.The ruling's intent holds:
This package already follows the same pattern:
analytics-dataset-selection-door.test.tspays@objectstack/spec/apiand@objectstack/spec/dataat module top for the same reason.Ablation (one-off, no permanent artifact)
The fix was committed first. Then
node scripts/ablation-replace.mjsreplaced the anchorimport '@objectstack/objectql';(1 hit, 1 to 0) with a marker comment (0 to 1), blob41d43e13d9c9to7b3ddb152ff9. The on-disk count read 0 import lines and 1 marker line before either leg ran. Both legs were run from the mutated tree:expected 2676.690643 to be less than 500, and the other 13 cases passed.localsuite, 3 workers: the pin went red withexpected 1723.4459419999994 to be less than 500, with 1 failed and 4897 passed.Restore was proven by the tool: blob after restore equals the HEAD blob
41d43e13d9c9, andgit diff HEADis empty.git status --porcelainwas empty afterwards. The ablation needed no build leg, because the mutated file is the test itself, which vitest reads from source.Family readings (H5): no second case near the default
These readings come from four runs of the whole
@objectstack/restlocalsuite with 3 workers: before the fix, the ablation, after the fix, and at the final head. The last of those ran beside the gate battery. They list every other case at or above 300 ms:import-template-route.test.ts"for every shape of default the engine reads"meta-published-overlay.test.ts"§1 serves a RUNTIME-published item…"import-template-route.test.ts"answers an xlsx template…"import-*files andrest-data-number-value.test.tsI read the files of the first three rows. They import their engines statically at module top, so no first load is paid inside their clocks. "For every shape of default" spends its time on real work: SQL DDL across many objects. I did not read the files of the last row. Every reading is at or below 26% of the 5000 ms default, so this PR changes nothing else.
Tests and gates
All of these ran at
1c0800d8, the PR head, as one command chained with&&under the verify lock, which reportedVERDICT command-exit 0:@objectstack/restlocalsuite,vitest run --project local, 3 workers: 260 files passed, 4898 passed and 326 skipped. The §0 multi-kernel case took 3 ms.pnpm --filter @objectstack/rest test:repo: 5 files passed, 177 passed and 1 skipped.pnpm --filter @objectstack/rest typecheck:check:test-typecheck: OKwith 0 ledgered errors. The test layer is compiled undertsconfig.test.json, and--listFilescounts this file once among 265src/**/*.test.tsfiles.The gate battery is the dispatch's 128 commands, a superset of the 54 that
dispatch-gates.mjs --commandsderives for this one-path change. Its results are in the report on the card.check:closing-target-claimreads PR context, so it is NOT MEASURED before the PR exists.Acceptance notes
scripts/check-test-source-alias.mjs's clocked-window rule reads load sites written in TEST files. It does not read a dynamic import written in production source and reached from a test body, which is how this one landed in a clocked window with the gate green. This is recorded as an observation only. No gate is proposed, since new gates default to no, and nothing is filed. Carrier: none.Generated by Claude Code