01230bf16b
Four real bugs, all of them the kind that show as a wrong number or a silence. tasks.Stalls compared Due against an instant while Rank compares whole calendar days through dayDelta, under a long comment about that exact trap. Both render on /tasks, so a task due at 09:00 counted as просрочено in the header from 09:01 while its own row still read сегодня. Stalls reads dayDelta now. tasks.Stalls also counted a row with no capture time as sitting, because the zero time is January of year 1. score() already guarded IsZero and Stalls did not. morning and routine both key their last-fired map by name, and neither Validate rejected a duplicate. Two routines sharing one name take turns suppressing each other, and the operator sees a routine that never runs and no error. Both Validate functions reject it now. parseHHMM checked digits arithmetically, so a stray character could cancel out. window_start: "2 :00" parsed as 04:00 and passed the validation whose whole job is catching that typo. All four positions are checked as digits, which makes the negative bounds unreachable, so they are gone. FormatRU and Spoken each carried a byte-identical open and candidate partition, now one split. They have to agree on where that line falls, or she reads one list and binds ordinals against another. The three copies of the unevidenced item loop folded into one helper. The not-a-nag check passes. All three packages are pure, return candidates, and reach no sink. (V-581)