be get must pick where to fetch each submodule from based on the kind of the parent source, then validate by gitlink-pin presence and fall back. This formalises and extends the resolution already shipped for beagle parents (see Submodules, submodule-parent-source-fetch); the git-parent branch is split by the .git suffix. REOPENED 2026-06-16: be post/push must MIRROR this — send each sub commit to the SAME destination GET would fetch it from (same peer for beagle, parent-relative for git non-.git), so the submodule is tracked on the other end; only a git .git parent pushes the sub to its independent official URL.
while git parents "behave like git" with no documented .git split.
whether that commit is present afterward; on miss, fall to the next.
be:/keeper:, or file:/ssh: at a .be
store): request the sub from the same peer (parent locator + project query); if that fails, fall back to the official .gitmodules URL.
.git: go straight to the
official URI from .gitmodules (no path calculation).
.git: compute the
sub URI by resolving its path relative to the parent URI, try that; if it fails, fall back to the official .gitmodules URL.
be post/push routes each recursed sub commit to the SAME destination case 1–3 above would FETCH it from — push and fetch are symmetric so the submodule is tracked on the other end:
?/<project>), the same shard GET case 1 reads. Expect the sub project tracked at that peer.
.git → push the sub to its *official .gitmodulesURL* (independently hosted; git submodules live in their own remote).
.git → push the sub to the *parent-relativeURI* (same host, path resolved off the parent), the same address GET case 3 computes. Expect the sub tracked alongside the parent.
Summary (user): send the sub to the same repo as the parent when beagle OR not .git; only a .git git parent pushes the sub to its independent official URL.
sniff/SUBS.c subs_recover_locator,
subs_pin_present, the is_beagle probe); do not re-roll locator or pin-check logic. Recursion stays a child process per sub.
be get policy. --nosub still opts out..git suffix is the git-parent discriminator: present ⇒ canonical remote(case 2); absent ⇒ relative-path resolution off the parent (case 3).
.gitmodules url = as specified, the final fallbackin all three cases.
test/get/50-file-subs-git-relative (3 cases:
relative-resolve hit, fallback-to-official, .git single-try).
.git-suffix split + parent-kind branch in sniff/SUBS.c
(subs_src_ends_git); cases 1/2 confirmed unchanged.
subs_candidate_git_rel,git directory-base resolution).
resolver (exported SNIFFSubSrcEndsGit / SNIFFSubCandidateGitRel). beagle→same peer (was already done — bepush_recurse_cb); git-.git→ official URL, git-non-.git→parent-relative via a NEW bepushgit_recurse_cb in the previously do-nothing git-peer arm of BEActSubsPost (beagle/BE.cli.c). The sub commits onto a synthetic ?/<sub>/.<parent> coordinate; pushing it to a git wire needed keeper/KEEP.exe.c to project-strip the cur/peer-refname branch (not just the explicit ?query) so the synthetic-.-prefix → git default-branch mapping (POST-013 git_wire_default) fires.
post/43-sub-push-git-official-url (case 2, local
file://, RED→GREEN) asserts the sub lands on its official .gitmodules url; post/44-sub-push-git-parent-relative (case 3, ssh) mounts via an absolute url then rewrites .gitmodules to ../sub and asserts the push lands PARENT-RELATIVE (repos/sub), NOT the absolute url. Case 1 stays covered by post/38-sub-push-beagle-peer-shard. 305/305 (main) + 384/384 (WITH_SSH) green.
child process per sub. Relates to GET-010 (git file: clone routing).
4121eaaf — git-parent split on .git; case-3 parent-relative
resolution before the official-URL fallback; beagle parents unchanged. Reuses the existing sniff/SUBS.c resolver/pin-check. 287/287 green.
3eba8e76 (FF child of 9bfb0157; clean sniff/SUBS.c
weave-merge keeping both PTR-005's ptr-discipline and the resolver export; 305/305 + post/43&44 green WITH_SSH): the git-peer push arm of BEActSubsPost (beagle/BE.cli.c) was a NO-OP for cases 2/3 — the parent pushed a gitlink referencing a sub sha that lived nowhere remote (dangling). Fix: exported the GET resolvers (SNIFFSubSrcEndsGit, SNIFFSubCandidateGitRel) and reused them in a new bepushgit_recurse_cb (git-.git→official URL, git-non-.git→parent-relative; beagle peer already via bepush_recurse_cb); plus keeper/KEEP.exe.c now project-strips the cur/peer-refname branch (not only the explicit ?query) so the synthetic ?/<sub>/.<parent> → git default-branch mapping (POST-013 git_wire_default) fires. Tests post/43 (case 2) + post/44 (case 3, ssh), RED→GREEN; 305/305 main + 384/384 WITH_SSH. Awaiting gate. (Scope: GET-side case-3 over ssh is a pre-existing GET limitation, untouched.)