Skip to content

[Decision] 裁决批 #132 item 2 ② 的「a per-app bundle carrying settings was inert」被实测推翻 —— 「不做渐进弃用窗口」是否重裁,以及 Studio 那道门要不要一起收 #19601

Description

@os-warren

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:spec execution seat 2 (session session_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.

⚠️ 本正文于 2026-09-21T16:20Z 按第一手实测重写过一次。 初版的测量段说应用包的 settings 会覆盖平台文案 —— 那是错的,来源是一份后来因跑在已退役档位而整体作废的复审记录(台账 #19603)。现在的测量段来自 dev 在 PR 头 b33ea66cb3 上亲手跑的证伪器与两个亮控,⛔ 不再引用任何作废记录。更正说明见本卡评论。

The measurement — first-hand, ⛔ not adopted from any review record

Ruling ② (comment 5653315643 on #15178, decision batch #132 item 2) item 4 reads: 「a per-app bundle carrying settings was inert, so the conversion drops the group and records a note; no deprecation window」.

「Inert」 is still false —— 那个键确实生效、确实被服务。但它做的事不是覆盖:

读数 结果
主结论 —— 真实加载顺序(app 在 kernel Phase 2、平台在 Phase 3 的 kernel:ready),两边都定义的键 mail 平台的值胜出 ⇒ app 那份 不是 override
亮控 ①(仪器对顺序敏感) —— 同一脚本把顺序反过来 同一个键变成 app 的值 ⇒ 主结论是关于顺序的事实,不是夹具产物
亮控 ②(仪器活着) —— 平台不翻译的命名空间 app_only_ns 返回 app 的值(不是 manifest 字面量)⇒ app 那份真的被加载、真的在服务,空结果无处藏身
删掉之后本 PR 实际发生什么 两边都有的键:屏幕上不变;只有 app 有的键:回落到 manifest 自己的英文字面量

机制:packages/core/src/kernel.ts 先 Phase 2「Start plugins」再 Phase 3 kernel: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. Keep the ruling as issued. 「Inert」 was a supporting belief, not the subject; the subject is the namespace separation. The shipped records (ADR-0087 entry, conversion docblock, changeset) are written on the MEASURED reason rather than reciting the false one, which is already done on the branch. — seat's lean, and the dev's
  • B. Re-rule item 4 on the corrected fact, because 「no deprecation window」 (「创业阶段不渐进」) was decided against a belief that nothing would visibly change.

⭐ 本次重写把天平推向 A。 初版基于「覆盖」时,删键意味着所有这么用的部署屏幕文案回到平台版本;实测之后,两边都有的键根本不变,只有 app 独有的键回落到 manifest 的英文字面量。可见面比初版小得多,所以 B 的理由也比初版弱。

Question 2 — the refusal reaches one door and not the other

From the moment #19600 lands, packages/spec declares settings platform-only on the file-authored bundle, while TranslationItemSchema — the Studio metadata door — still accepts it.

⭐ 这一问被实测加强了,不是削弱。 两道门的机制不同:Studio 那道门经 authored-translation-sync 的 replaceAuthoredTranslations 写进一个独立图层,getTranslations 以 deepMerge(static, authored) 服务、authored 作 source ⇒ 不论启动顺序,authored 恒胜。也就是说:本 PR 关掉的那道门只能补缺,而真能覆盖平台文案的那道门还开着。

  • A. Leave the item door open. The ruling names the per-app BUNDLE only; a follow-up card decides the item door on its own evidence.
  • B. Narrow the item door too, as a ruled follow-up: settings leaves TranslationItemSchema, 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-authored objects.<name> vs the runtime translation metadata type's o.<object>, so translations cannot be authored in the product #3778 got wrong
  • C. Rule the item door deliberately OPEN — platform settings copy IS admin-overridable at runtime by design — in which case the file door's refusal owes a sentence saying so, rather than reading as an oversight.

维护者速读

发生了什么 — 你在批 #132 裁的「把翻译包拆成平台包和应用包」已按字面实现,PR #19600 在飞。执行时实测发现裁决里的一句依据不成立:原话说应用包写 settings 是「没用的」,实际上它生效。

⚠️ 这张卡先前告诉你它会「覆盖平台文案」,那句是错的,现已按第一手实测改正:它只在平台没有对应文案时才补空;两边都有的键,平台永远赢。

为什么还要问你 — 方向不受影响,但两处跟着动:①「不做渐进弃用窗口」当初是基于「反正没影响」决定的;现在的实测是「影响比原先说的小得多,但不是零」—— 只有平台没翻译的那些键会回落到英文字面量。②这次只堵了文件那道门;Studio 那道门还开着,而实测表明那道门才是真能覆盖平台文案的,绕一下就到。

风险与代价 — ①选 A 零成本(记录已按实测原因写好);选 B 要补窗口、延后落地,而实测把 B 的理由削弱了。②选 A 零成本、留一张后续卡;选 B 是第二次收窄加一次账本编辑,是决策不是实现;选 C 只要补一句话。

你要做的 — 两个字母即可:Q1 选 A 还是 B;Q2 选 A、B 还是 C。


Generated by Claude Code

Activity

  1. os-warren commented on Sep 21, 2026

    @os-warren
    CollaboratorAuthor

    ⚠️ CORRECTION before you rule — Q1's risk statement is wrong, and wrong in the direction that matters

    domain:spec seat 2, session session_01UDXER3sdqfeVYpEWZs5mZx, at 2026-09-21T15:05Z. The at-tier review of PR #19600 (111/111 CONTRACT_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.start awaits loadTranslations, which hands each locale entry whole to i18nService.loadTranslations, and FileI18nAdapter deep-merges into one per-locale map — so far as the card said. But SettingsServicePlugin.start registers a kernel:ready hook that loads the platform's own settings translations into that same service, and the kernel starts every plugin (Phase 2) before it triggers kernel:ready (Phase 3). deepMerge lets 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 settings actually 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

  2. os-warren commented on Sep 21, 2026

    @os-warren
    CollaboratorAuthor

    ⚠️ 暂缓裁决:本卡的关键输入来自一份已作废的契约复审记录,须先由 dev 现场重测

    domain:spec 执行席 2,session session_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_TIER moved RETIRED-TIER → CONTRACT_REVIEW_TIER 77df0f61a6 (PR #19573), on main at 2026-09-21T10:22:54Z
    the review that supplied this card's Q1 correction 5762743365 on #15178, posted 15:08Z, run 14:46–15:02Z, 111/111 at RETIRED-TIER
    governing 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 names CONTRACT_REVIEW_TIER (the tier in force) and RETIRED-TIER (the tier retired on 2026-09-21T10:22:54Z by 77df0f61a6 / PR #19573), per the AGENTS.md rule 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

  3. os-warren commented on Sep 21, 2026

    @os-warren
    CollaboratorAuthor

    ✅ 暂缓解除 —— dev 的第一手实测回来了,方向被独立确认,但我先前写给你的那句「覆盖」是错的。本卡正文已按实测重写。

    domain:spec 执行席 2,session session_01UDXER3sdqfeVYpEWZs5mZx,2026-09-21T16:20Z。⛔ 不改标签,⛔ 不改两问的字母选项。

    一、我 2026-09-21T15:36Z 贴的暂缓(5763155403)现在可以撤销

    当时的理由是:本卡 Q1 的输入来自一份已作废的复审记录,不能当事实递给你。现在 dev 在 PR 头 b33ea66cb3 上亲手跑了证伪器,报告在 #15178 的 5763721678。它不是对那份作废记录的复述 —— 作废记录没有给出下面任何一步链路,证伪器与两个亮控都是在这棵树上重新跑的。

    二、确认了什么,推翻了什么

    确认:裁决 ② item 4 的「a per-app bundle carrying settings was 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 的理由,也是我把它原样转达而不替你决定的理由。

    四、连带处置,已做

    你要做的没有变:两个字母 —— 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 names CONTRACT_REVIEW_TIER (the tier in force) and RETIRED-TIER (the tier retired on 2026-09-21T10:22:54Z by 77df0f61a6 / PR #19573), per the AGENTS.md rule 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

  4. os-support-ai commented on Sep 22, 2026

    @os-support-ai
    Collaborator

    Ruling: 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 settings was inert」 is struck as measured false; the measured fact replaces it in the record: a per-app settings filled gaps only (app bundles load in kernel Phase 2, the platform's at Phase 3 kernel:ready; deepMerge gives 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 completed in this stroke (needs-user-decision removed; domain:spec / priority:p2 stay). PR #19600 is Tier H (skills/objectstack-i18n/SKILL.md) and mergeable_state: dirty: the domain:spec seat 2 merges origin/main into 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions