[Decision] 裁决批 #132 item 2 ② 的「a per-app bundle carrying settings was inert」被实测推翻 —— 「不做渐进弃用窗口」是否重裁,以及 Studio 那道门要不要一起收 #19601
Description
Activity
- addedpriority:p2Medium: important, M3Medium: important, M3
on Sep 21, 2026 ⚠️ CORRECTION before you rule — Q1's risk statement is wrong, and wrong in the direction that mattersdomain:specseat 2, sessionsession_01UDXER3sdqfeVYpEWZs5mZx, at 2026-09-21T15:05Z. The at-tier review of PR #19600 (111/111CONTRACT_REVIEW_TIER) re-measured the premise independently and found the implementer's correction right that it was not inert, wrong about which side won.What this card told you — that a per-app
settings「生效,而且会覆盖掉该部署的平台设置文案」 (resolved, and overwrote the platform's settings copy). ⛔ That is backwards.What was measured on the base tree, three ways.
AppPlugin.startawaitsloadTranslations, which hands each locale entry whole toi18nService.loadTranslations, andFileI18nAdapterdeep-merges into one per-locale map — so far as the card said. ButSettingsServicePlugin.startregisters akernel:readyhook that loads the platform's own settings translations into that same service, and the kernel starts every plugin (Phase 2) before it triggerskernel:ready(Phase 3).deepMergelets the later source win per leaf.AppPlugin's own comment says it outright: 「the platform bundles have not arrived yet at this point in the lifecycle」.⇒ On any key both bundles define, the platform overwrote the app's value, not the reverse. What a per-app
settingsactually did was fill gaps — it rendered only where the platform bundle had no leaf for that key and locale (the platform ships en / zh-CN / ja-JP / es-ES).So the risk you are actually deciding on Q1 is not 「deployments lose an override」. It is 「deployments lose GAP-FILLING」 — a deployment that used this to supply a locale the platform does not ship, or a key it left untranslated, will see those Settings screens fall back to the manifest's literal English strings. That is still a visible change, and it is still a real reason 「no deprecation window」 could be reconsidered; it is simply a different change from the one this card described.
⭐ Q2 gains force from the same measurement. The one door where an app-side value genuinely DOES override the platform's is the Studio item door —
replaceAuthoredTranslations, where authored wins over static on read. That is the door this PR leaves open. So the override capability the card attributed to the file door lives at the item door instead, which sharpens option C: if the item door is ruled deliberately open, the sentence saying so has to name the item door, ⛔ not the file door.⛔ Consequence for the PR, already recorded. The tree asserts the reversed sentence at nine sites, including the parse-time refusal text an author sees and the changeset that ships in the CHANGELOG. Those are customer-facing and expensive to correct after release, so the at-tier verdict is FAIL and a text-only rework is owed before this can land. ⛔ Nothing about the ruled direction changes.
⛔ This correction fixes the INPUT to your decision. It does not answer either question, and this seat is not answering them.
Generated by Claude Code
⚠️ 暂缓裁决:本卡的关键输入来自一份已作废的契约复审记录,须先由 dev 现场重测domain:spec执行席 2,sessionsession_01UDXER3sdqfeVYpEWZs5mZx,2026-09-21T15:36Z。⛔ 本条不改本卡任何标签,也不改问题本身。维护者速读
这张卡问你两件事,第一件(Q1)的前提——「
settings其实不是死键,被推翻的是哪个方向」——是我从 PR #19600 的一份契约复审记录里读来的。那份记录跑在已经退役的 fable 档上(你今天上午裁的「fable 没有了,改成 opus」落主干于 10:22:54Z,复审 14:46Z 才起跑),按「降档保险丝」的规矩整体作废。作废的意思不是「它说错了」,而是「它说的不算数」——我不能把它的读数当事实递给你。所以:
- Q1 先别裁。 它的方向输入我已经请在飞的 dev 现场重测(自己跑证伪器、自带对照),读数回来我立刻贴在本卡上。届时若与那份作废记录一致,Q1 原样成立;若不一致,我会把更正连同新读数一并呈上。
- Q2 可以照裁。 Q2 问的是 Studio 那道门要不要一起收,它不依赖被作废的那个方向读数。
整件事的台账与两张已合并 PR 的补救选项,另立在 #19603,那张卡等你回一个字母。
The mechanical part, in English for the record
fact reading CONTRACT_REVIEW_TIERmovedRETIRED-TIER→CONTRACT_REVIEW_TIER77df0f61a6(PR #19573), onmainat 2026-09-21T10:22:54Zthe review that supplied this card's Q1 correction 5762743365on #15178, posted 15:08Z, run 14:46–15:02Z, 111/111 atRETIRED-TIERgoverning rule references/contract-review.md「降档保险丝」 — 「产出裁决的每轮都须读到契约复审档位,见回退证据 ⇒ 裁决整体作废」;「父会话只可逐字采纳或整体作废」Served tier read from the reviewer's own transcript (per-assistant-row
message.model), ⛔ never a self-report and ⛔ never the argument passed.⇒ The Q1 framing on this card is a claim pending first-hand confirmation, ⛔ not a measured fact. ⛔ This seat does not withdraw the card, does not re-word the question, and does not substitute its own reading for the one that is owed — the dev in flight on #15178 has been instructed to establish the direction first-hand, with its own lit control, and to report a disagreement rather than reconcile it.
⚠️ Redacted 2026-09-21T18:2xZ by the seat. Model identifier VALUES in this comment were replaced by the namesCONTRACT_REVIEW_TIER(the tier in force) andRETIRED-TIER(the tier retired on 2026-09-21T10:22:54Z by77df0f61a6/ PR #19573), per theAGENTS.mdrule that no model identifier lands in a PR title or body, a comment, a changeset, a doc or a code comment. ⛔ No judgment, figure, coordinate or verdict was changed. Inventory and the standing rule conflict: #19615.
Generated by Claude Code
✅ 暂缓解除 —— dev 的第一手实测回来了,方向被独立确认,但我先前写给你的那句「覆盖」是错的。本卡正文已按实测重写。
domain:spec执行席 2,sessionsession_01UDXER3sdqfeVYpEWZs5mZx,2026-09-21T16:20Z。⛔ 不改标签,⛔ 不改两问的字母选项。一、我 2026-09-21T15:36Z 贴的暂缓(
5763155403)现在可以撤销当时的理由是:本卡 Q1 的输入来自一份已作废的复审记录,不能当事实递给你。现在 dev 在 PR 头
b33ea66cb3上亲手跑了证伪器,报告在 #15178 的5763721678。它不是对那份作废记录的复述 —— 作废记录没有给出下面任何一步链路,证伪器与两个亮控都是在这棵树上重新跑的。二、确认了什么,推翻了什么
确认:裁决 ② item 4 的「a per-app bundle carrying
settingswas inert」仍然是假的 —— 那个键确实解析、确实被服务。本卡因此成立,⛔ 不撤。推翻的是我自己写的下一句。我在正文里说它「overwrite the platform's own settings copy」。实测:
读数 结果 真实顺序(app = kernel Phase 2,平台 = Phase 3 的 kernel:ready),争用键mail平台值胜出 ⇒ app 那份不是 override 亮控 ①:同脚本反转加载顺序 同键变成 app 值 ⇒ 仪器对顺序敏感,主结论是事实不是夹具产物 亮控 ②:平台不翻译的 app_only_ns返回 app 值 ⇒ app 那份真被加载且在服务,空结果无处藏身 ⇒ 它是补缺者,不是覆盖者。机制是顺序:
deepMerge把叶子给后到的一份,而平台后到。三、这对两问的影响
- Q1 的天平推向 A。 可见面比我原先告诉你的小得多:两边都有的键屏幕上根本不变,只有 app 独有的键回落到 manifest 自己的英文字面量。B(补弃用窗口)的理由随之变弱。
- Q2 被加强**。** Studio 那道门走的是另一套机制 ——
replaceAuthoredTranslations写进独立图层,getTranslations以deepMerge(static, authored)服务、authored 作 source ⇒ 不论启动顺序,authored 恒胜。也就是:本 PR 关掉的门只能补缺,真能覆盖平台文案的那道门还开着。这正是 dev 倾向 B 的理由,也是我把它原样转达而不替你决定的理由。
四、连带处置,已做
- 本卡正文已重写,测量段换成上面的第一手读数,并在开头留了一行说明它被重写过与为什么;⛔ 正文里不再引用任何作废记录。
- PR feat(spec)!: split the translation bundle type —
settingsis a platform group, not a per-app one (#15178) #19600 的正文同样改了两句(「覆盖」→「补缺」,以及升级后果那句),并把原本空着的「席位意见」一行补上。 - PR feat(spec)!: split the translation bundle type —
settingsis a platform group, not a per-app one (#15178) #19600 的新 headb33ea66cb3的达档复审已在CONTRACT_REVIEW_TIER上派出,并写明引前次作废因、⛔ 不为求 PASS 重起。 - ⛔ PR feat(spec)!: split the translation bundle type —
settingsis a platform group, not a per-app one (#15178) #19600 仍是 draft、⛔ 不入队、⛔ 不挂 auto-merge —— 它同时还是 Tier H(skills/objectstack-i18n/SKILL.md命中skills/**),落地要你的那句话。
你要做的没有变:两个字母 —— Q1 选 A 还是 B;Q2 选 A、B 还是 C。
⚠️ Redacted 2026-09-21T18:2xZ by the seat. Model identifier VALUES in this comment were replaced by the namesCONTRACT_REVIEW_TIER(the tier in force) andRETIRED-TIER(the tier retired on 2026-09-21T10:22:54Z by77df0f61a6/ PR #19573), per theAGENTS.mdrule that no model identifier lands in a PR title or body, a comment, a changeset, a doc or a code comment. ⛔ No judgment, figure, coordinate or verdict was changed. Inventory and the standing rule conflict: #19615.
Generated by Claude Code
os-support-ai commented
on Sep 22, 2026 CollaboratorMore actionsRuling: batch #210 item 1 · letter A · maintainer 「210 同意」 2026-09-22T02:40Z
Director seat, summon #26 (
session_01SPwf6Kmqo1gqzCSWSuMtQM). Presented with this seat's recommendation A from facet ①; the maintainer approved batch #210 whole. Q2 of this card is ruled on #19620 (batch #210 item 2, letter B) and is not repeated here.Governing text: ruling batch #132 item 2 letter ② (5653315643 on #15178) — the DIRECTION stands unchanged; the maintainer's standing clause 「项目在创业阶段,用户也很少,短期不考虑渐进」 (2026-08-27); the ADR-0087 semantic-entry discipline (the entry records the measured reason, not the struck belief).
Ruled (Q1 = A): the ruling is kept as issued — no deprecation window. Item 4's supporting sentence 「a per-app bundle carrying
settingswas inert」 is struck as measured false; the measured fact replaces it in the record: a per-appsettingsfilled gaps only (app bundles load in kernel Phase 2, the platform's at Phase 3kernel:ready;deepMergegives the leaf to the later source, so the platform won every key both defined). The visible change on upgrade is confined to keys the platform never carried for that locale, which fall back to the manifest's English literal. PR #19600's ADR-0087 entry, conversion docblock and changeset already say this in those words (at-tier PASS 5766180686, adopted 5766199574); nothing on the branch changes on this ruling.Execution: this card closes
completedin this stroke (needs-user-decisionremoved;domain:spec/priority:p2stay). PR #19600 is Tier H (skills/objectstack-i18n/SKILL.md) andmergeable_state: dirty: thedomain:specseat 2 mergesorigin/maininto the head, re-reads the check-runs, flips ready and requests review; the maintainer's own merge lands it. ⛔ No auto-merge, no queue.
Generated by Claude Code
Ruled: 5770444804 · letter A · 2026-09-22T02:40Z — batch #210 item 1 (Q1 A; Q2 ruled on #19620 as B); closed completed
Path: P2 | none | 对向事实 — 裁决批 #132 item 2 letter ② 的一句前提被实测推翻
⏱️ Filed by the
domain:specexecution seat 2 (sessionsession_01UDXER3sdqfeVYpEWZs5mZx) at 2026-09-21T14:40Z, under the standing clause: 裁决明令的动作实施中测出对向事实 ⇒ 照字面执行,冲突立成needs-user-decision卡,该 PR ⛔ 不挂 auto-merge 留异议窗口. PR #19600 is therefore ⛔ NOT enqueued and ⛔ NOT auto-merged pending your word.⛔ The ruled DIRECTION was executed literally and is not in question. Two linked questions follow from one measurement.
The measurement — first-hand, ⛔ not adopted from any review record
Ruling ② (comment
5653315643on #15178, decision batch #132 item 2) item 4 reads: 「a per-app bundle carryingsettingswas inert, so the conversion drops the group and records a note; no deprecation window」.「Inert」 is still false —— 那个键确实生效、确实被服务。但它做的事不是覆盖:
kernel:ready),两边都定义的键mailapp_only_ns机制:
packages/core/src/kernel.ts先 Phase 2「Start plugins」再 Phase 3kernel:ready;AppPlugin.start()直接调loadTranslations(无 hook),而service-settings把自己的loadTranslations包在kernel:ready钩子里;deepMerge把叶子给后到的那一份。⇒ 应用包里的
settings是一个补缺者(gap filler):只在平台包对那个 key、那个语言没有字符串时才显示。Question 1 — does the corrected fact reopen 「no deprecation window」?
The ruled remedy is unchanged either way; what moves is how visible the removal is.
⭐ 本次重写把天平推向 A。 初版基于「覆盖」时,删键意味着所有这么用的部署屏幕文案回到平台版本;实测之后,两边都有的键根本不变,只有 app 独有的键回落到 manifest 的英文字面量。可见面比初版小得多,所以 B 的理由也比初版弱。
Question 2 — the refusal reaches one door and not the other
From the moment #19600 lands,
packages/specdeclaressettingsplatform-only on the file-authored bundle, whileTranslationItemSchema— the Studio metadata door — still accepts it.⭐ 这一问被实测加强了,不是削弱。 两道门的机制不同:Studio 那道门经
authored-translation-sync的replaceAuthoredTranslations写进一个独立图层,getTranslations以deepMerge(static, authored)服务、authored 作 source ⇒ 不论启动顺序,authored 恒胜。也就是说:本 PR 关掉的那道门只能补缺,而真能覆盖平台文案的那道门还开着。settingsleavesTranslationItemSchema, its liveness row goes, the D2 conversion learns the item shape, and the accept-set narrowing is declared a second time. — the dev's lean, strengthened by the measurement above; the file's own docblock records that retiring at one door and not the other is the asymmetry i18n: two unbridged bundle shapes — file-authoredobjects.<name>vs the runtimetranslationmetadata type'so.<object>, so translations cannot be authored in the product #3778 got wrong维护者速读
发生了什么 — 你在批 #132 裁的「把翻译包拆成平台包和应用包」已按字面实现,PR #19600 在飞。执行时实测发现裁决里的一句依据不成立:原话说应用包写
settings是「没用的」,实际上它生效。为什么还要问你 — 方向不受影响,但两处跟着动:①「不做渐进弃用窗口」当初是基于「反正没影响」决定的;现在的实测是「影响比原先说的小得多,但不是零」—— 只有平台没翻译的那些键会回落到英文字面量。②这次只堵了文件那道门;Studio 那道门还开着,而实测表明那道门才是真能覆盖平台文案的,绕一下就到。
风险与代价 — ①选 A 零成本(记录已按实测原因写好);选 B 要补窗口、延后落地,而实测把 B 的理由削弱了。②选 A 零成本、留一张后续卡;选 B 是第二次收窄加一次账本编辑,是决策不是实现;选 C 只要补一句话。
你要做的 — 两个字母即可:Q1 选 A 还是 B;Q2 选 A、B 还是 C。
Generated by Claude Code