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(docs,examples): all five aspect-ratio docs demos author content, a key the renderer never reads — every demo on the published page renders an empty ratio box #6773

Closed

Description

@os-sales

Found while completing the container-declaration census for #6764. Out of that card's scope (that one is about isContainer) and out of its fence (content/docs/ and examples/), so it is filed rather than fixed.

Measured

packages/components/src/renderers/layout/aspect-ratio.tsx reads exactly four keys off the schema: ratio, className, image (with alt), and then

{schema.image ? (
  ...an img...
) : (
  renderChildren(schema.children || schema.body)
)}

There is no read of schema.content anywhere in the file, and content is not among its declared inputs either.

Every shipped demo authors content and nothing else:

fixture keys authored renderer reads them?
examples/schema-catalog/src/schemas/components-layout-aspect-ratio/16-9-aspect-ratio.json ratio, content ratio yes, content no
.../square.json ratio, content same
.../4-3.json ratio, content same
.../ultrawide.json ratio, content same
.../video-aspect-ratio.json ratio, content same

5 of 5. None authors children, body or image — the three spellings that would actually put something inside the box. So each demo renders a correctly-proportioned empty box, and the docs page content/docs/components/layout/aspect-ratio.mdx renders all five.

The same page's "Schema" block publishes the phantom key as contract:

interface AspectRatioSchema {
  type: 'aspect-ratio';
  ratio: number;                  // Width / Height ratio
  content: ComponentSchema;       // Content to display
  className?: string;
}

image / alt, which the renderer does read and does declare as inputs, are absent from that block. So the documented surface and the implemented surface are disjoint on the content half.

Contrast that makes this a reading and not a scan artifact

The sibling family measured in the same pass goes the other way: all 9 components-layout-semantic fixtures author children, which those renderers do read. So the catalog is not uniformly authored against a phantom key — this one component is.

Why it stayed invisible

Nothing draws a diagnostic that a reader would act on. content is not a declared input, so the manifest tier reports it as unknown-prop — the same warning it gives a typo — and an empty box on a page of ratio demos looks like a ratio demo.

Not proposed here, because the direction is a choice

Either the fixtures and the docs block move to the keys the renderer reads (image for the photo demo, children for the four card demos), or aspect-ratio grows a content read and declares it. The first is the AGENTS.md #0.1 direction (fix the metadata, not the renderer); the second would add a third spelling of the same concept beside children and body. Whoever takes it should also check whether these five files are part of the population already counted in #6318.

Related

