Build Log · June 22, 2026
Hearth: Copied Item Polish
Tighter dedup, honest time display, source labels, and remove — the loop is coherent. Ready for Courtney.
- Hearth
- UX
- Data Model
- Bug Fix
- duplicate detection fix
- 1
- time ghost closed
- 1
- new server action
- 1
- RouteItemCard label paths
- 2
duplicate detection fix
time ghost closed
new server action
RouteItemCard label paths
Timeline
Start
Plan review + time ghost catch
Zeb flagged scheduledTime on copied items implies today's time — plan adjusted before build
20m
Duplicate detection fix
OR(sourceRouteItemId, sourceGoogleEventId) — defensive null guard
40m
removeFromTodayRoute action
Hard delete of Hearth copy only — guard, delete, revalidate /today + /week
1h
RouteItemCard: source label + time suppression
isCopiedItem → liveScheduledTime = null, buildSourceLabel shows original day/time
1.5h
Remove button + tsc clean
Copied items: Done + Trash2 only. Native items: unchanged. tsc passes.
What shipped
addToTodayRoute: OR duplicate check — sourceRouteItemId OR sourceGoogleEventId (only when source.googleEventId exists — avoids eq(field, null) weirdness)
removeFromTodayRoute server action: fetches item, guards on sourceRouteItemId || sourceGoogleEventId, hard-deletes Hearth copy, revalidates /today and /week — Google Calendar untouched
RouteItemCard: isCopiedItem = !!(sourceRouteItemId || sourceGoogleEventId)
RouteItemCard: liveScheduledTime = isCopiedItem ? null : item.scheduledTime — copied items never render a clock time badge
RouteItemCard: buildSourceLabel() — 'From Google Calendar · Original: Sat 10:00 AM' or 'Added from Week · Original: Tue' — quiet italic text-[10px]
RouteItemCard: copied items get Done + Trash2 (destructive ghost) only — Move/Skip/Note hidden since they don't apply to a reminder-copy
RouteItemCard: removed state returns null immediately on client — no flicker waiting for revalidation
“Hearth should feel like a calm route, not a calendar in a trench coat.”