Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Show

prikk show reports what one sealed block or one patch changed: each operation, its kind, the path(s) it affects, and the content it changed (RFC 142).

prikk show <block-id|patch-id> [--format json]

A patch is self-describing — the content is already in it. EditText carries the exact bytes replaced and their replacement; CreateFile/DeleteNode carry (or point to) the file’s content; RenamePath/ChangePerm/CreateSymlink carry everything they need inline. Nothing is replayed to find what changed.

A RenamePath also reports the AUTHOR key id that signed the patch asserting it — the signer is recoverable in the same answer as the rename itself, never a fact a caller has to look up separately. This is structural, not a rendering choice: show’s own read type cannot represent a rename without it, so a patch whose AUTHOR signature is missing fails the command rather than rendering a rename with no signer.

Three operation kinds — EditText, ChangePerm, ReplaceBinary — are node-addressed rather than path-addressed, so finding where they apply needs one replay of some lifecycle state — which state depends on what the target is (below). show pays that cost once per invocation, not once per operation, and there is no flag to skip it: a surface that named a 32-byte node id where a path belongs would have failed at the one thing it exists to do. If the state a node-addressed operation resolves against no longer has that node live — one patch that edits a node and then deletes it — the edit’s own path reports as unresolved rather than failing the command; every other operation still renders.

Which forms resolve a node-addressed path:

TargetResolves againstNode-addressed paths resolve?
A patch in a sealed blockthat patch’s own state: the block’s starting state (its parent’s, or empty for the first block), folded with the block’s own patches in canonical order up to and including that patchYes
A queued (committed, unsealed) patch idthe folded baseline — the sealed tip with the queue folded on top, truncated at that patch — exactly the state a seal right now would give itYes
A bare sealed patch idnothing — a patch id alone carries no block context, and searching for a block that happens to contain it would make the answer depend on what else is sealedNo — reports unresolved_node_id

A block’s output is the union of its patches, in the block’s own canonical order.

Truncation matters, for a block’s own patches too, not only a queue. Every patch resolves against the state at that patch, not its block’s end: if a later patch in the same block renames a path an earlier one edited, or deletes the node an earlier one edited, the earlier patch’s own edit-text still names the path (or node) it had at the time — never the later name, and never unresolved_node_id just because a later patch in the same block went on to delete it. The block form folds a block’s own patches onto its parent’s state, and the queued form folds the active queue onto the sealed tip, through two different drivers — but both apply the same per-operation fold to resolve a path, so the answer is identical before and after seal by construction: sealing does not change what came before a given patch, only what comes after it.

show renders EditText’s own before/after span — it does not synthesize a unified diff. prikk’s edits are content-anchored spans, not line ranges, and a line-oriented rendering would assert a structure the format does not have.

ReplaceBinary and any binary-kind blob report their object id and declared size, never content — nobody has asked to see binary bytes in a terminal.

A content reference is an id, not a guarantee. CreateFile, DeleteNode’s file preimage, and both sides of ReplaceBinary name a blob by content-addressed id — and once a text file has been edited, its pre-edit identity is deliberately never written back to the object store (the content is reconstructed by replay instead). The exception is a checkpoint — a ref’s first sealed block, and every 64th block after it along its history — which stores the content of every file live at that block, edited or not, so content that was live at a checkpoint reports normally. If a referenced blob is simply absent from the object store, that one piece of content reports as unavailable — a named state carrying the blob id, distinct from real empty content — rather than failing the command. Every other operation in the block still renders, and the command still exits 0. This is not evidence of a damaged repository: the overwhelmingly common cause is a deleted file whose most recent edit made its old identity unbacked by design, and show cannot tell that specific case apart from any other blob that simply never made it into the store; a doctor-level surface wanting to would need to check independently whether the node’s own history includes an edit since that blob was last live.

Damage is different, and fails the command. If the object store reports something more specific than absence for a referenced blob — a content-hash mismatch, a stored type disagreement, a malformed payload, or a SNAPSHOT-kind blob named where file content belongs — that is the object store affirmatively reporting a problem, not an ordinary, by-design gap. show propagates it: the command fails (exit 1) with a message naming the integrity problem, rather than rendering the affected content as unavailable and exiting 0. Absence is ambiguous enough to degrade; a reported error is not.

show never fails because there was nothing notable to report: exit 0 covers every case the target resolves to, whether or not anything is unresolved or an absent content reference reports as unavailable. A malformed or missing id is a usage error (exit 2), a well-formed id naming no real block or patch is a failure (exit 1), and so is a referenced object the store reports as damaged rather than merely absent — an unavailable content reference never softens any of those, which stay what they were.

A queued patch can be shown before it is sealed. An id prikk status --format json lists under the queue — committed, not yet sealed — is looked up in the active WAL when the object store does not hold it, and renders exactly as it will once sealed — node-addressed paths resolved, from the folded baseline truncated at that patch (the table above) — plus a queued: yes line in prose and "queued": true on the patch in JSON (false for everything read from the object store, block or sealed patch alike). An id found in neither place is a precondition (exit 1) that names both places and where each kind of id is listed; it is not reported as damage.

Three things are easy to conflate, and show only ever speaks to the first: queued here means committed to this repository’s own local active WAL — not yet sealed, and never anything received from elsewhere; sync pending means a patch sync accept has already verified and stored from an exchange artifact, but not yet sealed into a block; and log means sealed, permanent history. All three are distinct states a patch passes through, never the same thing twice.

A rename names every signer. A patch may carry several AUTHOR signatures (format 7: another signer’s copy of the same patch merges in). A rename reports every one: prose lists them all on its asserted by line, and JSON carries author_key_ids, every signer in canonical order (key id bytes). author_key_id keeps its meaning — the first signer in that order — so a patch with one signer reports exactly as before.

--format json carries the same content as the prose form, as show-report-v1. It settles the format for show and nothing else.

Comparing two arbitrary points in history — not just one block or patch — means reconstructing both and comparing them, a materially more expensive operation show’s own cost model does not cover. That is a separate command: prikk diff replays both points (or one point and the worktree) and shows the difference as unified hunks. show still answers “what did this block or patch change”, from the patch’s own record.

Claim-to-Source Anchors

ClaimSource anchors
Content comes from the patch payload directly; only node-addressed operations need a replay, once per invocation, against that patch’s own state – its block’s starting state folded with the block’s own patches up to that patch, or (for a queued patch) the folded baseline truncated at that patch.show.rs, patch_replay.rs
An unresolved node-addressed operation is reported, not fatal; every other operation still renders. A bare sealed patch id resolves nothing; a queued patch id resolves against its own truncated folded baseline.show.rs
EditText renders its own before/after span; ReplaceBinary and binary blobs report id and size only, never content.show.rs, output/show.rs
An absent blob reference degrades that one piece of content to a named “unavailable” state rather than failing the command; every other operation still renders and the command still exits 0. A blob the object store reports as damaged (hash mismatch, type mismatch, malformed payload, or SNAPSHOT-kind) propagates instead — the command fails rather than rendering it unavailable.show.rs, object_store.rs
Exit 0 whichever way the target resolves; a malformed or missing id is a usage error, exit 2; a well-formed but nonexistent target id, or a referenced object the store reports as damaged, is a failure, exit 1.main.rs, args.rs
RenamePath cannot be rendered without its asserting AUTHOR key id – the read type has no construction that omits it, and a patch with no AUTHOR signature fails the command.show.rs, author_signing.rs

Provenance

This guide covers RFC 142’s show command. Comparing two arbitrary points in history, or a point with the worktree, is RFC 153’s prikk diff, a separate command with a materially different cost.