Skip to content

refactor(lint): one reference-integrity entry point + the HotCRM residual audit (#3583 D5/§6.4) - #3818

Merged
os-zhuang merged 3 commits into
mainfrom
claude/app-metadata-validation-midr20
Jul 28, 2026
Merged

refactor(lint): one reference-integrity entry point + the HotCRM residual audit (#3583 D5/§6.4)#3818
os-zhuang merged 3 commits into
mainfrom
claude/app-metadata-validation-midr20

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#3583 收口的两件事:方案 §5 D5(接线漂移)和 §6.4(残留审计)。没有新规则。

1. D5 —— 一个入口,终结接线漂移

六条回答同一个问题(「这个名字解析得到东西吗?」)的规则,此前是手工接进三个命令的:validate / lint / compile 各自维护一份 import 和一处调用点。落一条规则要记三个地方,漏一个就意味着同一个 stack 因为作者跑了哪个命令而得到不同结论 —— 方案 §2.2 点名的正是这个。六条规则下来,每条都付了三次手工编辑的代价。

validateReferenceIntegrity(stack) 按序跑 REFERENCE_INTEGRITY_RULES 并合并结果。加规则从此是这个列表里的一行,命令侧不动。lint.ts 少了五段几乎一样的 for 循环,validate.ts/compile.ts 少了六路 spread。

两处刻意的设计:

  • 成员是写死的列表 + 对应的测试:规则要进套件得经过 review,而不是顺手混进来。这份列表同时就是「哪些规则会在这条路径上跑」的答案。
  • 套件测试为每个成员各喂一个真实实例,断言每条都出 finding。一个静默不再被调用的成员,和一个干净的 stack 是无法区分的 —— feat(lint): page-component field bindings + non-dashboard chart bindings (#3583) #3684 那个死掉的 quick-actions 检查就是这么通过自己测试的。

os doctor 刻意不改:它只跑 validateWidgetBindings,本质是环境体检(node 版本、配置存在性、循环 lookup),不是作者侧门禁;给它接套件是「doctor 是干什么的」这个产品决策,不是接线清理。这条残留不对称写进了模块文档,免得被重新发现一遍。

行为不变:三个示例应用(0)与 HotCRM 语料(逐规则计数不变)结果完全一致。

2. §6.4 —— HotCRM 残留审计

对着原审计读的同一份语料(hotcrm @ 8b28fa2,v2.2.2,~18k 行)重跑,23 条 finding,未见误报,逐类对上 issue 原文:

规则 条数 issue 类别 已发布实例
object-reference-unknown 4 1b 四个仪表盘的 optionsFrom.object: 'user'(平台对象是 sys_user
action-name-undefined 5 3 mass_update / mass_delete / assign_owner + edit / delete
chart-measure-unknown 4 7 报表 yAxisamount / case_number 而非 measure
translation-target-unknown 6 9 apps.crm_enterprise.navigation.group_products / .group_analytics × 3 locale
object-reference-unregistered-platform 2 2 导航 sys_approval_process
nav-object-ungranted 2 8 crm_knowledge_articlecrm_forecast 六个权限集都没授予

三件值得单独记的事:

  • 第 4、5a 类报 0,且这个 0 是实的:往 HotCRM 的 record:highlights 组件注入一个假字段,页面规则从 0 变 3 —— 遍历确实走到了页面,语料在这两类上现在就是干净的(HotCRM 在审计之后已经修过)。
  • 语料在发布前抓到了一个误报类:~40 条 _views 键被误报,因为 view record 是容器,对象绑定在 list.data.object 里而不是记录根上。示例应用漏掉它,是因为它们的 bundle 一条 _views 键都没有 —— 所以 §6.1 的误报地板得按分支读,不能按规则读
  • HotCRM 已经对着 dev 版 spec 完全解析不过(24 个 Zod 错误:enable.trash/enable.mru、非 script action 带 body)。既有漂移、与本次无关,但它说明了 lint 走原始配置这件事的价值:一个钉在已发布 spec 上的应用,可能对着 main 根本 validate 不了

明确接受的缺口(各自带证据):hook body 写入集(D4,已在作者界面标注)、knowledge indexes(D1 —— stack 里没有定义位,2 条引用天然不可解析)、skill 交接(自由文本,§7 非目标)、R8 选项值字面量(Tier-B,需先出验证说明)。

唯一还能建的缺口是 R7:HotCRM 声明了 8 条 agent→skill、16 条 skill→tool 引用,而这个 stack 声明的 tool 数是 0 —— 16 条全是死的,和原审计说的一模一样。但它得先定 D1(spec 加定义位,还是标 [EXPERIMENTAL])和 D2(内核运行时注册的 skill/tool 怎么静态看待),这两个是 spec 决策不是 lint 决策,所以应当独立成 issue 而不是把 #3583 一直挂着。

验证

  • 测试:lint 501(新增 5 条套件测试)、cli 682 全过。
  • 门禁:eslintcheck:nul-bytescheck:doc-authoring 干净;lint / cli build(含 DTS)通过。
  • 三个示例应用 reference-integrity 类 finding 仍为 0;HotCRM 逐规则计数与重构前完全一致。

Refs #3583 · #3806(R6)· #3698(R5)· #3684(Phase 2)· #3657(Phase 1)· #3640(方案)

🤖 Generated with Claude Code

https://claude.ai/code/session_015r31hzuSN19iK8ATRPcCpS


Generated by Claude Code

claude added 2 commits July 28, 2026 07:14
 D5)

Six rules answering the same question — "does this name resolve to anything?"
— were wired by hand into three CLI commands. `validate`, `lint` and `compile`
each carried their own import list and their own call site, so landing a rule
meant remembering three places, and forgetting one meant the same stack got a
different verdict depending on which command the author ran. The assessment
(§2.2) named that drift as the enemy and (§5 D5) asked for this entry point
once Phase 2 landed; six rules in, it has cost three hand-edits per rule.

`validateReferenceIntegrity(stack)` runs `REFERENCE_INTEGRITY_RULES` in order
and returns the concatenated findings. Adding a rule is now a one-line edit to
that list — the commands do not change. `lint.ts` loses five near-identical
for-loops; `validate.ts`/`compile.ts` lose their six-way spreads.

Membership is deliberately a written-out list, mirrored by a test, so a rule
joins the suite by review rather than by accident. What belongs: rules that
resolve a NAME against what a stack declares. What does not: shape checks
(view containers, responsive styles, seed replay/state) — a different question
with its own call sites.

The suite test runs one live instance per member and asserts a finding from
each. A suite that silently stops invoking a member is indistinguishable from
a clean stack — exactly how the dead quick-actions check in #3684 passed its
own tests.

`os doctor` is NOT converted: it runs only `validateWidgetBindings` and is an
environment health check, not an authoring gate, so adopting the suite there
is a product decision about what `doctor` is for. Named in the module doc so
the remaining asymmetry stays visible.

Behaviour-preserving: identical findings on all three example apps (zero) and
on the HotCRM corpus (24, unchanged per rule).

Refs #3583

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015r31hzuSN19iK8ATRPcCpS
… (§6.4)

§6.4 asked for a re-run of the audit after the rules landed, so the issue could
close with an explicit accepted-gap statement instead of silence. This is that
re-run, against the same corpus the original audit read (hotcrm @ 8b28fa2,
v2.2.2, ~18k lines).

Results: 23 findings, no false positives, mapping category-for-category onto
the issue's list — `optionsFrom.object: 'user'` on four dashboards, the three
undefined bulk actions plus two row actions, four report axes naming raw
fields, the `sys_approval_process` navigation, two nav-exposed objects granted
by none of the six permission sets, and six orphan translation keys.

Three things worth recording beyond the counts:

- Categories 4 and 5a report zero, and the zero is real: injecting a bogus
  field into HotCRM's `record:highlights` components moves the page rule from
  0 to 3, so the walk reaches the pages and the corpus is simply clean there.
- The corpus caught a false-positive class before release (~40 `_views` keys),
  because a view record is a container whose object binding lives inside
  `list.data.object`. The examples missed it since none of their bundles carry
  `_views` keys at all — so §6.1's false-positive floor has to be read per
  branch, not per rule.
- HotCRM no longer parses against the dev spec at all (24 Zod errors:
  `enable.trash`/`enable.mru`, `body` on non-script actions). Pre-existing
  drift, unrelated to this work, but it is why the lint path taking raw config
  matters: an app pinned to a published spec can be un-`validate`-able against
  main.

Accepted gaps are named with their evidence: hook body write sets (D4,
documented at the authoring surfaces), knowledge indexes (D1 — no definition
site, 2 refs unresolvable by construction), skill hand-off (free-form prompt
text, §7 non-goal), and R8's option-value literals (Tier-B, needs a
verification note first).

The one buildable gap left is R7: HotCRM declares 8 agent→skill and 16
skill→tool references against a stack with zero tools — every one dead, as the
original audit reported. It needs D1 and D2 decided first, which are spec
questions rather than lint ones, so it belongs in its own issue.

§5 D5 is also marked done, pointing at the suite entry point.

Refs #3583

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

vercel Bot commented Jul 28, 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 28, 2026 7:19am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests size/m labels Jul 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/lint.

19 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/cli)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, @objectstack/lint)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint)
  • content/docs/plugins/packages.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli)
  • content/docs/releases/v16.mdx (via @objectstack/cli)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

The suite adds public API to @objectstack/lint (validateReferenceIntegrity,
REFERENCE_INTEGRITY_RULES and its types), so it releases as a minor there and
a patch on the CLI, whose behaviour is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015r31hzuSN19iK8ATRPcCpS
@os-zhuang
os-zhuang marked this pull request as ready for review July 28, 2026 07:20
@os-zhuang
os-zhuang merged commit f022c4d into main Jul 28, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/app-metadata-validation-midr20 branch July 28, 2026 07:33
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.

2 participants