Skip to content

fix(analytics): escape the NUL separator so usage-ledger stops being binary - #30

Merged
oratis merged 1 commit into
mainfrom
claude/fix-ledger-nul-bytes
Aug 9, 2026
Merged

fix(analytics): escape the NUL separator so usage-ledger stops being binary#30
oratis merged 1 commit into
mainfrom
claude/fix-ledger-nul-bytes

Conversation

@oratis

@oratis oratis commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Summary

summarize()'s compound cache key used a raw 0x00 byte written directly into the source — a literal control character, not the escape sequence. Git classifies a file with a NUL in its first 8000 bytes as binary, so:

before
git diff Bin 9679 -> 10779 bytes (the real change is invisible)
git blame doesn't work
file data, not UTF-8 text

Worth noting how it got in: I merged it in #17, and the reason nobody caught it is the bug itself — the file was undiffable, so review had nothing to look at.

The separator choice is fine: NUL can't collide with a YYYY-MM month or any agent_id. Only the encoding was wrong. Both occurrences are now the escape sequence, which evaluates to the same U+0000 character, so getWorkspaceUsage / getPlatformUsage group byte-identically.

Test plan

  • 0 NUL bytes remain; file reports Unicode text, UTF-8 text
  • The template still evaluates to a string containing U+0000 (length 16 for "2026-08" + NUL + "research")
  • End-to-end aggregation still separates same-month agents (2026-08/research=8, 2026-08/strategy=7, total 15)
  • npm test 678/678

Credit

Found by the background session on #27. That branch was cut before #23 and would have reverted that PR's documentation on this same file, so the two-byte fix is applied to current main instead and #27 can close.

🤖 Generated with Claude Code

…binary

The compound cache key in summarize() used a raw 0x00 byte written
directly into the source — a literal control character, not the escape
sequence. Git classifies a file with a NUL in its first 8000 bytes as
binary, so `git diff` reported "Bin 9679 -> 10779 bytes" instead of the
change, `git blame` stopped working, and `file` reported `data` rather
than UTF-8 text.

Worth noting how it got in: I merged it in #17, and the reason nobody
caught it is the bug itself — the file was undiffable, so review had
nothing to look at.

The separator choice is fine: NUL cannot collide with a YYYY-MM month or
any agent_id. Only the encoding was wrong. Both occurrences are now the
escape sequence, which evaluates to the same U+0000 character, so
getWorkspaceUsage / getPlatformUsage group byte-identically.

Verified: 0 NUL bytes remain, `file` reports UTF-8 text, the template
still evaluates to a string containing U+0000, and an end-to-end
aggregation still separates same-month agents correctly. npm test
678/678.

Found by the background session on PR #27, which was branched before #23
and would have reverted that PR's documentation on this file; applied
directly to main instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@oratis
oratis merged commit 7c72ddb into main Aug 9, 2026
5 checks passed
@oratis
oratis deleted the claude/fix-ledger-nul-bytes branch August 9, 2026 15:16
oratis added a commit that referenced this pull request Aug 9, 2026
…nded (#31)

Two defects found while reviewing the #23#30 batch, both now on main.

**Wrong PR credited.** #29's .gitattributes header and memory.md §6 both
say #27 fixed the usage-ledger NUL bytes. #27 was closed as a duplicate —
#30 landed the identical fix (verified byte-for-byte identical trees).
Anyone following the reference lands on a closed PR with an empty diff.

**The count treadmill.** #26 corrected five hardcoded test counts from
234/377/656 to the then-accurate 678. #28 merged minutes later and made it
679, so a PR whose entire purpose was de-staling docs shipped a number that
was stale on arrival. Five copies of a figure that changes on every
test-bearing merge cannot stay right.

Counts are now stated as a magnitude pinned to a commit ("~680 as of
c7c7d5b") with an instruction to measure instead of cite, and the two
places that only needed "all green" no longer carry a number at all. The
prose that never had one ("Vitest files under client/src/{...}") aged fine
through this whole batch, which is the argument.

memory.md §5.2 records the pattern so the next doc pass doesn't reinstate
it. The remaining 234/656 mentions are deliberate — they are the history
being explained, not live facts.

Verified: 679/679 serialized on this branch; grep confirms no stale
hardcoded count or bare #27 reference survives.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant