post's remote path has no ahead/behind calc: it asks only "is the remote tip an ancestor of cur?", so eq becomes POSTNONE ("already at cur's tip") and every other case — behind, diverged, unrelated — becomes one blind POSTNOFF ("not an ancestor of cur"). The user cannot tell "nothing to do" from "run get first" from "you diverged, merge". The full verdict already exists (relate.verdict / dag.aheadBehind, rel = eq/ahead/behind/diverged/unrelated) but only the PULL side calls it.
Hit 2026-07-14: a post answered "nothing to post" over two trees that had genuinely DIVERGED (work/DOG-021/dog at 63cb570e vs journal/jab/dog at 8ebbfd35, forked at 79612854).
post.js:330 — if (rel.verdict.eq) throw "POSTNONE: remote ... already at cur's tip"; eq is the ONLY named case.post.js:336 — if (!rel.verdict.ff) throw "POSTNOFF: not an ancestor of cur"; behind/diverged/unrelated all land here.shared/relate.js:15-16 states the gap outright: push-side verdict is { eq, ff } and "behind is UNKNOWN".post.js:333-334 concedes it too: "the remote ancestry is unknown here (no fetch) so no diverged/unrelated guess".advanceBranch throws POSTNONE at :270 (already at tip) and :277 (already contains cur).post to a remote names WHICH relation refused it, and says what to run next.
eq → nothing to do (not an error worth a stack; the current POSTNONE text is right).behind → "the remote is ahead of cur — get first"; the user's next move is a pull, not a force.diverged → "both moved since <base> — get then re-post"; name the merge base and the counts.unrelated → no common base; a distinct, loud refusal (never phrased as behind).status already does for branches.Fix in beagle-ext (JS); reuse the existing spine, do not fork a second verdict.
relate.verdict(keeper, cur, tip, remoteIx) already returns eq/ahead/behind/diverged/unrelated — call it, don't refork.dag.aheadBehind yields the row shape (sha/hashlet/ts/subject) for the counts.abc/ok64); new codes need real names, not POSTNOFF overloading.The push side must LEARN the remote's ancestry — it currently refuses on a local-only parent walk.
relate.verdict needs remoteIx (a wh128 of commit->parent edges) to see the remote side; the push path builds none.rel.adv) gives remote TIPS not edges — a behind/diverged split needs the remote's commit closure.getrelate.verdict into pushRemote (post.js:295-338), keep FF-onlystatus-stylebe post wording before fixing the strings (parity)advanceBranch siblings (post.js:270/:277) — same collapse, local refsThe behind/diverged split is not computable from what the push path holds today.
dag.aheadBehind can't walk.-