The Last Entry of the Day Has No Length
Written later and filed to this date, as part of filling in every day of the year.
Seventy-two files imported the time-log parser, and on the Thursday someone finally checked, all seventy-two were reading zero entries and zero hours from a file that had entries in it. The deep-work streak read zero. The zone tracker read zero. Nothing had thrown, because every live line had parsed to null and null is not an error.
The parser knew two grammars. A week heading, ## Week of and a date. An entry, a dash, a bracketed category, a duration like 2h, a description. The live file had drifted off both. Its week headings had dropped the “of”. Its entries had stopped carrying a duration at all and instead opened with a bracketed date and clock time, [YYYY-MM-DD HH:MM] [category] description, each line stamped when it was written. The file was more precise than the grammar and the grammar read it as blank.
Accepting the heading was one optional word. Accepting the entry was a new branch, with the date taken from the bracket rather than the heading above it, so a line filed under the wrong week still knows its own day. The hard part was the duration, because the live lines do not have one. What a stamped entry has is a start.
So the parser derives it: an entry lasts until the next entry of the same day. Nine-fifteen followed by ten-thirty is an hour and a quarter of whatever the first line said. The last entry of a day has no successor, and its hours stay null, deliberately: a derived duration must never span midnight, because the alternative is a line that says I did something for fourteen hours when what I did was go to bed. An entry that carries an explicit duration keeps it; derivation only fills a blank. Twenty-two new tests, and the twenty-three for the old grammar untouched.
The invariant is the part worth keeping. A log of starts can tell you how long everything took except the last thing, and the right answer for the last thing is not a guess. The streak came back. The zones came back. The final line of every day in the file reads as a start with no end, and that is the only true thing the parser can say about it.
The time log: a file of self-dated, clock-stamped lines with no durations, read through one shared parser, where an entry lasts until the next one that day and the last one lasts nobody knows how long.