Skip to content

feat(ui): the translation preview strings move into the studio i18n namespace (#25922 slice S6b) - #27083

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-6d34fw
Oct 28, 2026
Merged

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread

Part of #25922

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

  • Slice S6b of the (M) item. The last family in ENGINE_STRINGS_EN / ENGINE_STRINGS_ZH (ui/packages/app-shell/src/views/metadata-admin/i18n.ts), engine.translationPreview.*, is appended to STUDIO_EN / STUDIO_ZH in ui/packages/i18n/src/namespaces/studio/{en,zh}.ts under an S6b heading comment, text byte-for-byte unchanged, its group comment moving with it. That is 23 rows in each language, not the 22 the order counted: feat(spec): a hook declares its refusal catalogue, and its body refuses by code, answered in the caller's language #26831 (merged before this branch) added engine.translationPreview.category.hooks, and this PR carries it.
  • The table is now empty. Both ENGINE_STRINGS_* declarations stay, as the order requires, each holding a two-line comment that says where the rows live and that slice S7 retires the table. t() / tOptional(), lookupString, TYPE_LABELS / DOMAIN_LABELS, FLOW_FIELD_ZH and check:i18n-designer-parity are untouched.
  • No runtime change. lookupString asks the empty table first and the namespace second, so TranslationPreview.tsx and its tests read the same strings with no edit. The preview's locale comes from its host's useMetadataLocale(), which already subscribes to the lazy zh catalogue.
  • One forced test adaptation. previews/__tests__/block-config-i18n.test.ts, case "reads two disjoint, non-empty tables out of i18n.ts", floored each table at non-empty. It now asserts both tables are empty (a key moved back would shadow the namespace) and keeps its range-disjointness check and its 3,000-key floor over both homes, which is what keeps an empty table from reading as a parser gone quiet. The case name says "both emptied into the namespace".
  • Changeset: .changeset/25922-studio-i18n-translation-preview.md, @object-ui/i18n patch.
  • ⛔ Untouched: ui/packages/i18n/src/locales/*.ts, ui/.github/**, root ci.yml, ui/scripts/check-i18n-designer-table-parity.mjs.

Why

Ruling 6431032267 Q2 = A (upheld by 6431234244): the designer table becomes one lazy @object-ui/i18n namespace, moved in slices. This family was held out of S6 while #26831 was open.

Tests

  • Pin widened: inspectors/inspectorStrings.studioNamespace-25922.test.ts gains a floor of 20 for engine.translationPreview. (87 families in all). Every key in the family must be in zh and resolve through t() to the namespace value in en-US, zh-CN and de-DE.
  • Move proof (one-off, not committed): both homes parsed by AST at f708cf22 and at this head. In each language: table 23 → 0, namespace 3,186 → 3,209 (en) and 3,240 → 3,263 (zh); removed set equals added set, 0 values differing, 0 keys in both homes, 0 existing namespace rows dropped or changed.
  • Equivalence (one-off, not committed): all 23 base rows per language, read by AST at f708cf22, compared with t(), tOptional() and tFormat() on this branch with zh resident, in en-US, en, de-DE, fr, no locale, zh-CN, zh and zh-TW: 552 lookups, 0 differing.
  • Ablations (scripts/ablation-replace.mjs; mutation landed by anchor count and blob, restored to the HEAD blob with git diff HEAD empty):
    • A zh row engine.translationPreview.coverage planted back in ENGINE_STRINGS_ZH with another value: the pin's t() case for engine.translationPreview. goes red, and the equivalence check reports exactly 9 differing lookups (t / tOptional / tFormat × zh-CN, zh, zh-TW).
    • The same row deleted from studio/zh.ts: the pin's family case and t() case go red, and the equivalence check reports the same 9.

The sweep

The zh loader in namespaces/studio/index.ts was delayed by 4,000 ms (ablation-replace.mjs --hold, restored to the HEAD blob). Under the delay, every app-shell test naming zh or a moved key plus the i18n tests naming studio ran (310 files): 3,617 of 3,618 tests passed. The one red is i18n/src/__tests__/studio-namespace-lazy.test.tsx, red by construction (its findByText waits 1 s against a 4 s delay). No racer. Then each .test.ts file that names a moved key or reads the table (6 files: the pin, block-config-i18n, zh-base-term.i18n-13131, and the dead-keys, designer-parity and en-drift script tests) ran alone, delayed: all green.

Acceptance notes

  • The parity gate on an empty table: check:i18n-designer-parity exits 0 and reports ENGINE_STRINGS 3209 en / 3263 zh, the same totals as on f708cf22, because its extractor reads the table and the namespace as one table. The AST extractor accepts an empty object literal; the line-range extractor in block-config-i18n and the indexOf reader in zh-base-term.i18n-13131 both need the closing }; on its own line, which is why the empty declarations keep the multi-line form.
  • Other open PRs: none known to add a table row after f708cf22 (claim 6460205408).
  • Eager bundle: not re-measured locally, as in S2–S6. CI's Build & E2E UI measures it.

Verification

At 13e08033. origin/main is 3 commits ahead (#27034, #27031, #27066); none touches either home, the namespace or an i18n gate, and git merge-tree is clean.

Tests and gates
  • pnpm --filter @object-ui/i18n --filter @object-ui/app-shell run type-check: exit 0. pnpm --dir ui run type-check:scripts: exit 0.
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 34 commands, each exit 0 (captured before any pipe), including pnpm --dir ui exec vitest run scripts/ (Test Files 176 passed | 2 skipped (178)). --ran: 34 derived, 34 run, 0 NOT-MEASURED.
  • ui check:i18n-designer-parity, check:i18n-dead-keys, check:i18n-drift ("No en value changed in this range."), check:i18n-keys: exit 0. check:new-line-citations: exit 0 (0 new). node scripts/check-nul-bytes.mjs: exit 0.
  • Focused set at normal speed (pin, the three TranslationPreview readers, zh-base-term, block-config-i18n, the parity and dead-keys script tests, studio-namespace, equivalence): Tests 451 passed (451).
  • Changed lines: 134 (+78 / −56) over 6 files.

Human Minimum

  • 1. No packages/spec change.
  • 2. No new names; the only new file is the changeset.
  • 3. No formatter ran; pnpm lint is CI's.
  • 4. One card slice, one branch off main, one pull request.
  • 5. Patch changeset with both declaration lines.
  • 6. n/a.
  • 7. No hand edits to generated or release-owned files.
  • 8. English.

Generated by Claude Code

… namespace

The 22 en and 22 zh engine.translationPreview rows, the last family in
app-shell's designer table, move into @object-ui/i18n's studio namespace
with their text unchanged. ENGINE_STRINGS_EN / ENGINE_STRINGS_ZH stay
declared, now empty, for the slice that retires the table. The namespace
pin gains a floor for the moved family.

Claude-Session: https://claude.ai/code/session_01JQwxbX3S5QrD29Ghii633f
Co-authored-by: Claude <noreply@anthropic.com>
The designer table's floor was "non-empty"; with its last rows moved into
the studio namespace it now asserts both tables are empty, so a key moved
back would shadow the namespace. The 3,000-key floor over both homes keeps
the parser's non-vacuity.

Claude-Session: https://claude.ai/code/session_01JQwxbX3S5QrD29Ghii633f
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 28, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#1 · session_01JQwxbZeBv2y91towxasSUT · head d53a76b1 · 2026-10-28T04:57Z

席位意见:第六片补遗把设计器私有表里最后的 engine.translationPreview.* 行(每种语言 23 行)原样搬进 studio 命名空间,表已清空,表本身留给 S7 删除。席位用自己的搬移校验核对过:增删相等、值不变、无重复归属。

  1. Shape: Part of #25922 (S6b); 6 files, +78/−56: metadata-admin/i18n.ts (rows out; both ENGINE_STRINGS_* declarations stay, empty, with a two-line comment each), namespaces/studio/en.ts +27 and zh.ts +25, two test files adapted, and a patch changeset for @object-ui/i18n (Clause-②: no).
  2. Premise measured: the seat ran its own move proof (moveproof.mjs, brace-matched parse of ENGINE_STRINGS_EN/ZH and STUDIO_EN/ZH at the merge base and the head). en: 23 removed, 23 added, 0 in both homes, 0 values differing. zh: 23 / 23 / 0 / 0. That is 23 rather than the order's 22 because feat(spec): a hook declares its refusal catalogue, and its body refuses by code, answered in the caller's language #26831's category.hooks merged first, as the order allowed. The only non-row hunks in i18n.ts are the two "empty since S6b" comments. t() / tOptional(), TYPE_LABELS / DOMAIN_LABELS, FLOW_FIELD_ZH and check:i18n-designer-parity are untouched; the dev measured the gate exiting 0 on the empty table. Dev: equivalence 552/552 lookups, both ablations red then restored, and the delayed-zh sweep over 310 files red only on the by-construction lazy test.
  3. Gates / check-runs: PR check-runs on d53a76b1: 43 success, 10 skipped, 0 failure; mergeable_state clean. Dev's local run: 34/34 derived gates exit 0 (--ran 34/34). The fix-up commit d53a76b1 changes only one changeset line (22 → 23 at the seat's request), and the changeset gates re-ran 0.
  4. Accepted deviations: block-config-i18n.test.ts's "non-empty table" floor now asserts both tables are empty. The adjacent range check (EN_TABLE.to < ZH_TABLE.from) still proves the source parser found both tables, so a parser gone quiet still fails. inspectorStrings.studioNamespace-25922 gains an engine.translationPreview. family floor of 20.
  5. Out of scope: none. Next is S7 (Tier H): delete the table, retire check:i18n-designer-parity and its ci.yml step. Skills-docs: none — string moves only.
  6. Landing: not Tier H; the seat readies and arms auto-merge.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 04:59
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 28, 2026 04:59
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 6e5f909 Oct 28, 2026
54 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-6d34fw branch October 28, 2026 05:48
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 40638669564 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Test UI (3/16) — 失败步骤: Run the ui tests (shard 3/16)

    × the package door draws the `*` entry too, and its save keeps the stored `*` entry 1056ms
    FAIL   dom  packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.objectGrantInherited-27010.test.tsx > every object-row control writes only what the admin sees change (objectstack#27010)
      ↳ 失败原因: (这条 FAIL 之后 12 行内没有可识别的原因行 —— 点进 job 看)
    
  • Test UI (10/16) — 失败步骤: Run the ui tests (shard 10/16)

    × (f) CONTROL: offers it, once, to a member granted that permission 54ms
    FAIL   dom  packages/app-shell/src/views/__tests__/AppReportIndex.navGates-26892.test.tsx > ⌘K offers its navigation entries as the sidebar shows them (objectstack#26892) > (f) CONTROL: offers it, onc
      ↳ 失败原因: AssertionError: expected [ 'Alpha', 'Beta', 'Gamma' ] to deeply equal [ 'Alpha', 'Beta', 'Delta', 'Gamma' ]
    
  • Test UI (5/16) — 失败步骤: Run the ui tests (shard 5/16)

    × keeps every key the editor does not author from the pending draft, byte-for-byte 1113ms
    × CONTROL — with no pending draft the base is still the published body 1036ms
    × REFUSES the save when the save-time draft read rejects, rather than fall back to the published body 1047ms
    FAIL   dom  packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.packageDoorDraftBase-26837.test.tsx > PermissionMatrixEditPage — the PACKAGE door saves onto the pending draft (objectsta
      ↳ 失败原因: (这条 FAIL 之后 12 行内没有可识别的原因行 —— 点进 job 看)
    FAIL   dom  packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.packageDoorDraftBase-26837.test.tsx > PermissionMatrixEditPage — the PACKAGE door saves onto the pending draft (objectsta
      ↳ 失败原因: (这条 FAIL 之后 12 行内没有可识别的原因行 —— 点进 job 看)
    FAIL   dom  packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.packageDoorDraftBase-26837.test.tsx > PermissionMatrixEditPage — the PACKAGE door saves onto the pending draft (objectsta
      ↳ 失败原因: (这条 FAIL 之后 12 行内没有可识别的原因行 —— 点进 job 看)
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 22 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants