Changelog
0.2.1 — Dial header search opens Search mode instead of pinning
Picking a lead from the header search now displays it in an ephemeral Search mode that never enters the bucket queue or bypasses filters.
What's fixed
- A lead tagged
Lostno longer reappears in a bucket whose filter says "Tags is not Lost". The root cause was header search: picking a lead unconditionally pinned the row past every filter and persisted the pin to localStorage with no un-pin action. Each subsequent dial refreshed the pin's staleness guard, so once a pinned lead was later taggedLost, it was trapped in the bucket indefinitely.
What changed
- Search mode is ephemeral. Picking a header-search result now sets an in-memory Search mode that displays the lead with the bucket's render config (field map, scripts, detail columns) but never enters the queue and never bypasses filters, cap, cooldown, or the active-appointment check. A header Search pill shows the lead name, an "outside filters" hint when the row wouldn't normally match the bucket, and an exit button back to the queue.
- Disposition / skip returns to the queue. Recording a result against the searched lead writes the activity, then drops you back into the bucket's auto-cycle where you left off. Search mode clears automatically.
- Pins are session-only. localStorage pin persistence is removed
entirely. The mid-call anti-yank carve-out still protects the active
queue lead from filter changes, and the next-meeting badge still pins
the linked lead past the active-event filter — but both are
session-only and clear on reload. Legacy persisted
pinnedRowIdsrecords from older clients are ignored on read.
Under the hood
- New
searchedLead = { bucketId, rowId, outsideFilters }state decouples render config from queue membership.currentRowreadssearchRow || queueRow;pinnedRowIdRefstays bound to the queue row so the search path can't re-enter the filter carve-out. loadLeadIntoDialer(which pinned) is now called only by the next-meeting badge. Every other "jump to this lead" surface flows through Search mode.- Regression coverage:
dialBucketRuntime.test.jsasserts that a row matchinghas YTQbut also carryingnot_has Lostis excluded when unpinned;DialSearchWiring.test.jsxwas rewritten to assert search picks setsearchedLeadand never pin or move the queue cursor;dialCursorStoragetests cover the dropped pin helpers and the legacy-payload guard.
0.2.2 — Server-side dial queue, authoritative leasing, sensitive Lead Details
The dial queue is now computed in Postgres with keyset pagination, two operators on the same bucket can no longer double-dial, and sensitive Lead Details fields reveal on click with an audit trail.
0.2.0 — Version tracking & changelog
The app now knows when it's outdated and offers a one-click refresh. Release notes live here.