Skip to content

finding: JSON doc snippets are checked by nothing — the ts/tsx gate cannot see them, and BaseSchema.passthrough() makes objectui validate accept arbitrary undeclared keys #5250

Description

@os-support-ai

Observation-class finding — a structural gap, measured while implementing #5229. Filed unassigned, not claiming.

#5138 filed this class ("no gate reads a doc snippet's schema KEYS") and was closed as completed by PR #5161, which built scripts/check-doc-snippet-types.mjs. That gate closed the TypeScript half. The JSON half is still open, and #5229 is a live instance of it.

Two independent reasons a JSON teaching snippet is unchecked

1. The snippet gate never sees it.check-doc-snippet-types.mjs:

constTS_FENCE_LANGUAGES=newSet(['ts','tsx','typescript']);

content/docs/blocks/forms.mdx holds four fences, all ```json. The gate's own summary confirms the shape of this: 138 covered (13 of them hold a ts/tsx block) — a document with no ts/tsx fence is "covered" and contributes zero blocks, so it is vacuously green. (Adjacent but distinct from #5174, which is about .md vs .mdxcollection; this is about the fence language filter, and it bites .mdx files too.)

2. Even a JSON-parsing gate would pass the defect, because the schemas are passthrough.BaseSchemaCore ends .passthrough() (packages/types/src/zod/base.zod.ts), so every node schema extending it accepts undeclared keys unvalidated. Measured against objectui validate on origin/main at 56735762f:

$ cat probe.json
{"type":"input","name":"email","validation":{"pattern":12345,"message":false,"nonsense":[1,2]}}
$ objectui validate probe.json
✓ Schema is valid!
Type: input

InputSchema declares novalidation key. The entire object — including a numeric pattern and a boolean message — rides through. Contrast the same garbage in a declared key:

$ echo '{"type":"input","name":"email","pattern":12345}' > probe2.json
$ objectui validate probe2.json
✗ Schema validation failed!
1. Invalid input Code: invalid_union

So the validator's verdict on a snippet says nothing about the keys it does not declare, which is exactly the class of docs defect that keeps getting filed one file at a time.

What that let through, concretely

#5229: content/docs/blocks/forms.mdx taught "validation": { "pattern": "…", "message": "…" } on a "type": "input" node. InputSchema has no validation key; InputRenderer never reads schema.validation; form.tsx's #5099 diagnostic walks a form node's fields[], not standalone input nodes. Every shipped tool was green on it, and check-doc-component-types.mjs passed it because the one key it judges (type: "input") was correct — its header says so deliberately:

NOT in scope, deliberately: whether the snippet's OTHER keys are read by the renderer the type resolves to.

Shapes this could take — a maintainer call, hence finding not pm:queue

  1. Parse JSON fences against the node schemas — needs the fragment-marking design finding: no gate reads a doc snippet's schema KEYS against the spec — #4823's deferred "second dimension", closed unbuilt #5138 already identified as the real cost (many blocks are deliberately partial), plus a decision on passthrough: a check that runs the current schemas catches almost nothing, so it would need a strict variant used for validation only.
  2. Make the strictness decision first..passthrough() is load-bearing for renderer props (the specFieldsExcept docblock explains why), so this is not a flip — it is "is there a strict face for authoring, separate from the tolerant face for rendering". That question is bigger than docs and touches AGENTS.md #0.1.
  3. Do nothing and keep filing instances. Honest option; the cost is one reader-found defect per file, which is the observed rate.

Related: #5138 (this class, TypeScript half now built), #5161 (the gate that built it), #5174 (collection surface of the same gate), #5106 (scan surface of check-doc-component-types), #4823 (the original deferral), #5229 (the instance that produced this reading).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions