In the parent worktree in EXPLICIT-STAGE (selective) mode — at least one be put/ be delete since the last get/post — jab post commits a mounted submodule that had NOTHING staged: it recurses a post into the sub, the sub (no staged rows of its own) runs in COMMIT-ALL mode and rewrites its dirty files, and the parent gitlink is bumped to the new sub commit. Selective mode must commit only what is explicitly staged, so a sub with nothing staged must be left untouched (pin unchanged). The parent's selective intent does not propagate into postSubs's recursion. be/ JS (reported by user, 2026-06-30). JS-side twin of the native SUBS-029 phantom-sub-put fix; parent DIS-058; spec Submodules / Dirty; method Issues.
be put <parentfile>), a mounted
sub with a dirty-but-UNSTAGED file, then jab post — the sub is committed and the parent gitlink advanced, despite nothing staged in the sub.
post.js::postTree (post.js:280) calls postSubs (post.js:282, unless --nosub)
BEFORE postOne; postSubs (post.js:290) enumerates mounted gitlinks (subs.enumerate) and recurses postTree(subInfo, ctx, {uri: subWt}) into EVERY mounted sub (post.js:314) — no selective-mode gate, no "does the sub have staged changes?" check.
wtlog: decideM.decide → m.anyPd (fold-decide.js:109). With no in-scope sub put/delete anyPd is false → COMMIT-ALL → a modified sub file is rewritten (fold-decide.js:160 if (anyPd) keep; else rewrite), so an unstaged-dirty sub is committed.
the synthesised put <subpath>#<newtip>), recording the spurious sub commit.
staged paths; Submodules POST recursion is post-order but must respect the staging intent. Native SUBS-029 added a tip-vs-pin + PUTNONE-tolerant gate to avoid phantom no-op sub commits; the be/ JS port lacks the selective gate.
be post must NOT commit or advance asubmodule that has nothing explicitly staged (no in-scope sub put/delete, no staged parent gitlink bump for it) — the sub's pin stays unchanged.
today (recursion is the default per Submodules).
clean/unstaged sub is never spuriously committed.
be/ JS only. REUSE decide's anyPd, subs.enumerate, and the existinggitlink-bump primitive; do not re-roll the recursion.
detached/attached sub commit (SUBS-035/SUBS-036), or --nosub.
dirty-but-unstaged file → assert be post leaves the sub tip AND the parent gitlink UNCHANGED; a commit-all parent still commits the dirty sub.
postSubs on the parent's mode: in selective mode recurse into a sub ONLY
when it has in-scope staged changes (its own anyPd) OR an explicit parent gitlink-bump targets it; skip clean/unstaged subs. In commit-all mode descend into every dirty sub as now.
recursive sub post so the sub does not silently commit-all when the parent is selective — pick the cleaner of the two, do not double-gate.
no-op sub neither commits nor bumps.
be/test/sub/selective/run.sh (be-js-sub-selective) — arm 1 selective parent+ dirty-unstaged sub → sub tip + gitlink UNCHANGED; arm 2 commit-all still commits.
postSubs recursion on selective vs commit-all — landed 1c4a97c8:
anyStaged(wtl) parent-mode + the per-sub scope gate (post.js:479-484).
s.bucket === "adv" falls through),
--nosub (post.js:433).
d80bdb5c (TEST-003).keep the change minimal and reconcile on land.
be put/be delete inside the
sub wt vs a parent staged gitlink bump (be put <sub>#<sha>).
1c4a97c8 ("SUBS-042: staging files in submodules", be trunk 30Jun):
post.js::postSubs selective gate — in selective mode a sub is recursed ONLY when in parent scope / own anyPd / already adv; commit-all descent unchanged.
be/test/sub/selective (both arms); suite green jab-only per d80bdb5c.CLOSED (audit 2026-07-07). (The same commit also landed the SUBS-039 PUT delegation arm — see SUBS-039.)