Skip to content

参考文档生成器把数值字面量 z.literal(2) 渲染成带引号的 '2',数值型联合被记成字符串型 #5729

Closed

Description

@os-zhuang

实施 #5611 时实测到的范围外问题,只记录不修。

实测

packages/spec/scripts/build-docs.ts 渲染 z.literal(number) 时加了引号,把数值字面量写成字符串字面量。

现存实例 —— FormSectionSchema.columns(packages/spec/src/ui/view.zod.ts:1502-1510)声明为:

columns: z.union([
  z.enum(['1', '2', '3', '4']),
  z.literal(1), z.literal(2), z.literal(3), z.literal(4),
]).default(1).transform(...)

生成的 content/docs/references/ui/view.mdx:184 却是:

| **columns** | `Enum<'1' \| '2' \| '3' \| '4'> \| '1' \| '2' \| '3' \| '4'` | optional |  |

后半段的四个 '1' | '2' | '3' | '4' 就是那四个数值 z.literal(1..4),被渲染成了带引号的字符串字面量。参考文档因此读起来像"这个键只收字符串",而它实际同时收 2 和 '2'。

为什么今天不痛、但值得记

FormSectionSchema.columns 恰好两种都收(联合里字符串 enum 和数值字面量都在),所以照文档写 '2' 目前能过 —— 今天没有用户会踩到,故打 finding 不进队列。

但这是个装了引信的错误:任何"只收数值"的字面量联合都会被记成只收字符串,而参考文档正是 AI 作者唯一的权威来源。#5611 实施中就直接撞上了:RecordDetailsProps.sections[].columns 本打算写成 z.union([z.literal(1), ..., z.literal(4)]),生成的参考显示为 columns?: '1' \| '2' \| '3' \| '4',而 schema 只收数值 2 —— 照参考写就是硬解析错误。PR 里改用了 z.number().int().min(1).max(4) 绕开(接受集合完全相同,且渲染为诚实的 integer),并在代码注释里写明了原因。

也就是说:这个渲染缺陷已经在改变 schema 的写法,这是它值得记下来的真正理由 —— 绕开一次是工程判断,绕开成惯例就是让生成器的缺陷反向定义契约。

修复方向

build-docs.ts 的字面量渲染按 typeof value 决定是否加引号:字符串加引号,数值/布尔不加。修完后 view.mdx 的 FormSectionSchema.columns 应变为 Enum<'1' \| '2' \| '3' \| '4'> \| 1 \| 2 \| 3 \| 4,#5611 里的那处也可以按需改回字面量联合。

Activity

  1. added
    domain:specDomain lane — seat card indexed by label:pm:seat
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 6, 2026
  2. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 6, 2026
  3. claude commented on Aug 6, 2026

    @claude
    Contributor

    发现分诊轮判级(#4949 纪律):晋级 pm:queue,域 domain:spec 保持。

    过时前提检查:origin/main 889ae47 上渲染仍由 packages/spec/scripts/lib/format-type.ts 的 formatType 承担(build-docs.ts:30 导入、279 行调用),FormSectionSchema.columns(packages/spec/src/ui/view.zod.ts:1502)的字符串 enum + 数值字面量联合原样在;前提成立。

    晋级理由(为什么不按"今天不痛"持有):正文自己给出了已经咬到人的实例 —— #5611 实施中按参考文档写 columns 就是硬解析错误,只能改用 z.number().int() 绕开。参考文档是 AI 作者的唯一权威来源,一个把"只收数值"记成"只收字符串"的渲染器,产出的是会被照抄的错误前提(同 #4115 记录的失效类:错误的 canonical 声明不是陈旧文档,是给下一个会话埋的前提)。落点唯一、验收可机械陈述(z.literal(<number>) 渲染为不带引号的 2,并补一条渲染 pin 测试),具备入队条件。

    ⚠️ 同文件串行(step 3):#5340(内联长枚举不省略)同落 packages/spec/scripts/lib/format-type.ts,两单不得同轮派发;#5340 本轮判为持有,若本单的 dev 已在该文件内,顺带收 #5340 的宽度省略成本极低(见 #5340 上的同文提示)。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  4. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    疑似域误标:本单落点在 docs-gen 生成器(packages/spec/scripts/**,C 包 #5163 文件面),不触 packages/spec/src/**/*.zod.ts,建议改标 domain:spec-tooling ——交分诊座位定夺。背景:维护者 2026-08-06 拍板 spec 车道缩盘方案,见 #5837。


    Generated by Claude Code

  5. added and removed
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 6, 2026
  6. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    标签落实(维护者 2026-08-06 指示,session_01LeEfA7CFwbJb7JJmXm2KM3):按 08-06 转席建议执行 domain:spec → domain:spec-tooling(缩盘方案 #5837 已拍板,落点 C 包文件面)。搭车项 #5340 已随本单归属同车道。


    Generated by Claude Code

  7. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    排程备注(spec-tooling 座位,会话 session_014wsZeReNTqiceBfLb5Pyf5,2026-08-06):本单延后串行,两个原因成对记录:

    1. 同渲染管线让行:[docs-gen] 生成的 reference 把 retiredKey() 墓碑渲染成 any —— 嵌套两层时连 [REMOVED] 处方都没有,退役键读起来像自由槽 #5606(retiredKey 墓碑渲染成 any)已派发在飞,落点 lib/format-type.ts + content/docs/references/** 整体重生成 —— 与本单大概率同一条字面量/类型格式化路径,同批必撞。已要求 [docs-gen] 生成的 reference 把 retiredKey() 墓碑渲染成 any —— 嵌套两层时连 [REMOVED] 处方都没有,退役键读起来像自由槽 #5606 的 dev 在报告里回答「字面量加引号发生在哪个文件、其改动让本单变简单/变难/不必要/无影响」——派发本单前以该回答重新定价,⛔ 不沿用本单正文的修法假设(正文写的落点是 build-docs.ts,[docs-gen] 生成的 reference 把 retiredKey() 墓碑渲染成 any —— 嵌套两层时连 [REMOVED] 处方都没有,退役键读起来像自由槽 #5606 的实测可能推翻它)。
    2. spec 生成物按 category 分片:拆掉三个单体 ratchet 文件的合并队列串行税(维护者 2026-08-06 已拍板) #5837 窗口:build-docs.ts 在分片工程(在飞)的 S3 读点面内;若本单落点确在 build-docs.ts,还需等 spec 生成物按 category 分片:拆掉三个单体 ratchet 文件的合并队列串行税(维护者 2026-08-06 已拍板) #5837 落地后再派。

    Generated by Claude Code

  8. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    重新定价(承 15:2xZ 排程备注的必答项,答案来自 #5606 的实现 PR #6058,2026-08-06 15:5xZ):

    变简单,落点已实测锚定。 加引号不在本单正文猜的 build-docs.ts,而在 packages/spec/scripts/lib/format-type.ts 的两个相邻分支——prop.enum 与 prop.const !== undefined 都无条件套单引号、不看 typeof。修法 = 给这两处加类型判别(number/boolean/null 不加引号);format-type.test.ts(#6058 新增)已有现成 fixture 惯例,直接加 describe 块;content/docs/references/** 整体重生成与 #6058 同一套流程(含 gen:schema 物化 json-schema 树的前置)。

    排序不变:串行在 #6058 合入之后(同函数,叠加 diff 互埋);#5837 窗口对本单的约束随落点改判——format-type.ts 不在分片改造面内,故本单解除让行的条件收窄为「#6058 合入」,不再等 #5837。派发时按此定价,⛔ 不沿用正文的 build-docs.ts 假设。


    Generated by Claude Code

  9. self-assigned this
    on Aug 7, 2026
  10. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 4 轮(spec-tooling 车道,座位登记 #6018;rc.4 release-priority 批次,维护者 2026-08-07 指示优先;解除条件 #6058 已 MERGED,按 15:57Z 重新定价派发)
    会话:session_014wsZeReNTqiceBfLb5Pyf5
    分支:claude/issue-5729-numeric-literal-rendering
    Worktree:objectstack-issue-5729
    域:domain:spec-tooling
    文件面:packages/spec/scripts/lib/format-type.ts(prop.enum 与 prop.const 分支按 typeof 判引号)+ packages/spec/scripts/format-type.test.ts + content/docs/references/** 重生成 + .changeset/*.md。⛔ 不碰 zod 文件与 build-docs.ts(#5059 并行在飞);#5340(finding,同文件)⛔ 不搭车,只在报告里给定价答案。(越界即停,报告说明)


    Generated by Claude Code

  11. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    ContributorAuthor

    验收:ACCEPT → PR #6127(转 ready 入队,rc.4 gate 单)

    亲核 GitHub:24/24 检查绿,门禁承载 job 逐个 conclusion=success(ESLint / TypeScript Type Check / Check Changeset);文件面精确 11 个(lib/format-type.ts + 测试 + 8 页重生成 + changeset),build-docs.ts 未触碰(#5059 并行面保持干净)。

    三点值得记的判断:

    1. per-value 而非 per-node 判引号——dev 探测到 z.nativeEnum({A:1,B:2}) 会发出 {type:'number', enum:[1,2]},即一个 enum 可混类型,按节点 prop.type 判会渲染错。这是比 issue 修法建议更准的实现。
    2. 单调性被机械证明:脚本逐行 diff 引号多重集,18 个引号对全部来自非字符串(6 布尔 / 12 数值),无字符串字面量失去引号、无新增加引号——正是「只删错的、不伤对的」这条要求的可验形式。
    3. 一次自我更正,如实留档:初版预测「4 红 2 绿」实测 5 红,dev 查明是自己的测试结构问题(字符串守卫与数值断言同处一个 it,不可能独立保持绿),拆开重测并把「先前预测是错的」写进注释。方向预测错了就改测试并记录,这是好运行。

    ui/view.mdx:184 现读作 Enum<'1' | '2' | '3' | '4'> | 1 | 2 | 3 | 4,#5611 被迫的绕开可按需回退。#5340 定价:基本无影响(布局问题 vs 拼写问题),边际略易。


    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

Labels

pm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loop

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions