abc.index (point / range / prefix)
The lane containers (HASH/HEAP/HIT) expose the LSM primitives but not a reusable index. Add abc.index(lane, opts) — a stack of mmapped sorted runs + a memtable, with point/range/prefix query and ladder compaction. This is the substrate the pack-log index (JS-024 git.pack) builds on. Method: Issues.
js/cont.cpp binds HASH (sets/maps), HEAP (sorted runs + sort), and
HIT abc.merge/abc.intersect — the LSM building blocks — but NO index control structure or query verbs over a stack of persisted runs.
wh128 puppy registry (KEEPLookup point/prefix, KEEPCompact 1/8 ladder) and spot wh64 trigram (CAPO SeekRange). Design pass produced this scope.
abc.index(lane, opts) → object owning runs + memtable, with .put /
.flush / .compact / .get (point) / .range / .prefix / .seek.
opts.dir: *present* → persisted file runs
(abc.book, re-opened on open); *absent* → ephemeral io.ram runs (no files, gone at exit). Same leaves/memtable/compaction; only run backing + persistence differ (JS-side branch).
.range/.prefix,
rule #4). PULL via .seek(needle) → a cursor (.next / .key / .val / .entry) to read several entries at your own pace, stop anytime.
[p, p+2^lowBits) (spot-style). Hits are a BigInt,
[k,v] pair, or blob per lane.
flush = memtable.sort() → abc.merge into a fresh
run → push onto .runs. ON-DISK run = abc.book file (close msync+trim, rename, re-open RO); IN-MEMORY run = io.ram (kept as-is, no file). Runs are immutable (growth = new runs).
.seek(needle) is a PURE-JS k-way merge cursor: per-run positions seeked via
_findge_<lane>, a tiny JS heap + newest-wins dedup, reading lane elements off the run typed-array views; JS owns ALL cursor state (rule #4 — no held native state, like the ULOG/HUNK cursors). .range/.prefix may be sugar over it or keep the native _seekrange_ fast-drain — implementer's call.
hit.hpp-sized leaves in a new js/index.hpp (registered in
JABCContInstall): _findge_<lane> (binary-search point, mirrors KEEPLookup), _seekrange_<lane> (binds HIT<lane>SeekRange), _compact_<lane> (binds HIT<lane>Compact — the 1/8 ladder, keeper/spot parity, full-element dedup + newest-run-wins). NO keyed/tombstone compaction.
lo/hi are BigInt; mind lane
alignment on re-mmap; validate byteLength % (w*BPE) === 0 on open.
abc.index lives in the JABC_CONT_JS bundle (like Buf/pol);
js/index.hpp holds the 3 leaves. v1 deletes = newest-run shadows older at query time (no tombstone drop) — DOCUMENT it.
be get --nosub onto current trunk (JS-021 landed); build.js/test/index.js (model on hit.js) — build wh128 + u64
runs, flush, compact to the 1/8 ladder, assert POINT/RANGE/PREFIX vs a brute-force JS oracle. Red before, green after.
abc.index object; doc INDEX.md / API.md.keeper/pack-log) is out of scope → JS-024.5d162989 (2026-06-21): abc.index(lane, opts) — generic mmap LSM
over u64/wh128: put/flush/compact (HIT<lane>Compact 1/8 ladder)/ get/range/prefix (half-open)/seek. ON-DISK (opts.dir → abc.book files, re-opened) vs IN-MEMORY (no dir → io.ram, ephemeral). .seek(needle) = pure-JS pull cursor (per-source _findge_ + JS min-heap + newest-wins dedup; rule #4, memtable snapshot on seek). 3 leaves in js/index.hpp; flush path pure JS; added io.rename/io.mkdir. js/test/index.js (JABCindex) vs a brute-force oracle red→green; ctest -R JABC 20/20, ASAN/LSan clean.
.range/.prefix (native _seekrange_ drain) do NOT dedup across
runs; .seek does. kv64 + keyed/tombstone compaction deferred.