Skip to content

All nine i18n-extract configs author name: on defineStack — a key the lint drops at load, warning on every check:i18n run #4736

Description

@os-zhuang

在 #3207 收尾(PR #4734)跑 pnpm check:i18n 时发现的既有噪音,与该 PR 无关,按 Prime Directive #10 立单不修。

现象

check:i18n 全绿的运行中稳定输出:

defineStack: stack.name: 'name' is not a declared stack key, so its value is dropped at load — did you mean 'pages'?

(unknown-authoring-key lint 有 dedupe,九个包只打印一次。)

根因

全部九个 scripts/i18n-extract.config.ts 都在 defineStack({ ... }) 顶层写了 name::

packages/platform-objects/scripts/i18n-extract.config.ts:181
packages/plugins/plugin-approvals/scripts/i18n-extract.config.ts:30
packages/plugins/plugin-audit/scripts/i18n-extract.config.ts:25
packages/plugins/plugin-security/scripts/i18n-extract.config.ts:27
packages/plugins/plugin-sharing/scripts/i18n-extract.config.ts:23
packages/plugins/plugin-webhooks/scripts/i18n-extract.config.ts:26
packages/services/service-messaging/scripts/i18n-extract.config.ts:30
packages/services/service-realtime/scripts/i18n-extract.config.ts:23
packages/services/service-storage/scripts/i18n-extract.config.ts:26

name 不是声明的 stack key,值在 load 时被丢弃 —— lint 行为正确,配置是错的(九份互相拷贝的同一处错)。

决策点(二选一,不建议消音 lint)

  • A. 删掉九处 name::机械修正,extract 配置本就不需要自命名;
  • B. 若 stack 确实该有 name:走 spec 正路把它声明成 authorable key(Zod + 生成物),而不是靠 lint 容忍。

倾向 A:这些是内部 extract 夹具,name 从未被读。绿色运行里稳定出现的 warning 会训练人忽略 warning,这本身就是成本。

复现

pnpm check:i18n(需先构建 CLI:pnpm turbo run build --filter=@objectstack/cli...)。


发现于 session session_0176qgxgCXTJCUv4YFLtusP9(#3207 收尾途中,超范围不代修)

Activity

  1. self-assigned this
    on Aug 3, 2026
  2. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 4 轮
    会话:session_015Br2xsJsczFsTR9bvbh2Ny
    分支:claude/issue-4736-i18n-extract-stack-name
    Worktree:objectstack-issue-4736

    分诊:落地 objectstack;PM 裁定取方案 A(删掉九处 name:),不取 B。

    理由按两条轴:

    • 长远合理性 —— B(把 name 走 spec 正路声明成 authorable key)是为了迁就九份互相拷贝的同一处笔误,而去扩大公开契约面。name 从未被任何东西读过,这九个文件是内部 extract 夹具,不是产品形态。为不存在的需求加 authorable key,以后就要一直养着它(生成物、文档、退役流程),这正是 ADR-0049 要清的那类账。
    • 防 AI 写错 —— 绿色运行里稳定出现的 warning 会训练人(和 agent)忽略 warning,这本身就是成本。而且这九处是同一个错被拷贝了九次,说明有人照着第一份抄——留着它,下一份 extract 配置还会照抄。

    ⚠️ 范围约束:只删这九处 name:,不要动 lint 规则本身(lint 行为是正确的,配置是错的),也不要改任何 defineStack 的 schema。若你发现删掉之后有任何东西真的读了 name,停下来报告 —— 那意味着前提错了。

    并行批隔离:改动只碰 packages/*/scripts/i18n-extract.config.ts。本轮另有 agent 在 packages/plugins/plugin-auth/src 与 packages/objectql/src,其中 plugin-approvals 与 platform-objects 的 src/ 也可能有在飞改动 —— 你只碰 scripts/,文件不相交,但请勿顺手改这些包的其它文件。


    Generated by Claude Code

  3. os-zhuang commented on Aug 3, 2026

    @os-zhuang
    ContributorAuthor

    PM 复核:ACCEPT(待 CI 全绿) —— PR #4803。

    我在派发时写了「若你发现删掉之后有任何东西真的读了 name,停下来报告 —— 那意味着前提错了」。dev 没有把这句话当成免责声明,而是真的去证了一遍,四条独立证据:

    1. ObjectStackDefinitionSchema 顶层键里没有 name;
    2. 这九个文件 export default defineStack({…}),导出的是 parse 之后的结果 —— name 在那一步就已经没了,也就是说消费者根本不可能读到它,这条最有说服力;
    3. os i18n extract 经 loadConfig 拿到的正是那个 default 导出,读 i18n / objects / apps,从头到尾没碰 name;
    4. 全仓只有两个消费者(package.json 的 i18n:extract、scripts/check-i18n-bundles.mjs),都走同一条路径。

    第 2 条把这件事从「搜了一遍没找到读的地方」升级成了「结构上不可能被读到」。这两种结论的强度差很多,值得记下来。

    验收证据也是实测的

    我要求「提取结果与改动前一致 —— 请实际验证,不要假设」。dev 跑了全量重生成 check-i18n-bundles.mjs --write,40 个 bundle 重写后 git status 对 src/translations/** 干净,即产物逐字节一致。这比「check:i18n 还是绿的」强得多——后者只说明没变坏,前者说明什么都没变。

    没加单测,理由成立

    scripts/ 不在任何包的 files(只发布 dist),也不在 tsconfig 的 include 里,没有自然的单测落点;真正加载并执行这些配置的是 check:i18n 门禁本身(走 bundleRequire 实打实跑),所以用它的实测输出作证据是对的。我接受这个理由 —— 为一个纯删除硬凑一个单测,只会增加一处需要维护的东西。

    范围

    九个 scripts/i18n-extract.config.ts + 一份 changeset,共 10 行删除。未动 lint 规则、未动 defineStack schema、packages/spec 零改动 —— 三条约束都守住了。

    那条建议我采纳,但另立

    能防住"第十份照抄"的最廉价办法是把这条 lint 升级为 check:i18n 的硬失败

    同意,而且这正是本 issue 背后真正的问题(同一个错被拷贝九份,说明没有东西拦住第一份)。按我给的范围约束它没在本 PR 实现,是对的 —— 那会改变 gate 行为。CI 绿、PR 合并后我会立单跟进。


    Generated by Claude Code

  4. added 2 commits that reference this issue on Aug 3, 2026
    ffab803
    f4847a6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions