Skip to content

test(ui/scripts): take the dead-keys sweep's whole-repo readings once, at collection - #27437

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-mb86y4
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-mb86y4

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #27423

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:check-i18n-dead-keys.test.ts 里读真实仓库的四个读数(sweep、analyze、collectEnKeys、间接模板头)每个文件只算一次,在 describe 体(收集阶段)里取,三个用例不再在自己的 15 秒预算里重扫整个仓库。
  • 为什么改:main 上 Test UI (10/16) 在用例「keeps every key it makes reachable OUT of both tiers」超时 15 秒;同一 sha 在合并队列里是绿的,属于负载下的间歇红。按裁决不调超时、不跳过、不重试、不改断言。
  • 风险与回滚:只动一个测试文件,断言逐条不变,读数被冻结,用例之间无法互相污染;回滚即 revert 本 PR。
  • 先看:ui/scripts/__tests__/check-i18n-dead-keys.test.ts 顶部新增的 realTree 备忘块,以及两个 on the real tree / measured on THIS repository describe 体里的取值行。
  • 两分钟验证:pnpm --dir ui exec vitest run scripts/__tests__/check-i18n-dead-keys.test.ts,预期 146 passed,三个原慢用例各在几毫秒内完成。
  • 需要你做的:无,席位落地。

What changes

ui/scripts/__tests__/check-i18n-dead-keys.test.ts only.

  • A module-level realTree memo takes each whole-repository reading once per file: sweep(REPO_ROOT), analyze(REPO_ROOT), collectEnKeys(REPO_ROOT) and collectIndirectTemplateHeads(REPO_ROOT, …). Each value is frozen (arrays and plain objects, recursively), so a case that sorted or spliced one in place would throw instead of leaking into the next case.
  • The two describes that read the real tree (the one-hop indirect template leg › on the real tree and the applied dynamic heads are REPORTED, not filtered › measured on THIS repository) now take those values in their describe bodies, which run at collection. Three cases lose their in-case repository walks:
    • keeps every key it makes reachable OUT of both tiers (the red one): its own sweep(repoRoot).
    • ⛔ does NOT enrol its heads in the call-site gate’s family registry: its own analyze(repoRoot).
    • reports one row per head the sweep actually applied — no head goes unreported: its own analyze(repoRoot) plus collectIndirectTemplateHeads(repoRoot, collectEnKeys(repoRoot)).
    • Three more collectEnKeys(repoRoot).leaves reads in the second describe read the shared packKeys instead.
  • scripts/check-i18n-dead-keys.mjs is untouched: no seam was needed.

Why

The ruling carried over from #27076 holds: the timeout is not raised, no case is skipped, no retry is added, and no assertion changes. The cost was the test's own, so the cost moved out of the cases.

Collection is the right home. ui/AGENTS.md (测试纪律) puts warm-up cost at module scope because no test or hook timeout bounds it, and it rules out a beforeAll, whose 10 s hookTimeout is narrower than the 15 s testTimeout. The second describe already took its sweep(repoRoot) in its body; this PR makes both describes share that one reading. In @vitest/runner 4.1.12, withTimeout wraps test bodies and hooks only, not the suite collect path.

Tests

Measured on this container (4 cores, a shared box). "Load" means four node -e 'for(;;){}' CPU burners beside the run. Every run went through scripts/pm/os-verify-lock.sh. Durations come from vitest's JSON reporter (per case) and its Duration line (per file).

leg red case reports one row per head… does NOT enrol… file Duration (import / tests) result
before, first run after install (cold) 15305 ms, timed out 6482 ms 4439 ms lock held 45 s 145/146, red
before, idle 8378 ms 5909 ms 4709 ms 32.52 s (11.40 / 20.74) 146/146
before, load 10507 ms 7544 ms 5504 ms 44.90 s (17.87 / 26.40) 146/146
after, first run 2 ms 0 ms 0 ms lock held 22 s 146/146
after, idle 3 ms 0 ms 0 ms 20.82 s (18.32 / 2.04) 146/146
after, load 5 ms 1 ms 0 ms 31.34 s (27.51 / 3.15) 146/146

The cold "before" run reproduces the main-red: the same case, Error: Test timed out in 15000ms. After the change, the slowest case in the file under load is 404 ms (both control groups from the card … POSITIVE). The collection phase grows by the one extra analyze() reading, about 7 s idle and 10 s loaded. No timeout bounds that phase. The file's total wall drops by about 12 s idle and 13.5 s loaded.

The before legs ran the file restored from HEAD~1 by git restore --source=HEAD~1, with a trap that restores HEAD. Restore proof: git hash-object = git rev-parse HEAD:… = 9c08a7b0, and git status --porcelain is empty.

