You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
decision(plugin-calendar): a record with no value in the declared date field is silently placed on today — and the isNaN guard beside it structurally cannot catch that #7071
Filed by the domain:ui seat (session session_013hfmP9hoMd3dJwTh85J4yB) on behalf of PR #7062, whose body states this was "Filed separately". It was not — the implementing agent's dedupe channel was rate-limited, so it declined to file blind and handed the finding back. This is that filing, re-measured against origin/main at 592acafbe.
⚠️This is layer 3 of the chain already described in #7029's body. It is filed as its own card, not as a duplicate, because #7029's ruled deliverable closes a different trigger — see "What #7062 leaves" below. If a reviewer judges it belongs inside #7029 after all, close this as a duplicate; the seat would rather over-file than leave a landed PR pointing at a card that does not exist.
A record with no value at the configured startDateField is given the current moment as its event start, and then renders as an ordinary event indistinguishable from a real one.
⭐ The guard six lines below cannot catch it, by construction
:451:
}).filter(event=>!isNaN(event.start.getTime()));// Filter out invalid dates
That filter exists to drop unusable dates. It cannot fire here: new Date() with no argument is always a valid Date, so the fallback at :445 produces exactly the one value the guard is guaranteed to pass. The absent-value case is converted into a well-formed lie before the check that would have caught it.
Note the asymmetry two lines away — end: endDate ? new Date(endDate) : undefined falls back to undefined, which is honest. Only start fabricates. (allDay: !endDate then infers all-day from the missing end; adjacent, and probably fine, but it means one absent field silently changes two rendered properties.)
Before #7062, this fired for views that declared no calendar config at all — the invented 'due_date' binding meant every record missed its field, which is how nine hotcrm records piled onto today's cell.
After #7062, the fabricated bindings are gone and the refusal screen catches the unconfigured view. The hole that remains is narrower and genuinely different: a view that correctly declares startDateField, over records where some rows have no value in that field. Those rows silently collect on today, mixed in with correctly placed ones — arguably harder to notice than the original, because the screen is now mostly right.
Why this is needs-user-decision and not a fix card
The correct behaviour is undecided, and each option is a real product choice with a different failure mode:
Drop the event — clean, but data disappears from a view with no indication it was ever there.
Bucket as "unscheduled" — honest and discoverable, but the calendar surface has no such affordance today, so this is a feature, not a fix.
Badge it in place — keeps it visible, but on a date that is still a fabrication.
#7029's ruling ("no invented field names") arguably reaches option 1 or 2 by extension, but it was ruled about view configuration, not record data, and the seat will not stretch a ruling across that boundary on its own. ObjectCalendar.tsx:657's existing refusal screen answers the config question, not this one.
⛔ Whoever takes this should not pick an option without a ruling.
Refs: #7029 · PR #7062 · #7070 (the sibling finding from the same handback) · objectstack#13748.
Filed by the
domain:uiseat (sessionsession_013hfmP9hoMd3dJwTh85J4yB) on behalf of PR #7062, whose body states this was "Filed separately". It was not — the implementing agent's dedupe channel was rate-limited, so it declined to file blind and handed the finding back. This is that filing, re-measured againstorigin/mainat592acafbe.Measured
packages/plugin-calendar/src/ObjectCalendar.tsx:445:A record with no value at the configured
startDateFieldis given the current moment as its event start, and then renders as an ordinary event indistinguishable from a real one.⭐ The guard six lines below cannot catch it, by construction
:451:That filter exists to drop unusable dates. It cannot fire here:
new Date()with no argument is always a valid Date, so the fallback at:445produces exactly the one value the guard is guaranteed to pass. The absent-value case is converted into a well-formed lie before the check that would have caught it.Note the asymmetry two lines away —
end: endDate ? new Date(endDate) : undefinedfalls back toundefined, which is honest. Onlystartfabricates. (allDay: !endDatethen infers all-day from the missing end; adjacent, and probably fine, but it means one absent field silently changes two rendered properties.)What #7062 leaves
Before #7062, this fired for views that declared no calendar config at all — the invented
'due_date'binding meant every record missed its field, which is how nine hotcrm records piled onto today's cell.After #7062, the fabricated bindings are gone and the refusal screen catches the unconfigured view. The hole that remains is narrower and genuinely different: a view that correctly declares
startDateField, over records where some rows have no value in that field. Those rows silently collect on today, mixed in with correctly placed ones — arguably harder to notice than the original, because the screen is now mostly right.Why this is
needs-user-decisionand not a fix cardThe correct behaviour is undecided, and each option is a real product choice with a different failure mode:
startDateField: 'due_date'/titleField: 'name'for views with nocalendar:block — the guess short-circuits ObjectCalendar's own refusal screen and piles every record on today #7029's ruled loud-over-silent direction, but disproportionate: one bad row would blank a working calendar.#7029's ruling ("no invented field names") arguably reaches option 1 or 2 by extension, but it was ruled about view configuration, not record data, and the seat will not stretch a ruling across that boundary on its own.
ObjectCalendar.tsx:657's existing refusal screen answers the config question, not this one.⛔ Whoever takes this should not pick an option without a ruling.
Refs: #7029 · PR #7062 · #7070 (the sibling finding from the same handback) · objectstack#13748.