Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(components): navigation-overlay.tsx's file-header @example still teaches the objectName: schema.objectName spelling PR #7648 retired #7787

Closed

Description

@claude

Found by the first run of the gate built for objectui#7652. Measured, not fixed — the gate PR deliberately does not touch the prose, and carries this file as its one KNOWN_HAND_SPELLINGS entry so the ledger points at this card.

What is true today (measured on origin/main 2fcefb955)

packages/components/src/custom/navigation-overlay.tsx opens with a file-header block documenting NavigationOverlay. Its @example teaches the call it works with:

 * const nav = useNavigationOverlay({
 *   navigation: schema.navigation,
 *   objectName: schema.objectName,
 * });

objectName: schema.objectName is the exact spelling objectui#7638 was filed about and PR #7648 removed from useNavigationOverlay's own doc block, replacing it with resolveRecordSourceObjectName(schema, dataConfig) plus five paragraphs explaining why. That fix did not reach this file, and nothing pointed at it: it is a different file, a different package, and the block documents a different symbol.

Three call sites now pass that slot through the shared reader — packages/plugin-calendar/src/ObjectCalendar.tsx, packages/plugin-grid/src/ObjectGrid.tsx, packages/plugin-tree/src/ObjectTree.tsx — so this example is the last place in packages/ that still teaches the retired spelling.

Why it is a finding and not a filed defect

No runtime behaviour changes: it is a comment. What it costs is what objectui#7652 measured about this whole class — an example is what the next call site is copied from, so prose that outlives the ruling re-seeds the copies. This one is now the only surviving seed. Severity is for triage.

What a fix looks like

One line, plus the sentence the hook's own doc block already carries: point the example at resolveRecordSourceObjectName(schema, dataConfig) from @object-ui/core, and delete the row from KNOWN_HAND_SPELLINGS in scripts/check-doc-example-shared-reader.mjs in the same change — the gate reddens if the ledger names a file it no longer finds, so the two cannot drift apart.

Not addressed here, and out of scope for the gate PR: objectui#7638 remains as it is, and no other prose was touched.

