Skip to content

fix: Setup form help speaks to an administrator; queue pages, mail status banner and test toast read in Chinese - #30551

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

objectstack-fleet[bot] merged 7 commits into
mainfrom
claude/project-thread-q572zu

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

Refs #30208 (rows 1, 2, 3, 7, 8)

Clause-②: yes (widening)
Metadata-protocol: none
Skills-docs: none — git grep -n -I -E "fail-closed at resolution|half-open \[from, until\)|graph semantics|root of tenant|HRIS sync|upstream HRIS|expanded by graph|When true, every member|When true, the user|task/run attribution|No mail leaves this machine|Sent test email" -- skills on e205cf31 answers 0 lines; no published skill sentence quotes the replaced help or the mail status text.

维护者速读

  • 改了什么:Setup 里「新建权限集分配 / 岗位分配」「外出委派规则」「新建业务单元」「编辑组织」「用户」表单的字段说明改成管理员能看懂的话(去掉 fail-closed、半开区间、图谱、Null、HRIS、「为 true 时」等,改为「开启后…」);「队列」「队列成员」两页补上中文;「邮件投递」顶部状态横幅和「发送测试邮件」的提示在中文界面下显示中文。
  • 为什么改:真实用户走查 Setup 时,这些说明在描述实现而不是告诉管理员该填什么;队列两页整页英文(按钮显示「新建Queue」);邮件页横幅和测试提示是英文。
  • 风险与回滚:只改服务端下发的文字,不改任何字段名、选项值或行为;唯一的接口变化是设置动作处理函数多收一个可选的 locale,已有处理函数不受影响。回滚即 revert 本 PR。
  • 先看:packages/plugins/plugin-email/src/live-transport-status.ts(中英文案表与按语言取文案),packages/services/service-settings/src/settings-routes.ts 与 settings-service.ts 的 runAction(动作路由把请求语言交给处理函数),packages/plugins/plugin-sharing/scripts/i18n-extract.config.ts(队列两个对象进翻译包)。
  • 两分钟验证:pnpm --filter @objectstack/plugin-email exec vitest run src/mail-log-provider.pin.test.ts,预期 13 条全过,其中 5 条是中文横幅与测试提示。
  • 需要你做的:无,席位落地。

What changes

Rows 1–3: field help in administrator wording (English source and zh-CN). Text only; no field name, key, option value or behaviour moves.

Form Field Before (zh-CN) After (zh-CN)
权限集分配 / 岗位分配 valid_from 在解析时以 fail-closed 方式强制执行 到时即生效,无需等待任何定时任务
权限集分配 / 岗位分配 valid_until 半开区间 [from, until),UTC;智能体授权必填 到此时间即失效(按 UTC 计);授予 AI 智能体的分配必须填写
权限集分配 reason 智能体授权在此记录任务/运行归属 授予 AI 智能体时,请写明它为哪项任务获得授权
审批委派 valid_until 半开区间 [from, until) 规则到此时间即失效(按 UTC 计)
业务单元 kind 不会改变图谱语义 仅用于分类和报表,不会改变该单元在组织中的位置和覆盖范围
业务单元 parent_business_unit_id Null 表示租户根节点 留空表示顶级单元
业务单元 active 为 false 时,图谱查询不会展开该业务单元成员 关闭后即停用该单元:授予该单元或其上级单元的共享等访问权限,将不再覆盖其成员及下级单元
业务单元 effective_from / effective_to / external_ref HRIS 同步 / 上游 HRIS 通常由 HR 系统同步填写 / 在 HR 系统中的编号
组织 require_mfa 为 true 时 开启后
用户 banned, must_change_password 为 true 时;403 PASSWORD_RESET_REQUIRED 开启后;用户必须先修改密码才能继续使用

The English sources (*.object.ts) say the same in English; en.*.generated.ts follow by extract. The active sentence states what BusinessUnitGraphService does with an inactive unit (contributes no members and stops the descent into its subtree, plugin-sharing/src/business-unit-graph.ts); must_change_password names the admin create, import and reset paths that set it (plugin-auth admin-user-endpoints.ts, admin-import-users.ts).

