<sub>/<path> verb arg into the mounted submodule (PUT/DELETE first; EVERY state verb needs it) DIS-058 D10
Submodules Recursion §3: "staging a submodule file delegates that to the submodule, then stages that submodule". The be/ JS read spine (core/recurse.js: walk/isMount/gitmodulesOrder/joinPrefix) ENUMERATES every mounted sub for whole-tree read recursion, but there is NO shared routine that takes a SCOPED PATH ARGUMENT (be put <sub>/file, be delete <sub>/file) and DELEGATES the verb to the owning submodule on the remaining subpath, then stages the sub in the parent. Today the state verbs just SKIP gitlink subtrees (stage.js:149/261, delete.js:78), so a <sub>/file arg is silently dropped/mis-handled. This is CROSS-CUTTING: every verb that takes a path — put, delete, get (single-file restore), and the scoping side of status/diff — needs the same "split the path at a sub mount, run the verb inside the sub, fold the staging back" primitive. This ticket adds that ONE reusable routine and wires PUT/DELETE as its first consumers (the DIS-058 D10 slice). Scope be/ JS. Parent DIS-058 (D10); see Submodules, SUBS-037; method Issues.
core/recurse.js::walk enumerates mounted subs (.gitmodules order, isMount gate, joinPrefix) — the reusable spine for ENUMERATION (whole-tree), not for a single path arg.delegatePath(repo, pathArg)-style routine — find the deepest MOUNTED-sub prefix of pathArg, open that sub's repo (be.find/store), run the verb on the REMAINING subpath in the sub's wt, then stage the sub (gitlink) in the parent — pre-order (stage the sub file, THEN stage the submodule).b.kind === "s" → continue, stage.js:149/261; delete.js:78), so be put <sub>/file is not delegated. The ONLY sub-touching put today is the MANUAL gitlink bump be put <sub>#<sha> (fold-decide.js:178-184, SUBS-019).isMount/gitmodulesOrder/joinPrefix (recurse.js), be.find/store for the sub repo, and the existing gitlink-bump primitive to stage the sub after delegation.shared/subdelegate.js, or extend core/recurse.js) that, given a verb op + a path arg, routes a <sub>/<subpath> to the mounted sub and folds the staging back — callable by ANY state verb (single delegation point).be put <sub>/file stages the file INSIDE the sub then stages the sub gitlink in the parent (pre-order); be delete <sub>/file likewise.<sub>/file whose <sub> is NOT a mounted sub falls through to the normal path; a DECLARED-but-unmounted sub gets a friendly refuse, never a silent drop.be/ JS only; REUSE the core/recurse.js spine — do NOT re-roll a parallel walk. Keep the friendly string throws.be put <sub>/file / be delete <sub>/file case proving the file lands in the sub AND the parent stages the sub.be put <sub>#<sha> bump, or DIS-058's get/post recursion.<sub>/path args; after the sub stages/commits, stage the parent gitlink by REUSING the existing bump primitive (coordinate with DIS-058's post-order auto-bump D7 so the tree-build path stays single).1c4a97c8: put.js::subMountPrefix (shallowest mounted-sub prefix, recurse.isMount gate) + stageInSub (stage in the sub's own wtlog; gitlink bump left to POST per Submodules); wired in putOne (put.js:524-528).delete.js::delStage still runs a <sub>/file arg against the PARENT engine (no sub-crossing split; verified 2026-07-07): reuse subMountPrefix-style delegation for the file- and dir-forms.subMountPrefix is put.js-private; the read twin core/recurse.js::resolveRepoForPath (SUBS-045) already exists — one write-side delegatePath next to it, consumed by put + delete.jab delete <sub>/file case (sub wtlog gets the delete row, parent untouched); put side is covered implicitly — add an explicit put <sub>/file case too.put <sub>#<sha> bump + sub/cycle intact.fold-decide.js/subs.js/recurse.js (the bump primitive + the spine) — keep the put/delete changes minimal and reconcile on land.1c4a97c8 (put.js subMountPrefix + stageInSub). OPEN: the DELETE arm (delete.js has no sub-crossing split), hoisting the splitter to a shared routine (pair with core/recurse.js::resolveRepoForPath), unmounted-sub refuse, repros.