Skip to content

meta: /meta/objects reports field metadata from the build artifact, not the registry — created_at reads readonly: false while the write path enforces read-only #4513

Description

@os-zhuang

发现于修复 #4447 时(PR #4511),与该 issue 同源但是另一处缺陷,故单独记录,未认领。

摘要

GET /api/v1/meta/objects/<object> 返回的字段元数据来自应用构建产物dist/objectstack.json),而不是运行时注册表registry.getObject())。两者已经不一致:写入路径按注册表强制 created_at 为只读,而这个机器可读面仍然声称它可写。

复现

pnpm dev -- --fresh -p <port>,showcase,admin 会话,#4447 修复之后

GET /api/v1/meta/objects/showcase_task
→ "created_at": {"label":"Created At","type":"datetime", …, "readonly": false}

但同一个字段在同一次启动里确实是只读的:

PATCH /api/v1/data/showcase_task/<id>  {"progress":42,"created_at":"1999-01-01T00:00:00Z"}
→ 200
   droppedFields: [{"object":"showcase_task","fields":["created_at"],"reason":"readonly"}]
GET  …?select=created_at,progress
→ {"created_at":"2026-06-22T00:00:00.000Z","progress":42}   ← 锚点没动

即:面说可写,引擎按只读执行。

另外注意同一响应里 updated_at / created_by / updated_by 根本不出现,只有 created_at 出现——这本身就说明这份字段表不是注册表的投影(注册表四个都有),而是构建产物里恰好被物化的那一个。

#4447 的区别

影响

AGENTS.md「Route & surface ownership」第 4 条:机器可读面不许撒谎/meta/objects 会被 SDK、代码生成、Studio 表单渲染和 AI 客户端读取:

  • 表单/Studio 会把 created_at 渲染成可编辑输入框,用户改了却静默不生效(值被 droppedFields 丢弃,UI 若不读该字段就完全无提示);
  • 代码生成/AI 作者会据此认为该字段可写,产出写它的代码;
  • 更一般地:任何构建产物与注册表存在差异的字段,这个面给出的都是产物那一侧的答案,而强制的是注册表那一侧。created_at 只是第一个被抓到的样本,不一定是唯一的。

期望

/meta/objects 投影应以运行时注册表为准(registry.getObject(),即 applySystemFields / provisionPrimary 之后的规范形状),使它与实际执行的写入契约一致。若出于性能或其他原因必须读产物,则产物必须在构建时就经过同样的规范化,并有门禁保证两者不漂移。

顺带值得查清的:构建产物里那个 created_at物化进去的(showcase 源码并未声明它,task.view.ts / dashboards / datasets 只是引用了它)。如果是「把视图引用到的字段补进对象」这类构建步骤,那它用 FieldSchema 默认值补出一个系统字段本身就该修——那会是第三处,比这个面更靠上游。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions