LITE-044 DONE: list dir rows go blank at scale — the 512-commit dir fuse starves

Now
DONE
Sev
MED
Ask
gritzko
Rep
///lite
See
LITE-017
See
LITE-013

On the linux tree, /list/include/drm/ fuses every FILE row but leaves the dirs amd/ bridge/ clients/ display/ with no commit message at all (gritzko, 2026-08-15, http://localhost:8888). The dir half of the LITE-017 fuse walks only the newest DIR_WALK_CAP = 512 commits, and at linux scale everything below the first level starves: the four dirs' newest commits sit 2072, 32176, 94935 and 151871 commits behind the tip. The file half never starves — one exact lane prefix scan — and that asymmetry is the bug.

Input

Context

lite/index/list.js dirCommits: CPAR ancestry newest-first, rd.entryAt per dir per commit, capped at 512 (LITE-013 style); past the cap a row keeps no summary and no age — documented ceiling behaviour that is fine on small repos and useless on linux.

Goals

A dir row's attribution is as exact as a file row's, at any repo scale: /list/include/drm/ shows the newest commit UNDER each of amd/ bridge/ clients/ display/, with an age, on the served linux tree.

Constraints

WIP

Design decisions

The indexer says WHEN a dir changed; the fuse reads the newest of those rows. No history walk survives on either side, so depth and scale cost nothing.

  1. descend() (index/index.js) already visits exactly the CHANGED dirs of a commit — it prunes any subtree equal to a parent's — so it now emits a node for each of them too, the parent before its children, tagged dir: true.
  2. emit() mints a DIR rev as ONE row: REV-CMMT, key path_hl(dir)|rev|2, val the commit. Nothing else: no REV-BLOB (a subtree sha is no blob), no REV-PARS (a dir has no content to fold), no B2P, no FSEG (that names a FILE for resolve.js's descent, which only ever answers files). No new kind.
  3. A hot dir changes in most commits, so its rev chain is as long as the HISTORY. Folding it whole the way loadPath folds a file's brings back the LITE-028 stall — MEASURED on its own fixture: the reads doubled with the lane, 227/4002 then 457/8004, against a bound of 64/116. Rev chains are DENSE, so the highest rev is found by galloping and then bisecting EXACT-key probes (lastRev): O(log k) seeks and not one row of the chain. loadDir fills the indexer's arrival state from it.
  4. The fuse (index/list.js lastCommits) is one lookup per entry, off that entry's OWN rows: a FILE folds its chain through fileLog as before (short, and PARS is what orders a rewritten file history), a DIR takes its last rev straight. dirCommits, the CPAR ancestry, DIR_WALK_CAP and opts.cap are all gone — there is no tip and no ceiling in the dir answer any more.
  5. STALE INDEXES. Presence is the walk boundary, so an old lane's commits never re-derive and its dirs would stay blank forever. The lane FORMAT is therefore its file EXTENSION — .lite.idx becomes .lite2.idx — and openIndex SWEEPS (unlinks) every file of an outdated format before the family is opened. No reader ever opens a lane it cannot answer from, and the next run derives from scratch. Cost: one full re-derive per repo.
  6. lindex skips the dir nodes descend now yields; no other consumer exists.

TODOs

Blockers and bummers

Outcome

RED, at the real 512 ceiling: a 2000-commit fixture whose ancient/ was touched at C0 only listed ancient/ with no summary and no age — gritzko's linux screenshot, reproduced. GREEN: ancient/ c0 5y, and one level down ancient/deep/ -> er/ c0 5y; list at the root takes 18 ms.

Changed: index/index.js (dir nodes, emitDir, lastRev/loadDir, the format bump and sweep), index/list.js (lastCommits, the cap gone), index/lindex.js (skip dirs), INDEXES.mkd, and the pinning tests test/list/{run.sh,fuse.js} plus the lane-shape assertions in test/index/run.sh (5 -> 7 revs, the new extension) and test/first/run.sh.

Suites under a fresh quickjab build: list 85 PASS (78 before), index 129 PASS, first 18 PASS, serve 174 PASS, lindex 31 PASS, and every other lite suite green (blob 13, cat 35, chat 148, click, commit 45, commitnav 32, cursor 43, hook 14, land, logspine 41, mark 66, merge 46, now 42, perma, refline, rst 92, tree 47). diff (1 of 34) and pager (1 of 33) fail identically on the UNTOUCHED main tree — pre-existing, not this ticket's.

LITE-044: dir revs — the list dir fuse reads the lane