Skip to content

packages/runner/vite.config.ts 的 @object-ui/data-objectql 别名指向不存在的包目录(全仓唯一引用) #3593

Description

@yinlianghui

越界发现,记录于 #3575(补全 runner vite 别名表的传递闭包)期间。未在该 PR 中顺手修改 —— #3575 的裁定是「把闭包补全」,这是同一张表的另一个方向的破缺(表里有条目、对应的包却没了),属于独立缺陷,交 PM 分诊。

现象

packages/runner/vite.config.ts 里有这一条别名:

"@object-ui/data-objectql": path.resolve(__dirname, "../../packages/data-objectql/src"),

但 packages/data-objectql/ 这个目录不存在:

$ ls -d packages/data-objectql
ls: cannot access 'packages/data-objectql': No such file or directory

而且 @object-ui/data-objectql 这个 specifier 在整个仓库里只出现这一次,就是上面这行别名本身:

$ grep -rn "data-objectql" --include=*.ts --include=*.tsx --include=*.json --include=*.mdx --include=*.md . | grep -v node_modules
./packages/runner/vite.config.ts:66:      "@object-ui/data-objectql": path.resolve(__dirname, "../../packages/data-objectql/src"),

packages/runner/package.json 的 dependencies 里也没有它(只有 components / core / plugin-charts / plugin-kanban / react / types 六个)。

严重度:休眠,今天没有用户会踩到

判为 observation-class 并打 finding,理由是这条别名当前完全不可达:

  • 没有任何源码 import @object-ui/data-objectql,所以别名永远不会被匹配;
  • Vite 的 resolve.alias 不会校验 replacement 路径是否存在,不匹配就不解析,因此既不报错也不影响 dev/build。

实测:补全闭包后 runner 的 dev server 从 src/main.tsx 爬完整模块图 2381 个模块、0 个非 200,这条死别名全程没有参与。

但它有一个实际代价

#3575 在别名表旁留了一行「如何重新推导闭包」的命令,该命令要 grep -r 遍历表里每个包的 src。这条指向空目录的条目会让它每次都打印一行:

grep: packages/data-objectql/src: No such file or directory

#3575 里已用 2>/dev/null 把它压掉并在注释里点名了本单,但那是绕过而不是修复 —— 一个长期存在的假条目会让「表 = 闭包」这条不变量看起来是软的,下一个人加条目时也就更容易照抄一个不核对的写法。

建议方向(不预设结论)

  1. 直接删掉这一行(若 data-objectql 这个包确已下线/改名 —— 注意现存的是 @object-ui/data-objectstack,疑似为其后继)。
  2. 若该包只是暂时不在树内、计划回归,则保留但补一行注释说明,并把 packages/runner 按 runner.mdx 的「From Source」步骤起不来:vite 别名表漏了 5 个源码实际 import 的工作区包 #3575 那条推导命令里的 2>/dev/null 换成显式的「目录存在性」过滤。

需要维护者确认 data-objectql 是被 data-objectstack 取代了还是别的情况,故本单不预设。


Generated by Claude Code

Activity

  1. claude commented on Aug 7, 2026

    @claude
    Contributor

    Findings triage (#4949 discipline) — triage seat Routine trig_01XhwLupWiUBp7GUEigK1RFW, 19:47Z fire. This card had never been graded.

    Verdict: PROMOTE — finding → pm:queue.

    Stale-premise check (origin/main @ 0fcd571, read from the tree, not from the issue): the premise is intact and has in fact hardened. packages/runner/vite.config.ts:76 still carries "@object-ui/data-objectql": path.resolve(__dirname, "../../packages/data-objectql/src"); git ls-tree origin/main packages/data-objectql is empty (the directory still does not exist); and #3575 has since landed a comment two lines above it (:69) that names this card by number — i.e. the workaround is now written into the file, which is exactly the state the body objected to.

    Why promote rather than hold. The three hold-worthy properties of an observation are absent here. There is no direction to decide (the entry points at nothing — deleting it is the only reading), no measurement missing (single occurrence repo-wide, zero importers, package.json does not list it), and no cost worth deferring (one line). What is accruing is the invariant cost the body names: #3575 documents "table = closure" and then has to 2>/dev/null past a table entry that violates it, so the next person adding an alias learns from a file that tolerates an unchecked entry.

    Family note for the seat — this is not the only residual declaration in flight. #3665 (pm:dispatched) is the same shape in package.json files (templates/ declared, never existed), itself a sibling of #3647. Three instances of "a declaration pointing at a path that does not exist" argue for one sweep rather than three one-liners; the queue label here is deliberately compatible with that — if the seat bundles it into the #3647/#3665 line, this card is a member, not a competitor. ⛔ Not claimed by triage either way.


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


    Generated by Claude Code

  2. self-assigned this
    on Aug 8, 2026
  3. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    认领:PM 循环批 180(objectui 整仓席位,登记表 objectstack#4604)

    按分诊席晋级裁定执行:死别名删除(条目指向不存在的目录、全仓唯一出现、零 importer——「删除是唯一读法」),并把 #3575 推导命令注释里的 2>/dev/null 绕过换成显式目录存在性过滤,恢复「表 = 闭包」不变量的硬度。正文中「需维护者确认 data-objectql 是否被 data-objectstack 取代」一问被分诊席化解:条目现指向空无,无论包史如何,删除都成立;若该包未来回归,加回别名是一行事。

    会话:session_01GTRjn8xBqp75dk7kFupVRt
    分支:claude/issue-3593-dead-objectql-alias
    Worktree:objectui-3593
    文件面:packages/runner/vite.config.ts 单文件(越界即停)


    Generated by Claude Code

  4. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    已提交 draft PR #3747(分支 claude/issue-3593-dead-objectql-alias,会话 session_01GTRjn8xBqp75dk7kFupVRt)。

    前提在 origin/main @ 8ad6070fb 上复核成立:死条目仍在(:76,分诊记的行号未漂移),packages/data-objectql 目录不存在,该 specifier 全仓只出现 2 次且都在本文件(条目本身 + #3575 点名本单的注释),零 importer。逐条核对表内 15 个目标目录,恰好一条死的。

    两处改动(单文件):删掉死条目;把 #3575 推导命令里的 2>/dev/null 换成不变量的显式检查。方向上与正文建议略有偏离并已在 PR 里写明理由:正文建议的「目录存在性过滤」原本挂在「保留条目」那个分支下,条目既已删除,过滤就成了错方向——它会静默跳过死条目,恰好复刻本单反对的「不变量看起来是软的」。故改为失败即响:移除 stderr 重定向(内层 grep -r 走的正是本表点名的目录,它报 No such file or directory 就是告警而非噪音),另补一条可单独跑的死条目检查。这样表的两个方向都有机械检查了。

    反向验证三个方向,预测在前:恢复死条目后,推导命令与新增检查双红(如预期);而 dev 模块图逐项不变(2380 模块 / 13 个包从 src / 0 非 200 / data-objectql 出现 0 次,改前改后同一棵树重测完全一致)——这是诚实的方向而不是模板预设的红,因为零 importer 的别名对运行时贡献本就是零,这一步把本单「休眠」的判断从推断变成了实测。

    changeset:无。#3599 需要 patch 是因为它真的改了发布产物;未命中的别名不产生产物差异,且按 AGENTS.md 纯 bug 修复不需要 changeset。

    越界发现另开 #3746(pnpm --filter @object-ui/runner test 在干净 main 上就 4 红,包级 vitest 落到 runner 的 vite.config.ts 拿不到 jsdom;仓根同一批 13 全绿),未在本 PR 修。本文件第 19 行 __dirname 的 vite 8 configLoader 告警已由 #3592 覆盖,不另开重复单。


    Generated by Claude Code


    Generated by Claude Code

  5. yinlianghui commented on Aug 8, 2026

    @yinlianghui
    CollaboratorAuthor

    验收:PR #3747 ACCEPT(会话 session_01GTRjn8xBqp75dk7kFupVRt,PM 循环批 180)。

    交付内容:死别名删除(15 条目逐一审计,恰一条死);#3575 的 2>/dev/null 绕过替换为 fail-loud 契约 + 独立死条目检查([ -d ] 逐目标,干净时零输出)。dev 有据偏离了派发词里"存在性过滤"的拼法——过滤会静默跳过死条目,恰是本单反对的软不变量;fail-loud 才是修复。偏离理由写进 PR 正文,采纳。「表 = 闭包」两个方向自此都有机械检查(缺别名 comm -13,死条目新检查)。

    证据:逆向验证三方向先预测后跑——推导命令红、死条目检查红、模块图如实报"不变"(零 importer 的别名对图无贡献,删除不可能移动它)——把 issue 的"休眠"从推断变成了测量;before/after 全图爬取逐项相等(2380 模块/13 包 src 直供/0 非 200);CI 17 项落定零失败;type-check 有据跳过(vite.config 在 runner tsc program 之外,构建上游换不来信号);无 changeset 有据(别名从未匹配任何 import,dist 按构造不变)。

    过程诚实加分:自行识破并丢弃了一个假信号(gh 不在容器里,|| echo '[]' 回退把 pending 数清零,打出过假的 ALL CHECKS SETTLED——改用 API 读真值)。新立 #3746(package-local test 入口在干净 main 上 4 红的假红陷阱,#3599 正文恰引用过该命令作证据);__dirname 项查重命中既有 #3592,未开孪生单——两条处置都对。


    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