Skip to content

finding: no gate reads a doc snippet's schema KEYS against the spec — #4823's deferred "second dimension", closed unbuilt #5138

Description

@os-zhuang

Observation-class finding — a structural gap, not a defect anyone is stepping on today (the known instances get filed and fixed individually). Found while implementing #5047.

The gap

scripts/check-doc-component-types.mjs (built by #4823 / PR #4900) answers exactly one question about a documentation snippet: does the type string name something the registry registers. Its own header says so, and says what it deliberately leaves out:

NOT in scope, deliberately: whether the snippet's OTHER keys are read by the renderer the type resolves to. That is objectui#4823's second dimension and needs a per-renderer read-point contract; this gate answers one question only — does the type exist.

#4823 is closed as completed. The first dimension shipped; the second was never built and no open card carries it. So the class is currently untracked.

What that lets through — measured on #5047

Both documents in #5047 taught the pre-9.0 report query form for the entire interval since the ADR-0021 cutover. Every relevant gate was green on that prose the whole time. Baseline, run on unmodified origin/main at 958d757 before any edit:

node scripts/check-doc-links.mjs exit=0 Links are valid across 13 scan roots.
node scripts/check-doc-component-types.mjs exit=0 482 registered, 88 exempted
node scripts/check-control-bytes.mjs exit=0 scanned 4562 tracked text file(s)

The teaching snippets contained, simultaneously:

  • objectName and groupingsDown — keys the strict ReportSchema rejects outright (unrecognized_keys);
  • columns: [{ field, aggregate }] — a repurposed key, now string[], so the old spelling is a type error rather than an unknown one;
  • import type { ReportInput } from '@objectstack/spec/ui' — a type the spec does not export at all;
  • registerDrillHandler — a fabricated export of @object-ui/plugin-report.

None of it is visible to any gate, because the type literals themselves (summary, matrix, joined) were fine. The gate looked at the one key that was correct.

This is also why the defect class keeps recurring one document at a time: #4600 (dashboard examples), #5016 / #5048 (this package's README exports and signatures), #5047 (this schema shape), #5057, #5064, #5126 — each found by a human or agent probe, never by a check.

Shapes this could take, deliberately not chosen here

  1. Parse the snippet against the spec schema. Strongest: a fenced block declaring a report / dashboard / view could be safeParsed against the matching @objectstack/spec schema, and unrecognized_keys fails the gate. Needs a way to mark which blocks are complete documents versus prose fragments — a real design question, since plenty of blocks are deliberately partial.
  2. Compile the snippets.docs(plugin-report): README 按真实导出面重写三处虚构导出与陈旧幸存清单 #5053, docs(plugin-report): rewrite README export snippets against the real signatures #5060 and plugin-report docs still teach the pre-9.0 query form as the live authoring shape — and name three renderers removed at the ADR-0021 cutover #5047's PR each hand-rolled a script-extraction + tsc --strict probe against the built dist/index.d.ts, and each found defects the reviewer had not listed. Three independent reimplementations of the same harness is itself the signal that it belongs in scripts/.
  3. Type-literal coverage only — the cheapest, and the one already built.

Which of these, and how fragments get marked, is a maintainer call on scope and cost; that is why this is finding and not pm:queue.

Reference

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions