SUBS-039/LOG-002 taught the be/ JS READ views to DESCEND into a mounted sub when the query path falls there (jab log:be logs the sub's OWN history, correct). But a descended view still emits its per-row / per-leaf nav URIs STORE-AGNOSTIC — WITHOUT the descent prefix. The pager re-dispatches each nav URI as a fresh jab <uri> FROM ITS OWN CWD — the SAME base the original call used (ctx.repo == be.find(cwd), core/loop.js:269). So an emitted URI's path must be expressed RELATIVE TO THAT BASE, exactly like the original log:<path> arg; a bare commit:?<sha> names a sub object the base store can't resolve → dead nav. The quantity to prepend is NOT an absolute top-wt path but the DESCENT DELTA relative to ctx.repo — precisely the joinPrefix accumulation descendSub computes and THROWS AWAY. This keeps links cwd-INVARIANT: from the journal root the link must read commit:be?<sha>, but cd be && jab log: has base = the be sub itself, descends nothing, so the link must STAY commit:?<sha> — prepending be there would be WRONG. Worse still, the TARGET read views (commit:, blob:, tree:, size:) do NOT descend a <sub> prefix at all (sub-blind — only log learned descendSub), so even a correctly base-relative commit:be?<sha> won't round-trip yet. This is the READ-side twin of SUBS-039 (the state-verb path-delegation primitive): a descended read view must (a) emit URIs prefixed by the descent delta relative to ctx.repo, and (b) the target read view must DESCEND that prefix from the same base before resolving. Scope be/ JS; parent DIS-058; see Submodules, BRO-006; method Issues.
jab = beagle/build/bin/jab):jab log:be row 1 → a715b0d3 07:21 SUBS-044: … — the be SUB's owncommit (correct, per LOG-002).
U click-target is the QUERY form with the FULL 40-hex
sha and NO path — commit:?a715b0d3604deac807d6262279e2ed48f968cac8 (verified via jab log:be --tlv). log.js:359 const uri = "commit:?" + sha; builds it store-agnostic, unchanged by descendSub (LOG-002 Outcome even notes "appendRow is store-agnostic, unchanged").
jab commit:?a715b0d3 (from the journal ROOT, same base as the log call)
→ JS exception: COMMITNONE, rc=1 — the sub sha is NOT in the base store.
cd be && jab commit:?a715b0d3 → renders (rc=0). So the click-through
fails ONLY because the emitted URI dropped the descent prefix; correct is commit:be?<sha> FROM the root (and unprefixed commit:?<sha> from be).
core/loop.js:269 repo = be.find() re-roots at the pager's OWN
cwd (the invocation base), then the target view opens store.open(repo. storePath, repo.project) (e.g. commit.js resolveSlot(k, repo, …)). The emitted URI must be relative to THAT base — cwd-invariant, not absolute-top.
log.js has descendSub (:406);
commit.js/blob.js/tree.js/size.js never split a <sub> prefix (grep: no descendSub/mountWtDir there). tree.js even navs a 160000 gitlink row to blob:<name> (→ BLOBFAIL), never into the sub.
status, diff, ls/lsr) prefix names at emit
under prefix — AUDIT whether their nav/open targets (not just the visible column) also carry the full path, or share this defect.
round-trip: feeding a row's click-target back from the TOP wt resolves the SAME sub object. Concretely jab log:<sub> rows nav to commit:<sub>?<sha> and jab commit:<sub>?<sha> (from root) renders == cd <sub> && jab commit:?<sha>.
commit: first; then blob:/tree:/size:)
DESCEND a <sub>/… mount prefix to the sub store before resolving — reusing the SAME split-at-mount primitive, not a per-view re-roll.
be/ JS only. REUSE the existing seam: log.js::descendSub /
core/recurse.js (isMount/mountWtDir/joinPrefix) — do NOT hand-roll a second gitlink/.be probe. Prefer factoring ONE shared read-side resolveRepoForPath(repo, path) → {repo, rest, prefix} that log already needs and commit/blob/tree/size can share (the read twin of SUBS-039's delegatePath).
log:<sub> row's U target, feed it
back from the parent root, assert it renders the sub commit (RED today: COMMITNONE). Preserve LOG-001 spine/grey + BRO-006 U links.
be where it prefixes (confirm what C's
graf/LOG.c emits for a sub row's U target — parity target, not a guess).
delegation split, read flavor): deepest mounted-sub prefix → {subRepo, restPath, subPrefix}. log.js replaces its private descendSub with it and RE-PREFIXES the emitted commit: target with subPrefix; commit/blob/ tree/size call it on their own path arg before resolving.
commit:<sub>?<sha> vs
commit:<sub>/?<sha> — pick the one the target descender + native parity accept; verify the banner/?query/#frag split still parses (new URI).
tree's gitlink-row nav (blob:<name> → descend the
sub, or a commit:<sub>?<pin> link) here or split to a tree follow-up — prefer the smallest change that makes the log→commit round-trip green, then fan the same primitive out.
be/test/log/subnav (be-js-log-subnav) — the log:<sub> Uround-trip from the parent root; RED COMMITNONE pre-fix, GREEN after.
36b1aec0:
core/recurse.js::resolveRepoForPath (:83); log.js re-prefixes emitted targets with the descent delta (log.js:369,497-501).
commit: descends the <sub> prefix (commit.js:428-436, first consumer);
tree: too (tree.js:203).
blob:/size: still sub-blind — verified live 2026-07-07: jab blob:be/main.js
from the journal root → BLOBNONE (blob.js descends via k.descendPath only, size.js likewise); wire both through resolveRepoForPath.
status/diff/ls recursors' nav/open targets (not just the visiblepath column) for the same unprefixed-URI defect.
d80bdb5c.
DIS-058/core/recurse.js — coordinate so read + write share ONE splitter, not two. The target views being sub-blind is the bulk of the work (the log emit-prefix alone is a 1-line change but is INERT until commit: descends).
be's sub-row U target format first — this is a parity fix,not an invention.
36b1aec0 ("SUBS-045: log submodule handling"):
core/recurse.js::resolveRepoForPath + prefixed log emit + commit:/tree: descent + test/log/subnav; the same commit carried SUBS-043's declared-subs classify gate.
blob:/size: still sub-blind (live: `jabblob:be/main.js` from root → BLOBNONE) + the status/diff/ls nav-target audit.
</content> </invoke>