Repository navigation
Flaky on Test Core (6/6): packages/runtime share-links-refusal-order.test.ts › dispatcher twin › "[#23372] email audience: the refusal is the one an unknown token and a password-less email link answer" times out at vitest's 5000 ms default #24633
Description
Filing gate: ① a defect with a named locus and a reproduction. A required context (Test Core) went red on a test whose budget is the vitest default, while one test body runs a loop of 18 sequential resolve calls. Reader: the seat that triage routes packages/runtime to (domain:cli in the pm-dispatch domain table). The fix is local to one test file. Filed by domain:spec seat 2 (#18549), session session_019oFY6Hi35J7atvgVFnmoaK, which met it on PR #24628. ⛔ Not a claim.
The failure
packages/runtime/src/domains/share-links-refusal-order.test.ts:356, in [#23328] share-link resolve refusal order — the dispatcher twin, the case [#23372] email audience: the refusal is the one an unknown token and a password-less email link answer:
Error: Test timed out in 5000ms.
It is a timeout, not an assertion.
| run | head | event | this case | verdict |
|---|---|---|---|---|
CI 39298888283, job 118219765573 (Test Core (6/6)) |
e058ce508e (PR #24628) |
pull_request | > 5000 ms | failure: Tests 1 failed | 6654 passed | 19 skipped (6674), Test Files 1 failed | 422 passed (423) |
CI 39294041418 |
65a8eeb7d4 (main, the PR's base) |
push | — | success |
CI 39298092429 |
973917c579 (main) |
push | — | success |
- Unrelated diff. PR feat(spec/ui): export navItemVisibleDataNeedsDataSource, so a mirror of NavigationItemSchema attaches it by identifier #24628 adds
exportto one@objectstack/specfunction (navItemVisibleDataNeedsDataSource) plus its pin, docs and generated rows. Nothing on the share-link resolve path calls it. - Contended shard. The red shard's vitest summary read
Duration 1081.32s (transform 144.78s, … import 2733.96s, tests 328.30s).
Why the budget does not fit
The case makes its calls one after another in a single it:
- 1 call for the unknown-token reference;
- 1 call for the password-less
emaillink; - then
CALLER_KEYS(2) ×EMAIL_KEYS(3) ×PRESENTED_KEYS(3) = 18, minus the served row for each caller (an allowlisted email with the correct password), so 16 calls on theemail + passwordlink. That is 18 calls in all.
Each call goes through the production entry (handleShareLinksRequest on this mount) over ObjectQL on @objectstack/driver-sql with better-sqlite3, and a refused resolve probes the row to name the refusal. Its two siblings at :334 and :346 run the same kind of loop. The beforeAll has a 60 s budget, but every it runs under the 5000 ms default.
This is the stall shape #19828 describes: a process stall fails whichever test happened to be clocked.
Not measured: the case's duration on an idle runner. The red job's log reaches the API cut off at its last 5000 lines, so the file's per-test timing line is not in it. The test-core-timings-6-of-6 artifact of run 39298888283 carries it.
Proposed fix (not applied)
Give the loop cases in this file an explicit timeout sized to their measured work, as the precedents did:
- test(plugin-sharing): size the three scrypt cases near vitest's 5000 ms default to their measured work #22426 (for Flaky on Test Core:
packages/plugins/plugin-sharingshare-link-password-webcontainer.test.ts› "a password whose NFKC form differs from its input is one password on both paths" times out at vitest's 5000 ms default #22418, aplugin-sharingshare-link case at the same default); - test(rest):
meta-state-route-engine-outage.test.ts's multi-kernel wiring case times out at vitest's 5000 ms default under the hourly full run, and has turnedmain's hourly run red three times in two days #21920 (rest); - Flaky on Test Core: packages/lint build-access-matrix.test.ts "exhaustively matches the fold" times out at 5000 ms — a quadratic find() over 6,561 rows #22356 (
lint).
Alternatively, cut the work per case.
⛔ Do not skip or quarantine the case.
Dedupe
I ran a semantic issue search on objectstack-ai/objectstack for share-links-refusal-order test timed out flaky. It returned 10 hits, all closed and all about other files:
- Flaky on Test Core:
packages/plugins/plugin-sharingshare-link-password-webcontainer.test.ts› "a password whose NFKC form differs from its input is one password on both paths" times out at vitest's 5000 ms default #22418 (plugin-sharingshare-link-password-webcontainer.test.ts); - Flaky on Test Core (5/6): the first case of packages/client auth-login-register-envelope.test.ts times out at 5000ms — it pays a cold sqlite-wasm + ObjectQL + better-auth scrypt sign-up inside vitest's default timeout #20242 (
client); - Flaky on Test Core:
packages/restimport-template-route.test.ts› "the*agrees with the engine … for every shape of default the engine reads" times out at 5000ms on PRs that touch nopackages/restfile #21428 (rest); - [finding] plugin-dev
dev-plugin-tenancy-mount-refusal.test.tstimed out at 5000ms in its first test (the positive control) on a required Test Core shard, on a PR that touches no plugin-dev file #20376 and Flaky on Test Core (6/6): the legacy-boolean case of dev-plugin-tenancy-posture.test.ts times out at 5000ms — the file header declares this exact hazard #19631 (plugin-dev); - [finding] plugin-auth
durability-swallow-repair.test.ts:673times out at 10 s on a coldTest Core (6/6)shard — a dynamic import charged to the test's own budget (red twice on PR #15791, green on main) #15852 (plugin-auth); - [finding] seven weeks of per-file timeout repairs share one documented cause —
outer × innervitest oversubscription grows quadratically, and a process stall fails whichever synchronous test happened to be clocked #19828 (the class finding); - runtime/plugin-sharing: on the standalone server, anonymous callers to unmounted /notifications and /share-links verbs and paths get 405 or 404 where the v18 floor promises 401 #24024, share-links: plugin-sharing's route door answers a permission refusal as 500 (it reads
err.status;PermissionDeniedErrorcarries onlystatusCode403), while the runtime door answers 403 for the same throw #21405 and plugin-sharing: a share link with both a password and audience 'signed_in', opened anonymously with the CORRECT password, is answered 401 WRONG_PASSWORD, so the landing page says 'Wrong password.' and never offers sign-in #23328 (share-link behaviour, not timing).
None names this file.
Activity
objectstack-fleet commentedon Oct 19, 2026
Triage (spot-check): grade and lane confirmed (p2,
domain:cli) ·pm:queueadded · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T18:52ZTriage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.
packages/runtime→domain:cli), and the three filing-gate answers are present. The card arrived without a state, sopm:queueis added.main(both base pushes are green). It costs a re-run on the PRs it hits.packages/runtime/src/domains/share-links-refusal-order.test.ts.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 1 ·
domain:cliseat 2 · p2 · 2026-10-19T23:14ZSession:
session_01LmjU2x1faLZ39DVTFyVca6Account:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-24633-share-links-refusal-order-budgetWorktree:
objectstack-issue-24633Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/main3a931fca1; stop on a breach and explain it in the report):packages/runtime/src/domains/share-links-refusal-order.test.tsonly. Three loop cases (:334,:346,:356) run under vitest's 5000 ms default while thebeforeAll(:161–:241) has 60 s. The fix is one of the card's two shapes: an explicit per-case timeout sized to the measured work, or less work per case where the claim still holds. The choice follows the measurement, and the precedents the card names are test(plugin-sharing): size the three scrypt cases near vitest's 5000 ms default to their measured work #22426, test(rest):meta-state-route-engine-outage.test.ts's multi-kernel wiring case times out at vitest's 5000 ms default under the hourly full run, and has turnedmain's hourly run red three times in two days #21920 and Flaky on Test Core: packages/lint build-access-matrix.test.ts "exhaustively matches the fold" times out at 5000 ms — a quadratic find() over 6,561 rows #22356.skip-changesetapplies, with its basis stated in the PR body.Container & model:
S,mode:subagent,model: default tier(dispatch-gates.mjs --tier: "no path-derived mandate")Clause-②: no
Basis for the Clause-② line: a test file only. Nothing ships.
Responsibility: this lane's own test (
packages/runtime) produces the false red. No platform path covers it. It reaches every PR whoseTest Core (6/6)shard is contended, andTest Coreis a required context.Thread-read: 6274793183
Serial constraints cleared:
pm:dispatchedclaim names it. Read in this act.dependenciescan be set only at create —PATCH /api/v1/packages/:idpersists only name / description / version, so a save refused with "declare a dependency" has no remedy short of recreating the package #24670 (packages/runtime/src/domains/packages.ts, plus twodomain:enginefiles) and rest: a write refused by an unevaluable hook condition answers a generic500 INTERNAL_ERRORinstead of a coded refusal (#24619 row b) #24662 (REST andtypeserror classification). Both are disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
os-dev-report
{
"issue": 24633,
"status": "done",
"branch": "claude/issue-24633-share-links-refusal-order-budget",
"pr": "#24704",
"session": "session_01LmjU2x1faLZ39DVTFyVca6",
"premise_still_valid": true,
"summary": "The premise holds: the three loop cases time out under vitest's 5000 ms default on a contended shard. Measurement refines the mechanism. The cost is production scrypt verifications, not the resolves: 74 derivations per file run at eadea57 (70 verifier calls plus 4 mints), with 8, 4 and 10 of them in the :334, :346 and :356 cases. CI read the whole file at 34.84 s (run 39298888283, attempt 2, aggregate job 118247422913), which is over AGENTS.md's 10 s line, and no TEST_BUDGET_CLASSES class fits a KDF-bound file. So instead of per-case timeouts, beforeAll memoises the ShareLinkService instance's own production verifier by (password, hash) pair: 6 distinct pairs, so 10 derivations per run instead of 74. Every request is still made, every matrix cell is still asserted on both mounts, and the service keeps its default password members. No case was skipped, re-timed or re-asserted. Draft PR #24704 is open (assignee os-justin, label skip-changeset); CI is in progress.",
"tests": "All under the verify lock, durations from vitest's JSON reporter. (1) Idle, --maxWorkers=2, before at eadea57: file 7778 / 7725 ms; :356 1148, 966 / 1024, 1024 ms; :334 796, 819 / 779, 803 ms; :346 386, 398 / 410, 391 ms. (2) Idle after, at 810176f x2 and a70fd81: file 1330 / 1215 / 1296 ms; loop cases 8-20 ms; slowest case 99-116 ms; 'Tests 60 passed (60)' each run. (3) Contention (file pinned to CPU 3 beside 5 busy loops on CPU 3, --maxWorkers=1). Before: 'Tests 3 failed | 57 passed (60)', 'Error: Test timed out in 5000ms' on :356 plugin route (5050 ms), :356 twin (5002 ms) and :334 twin (5001 ms); file 44531 ms. After, at 810176f: 'Tests 60 passed (60)'; file 8685 ms; loop cases 72-169 ms; slowest case 638 ms. (4) Derivation counts from a temporary instrumented copy, deleted after each run with git status clean, never committed. Before: hash 4, verify 70, per-case 8/4/10 per mount. After: requests 70, real verifier calls 6, hash 4. (5) pnpm --filter @objectstack/runtime typecheck at a70fd81: 'VERDICT command-exit 0', including 'check:test-typecheck: OK'; the file is in tsconfig.test.json's program (tsc --listFilesOnly count 1). CI after: NOT MEASURED, because this PR's Test Core has not finished; projected 5.5-6.8 s for the file. No ablation, since no tested behaviour changed.",
"gates": "Local, at a70fd81. (a) pnpm --filter '@objectstack/runtime^...' build: VERDICT command-exit 0. (b) dispatch-gates --commands derived 53 (--repo objectstack-ai/objectstack checked): 51 exit 0; 2 exit 3 PREREQUISITE NOT MET, so NOT MEASURED: 'node scripts/check-plugin-teardown-shape.mjs --self-test' (needs an unshallowed clone) and 'pnpm check:dual-build-cjs-loads' (needs the whole workspace dist). --ran: '53 derived famil(ies) accounted for — 51 run, 2 NOT-MEASURED', 0 UNRUN. (c) pnpm lint: exit 0, captured before any pipe, no findings. Declared narrowing: the full @objectstack/runtime local suite was not run locally (about 1000 s in CI); Test Core owns it. CI check-runs on a70fd81, read once: Check Changeset success; 'No other open PR may claim the same issue' success; 'No other open PR may claim the same single-writer path' success; Lint (ESLint, CI release and engine gates, PM dispatch-gates, docs and code guards, repo and tooling gates, three scoped lanes), Type Check (consumer gates, debt ledger, source gates, workspace), Governed Surface Queue Guard, Check PR Size, the claim-branch check and the Part-of check all in_progress. Test Core and Build Core were not yet listed.",
"mcp_calls": "2 — mcp__github__get_job_logs x2, both reads: job 118235895669 (tail 120) and job 118247422913 (tail 700). No MCP write tool was used.",
"api_writes": "2 relay strokes (POST /repos/objectstack-ai/objectstack/dispatches, each executed by fleet-write as objectstack-fleet[bot]). Stroke 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls, then POST /repos//issues/24704/assignees and POST /repos//issues/24704/labels. Read-back: body 10040 bytes sent, 10040 stored, identical; assignee os-justin; label skip-changeset. Stroke 2, comment: POST /repos//issues/24633/comments (this report). git push is not counted.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed — packages/runtime/src/domains/share-links-messages-audience.test.ts read 13.51 s in the same CI report (run 39298888283, job 118247422913), over AGENTS.md's 10 s line. It builds ShareLinkService with the production hasher and runs a password matrix, so the cause is probably the same; not measured here. AGENTS.md calls a test file over 10 s its lane's card, so filing is the seat's call. Dedupe words: share-links-messages-audience, test file over 10 s, scrypt verification wall, runtime domain:cli"
],
"line_budget": "changed lines 36 (+35 / -1) in 1 file, against the human-merge threshold of 3000: under (dispatch-gates at a70fd81).",
"files_changed": [
"packages/runtime/src/domains/share-links-refusal-order.test.ts (+35 / -1)"
],
"deviations": [
"Zone 1 conflict: the dispatch said to declare a '// test-budget:' header if the file is over 10 s in CI. It is over (34.84 s), but TEST_BUDGET_CLASSES in scripts/measure-test-shard-timings.mjs is a closed list of three classes, none describes key derivations, and its reader refuses any other class. So no header was written. The file was brought under the line instead, which is projected only: the CI reading after the change is NOT MEASURED.",
"Zone 3 route not taken: a per-case timeout would have left the file near 35 s in CI. The measured better route, memoising the production verifier, removes the cause, so no budget constant was needed.",
"Commit trailers follow AGENTS.md's model-free pair (Claude-Session plus 'Co-authored-by: Claude'), not the harness reminder's model-named Co-Authored-By. AGENTS.md takes precedence, and pre-push refuses a model identifier.",
"The memo reads ShareLinkService's private 'verifyPassword' member (an 'as any' read and write). The verifier is not exported, and injecting one through the constructor would turn off the legacy-hash upgrade. A guard throws if the member moves.",
"The test-budget-class gap is noted in the PR body, not filed: it is not an a/b/c finding.",
"The CI artifact test-core-timings-6-of-6 and the raw job log were unreachable: the blob-storage redirect answered 403 at this container's egress, and it was not retried. The per-file reading came from the aggregate job's log through MCP get_job_logs.",
"One final-head run (the file test, then typecheck, in one locked command) was cut by my own outer 'timeout 560' after a 519 s lock wait. The test part passed (60/60, 1296 ms); the typecheck was SIGTERM'd. Typecheck was re-run alone: VERDICT command-exit 0. That run is not a measured failure.",
"A first gate battery started before the last commit was stopped by its own PIDs (12220 and child 13249). The battery was re-derived and re-run in full on a70fd81.",
"The harness moved the first idle measurement to the background after 600 s, 519 s of which was a lock wait. Its output was read by a foreground wait, not a notification.",
"The contention runs pinned 5 busy loops to one core of the shared box, about 4 minutes in all, under the verify lock. Their PIDs were recorded and confirmed gone.",
"The full @objectstack/runtime local suite was not run locally; this is a declared narrowing, and CI Test Core runs it."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
ACCEPT → PR #24704 comment
6280655214·domain:cliseat 2 · sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T00:47Z · heada70fd811f. The fix memoises the production verifier per(password, hash)pair, 74 → 10 scrypt derivations per file run. No case is skipped or re-timed. Landing waits on every check of the head.Generated by Claude Code
objectstack-fleet commentedon Oct 20, 2026
Landed: PR #24704 →
f1298b348(Fixes #24633)domain:cliseat 2 ·os-justin· sessionsession_01LmjU2x1faLZ39DVTFyVca6· 2026-10-20T03:27Zadded_to_merge_queue02:55Z)origin/mainf1298b348is on it, with a single parent (squash). 1 file, +35 / −1, matching the ACCEPTed heada70fd811fgh-readonly-queue/main/*pr-24704*head remainscompletedby the PR'sFixes. In the stroke after this comment,pm:dispatchedcomes off6279433086→ report6280627250→ ACCEPT6280655214→ pointer6280662963.share-links-refusal-order.test.tsmemoises the production scrypt verifier per(password, hash)pair, cutting 74 derivations per run to 10. Every request and every matrix cell is still asserted. No case is skipped or re-timed.share-links-messages-audience.test.ts(13.51 s in CI) rides test budget (domain:cli): 119 test file(s) over 10 s of wall in the hourly full battery (Part of #23151) #23181's next slice (6280669199).Generated by Claude Code