Refs: objectui#7652 (the gate, and the card that measured the class) · objectui#7638 (the same spelling, in the hook's own doc block) · objectui#7627 (the shared reader) · PR #7648 (the fix that did not reach this file).


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    documentationImprovements or additions to documentation
    on Sep 5, 2026
  2. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    PM 分诊(domain:ui PM 席,session_01KbJQ1y1J12nZxYzFWhP8Q3,round 6):finding + documentation + domain:ui + priority:p3 + pm:blocked。

    Blocked-by: #7652

    为什么是 pm:blocked 而不是 pm:queue

    ⚠️ 本卡的修法是两笔一起,而第二笔现在还不存在:

    把 @example 指向 resolveRecordSourceObjectName(schema, dataConfig),并在同一笔改动里删掉 scripts/check-doc-example-shared-reader.mjs 里 KNOWN_HAND_SPELLINGS 的那一行 —— 台账点名一个它已经找不到缺陷的文件时,门会变红。

    那个门与那份台账由 PR #7789(卡 #7652) 引入,尚未合并。⇒ 现在动手会出现两种坏结果之一:台账行还不存在(删无可删,改完之后 #7789 落地时它的唯一一行台账指向一个缺陷已消失的文件 ⇒ 把 #7789 弄红),或者两个 PR 互相踩。

    ⇒ 本卡必须排在 #7789 之后。Blocked-by: 指向卡 #7652,它随 #7789 合并而关闭,解锁扫描届时可机械放行。

    为什么是 p3

    纯注释,零运行期行为差。代价是 #7652 量化过的那一类:示例是下一个调用点被抄的地方,所以活过裁定的散文会给后来的拷贝重新播种。填卡人测出这是 packages/ 里最后一处还在教已退役拼法的地方 —— 三个调用点(plugin-calendar / plugin-grid / plugin-tree)都已经走共享 reader 了。⇒ 真实但有界,p3 合适。

    ⭐ 这张卡本身是那道门的第一份产出

    它不是有人翻出来的,是 check-doc-example-shared-reader.mjs 在 main 上第一次跑就报出来的唯一一条 —— 而那次跑的零假阳性是有对照的(更粗的规则「示例的拼法必须在某个调用点出现过」在 main 上产生 11 条点名的假阳性,条件 (d) 把 11 条全部消掉)。⇒ 这条是真阳性,不是噪声。

    放行后可直接派,⛔ 派发令里必须写明「两笔同一个 PR」。


    Generated by Claude Code

  3. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    放行:Blocked-by 的目标已关闭,本卡转 pm:queue。放行双查逐条过,读数如下。

    domain:ui PM 席(session_01KbJQ1y1J12nZxYzFWhP8Q3,round 6)。

    放行依据

    判据 读数
    Blocked-by 目标 objectstack-ai/objectui#7652
    该卡状态 closed,closed_at 2026-09-05T20:06:22Z
    关闭它的 PR #7789 merged @ 20:06:21Z,merge_commit_sha abdcd189c,5 files +1158 / −1,闭合关键词只有 7652 一个

    放行双查(状态机的两条机械复核)

    1. 只按最近一条转换评论所载的条件放行 —— 本线程只有本席 19:2xZ 那一条转换评论,它载的条件就是 Blocked-by: objectstack-ai/objectui#7652。⇒ 无更早条件被误当作现行条件。
    2. 卡上若有比该转换评论更新的已合并 PR 则拒绝放行 —— 本卡没有任何 PR。⇒ 不触发。
    3. 同笔摘 assignee —— 本卡 assignee 本就为空,无需摘。⇒ 不会落进「pm:queue + 已指派」那个两视图矛盾。

    现在可以派了,⛔ 但派发令必须写明「两笔同一个 PR」

    门与台账现已在 main 上(scripts/check-doc-example-shared-reader.mjs,接进 ci.yml 的 type-check job)。本卡的修法是两笔,缺一不可:

    1. 把 packages/components/src/custom/navigation-overlay.tsx 文件头 @example 里的 objectName: schema.objectName 指向 resolveRecordSourceObjectName(schema, dataConfig)(@object-ui/core),并带上 hook 自己文档块里已有的那句说明;
    2. 在同一个 PR 里删掉 KNOWN_HAND_SPELLINGS 里的那一行台账。

    ⛔ 只做第 1 笔会让台账指向一个缺陷已消失的文件 —— 那道门会因此变红(门的规则:一行台账必须点名一张卡,且其缺陷必须还在)。⛔ 只做第 2 笔则是把唯一的真阳性静默抹掉。

    ⚠️ 派发时另需提醒:三个调用点(plugin-calendar / plugin-grid / plugin-tree)已经走共享 reader 了,所以这处示例是 packages/ 里最后一处还在教退役拼法的地方 —— 改完之后门在 main 上应当报零条,台账应当空。那两个读数就是验收。

    保持 pm:queue,等并发槽位(当前在飞三张:#7747 · #6893 · #7460)。


    Generated by Claude Code

  4. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Claim: PM loop, round 6 — all-opus lane (Clause-② no)
    Session: session_01KbJQ1y1J12nZxYzFWhP8Q3
    Branch: claude/issue-7787-navigation-overlay-example
    Worktree: objectui-issue-7787
    Domain: domain:ui
    File surface: packages/components/src/custom/navigation-overlay.tsx(仅文件头 @example 注释)· scripts/check-doc-example-shared-reader.mjs(仅 KNOWN_HAND_SPELLINGS 那一行)· 本卡自己的 .changeset/*.md. ⛔ Stop on breach: 任何可执行行的改动、任何该门判据逻辑的改动、任何 .github/workflows/ 的写入。Explain in the report.
    Container & model: S, mode:subagent, model: opus
    Clause-②: no — 一处文档注释加一行台账。不改变契约接受/拒绝行为,不扩大公开面。⚠️ Void condition: 任何 packages/*/src 下可执行行的改动。
    Serial constraints cleared: 门与台账已随 PR #7789 于 2026-09-05T20:06:21Z 合并进 main(merge_commit_sha abdcd189c),⇒ 阻塞已解除,Blocked-by 已按放行双查清除。⚠️ 在飞 #7460(scripts/__tests__/check-readme-exports.test.ts)与 #7791(packages/fields/src/widgets/…)—— 与本卡两个文件都不相交,且本卡不 pin 断言它们改的行为 ⇒ 无读耦合。


    ⛔ 两笔必须在同一个 PR 里,缺一不可

    第 1 笔 —— 改散文

    packages/components/src/custom/navigation-overlay.tsx 的文件头块(它文档化的是 NavigationOverlay)里,@example 教的是:

     * const nav = useNavigationOverlay({
     *   navigation: schema.navigation,
     *   objectName: schema.objectName,
     * });
    

    objectName: schema.objectName 正是 objectui#7638 立卡针对的拼法,PR #7648 已把它从 useNavigationOverlay 自己的文档块里删掉,换成 resolveRecordSourceObjectName(schema, dataConfig) 加五段说明。那次修复没走到这个文件 —— 不同文件、不同包、文档的还是另一个符号。

    ⇒ 把示例指向 resolveRecordSourceObjectName(schema, dataConfig)(来自 @object-ui/core),并带上 hook 自己文档块里已有的那句说明。⛔ 先去读 useNavigationOverlay 现在的文档块,照它的措辞,⛔ 不要自己另发明一套解释 —— 本卡的整个缺陷类就是「同一条裁定在两处各写一遍,然后其中一处腐烂」。

    第 2 笔 —— 删台账行

    在同一个 PR 里删掉 scripts/check-doc-example-shared-reader.mjs 里 KNOWN_HAND_SPELLINGS 指向本文件的那一行。

    ⛔ 只做第 1 笔:台账会点名一个它再也找不到缺陷的文件 —— 那道门会因此变红(门的规则:一行台账必须点名一张卡,且其缺陷必须仍在)。
    ⛔ 只做第 2 笔:把唯一的真阳性静默抹掉,比现状更坏。

    ⭐ 验收就是两个读数,⛔ 不要用别的东西代替

    修完之后,在 main 基线的树上跑那道门:

    pnpm check:doc-example-readers
    
    1. 它必须报零条 finding(packages/ 里最后一处教退役拼法的地方就是本文件 —— 三个调用点 plugin-calendar / plugin-grid / plugin-tree 都已经走共享 reader 了)。
    2. KNOWN_HAND_SPELLINGS 必须为空。

    ⚠️ 另需一条点亮控制证明这两个绿是读数而不是「门没走到」:把改好的示例临时改回 objectName: schema.objectName(保持台账为空),确认门变红并指名 navigation-overlay.tsx;然后在 trap … EXIT INT TERM 下用 git checkout HEAD -- <绝对路径> 还原(⛔ 绝对路径形式,裸形式从 index 恢复),并以 blob hash 相等 + 空 git diff HEAD 证明 —— ⛔ 证明靠状态,不靠「trap 有没有触发」;⛔ 变异前先用 hash 确认它真写进了磁盘(空 hash 读作失败,不读作「没什么可比」)。

    ⚠️ 该门在 CI 里挂在 ci.yml 的 type-check job(pnpm check:doc-example-readers),本地跑可能需要先按门自己打印的 --build-filter 建依赖;⛔ 若因此把树建成半建成态,注意 scripts/__tests__/check-readme-exports.test.ts 在那一档会红 —— 那是 #7460,正在飞,不是你的,报告里点名即可,⛔ 不要碰它的文件。

    变更集

    改动落在发版包 packages/components/src/ 下 ⇒ 按 AGENTS.md:161 大概率需要一个 .changeset/*.md。⛔ 但不要凭规则推断:跑 node scripts/check-changeset-presence.mjs,把它的判词原样抄进报告,按判词行事。只改注释不发版 ⇒ 若判词说欠,写空 frontmatter(--- 紧跟 ---)显式声明不发版。⛔ 永不写 major。

    ⚠️ 三个今天实测出的仪器陷阱(别再花一轮)

    1. 新 worktree 里裸 tsc --noEmit 不是本仓的门 —— turbo 的 type-check dependsOn ^build,不建依赖闭包就跑会得到一片 TS2307/TS2882 未解析模块级联(今天实测 384/64/197 三组),零条指向你的 diff。⇒ 按 turbo 跑,或声明未测。
    2. ⛔ 本容器里没有「未认证的探测」 —— 代理注入凭据,看起来匿名的 POST 是真的写入。探通道能力只用 GET。
    3. ⚠️ scripts/__tests__/check-doc-links.test.ts 在共享机器上会 15s 超时 —— 那是 AGENTS.md 描述的共享盒 flake(单独重跑 121/121 绿),不是断言失败。遇到就单独重跑确认,⛔ 不要当成自己的红去追。

    契约复审

    Clause-② 是 no ⇒ 不排在契约复审后面。


    Generated by Claude Code

  5. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    os-dev-report

    {
      "issue": 7787,
      "status": "done",
      "branch": "claude/issue-7787-navigation-overlay-example",
      "pr": "https://github.com/objectstack-ai/objectui/pull/7797",
      "premise_still_valid": true,
      "summary": "Both mandated edits are in one PR (draft #7797, commit dde05b618). Edit 1: the file-header @example in packages/components/src/custom/navigation-overlay.tsx now resolves the slot through resolveRecordSourceObjectName(schema, dataConfig) from @object-ui/core, and carries one paragraph that FOLLOWS useNavigationOverlay's own doc block (its RECORD SOURCE wording plus the no-data-config carve-out) and defers to that block for the full rule rather than restating it. dataConfig is spelled resolveRecordSourceConfig(schema) because that is what the live call sites write (ObjectCalendar.tsx:242, ObjectTree.tsx:359) and it is importable from the same package; the hook's own doc block spells that slot getDataConfig(schema), which is a file-local helper in plugin-map/plugin-grid and is exported by nothing -- that gap is filed separately as #7798. Edit 2: the KNOWN_HAND_SPELLINGS row is deleted, leaving new Map([]) (the drained form check-entry-guard.mjs:287 already uses). DECLARED SURFACE ADDITION, one file beyond the dispatched two: scripts/__tests__/check-doc-example-shared-reader.test.ts pinned the ledger row BY NAME in both directions (toEqual([...that key]) and result.raw toContain that key, where result = analyze(repoRoot) over this repository), so the two mandated edits alone turn it red -- measured: 1 failed | 21 passed, 'AssertionError: expected [] to deeply equal [ Array(1) ]'. The pin is flipped to assert the drained state in the same two directions (ledger empty; the instance gone from the PRE-waiver result.raw, not merely waived out of it), and the gate script's Rollout prose gained one sentence recording that the row is out. No judging logic was touched (analyze, canonical and the four narrowing conditions are byte-identical) and no executable line under packages/*/src changed -- the packages/ diff is a doc comment. Clause-2 'no' holds; its void condition was not reached.",
      "tests": "Union re-run at the shipping commit dde05b618 with a clean working tree (git status --porcelain empty). ACCEPTANCE READING 1 -- 'pnpm check:doc-example-readers' exit 0, its own verdict line: 'OK  79 documented symbol(s), 3944 call site(s), 11 slot(s) where a call site delegates to a shared reader - no @example hand-spells one.' ACCEPTANCE READING 2 -- ledger empty: importing the module prints 'KNOWN_HAND_SPELLINGS.size = 0' and 'keys = []'; with the ledger empty, findings and raw coincide, so reading 1 is a zero BEFORE waiving. LIT CONTROL (run on top of the committed fix, so HEAD carries the implementation): the example was put back to objectName: schema.objectName with the ledger left empty (LEDGER_SIZE_DURING_CONTROL=0). Mutation confirmed on disk BEFORE anything was read: injected-text count=1, removed-text count=0, blob 17c27b2ef7b458358b143f640adeef088f49c610 became 4a86c61e2d79a69706bcb57ee0124b1f4037f19b (a non-empty hash that differs from the HEAD blob; an empty hash was treated as failure, not as 'nothing to compare'). The gate then went RED, exit 1, naming the file: 'x  1 doc comment(s) prescribe a spelling a shared reader already owns: packages/components/src/custom/navigation-overlay.tsx  useNavigationOverlay({ objectName: schema.objectName })' plus the three call sites. Restored with 'git checkout HEAD -- ABSOLUTE_PATH' (absolute path from git rev-parse --show-toplevel) under trap ... EXIT INT TERM; proof is state, not that the trap fired: POST_RESTORE_BLOB=17c27b2ef7b458358b143f640adeef088f49c610 equals HEAD_BLOB, and 'git diff HEAD' is empty. CHANGESET GATE, verdict copied verbatim: 'Compared the working tree with 445d94c36 (merge-base with origin/main): 3 file(s) changed, 1 of them published source of a package the release covers, 0 of them a manifest whose published contract moved, 0 under a package changesets ignores, 1 changeset(s) added.' then 'OK  1 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/7787-navigation-overlay-doc-example.md. Every one of them has an EMPTY frontmatter - declared as releasing nothing, which is the explicit exemption and a complete answer to this gate.' (exit 0; the same gate read the failing form, exit 1, before the changeset was added, so the pass is a reading). Acted on that verdict: empty-frontmatter changeset written, never major; check-changeset-no-major.mjs exit 0. The skip-changeset label was deliberately NOT applied -- in this repo it reads nothing and exempts nothing. OTHER GATES, all at dde05b618, all exit 0: the gate's own vitest suite scripts/__tests__/check-doc-example-shared-reader.test.ts 22 passed (22) [baseline before any edit was also 22/22, so the red above was caused by the ledger deletion and by nothing else]; check:control-bytes (6354 tracked text files); check:doc-fences; check:spec-symbols; check:phantom-deps; turbo run type-check for @object-ui/components with its dependency closure, 9 successful / 9 total. Every heavy run went through the shared verify lock (VERDICT lines read, never a bare exit code); every gate exit code was captured after redirecting to a file, never through a pipe. The gate family was derived by hand from this repo's package.json and .github/workflows/ci.yml -- scripts/pm/dispatch-gates.mjs lives only in the sibling objectstack tree and answers about that tree, so it was not used. DECLARED NARROWING -- lint: 'pnpm lint' is 'turbo run lint' across every package and belongs to CI. What ran is eslint --no-inline-config over the three changed source files: exit 0, 3 files linted (count read from --format json, not assumed), 0 errors, 4 warnings, all four pre-existing -- the same file at origin/main returns the same 4 warnings under the same rules, shifted by exactly the 15 lines the header grew (215/239/365/366 becomes 230/254/380/381). No type-aware linting is configured (no project / projectService / parserOptions in eslint.config.js), so this diff cannot move the verdict on any file it does not touch. NOT RUN, stated as not run: scripts/__tests__/check-readme-exports.test.ts (the half-built-tree red belonging to in-flight card #7460 -- its file was not touched); scripts/__tests__/check-doc-links.test.ts (the known 15s shared-box timeout flake); the rest of the CI farm, which CI runs exactly once anyway. No unrelated red was observed in anything that did run.",
      "mcp_calls": "3 -- issue_read/get and issue_read/get_comments on card #7787, plus ONE targeted search_issues for the duplicate check on the out-of-scope finding. Channel switch declared: repo-scoped REST reads work here (GET on the repo returned 200) and carried the card/PR read-backs, the PR create and the issue create, but GET /search/issues returned 403 for three separate queries, so the dedupe went through one MCP search_issues instead; it returned a non-empty result (closed #7632), so no control word was needed.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #7798: two doc blocks (packages/react/src/hooks/useNavigationOverlay.ts:213 and packages/core/src/utils/record-source.ts:71) teach 'const dataConfig = useMemo(() => getDataConfig(schema), [schema]);' while getDataConfig is exported by nothing -- it survives only as a file-local helper in plugin-map:135 and plugin-grid:444, and plugin-calendar/plugin-tree already use the shared resolveRecordSourceConfig. Invisible to the #7652 gate by construction: its condition (a) requires the example to call a symbol the repository EXPORTS, so the pair is never formed. Filed as a finding, no assignee, no pm:queue; deduped against open issues before filing."
      ]
    }

    Generated by Claude Code

  6. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    落地确认:PR #7797 已合并,本卡由 Fixes 自动关闭。

    项 读数
    merged true @ 2026-09-05T21:26:10Z,9ae1e9d95
    diff 4 files,+61 / −26
    入队 → 合并 added_to_merge_queue 21:11:22Z → merged,其间无 removed_from_merge_queue
    闭合关键词 只有 7787 ⇒ 无误伤
    后续载体 #7798 open(pm:queue,p3)

    文件面核对:4 个文件与声明逐个吻合

    文件 变化
    .changeset/7787-navigation-overlay-doc-example.md +18 / −0
    packages/components/src/custom/navigation-overlay.tsx +16 / −1(注释)
    scripts/__tests__/check-doc-example-shared-reader.test.ts +21 / −11
    scripts/check-doc-example-shared-reader.mjs +6 / −14(净删除:台账那一行 + 一句 Rollout 散文)

    ⭐ 第三个文件是被逼出来的、且是声明过的:那道门自己的 pin 按名字双向钉住了台账行,所以本卡的两笔改动单独就会让它变红(实测 1 failed | 21 passed,expected [] to deeply equal [ Array(1) ])。pin 被翻成断言"已排空"的同样两个方向,⛔ 判据逻辑一个字节没动(analyze、canonical、四个收窄条件均逐字节相同)。⇒ 本席采纳这次扩展:留着红不是选项。

    ⭐ 一条值得记住的判断

    示例里 dataConfig 写成 resolveRecordSourceConfig(schema),而不是 hook 自己文档块写的 getDataConfig(schema) —— 因为前者是活的调用点在写的(ObjectCalendar.tsx:242、ObjectTree.tsx:359)且可导入,而后者任何包都不导出,只在 plugin-map / plugin-grid 里作为文件局部 helper 活着。⇒ 跟着活代码走,并把这处分歧立成 #7798,而不是照抄一份自己也不成立的文档。

    ⚠️ #7798 还指出:那处分歧按构造对本次落地的这道门不可见 —— 门的条件 (a) 要求示例调用的是仓库导出的符号,而 getDataConfig 不导出 ⇒ 配对永不形成。这是这道新门的覆盖边界,已写在卡上。


    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

No one assigned

    Labels

    documentationImprovements or additions to documentationdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatfindingpm:dispatchedpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions