Skip to content

spec: appearance.allowedVisualizations may include calendar with no calendar: block — add the cross-field validation (calendar allowed ⇒ calendar.startDateField required) #13817

Description

@huangyiirene

Ruled on #13748 (2026-08-31, director batch #19, option A — fix both halves). This is the objectstack half; the objectui half (removing the invented due_date default) is objectui#7029.

The gap

  • packages/spec/src/ui/view.zod.ts:945allowedVisualizations is optional;
  • packages/spec/src/ui/view.zod.ts:1679 — the calendar: config block is optional;
  • there is NO cross-field check tying the two together. A view declaring appearance.allowedVisualizations: ['grid','calendar'] with no calendar: block passes metadata validation.

Downstream (measured on #13748, hotcrm pinned at @objectstack/* 17.1.0): the calendar toggle renders and is clickable, objectui invents startDateField: 'due_date' (app-shell ObjectView.tsx:2220), the renderer lands every record whose invented field is absent on "today" (ObjectCalendar.tsx:445), and the author gets a plausible-looking, fully wrong screen — all 9 leave requests piled on today's cell. The renderer's own refusal screen (ObjectCalendar.tsx:657) is unreachable because the synthesized config always looks complete.

Deliverable

A cross-field refinement on the list-view schema: when appearance.allowedVisualizations contains calendar, require the calendar: block with startDateField. Only startDateField is load-bearing — title resolution has the ADR-0079 display-name fallback chain; ⛔ do not require more than the renderer actually needs.

⚠️ Scope: calendar only — the measured defect. If timeline or another visualization has the same shape, that is a separate finding to measure first, not a rider here.

Pre-landing census (required — write the result into the PR)

Count existing views in the reference apps (hotcrm at minimum) that declare calendar without the block and currently render only via objectui's invented due_date guess. Each one flips from "coincidentally renders" to a build-time red — that is the ruled loud-over-silent direction, but the PR must name the population rather than discover it in CI.

Gates

Clause-②: YES — path limb packages/spec/src/**, content limb = accept-behavior tightening (previously-valid metadata becomes invalid). Dispatch at the contract-review tier; changeset marks the tightening.

Refs: #13748 (phenomenon record, closed by the ruling), objectui#7029 (runtime half), #13751 (unrelated navigation bug on the same surface, separately queued to objectui).

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions