SUBS-050: one parsed-branch type for all branch paths

Now
OPEN

REBASE 2026-07-15: the shape inventory shrinks ?/libdog/.jab/JS-101 (absolute dot-chain) and ?.libdog/.jab/JS-101 (relative) both die with the dot-branch (URI-016 d5, SUBS-054); the replacement shapes are the wtlog pin rows ///path/to/sub?proj_branch#pin and ///path/to/sub/?branch#base. The unify-on-one-parsed-type goal stands and gets easier.

Branch paths in be/ JS are handled by ad-hoc string surgery at every call site; three recorded shapes leak verbatim into display, so status labels the same branch three ways at three depths: plain ?JS-101 (primary wt), absolute ?/libdog/.jab/JS-101 (mounted sub), relative ?.libdog/.jab/JS-101 (sub-of-sub, title-stripped rows). Unify on ONE parsed type { title, branch: [segments] } and ONE helper module; no string concat or manual parsing at call sites.

Input

Context

shared/branch.js (SUBS-048) is an ORPHANED string codec nothing requires it; every call site grew its own indexOf/slice surgery. Composers: submount.js:114 syntheticBranch (manual slice surgery; writes the absolute sub-anchor shape at :233/:283/:325), store.js:626 keyURI/refKey, relate.js:29 resolveRef (refs/heads/X KEEPS the title disagrees with serve.js:45 which advertises the title-STRIPPED branch), status.js:365 "?"+rawQuery verbatim, refs.js:34, head.js report, get.js ?<branch>#<tip> wtlog rows. Parsers: wtlog.js:36 stripProject + refOf (&-chain), store.js:588 stripProj (byte-identical duplicate of stripProject) + resolveRef's 3-way fuzzy match + shaOf's /proj/branch/<sha> split, get.js:92 query.slice(1).split("/"), wire.js:135 refs/heads/ strip, post.js resolveTarget, delete.js:330, patch/fetchleg.js. Related: SUBS-040 dot-branch tracking, SUBS-023 synthetic-name get (wontfix), Submodules wiki, BE-011 segment-array path law.

Goals

Constraints

WIP

Design decisions

TODOs

Blockers and bummers

Outcome