The calendar resolves priority itself, and disagrees with the backend #93
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#93
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while scoping conflict detection for #48 batch C. This is the same class of bug as #43 — priority resolution not being the one used for real — but on the frontend side, and still open.
The divergence
buildDayMap(frontend/src/components/calendar/utils.ts:44-49) does its own resolution:services/priority_resolver.get_events_for_date— the one that decides what actually reaches the controller — does three things this does not:event_date_overrides)parent_event_id)_SOURCE_RANK(user 3, builtin 2, system 1)So the calendar can show a different primary event than the one Iris will push.
This is not theoretical
Against the real dev database, 2026 has 248 days with events, 91 with more than one, and 43 where the top priority is tied — decided by a tiebreak the calendar does not implement:
On each of those 43 days the displayed primary is whatever order the API happened to return, while the pushed primary is chosen by source rank.
The pin case is worse
event_date_overridesis never fetched by the calendar — there is nogetDateOverride/listDateOverridesinapi/index.ts, andbuildDayMap(events, schemes, year)has no parameter for it.So "Promote Secondary" appears not to work. The mutation succeeds and the backend honours the pin on the push path (fixed in #43), but the calendar recomputes from events alone and keeps showing the old primary. From the user's side the button looks broken — which is precisely the symptom #43 set out to fix, reintroduced one layer up.
I have not confirmed this end-to-end against a running instance with a pin set; it is read from the code. Worth verifying before fixing, in case a refetch masks it somewhere I have not spotted.
Why it blocks batch C
Items 1 and 2 of #48 are the day-cell
⚠ conflicticon and a "conflicts only" filter. Both need to know which events contend for a day and which one wins. Building that onbuildDayMapwould mean encoding the tiebreak a second time, in a third place, and the conflict flag would then disagree with the backend exactly where it matters most — the tied days.Suggested fix
Give the backend one resolved-day endpoint and let the calendar render it, rather than re-deriving:
built on
get_events_for_date, so there is a single source of truth. Theconflictflag comes free: it istruewhen 2+ events share the top(priority, source_rank), which is the honest definition — a winner chosen arbitrarily rather than by priority.That also removes duplicated date arithmetic and the shadowing/pin logic from the client entirely.
Alternative, if a new endpoint is unwanted: expose
event_date_overridesfor listing and port shadowing plus source-rank tiebreak intobuildDayMap. Cheaper now, but keeps two implementations that must be kept in step — which is what produced this.Note on scope
Spec §2.4 is explicit that a month-long backdrop being overridden by a higher-priority day event is normal, not a conflict: "Any higher-priority event on a given day naturally overrides the backdrop for that day, without any special configuration." So
⚠should mean tied at the top, not merely more than one event — 43 actionable days rather than 91 noisy ones.