Skip to content

P0:5 个已发布模板对真实新用户是坏的 —— 脚手架的对象名前缀改写对所有远程模板静默跳过,夜间金丝雀连红 20 次无人察觉 #4926

Description

@os-zhuang

影响

npx create-objectstack@latest my-app -t <模板>6 个模板里的 5 个产出的工程连 objectstack build 都过不去(exit 2)。只有本仓库自带的 blank 是好的。

Registry canary: todo         ✗ Object 'todo_task' is missing the package namespace prefix.
                                 Rename it to 'canary_app_todo_task' (namespace = 'canary_app')
Registry canary: compliance   ✗ 4 issues
Registry canary: content      ✗ 9 issues
Registry canary: contracts    ✗ 3 issues
Registry canary: procurement  ✗ 4 issues

Scaffold E2Eregistry-canary 最近 20 次定时运行全部失败,连续至少从 2026-07-27 到今天(最近一次 run 30784751821)。

为什么无人察觉

registry-canary 的条件是 if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' —— PR 永远不跑它,只在夜里跑,而夜里的红灯没有任何人或机制去看。这个 workflow 的全部存在意义就是当新用户金丝雀,它红了一周多,首次使用体验一直是坏的。

根因:同名文件、两套 schema

packages/create-objectstack/src/index.tsrewriteProjectIdentity 只从 objectstack.manifest.json 读模板原始 namespace:

if (typeof m.namespace === 'string') templateNamespace = m.namespace;

if (namespace !== templateNamespace && templateNamespace) { …改写 src/**/*.ts 里的对象名… }

objectstack.manifest.json 这个文件名对应两种完全不同的文档:

自带 blank 远程模板(objectstack-ai/templates)
schema app 形态 $schema: …/template-manifest.json(注册表文档)
namespace 字段 ("blank") 没有 —— 只有 name/displayName/category/skills/translations
真实 namespace 在哪 manifest + config 只在 objectstack.config.ts

于是对每个远程模板 templateNamespace 都是 undefined,守卫 && templateNamespace 为假,对象名改写整段被跳过;而 objectstack.config.tsnamespace:无条件改写的。结果就是 namespace: 'my_app'name: 'todo_task' 并存,直接违反 packages/spec/src/kernel/namespace-prefix.ts${namespace}_${shortName} 规则。

实测(把 objectstack-ai/templates@960f24d 的真实模板喂给新旧两套逻辑):

模板 旧逻辑读到的 namespace 新逻辑 应改写的对象名 旧逻辑实际改写
todo undefined todo 7 0
compliance undefined compliance 17 0
content undefined content 22 0
contracts undefined contracts 12 0
procurement undefined procurement 16 0

生产上共 74 处对象名从未被改写。

代码注释本身就留了线索 —— 「Used to swap the bundled template's literal blank_ object-name prefix」:这段逻辑从设计起就只考虑了自带模板,远程路径从未被覆盖。

修复方向(PR 随后)

  1. objectstack.config.ts 作为 namespace 的权威来源,manifest 降为回退。config 里的 namespace: 正是脚手架自己要改写的那个字面量,两者不可能不一致。
  2. 改写完成后自我校验。「静默什么都没做」和「本来就不需要做」在外部完全同形 —— 这个歧义正是本缺陷得以出厂的原因。残留任何旧前缀就直接报错退出,把失败拉回到脚手架现场,而不是留给用户的第一条 objectstack build

顺带发现:4 个模板完全没有自动化覆盖

objectstack-ai/templates 里有 10 个包。脚手架 TEMPLATES 注册表只提供 5 个远程模板,金丝雀矩阵也只有这 5 个 + blank。而 expense / helpdesk / hr / project 各自都有完整的 objectstack.config.ts 和 namespace(expense/helpdesk/hr/pm),却既不对用户开放、也无任何 CI 覆盖。(all 没有 config,不是模板。)是有意暂不发布还是漏了,需要维护者确认 —— 另行记录。

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingtooling

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions