影响
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 (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.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,不是模板。)是有意暂不发布还是漏了,需要维护者确认 —— 另行记录。