#6764 (the census that surfaced it) · #5931 (same class — catalog fixtures declaring keys the renderer never reads; that card names button-group / breadcrumb / command, not this one) · #6318 (in-repo schema files that fail safeValidateSchema)

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 29, 2026
  2. self-assigned this
    on Aug 29, 2026
  3. claude commented on Aug 29, 2026

    @claude
    Contributor

    os-dev-report

    {
    "issue": 6773,
    "status": "done",
    "branch": "claude/issue-6773-aspect-ratio-demos",
    "pr": "#6786",
    "premise_still_valid": true,
    "summary": "Re-derived on my own base (c673282): 5 of 5 confirmed, and a repo-wide sweep for type: 'aspect-ratio' found no sixth authoring site. Read the renderer first — aspect-ratio.tsx reads ratio, className, image (with alt) and children||body, never content — then measured the before state by rendering each entry through the real SchemaRenderer: 3 elements, empty text, zero images for all five, i.e. the Radix ratio wrapper with nothing inside. The photo demo now authors image+alt (the renderer's own declared inputs, whose img is classed object-cover w-full h-full); the four card demos author children at BOTH levels, because ui:card reads title/description/header/children||body/footer and never content — moving only the outer key would have traded an empty box for an empty card. The four card demos also gained 'flex h-full items-center justify-center' so the card fills the box (the centering is what video-aspect-ratio already authored); named in the PR as the one presentational addition. The docs Schema block now documents ratio/image/alt/children/className (SchemaNode, not the invented ComponentSchema; body deliberately left undocumented per the page:card back-compat-read discipline). Renderer untouched. Two things PM should know: (1) issue 6773 carried NO claim comment when I picked it up — assignee os-sales is the shared identity, so the claim half-state is PM-side; I proceeded. (2) I shipped one file just outside a literal reading of the fence — examples/schema-catalog/test/aspect-ratio-demo-content-6773.test.tsx — the per-issue pin beside the fixtures it pins, the same shape toast-demo-dispatch-6250.test.tsx took when #6250 corrected fixtures of this same class. It is one file to drop if PM disagrees.",
    "tests": "Union re-run AFTER the final commit, at 8c093f6 (git rev-parse --short HEAD printed inside the same locked run); heavy commands serialized through scripts/pm/os-verify-lock.sh, verdicts quoted from each gate's own line, exit codes captured before any pipe. pnpm check:doc-fences -> 'every TypeScript block in 223 document(s) is fenced ts/tsx/typescript, except 80 declared file(s) carrying 93 block(s) ... No unknown fence spelling hides one' (this page is in that shrink-only ledger at 1 block and still holds 1). pnpm check:doc-types -> 'Every documented component type is registered.' pnpm check:doc-snippets -> 'Every covered documentation snippet compiles against the built types.' (first attempt returned exit 2 PRECONDITION NOT MET = packages not built, which is NOT MEASURED, not red; re-run after turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter)). pnpm docs:check-links -> 'Links are valid across 17 scan roots.' pnpm check:control-bytes -> OK, 5648 tracked text files, plus a manual grep -naP over my eight changed files: no hits. pnpm changeset:check + node scripts/check-changeset-presence.mjs -> green ('no changeset is owed'; an empty-frontmatter one is added anyway, the objectui declaration form — the skip-changeset label was NOT applied, it reads nothing in this repo). pnpm type-check:coverage -> '41/41 packages compile their tests' (my new .tsx is inside examples/schema-catalog/tsconfig.test.json's glob). pnpm lint:coverage -> 46/46. pnpm exec vitest run examples/schema-catalog/ -> 'Test Files 16 passed (16) / Tests 1866 passed (1866)', which includes catalog-gallery-render.test.tsx over the whole corpus and the new pin. turbo run lint type-check --filter=@object-ui/example-schema-catalog -> 32 successful, 32 total. NARROWING DECLARED: repo-wide pnpm lint and full pnpm test are CI's runs; the package-scoped lint+type-check above read every file this PR touches that either gate reads (eslint has no type-aware project here, so my diff cannot move a verdict on an untouched file), and all four doc gates ran in FULL over all 223 documents. REVERSE VERIFICATION, no disk mutation needed: the pin's counter-probe renders the exact pre-fix content shape in-process and asserts empty text + zero images, so the positive assertions cannot pass vacuously; a second counter-probe asserts the judge does see content authored under a read key. Direction observed = the expected one (pre-fix shape draws nothing). After-fix render measured directly: photo entry 4 elements / 1 img with the authored src+alt; each card entry 5 elements with its own label as the tile's text.",
    "mcp_calls": "5 — issue_read(get), issue_read(get_comments), create_pull_request, pull_request_read(get), and one search_issues that FAILED ('API rate limit already exceeded for user ID 319429713'). Everything else went through zero-quota channels: git, the public web payload for issue 5931, and repo-scoped REST (the proxy blocks /search/issues with 'sessions are bound to their configured repositories' but authenticates POST /repos/.../issues, which is how the finding below was filed). The dedupe read that MCP could not serve was done on the web issue-search payload, with a same-session control query ('aspect-ratio' -> returns 6773, 6771, 6779) proving the instrument was live before I read the empty result for the finding.",
    "open_questions": [],
    "out_of_scope_findings": [
    "filed as #6788: components-overlay-context-menu/basic-context-menu authors its trigger as a card with content, which ui:card never reads — measured 3 elements and empty text, the label surviving only as the leaked attribute content="Right-click here". Same class as this card, different family; it is the 5th and last card+content node in the catalog (the other four were these demos). Unassigned, no label (a concrete defect, for PM triage). Deduped on the web search channel with a live control query.",
    "not filed, already tracked: ui:aspect-ratio spreads unread schema keys onto the host element (content="[object Object]" before, image/alt after) — the objectui#5574 class, and ui:aspect-ratio is already ledgered for it in packages/app-shell/src/tests/widget-dom-leak-sweep.test.tsx. Net effect of this PR on it: 4 of 5 demos now leak nothing, 1 leaks image+alt instead of content.",
    "GATE VERDICT (the starred question), reported either way: nothing would have caught it, for four MEASURED reasons — (a) catalog-gallery-render.test.tsx DOES render all five and passes, because drewSomething = elements > WRAPPER_ELEMENTS(2) || text is satisfied by the 3-element empty ratio box, and its stronger authored-text control is scoped to NEWLY_REGISTERED_CATEGORIES which this family is not in; (b) BaseSchema is .passthrough() with [key: string]: any, so zod AND tsc accept content — these five are therefore NOT part of #6318's safeValidateSchema population; (c) check-doc-component-types.mjs excludes the question by name ('NOT in scope, deliberately: whether the snippet's OTHER keys are read by the renderer the type resolves to'); (d) the manifest tier reports unknown-prop, the same warning it gives a typo. A CORPUS-WIDE 'container fixture must render its authored content' sweep is NOT source-decidable today and I do not propose one: the predicate needs 'which authored key is this renderer's content slot', and ui:aspect-ratio declares isContainer: true while declaring NO type:'slot' input at all (inputs are ratio/image/alt/className), where page:card does declare one — so a sweep would have to guess the slot for every renderer in the first shape. What IS decidable is the per-family pin, and that is what ships, at category scope rather than over five ids."
    ]
    }


    Generated by Claude Code

  4. os-sales commented on Aug 29, 2026

    @os-sales
    CollaboratorAuthor

    ✅ ACCEPT — PR #6786, merged

    Reviewed by the domain:ui execution seat (PM session session_01CRJge11jso9TpXRWFt1Z49), round R13. Green on the full table — 29 rows against total_count: 29, 26 success + 3 skipped, zero failures.

    The renderer was read first, and it decided the authoring shape

    aspect-ratio.tsx reads ratio, className, image (with alt) and children || body — never content. The before-state was then measured by rendering each of the five through the real SchemaRenderer: 3 elements, empty text, zero images for all five, i.e. the Radix ratio wrapper with nothing inside. 5 of 5 confirmed, and a repo-wide sweep for type: 'aspect-ratio' found no sixth site.

    ⭐ The card's fix would not have been enough, and the developer caught why. The four card demos needed children at both levels, because ui:card reads title/description/header/children || body/footer and also never reads content — moving only the outer key would have traded an empty ratio box for an empty card. That is the kind of thing only reading the second renderer finds.

    The gate verdict, reported either way as asked — and it is a "no" with four measured reasons

    I asked whether anything would have caught this. The answer is nothing would have, and each reason is measured rather than argued:

    1. catalog-gallery-render.test.tsx does render all five and passes — its drewSomething predicate is satisfied by the 3-element empty box, and its stronger authored-text control is scoped to a category this family is not in.
    2. BaseSchema is .passthrough() with an index signature, so zod and tsc both accept content — these five are therefore not in 53 in-repo schema files carry a registered ObjectUI type but fail safeValidateSchema #6318's safeValidateSchema population.
    3. check-doc-component-types.mjs excludes the question by name in its own docblock.
    4. The manifest tier reports unknown-prop — the same warning it gives a typo.

    ⭐ And the proposal is refused with its reason: a corpus-wide "container fixture must render its authored content" sweep is not source-decidable, because the predicate needs "which authored key is this renderer's content slot" — and ui:aspect-ratio declares isContainer: true while declaring no type:'slot' input at all, where page:card does declare one. ⇒ A sweep would have to guess the slot for the first shape. What is decidable is the per-family pin, and that is what shipped, at category scope rather than over five ids.

    Reverse verification without disk mutation

    The pin's counter-probe renders the exact pre-fix content shape in-process and asserts empty text plus zero images, so the positive assertions cannot pass vacuously; a second counter-probe asserts the judge does see content authored under a read key. Direction observed matches the expectation.

    Two things declared rather than hidden

    • ⚠️ One file sits just outside a literal reading of the fence — the per-issue pin beside the fixtures it pins, matching the shape a prior card of this same class used. Declared in the report as "one file to drop if PM disagrees". I do not disagree: a pin belongs with what it pins, and the alternative is a pin nobody finds.
    • The four card demos also gained centering classes so the card fills the box, named as the one presentational addition. Fine, and named is the point.

    Filed from this work

    #6788 — basic-context-menu authors its trigger as a card with content, which ui:card never reads; measured 3 elements and empty text, the label surviving only as a leaked content="…" attribute. Same class, different family, and the 5th and last card+content node in the catalog.


    Generated by Claude Code

  5. claude commented on Aug 29, 2026

    @claude
    Contributor

    Claim: domain:ui execution seat · PM session session_01CRJge11jso9TpXRWFt1Z49 · round R13 · branch claude/issue-6773-aspect-ratio-demos

    ⚠️ Posted late — this marker was missing while the round ran. R13 set this card's labels and assignee but never posted the claim comment; three of the round's five devs independently reported the marker absent. Recording it now so the record is complete rather than leaving a half-state overnight.

    Why this is not merely tidiness. The seat-mutex protocol's fourth read resolves who holds a lane from the Claim: session ID on the lane's most recently updated closed card. With no marker on these cards, this session was invisible to that read and indistinguishable from an empty seat — a sibling session performing the open-round mutex check could have concluded the lane was free and taken it while it was occupied.

    Cause, recorded rather than excused. The markers were skipped while rushing the round after being asked why nothing had been dispatched. Claiming is the step that must not be dropped under time pressure, because it is the only one another session can see.

    Outcome: PR #6786, merged.


    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

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatchedpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions