file.c:k4:d8K3, blob offset + blob hashletgritzko's ruling 2026-08-14: a text-file permalink is file.c:k4:d8K3 — segment 1 a ron64 BYTE OFFSET into the named blob, segment 2 the BLOB's ron64 hashlet, ONLY ever a blob hash (commit-id tier overruled same day). Nav: resolve the file name (may hit several files — chooser), find that blob in the path's history, count to byte k4 there, find the same place in the current/required version, open, set the cursor. Blob offset, never a weave/insertion offset: the fold's ranges are tokenizer-dependent, a weave rebuild would re-point every link; blob bytes are canonical git ground. The DOG-034 lexer already fuses both segments (pathanchor, ron64{1,10} twice), so the grammar is DONE — this ticket is the door/resolution/mint half, extending the LITE-024 :line:col landing.
LITE-024 lands file.c:12:24 on the line via the door's splitRef (the ONE split point in openTarget) and the LITE-023 cursor; both anchor segments are lexed into the fused F token since DOG-034. CFOLD (DIS-082, quickjab/dog/CFOLD.h) stores per-commit 'C' records: canonical id (hi64 sha1), body range, P_c view length; CFOLDBlame maps a body offset to its inserting commit; CFOLDIterNext walks any rev's view.
:123 line; :123:45 line:col, current version only (both all-digit); :k4:d8K3 permalink (segment 2 carries a non-digit).:line:col or pins the pre-edit blob.Door leg + resolution walk + mint gesture; line:col behavior unchanged.
splitRef learns the permalink form — segment 2 non-digit routes to resolution instead of the line:col shed; miss stays the quiet plain-words bar message.k4 in that blob -> forward-map to the current/required version -> open, cursor on the row:col via LITE-023.:line:col.///quickjab worktree (its dog sub carries DOG-034; ///jab/dog and installed jab are STALE — run pty probes with LITEJAB=<quickjab build>); door/pager/tests in ///lite. No VC ops.F token bytes; no regex, no URI machinery, no new grammar.P_c gives the bounds check for free.:123, :123:45, :k4:d8K3, all-digit segment 2), earliest-match blob collision, worktree-only blob, multi-file path chooser leg: bar leg///quickjab's dog (39158d0c); stock jab fuses no path anchors — same bummer as LITE-024.NAV HALF ONLY (mint untouched, out of scope by order). Worker wt
work/LITE-025, lite base ///lite/#efa67a47 — which ALREADY CARRIES
LITE-024 (3d0ecd67) and LITE-023 (1d0b187b), so nothing had to be ported
from the LITE-024 worktree. 5 files jab put, NO commit.
index/perma.js NEW (369): the whole walk. hashletHex unpacks the ron64
pairs through ron.decode (12 bits a pair, 3 hex, big-endian — no alphabet
table of its own); scope is ONE FILE — blobsFor takes the path's own
commits (log.js fileLog, oldest first) whose blob AT THAT PATH carries the
prefix, earliest picks among them, then blobIdOf (git's blob <n>\0
framing) answers for a working-copy-only blob. Forward map: ONE CFOLD pair
(anchored blob, then the worktree bytes on top — index/diff.js's own
scratch-buffer discipline), walk at the anchor rev to name the token
covering the byte (its body offset IS the identity), walk at the head rev
for where it sits now; a dead token lands where it stood and deleterOf
names the commit that took it (bounded at 64 folds).main.js +39/−1: permaTail() decides the form on SEGMENT 2 (even, 4..10
ron64 chars, one non-digit) inside the ONE splitRef split point; openPerma
is the door leg — the chooser hunk carries the anchor on every row, a miss is
the same quiet plain-words bar line a path miss gives. splitRef exported
for the fixtures.view/pager.js +3: _openPush shows land.note on the bar. No path math
added; the row:col landing is LITE-024's _land() unchanged.test/perma/{run.sh,pty.js} NEW (135+332): PASS 51 checks, 0 bad — real
openpty, SGR presses, : bar typed through the pager's own input. RED
FIRST: the same file against a pristine clone (only splitRef exported and a
null perma.js stub so it loads) is 35 of 51 bad. Fixture: 40 fixed-width
16-byte lines so a blob offset is arithmetic, r1 prepends 5, r2 deletes one
above the anchor (anchored line 20 -> line 24 today), r3/r4 make
src/abc/TCP.c LEAVE its r0 blob and REVERT to it (a real earliest-match
collision, asserted to anchor at r0), net/TCP.c edited but NOT committed
(the working-blob leg), TCP.c byte-identical in two dirs (the chooser).perma.Spec/code notes for gritzko, nothing improvised around:
.git/index (index/diff.js's own stance), so a staged-only change reads as a
worktree one. If a real index reader is wanted, that is a separate leg.quickjab/build-release carries DOG-034 but is built with
QUICKJAB_JSRC_PACK=ON, and a packed build is bundle-ONLY — it ignores a
lite worktree entirely, so it silently tests the BUNDLED lite. Every other
quickjab/build* binary predates DOG-034 and fuses no anchors. Probes here
ran on an out-of-source unbundled build at ~/tmp/l25/qjb/bin/quickjab
(cmake -S quickjab -B ~/tmp/l25/qjb -DQUICKJAB_JSRC_PACK=OFF); the quickjab
tree stayed untouched (jab status clean).Suggested commit (lite wt): LITE-025: permalinks follow the blob anchor