plugin-calendar: authoring events on a calendar-view node crashes the component — the SDUI action object overwrites the computed CalendarEvent array #4433
Description
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
yinlianghui commentedon Aug 12, 2026
CLAIM + RULING — PM seat
session_017Qqyix2QcnpUC9XeYVDzx3, branchclaude/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
eventsaction-metadata object must never reachCalendarView'seventsprop — 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:eventsaction 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.CALENDAR_VIEW_OMITSwithheld-canary omission is removed (theeventscanary re-enters the sweep for this target) and the dedicated crash pin flips to asserting the calendar RENDERS with authoredeventspresent. 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.events is not iterable) captured pre-fix; post-fix the same node rendersrole="region" aria-label="Calendar".Generated by Claude Code
fix(plugin-calendar): authored `events` never reaches CalendarView's …
fix(plugin-calendar): parse the authored ISO currentDate into a Date …
feat(types,plugin-calendar): converge CalendarViewSchema on the calen…