影响
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 E2E 的 registry-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.ts 的 rewriteProjectIdentity 只从 objectstack.manifest.json 读模板原始 namespace:
if(typeofm.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.ts 的 namespace: 是无条件改写的。结果就是 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 随后)
objectstack.config.ts 作为 namespace 的权威来源,manifest 降为回退。config 里的 namespace: 正是脚手架自己要改写的那个字面量,两者不可能不一致。- 改写完成后自我校验。「静默什么都没做」和「本来就不需要做」在外部完全同形 —— 这个歧义正是本缺陷得以出厂的原因。残留任何旧前缀就直接报错退出,把失败拉回到脚手架现场,而不是留给用户的第一条
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,不是模板。)是有意暂不发布还是漏了,需要维护者确认 —— 另行记录。
影响
npx create-objectstack@latest my-app -t <模板>对 6 个模板里的 5 个产出的工程连objectstack build都过不去(exit 2)。只有本仓库自带的blank是好的。Scaffold E2E的registry-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.ts的rewriteProjectIdentity只从objectstack.manifest.json读模板原始 namespace:而
objectstack.manifest.json这个文件名对应两种完全不同的文档:blank$schema: …/template-manifest.json(注册表文档)namespace字段"blank")objectstack.config.ts于是对每个远程模板
templateNamespace都是undefined,守卫&& templateNamespace为假,对象名改写整段被跳过;而objectstack.config.ts的namespace:是无条件改写的。结果就是namespace: 'my_app'与name: 'todo_task'并存,直接违反packages/spec/src/kernel/namespace-prefix.ts的${namespace}_${shortName}规则。实测(把
objectstack-ai/templates@960f24d的真实模板喂给新旧两套逻辑):undefinedtodoundefinedcomplianceundefinedcontentundefinedcontractsundefinedprocurement生产上共 74 处对象名从未被改写。
代码注释本身就留了线索 —— 「Used to swap the bundled template's literal
blank_object-name prefix」:这段逻辑从设计起就只考虑了自带模板,远程路径从未被覆盖。修复方向(PR 随后)
objectstack.config.ts作为 namespace 的权威来源,manifest 降为回退。config 里的namespace:正是脚手架自己要改写的那个字面量,两者不可能不一致。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,不是模板。)是有意暂不发布还是漏了,需要维护者确认 —— 另行记录。