@@ -195,6 +195,10 @@ final class LiveTailViewModel {
195 hiddenColumns = []
195 hiddenColumns = []
196 savedHiddenColumns = []
196 savedHiddenColumns = []
197 columnFilters = []
197 columnFilters = []
198+ // Clear the text filter too. Leaving it set while clearing the column-filter
199+ // chips is inconsistent and would let a stale search from a previous stream
200+ // make the fresh tail come up appearing empty or partially filtered.
198 currentStream = stream
202 currentStream = stream
199 rebuildFilteredEntries()
203 rebuildFilteredEntries()
@@ -246,6 +250,9 @@ final class LiveTailViewModel {
246 hiddenColumns = []
250 hiddenColumns = []
247 savedHiddenColumns = []
251 savedHiddenColumns = []
248 columnFilters = []
252 columnFilters = []
253+ // Match start(): clear the text filter alongside the column-filter chips so
254+ // a clear()ed tail isn't immediately re-hidden by a lingering search string.
249 rebuildFilteredEntries()
256 rebuildFilteredEntries()
@@ -580,7 +587,19 @@ final class LiveTailViewModel {
580 // (with NaN folded to a single bit pattern) so a field that serializes as `5`
587 // (with NaN folded to a single bit pattern) so a field that serializes as `5`
581 // in one poll and `5.0` in another doesn't bypass dedup as a phantom row.
588 // in one poll and `5.0` in another doesn't bypass dedup as a phantom row.
582 case .int(let i):
589 case .int(let i):
590+ // If the integer round-trips losslessly through Double, hash via the
591+ // Double path so `.int(5)` and `.double(5.0)` (which are ==) share a
592+ // fingerprint. Integers beyond 2^53 lose precision in Double, so two
593+ // distinct values (e.g. 2^53 and 2^53+1) would otherwise collide and
594+ // the second would be silently dropped as a phantom duplicate — the
595+ // dedup set has no `==` fallback. No Double can equal such a
596+ // non-representable integer, so hashing its exact 64-bit pattern can't
597+ // wrongly merge it with a `.double`.
598+ if let exact = Int(exactly: Double(i)), exact == i {
583− hashNumberBits(Double(i).bitPattern, h0: &h0, h1: &h1)
599+ hashNumberBits(Double(i).bitPattern, h0: &h0, h1: &h1)
601+ hashNumberBits(UInt64(bitPattern: Int64(i)), h0: &h0, h1: &h1)
584 case .double(let d):
603 case .double(let d):
585 // Canonicalize NaN (so all NaNs fold together) AND signed zero: JSONValue
604 // Canonicalize NaN (so all NaNs fold together) AND signed zero: JSONValue
586 // equality treats `-0.0 == 0.0`, but their raw bit patterns differ, which
605 // equality treats `-0.0 == 0.0`, but their raw bit patterns differ, which