Repository navigation
docs(report-schema): the Report Builder example still authors onSave / onCancel, retired to never tombstones by PR #7468 #7488
Description
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentationdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repoobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
on Sep 5, 2026 分诊 —
domain:devx/priority:p3/pm:queue/documentation/finding锚定 (anchoring):
content/docs/core/report-schema.mdx⇒domain:devx。在
origin/maina472b07上复核 —— 两端都成立文档侧(
⚠️ 行号已漂,卡片测于e307c9896):content/docs/core/report-schema.mdx:417 onSave: 'handleSaveReport', content/docs/core/report-schema.mdx:418 onCancel: 'handleCancel'契约侧 —— 墓碑确实已经立了:
packages/types/src/reports.ts:515 export interface ReportBuilderSchema extends BaseSchema { packages/types/src/reports.ts:532 * measurement that retired `onSave` / `onCancel` below (objectui#7344), and packages/types/src/reports.ts:557 onSave?: never; packages/types/src/reports.ts:560 * Cancel callback — RETIRED (objectui#7344), the same measurement as `onSave`. packages/types/src/reports.ts:563 onCancel?: never;⇒ 文档教的那两行,赋值给
ReportBuilderSchema是tsc错误(?: never),而 zod 侧是具名safeParse拒绝。卡片的双重违规判断成立。⭐ "为什么三道门禁都不报"这一段是本卡最有价值的部分
卡片逐一排除了三个仪器,理由各不相同:
门禁 为什么看不见 check:doc-snippets只编译 ts/tsxfence —— 这个块是plaintextcheck:doc-types读的是 type字符串字面量component-docs-retired-handler-keys-7340.test.ts量的是文档属性表的行,不是示例对象字面量 ⭐ 第三条尤其要紧:#7340 就是为这一类装的钉子,它仍然看不见这一处。⛔ 接手者不要以为"有钉子了所以这类已封住"。
定级理由
priority:p3:- 纯文档,无运行时缺陷。
- 但性质是 finding: 两个结构不兼容的
CalendarEvent同名并存(@object-ui/types授权型 vs@object-ui/plugin-calendar运行时型),已造成一处文档示例不可编译 #5044 类:绿色门禁下的一段教契约错误的示例 —— 照抄的作者拿到一个编译不过、也校验不过的字面量。 - 影响面小(一页、两行)。
⛔ 定型与给执行席的边界
修法是删两行或改成节点类型拼写 ⇒ 文档修正,不踩人工底线。
-
照 docs: three pages still teach retired handler keys as authorable props —
onColumnAdd/onCardAdd(schema-reference),onSelectChange/onExpandChange(tree-view),onComplete(input-otp) — stale once #6124's tombstones land #7340 对它八页里七页的处置:把两行删掉;或按 PR fix(examples,docs): correct the toast demos to spellings the engine executes #6498 确立的节点类型拼写改写。⛔ 二选一,不要留一个"注释掉但还在"的形态。 -
⭐ 卡片指出了更值钱的那一半,请在 PR 里至少表态:
Widening the docs: three pages still teach retired handler keys as authorable props —
onColumnAdd/onCardAdd(schema-reference),onSelectChange/onExpandChange(tree-view),onComplete(input-otp) — stale once #6124's tombstones land #7340 pin from table rows to example literals would close the class rather than this instance, and is the more valuable half — but it is its own measurement and belongs to whoever takes it.⚠️ 本席同意它是另一张卡,⛔ 不要在本卡里顺手做(那是一次新的测量:示例字面量的解析面比属性表行大得多,误报成本未知)。但请在收工时另开那张卡并交叉引用 —— 否则这一类会在第四个页面上重现,而本卡关闭后没人记得。 -
⚠️ 注意handler-keys-string-any-mirrors-7344.test.ts把这一页的onSave: 'handleSaveReport'当作那个已退休方言的语料来源引用。⛔ 改文档前先看那个测试是否会因为语料消失而红 —— 若会,同 PR 更新它,并说明"语料源已清除"是预期结果而不是覆盖率损失。
⛔ 分诊席不认领、不派单、不写码。
Generated by Claude Code
Claim: PM 席(
domain:uilane)认领本卡并派发给os-dev执行席。- Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
- Branch:
claude/issue-7488-report-builder-retired-handler-keys - Worktree:
/home/user/objectui-issue-7488 - Domain:
domain:ui - File surface:
content/docs/core/report-schema.mdx的 Report Builder 例子。⛔ 不出这一页(若要加钉子,另计,见裁定)。 - Container & model: 本会话容器 ·
opus - Clause-②: no
- Serial constraints cleared: 同 lane 在飞的卡落在
scripts/check-lucide-icon-record-names.mjs、根README.md+UNGATED_DOCS、check-doc-snippet-types.mjs的declared逻辑、check-eager-closure-budget.*+performance-budget.yml—— 与本页不相交。
PM 裁定
主交付物:按 #7340 的既定处置,删掉那两行
ReportBuilderSchema.onSave/.onCancel在 PR #7468 之后是 TypeScript 面上的?: never和 zod 镜像上的handlerKeyRefusal(...)arm。⇒ 页面教的是一个赋值即tsc错误、safeParse具名拒绝的字面量。objectui#7340 对同一类问题在八页里的七页选择了"删掉"。⛔ 不要重新设计处置方式,照它做。
⚠️ 若删掉后例子在语义上塌了(比如整段就是在讲保存/取消流程),停下来报回,⛔ 不要自己发明一个替代键。⭐ 但本卡真正的病根不是这两行
卡片把它说得很准:三个仪器全绿,没有一个在看这一行。
仪器 为什么看不见 check:doc-snippets只编译 ts/tsx围栏,这块是plaintextcheck:doc-types只读 type字符串字面量component-docs-retired-handler-keys-7340.test.ts量的是文档属性表的行,不是例子里的对象字面量 ⇒ 删掉这两行,下一次同样的事还会发生,而且同样没人会红。
⇒ 一条必须给出的读数(不一定是改动)
把这个
plaintext围栏改成ts会发生什么?去量一次:改成ts后check:doc-snippets在这一页上报多少条诊断、分别是什么。- 若只报这两行造成的那两条(删掉它们之后就是 0 条)⇒ ⭐ 那就一起改,本页从此进入门的扫描面,这一类在这页上被根除。
- 若还报出别的(该页其他块用了环境名、或续接上一块)⇒ ⛔ 不要顺手修那些,把读数写在 PR 里并作为 out-of-scope finding 报回 —— 那是"让这一页可编译"的另一张卡。
⚠️ 这条读数必须给,无论最后改不改围栏。⛔ 只删两行、不回答"为什么没人会红",等于把同一张卡留给下一个人。边界
- ⛔ 不要动
packages/types的墓碑或 zod 镜像 —— 契约是对的,错的是文档。Clause-②no。 ⚠️ handler-keys-string-any-mirrors-7344.test.ts引用了本页的onSave: 'handleSaveReport'作为退休方言的语料来源 ⇒ 你删掉这一行可能会让那条钉子失去它的语料。先读那条钉子,确认它是按内容匹配还是按存在性匹配;若会因此变红,停下来报回,⛔ 不要为了让它绿而改钉子。- 跑
node scripts/check-changeset-presence.mjs并原样引用判词。
Generated by Claude Code
os-dev-report
{ "issue": 7488, "status": "done", "branch": "claude/issue-7488-report-builder-retired-handler-keys", "pr": "https://github.com/objectstack-ai/objectui/pull/7843", "premise_still_valid": true, "summary": "Dropped `onSave: 'handleSaveReport'` / `onCancel: 'handleCancel'` from the Report Builder example on content/docs/core/report-schema.mdx — the objectui#7340 disposition for seven of its eight pages. The example is NOT hollow without them: the section teaches the ReportBuilderSchema shape (type / report / availableFields / showPreview), not a save/cancel flow, so no replacement key was invented. The required reading came back clean, so the re-fence LANDED too: the block is now ```ts and the page has joined check:doc-snippets' scan surface (456 -> 457 compiled blocks), which kills this class on this page by construction. That re-fence forced ONE line outside the declared file surface — scripts/check-doc-fence-languages.mjs, the shrink-only ledger entry for this page, 8 -> 7 — because check:doc-fences goes red as STALE the moment the block leaves its baseline and prints that exact remedy itself; the gate's header states the protocol ('lower these numbers in the same pull request that re-fences the blocks'). Clause-2 untouched: no edit to the packages/types tombstones or the zod mirror. A FOURTH instrument the card did not name did in fact see the block: check:doc-fences classified it as a SYNONYM finding and carried it as declared, baselined debt — so the block being invisible to the compiler was a KNOWN state, not an unknown one. The 7340 pin's real blind spot is sharper than 'it measures table rows': its DOC_MEMBER_RE requires the `?` of a member declaration, so an example object literal matches neither of its two shapes; filed as objectui#7840.", "tests": "All on 9d46971b1 (branch head, worktree clean), doc-gate closure built first via `pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2` (34/34 tasks successful; heavy runs wrapped in the shared verify lock, VERDICT command-exit 0). BEFORE, with the defect present, all green — which is the card's whole point: check:doc-snippets exit 0 ('Semantic phase: 456 of 456 block(s) judged, 0 failed', zero report-schema lines in the output); check:doc-types exit 0 ('Every documented component type is registered'); check:doc-fences exit 0 (80 files / 90 blocks baselined); component-docs-retired-handler-keys-7340.test.ts + handler-keys-string-any-mirrors-7344.test.ts: Test Files 2 passed, Tests 76 passed. MEASUREMENT (re-fence ```plaintext -> ```ts with both lines STILL PRESENT; mutation confirmed on disk before the run: ```ts fence count 3->4, ```plaintext 8->7, diffstat 1 file/1 line): check:doc-snippets exit 1, and the ONLY diagnostics on the page were the two lines this card is about — 'content/docs/core/report-schema.mdx:421:3 TS2322: Type \\'string\\' is not assignable to type \\'undefined\\'' and the same at 422:3; 'Semantic phase: 457 of 457 block(s) judged, 1 failed'. No other block on the page uses an ambient name or continues an earlier block. AFTER the deletion: check:doc-snippets exit 0, '457 of 457 block(s) judged, 0 failed', 'Every covered documentation snippet compiles against the built types'. check:doc-fences then failed exactly as designed — 'content/docs/core/report-schema.mdx — baselined at 8, now carries 7' — and after the ledger decrement: exit 0, '80 declared file(s) carrying 89 block(s)'. UNION re-run on the committed head 9d46971b1: check-doc-snippet-types exit 0, check-doc-component-types exit 0, check-doc-fence-languages exit 0, --self-test exit 0 (26 cases), check-doc-links exit 0 ('Links are valid across 17 scan roots'), check-docs-route-eager-closure exit 0, check-doc-example-shared-reader exit 0, check-handler-key-read-sites exit 0, check-control-bytes exit 0 (6365 files). Tests: `pnpm exec vitest run packages/types/ scripts/__tests__/check-doc-fence-languages.test.ts scripts/__tests__/check-skill-examples.test.ts scripts/__tests__/one-authority-per-exported-name-6273.test.ts` -> Test Files 130 passed (130), Tests 2384 passed (2384) — the three script suites are owed separately because the diff edits a gate script, and gates-triggered-by-paths does not answer 'which tests test this script'. Every exit code captured by redirecting first (cmd > log 2>&1; EXIT=$?), never through a pipe. CHANGESET, verdict verbatim: 'No source or published contract of a released package changed in this range, so no changeset is owed.' (exit 0) => no changeset file; no skip-changeset label either, since in this repo that label is read by no workflow and exempts nothing. LINT, narrowed with proof rather than skipped: asked ESLint's own config resolution about the changed paths — report-schema.mdx ignored:true; check-doc-fence-languages.mjs ignored:false but 0 rules apply (the flat config's only selector is **/*.{ts,tsx}); control packages/types/src/reports.ts 116 rules. tseslint.configs.recommended is configured with no project/projectService, so linting is not type-aware and this diff cannot move any untouched file's verdict. NOT RUN: full `turbo run lint`, the full test suite, and any browser verification (docs-only, no runtime surface); CI covers those. No ablation beyond the before/after pair above — that pair IS the card's required measurement.", "mcp_calls": "0 — every GitHub action (issue read, comments read, dedup listings, issue create, label add, PR create, read-backs) used repo-scoped REST with $GITHUB_TOKEN; no MCP GitHub tool was called", "open_questions": [], "out_of_scope_findings": [ "filed as objectui#7840 (label `finding`, no assignee): the objectui#7340 pin cannot see example object literals at all — its DOC_MEMBER_RE requires `key?: type` (a declaration row) and its DOC_TABLE_RE a markdown prop-table row, so `onSave: 'handleSaveReport',` inside a `const x: Schema = {}` example matches neither. Widening it closes the CLASS rather than this instance, but it needs its own measurement (owner resolution from a type annotation for the PAIR RULE, a prose/counter-example rule, and a population count on main); the card also prices the alternative of driving check:doc-fences' remaining 80 files / 89 blocks to zero instead, since a compiled block makes a retired key a tsc error by construction.", "reported, NOT filed and NOT edited: handler-keys-string-any-mirrors-7344.test.ts line 196 now cites this page for a spelling it no longer carries. Checked before deleting — the citation is a provenance COMMENT and the value is a hard-coded constant (AUTHORED_STRINGS), while every file that test reads comes from packages/types/src/zod, so it matches by existence-at-authoring-time, never by content; it is green on this branch and the comment still reads correctly as history.", "declared, not a finding: scripts/check-doc-fence-languages.mjs is one line outside the dispatched file surface (ledger 8 -> 7). Mechanically forced by the re-fence the dispatch authorised, its correct form printed by the gate itself, same gate family, no new verification surface." ] }
Generated by Claude Code
PM 席回执 —— 你把卡片的核心论断修正了,而且修正后更强
⭐⭐ ① 「三个仪器全绿、没人在看」是错的:有第四个仪器,而且它看见了
check:doc-fences把这个块判成了 SYNONYM 发现,并作为已声明的、进了基线的债携带着它。⇒ 这个块对编译器不可见,是一个已知状态,不是一个未知状态。 ⭐ 这条比卡片原来的说法要紧得多:不是"没人看",是"看见了、记下了、然后就停在那里"。⛔ 后来的人不要再复述卡片那句三仪器全绿。
⭐⭐ ② #7340 钉子的盲区比卡片说的更锋利
卡片说它"量的是文档属性表的行"。实际是:它的
DOC_MEMBER_RE要求成员声明里的那个?,DOC_TABLE_RE要求 markdown 属性表行 ⇒ 一个const x: Schema = {}例子里的onSave: 'handleSaveReport',两种形状都不匹配。⇒ 不是"它看的是另一个地方",是"它在语法上无法表示例子里的对象字面量"。已由你立卡 #7840 承接,本席已补
pm:queue+domain:devx(到达时缺pm:*—— 今天第 18 次)。⭐ ③ 那条"必须给的读数"回来是干净的,所以围栏也落了 —— 这正是裁定希望的分支
带着两行仍在的情况下改成 ```ts,整页上的诊断恰好只有这两行(TS2322 ×2,421:3 / 422:3),没有别的块使用环境名或续接上一块。⇒ 于是围栏一并改掉,
456 → 457个编译块,这一页从此进了扫描面 —— 这一类在这页上由构造被杀死,而不是被清扫一次。⛔ 如果那次测量报出了别的诊断,正确动作是只删两行、把读数报回;你没有遇到那种情况,但流程是对的。
⚠️ ④ 越界一行,本席认可 —— 因为是门自己要求的scripts/check-doc-fence-languages.mjs的 shrink-only 台账 8 → 7 在声明的文件面之外。但它是被那次围栏改动机械强制的:块一旦离开基线,check:doc-fences立刻以 STALE 变红,并且自己打印出正确的补法,门的头注还写着协议("lower these numbers in the same pull request that re-fences the blocks")。⇒ ⭐ 判据是:这一行不是你选的,是门在同一次运行里指定的。 你把它声明出来而不是混在 diff 里,正确。⛔ 换成"我觉得顺手一起改比较好",就不成立。
⭐ ⑤ 我在派发令里让你先查的那条引用,你查了,答案是干净的
handler-keys-string-any-mirrors-7344.test.ts:196引用本页作为退休方言的语料来源。你在删除之前读了它:那是一条出处注释,值是硬编码常量(AUTHORED_STRINGS),而它真正读取的每个文件都来自packages/types/src/zod⇒ 按撰写时的存在性匹配,从不按内容匹配。分支上是绿的,注释作为历史仍然读得通。⇒ ⛔ 你没有为了让它绿而改钉子,也没有假设它不会红 —— 这两件事都做对了。
Generated by Claude Code
落地记录 —— PR #7843 已合入(本 lane 今日第 36 次落地)
merged: true@ 2026-09-06T00:52:29Z,squashbaa24fea2- 2 files, +3 / −5;closing keyword 只有
#7488;卡片closed_at00:52:30Z
⚠️ 2 files / +3 −5 是一个极小的 diff,但它把这一页从「靠人读」搬进了「靠门」。下面三条读数才是本卡的价值。⭐⭐ 卡片的核心论断被修正了 —— 而且修正后更强
卡片写「三个仪器全绿、没有一个在看这一行」。有第四个仪器,而且它看见了:
check:doc-fences把这个块判成 SYNONYM 发现,并作为已声明的、进了基线的债携带着它。⇒ 这个块对编译器不可见,是一个已知状态,不是一个未知状态。 ⭐ 不是"没人看",是「看见了、记下了、然后就停在那里」。⛔ 后来的人不要再复述卡片那句"三仪器全绿"。
⭐⭐ #7340 钉子的盲区,比卡片说的更锋利
卡片说它"量的是文档属性表的行"。实际是:它的
DOC_MEMBER_RE要求成员声明里的那个?,DOC_TABLE_RE要求 markdown 属性表行 ⇒ 一个const x: Schema = {}例子里的onSave: 'handleSaveReport',两种形状都不匹配。⇒ 不是"它看的是别处",是它在语法上无法表示例子里的对象字面量。已由 #7840 承接(
pm:queue/domain:devx)。⭐ 那条「必须给的读数」回来是干净的,所以围栏也一并落了
带着两行仍在的情况下把
plaintext 改成ts,整页诊断恰好只有这两行(TS2322×2,421:3 / 422:3),没有别的块使用环境名或续接上一块。⇒ 于是围栏一并改掉,456 → 457 个编译块,这一页从此进入check:doc-snippets的扫描面 —— 这一类在这页上由构造被杀死,而不是被清扫一次。⛔ 如果那次测量报出了别的诊断,正确动作是只删两行、把读数报回。流程走对了,结果恰好是好的那一档。
⚠️ 一行越界,本席认可 —— 因为是门自己要求的scripts/check-doc-fence-languages.mjs的 shrink-only 台账 8 → 7 在声明的文件面之外。但它被那次围栏改动机械强制:块一旦离开基线,check:doc-fences立刻以 STALE 变红,并且自己打印出正确的补法,门的头注还写着协议("lower these numbers in the same pull request that re-fences the blocks")。⇒ ⭐ 判据是:这一行不是执行席选的,是门在同一次运行里指定的,而且它把这一行声明了出来而不是混在 diff 里。⛔ 换成"我觉得顺手一起改比较好"就不成立。
⭐ 本席让它先查的那条引用,它查了,答案是干净的
packages/types/src/__tests__/handler-keys-string-any-mirrors-7344.test.ts:196引用本页作为退休方言的语料来源。它在删除之前读了那条钉子:那是一条出处注释,值是硬编码常量(AUTHORED_STRINGS),而它真正读取的每个文件都来自packages/types/src/zod⇒ 按撰写时的存在性匹配,从不按内容匹配。分支上是绿的,注释作为历史仍然读得通。⇒ ⛔ 它没有为了让钉子绿而改钉子,也没有假设它不会红。两件事都做对了。
Generated by Claude Code
Measured on
maine307c9896while executing the objectui#6121 retirement, in thesame file and the same fenced example.
content/docs/core/report-schema.mdx's Report Builder example still authors twokeys the published contract now refuses by name:
ReportBuilderSchema.onSave/.onCancelbecame?: neveron the TypeScript faceand
handlerKeyRefusal(...)arms on the zod mirror when PR #7468 landed(objectui#7344, in the objectui#6124 shape; the maintainer ruling of 2026-08-25 that
the handler-expression string dialect is not a supported authoring form). So the page
teaches a literal that is a
tscerror to assign AND a namedsafeParserefusal —packages/types/src/__tests__/phase2-schemas.test.tspins exactly that refusal, andhandler-keys-string-any-mirrors-7344.test.tscites THIS page'sonSave: 'handleSaveReport'as the corpus source of the retired dialect.Why no gate reports it
The block is a
plaintextfence:check:doc-snippetscompilests/tsxfencesonly,
check:doc-typesreadstypestring literals, andcomponent-docs-retired-handler-keys-7340.test.ts— the pin objectui#7340 landed forexactly this class — measures doc property-table ROWS, not example object literals.
Three instruments, all green, none of them looking at this line. It is the
objectui#5044 class: a snippet teaching a contract error under a green gate.
Suggested remedy
Drop the two lines from the example (the disposition objectui#7340 chose for seven of
its eight pages), or replace them with the node-type spelling PR #6498 established.
Widening the #7340 pin from table rows to example literals would close the class
rather than this instance, and is the more valuable half — but it is its own
measurement and belongs to whoever takes it, not to a one-line docs edit.
Why this was not folded into the PR that found it
The objectui#6121 dispatch fences that card to its own ruling: 「⛔ Do not fold in
neighbouring report-schema work that is not this ruling.」 This is PR #7468's residue,
not that ruling, so it is filed rather than fixed. Deduped first against the closed
objectui#7340 / objectui#7239 family and the objectui#5047 plugin-report docs card:
none of them covers an example literal on this page.
Found by an execution seat while landing objectui#6121, session
session_01EMrWaQw3XS5DxTHxp4yRyC. Generated by Claude Code.Generated by Claude Code