be patch whole-tree merge fetches subs from their .gitmodules github URL, not parent-relative from the patch source → WIRECLFL
A whole-tree be patch be://spot/journal?main! merges the parent (journal) level CLEANLY (202 noop, 2 take-theirs, 1 merged, 3 added, 0 conflict), then recurses into the submodules and fetches each sub's THEIRS from its declared .gitmodules remote — for the be sub that is git@github.com:gritzko/beagle-ext.git (scp-style, offline/unreachable) → sniff: submodule fetch failed for git@github.com:gritzko/beagle-ext.git / WIRECLFL / BEDOGEXIT. The CLONE (be get be://localhost/journal) recurses the SAME subs fine — it resolves each sub parent-relative from the source (be://…/journal/<sub>, SUBS-024). PATCH's sub-recursion lacks that parent-kind resolution. Blocks the whole-tree spot merge. Method Issues.
be get be://localhost/journal clone,
be patch 'be://spot/journal?main!' → parent merge OK, then get html?91ae5b53, sniff: submodule fetch failed for git@github.com:gritzko/beagle-ext.git / WIRECLFL / get beagle?… / get beagle/abc?… / BEDOGEXIT. The be sub (scp-git url) is the failure; beagle (https) gets further.
be get be://localhost/journal recursed be/beagle/html
parent-relative from the source (get be?498e7dbe etc.), never touching github.
gitlink-diff recursion (reuses GET)" (sniff/PATCH.c:79) — but that recursion fetches the sub from its .gitmodules url, not the parent-relative candidate GET's top level builds via SNIFFSubCandidateFromSource (SUBS-024, sniff/SUBS.c:427).
?main! is the working
form): be patch be://spot/journal?<sha>! (sha in query) → WIRECLFL (the wire advertises refs, not a bare sha); be patch be://spot/journal#<sha> (remote + fragment) → PATCHFAIL ("URI must be ?<br>/?<br>!/#<sha>"). So a remote merge can only be addressed by BRANCH (?main!), not by sha — worth its own usability note.
(be://spot/journal/<sub>), mirroring GET/POST (SUBS-024); the .gitmodules remote is only the fallback for a non-beagle parent. A whole-tree be patch be://spot/journal?main! completes through every sub.
SNIFFSubCandidateFromSource (the GET-side parent-relative
resolver) in BEActSubsPatch's sub fetch. Repro-first (CLAUDE.md §17): a hermetic 2-level be:// fixture whose sub MUST be fetched parent-relative (its .gitmodules url unreachable), RED today, GREEN after. Don't regress single-project patch.
the sub fetch URI with SNIFFSubCandidateFromSource(<patch-source>, <sub-basename>) FIRST (the be://…/journal/<sub> candidate), fall back to the declared .gitmodules url only when the parent source isn't a beagle multi-project remote — exactly the arms GET/HEAD already use (HEAD-004 / SUBS-024).
.gitmodules url isunreachable; assert the merge fetches the sub parent-relative (RED today → WIRECLFL).
beagle/build; verify be patch be://spot/journal?main! recurses all subs.?<sha>!/remote-#<sha> rejection.parent-level merge already works; only the sub-source resolution remains.
does NOT reproduce: a beagle parent re-gets each moved sub gitlink PARENT-RELATIVE during patch via the existing GET-011 historical-REFS locator recovery (subs_recover_locator reads the parent shard's recorded be: source row → builds the ?/<sub> sibling candidate, sniff/SUBS.c). No explicit source-threading needed. Verified with a hermetic 2-level be:// fixture (dead .gitmodules url, sub reachable only parent-relative): the patch lands the sub from the sibling shard, never touches the dead url. Kept as a regression guard test/patch/38-sub-source-parent-relative (lands with PATCH-006 9ed6f41b). No code change.