Skip to content

fix(service-storage): Setup storage Test connection answers in the caller's language (#30335) - #30627

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-flbs42
Nov 5, 2026
Merged

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread
domain:server#2 · os-bill · session_01Utp6CaWLG2RrgKub5oRNjC

维护者速读

  • 改了什么:设置 → 存储 → 「测试连接」的结果提示按管理员的界面语言显示(成功、下载内容不一致、S3 缺存储桶或区域三种),覆盖平台全部 11 种语言;没给语言或语言不在平台表上时,仍是原来的英文。
  • 为什么改:中文控制台点「测试连接」看到的是 Storage round-trip succeeded (adapter=local).,管理员可能读不懂下一步。fix: Setup form help speaks to an administrator; queue pages, mail status banner and test toast read in Chinese #30551 已让设置动作拿到调用者语言,本 PR 让存储这个按钮用上它。
  • 风险与回滚:只动 service-storage 的 storage/test 处理器和一个新文案文件;ok、severity、探针上传下载删除、运维日志都不变;英文调用方的句子一字不变。回滚即还原本 PR。
  • 先看:packages/services/service-storage/src/storage-test-copy.ts(文案表与 storageTestCopyLocaleOf 语言查找);其次 storage-service-plugin.ts 里 storage/test 的四处 copy. 调用。
  • 两分钟验证:pnpm --filter @objectstack/service-storage exec vitest run --maxWorkers=2 src/storage-test-locale.test.ts,预期 10 个全绿,第一个用例的消息是 存储连接测试成功(适配器:local)。
  • 需要你做的:无,席位落地。

Refs #30335

Clause-②: no
Metadata-protocol: none

What changes

The console prints the storage/test settings action's message as the toast, bare. Since #30551 the settings action route hands each action handler the caller's display language as the input's locale (Accept-Language, else ?locale; settings-routes.ts requestLocaleOf). The storage handler now writes its answer in that language.

  • New packages/services/service-storage/src/storage-test-copy.ts: one entry per language on the platform locale table (PLATFORM_LOCALES): en, zh-CN, zh-Hant, es-ES, ar, fr, pt-BR, ru, de, ja-JP, ko. The four codes this package's bundles already used keep their keys. Four sentences each: success (still names the adapter), probe read back not the one written, S3 settings missing a bucket or a region, and a lead-in for an adapter's own error.
  • storage/test reads locale from the handler input, the same source as the mail test notice in fix: Setup form help speaks to an administrator; queue pages, mail status banner and test toast read in Chinese #30551. The adapter's own error text (S3 SDK, file system) stays verbatim: alone in English, as before; in another language behind the lead-in (存储连接测试失败:…), so the reader knows the rest is the adapter's untranslated report.
  • buildAdapterFromValues throws a new S3SettingsIncompleteError with the same English message as before, so the settings re-apply path and its warn log line are byte-identical; only the storage/test answer reads the type to localise the refusal.
  • Unchanged: ok, severity, the adapter name, the probe and its cleanup, every ctx.logger line, and every sentence an English or locale-less caller gets.

Where the strings live, and one deviation from the precedent. The precedent is #30376 (mfa-required-enrollment-predicate.ts): a settings handler's prose sits in a module-level copy table beside its code, not in the package's translations/ bundles (those carry object metadata). This PR follows it, with one difference: the lookup does not use @objectstack/core's resolveLocale. With both zh-CN and zh-Hant in one table, that ladder's base-language and first-variant steps answer zh-TW by key order, which is the trap the platform table's own reader warns about (packages/spec/src/system/platform-locales.ts, the platformLocaleTagOf note). So storageTestCopyLocaleOf reads the caller's code through platformLocaleTagOf (aliases zh-TW, pt, en-US; table tags zh-Hans, ja), then drops one subtag at a time (RFC 4647 lookup: fr-CA → fr, zh-Hant-TW → zh-Hant), and falls back to English. This is the gap #30538 names (resolveBundleLocale / resolveLocale do not read platformLocaleTagOf); once #30538 lands this module can go back to the shared resolver.

Tests

New packages/services/service-storage/src/storage-test-locale.test.ts, 10 cases, all through the REAL handler the plugin registers, on a real local adapter, with the input locale set or absent:

  • zh-CN success sentence, ok: true, severity: 'info'; en-US success is the old English sentence;
  • no locale, tr-TR (not on the table) and '' answer the old English sentence;
  • zh resolves to the zh-CN copy;
  • zh-CN probe mismatch (ok: false, severity: 'error'), and the probe object is still removed;
  • zh-CN incomplete S3 settings; no locale keeps the English S3 refusal;
  • zh-CN adapter error = lead-in + the exact English adapter text;
  • the table carries all 11 languages, every key in every language, placeholders verbatim, no non-English entry copied from English, and every PLATFORM_LOCALE_TAGS tag finds its own entry;
  • 24 code → entry mappings (aliases, table tags, shortened subtags, unknown → English).

Existing pins in storage-service-plugin.test.ts and storage-service-plugin.probe-cleanup-store.test.ts (English messages, no locale) pass unchanged.

