Skip to content

localization 的 timezone / currency 用「策展式 options 表」当穷尽执行边界:合法的 IANA 时区与 ISO 4217 币种被拒 #5712

Description

@os-zhuang

#5204(env 覆盖过 options 表)的实现中发现,记录下来交 triage。不在 #5204 的完成范围内,#5204 也没有为它开豁免口子。

事实

packages/services/service-settings/src/manifests/localization.manifest.ts 里两个 select 的 options 表是「策展便利列表」,而它们各自的 description 描述的是一个开放域:

表里有 description 声明的域
timezone 17 个时区(UTCAmerica/New_YorkAsia/Shanghai …) 「IANA zone used to resolve today()/daysFromNow, analytics date buckets, and rendered datetimes.」
currency 9 个币种(USD/EUR/GBP/JPY/CNY/INR/AUD/CAD/BRL) 「ISO 4217 code applied when a currency field omits its own.」

IANA 时区数据库有约 600 个 zone,ISO 4217 有约 180 个 code。

#5131 起,SettingsService.validatePatch 把 options 表当作穷尽式执行边界:PUT /api/settings/localization 写入 timezone: 'Europe/Zurich'(或 currency: 'CHF')会被 invalid_option 拒绝——尽管那是一个完全合法、运行时也能正常处理的 IANA 标识符。#5204 把同一张表接到 env 侧之后,OS_LOCALIZATION_TIMEZONE=Europe/Zurich 也会被忽略并回落(带响亮 error)。于是两扇门都关上了。

为什么值得判一下

两种读法都说得通,而它们指向相反的修法:

  1. 表是 UI 便利列表,域是开放的 → 那么 service-settings: select 型 specifier 的 options 在保存期完全不校验 —— 声明的枚举不被强制 #5131 起写入侧就在越权执行,specifier 类型选错了。契约优先的修法在生产者侧:补全表(时区表可生成),或者换成带校验的 text(IANA/ISO 4217 校验),而不是在消费侧放宽。
  2. 表就是「受支持集合」 → 那么现状正确,只是 description 在撒谎,该改的是文案(说清只支持列出的这些),顺便让 env 来源的 settings 值绕过 manifest 的 options 表校验 —— #5094 在写入 API 上堵住的洞,在 OS_* 覆盖这一侧原样敞开 #5204 的 error 消息不至于让运维困惑。

按 AGENTS.md Prime Directive #10 的反面(「never advertise a capability the runtime doesn't actually deliver」),现在这个形状两头都不干净:文档宣称 IANA / ISO 4217,执行面只认 17 / 9 个。

影响面(已核实的部分)

建议

按读法 1 处理(生产者侧补全或换类型)看起来更符合 description 已经承诺的东西,但这是一次会影响公开 authoring 面的取舍(枚举语义 = 是否穷尽),交维护者定。


2026-08-06 契约拆分(services 座位):裁读法 1 的落地经 dev 实测确认需要 spec 声明位(valueDomain),按裁决预授权路径 contract-first 拆分 —— spec 半边见 #5933,本单收窄为 services 半边(manifest 对 timezone/currency 声明 valueDomain + 两扇门按域校验 + description 对齐;default_country 同洞第三例一并采纳或另立小单)。

Blocked-by: #5933

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions