GET-053: bare get goes FF/FB-only; get! becomes the any-commit reset
Now:
DONE
RULED into /wiki/GET (gritzko, 2026-08-01): a bare get may only move the wt ALONG cur's line — fast-forward or fast-backward, "refuses otherwise" (/wiki/GET "Forceful execution"); diverged and unrelated targets need the bang, which resets to any commit, discards local changes and deletes untrackeds. Divergence resolves through two loud doors: patch (weave theirs in) or get! (adopt theirs). Kills the diverged-plain-reset machinery of GET-048 and the silent non-FF clobber class of GET-014.
Input
Context
Today bare get moves the wt to ANY ref: a diverged target is a plain reset (GET-048), needing merge-base basePaths classification and still risking silent loss (GET-014, GET-052); get! means "discard dirty edits + sweep untracked" (/wiki/GET §2.2, GET-040).
Line-only makes bare get provably lossless: oldTip and target are ancestor-related either way, so the weave has a true common base and never a merge-base fold.
A diverged peer can land objects but can never move the wt onto its own line (the GET-014 clobber class dies structurally); a BEHIND peer still can, see the open question below.
get '#~1' rewind is a fast-backward, so it STAYS a bare form (the earlier "rewind is PUT's ground" reading is retired by the 2026-08-01 spec).
Goals
Land the line gate in be/verbs/get/get.js (and the native twin); the spec is written and the bang semantics are ruled, so the code is the only thing left.
Bare get and every fetch-leg update refuse an OFF-LINE target (diverged, unrelated) in plain words: "not on this line — patch to merge, get! to reset"; ancestor and descendant targets both pass.
RULING (gritzko 2026-07-29, from the GET-057 incident; extended 2026-08-01): staged rows STAY across any bare get, forward or backward — no silent ...V → ...v demotion; only get! clears them.
RULING (gritzko 2026-08-01) on a BEHIND remote: the network leg does NOTHING — a stale peer's older tip is a no-op, not a rewind and not a refusal, so the GET-019 class stays dead; fast-backward is a LOCAL motion.
get! reaches any commit: diverged, unrelated, backward detach (/wiki/GET "not necessarily fast-forward or fast-backward").
The refusal fires BEFORE the wtlog append — today every seed appends the get row first, then fans out; pre-append refusal also serves the GET-016/GET-018 atomicity line.
Constraints
Concerns raised in review (2026-07-24); the first two are settled by the 2026-08-01 spec, the third stands:
SETTLED nuke-by-habit: fast-backward is bare now, so only a genuinely DIVERGED switch demands the bang — the everyday git checkout feat analogue no longer routes through the destructive door.
SETTLED subs: a parent moving a sub's pin BACKWARD is a fast-backward, a bare-legal motion; the GET-047 §4.1 pin-attached update stays declarative regardless.
CONCERN get! reach: "any ref" includes unrelated history — crossUpdate's unconditional unrelated refusal (get.js:441) would need a force override, reopening the "another project in the cell's clothes" hazard GET-047 guards; sweepUntracked on an unrelated-ref jump approximates rm -rf of the wt, making the GET-051 pre-discard guard load-bearing.
WIP
Design decisions
The bang-semantics split is RULED (c) by /wiki/GET 2026-08-01; (a) and (b) are dead:
RULED (c): one bang, one meaning — any commit AND discard (reset to a clean state, local changes dropped, untrackeds deleted); no separate destruction-only form.
(a) dead: the bang stays destructive; the spec binds "any commit" and "clean state" in the same sentence.
(b) dead: the line gate is not scoped to same-track updates — a branch switch obeys it too, and stays bare as long as the target is on cur's line.
The FAST-BACKWARD case in GET-058 terms (the landed quad classifier decides, this only says which column feeds it):
The deciding axis is TARGET vs BASE, never "track vs root" literally; the wt column stays measured vs BASE in both directions (GET-058).
FAST-FORWARD: root = mergeBase = base, so the track column IS target-vs-base — the 13 cells are indexed exactly as GET-058 wrote them.
FAST-BACKWARD: nothing to add — checkout.trackChar(oldSha, newSha) already computes that axis directly, so the backward cells (o→delete, x→restore) fall out of the landed code (VERIFIED 2026-08-01: test/get/line-backward was green before any edit).
So no inversion helper was written; the backward test stays as a regression guard on trackChar.
Both columns lit at once = DIVERGED = refuse (bare) — the shape the table never has to fold, as GET-058 states.
Nothing else moves: same 13 cells, same WEAVE3/OURS/THEIRS/DELETE verdicts, same binary modifier on the both-sides-edited cells.
TODOs
gritzko rules on the bang split — (c), /wiki/GET 2026-08-01; get! vs UNRELATED history still open (does the GETCELL refusal at get.js:441 survive force?)
line gate: compute relate.verdict in every seed BEFORE appendWtlog (seedLocal, seedRemote, handleWtSeed, crossUpdate, inRepoSeed) — refuse diverged/unrelated pre-append, PASS behind
fast-backward axis: no work needed, checkout.trackChar is already target-vs-base (Design decisions 3-4)
plain-words refusal message ("not on this line — patch to merge, get! to reset"), never a bare code
bare get '#~1' and backward detach ?<sha>/#<sha> KEEP working (fast-backward); the bang is needed only off-line
sub carve-out: §4.1 pin-attached sub updates stay declarative (never line-checked); the §4.2 get! override unchanged
drop the GET-048 diverged machinery (basePaths, merge-base del classification) from the non-force path
GET-051 pre-discard size guard lands before (or with) the widened get!
staging survives any bare get: classify/wtlog row-liveness keeps put rows across the new get tip row (ruling above); tests = stage, FF get, still ...V; stage, FB get, still ...V; get! clears
network leg: a behind fetched tip is a NO-OP (objects land, wt and cur do not move) — no wtlog get row, no refusal text
tests: off-line refusal cells added to the GET-047 matrix, plus a fast-BACKWARD accept cell; same-tip recovery and detached recovery stay green
spec: /wiki/GET intro + "Forceful execution" written by gritzko 2026-08-01; /wiki/Verbs cheat sheet (git checkout feat row) still to check — his page, request his edit
the GET-058 quad classifier stays as landed; this ticket only adds the fast-backward axis derivation (Design decisions) — no second mechanism
mark GET-048STALE with a pointer here once the gate lands (GET-052's hazard dies with it)
Blockers and bummers
Unblocked (bang split ruled); the gate itself is small, but its pre-append placement touches every seed and overlaps the GET-018 atomicity design.