Acceptance notes

  • Measured before the change on the real plugin handler (base c23eafa8): locale: 'zh-CN' and no locale both answered Storage round-trip succeeded (adapter=local).; mismatch Probe download did not match upload.; S3 StorageServicePlugin: S3 adapter requires s3_bucket and s3_region.
  • Clause-②: no: nothing outside this package's own tests matches the English text (git grep -n "round-trip succeeded\|did not match upload" hits only service-storage). The console prints the message and reads ok.
  • Arabic copy carries no bidi control characters; direction is the console's dir.
  • An end-to-end pin through SettingsService + routes was not added here: service-storage has no service-settings dependency, and fix: Setup form help speaks to an administrator; queue pages, mail status banner and test toast read in Chinese #30551 pins the route → handler locale hop.

Verification

All on head 47c43908c (merge of main at bdbaf80c, which carries #30551).

Local runs
  • pnpm --filter @objectstack/service-storage test: Test Files 73 passed (73), Tests 1353 passed (1353).
  • pnpm --filter @objectstack/service-storage typecheck: exit 0 (check:test-typecheck: OK).
  • node scripts/check-i18n-bundles.mjs: exit 0 (10 packages, all bundles in sync).
  • node scripts/pm/dispatch-gates.mjs --commands: 62 derived families, all 62 exit 0; --ran: 62 derived, 62 run, 0 NOT-MEASURED.
  • eslint --no-inline-config on the three changed source files: exit 0.
  • Full dogfood under the verify lock (pnpm --filter '@objectstack/dogfood^...' build && pnpm --filter @objectstack/dogfood test): VERDICT command-exit 0, Test Files 420 passed, 3 skipped (423); Tests 3496 passed, 36 skipped (3532).
Ablations (scripts/ablation-replace.mjs, each restored, git diff HEAD empty after)
  • A1 handler ignores the input locale: 5 failed, 5 passed (the five zh cases).
  • A2 fallback en → zh-CN: 4 failed (no-locale English, no-locale S3, the lead-in case, the mapping pin).
  • A3 S3 type check off: 1 failed (zh-CN incomplete S3).
  • A4 drop the ko entry: 1 failed (all 11 languages pin).
  • A5 no subtag shortening: 1 failed (mapping pin).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Utp6CaWLG2RrgKub5oRNjC

…ller's language

The storage/test settings action writes its message in the locale the
settings action route hands the handler (Accept-Language, else ?locale):
success, probe mismatch and incomplete S3 settings in en, zh-CN, ja-JP and
es-ES; an adapter's own error text stays verbatim behind a localized
lead-in outside English. Absent or unknown locale answers in English.

Co-Authored-By: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01Utp6CaWLG2RrgKub5oRNjC
…platform languages

Adds zh-Hant, ar, fr, pt-BR, ru, de and ko to the storage/test copy table,
reads the caller's code through platformLocaleTagOf (aliases and table tags)
and then shorter subtags, and pins that every key carries every language.

Co-Authored-By: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01Utp6CaWLG2RrgKub5oRNjC
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@github-actions

github-actions Bot commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

11 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

What this run could not see
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 10 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json aad1603cc2180b3eefa8cee41f5b895b8ee45909 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 5080ecef6bce855c879ca63082250c036593845c — the merge of head 47c43908c592df4ac5a26fc5488140d64c7b741e into base aad1603cc2180b3eefa8cee41f5b895b8ee45909, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5080ecef6bce855c879ca63082250c036593845c && git checkout 5080ecef6bce855c879ca63082250c036593845c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin aad1603cc2180b3eefa8cee41f5b895b8ee45909 47c43908c592df4ac5a26fc5488140d64c7b741e && git checkout -B drift-repro aad1603cc2180b3eefa8cee41f5b895b8ee45909 && git merge --no-ff 47c43908c592df4ac5a26fc5488140d64c7b741e

node scripts/docs-audit/affected-docs.mjs --json aad1603cc2180b3eefa8cee41f5b895b8ee45909

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#2 · os-bill · session_01Utp6Cbvcmv8YWFhFJwzjKL

维护者速读

  • 改了什么: 设置 → 存储 → 测试连接的结果提示按管理员的界面语言显示(平台 11 种语言),英文和不带语言的调用方一字不变。
  • 为什么改: 中文控制台里这条提示一直是英文 Storage round-trip succeeded (adapter=local).(Setup: datasource and storage results reach the toast in English, and a refused delete does not name the objects #30335 存储一半)。
  • 风险与回滚: 只换提示文案;测试结果、成功/失败判断、探针和清理、服务器日志都不变。回滚即撤本 PR。
  • 先看: packages/services/service-storage/src/storage-test-copy.ts(文案表和查找),再看 storage-service-plugin.ts 里 storage/test 的几处替换。
  • 两分钟验证: pnpm --filter @objectstack/service-storage test -- storage-test-locale。
  • 需要您做的: 无,席位经合并队列落地(非受管面,402 行,非 BREAKING)。
  • 席位意见: ACCEPT。语言来源和邮件“发送测试邮件”提示同一个(fix: Setup form help speaks to an administrator; queue pages, mail status banner and test toast read in Chinese #30551 加的动作入参 locale),查找先过平台语言表的别名,繁中请求不会落到简体。

席位核对 — ACCEPT · domain:server#2 · head 47c43908c592df4ac5a26fc5488140d64c7b741e

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 Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant