Skip to content

fix(platform-objects): translate sys_user.role help text away from the retired Set Platform Role action - #19914

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19897-sys-user-role-help-translations
Sep 23, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-19897-sys-user-role-help-translations

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19897

Clause-②: no

What changed

The zh-CN, ja-JP and es-ES help text for objects.sys_user.fields.role.help (packages/platform-objects/src/apps/translations/{zh-CN,ja-JP,es-ES}.objects.generated.ts) still told a Setup administrator to press the "Set Platform Role" action retired in #9968. The en text had already moved on twice (#17102, then #19892/#19875) to name OS_PLATFORM_OWNER_EMAIL and the single-posture admin_full_access grant, but the three translations were never brought forward, and no i18n gate could see the drift because the leaf carries no source-hash entry.

Retranslated the leaf in all three locales as a faithful rendering of the CURRENT en text (per dispatch Zone 1), keeping code spans verbatim: OS_PLATFORM_OWNER_EMAIL, single, admin_full_access, sys_user_permission_set.

A repo-wide grep for the retired action's name/label across every locale's objects/metadata-forms bundles (en included) now returns 0 hits — nothing else still references it.

The source-hash half of the suggested fix — measured, not done, and why

The issue's suggested shape (also in Zone 2 A2) is to also give the leaf a source-hash entry so a future en change is caught. Traced and measured, and it does not hold for a leaf that carries a genuine translation:

  • collectFilledFromHashes (packages/platform-objects/src/apps/translations/source-hash.ts) — the function os i18n extract --source-hashes calls to populate <locale>.source-hashes.generated.ts — records a hash for a leaf only when value === currentSource (it's still a literal, untranslated copy of en) or previous[path] === hash(value) (it was already such a copy on a prior run). A leaf holding a real translation satisfies neither, by the mechanism's own documented design (ruling [Decision] 把 #8765 的 source-hash sidecar 扩展到生成的 i18n bundle —— #9672 写明的升级条件已满足 #12069 Option A): "a leaf someone actually TRANSLATED … gets no record and stays legacy-trusted."
  • Ran pnpm i18n:extract after writing the three translations: it rewrote nothing else (git status showed only the 3 hand-edited lines — A3 satisfied), and it did not add a hash entry for this leaf, exactly as the trace predicts.
  • A2's own ablation, run for real: mutated the sys_user.role field's description in sys-user.object.ts, regenerated en via pnpm i18n:extract, and ran pnpm check:i18n and pnpm check:i18n-stale-fill. Both report nothing for this leaf — 0 findings, 0 stale fills — both before and after this fix. Mutation and regeneration were fully reverted (git checkout HEAD --, blob hashes re-verified equal to HEAD).

So the leaf remains legacy-trusted going forward — not a regression this PR introduces, but the pre-existing, ruled status quo for every hand-translated leaf in the objects bundle (measured: 1203 in zh-CN, 1182 in ja-JP, 1173 in es-ES carry no hash and are not byte-copies of en). Extending protection to genuinely-translated generated leaves would need a new ruling in the shape of #8765/#12069, which is out of this card's scope — full measurement and a recommendation are in the dev report.

Tests

  • pnpm --filter @objectstack/platform-objects build — clean.
  • pnpm --filter @objectstack/platform-objects test — 883/883 passed.
  • pnpm --filter @objectstack/platform-objects typecheck — clean (pre-existing shrink-only test-typecheck-debt entry untouched).
  • pnpm check:i18n — OK (9/9 packages in sync).
  • pnpm check:i18n-stale-fill — OK (0 stale fills, 0 baselined).
  • Full derived gate list (node scripts/pm/dispatch-gates.mjs --commands, re-derived on the final commit, origin/main fetched first): 54 families, 53 ran clean, 1 (pnpm check:dual-build-cjs-loads) NOT MEASURED — exits 3 PREREQUISITE NOT MET, needs a full whole-workspace pnpm build unrelated to this diff's closure; CI's Build Core covers it. node scripts/check-issue-citations.mjs (the live command, since the derivation only reaches its --self-test) run by hand: exit 0.

Generated by Claude Code

…e retired Set Platform Role action

zh-CN, ja-JP and es-ES help text for objects.sys_user.fields.role.help
still told a Setup administrator to press the "Set Platform Role" action
that was retired. Translate the leaf into each locale as a faithful
rendering of the current en text: it names OS_PLATFORM_OWNER_EMAIL and
the single-posture admin_full_access grant, with code spans kept verbatim.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TEhopqrWQYBycZzyJHpAZr
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs.

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

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 0807fd8143b00ae1eebb769e33c59769ee3c1223

Head verified (PR head.sha agrees); two commits over merge-base 44ce049a8c; 4 files, +10/−3. PR #19892's en rewrite (029d8a4710) is an ancestor of the merge-base, and neither sys-user.object.ts nor en.objects.generated.ts changed between it and head, so the en translated from is the current one. CI at head, latest per name over 32 names at the last poll: 22 success, 3 skipped, 7 in progress, 0 failed. Vercel is an external commit status. No derived gate re-run locally.

① Derived judgments

(a) Faithful in all three locales. The en source (sys-user.object.ts:704 = en.objects.generated.ts:38, byte-identical) makes four claims. C1: a legacy better-auth role scalar (admin, user, …). C2: no longer written (ADR-0068 D2). C3: route 1, a VERIFIED email listed in OS_PLATFORM_OWNER_EMAIL, on every posture. C4: route 2, an unscoped admin_full_access assignment in sys_user_permission_set, on the single posture only, "also confers".

  • zh-CN: C1–C4 ✓. The single qualifier sits after the semicolon and governs only the admin_full_access clause; 已验证的邮箱 = verified email; 未限定范围 = unscoped.
  • ja-JP: C1–C4 ✓. Route 2 is its own sentence opening with single テナンシー態勢では, so the qualifier cannot leak onto route 1; 確認済みメールアドレス = verified email.
  • es-ES: C1–C4 ✓. The single qualifier is after the semicolon; correo verificado; sin ámbito = unscoped. "valor de rol" renders "role scalar" as "role value", which changes no claim.
    All four code spans are verbatim in all three locales. No translation extends the single-only route to every posture, and none drops "verified".

(b) Each locale file changes exactly one line (the help value at line 38). No key, structure or sidecar changes; none of the six hash files carries this leaf (0 hits). The retired action (Set Platform Role / 设置平台角色 / プラットフォームロールを設定 / Establecer rol de plataforma / setPlatformRole / set_platform_role / set-platform-role) has 0 hits across all 98 non-test files under a translations/ directory at head, en included. At the merge-base the same grep hits exactly the three lines this PR replaces.

(c) The refutation holds on the code. collectFilledFromHashes writes a hash only when the value equals the en source or the previous record matches its hash; a genuine translation satisfies neither (source-hash.test.ts:270 pins "records nothing for the leaves that were translated"). A hand entry is forbidden: AGENTS.md's **/translations/*.generated.ts row, and the file header says "Do not hand-edit". It would also fail: extract --check compares the companion byte-for-byte; an entry of hash(en) never fires; an entry of hash(translation) would fire forever and make withSourceFallback serve English. Fixes #19897 is right. The card's "What happens" defect is fixed and verified. The hash entry sat under "Suggested shape (⛔ not a ruling)", and the dispatch allowed the sidecar only through the tooling, which wrote nothing.

(d) Every checkable claim in the changeset and PR body is true: the en text moved twice (4215417220 for #17102, 029d8a4710 for #19892); the stale text dates from 033a34c7c4 (#11530); there is no hash entry; the retired-name grep is 0. Two wording nits, neither actionable: the changeset says the en text was "renamed" (it was rewritten), and its second paragraph is more process narrative than an upgrader needs, though every sentence is true.

② Semver level

patch on @objectstack/platform-objects, Clause-②: no: CORRECT. Three translated help strings change. No key set, accept set, export or authorable surface moves, and no ADR-0087 disposition is owed.

③ Boundary flags

Implemented-by: claude/issue-19897-sys-user-role-help-translations
Reviewed-by: session_01TEhopqrWQYBycZzyJHpAZr

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 23, 2026 18:14
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit a34c27c Sep 23, 2026
36 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-19897-sys-user-role-help-translations branch September 23, 2026 18:36
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/s tooling

Projects

None yet

1 participant