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

plugin-calendar: authoring events on a calendar-view node crashes the component — the SDUI action object overwrites the computed CalendarEvent array #4433

Closed

Description

@yinlianghui

Measured by the #4425 phase-1 DOM-leak sweep gate. This one is not a DOM leak — it is a crash, found because the sweep plants the same canary set on every target and this target refused to render.

The defect

packages/plugin-calendar/src/calendar-view-renderer.tsx computes a CalendarEvent[] from schema.data, passes it as events, and then spreads the remaining props after it:

return (
  CalendarView
    className={className}
    events={events}
    onEventClick={handleEventClick}
    {...props}
  /
);

SchemaRenderer forwards a node's events key as a prop (it is not on the renderer's strip list). So an SDUI node that authors events — the ordinary action metadata of AGENTS.md section 4, legal on any node — has its { onClick: [...] } object land on the events prop, replacing the array. CalendarView then iterates it and throws.

Measured, in isolation

events alone, nothing else authored:

{ "type": "plugin-calendar:calendar-view", "id": "n",
  "events": { "onClick": [{ "action": "navigate" }] } }

renders the error boundary, not the calendar:

Component "plugin-calendar:calendar-view" failed to render
events is not iterable

The same node without events renders the real calendar (role="region" aria-label="Calendar"), and so does one carrying every other canary. So events is the sole trigger — this is not a side effect of the sweep's other canaries.

Why this is worse than the leaks filed alongside it

#4431 and #4432 put junk attributes on the DOM. This one takes the whole component down: a perfectly spec-legal node loses its calendar and shows an error card instead. A prop-name collision between injected SDUI metadata and a component's own prop is a different failure mode from the leak class, and a whitelist at the spread site would close it as a side effect — one more input for #4425 phase 2.

Interaction with the gate

The sweep renders plugin-calendar:calendar-view without the events canary, recorded in the gate as CALENDAR_VIEW_OMITS with the reason, because a crashing render produces a tidy error-boundary DOM with no leaked attributes and would otherwise read as a clean pass. The omission is not silent: the gate carries a dedicated case pinning this crash, so it cannot regress unnoticed. Fixing it turns that case red, and both halves — the omission and the pin — come out in the same change, putting events back into the sweep for this target.


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 12, 2026
  2. yinlianghui commented on Aug 12, 2026

    @yinlianghui
    ContributorAuthor

    CLAIM + RULING — PM seat session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4433-calendar-events-crash, one dev agent, one PR, Fixes #4433. finding → pm:queue, dispatched at priority: a spec-legal node losing its component to an error card is the severest thing today's sweeps measured.

    Ruling (delegated, veto window open): the authored events action-metadata object must never reach CalendarView's events prop — strip the collision out of the spread per the #4428 deny-list precedent (the phase-2 whitelist question stays open; this crash does not wait for it). Conditions:

    1. Measure the semantics first: (a) does the authored events action metadata on a calendar-view node DO anything today through the renderer layer's own event wiring (did actions ever work on this node type, or was the key always a landmine)? State it — the fix must not silently disable a working action path, and if actions never worked here, that's recorded as the pre-existing state, not regressed. (b) Sweep the component's other computed props (className, onEventClick) for the same overwrite exposure and grade each — fix the crash-capable ones, record the benign ones.
    2. The gate's two halves come out together per the card's own design: the CALENDAR_VIEW_OMITS withheld-canary omission is removed (the events canary re-enters the sweep for this target) and the dedicated crash pin flips to asserting the calendar RENDERS with authored events present. Gate on PR test(app-shell): generalize the #3291 DOM-leak canary sweep beyond packages/fields (#4425 phase 1) #4441 landing first (the gate file is its surface) — poll.
    3. Red-first: the card's own minimal repro (the error boundary + events is not iterable) captured pre-fix; post-fix the same node renders role="region" aria-label="Calendar".
    4. Changeset patch (@object-ui/plugin-calendar — crash fix, no API movement; grade up per precedent only if an exported type moves), never major.

    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions