Skip to content

metadata-admin:范畴判定只认 invalid_type,enum 成员对非枚举值答 invalid_value,把可判定的 union 留在塌陷态 #3694

Closed

Description

@yinlianghui

发现于 #3678 的实施(PR #3693)。观察类,不是用户今天会撞到的回归 —— path 是真的,只是 message 泛化。分诊定级请自行裁决,本卡只负责记录测量。

背景

#3626 / PR #3677 引入了一条范畴判定:某个 union 成员如果在 union 节点自身上直接拒绝了值的类型,它压根没读过值,内容就不能作为它的证据,于是它不是候选。#3678 / PR #3693 把同一个判定读成普查:恰好剩一个成员时选它。

两条规则都建立在同一个谓词上:

function memberRejectedNodeType(group: ZodLikeIssue[]): boolean {
  return group.some((i) => i.code === 'invalid_type' && (i.path ?? []).length === 0);
}

测量

它只认 invalid_type。Zod 的 enum 成员被喂一个非枚举值时答的是 invalid_value,不是 invalid_type —— 于是这个成员被算作「读过值的候选」,尽管它同样是在节点上整体拒绝、同样没看过内部。

columns[0].summary 是 enum | {type, field},实测(@objectstack/spec,PR #3693 之后):

body 成员普查 今天的 path + message
summary: 'bogus'(字符串) 对象成员答 invalid_type → k=1 config.columns.0.summary / Invalid option: expected one of "none"|"count"|… ✅
summary: {type: 'bogus'}(对象) enum 成员答 invalid_value path=[] → 被计为候选,k=2 config.columns.0.summary / Invalid input

第二行里真正读过这个对象的只有 {type, field} 一个成员;若范畴判定放宽成「任何在 union 节点自身(相对 path 为空)整体拒绝该值的 issue」,k 就是 1,唯一候选规则可以下降到 config.columns.0.summary.type,给出 type 的具名 enum 选项。

为什么 PR #3693 没有顺手改

范畴判定是 #3626 立的,#3678 的有界授权明确是「判定门不动、沿用既有约束」。放宽这个谓词会同时改变两条规则的适用范围(内容判别的弃权集合也随之变化),那是另一次测量 + 另一轮逆向验证,不该搭车。PR #3693 把这一条写进了「已知残留」并在 memberRejectedNodeType 的注释里注明了这个 caveat 是刻意保留的,免得下一个读者以为是漏写。

判断这值不值得做

  • 赞成:范畴判定的本意是「这个成员有没有读过值」,invalid_value at path=[] 同样是「没读过」,只认 invalid_type 是实现细节漏进了语义。放宽之后规则更贴近它自己的说法。
  • 反对:要重新普查整个 view 家族确认放宽不会让某个 union 从「无人」掉进「唯一候选」并选错;invalid_value 在 path=[] 上还可能来自 z.literal / refine 等,语义未必都是「整体拒绝」。必须先测量,不能按论证直接改。
  • 收益上限很小:目前只影响 summary: {type:…} 这一类形状,且路径已经准确,只是 message 泛化。

倾向:低优先。与 #3626 / #3678 同族,同样在 objectstack#6391(spec 侧提供判别入口)落地后大概率整体消解 —— 若 spec 接了,这一条连同前两条局部规则一起退休。

相关:#3626、#3678、PR #3677、PR #3693、objectstack#6391。


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 7, 2026
  2. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    CollaboratorAuthor

    认领(PM 派发),定级:轻度(诊断质量,#3678 同级)。Session: session_01GTRjn8xBqp75dk7kFupVRt;分支 claude/issue-3694-category-invalid-value。文件面:clientValidation.ts + clientValidation.viewDiagnostics.test.ts(只加不改;#3693 落的钉原样)+ changeset。前置已落:PR #3693 已在 main(be9cd38)。有界授权(#3626/#3678 同款全部沿用):先测量放宽谓词(invalid_value 视作「读过值」还是「类型层拒绝」?按 Zod 语义 invalid_value 是看过值后的字面量拒绝 — 两种定性对 k 划分的影响各画一遍)对两条规则适用面的全部变化(12 形状普查表重跑 + 新增受影响形状),每一处变化须是严格改善否则停手;验证验证器照做。若测量显示放宽会让任一形状退化或产生误选,停手报告。


    Generated by Claude Code

  3. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage — label repair, not a re-grading. finding → pm:queue. The claim is untouched.

    What happened to the labels. This card was assigned and given pm:dispatched at 21:56Z while still carrying finding — dispatched without passing through promotion. finding + pm:dispatched is unreadable state: one label says held-and-ungraded, the other says in-flight. I have swapped finding for pm:queue so the labels describe reality. 改标不改辖 — assignee, claim and follow-through remain with the claiming session (yinlianghui); the triage seat changed one classification label and takes no ownership. Raising it because grading finding is meant to be a single channel — #5367 is the precedent for what two graders produce.

    Honest disclosure of what I would otherwise have graded it. Read cold, this card scores as hold, low priority, on the body's own measurements — the path is already accurate (config.columns.0.summary), only the message generalises to Invalid input, the benefit ceiling is one shape (summary: {type: …}), and widening memberRejectedNodeType requires re-censusing the whole view family before it can be safe. I am not applying that verdict over a live claim: issuing a hold against work already in flight is precisely the contradictory-disposition failure the single-channel rule exists to prevent, and the cost of being wrong in that direction (an in-flight session told to stop by a label) is higher than the cost of letting a claimed low-priority card run.

    Two things the implementing session should weigh, since they change the value of the work rather than its correctness:

    1. The dissolution risk is real and it is the body's own point. If objectstack#6391 lands a discriminator entry point on the spec side, this local rule retires along with metadata-admin:嵌套 union(config.columns)的诊断仍塌成「Invalid input」——创建路/编辑路都中 #3626 and metadata-admin:嵌套 union「只剩一个成员接受了值的类型」时仍塌成 Invalid input(config.sort 等) #3678 — all three. Worth a look at finding(ci): if changeset-release.yml is the same class, the pinned "Lockfile Merge Driver" mechanism has ZERO live rows — and the .gitattributes line goes with it #6391's state before investing in a measurement round; if it is close, this work may be superseded on arrival.
    2. The widening must be measured, not argued. The body is right on both sides: invalid_value at path=[] genuinely means "never read the value", which is what the categorisation predicate says it tests — but invalid_value at path=[] can also come from z.literal / refine, where the semantics are not uniformly "rejected the node wholesale". Relaxing the predicate moves two rules at once (the candidate set and the content-discrimination abstention set), so the census has to cover both before the change, exactly as PR fix(app-shell): 唯一候选规则 — union 只剩一个成员读过值时,给出它的具名诊断 #3693 declined to do in passing. The caveat comment left in memberRejectedNodeType is deliberate and must be deleted in the same change that makes it false.

    Stale-premise check: the predicate and both measured rows are from PR #3693, merged hours ago; nothing has landed on that path since. Premise holds.

    No target:<major>: the path is correct today and only the message is generic — no shipped-surface defect.

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


    Generated by Claude Code

  4. yinlianghui commented on Aug 7, 2026

    @yinlianghui
    CollaboratorAuthor

    验收 ACCEPT → PR #3706(session_01GTRjn8xBqp75dk7kFupVRt)。停手条款的模范执行 — 测量普查 15 形状 ×3 定性,两候选谓词各有退化(含碎一条 #3693 CANARY),按「每处变化须严格改善」否决放宽;交付物是把测量钉成 14 条只加不改的现状钉(被否决谓词日后被加会立即红)。

    已核:CI 17 项全 completed 零失败;+196/−0 只加不改;六组扰动预测逐条命中;零行为 PR 的逆向方向正确反置并如实注明。

    裁决记录:

    1. 「停手也要留下牙齿」记入方法库:否决一个改动的测量不该只活在 PR 正文里 — 钉成测试让否决可执行。
    2. 误选核对(B 的伤害全来自去激活而非选错)与内容判别适用面不动的证明 — 边界完整。
    3. 新发现 metadata-admin:唯一候选规则存在一个 5 改善/0 退化的「证据深度」谓词,但它换掉了规则的理据 — 需设计裁决 #3707(证据深度谓词,5/0 带单调性证明,但属新偏好排序)入池,优先级排 objectstack#6391 后 — 定位正确;spec 侧 enum|literals 混排的跨仓观察记录不越界开卡,对。

    诊断程序四级账目终态:#3606/#3626/#3678 已落,#3694 测量否决,#3707/objectstack#6391 池中待设计裁决。


    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