Skip to content

docs-gen: .describe() 里的 {{var}} 在生成的参考文档里被转义成 ` {{var} + 游离的 }`(main 上现存 3 处) #5452

Closed

Description

@os-zhuang

实施 #5307 时给 EmailServiceConfigSchema.appName 写 .describe('… ({{appName}}) …'),重新生成参考文档后发现输出被切坏。查了一下,不是新引入的,main 上已有 3 处。

现象(origin/main @ ed0d2aa)

packages/spec/scripts/build-docs.ts 把 .describe() 文本写进属性表的 Description 列时,对 MDX 的花括号做转义。输入 {{var}},输出是反引号只包住前半截、后半个花括号漏在外面:

grep -rn '`{{' content/docs/references/
content/docs/references/ai/model-registry.mdx:171:| **system** | … | optional | System prompt — supports `{{var}`} interpolation |
content/docs/references/ai/model-registry.mdx:172:| **user**   | … | ✅       | User prompt template — supports `{{var}`} interpolation |
content/docs/references/automation/flow.mdx:106:| **outputSchema** | … | … 表达式(`{{nodeId.field}`})… |

对应的源:

packages/spec/src/ai/model-registry.zod.ts:121:  system: … .describe('System prompt — supports {{var}} interpolation'),
packages/spec/src/ai/model-registry.zod.ts:122:  user:   … .describe('User prompt template — supports {{var}} interpolation'),

即 {{var}} 变成 `{{var}` 后面跟一个游离的 }。渲染出来读者看到的是 {{var} 加一个孤立右括号,而模板语法本身要的正是成对的双花括号 —— 这一列恰恰是在教读者怎么写模板变量。

分级

observation-class:纯生成物排版,没有运行时行为、没有校验绕过,今天没有用户因此报错;但它出现在「怎么写模板变量」这一句上,是唯一会误导人的地方。故打 finding、不进 pm:queue,交 PM 分诊。

规避与代价

#5307 的 PR 已经绕开:appName 的 .describe() 改写成「the appName variable」,不带花括号,并在源码里留了一行注释指回本单。这说明代价是真实的 —— 一个 schema 作者想在描述里写模板语法,就得先知道生成器会切坏它,否则得等文档生成完再回头改。

修法方向(未验证,交实施者实测)

build-docs.ts 里做 MDX 转义的那一段。花括号在 MDX 里是 JSX 表达式定界符,所以转义本身必要;问题出在转义边界与代码反引号包裹的先后顺序——现在的顺序让包裹只吃掉了一个 }。要么整段用行内代码包住再转义,要么转义时把连续花括号当一个整体。修好后 pnpm --filter @objectstack/spec gen:docs,上面三处 grep 应归零。

Activity

  1. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    分诊轮判级(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05):晋级(摘 finding 挂 pm:queue)。理由:docs-gen 转义顺序 bug,main 上 3 处存量恰好切坏「教读者写模板变量」的那一句;#5307 的 PR 已被迫绕写一次 —— 代价已经在发生。修法方向 issue 已写(转义边界与反引号包裹顺序),小单。


    Generated by Claude Code

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

    @os-zhuang
    ContributorAuthor

    认领:spec 车道恢复后第 1 批(batch:2)
    会话:session_018fxLGQdatPbBUvCgiVxg6D
    分支:claude/issue-5452-docs-gen-brace-escape
    Worktree:objectstack-issue-5452
    域:domain:spec
    文件面:packages/spec/scripts/build-docs.ts + 重生成 content/docs/references/** 受影响页(main 上 3 处存量:model-registry.mdx ×2、flow.mdx ×1)+ 门禁性测试。

    与同批 #5050 源文件不相交;references 生成物重叠按 os-regen 四步互保。修好后 #5307 在 email-config 里的绕写注释可留(它引用本单,历史成立)。


    Generated by Claude Code

  4. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    实施完成,draft PR #5550(会话 session_018fxLGQdatPbBUvCgiVxg6D,分支 claude/issue-5452-docs-gen-brace-escape)。

    前提复核:基线 ed0d2aac0 已前移,在 origin/main @ 5acb93add 上重核,3 处存量仍在,前提成立。

    两点与本单原文不同,请分诊时留意:

    1. 实际是 5 处,不是 3 处。 根因(escapeMdxDescription 用 indexOf 取第一个闭合符而非配对闭合符)对任何嵌套定界符都成立,不限于双花括号。另有两处同样被切开、但起手只有单个左花括号,因此本单用的 `{{ grep 天然看不见:

      • content/docs/references/ai/solution-blueprint.mdx:156 —— roll-up filter 例子 { status: { $in: [...] } }
      • content/docs/references/api/analytics.mdx:70 —— 已退役的 query 信封 { cube, query: {...} }
    2. 本单的验收判据(grep 归零)不成立,也不应该成立。 grep -rn '`{{' 匹配的是「反引号 + 两个左花括号」,而修好后的正确输出 `{{var}}` 同样以此开头 —— 修前修后都是 3 命中,变的是内容不是计数。归零只有在「参考页里根本不许出现模板变量语法」时才成立,与本单目的相反。

      门禁改用等价且更宽的不变量:行内代码跨度里的花括号必须配平。实测 main 224 页 5 处违例、本 PR 重生成后 0 处、零误报。反向验证两个方向都实跑:还原旧 matcher → 5 条单元用例转红;再 gen:docs → 语料门禁转红并逐行复现 main 上那 5 行。

    顺带发现另立一单 #5553(不同函数、不同根因,未在本 PR 修):模块 JSDoc 走 getFileDescription,按源码行 join('\n\n') 成段落,跨行的行内代码跨度被段落边界切断,5 张参考页正文露出裸反引号。

    按派单要求,#5307 在 email-config.zod.ts appName describe 里的绕写保持原样。packages/spec/authorable-surface.base.json 被 gen:schema 顺带推进的 baseRev 已还原,未纳入本 PR。


    Generated by Claude Code

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