You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
platform locale table: script-subtag codes (zh-Hant-TW, zh-Hans-CN, zh-Hant-HK) are not read aliases, so a two-script bundle answers them with the first registered zh-* key #30618
Part of the #29428 family (ruling F of #29349: one platform locale table, read aliases closed). Filing gate: ① a measured gap found by the contract review of PR #30601 (card #30538, comment 6665489168, should-fix S5). ⛔ Not a claim.
Business reason. Browsers and operating systems send script-subtag codes (zh-Hant-TW, zh-Hans-CN, zh-Hant-HK). After PR #30601 the server ladder (resolveLocaleAmong) maps a requested code through platformLocaleTagOf before the base-language step, so zh-TW reaches a registered zh-Hant. PLATFORM_LOCALE_READ_ALIASES (packages/spec/src/system/platform-locales.ts :69-75 at origin/main4831d500) lists zh, zh-CN, zh-SG, zh-TW, zh-HK, zh-MO and no script-subtag spelling, so for zh-Hant-TW the table step finds nothing and the base-language and first-variant steps answer: over a bundle holding both zh-CN and zh-Hant, a Traditional-Chinese reader whose client sends zh-Hant-TW still gets whichever zh-* key was registered first.
Wanted
A decision, recorded on this card, on how the table reads script-subtag codes: add the common spellings as read aliases (zh-Hans-CN, zh-Hans-SG → zh-Hans; zh-Hant-TW, zh-Hant-HK, zh-Hant-MO → zh-Hant), or map any zh-Hans-* / zh-Hant-* to its script tag by rule. Ruling F closed the alias list, so widening it may need the maintainer's word; say which.
Dedupe: repo:objectstack-ai/objectstack is:issue is:open zh-Hant-TW → 6 hits; #30538 (the alias step itself), #30603 (skill text), #29428 (the table's tracking card) and three unrelated; none asks for script-subtag aliases. New.
Suggested-grade: p3 · a Traditional-Chinese reader on a script-subtag client gets Simplified where a zh-Hant bundle exists; the common clients send zh-TW.
Script-subtag codes (zh-Hant-TW, zh-Hans-CN, zh-Hant-HK) are not read aliases of the platform locale table. Common clients send zh-TW, so this is p3 as suggested: alias rows on the existing table, not a new key.
Claim: PM loop round 4 · 2026-11-05T21:04Z
Session: session_01L6bhgVugtCCwBs98FeR27P (seat; mode:subagent, so the dev shares this session id and is identified by the branch)
Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-30618-script-subtag-read-aliases
Worktree: objectstack-issue-30618
Domain: domain:spec
Seat: domain:spec#2
File surface:
packages/spec/src/system/platform-locales.ts: the PLATFORM_LOCALE_READ_ALIASES rows and the docblocks that describe them.
The pins:
packages/spec/src/system/platform-locales.test.ts, including the L120-124 "list is closed" case. Its two script-subtag codes move out of the unlisted set; every other code stays there.
service-settings and service-storage code. They are consumers: run their tests, don't edit them.
skills/**, docs/adr/**, .claude/**, AGENTS.md.
(Stop on breach and explain it in the report.)
Container & model: S (five alias rows and their pins), mode:subagent, model: default (no path-derived mandate; packages/spec/src/** non-test file ⇒ the seat runs a CONTRACT_REVIEW_TIER review before the queue), effort: medium
Clause-②: yes (widening)
Metadata-protocol: semantic
Responsibility: packages/spec (PLATFORM_LOCALE_READ_ALIASES names zh-TW / zh-CN but no script-subtag spelling, so platformLocaleTagOf('zh-Hant-TW') answers undefined and resolveLocaleAmong skips its table step) | PR #30601 added the table step for region codes only | a Traditional- or Simplified-Chinese reader whose browser or OS sends zh-Hant-TW / zh-Hant-HK / zh-Hans-CN, over a bundle holding both scripts
Thread-read: 6666534830
Decision the card asks for (recorded here): explicit read-alias rows. No rule-based mapping.
Triage 6666534830 routes it as "alias rows on the existing table, not a new key".
A spelling that names its script names the table tag outright. So the rows are zh-Hans-CN, zh-Hans-SG → zh-Hans and zh-Hant-TW, zh-Hant-HK, zh-Hant-MO → zh-Hant.
The list stays closed: every code is enumerated, nothing is guessed. pt-PT, de-AT, en-GB, es-419, fr-CA, it and he still answer undefined, and no region fallback is added.
"The list is closed" is the phase-1 implementation's docblock, not the ruling. Adding enumerated rows keeps that property, so no new maintainer word is needed.
Premise: holds, read at origin/mainb8929f48.
platform-locales.test.ts L121 pins zh-Hans-CN and zh-Hant-TW as answering undefined.
i18n-resolver.ts L569 runs platformLocaleTagOf(requested) as the table step.
Consumers whose answers move: service-settings/src/localization-locale-options.ts L67 and service-storage/src/storage-test-copy.ts L152. The latter already truncates zh-Hant-TW to zh-Hant, so its answer should not change. The dev measures both.
Serial constraints cleared:
{
"issue": 30618,
"status": "done",
"branch": "claude/issue-30618-script-subtag-read-aliases",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30681",
"session": "session_01L6bhgVugtCCwBs98FeR27P",
"premise_still_valid": true,
"summary": "PLATFORM_LOCALE_READ_ALIASES gains five enumerated rows: zh-Hans-CN and zh-Hans-SG read as zh-Hans; zh-Hant-TW, zh-Hant-HK and zh-Hant-MO read as zh-Hant. The list stays closed (no pattern, no region fallback; zh-Hant-US, zh-Hans-US, pt-PT, de-AT, en-GB, es-419, fr-CA, it and he still answer undefined). The docblock no longer says zh-Hans-CN is not listed. platformLocaleTagOf FROM undefined TO the table tag for the five codes (case-folded too). resolveLocaleAmong / resolveBundleLocale / core resolveLocale / resolveOfferedLocale: zh-Hant-TW/HK/MO over [en, zh-CN, zh-Hant] zh-CN TO zh-Hant, and over [en, zh, zh-Hant] zh TO zh-Hant; zh-Hans-CN/SG over [en, zh-Hant, zh-CN] zh-Hant TO zh-CN; the other order and every unlisted code are unchanged. Consumers measured, none edited: service-settings localization-locale-options.ts L67 MOVES (localeSelfName names the five codes from the table, e.g. zh-Hant-TW 中文(繁體,台灣) TO 繁體中文; a stored zh-Hant-TW over offered [en, zh-CN, zh-Hant] used to replace the 简体中文 option and now sits on 繁體中文; accepted set unchanged); service-storage storage-test-copy.ts L152 does NOT move (14 codes probed); the only other direct caller is the spec ladder itself. After the main merge, service-storage's shipped object translations (zh-CN before zh-Hant) now serve a zh-Hant-TW reader zh-Hant (row-less control zh-Hant-US still gets zh-CN). Declarations measured as claimed: Clause-② yes (widening), Metadata-protocol semantic, @objectstack/spec minor (core moves only a test file). Conflict noted, not chosen silently: os-dev rule 3 says a published sentence this change makes false must be fixed, but the dispatch file surface excludes content/docs; content/docs/protocol/kernel/i18n-standard.mdx's read-alias table is that sentence, so it is the PR's Skills-docs follow-up owed rather than an edit.",
"tests": "Head e731b654 (origin/main 47c457b2 merged; delta vs main = the 5 files, +93/-15), after a full pnpm build (118/118). All exit 0: spec 817 files / 25798 tests + 1 todo (platform-locales.test.ts + i18n-resolver.test.ts 2 / 575); core 136 / 3112 (fallbacks.test.ts 133); service-settings 69 / 1178; service-storage 73 / 1353. Typecheck spec 0, core 0 (test layer via check:test-typecheck under tsconfig.test.json; tsc --listFiles lists the 2 spec test files and core fallbacks.test.ts; debt ledgers held). Ablation (run at eadbe6e8, platform-locales.ts blob baefd871 = merged head's): attempt 1's mutation landed but its spec build never got the lock (VERDICT queue-timeout exit 99), so dist kept the rows (preflight --absent exit 1, core stayed 133 green): dist half void, not reported as a reading. Attempt 2: ablation-replace.mjs --delete of the five rows, anchor 1 TO 0, blob baefd871 TO be1e0adf; spec rebuilt exit 0; ablation-dist-preflight --absent for both markers exit 0 (absent from 592 built files); spec pins 20 failed / 555 passed (575); core fallbacks 16 failed / 117 passed (133); each code reds in the registration order where the other script comes first; service-settings 1178 and service-storage 1353 stayed green (no consumer test pins these answers). Restore: git checkout HEAD -- path; blob after restore baefd8712cec92d2a22aac2a8f3fd909a62635a5 == HEAD blob; git diff HEAD empty; porcelain empty; rebuilt; markers present in 2 built files; spec 575, core 133, settings 1178, storage 1353 green.",
"gates": "Local, at e731b654: dispatch-gates --commands --repo objectstack-ai/objectstack derived 79; all 79 exit 0, codes captured before any pipe (check:dual-build-cjs-loads first exit 3 PREREQUISITE NOT MET with 61 packages unbuilt, re-run after the full build exit 0). --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. spec build + check:generated exit 0 (14 artifacts up to date, nothing regenerated). eslint --no-inline-config on the 4 changed files exit 0. check:dev-prereqs exit 0. CI on the PR head read once after the PR opened (reading time below this block): 22 check-runs, 3 skipped, 19 in_progress; nothing waited on.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls, PR #30681, draft, no assignee or label leg); POST /repos/objectstack-ai/objectstack/issues/30618/comments (this report, post-stamped.mjs). Plus 3 git pushes (empty-branch probe, eadbe6e8, e731b654).",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: domain:spec#2 seat (the PR's Skills-docs follow-up owed line) · noted, not filed — content/docs/protocol/kernel/i18n-standard.mdx L166-182 lists the read aliases as ten rows and says any other code answers undefined, false for the five rows this PR adds; L185-192 (the ladder alone cannot tell the two Chinese scripts apart, answered by key order) has been false since PR #30601. Outside this card's file surface. Dedupe words: i18n-standard read aliases, zh-Hant-TW docs, platform locale table page",
"carrier: none · noted, not filed — measured consequence of the decision of record (closed list): a script-subtag code with another region (zh-Hant-US, zh-Hans-US) has no row and keeps the old path; over service-storage's shipped bundle it reaches zh-CN for either script. Not re-decided here"
]
}
CI check-runs in the gates field were read at 2026-11-05T22:15Z.
File surface (added): content/docs/protocol/kernel/i18n-standard.mdx, the Read aliases section only (the alias table and the two paragraphs under it, L166-192 at origin/main).
Reason: the dev's report 6670989840 names two sentences there that this card's change makes false, or that were already false:
A published sentence the change makes false is fixed in the same PR, so this goes in PR #30681 rather than a follow-up card. No open PR touches this page (38 open PR file lists read at 2026-11-05T22:20Z). The declarations stand: Clause-②: yes (widening) / Metadata-protocol: semantic. The PR's Skills-docs: line is restated by the dev once the page is fixed. The rest of the claim stands as posted.
{
"issue": 30618,
"round": "patch (seat amendment 6671045459: the docs page; review 6671200273 S1: the key side)",
"status": "done",
"branch": "claude/issue-30618-script-subtag-read-aliases",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30681",
"head": "d8713f3f32b323798a6416046bf4704ed6a9d82b",
"session": "session_01L6bhgVugtCCwBs98FeR27P",
"premise_still_valid": true,
"summary": "Two commits on e731b654. (1) 6a1d4627 docs: the Read aliases section of content/docs/protocol/kernel/i18n-standard.mdx (L166-207), nothing outside it. FROM: the table was headed 'Stored code' and listed ten rows; 'any other code answers undefined' was false for the five new rows; the ladder paragraph said the ladder cannot tell the two Chinese scripts apart and answers zh / zh-CN by key order (false since PR #30601's table step). TO: the table is headed 'Code' and lists zh, zh-CN, zh-SG, zh-Hans-CN, zh-Hans-SG -> zh-Hans and zh-TW, zh-HK, zh-MO, zh-Hant-TW, zh-Hant-HK, zh-Hant-MO -> zh-Hant; the intro names the script-subtag spellings browsers and operating systems send; the closed-list sentence is true again (read row by row, never as a pattern, so zh-Hant-US answers undefined too); the ladder paragraph names resolveLocaleAmong (run by resolveBundleLocale and core resolveLocale) and its five steps, says the table step takes the key spelled as the table tag else the first key the table maps to it, and that a two-script bundle answers zh, zh-CN, zh-Hans-CN Simplified and zh-TW, zh-Hant-TW Traditional in any order; a new paragraph names the two requests registration order still decides (zh-Hant-US, no row: zh-CN over [en, zh-CN, zh-Hant], zh-Hant with zh-Hant first; zh-TW over [en, zh-CN]: zh-CN). 41 claims probed against spec source at d8713f3f, all hold. (2) d8713f3f S1: the key-side move pinned in core fallbacks.test.ts's shared list (nine rows, run on resolveLocale and resolveBundleLocale) and in spec i18n-resolver.test.ts (two assertions in the bare-zh case, one new case), both registration orders; one changeset sentence says the table step maps each registered key through the table too. FROM measured on main a2437b56 (its i18n-resolver.ts and platform-locales.ts unchanged since merge base 47c457b2) first, TO at d8713f3f, identical through resolveLocaleAmong, resolveBundleLocale and core resolveLocale. The seat's three rows hold as measured: zh-TW over [en, zh-CN, zh-Hant-TW] zh-CN TO zh-Hant-TW; zh-Hant-TW over [en, zh, zh-Hant-HK] zh TO zh-Hant-HK (in both registration orders); control zh-Hant-TW over [en, zh-CN] zh-CN, unchanged. Also moved: zh-Hant over [en, zh-CN, zh-Hant-TW] zh-CN TO zh-Hant-TW; zh-CN over [en, zh-Hant, zh-Hans-CN] zh-Hant TO zh-Hans-CN. Unchanged (the script-subtag key already came first): zh-TW and zh-Hant over [en, zh-Hant-TW, zh-CN] zh-Hant-TW; zh-CN over [en, zh-Hans-CN, zh-Hant] zh-Hans-CN. platform-locales.ts (blob baefd871) and platform-locales.test.ts (blob 410cf43e) are byte-identical to e731b654. The PR body was not PATCHed: the full new body is in the seat's scratchpad as pr-body-r2.md (Skills-docs: none plus the measurement, the docs page and S1 lines in Acceptance notes, the key-side FROM -> TO table, the signed footer).",
"tests": "At d8713f3f, all exit 0: spec 817 files / 25799 tests + 1 todo (platform-locales.test.ts + i18n-resolver.test.ts 2 / 576); core 136 / 3130 (fallbacks.test.ts 151); typecheck spec 0, core 0 (tests included via check:test-typecheck). service-settings 69 / 1178 and service-storage 73 / 1353 carried from e731b654, code files byte-identical. Ablation at d8713f3f: ablation-replace.mjs --delete of the five rows, anchor 1 TO 0, blob baefd871 TO be1e0adf; spec rebuilt (VERDICT command-exit 0); ablation-dist-preflight --absent exit 0 for both markers. Spec pins 21 failed / 555 passed (576): round one's 20 plus the new key-side case (first failing assertion zh-TW over [en, zh-CN, zh-Hant-TW] received zh-CN). The two zh-Hant-HK assertions added to the bare-zh case follow an assertion already red there, so vitest stops before them; core fails those rows one by one. Core fallbacks 26 failed / 125 passed (151): round one's 16 plus 10 new, the five moving key-side rows on each of resolveLocale and resolveBundleLocale; the three unchanged-order rows and the control stayed green. The key-side probe on the mutated tree answered exactly main's FROM in all nine rows. Restore: git checkout HEAD -- path; blob baefd8712cec92d2a22aac2a8f3fd909a62635a5 == HEAD blob; git diff HEAD empty; porcelain empty; rebuilt; preflight present exit 0; spec 576 and core 151 green; probe equals TO. The consumer suites in both legs failed to resolve workspace package entries (@objectstack/metadata-core), because only spec dist was on disk: a setup failure, the same in both legs, not a reading. Consumer readings are carried from round one (eadbe6e8, same platform-locales.ts blob).",
"gates": "Local, at d8713f3f: dispatch-gates --commands --repo objectstack-ai/objectstack derived 102 (79 at e731b654; the 23 added came with the docs page). 99 exit 0 on the first run, codes captured before any pipe. Three first answered exit 3 PREREQUISITE NOT MET: check:skill-examples (re-run after building the @objectstack/client-react and @objectstack/client closure: exit 0, 283 prose examples type-check) and check:lean-entry-closure (re-run after building the @objectstack/objectql closure: exit 0); check:dual-build-cjs-loads needs every package built and no full build ran this round, so it is carried from e731b654 (exit 0), code files byte-identical. --ran with the codes measured here: 102 derived, 101 run, 1 NOT-MEASURED (dual-build-cjs-loads), 0 UNRUN; with the carried reading: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN. The derivation warned STALE TREE (at least 7 commits behind origin/main, 8 derivation files changed); re-derived from origin/main badf24df with the branch merged in (a scratch, uncommitted, conflict-free merge in a separate worktree): the same 102 commands. spec check:generated exit 0 (14 artifacts). eslint --no-inline-config on platform-locales.ts, platform-locales.test.ts, i18n-resolver.test.ts and fallbacks.test.ts exit 0. check:dev-prereqs (local-only, needs every package built) carried from e731b654 (exit 0), code files byte-identical; at this head it exits 1 naming unbuilt dist folders, and its derived --self-test exits 0. Built this round, no full build: spec (by the ablation) and the dependency closures of core, of lint and formula, of client-react and client, and of objectql; each VERDICT command-exit 0. CI on d8713f3f read once (reading time below this block): 65 check-runs, 57 success, 8 skipped, 0 failed.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/30618/comments (this report, post-stamped.mjs). Plus 2 git pushes (6a1d4627, d8713f3f). No PR body PATCH, no ready-for-review, no automerge.",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · noted, not filed — the round-one Skills-docs follow-up (i18n-standard.mdx read aliases) is closed by 6a1d4627; pr-body-r2.md says so for the seat's PATCH",
"carrier: none · noted, not filed — measured consequence of the decision of record (closed list), unchanged: zh-Hant-US / zh-Hans-US have no row and keep the old path; the docs page now says so"
]
}
CI check-runs in the gates field were read at 2026-11-05T23:14Z.
State: the card is closed completed by Fixes #30618, and pm:dispatched is removed in this stroke. The review's one should-fix landed in the patch round; the dev's one out-of-scope observation (zh-Hant-US has no row) was dropped in the ACCEPT (6672140814 item 5) as the closed-list decision of record. #30619 (seat 3, i18n-resolver.test.ts) is the later lander of the two and rebases. Nothing else is owed.
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 ·
domain:spec· 2026-11-05T18:56Z⛔ Not a claim.
zh-Hant-TW,zh-Hans-CN,zh-Hant-HK) are not read aliases of the platform locale table. Common clients sendzh-TW, so this is p3 as suggested: alias rows on the existing table, not a new key.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
Claim: PM loop round 4 · 2026-11-05T21:04Z
Session:
session_01L6bhgVugtCCwBs98FeR27P(seat;mode:subagent, so the dev shares this session id and is identified by the branch)Account:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30618-script-subtag-read-aliasesWorktree:
objectstack-issue-30618Domain:
domain:specSeat:
domain:spec#2File surface:
packages/spec/src/system/platform-locales.ts: thePLATFORM_LOCALE_READ_ALIASESrows and the docblocks that describe them.packages/spec/src/system/platform-locales.test.ts, including the L120-124 "list is closed" case. Its two script-subtag codes move out of the unlisted set; every other code stays there.packages/spec/src/system/i18n-resolver.test.tsandpackages/core/src/fallbacks/fallbacks.test.ts: both registration orders against a two-script bundle, on the shared case list PR fix(spec,core): resolve locales through the platform table's read aliases, so a zh-TW / zh-HK reader gets zh-Hant #30601 added.⛔ Not in scope:
i18n-resolver.tslogic (spec(i18n-resolver): resolveBundleLocale's exact fast path and pickData's exact read answer an Object.prototype member name (constructor) over a plain-object bundle #30619 is a separate card).ui/**(the Console picker is i18n phase 2 (Console UI): ui/packages/i18n reads PLATFORM_LOCALES, adds zh-Hant, and moves pack keys to table tags #30511 / PR feat(i18n)!: the Console's language packs follow the platform locale table, keyed by its tags, and Traditional Chinese (zh-Hant) ships #30595).service-settingsandservice-storagecode. They are consumers: run their tests, don't edit them.skills/**,docs/adr/**,.claude/**,AGENTS.md.(Stop on breach and explain it in the report.)
Container & model:
S(five alias rows and their pins),mode:subagent,model: default(no path-derived mandate;packages/spec/src/**non-test file ⇒ the seat runs a CONTRACT_REVIEW_TIER review before the queue),effort: mediumClause-②: yes (widening)
Metadata-protocol: semantic
Responsibility:
packages/spec(PLATFORM_LOCALE_READ_ALIASESnameszh-TW/zh-CNbut no script-subtag spelling, soplatformLocaleTagOf('zh-Hant-TW')answersundefinedandresolveLocaleAmongskips its table step) | PR #30601 added the table step for region codes only | a Traditional- or Simplified-Chinese reader whose browser or OS sendszh-Hant-TW/zh-Hant-HK/zh-Hans-CN, over a bundle holding both scriptsThread-read: 6666534830
Decision the card asks for (recorded here): explicit read-alias rows. No rule-based mapping.
zh-Hans/zh-Hant),不按区域」, and the existingzh/zh-CN/zh-TW… 「等写法作为读入别名保留」.zh-Hans-CN,zh-Hans-SG→zh-Hansandzh-Hant-TW,zh-Hant-HK,zh-Hant-MO→zh-Hant.pt-PT,de-AT,en-GB,es-419,fr-CA,itandhestill answerundefined, and no region fallback is added.Premise: holds, read at
origin/mainb8929f48.platform-locales.tslists ten aliases:zh,zh-CN,zh-SG,zh-TW,zh-HK,zh-MO,ja-JP,es-ES,pt,en-US.zh-Hans-CNis not listed".platform-locales.test.tsL121 pinszh-Hans-CNandzh-Hant-TWas answeringundefined.i18n-resolver.tsL569 runsplatformLocaleTagOf(requested)as the table step.service-settings/src/localization-locale-options.tsL67 andservice-storage/src/storage-test-copy.tsL152. The latter already truncateszh-Hant-TWtozh-Hant, so its answer should not change. The dev measures both.Serial constraints cleared:
platform-locales.ts,i18n-resolver.ts,memory-i18n.tsor the three test files (file lists read at 2026-11-05T21:04Z).i18n-resolver.ts's exact fast path and may touchi18n-resolver.test.ts. Whichever lands second rebases.domain:ui#5) follows the same table in the Console. It is not a file overlap.objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
os-dev-report
{ "issue": 30618, "status": "done", "branch": "claude/issue-30618-script-subtag-read-aliases", "pr": "https://github.com/objectstack-ai/objectstack/pull/30681", "session": "session_01L6bhgVugtCCwBs98FeR27P", "premise_still_valid": true, "summary": "PLATFORM_LOCALE_READ_ALIASES gains five enumerated rows: zh-Hans-CN and zh-Hans-SG read as zh-Hans; zh-Hant-TW, zh-Hant-HK and zh-Hant-MO read as zh-Hant. The list stays closed (no pattern, no region fallback; zh-Hant-US, zh-Hans-US, pt-PT, de-AT, en-GB, es-419, fr-CA, it and he still answer undefined). The docblock no longer says zh-Hans-CN is not listed. platformLocaleTagOf FROM undefined TO the table tag for the five codes (case-folded too). resolveLocaleAmong / resolveBundleLocale / core resolveLocale / resolveOfferedLocale: zh-Hant-TW/HK/MO over [en, zh-CN, zh-Hant] zh-CN TO zh-Hant, and over [en, zh, zh-Hant] zh TO zh-Hant; zh-Hans-CN/SG over [en, zh-Hant, zh-CN] zh-Hant TO zh-CN; the other order and every unlisted code are unchanged. Consumers measured, none edited: service-settings localization-locale-options.ts L67 MOVES (localeSelfName names the five codes from the table, e.g. zh-Hant-TW 中文(繁體,台灣) TO 繁體中文; a stored zh-Hant-TW over offered [en, zh-CN, zh-Hant] used to replace the 简体中文 option and now sits on 繁體中文; accepted set unchanged); service-storage storage-test-copy.ts L152 does NOT move (14 codes probed); the only other direct caller is the spec ladder itself. After the main merge, service-storage's shipped object translations (zh-CN before zh-Hant) now serve a zh-Hant-TW reader zh-Hant (row-less control zh-Hant-US still gets zh-CN). Declarations measured as claimed: Clause-② yes (widening), Metadata-protocol semantic, @objectstack/spec minor (core moves only a test file). Conflict noted, not chosen silently: os-dev rule 3 says a published sentence this change makes false must be fixed, but the dispatch file surface excludes content/docs; content/docs/protocol/kernel/i18n-standard.mdx's read-alias table is that sentence, so it is the PR's Skills-docs follow-up owed rather than an edit.", "tests": "Head e731b654 (origin/main 47c457b2 merged; delta vs main = the 5 files, +93/-15), after a full pnpm build (118/118). All exit 0: spec 817 files / 25798 tests + 1 todo (platform-locales.test.ts + i18n-resolver.test.ts 2 / 575); core 136 / 3112 (fallbacks.test.ts 133); service-settings 69 / 1178; service-storage 73 / 1353. Typecheck spec 0, core 0 (test layer via check:test-typecheck under tsconfig.test.json; tsc --listFiles lists the 2 spec test files and core fallbacks.test.ts; debt ledgers held). Ablation (run at eadbe6e8, platform-locales.ts blob baefd871 = merged head's): attempt 1's mutation landed but its spec build never got the lock (VERDICT queue-timeout exit 99), so dist kept the rows (preflight --absent exit 1, core stayed 133 green): dist half void, not reported as a reading. Attempt 2: ablation-replace.mjs --delete of the five rows, anchor 1 TO 0, blob baefd871 TO be1e0adf; spec rebuilt exit 0; ablation-dist-preflight --absent for both markers exit 0 (absent from 592 built files); spec pins 20 failed / 555 passed (575); core fallbacks 16 failed / 117 passed (133); each code reds in the registration order where the other script comes first; service-settings 1178 and service-storage 1353 stayed green (no consumer test pins these answers). Restore: git checkout HEAD -- path; blob after restore baefd8712cec92d2a22aac2a8f3fd909a62635a5 == HEAD blob; git diff HEAD empty; porcelain empty; rebuilt; markers present in 2 built files; spec 575, core 133, settings 1178, storage 1353 green.", "gates": "Local, at e731b654: dispatch-gates --commands --repo objectstack-ai/objectstack derived 79; all 79 exit 0, codes captured before any pipe (check:dual-build-cjs-loads first exit 3 PREREQUISITE NOT MET with 61 packages unbuilt, re-run after the full build exit 0). --ran: 79 derived, 79 run, 0 NOT-MEASURED, 0 UNRUN. spec build + check:generated exit 0 (14 artifacts up to date, nothing regenerated). eslint --no-inline-config on the 4 changed files exit 0. check:dev-prereqs exit 0. CI on the PR head read once after the PR opened (reading time below this block): 22 check-runs, 3 skipped, 19 in_progress; nothing waited on.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (relay pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls, PR #30681, draft, no assignee or label leg); POST /repos/objectstack-ai/objectstack/issues/30618/comments (this report, post-stamped.mjs). Plus 3 git pushes (empty-branch probe, eadbe6e8, e731b654).", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: domain:spec#2 seat (the PR's Skills-docs follow-up owed line) · noted, not filed — content/docs/protocol/kernel/i18n-standard.mdx L166-182 lists the read aliases as ten rows and says any other code answers undefined, false for the five rows this PR adds; L185-192 (the ladder alone cannot tell the two Chinese scripts apart, answered by key order) has been false since PR #30601. Outside this card's file surface. Dedupe words: i18n-standard read aliases, zh-Hant-TW docs, platform locale table page", "carrier: none · noted, not filed — measured consequence of the decision of record (closed list): a script-subtag code with another region (zh-Hant-US, zh-Hans-US) has no row and keeps the old path; over service-storage's shipped bundle it reaches zh-CN for either script. Not re-decided here" ] }CI check-runs in the
gatesfield were read at 2026-11-05T22:15Z.objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
席位核对 · Amendment · 2026-11-05T22:20Z · claim 6669501005 file surface widened
File surface (added):
content/docs/protocol/kernel/i18n-standard.mdx, the Read aliases section only (the alias table and the two paragraphs under it, L166-192 atorigin/main).Reason: the dev's report 6670989840 names two sentences there that this card's change makes false, or that were already false:
undefined". With the five rows of PR fix(spec/system): read the script-subtag Chinese spellings (zh-Hant-TW, zh-Hans-CN, …) as platform locale read aliases #30681,zh-Hans-CN,zh-Hans-SG,zh-Hant-TW,zh-Hant-HKandzh-Hant-MOanswer a table tag, so the page would contradict the code the day this lands.resolveLocaleAmong(packages/spec/src/system/i18n-resolver.tsL569 atorigin/main).A published sentence the change makes false is fixed in the same PR, so this goes in PR #30681 rather than a follow-up card. No open PR touches this page (38 open PR file lists read at 2026-11-05T22:20Z). The declarations stand:
Clause-②: yes (widening)/Metadata-protocol: semantic. The PR'sSkills-docs:line is restated by the dev once the page is fixed. The rest of the claim stands as posted.Generated by Claude Code
test(spec/system): pin the key side of the table step for script-subt…
objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
os-dev-report
{ "issue": 30618, "round": "patch (seat amendment 6671045459: the docs page; review 6671200273 S1: the key side)", "status": "done", "branch": "claude/issue-30618-script-subtag-read-aliases", "pr": "https://github.com/objectstack-ai/objectstack/pull/30681", "head": "d8713f3f32b323798a6416046bf4704ed6a9d82b", "session": "session_01L6bhgVugtCCwBs98FeR27P", "premise_still_valid": true, "summary": "Two commits on e731b654. (1) 6a1d4627 docs: the Read aliases section of content/docs/protocol/kernel/i18n-standard.mdx (L166-207), nothing outside it. FROM: the table was headed 'Stored code' and listed ten rows; 'any other code answers undefined' was false for the five new rows; the ladder paragraph said the ladder cannot tell the two Chinese scripts apart and answers zh / zh-CN by key order (false since PR #30601's table step). TO: the table is headed 'Code' and lists zh, zh-CN, zh-SG, zh-Hans-CN, zh-Hans-SG -> zh-Hans and zh-TW, zh-HK, zh-MO, zh-Hant-TW, zh-Hant-HK, zh-Hant-MO -> zh-Hant; the intro names the script-subtag spellings browsers and operating systems send; the closed-list sentence is true again (read row by row, never as a pattern, so zh-Hant-US answers undefined too); the ladder paragraph names resolveLocaleAmong (run by resolveBundleLocale and core resolveLocale) and its five steps, says the table step takes the key spelled as the table tag else the first key the table maps to it, and that a two-script bundle answers zh, zh-CN, zh-Hans-CN Simplified and zh-TW, zh-Hant-TW Traditional in any order; a new paragraph names the two requests registration order still decides (zh-Hant-US, no row: zh-CN over [en, zh-CN, zh-Hant], zh-Hant with zh-Hant first; zh-TW over [en, zh-CN]: zh-CN). 41 claims probed against spec source at d8713f3f, all hold. (2) d8713f3f S1: the key-side move pinned in core fallbacks.test.ts's shared list (nine rows, run on resolveLocale and resolveBundleLocale) and in spec i18n-resolver.test.ts (two assertions in the bare-zh case, one new case), both registration orders; one changeset sentence says the table step maps each registered key through the table too. FROM measured on main a2437b56 (its i18n-resolver.ts and platform-locales.ts unchanged since merge base 47c457b2) first, TO at d8713f3f, identical through resolveLocaleAmong, resolveBundleLocale and core resolveLocale. The seat's three rows hold as measured: zh-TW over [en, zh-CN, zh-Hant-TW] zh-CN TO zh-Hant-TW; zh-Hant-TW over [en, zh, zh-Hant-HK] zh TO zh-Hant-HK (in both registration orders); control zh-Hant-TW over [en, zh-CN] zh-CN, unchanged. Also moved: zh-Hant over [en, zh-CN, zh-Hant-TW] zh-CN TO zh-Hant-TW; zh-CN over [en, zh-Hant, zh-Hans-CN] zh-Hant TO zh-Hans-CN. Unchanged (the script-subtag key already came first): zh-TW and zh-Hant over [en, zh-Hant-TW, zh-CN] zh-Hant-TW; zh-CN over [en, zh-Hans-CN, zh-Hant] zh-Hans-CN. platform-locales.ts (blob baefd871) and platform-locales.test.ts (blob 410cf43e) are byte-identical to e731b654. The PR body was not PATCHed: the full new body is in the seat's scratchpad as pr-body-r2.md (Skills-docs: none plus the measurement, the docs page and S1 lines in Acceptance notes, the key-side FROM -> TO table, the signed footer).", "tests": "At d8713f3f, all exit 0: spec 817 files / 25799 tests + 1 todo (platform-locales.test.ts + i18n-resolver.test.ts 2 / 576); core 136 / 3130 (fallbacks.test.ts 151); typecheck spec 0, core 0 (tests included via check:test-typecheck). service-settings 69 / 1178 and service-storage 73 / 1353 carried from e731b654, code files byte-identical. Ablation at d8713f3f: ablation-replace.mjs --delete of the five rows, anchor 1 TO 0, blob baefd871 TO be1e0adf; spec rebuilt (VERDICT command-exit 0); ablation-dist-preflight --absent exit 0 for both markers. Spec pins 21 failed / 555 passed (576): round one's 20 plus the new key-side case (first failing assertion zh-TW over [en, zh-CN, zh-Hant-TW] received zh-CN). The two zh-Hant-HK assertions added to the bare-zh case follow an assertion already red there, so vitest stops before them; core fails those rows one by one. Core fallbacks 26 failed / 125 passed (151): round one's 16 plus 10 new, the five moving key-side rows on each of resolveLocale and resolveBundleLocale; the three unchanged-order rows and the control stayed green. The key-side probe on the mutated tree answered exactly main's FROM in all nine rows. Restore: git checkout HEAD -- path; blob baefd8712cec92d2a22aac2a8f3fd909a62635a5 == HEAD blob; git diff HEAD empty; porcelain empty; rebuilt; preflight present exit 0; spec 576 and core 151 green; probe equals TO. The consumer suites in both legs failed to resolve workspace package entries (@objectstack/metadata-core), because only spec dist was on disk: a setup failure, the same in both legs, not a reading. Consumer readings are carried from round one (eadbe6e8, same platform-locales.ts blob).", "gates": "Local, at d8713f3f: dispatch-gates --commands --repo objectstack-ai/objectstack derived 102 (79 at e731b654; the 23 added came with the docs page). 99 exit 0 on the first run, codes captured before any pipe. Three first answered exit 3 PREREQUISITE NOT MET: check:skill-examples (re-run after building the @objectstack/client-react and @objectstack/client closure: exit 0, 283 prose examples type-check) and check:lean-entry-closure (re-run after building the @objectstack/objectql closure: exit 0); check:dual-build-cjs-loads needs every package built and no full build ran this round, so it is carried from e731b654 (exit 0), code files byte-identical. --ran with the codes measured here: 102 derived, 101 run, 1 NOT-MEASURED (dual-build-cjs-loads), 0 UNRUN; with the carried reading: 102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN. The derivation warned STALE TREE (at least 7 commits behind origin/main, 8 derivation files changed); re-derived from origin/main badf24df with the branch merged in (a scratch, uncommitted, conflict-free merge in a separate worktree): the same 102 commands. spec check:generated exit 0 (14 artifacts). eslint --no-inline-config on platform-locales.ts, platform-locales.test.ts, i18n-resolver.test.ts and fallbacks.test.ts exit 0. check:dev-prereqs (local-only, needs every package built) carried from e731b654 (exit 0), code files byte-identical; at this head it exits 1 naming unbuilt dist folders, and its derived --self-test exits 0. Built this round, no full build: spec (by the ablation) and the dependency closures of core, of lint and formula, of client-react and client, and of objectql; each VERDICT command-exit 0. CI on d8713f3f read once (reading time below this block): 65 check-runs, 57 success, 8 skipped, 0 failed.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "1 — POST /repos/objectstack-ai/objectstack/issues/30618/comments (this report, post-stamped.mjs). Plus 2 git pushes (6a1d4627, d8713f3f). No PR body PATCH, no ready-for-review, no automerge.", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · noted, not filed — the round-one Skills-docs follow-up (i18n-standard.mdx read aliases) is closed by 6a1d4627; pr-body-r2.md says so for the seat's PATCH", "carrier: none · noted, not filed — measured consequence of the decision of record (closed list), unchanged: zh-Hant-US / zh-Hans-US have no row and keep the old path; the docs page now says so" ] }CI check-runs in the
gatesfield were read at 2026-11-05T23:14Z.objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
ACCEPT → PR #30681 comment 6672140814 · head
d8713f3f32b323798a6416046bf4704ed6a9d82b· contract review PASS 6671200273 (e731b654) + delta PASS 6672120777 (d8713f3f) · 2026-11-05T23:23ZGenerated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
Landed · PR #30681 · merge
4564d6fa5b79764676d554de1cedd5946ca0f120· 2026-11-05T23:48ZGET /repos/objectstack-ai/objectstack/issues/30681/timelineadded_to_merge_queue23:26:00Z →removed_from_merge_queue23:47:38Z,merged23:47:39Zorigin/mainby content (alias row)git grep -n -F "'zh-Hant-TW': 'zh-Hant'" origin/main -- packages/spec/src/system/platform-locales.tsorigin/mainby content (docs page)git grep -c -F "zh-Hant-TW" origin/main -- content/docs/protocol/kernel/i18n-standard.mdxState: the card is closed
completedbyFixes #30618, andpm:dispatchedis removed in this stroke. The review's one should-fix landed in the patch round; the dev's one out-of-scope observation (zh-Hant-UShas no row) was dropped in the ACCEPT (6672140814 item 5) as the closed-list decision of record. #30619 (seat 3,i18n-resolver.test.ts) is the later lander of the two and rebases. Nothing else is owed.Generated by Claude Code