Row 7: the 队列 and 队列成员 pages. plugin-sharing's extract config now lists SysQueue and SysQueueMember beside its three sharing objects (the bundle-ownership list follows). The extract added both objects to every bundle; zh-CN is written by hand (队列 / 队列成员, every field, help, the member-type options and the two list-view names). ja-JP and es-ES carry the extract's English fill, except the member-type options, which reuse the renderings sys_record_share / sys_sharing_rule already use in those bundles (the package's recipient-vocabulary-consistency pin requires one rendering per option key).

Row 8: Setup → Email.

  • plugin-email: describeLiveMailTransport(source, locale?) writes the banner from a per-language copy table (MAIL_DELIVERY_COPY, en and zh-CN; mailDeliveryCopy resolves exact, then by language, else English), the mechanism service-settings' currency lock already uses for its live status. The plugin's live-status provider passes the locale the settings service already hands it. The mail/test handler writes its sent, failed and log-only answers from the same table.
  • service-settings: SettingsActionHandler's input gains an optional locale; runAction(namespace, actionId, payload, ctx, display?) passes display.locale to the handler; the POST action route passes requestLocaleOf(req), the same reading the GET route gives the live status. The locale stays out of ctx. An existing handler compiles and behaves unchanged.

Tests

One pin file per row, plus a route pin:

  • plugin-security/src/translations/assignment-help-wording.test.ts: served zh-CN (SecurityTranslations) and the English source of valid_from / valid_until / reason on both assignment objects carry no fail-closed, interval notation or agent grants / 智能体授权, and the zh-CN help is Chinese.
  • plugin-approvals/src/translations/delegation-window-wording.test.ts: sys_approval_delegation.valid_until, same shape.
  • platform-objects/src/identity/setup-form-admin-wording.test.ts: served zh-CN (SetupAppTranslations) and the English source of the nine business unit, organization and user fields carry no graph vocabulary, null literal, HRIS, boolean literal or HTTP status code.
  • plugin-sharing/src/translations/queue-pages-zh-cn.test.ts: the served zh-CN bundle names 队列 / 队列成员 and translates every field label, help and member-type option.
  • plugin-email/src/mail-log-provider.pin.test.ts (the existing Setup → Email harness, new top-level describe): zh-CN banner for the out-of-the-box and the delivering transport, the zh-CN test toast, the zh-CN log-only warning, and a control (fr-FR answers English).
  • service-settings/src/settings-routes.test.ts: the POST action route hands the handler zh-CN from Accept-Language, undefined without one, and not in ctx.

Red on main (the pin commit 0f390750, before the fix): security 10 failed / 2 passed, approvals 2/2 failed, platform-objects 18/18 failed, sharing 4/4 failed, email 4 failed / 9 passed (the control passed), settings routes 1 failed / 34 passed.

Ablation (once, scripts/ablation-replace.mjs, anchor hit x1, restored blob equals HEAD, git diff HEAD empty): with the live-status provider calling describeLiveMailTransport(this.service) again (the locale dropped), exactly the two zh-CN statement pins go red, 2 failed / 11 passed.

Acceptance notes

Verification

Package suites and typechecks (head e205cf3; the later main merge brought one ui-only commit)
  • pnpm --filter @objectstack/PKG test and typecheck for service-settings, platform-objects, plugin-security, plugin-approvals, plugin-sharing, plugin-email: all exit 0 under the verify lock (VERDICT command-exit 0). plugin-sharing 66 files / 1409 tests after the ja-JP / es-ES option fix.
  • pnpm check:i18n: all ten bundle sets in sync. pnpm i18n:extract: byte-identical.
  • eslint --no-inline-config on the changed TypeScript files: exit 0. pnpm lint (repository-wide) on 7e4a3272: exit 0.
Derived gate families

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on f63ad0b2 (after the origin/main merge) derived 66 commands over 32 changed paths. Each ran with its exit code captured before any pipe; --ran: 66 derived, 65 run, 1 NOT-MEASURED, 0 UNRUN.

  • 64 exited 0 on the first pass.
  • pnpm check:dual-build-cjs-loads: exit 3, PREREQUISITE NOT MET (it reads every package's dist, and only this card's closure was built). NOT MEASURED here; CI's Lint & Repo Gates runs it.
  • pnpm check:i18n-stale-fill: exit 1 on the first pass. It found sys_approval_delegation.valid_until.help in ja-JP and es-ES still holding the byte-identical English fill of the old source. Both now carry the fill of the new source (recorded by the extract), and the gate exits 0 on 07d639c3 and on the final head.

After the union two small commits landed: 07d639c3 (those two fills) and 7e4a3272 (require_mfa help, see Acceptance notes). The changed-path set grew from 32 to 36 paths; the derived gate family did not move (the same 66 commands). Re-run on 7e4a3272: pnpm check:i18n exit 0, pnpm check:i18n-stale-fill exit 0, pnpm i18n:extract byte-identical, pnpm --filter @objectstack/platform-objects test 112 files / 1544 tests, pnpm --filter @objectstack/plugin-approvals test (on 07d639c3) 112 files / 1471 tests.


Generated by Claude Code

…pages and mail delivery

Red on main: developer terms in served help, no sys_queue translations,
English mail status and test toast under zh-CN.

Claude-Session: https://claude.ai/code/session_01Utp6CbDNK83SuSb8zsRt2s
Co-authored-by: Claude <[email protected]>
…s and test-toast text

Rows 1-3: business wording in the help on permission set and position
assignments, out-of-office rules, business units, organization and user
forms (English source and zh-CN). Row 7: sys_queue and sys_queue_member join
plugin-sharing's translation bundle, with zh-CN. Row 8: the mail live-status
statement and the Send test email answer are written in the caller's
display language; settings action handlers now receive that locale.

Claude-Session: https://claude.ai/code/session_01Utp6CbDNK83SuSb8zsRt2s
Co-authored-by: Claude <[email protected]>
@github-actions github-actions Bot added size/l 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

This PR changes 6 package(s): @objectstack/platform-objects, @objectstack/plugin-approvals, @objectstack/plugin-email, @objectstack/plugin-security, @objectstack/plugin-sharing, @objectstack/service-settings, touching 41 documentable anchor(s).

25 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 2ffdb649775d20313707d88a8388275f280a0a7f.

⛔ 14 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 1 anchor(s) matched too much of the corpus to be a work list: sys_user (symbol, 49 pages)
  • 2 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 — 31 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 2ffdb649775d20313707d88a8388275f280a0a7f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 5226a73bc19c9e65edef26eb7c8e7eea695b6948 — the merge of head adc94da56e685a3ca37a2dbfcc0bdf4380b944dc into base 2ffdb649775d20313707d88a8388275f280a0a7f, 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 5226a73bc19c9e65edef26eb7c8e7eea695b6948 && git checkout 5226a73bc19c9e65edef26eb7c8e7eea695b6948
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2ffdb649775d20313707d88a8388275f280a0a7f adc94da56e685a3ca37a2dbfcc0bdf4380b944dc && git checkout -B drift-repro 2ffdb649775d20313707d88a8388275f280a0a7f && git merge --no-ff adc94da56e685a3ca37a2dbfcc0bdf4380b944dc

node scripts/docs-audit/affected-docs.mjs --json 2ffdb649775d20313707d88a8388275f280a0a7f

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2ffdb649775d20313707d88a8388275f280a0a7f → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 7e4a32728884a9a1f8da400277dfc20dd321fb03
Local-runs: none

Scope: the Clause-②: yes (widening) declaration alone (check-governed-merges --pr 30551: 0 of 36 paths governed; no packages/spec/src/** path). Read: the diff of service-settings (settings-service.types.ts, settings-service.ts, settings-routes.ts, index.ts exports) and plugin-email (email-plugin.ts, live-transport-status.ts, index.ts), the changeset, the os-dev-report 6661810672 and the head's check-runs.

① Derived judgments

  • SettingsActionHandler (exported from @objectstack/service-settings index.ts) gains an optional input member locale?: string. Widening of a published callback input: an existing handler that ignores it compiles and behaves unchanged; a handler that destructures it gets undefined when no display language is passed. Correct, and correctly declared yes (widening).
  • SettingsService.runAction gains an optional fifth parameter display: SettingsDisplayOptions = {} (the same type the write predicates and live-status providers already take). Additive; every existing call site compiles. Correct.
  • The settings action route passes requestLocaleOf(req) (Accept-Language, else ?locale), the same reader the live-status door uses; it authorizes nothing and never enters SettingsContext. Correct: a display hint, not a security input.
  • plugin-email: describeLiveMailTransport(source, locale?) gains an optional parameter, and MailDeliveryCopy / MAIL_DELIVERY_COPY / mailDeliveryCopy are new exports of live-transport-status.ts, which plugin-email's index.ts does not re-export: not on the package's published surface. No accept set moves.
  • Field help, option labels and translation bundles: text only, no field name, key or option value changes (pinned by the three new wording tests). Not a contract face.

② Semver level

patch for all six packages. An optional input member and an optional trailing parameter are additive and break no consumer; patch matches this repo's practice for additive optional members under Clause-②: yes (widening). Consistent with the changeset's declaration.

③ Boundary flags

Implemented-by: claude/project-thread-q572zu
Reviewed-by: session_01Utp6CXCS98uhsFQYk64epE

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

席位记录 · 2026-11-05T15:48Z · Head-sha 7e4a3272 · ACCEPT

维护者速读(席位按 diff 校正)

  • 改了什么:Setup 里几张表单(权限集与岗位分配、外出委托、业务单元、组织、用户)的字段说明改成管理员能读懂的话;队列、队列成员页面在中文控制台下显示中文;「邮件」设置页顶部的投递状态和「发送测试邮件」的提示按请求语言出中文或英文。
  • 为什么改:Setup: replace developer wording and hand-written JSON with fields a business administrator can use #30208 第 1、2、3、7、8 行:说明里有「fail-closed」「半开区间」「为 true 时」这类实现用语,队列页面整页英文,邮件状态与测试提示只有英文。
  • 风险与回滚:字段说明、选项文字和翻译包只改文字,不动字段名、键和取值;service-settings 的动作处理器多一个可选 locale 输入,已有处理器不受影响。回滚即 revert 本 PR。
  • 先看:plugin-email 的 live-transport-status.ts(en / zh-CN 两套文案与 mailDeliveryCopy),service-settings 的 runAction 与动作路由;三个新的措辞测试。
  • 两分钟验证:pnpm --filter @objectstack/plugin-email exec vitest run src/mail-log-provider.pin.test.ts 与 pnpm --filter @objectstack/plugin-sharing exec vitest run src/translations/queue-pages-zh-cn.test.ts,全绿。
  • 需要你做的:无。非受管面、非 BREAKING,Clause-② yes (widening) 的 TIER_DEFAULT 契约复核由席位做(PASS,记录在本 PR),技能不要求你审,席位落地。

席位意见:同意落地。locale 只是显示提示、不进 SettingsContext、不参与授权;文案按语言取、找不到回落英文,和设置页现有的状态提示读同一个请求语言。

席位核对

  1. 形态:draft→ready,目标 main,Refs #30208 (rows 1, 2, 3, 7, 8),无闭合关键词(Setup: replace developer wording and hand-written JSON with fields a business administrator can use #30208 其余行不在本 PR);作者 objectstack-fleet[bot](中继)。
  2. 前提实测:报告 6661810672 在合并基上新钉 39 条红,消融一次转红已还原;席位读 diff 核对:main 的 describeLiveMailTransport 与测试提示只有英文,SettingsActionHandler 输入没有 locale。
  3. 门禁 check-runs(钉 head 7e4a3272):52 条,37 success、15 skipped、0 失败;含报告里 NOT MEASURED 的 dual-build-cjs-loads(由 CI 跑过)。
  4. 接受的偏差:ja-JP / es-ES 只动了两处机械项(队列成员类型选项沿用同包已有译法、审批委派 valid_until 按新源重填),其余留给席位 2 的七语言轮;sys_organization.require_mfa 说明与席位 2 的 fix(plugin-auth,platform-objects): an organization's require-MFA refusal reads in the admin's language, a turn-on names the grace period, and the help says two-factor must be on (#30411) #30529 重叠,本 PR 已并入其句,后合者取本 PR 文本。正文 Verification 一句(路径 32→36)由席位代改。都接受。
  5. 范围外去向:mailDeliveryCopy 走 @objectstack/core 的 resolveLocale,它不认平台读别名,这是 Server locale resolvers ignore the platform read aliases, so a zh-TW / zh-HK reader gets Simplified Chinese even where a zh-Hant bundle exists #30538(已转 domain:spec),本 PR 只发 en / zh-CN,不受影响。Skills-docs: none。changeset patch,Clause-②: yes (widening),Metadata-protocol: none;契约复核 TIER_DEFAULT PASS(本 PR 评论 6662396863)。
  6. 落地条款:check-governed-merges --pr 30551:NOT governed,874 行 ≤ 3000。全部 check 绿后 ready + auto-merge。合并后席位在 Setup: replace developer wording and hand-written JSON with fields a business administrator can use #30208 写落地(卡保持开,等其余行),结线程。

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 5, 2026 15:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 5, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Nov 5, 2026
Conflicts: sys_organization.require_mfa help (source, en and zh-CN
bundles) against #30529. Kept this branch's administrator wording,
which already carries #30529's two-factor sentence; en confirmed by
extract (byte-identical).

Co-authored-by: Claude <[email protected]>
Claude-Session: https://claude.ai/code/session_01Utp6CbDNK83SuSb8zsRt2s
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE

Contract review

Served-tier: TIER_DEFAULT
Head-sha: adc94da5
Local-runs: none

Delta review of the merge of origin/main (5d0904cf) into the branch after the queue's MERGE_CONFLICT dequeue; the full record on 7e4a3272 is 6662396863.

① Derived judgments

② Semver level

Unchanged: patch, one changeset.

③ Boundary flags

  • The dev re-ran on adc94da5: i18n:extract byte-identical, check:i18n and check:i18n-stale-fill 0, the six packages' suites and typechecks green. No pin in plugin-auth asserts the require_mfa help text.
  • Merge commit, no rebase, no force-push.

Implemented-by: claude/project-thread-q572zu
Reviewed-by: session_01Utp6CXCS98uhsFQYk64epE

VERDICT: PASS

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/l 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