Beagle SCM
GIT-032: .git/index (DIRC) reader in dog/git — the stage column
- Now
- OPEN
- Sev
- MED
- Rep
- ///dog
- On1
- GIT-030
- See
- BEE-022
The GIT-030 waist reads a foreign repo's ODB and nothing else, so
the STAGING AREA is invisible: nothing anywhere parses DIRC.
BEE-022 wants a stage column, and the same file carries git's
stat cache — without it a worktree column means sha1-ing every
tracked file on every run. This ticket adds dog/git/DIRC.h in
the IDX.h shape (whole mapped const slice, pure, revalidating)
plus one binding call, READ-ONLY: bee never writes an index and
never refreshes a stat entry, that stays git's own job.
Context
.git/index is git's own binary format, sorted by path, and the
one place that knows what is staged and what conflicts.
- Have:
dog/git/IDX.h (pack-*.idx v2) as the exact shape to
copy — const mapped slice, no allocation, layout revalidated.
- Have:
GITu8sDrainTree, the sibling drain whose pull shape a
DIRC entry drain should match.
- Missing: anything that reads
DIRC; bee states outright it
never reads .git/index (view/diff.js:25:o1).
- A staged-only edit is therefore indistinguishable from a
worktree one today, in
bee diff and bee list alike.
- Entries are ALREADY lex-sorted by path, so they feed a k-way
cursor merge with no sort at all (BEE-022).
Goals
One reader, one waist call, entries out in file order with the
five fields a status quad and a stat cache actually need.
dog/git/DIRC.h/.c: validate the header (DIRC, version,
count), drain entries in order, expose the trailer bounds.
- Per entry: the 20-byte sha (off 40), the u16 flags (off 60 —
low 12 the name length, bits 12..13 the STAGE number), mode.
- Per entry, the STAT CACHE: mtime (off 8) and size (off 36),
which is what lets a clean file skip being hashed.
- Versions 2 and 3 (v3's extended-flags u16 when flag bit 14 is
set); v4's varint prefix compression decoded, padding absent.
- Extensions after the entries skipped by their 4-byte name +
u32 length; the
link extension (split index) REFUSED loud.
- The binding: one call over an opened repo emitting the same
<path>#<sha> rows a tree walk gives, plus stage and stat.
Constraints
- Read-only, always: no write path, no refresh, no lock file.
- Fixed-width binary records — no ragel, but no hand-rolled
pointer walking either; slice drains per
meta/abc.mkd.
- dog stays allocation-free and caller-scratch; the map and its
lifetime are the binding's, exactly as
IDX.h has it.
- NOT in JS: bee walks no binary structs in JS by design, so
this cannot be a
Uint8Array loop above the waist.
- v1 non-goals, refused in plain words: SHA-256 repos, split
index, writing, and the TREE/REUC/UNTR extension payloads.
- Errors in plain words at the JS boundary, never ok64 codes.
WIP
Design decisions
- RACILY CLEAN is the reader's contract to STATE, not to solve:
an entry whose mtime equals the index's own mtime is suspect
and the caller must hash it — the reader reports both stamps.
- A conflicted path has THREE entries (stages 1/2/3) at the one
path; the reader emits them all and the caller collapses.
- Split index is refused rather than half-read: a partial stage
column is worse than an absent one (BEE-022 degrades).
TODOs
- [ ] W1:
dog/git/DIRC.h/.c + C tests over v2/v3/v4
fixtures written by stock git, incl. a conflicted index
- [ ] W2: the quickjab binding call + a JS test comparing the
rows against git ls-files --stage on real repos
- [ ] W3:
dog/INDEX.md gains a DIRC.h section
- [ ] fixture note: v4 needs
git -c index.version=4, v3 an
entry with --skip-worktree or --assume-unchanged
Blockers and bummers
- GIT-031 is in flight in
~/src/{bee,dog,quickjab}-GIT031
with no ticket page; this took the next free number instead.
Outcome