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

Merge

DC-74 adds prikk merge, the first command that executes a merge rather than only reporting on one. It builds on the same read-only evidence merge evidence and merge plan already report — see those pages, and Patch Algebra and Merge Evidence, for the underlying confluence concepts.

prikk merge --allow-no-audit \
  --baseline-block BLOCK \
  --into REF \
  --from REF \
  [path]
  • --baseline-block is required and names the sealed baseline block confluence is proven against.
  • --into is the ref the merge advances. It must currently be published and must be the branch the caller has maintainer signing authority to seal.
  • --from is the ref merged in. Its patches since the baseline are what get adopted. It may be a local branch, or a received ref (remotes/<name>, DC-85) imported by prikk bundle import — see Merging from a received ref below.
  • --allow-no-audit is required, matching seal’s own flag: this command signs and publishes new sealed history, and audit plugins are not implemented.
  • The optional positional argument is the repository root.

What a merge does — and does not do

A merge authors nothing. --from’s patches since the baseline are adopted verbatim: the exact same canonical bytes, the exact same ObjectId, the exact same author signature as when they were originally sealed. prikk merge never decodes, re-derives, or re-signs a patch. Only the new Block, RefState, and RefUpdate are signed — with the maintainer key, exactly as an ordinary seal signs them.

The two sides must be proven confluent from the given baseline — the same evidence merge-evidence/merge-plan already compute, reused rather than duplicated. Any outcome other than Confluent (Conflict, Deferred, NotConfluent, Unsupported, OrderedDependency, EvidenceFailure, InvalidCandidate) refuses the merge. Refusal writes nothing: no object, WAL record, or ref update of any kind is created until confluence is confirmed, so a refused merge leaves --into exactly where it was.

What gets recorded

Merge blocks are BlockKind::Merge, naming both parents (DC-75). parent_block_ids holds --into’s prior tip and --from’s adopted tip, sorted per the format’s uniqueness invariant. A separate mainline_parent_id field names which one is --into’s side, since sorted order carries no positional meaning. State derivation and replay follow the mainline parent only — the same shape as an ordinary single-parent block — while the secondary parent’s own chain is verified independently by the ordinary full-object-store scan every other block already gets.

The baseline is recorded, and independently re-derived. merge_baseline_block_id states what --baseline-block was at seal time — a claim, not a trust boundary: ordinary verify computes the true merge base itself (a full-parent reachability walk) and reports disagreement if the recorded baseline is not it. Authorship is unaffected (the adopted patches still carry their original author’s signature).

This discharges the release condition DC-74 attached to this command: sealed history now structurally records a merge, re-checkable by a later verifier from sealed history alone.

Merging from a received ref

--from accepts remotes/<name> — a ref imported by prikk bundle import --input FILE (produced on the other side by prikk bundle export --ref REF --output FILE) — exactly as it accepts a local branch. --into never does: it must always be a genuine local branch, since publishing a ref only ever writes the local ref store.

Adopting content from a received ref requires the maintainer key that sealed it to already be trusted here. Received content arrives via import_bundle with no trust check at all — deliberate, per DC-78 Stage 3: importing is not trusting. A local-to-local merge needs no equivalent check, because every block reachable from a local ref was itself created through this repository’s own seal/merge path, each already gated by trust at creation. A received ref’s blocks were never gated on the way in, so prikk merge checks them itself, before --into advances: every block it would adopt must carry a signature from a currently-adopted maintainer key, or the merge is refused with no trusted MAINTAINER signature and writes nothing.

If you meet that refusal, do not treat it as an error to clear. Running prikk trust maintainer add for whatever key the bundle happened to carry is exactly the decision this check exists to make you take deliberately, not by reflex. Trusting a maintainer key means trusting every block that key has ever sealed or ever will — confirm you mean to extend that trust to this specific origin before adding it, the same judgment call trust maintainer add already asks of a purely local setup.

Conflicts

Detection only. A resolution is itself a signed patch — a trust question prikk merge does not decide. patch_algebra’s conservative subset (DC-16, DC-18) governs what can be proven confluent at all; if it is too narrow to merge something that should be mergeable, that is its own finding, not something this command works around.

Compatibility

verify, doctor, rollback-preview, and DC-64’s incremental lifecycle cache all continue to work against a repository containing a merged block — tested, not argued (crates/prikk-cli/tests/dc74_merge_execution.rs).

Deferred

  • Automatic merge-base discovery — --baseline-block stays explicit.
  • Conflict arbitration / resolution.
  • Widening patch_algebra’s conservative subset.
  • Merging more than two sides in one command.
  • Populating PatchPayload.parent_patch_ids — no construction site sets it; the patch DAG it implies is a different structure than the block-parentage DC-75 records, answering a different question.