The low-severity leftovers from the panel audit, plus the tooling trap that made
reviewing this work harder than it needed to be.
.gitattributes (new) — `public/projects.ts diff`
That file embeds literal NUL bytes on purpose: the namespace sentinels
'\0active' / '\0other' are prefixed so they cannot collide with a real
`First.Second` key. git therefore classified it as binary and printed
"Binary files differ" for every diff, and `git diff --stat` reported
"Bin 66815 -> 68701 bytes" instead of line counts — the file was effectively
unreviewable. The `diff` attribute makes git diff it as text without setting
`text`, so no line endings are normalised and the bytes on disk are untouched.
(Same trap in the shell: grep prints only "Binary file ... matches", which
reads as a no-match. The comment in the file says to use grep -a.)
Detached HEAD now shows its short sha
The Head cell held the "detached HEAD" chip and nothing else: it said what was
wrong and nothing about where you were. SyncState gains an optional `head`,
populated from the .git/HEAD text readSyncState ALREADY reads for the detached
test — so this costs no extra I/O and no extra git call. Guarded by a hex regex
and rendered as textContent.
One geometry for the ghost button role
The design defines two button roles. The outline one had drifted to three
different sizes (.proj-wt-open at 11.5px/4px 12px/6px, .proj-diff-toggle at
12.5px/7px 15px/7px) and both used full-strength --text instead of the muted
label. All four outline buttons are now declared once, together, at the
design's geometry; the duplicate .proj-diff-toggle block further down the file
is gone, since a second block at equal specificity is exactly how the role
drifted in the first place.
Header branch chip joins the chip language
.proj-branch was the only chip with no border and no mono face, and 1px tighter
all round, so the detail header's branch did not match the branch chips in the
worktree list right below it.
"Changes" heading over the View Diff toggle
Every other block on the page is introduced by a section heading. Without one
the toggle hung 4px off the bottom of the sync band and read as part of it.
Tests: 2167 unit (4 new — detached sha present/absent on both the server and the
panel) and 27 integration, twice.