Skip to content

test(cli): 钉住三个命令都跑 reference-integrity suite(#4384) - #4402

Merged
os-zhuang merged 1 commit into
mainfrom
claude/authoring-wiring-guard
Jul 31, 2026
Merged

test(cli): 钉住三个命令都跑 reference-integrity suite(#4384)#4402
os-zhuang merged 1 commit into
mainfrom
claude/authoring-wiring-guard

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4384

这个 PR 补的是什么

#4394 已经修掉了那一例 —— validateReadonlyFlowWrites 手工接进 os validateos compile,唯独漏了 os lint,而它是 error 级,于是 os lint 长期放行 os compile 会拒绝的 stack。

但它没有修掉失败模式本身:今天仍然没有任何东西能阻止下一条规则被接进三个命令里的两个。

而这类缺陷的特点是不会有任何测试变红 —— 每个命令自己的测试都过,规则的单测也过,唯一症状就是三个命令对同一个 stack 给出不同答案。上一次就是这么从 #3425 一直活到 #4394 的,期间 suite 头注释里把它称作 "the standing proof of the drift the suite exists to end" —— 一条注释在干测试的活

钉住的不变量

os lintos compile 的门禁集。

lint 是廉价预检,compile 是门禁。lint 绿、compile 红,预检就没有存在意义;对 agent 更糟 —— 剩下的选择只有"全量重验"(慢)或"学会不信任这个信号"(危险)。

三条断言

  1. 三个命令都调用 validateReferenceIntegrity;
  2. 三个命令都直接 import suite 成员 —— 第二个调用点总是从这行 import 开始,所以卡 import 能堵住"加了 import 但还没加调用"的那个窗口;
  3. suite 非空且含 validateReadonlyFlowWrites —— 防止前两条在 suite 被清空或导出改名后空转通过

为什么扫源码而不是打桩

vitest 会把 import 内联进 transform,所以对 @objectstack/lint 打 spy 证明不了命令文件到底 reach 了哪些符号 —— 和 lazy-deps.test.tssrc/ 是同一个理由。

suite 内容的行为覆盖在 @objectstack/lintreference-integrity-suite.test.ts;本文件只守 suite 与三个调用点之间那道缝。

反向验证

不是"今天能过"就算数。在 compile.ts 里加回一行直接 import,它确实失败:

× compile.ts does not import a suite member directly

范围

纯测试,无运行时/行为变更。@objectstack/cli 65 文件 / 636 测试全绿,typecheck 干净。空 changeset。


顺带说明为什么只提这一条:我原本按 #4384 的分析做了一版"家族 + 组合层"(把 suite 的成员判据和"哪些命令跑"拆开),做到一半发现 #4394 已经先合入了。实测确认症状已消失(同一 fixture 下 os lint 现在 exit 1),所以那版重构的核心价值归零,我 abort 了。

剩下一个可以讨论但不在本 PR 范围的点:validateReadonlyFlowWrites 问的是"名字解析得到、但写会不会生效",而 suite 的判据写的是"名字能否解析"。#4394 的理由是"它走的是同一张 map"——这是邻近性论证。要不要为此调整 suite 的判据表述,是维护者的取舍,我没有在这里动它。

🤖 Generated with Claude Code

…ite (#4384)

#4394 removed the instance — `validateReadonlyFlowWrites` was hand-wired into
`os validate` and `os compile` and never into `os lint`, so an `error`-level
gate left `os lint` returning clean for stacks `os compile` refuses. It did not
remove the failure MODE.

A rule wired into two commands out of three produces no failing assertion
anywhere: every command's own tests pass, the rule's unit tests pass, and the
only symptom is the three commands disagreeing about the same stack. That is how
the last one survived from #3425 until #4394, with the suite's own header naming
it "the standing proof" of the drift the suite exists to end — a comment doing a
test's job.

The invariant worth pinning is `os lint` ⊇ `os compile`'s gate set: lint is the
cheap pre-flight, compile is the gate, and a green lint followed by a red
compile makes the pre-flight worthless — worse than worthless for an agent,
whose remaining options are re-verifying everything or learning to distrust the
signal.

The guard asserts each command calls `validateReferenceIntegrity` and that none
imports a suite member directly — the import is what a second call site starts
with, so catching it closes the window between adding the import and adding the
call. It scans source rather than spying, for the same reason lazy-deps.test.ts
scans src: vitest inlines imports through its transform, so a module-cache probe
cannot prove which symbols a command file actually reaches for. A third
assertion keeps the other two from passing vacuously if the suite were emptied
or its export renamed.

Verified to FAIL on a reintroduced direct import in compile.ts, not merely to
pass today. Test-only; no runtime or behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 11:41am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jul 31, 2026
@os-zhuang
os-zhuang merged commit 27f9072 into main Jul 31, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/authoring-wiring-guard branch July 31, 2026 11:53
os-zhuang added a commit that referenced this pull request Jul 31, 2026
…4340 后续) (#4417)

* fix(lint,cli): os lint / os compile 不再放行一个 os validate 会拒绝的 react 页面 (#4340 后续)

`validateReactPageProps` 只手工接在 `os validate` 上,`os lint` 和 `os compile`
从来没跑过它。在 showcase 的 react 页面植入一处 gating 违规
(`<ListView filters={['no_such_col','=',stage]}>` —— 谓词命中不了任何行,
SqlDriver 吞掉 "no such column" 后返回 [],列表回空且与「本来就没数据」无法区分)
实测:

              os lint      os compile     os validate
  修复前      exit 0 放行   exit 0 放行    exit 1 拒绝
  修复后      exit 1 拒绝   exit 1 拒绝    exit 1 拒绝

#4340 之后这条规则已经是整个 react 页面表面唯一的字段解析闸门:<ListView> 的
columns/fields/sort/grouping/userFilters、<ObjectForm> 的
fields/initialValues/sections/subforms、record:* 一族(与元数据表面共用同一张
COMPONENT_FIELD_SPECS)、<ObjectChart> 的 aggregate/axes,以及 searchableFields。
所以漏接不是少几条警告 —— 而是这些绑定在 build 路径上完全没人看,包括其中会 gate
的那些。

现接入 REFERENCE_INTEGRITY_RULES,`os validate` 那处手工接线随之删除,三个命令的
答案由构造保证一致。这正是 suite 设立要终结的漂移(#3583 §5 D5),也是
validateReadonlyFlowWrites 在 #4394 里刚走过的同一条路:那次是「一张 map、
两个检查、两套命令集合」,这次是「一次 JSX parse、七个 rule id、一套命令集合」。

按 charter,react-prop-missing-required / react-prop-typo 是 shape 而非解析问题,
本不属于 suite。它们随行的理由与 validateActionBodyWrites 完全相同(其注释已写明):
落在同一次 parse 的同一份 source 上,拆成第二个 member 就要把每个 react 页面
parse 两遍,而改回手工接线正是 suite 要终结的那种漂移。同时更正了那条注释里
"The ONE member here that emits two rule ids" 的说法 —— 现在不止一个。

规则行为零变化:id、严重级、文案都不动;输入也不变(`os validate` 原本就传
result.data,suite 拿到的是同一个)。#4402 的接线守卫会在下次有人想再手工接一条
规则时直接报错——本次删除 validate.ts 的直接 import 也正是被它逼出来的。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rK2McPogrTJBKdUsThrGs

* docs: validating-metadata 反映 react 页面字段绑定现在三个命令都跑

本 PR 把 react 页面的字段绑定检查从「只在 os validate」变成「suite 成员,三个命令
都跑」,这份文档有三处随之失真 —— 而 docs-drift 的包级扇出恰好没点到它(它按
@objectstack/cli / @objectstack/lint 列了 20 份,漏了语义上唯一真正耦合的这份)。

- "one gate, two entry points" 表补一行 React page block field bindings(两列都 ✓)。
- 表下那句把 "JSX/React page sources" 整体算作 os validate 独有 —— 现在只有
  「源码能否 parse」这个 SHAPE 闸门是独有的,里面的字段绑定属于 reference-integrity,
  suite 跑到哪它就跑到哪(含 os lint)。改写为分开陈述,并记下这里曾经的漂移与
  #4384 的接线守卫。
- 示例 os validate 输出里的 `→ Checking React-source page props (ADR-0081)...`
  随手工接线一并删除,已按真实 CLI 输出核对:示例里的每一行 step 现在都能在
  showcase 上逐字复现(comm 比对为空)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012rK2McPogrTJBKdUsThrGs

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[lint/cli] validateReadonlyFlowWrites 仍未接入 os lint —— 一条 gating error 只在 validate/compile 跑

1 participant