What the exercise showed
What the exercise showed
A factual reading of canvas-transcript.md. Every claim below names the invocation that
supports it, by the line the record starts at in that file. Nothing here is a recommendation
and nothing here rules on anything; the ruling is a later step’s.
What was run: twenty-five bin/canvas invocations against a scratch store at
…/bc-10330566962-deliver-the-first-priority-canvas-todo-s/canvas-store, on canvas
bc-10330566962-merge-and-split-exercise. One create, eight insert, three read, two
replace, two remove (one refused), one move, eight history (one refused). The clone at
…/canvas was left on main at 798ee8c2e3372099646dd2ff044f58b44649bf1d with an empty
git status --porcelain: no branch, no commit, no edit.
The four ids
- Split survivor —
e8ec.replaceon it at:148returnedCanvas-Node: e8ec. The id is unchanged and the finalreadat:375shows it atv="2". - Split-born —
dkjk. Theinsert --after e8ecat:161minted it.v="1"in the final read at:375. - Merge survivor —
oskz.replaceon it at:174returnedCanvas-Node: oskz;v="2"in the final read at:375. - Stranded —
dwqu.removeat:204returnedCanvas-Node: dwquat exit 0. It is absent from the finalreadat:375: the stringdwqudoes not occur anywhere in that document.
After the merge, does anything point at the stranded id?
The document does not. The final read at :375 contains no occurrence of dwqu, in a
node id, in an attribute or in any text.
The surviving node’s history does — because a human typed it, not because the tool wrote
it. bin/canvas history … oskz at :266 prints two entries, and the second one, the merge’s
replace, reads in part: “Node dwqu holds that clause today and will hold nothing this node
does not once this commit lands.” That sentence is the whole of the pointer. It is free text
inside the --why the writer chose to write; had the writer not named the id, nothing in that
output would have contained it. The appendix at :419 shows what the commit itself carries:
the trailers on the removing commit are Canvas-Node: dwqu, Canvas-Author: and
Canvas-Base: and nothing else. The tool minted no lineage field, no ancestor trailer and no
cross-reference of any kind.
So the pointer between the two halves of this merge exists in exactly one place: the prose of
two --why strings. It survives only as long as writers keep writing it.
What history does with the stranded id
It answers, at exit 0, with the node’s whole life. bin/canvas history … dwqu at :286
exits 0 and prints the Canvas-Node: dwqu header and two edit blocks: the original
insert (commit f05035c…) and the remove (commit ce80ed3…). The removing commit is the
last entry and its complete --why is printed. There is no refusal, no warning, and no
marker in the output saying the node is gone — the output for a retired id is the same shape
as the output for a live one (compare :286 with :266).
The stranded node’s history is therefore not gone; it is retrievable in full. The only
thing needed to retrieve it is the id itself. The appendix at :419 confirms there are
exactly two commits naming dwqu, which are exactly the two entries history printed.
But nothing in the document leads a reader to that id. read at :375 never mentions it,
and history takes an id as a required positional (bin/canvas history <ledger_id> <node-id>)
— there is no command in the exercise that listed or searched retired ids. A reader who does
not already know the string dwqu reaches it only through the sentence in oskz’s reason at
:266, i.e. through the convention, or not at all.
An id that never existed is a different case: bin/canvas history … root at :358 exits
1 with “no node with id root in the history of the canvas … no commit names it, so it was
never a node of this canvas. The canvas is there; the node is not”. So the tool does
distinguish “retired” (exit 0, full history) from “never a node” (exit 1, refusal) — but it
draws that line silently, inside the exit code, and says nothing in the exit-0 case about the
node having been removed other than the presence of a remove: entry.
After the split, does the newly minted node carry anything about where it came from?
Nothing the tool wrote. bin/canvas history … dkjk at :250 prints one entry: its own
insert, at commit e9f2b03…. The node is v="1" in the final read at :375. There is no
entry, trailer or field referring to e8ec, and the commit that split e8ec (bacf86f…,
recorded at :148) does not appear in dkjk’s history at all — history returned only the
commits whose Canvas-Node: trailer names dkjk.
What is there is, again, only the prose. The --why on that insert says “This content
was the second sentence of e8ec until the replace one commit earlier”, and history at :250
prints it. Remove that sentence from the --why and the newly minted node’s history would
contain no trace of its origin whatsoever.
The same holds in the other direction: history … e8ec at :230 shows two entries, and the
second one names no successor id — the writer described the second half as going “into its own
node” without naming dkjk, because at the time that replace ran the id did not yet exist.
That ordering is forced: the split’s replace happens before the insert that mints the other
half, so the surviving node’s reason cannot name the born id unless a later edit adds it.
Does --why text appear in history output?
Yes — in full, verbatim, as the body of every entry. Every history record in the
transcript (:230, :250, :266, :286, :306, :326, :342) prints each edit as
Canvas-Commit: / Canvas-Author: / <verb>: <reason>, with the reason exactly as it was
typed, unwrapped and untruncated. So a convention of naming the other id inside --why is
readable back by a reader, and the command that reads it is **`bin/canvas history