SPOT-003: spot.js tree search lazy trigram index, seen-tree/blob memo, dirty bypass

Now
OPEN

Input

Context

SPOT-002 locates within hunks; this ticket is the tree-wide search that feeds it candidate files. The C impl (spot/CAPO.h §"Index entry layout", CAPO.c scan/tip-walk) is the model: an LSM stack of sorted 8-byte postings under .be/*.spot.idx, a per-blob memo that makes indexing incremental, and a worktree scan where the index only ever EARLY-REJECTS clean files.

Goals

shared/spotidx.js (or views/spot/): trigram index maintained lazily AT SEARCH TIME search never requires a prior index pass, the index only makes it faster.

Constraints

WIP

Design decisions

tris = trigrams(needle)                    // a handful
cand = null
for t in tris (rarest range first):

ids = k-way-merge over runs of the contiguous block [t] // sorted path_hls cand = cand==null ? ids : intersect(cand, ids) // sorted merge if empty(cand): return NO MATCHES ANYWHERE // early out, no walk

for file in classify(wt):

dirty/untracked -> open+match path_hl(file) cand -> open+match // binary search in cand else -> reject

open(repo)              // find + mmap .be/ *.spot.idx runs → idx {runs[], fresh}
close(idx)              // flush fresh as ONE new run; compact past the 1/8 ratio
ent(type, off40, hl20)  // pack; entType/entOff/entHl unpack — SPOT-002 side

// never touches raw entries

trigrams(needle) // RON64 trigram set, CAPOTri40 packing; null when no

// 3-char run no filter (full scan)

pathHl(relpath) // the 20-bit full-path hash, ONE fn: postings+memos+gate ensure(idx, ref) // lazy tip-walk AT SEARCH TIME: TREE hit prune subtree,

// BLOB hit skip blob, else store-read + tok.parse // TRI postings + BLOB row; TREE row on subtree complete

candidates(idx, tris) // the filtering algo above; tris is CNF AND-list of

// OR-clauses of trigrams (flat needle singleton // clauses; regex fold from /todo/DOG/DOG-022 real // clauses); OR = union of blocks, AND = intersect; // [] = no match anywhere, null = unfiltered

gate(cand, step) // classify verdict SCAN | REJECT: dirty/untracked

// always SCAN; clean tracked binsearch pathHl in cand


TODOs

Blockers and bummers

Outcome