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

Patch Algebra and Merge Evidence

This page is the authoritative current-state reference for Prikk’s patch algebra and merge-evidence concepts. It describes the current implementation and is grounded in the code, released RFCs, and implementation status records listed in the anchor table at the foot of the page.

For command syntax and examples, see the merge evidence and merge plan guides.

Core Caveats

  • Prikk is early implementation software and is not a production Git replacement.
  • Patch algebra and merge evidence are currently read-only analysis surfaces.
  • prikk merge-evidence and prikk merge-plan require explicit baseline, left target, and right target inputs. They do not infer merge bases or branch merge intent.
  • Current confluence results apply only to the supported operation subset and the selected explicit candidate sequences.
  • Confluent and ConfluentSubset alone do not create a merge commit — prikk merge (DC-74) is the separate, explicit command that executes a confluent merge; see the merge guide.
  • Active-WAL merge drafts, worktree conflict materialization, conflict-resolution UI, persisted proof/witness/plan objects, JSON output, same-node text operational transforms, path-scoped analysis, and public stable Rust APIs remain deferred.

Patch Operations and Ordering

A Patch contains ordered operations. The evidence displays use op_seq to show the one-based operation sequence recorded by a Patch operation, while bracketed indexes such as left[0] and right[0] show the zero-based position in the derived left or right candidate sequence.

The current evidence model summarizes operation kind, optional node id, and a safe repository-relative path when one is available. It does not expose raw operation payloads. Preconditions and evidence facts are checked through the store-backed patch-algebra evidence boundary; malformed required sealed evidence is an evidence failure, not ordinary unsupported algebra.

Pair Classification

Internal pair classification currently uses four categories:

Pair classMeaning
IndependentThe classifier sees no ordering or conflict relation for the pair, subject to later replay proof.
OrderedDependencyThe pair has a required order, such as create-after-delete relations that can only be considered in one direction.
ConflictThe pair has a concrete conflict witness, such as same-path creation, live-state mismatch, mode/blob mismatch, or delete/mutation conflict.
UnknownThe relation cannot be safely classified, either because the operation/relation is unsupported, evidence is insufficient, or the design is intentionally deferred.

These Rust categories are implementation details, not stable public API. Public commands surface the separate merge-evidence outcomes described below.

Intent metadata is advisory. It does not override replay, lifecycle, preimage, evidence, or commutation proof requirements.

Commutation

Prikk treats a pair as commuting only when both conditions hold:

  • the classifier reports Independent; and
  • replaying the pair in both orders produces the same lifecycle state.

If the classifier reports an ordered dependency or conflict, the pair does not commute. If required evidence is missing or malformed, the analysis fails closed as an evidence problem. If a relation is not supported or is intentionally deferred, it remains unknown rather than being treated as safe.

Flat Confluence

Current confluence is flat and explicit-input. The analysis receives a sealed baseline state plus two candidate operation sequences derived from explicit left and right targets.

The current check requires:

  • each candidate sequence to replay validly enough for the supported subset;
  • cross-pairs between left and right to commute;
  • replay of left-then-right and right-then-left to succeed; and
  • final lifecycle states to be equal.

This is not automatic branch merge semantics. It does not choose a merge base, publish a result, materialize a worktree, create a merge commit, or create multi-parent Blocks.

Evidence Outcomes

prikk merge-evidence prints the public DC-21/DC-23 outcome vocabulary:

OutcomeMeaning
ConfluentThe selected sequences are proven confluent under the current supported analysis. This is scoped evidence, not execution readiness.
ConflictA concrete conflict witness was found.
OrderedDependencyA relation requires ordering policy that the current public merge surface does not execute.
UnsupportedThe operation kind or relation is outside the supported algebra subset.
DeferredThe relation is known but intentionally deferred, such as same-node text transforms or sequence-internal dependency handling.
NotConfluentReplay or final-state comparison failed after otherwise supported analysis.
EvidenceFailureRequired sealed evidence is missing, malformed, unreadable, wrong-type, or identity-invalid.
InvalidCandidateCandidate input is malformed or insufficient before analysis can produce usable evidence.

EvidenceFailure is distinct from Unsupported or Deferred: required sealed evidence failures must not be hidden as unknown algebra.

Reason Codes and Proof Phases

Evidence output also prints reason: and item-level phase: fields. Reason codes explain why an outcome was produced; phases say which proof stage produced the item.

Current public reason-code names include:

Reason codeMeaning
proven_confluentThe selected pair or sequence passed the current confluence proof.
pair_conflictA cross-side pair produced a conflict witness.
ordered_dependencyA cross-side pair requires a specific order.
unsupported_operationThe operation or relation is outside the current supported subset.
same_node_text_transform_deferredSame-node text operational transforms are intentionally deferred.
sequence_internal_dependency_deferredA sequence-internal dependency blocks flat confluence analysis.
pair_replay_failedReplaying a pair in both orders did not prove commutation.
final_state_mismatchFinal lifecycle states differed after composed replay.
missing_required_evidenceRequired sealed evidence was absent.
malformed_required_evidenceRequired sealed evidence was present but malformed.
wrong_type_required_evidenceRequired sealed evidence had the wrong object kind.
unreadable_required_evidenceRequired sealed evidence could not be read.
invalid_unsealed_candidateOptional unsealed candidate evidence was malformed.
insufficient_unsealed_candidate_evidenceOptional unsealed candidate evidence was insufficient for analysis.

Current public proof phases include:

PhaseMeaning
classificationPair classification or evidence validation produced the item.
replay-both-ordersPair replay in both operation orders produced the item.
flatnessCandidate-sequence flatness checks produced the item.
final-state-comparisonFinal lifecycle-state comparison produced the item.

composed-replay exists only behind test-only display code and is not a current public phase.

Conflict Witness Kinds

reason_code: pair_conflict names the outcome bucket, not the reason: all twelve conflict-witness kinds patch_algebra distinguishes internally reported as the same generic pair_conflict code, which told a reader nothing about why a specific pair conflicted (conflict-witness-presentation handoff v1). MergeEvidenceDisplayItem now additionally carries the specific kind, path, and node identity a cross-side (Conflict/OrderedDependency) item’s witness recorded:

FieldMeaning
witness_kindThe specific reason this pair conflicts or orders, as a stable kebab-case label. None for items with no underlying witness.
witness_pathThe repository-relative path the witness recorded as the reason for conflict, when it recorded one. Distinct from each side’s own operation.path/peer_operation.path: derived from whichever operand’s own path field or live baseline path resolves (conflict-witness-path-derivation handoff v1), so it is present even for node-identity conflicts where neither side’s own operation carries a path at all — as long as the shared node has a live entry in the baseline. None when the two operands resolve to two different paths (a single field cannot pick one) or when the node has no live baseline entry to derive from.
witness_node_idThe shared node identity, typed (not a rendered string — no stable human-facing node-identity rendering exists in this codebase to freeze into this field). The only correlating signal for the conflicts that stay genuinely path-less: a node-identity mismatch against a node with no live entry in the baseline at all.

Current witness_kind labels:

LabelMeaning
same-path-createBoth sides create a node at the identical path.
node-id-reuseA node identity is reused across unrelated creations.
live-state-mismatchA side’s precondition does not match the state the other side’s operation requires.
kind-mismatchThe two sides disagree about the node’s kind (file, symlink, etc.).
mode-mismatchThe two sides set different, incompatible permission modes.
blob-mismatchThe two sides replace binary content with different, incompatible results.
text-span-overlapBoth sides edit the identical text span.
text-anchor-staleA text edit’s anchor no longer matches the state it was planned against.
delete-mutation-conflictOne side deletes a node the other side mutates.
unsupported-operationThe operation kind is outside the currently supported algebra subset.
malformed-operationThe operation itself failed to decode into usable facts.
unknown-relationThe pair’s relation does not match any more specific classification.

These labels are an external interface, the same footing reason_code and proof-phase strings are already on (Privacy and Output Limits, below): renaming, removing, or reusing one is a breaking change to any tool reading merge evidence.

Conflict Resolution Is Refused By Design

Automation may not author a conflict resolution. This is a settled architectural position (conflict-witness-presentation handoff v1), not an unscoped feature waiting to be built, and it follows directly from two decisions already made elsewhere in this project:

  • DC-35: “Automation may verify evidence but cannot occupy either accountable approval identity.”
  • DC-74 applied that at the patch layer already, and its own reasoning is why arbitration can’t be added later as an ergonomics feature: in a context-dependent (Darcs-style) model, merging a patch transforms it — its canonical bytes change, its ObjectId moves, and the original AUTHOR signature no longer covers the result, so whoever performs the merge must re-sign content they did not write. That is DC-35’s “automation cannot occupy an accountable approval identity,” arriving at the patch layer. Prikk’s merge design avoids this entirely: prikk merge (DC-74) adopts the other side’s patches verbatim, unmodified, under their original AUTHOR signatures — nobody re-signs content they did not write.

An automatic conflict arbitrator would reintroduce exactly the problem DC-74 was built to avoid: resolving a conflict means producing new content — a patch — and a patch must be authored and signed by whoever is accountable for it. So conflict arbitration is refused by the architecture itself, not merely unscoped or deferred to a future increment.

Resolution already exists, and needs nothing further built: prikk merge refuses on any conflict, and a person reconciles the two sides by authoring ordinary patches under their own key — the same committing every other change in this repository already goes through.

Merge Plan Mapping

prikk merge-plan preserves the underlying evidence outcome and maps it to a non-executable planning status:

Evidence outcomePlan statusAction
ConfluentConfluentSubsetReview the evidence, then run prikk merge (DC-74) to execute.
ConflictBlockedConflictInspect evidence; conflict resolution is not implemented.
OrderedDependencyBlockedOrderedDependencyInspect ordering evidence; execution ordering policy is not implemented.
UnsupportedBlockedUnsupportedInspect unsupported operation evidence.
DeferredBlockedDeferredInspect deferred design evidence.
NotConfluentBlockedNotConfluentInspect replay/final-state mismatch evidence.
EvidenceFailureBlockedEvidenceFailureRepair or verify repository evidence before planning.
InvalidCandidateBlockedInvalidCandidateSelect valid sealed candidates before planning.

ConfluentSubset is intentionally narrow. It means the selected candidates are proven confluent only for the currently supported subset. It is not a whole-merge guarantee and does not mean Prikk can create a merge commit.

Privacy and Output Limits

Evidence and plan output are intended for human diagnostics, not as durable machine-readable schema. The current display model avoids raw replacement text, raw text spans, blob bytes, absolute host paths, .prikk private paths, signer secrets, key material, arbitrary object debug dumps, and raw operation payloads. Displayed paths are repository-relative when available and safe.

Deferred Work

prikk merge (DC-74) executes confluent merges — see the merge guide. Still deferred: automatic merge-base discovery, branch merge semantics beyond a two-sided confluent merge, active-WAL merge drafts, worktree conflict materialization, conflict-resolution UI, persisted proof/witness/merge-evidence/merge-plan objects, same-node text operational transforms, path-scoped analysis, display-path filtering, JSON output, patch-algebra crate extraction, and public stable Rust APIs for replay, patch algebra, merge evidence, or merge planning internals.

Conflict resolution itself is not on this list — see Conflict Resolution Is Refused By Design, above. “Deferred” means eventually built; automatic conflict resolution is refused by the architecture and will not be built at all. A conflict-resolution UI remains deferred in the sense above, but only for the human-authored-patch workflow this page already describes, never for an automatic resolver.

Claim-to-Source Anchors

ClaimSource anchors
Pair classification uses Independent, OrderedDependency, Conflict, and Unknown.types.rs, classify.rs, DC-16
Commutation requires classifier independence plus replay-both-orders proof.commutation.rs, DC-18
Flat confluence checks individual sequence validity, cross-pair commutation, composed replay, and final lifecycle-state equality.commutation.rs, analysis.rs, DC-18
Required sealed evidence failures are reported separately from ordinary unsupported algebra.evidence.rs, error.rs, DC-17
Merge-evidence public outcomes are Confluent, Conflict, OrderedDependency, Unsupported, Deferred, NotConfluent, EvidenceFailure, and InvalidCandidate.types.rs, display.rs, DC-21
Reason-code and proof-phase strings are display vocabulary, not persisted object schema.display.rs, mapping.rs, DC-21
merge-evidence is read-only and requires explicit baseline plus left/right targets.merge_evidence.rs, DC-22, merge evidence guide
merge-plan maps evidence outcomes to ConfluentSubset and Blocked* statuses without adding merge execution.merge_plan.rs, DC-25, merge plan guide
Evidence and plan output avoid raw text spans, replacement text, blob bytes, absolute host paths, and arbitrary object debug dumps.display.rs, DC-21, DC-23
Patch algebra, merge evidence, and merge plan internals are not public stable Rust APIs.DC-20, DC-25, implementation status
Conflict-witness kinds (twelve) are generated with their labels from one macro invocation, the same discipline VerificationStage uses.types.rs, conflict-witness-presentation handoff v1
MergeEvidenceDisplayItem publishes witness_kind/witness_path/witness_node_id, but never the underlying left_op_seq/right_op_seq pair or raw text_span bytes.display.rs, mapping.rs
Automatic conflict resolution is refused by design (DC-35 applied at the patch layer, per DC-74).DC-35, DC-74, merge_execute.rs, conflict-witness-presentation handoff v1

Provenance

This reference consolidates released records through DC-25 and follows the DC-26 documentation-home model: current-state references live in the published mdBook, while RFCs retain design history and gating material. It does not change code, schema, CLI behavior, merge semantics, or public API stability.