fix: stop the running-now header counting down to "ended"
The section header said "next after this ends in {live[1]}", which got the
question wrong in both of the ways lens.ts exists to prevent.
An event whose end was never announced has no time remaining, and the `?? 0`
that stood in for it made `formatRemaining` return its expiry string — so a
second row with `endsAt: null` had the header reading "next after this ends in
ended". That is the one rule this product is built on, inverted: an unknown end
announced as an expiry.
And `live[1]` is the second *row*, not the second deadline. The list is sorted
by whatever mode the reader picked, so under "doing first" the header named
whatever they were second-most partway through — the same mistake firstToExpire
was written to keep out of the headline, one row further down.
`followingDeadlineMs` asks the deadlines instead and returns null when there is
no second dated end, and the header then says nothing at all.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
447ea25632
commit
4fe563dcbb
@@ -71,6 +71,31 @@ export function firstToExpire<T extends Row>(rows: readonly T[]): T | null {
|
||||
return nextToExpire(rows, 1)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* How long the deadline *behind* the closest one has left, or null when there
|
||||
* is not a second dated deadline to report.
|
||||
*
|
||||
* The "Running now" header uses this to say what falls due after the row at the
|
||||
* top. It asked the list for `rows[1]` before, which was wrong twice over and
|
||||
* in the two ways this module exists to prevent.
|
||||
*
|
||||
* The list arrives sorted by whatever mode the reader chose, so under "doing
|
||||
* first" `rows[1]` is the second thing they are partway through — the same
|
||||
* mistake `firstToExpire` was written to stop the headline making, one row
|
||||
* further down. And an unannounced end has no time remaining at all, so the
|
||||
* old `?? 0` handed `formatRemaining` a zero and the header read "next after
|
||||
* this ends in ended": the `endsAt: null` rule turned into a claim that
|
||||
* something expired, which is exactly backwards.
|
||||
*
|
||||
* So it reads the second *dated* deadline and returns null rather than a
|
||||
* stand-in, and the caller omits the line when there is nothing to say.
|
||||
*/
|
||||
export function followingDeadlineMs<T extends Row>(
|
||||
rows: readonly T[],
|
||||
): number | null {
|
||||
return nextToExpire(rows, 2)[1]?.clock.msRemaining ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The focused game, if it is still a game the reader can see.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user