get writes ?<sha>, a detached post writes trunk-shaped ?#<sha>; the record is #<sha>The canonical detached record is #<sha>: laws #1+#3 of DIS-071 settle it with no ruling needed — a bare hash is not a branch/remote/worktree, so there is nothing to TRACK, so the query slot is ABSENT and the fragment carries the base (a "bare-hash record", law #4). URI-009's absent-vs-empty distinction then separates all three states byte-wise: #<sha> = no query = detached, ?#<sha> = present-empty query = TRUNK, ?br#<sha> = attached. Both records break it. (a) get's D2 detach writes the INPUT verbatim — ?<sha>, sha in the QUERY, no fragment (get.js:491-496); ?abc1234 is what the user TYPES (GET:11 "a bare sha detaches"), never what gets recorded. (b) A detached post writes ?#<sha> — branchKey is att.branch = "" when detached, so post.js:726 emits a TRUNK record (post.js:573-580, 720-726). Only attachedBranch's get-ONLY scan (wtlog.js:141-156) keeps such a wt detached; any reader trusting post rows sees the trunk — views/refs/refs.js:22-28 does exactly that, labelling off curTip().br, so jab refs prints ? for a detached wt. Precisely the disagreement DIS-059's DIS-057 comment swears is impossible. Law #4 makes a sub's own commit produce the same #<sha> (DIS-072), so the shape is load-bearing, not cosmetic.
Detachment is encoded in the query on one path, lost on the other, and re-derived by a get-only scan that not every reader uses.
?<40hex> — sha in the query, no fragment; wtlog.js:99-101 and 146-149 read the detach back off exactly that shape.?<branchKey>#<sha> with branchKey = att.branch = "" when detached → ?#<sha>, byte-identical to a trunk post.curTip().br, NOT attachedBranch → jab refs reports ? for a detached wt while post's guard reports detached.?<sha> is a GET ARGUMENT (GET:11, GET:24), and get.js:494 records that argument's shape instead of composing a record.u.query || "" collapses the URI-009 absent-vs-empty slot that distinguishes #<sha> (detached) from ?#<sha> (trunk) — the same collapse DIS-073 hits.?sha detach placement — the spec half of this ticket; it must say ARGUMENT ?<sha> → RECORD #<sha>.One record shape per state, readable by every reader without a get-only special case.
#<sha> for a detached wt: query slot ABSENT (not empty), base in the fragment — laws #1+#3, no ruling outstanding.post stops emitting a trunk-shaped ?#<sha>; a sub's own commit yields the same bare-hash shape (DIS-072).jab refs + a post-detach guard read — both must say detached.Read-compat and one reader; the ARGUMENT grammar does not change.
?<sha> (D2 detach) and ?#<sha> (today's detached post) must read back as they do now — no wtlog rewrite (DIS-071 law).?#<sha> ambiguity is UNRESOLVABLE in old rows — a trunk post and a detached post are byte-identical; legacy resolution stays get-anchored. Document, do not guess.be get ?<sha> stays the user-facing spelling (GET:11,24) — this ticket changes what gets RECORDED, never what gets TYPED.#<sha> and ?#<sha> collapse again — coordinate with DIS-073.#<sha> (query slot absent, base in fragment) — derived from laws #1+#3, 2026-07-15; no separate ruling needed.?<sha> is the detach COMMAND, #<sha> its recorded effect. get.js:494 conflates them today.jab refs says ? (trunk) while post says detached#<sha> when detached, never ?#<sha>; get: record #<sha> for a ?<sha> argumentcurTip().br?#<sha> ambiguity cannot be resolved from the record alone; any migration must stay get-anchored.