Acceptance notes

  • Finding, not fixed here (the dispatch order asked for a read-only measurement): ui/scripts/__tests__/check-vi-mock-inherit.test.ts has the same in-case repository-sweep shape. Idle on this box, three cases take 6.1 to 6.8 s each: puts the census in the verdict… (it spawns node scripts/check-vi-mock-inherit.mjs over the whole tree) and both the sweep — every @object-ui/i18n factory inherits… cases, which each call swept() (a scan(repoRoot, …)) in-case. The file runs 29.17 s (import 7.05 s, tests 21.77 s). About 2x load would put them near the 15 s budget.
  • The card's "Done when" needs two consecutive green push runs and the next scheduled full run. Those happen after merge and are the seat's to read.

Verification

Gates derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at the final head. The exit codes and the --ran reconciliation are in the os-dev report on #27423.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (CI owns the lint run)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset. This one publishes nothing: it is a test file under the private ui/ root, so the PR carries skip-changeset.
  • 6. packages/spec touched: n/a.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English. (The 维护者速读 block is the repo's Chinese summary convention.)

Generated by Claude Code

…, at collection

The case "keeps every key it makes reachable OUT of both tiers" ran its own
`sweep()` of the whole repository inside its 15 s budget and timed out on a
loaded Test UI shard; two sibling cases ran `analyze()` and the indirect-head
collection in-case the same way. Each real-tree reading is now taken once per
file through a frozen memo, in the describe bodies, so collection pays it and
no case does. Every assertion reads the same values as before.

Claude-Session: https://claude.ai/code/session_01JQwxbYeSmhiCsoJFL2RkQS
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 29, 2026
…I read as implicit any

Claude-Session: https://claude.ai/code/session_01JQwxbYeSmhiCsoJFL2RkQS
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#2 · os-warren · session_01JQwxbXpF772qWJjojJvRXw

席位核对

ACCEPT · domain:ui#2 · session_01JQwxbXpF772qWJjojJvRXw · head 823c7bb3a0 · 2026-10-29T07:08Z

席位意见:p0 main-red 修复。check-i18n-dead-keys.test.ts 的四个整仓读数每文件只取一次,在收集阶段的 describe 体里取并冻结,用例不再在 15 秒预算内扫仓库。没有调超时、跳过、重试或改断言,.mjs 未动。

  1. Diff read: 1 file, +52 / −11, test only.
    • A module-level realTree takes four memos (sweep, analyze, collectEnKeys, collectIndirectTemplateHeads) through once(), and each value is deep-frozen (arrays and plain objects).
    • The two real-tree describes read them in their bodies, at collection, so no case and no beforeAll hook budget walks the repo.
    • Every assertion line is unchanged; only the source of each value moved.
  2. Checked against the order (main red: ui/scripts/__tests__/check-i18n-dead-keys.test.ts:1714 times out at 15 s on Test UI (10/16) (push CI on 45c9be5f); the same sha passed in the merge queue #27423): the fix takes the reading out of the case rather than widening a budget, as the card's never-list required. The premise note (the second sweep already sat at describe level, and two analyze calls were the other in-case walks) is accepted.
  3. Proof: the red case went from 15305 ms (timed out, cold), 8378 ms idle and 10507 ms loaded to 2–5 ms. The file went from 32.5 s to 20.8 s idle, and from 44.9 s to 31.3 s under 4 CPU burners. 18/18 derived gates exit 0. The Type Check UI red on e784b672 (implicit any on the realTree self-reference) is fixed by 823c7bb3.
  4. Accepted deviation: no PR assignees (os-dev.md since pm-dispatch(review): a PR reaches a human only after the seat's ACCEPT and a same-head contract PASS: no seat assignee at the draft open, the approver request is the seat's hand-off, a PR landed owing a review is re-reviewed with findings filed as cards #27385).
  5. Shape: Fixes #27423, Clause-②: no, Metadata-protocol: none, skip-changeset (test only, nothing publishes). Not governed, and there is no contract-review face.
  6. Finding carried: check-vi-mock-inherit.test.ts has the same shape, with three in-case repo scans of 6.1–6.8 s each. Filed as check-vi-mock-inherit test: three cases scan the whole repository inside their 15 s budget (same timeout shape as #27423) #27449.
  7. Landing clause: all check-runs on 823c7bb3 concluded (43 success, 12 skipped, 0 failed), Test UI (10/16) included. Mergeable is clean. The seat readies and arms now. The card's done-when (two green push runs on main) is read after the merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

1 participant