Documentation
On this page
  1. Install the repository merge contract
  2. Independent worktree runtimes
  3. Fence coverage contract
  4. Artifact semantics
  5. Portable receipt proof
  6. Historical receipt reader compatibility
  7. Receipts from an aborted rebase
  8. Cross-branch id collision safety
  9. Executable convergence evidence
  10. Settle a lossless merge in one commit
  11. Required post-merge gate
  12. Delete versus modify policy
  13. Runtime receipts and retention
  14. Temporary-clone acceptance test

Multi-Branch Tracker Merge Safety

Tracked by pm-wc1r, with the integrity and concurrency fixes pm-9q2t, pm-cxyv, pm-gpo7, pm-m3nl, pm-wwfd, and pm-xdn6. Fresh-init fence ownership is tracked by pm-1w3ljt; runtime-cache index governance by pm-hous; local allocation safety by pm-khdq; fence-coverage completeness and drift detection by pm-i4fx; package-defined item coverage by pm-5rexki; non-item JSON coverage by pm-gjicmx; portable driver identity by pm-w91mvg; pending receipt validation by pm-ysqb6n; receipt classification by pm-jtwsct; direction-independent item conflict selection by pm-dlx7v7; corrected reconciliation guidance by pm-lwmstb; cross-branch id collision safety by pm-pibw; auditable merge history by pm-9j2r3b; durable conflict decisions by pm-rh98vo; continuous conformance by pm-76dnfg; workspace-wide CI enforcement by pm-pdr8t1; post-merge reconciliation by pm-mfkv92; linked-command execution trust by pm-ed28wi; this repository's own adoption by pm-iwsj.

Lossless receipt health gating is tracked by pm-baksix, and executable remediation that performs settlement is tracked by pm-r0p3at. Immutable record sealing and retained re-anchor evidence are tracked by pm-javbsq and pm-aka8m7; preferred-era receipt-summary compatibility is tracked by pm-wn3ee5. Lossless concurrent acceptance-criteria composition is tracked by pm-inn5y5. The Bun launcher and strict-health repair are tracked by pm-vks66s, with the Bun 1.3.5 package-runner recurrence tracked by pm-aaxq4n. Recency-aware scalar convergence, bounded fresh-clone decision evidence, and audited pre-durable receipt dispositions are tracked by pm-7wzb6d, pm-mg13iz, and pm-cf4t42.

pm stores project context as reviewable repository files. Concurrent agents can therefore use ordinary branches and worktrees, but tracker artifacts need semantic merge behavior: raw line merging cannot preserve TOON collection counts, JSON object structure, or append-only history hash chains.

Install the repository merge contract

Fresh pm init runs this automatically when the tracker is inside a Git worktree. It writes the shared fence and configures the current clone before returning success. Use pm init --no-merge-fence only when another system deliberately owns Git merge configuration.

Existing trackers and fresh clones can install or repair the contract directly:

pm merge install
git add .gitattributes
git commit -m "chore(pm): install tracker merge drivers"

pm merge install writes an idempotent, fenced .gitattributes block and repository-local git config entries. The attributes are committed; the driver commands are clone-local, so every collaborator and fresh CI clone that performs merges must run the install command.

The clone-local driver values record the absolute runtime launcher and bundled dist/cli.js path resolved by the installing SDK. With Node, the installer preserves an absolute PATH symlink when it resolves to the executing runtime, so a runtime manager can retarget that launcher during upgrades without breaking every clone. With Bun, the installer checks the absolute executable published by the package runner, absolute PATH entries, and the directly invoked binary for a matching Bun version, then records its stable target. Known temporary bun-node-* launcher copies are rejected even when their version matches. Relative paths, inaccessible launchers, and different runtimes are ignored. If no durable matching Bun launcher is available, installation fails with recovery guidance before it writes Git configuration or the shared fence; a temporary bunx runtime is never recorded as a successful driver installation. Git therefore does not depend on a bare pm command or the caller's later PATH when it merges tracker data. The item-path placeholder is stored as bare %P: Git performs the required shell quoting when it expands the placeholder. Receipt ingestion also removes one legacy matching quote pair so receipts written by older clone-local drivers remain reconcilable. pm validate --check-storage-integrity and pm health also compare every effective driver definition with the installed SDK. A command installed by another valid @unbrained/pm-cli package is also accepted when its Node or Bun launcher and dist/cli.js paths exist, its manifest owns the pm bin, the driver arguments are semantically identical, and its version matches any exact project runtime pins. A driver inside a sibling worktree of the same repository is rejected, even when that package is otherwise valid. Independent global installations remain supported. A missing, malformed, or semantically stale definition is reported even when the committed attribute fence is correct. Health and validation name pm merge install as the repair command for missing or drifted drivers. This upgrade behavior is tracked by pm-rcjyft.

The installer publishes the shared .gitattributes fence only after the clone-local driver commands are configured. Matching definitions are read without rewriting Git configuration. Concurrent pm installers coordinate through a clone-local lock shared by its worktrees. Each required Git write waits up to five seconds for Git's native config-file lock, with capped backoff; it never removes another writer's lock. Persistent contention, malformed configuration, and permission failures return the stable merge_git_config_unwritable error with recovery guidance and leave an absent fence absent. This behavior is tracked by pm-gh1424. Use pm merge install --dry-run --json to inspect the contract in intentionally read-only workspaces.

Independent worktree runtimes

Tracked by pm-c1dwbt.

Run pm merge install from each worktree with that worktree's intended pm installation. When installing in a linked worktree, the SDK enables Git's extensions.worktreeConfig and writes drivers with git config --worktree. Existing main-worktree drivers are preserved in its config.worktree; later installs cannot replace another worktree's runtime. Main-only core.worktree and core.bare=true settings migrate with their original scope. Ordinary clones retain local configuration until worktree isolation is needed. Git subprocesses discard inherited repository-location variables so an SDK caller's GIT_DIR cannot redirect installation or diagnosis to another clone. Configuration migration uses multiple Git writes: a failed write is reported, and rerunning pm merge install after resolving the config lock or permissions completes the migration while preserving values already copied for the main tree.

Health reads Git's effective configuration, including worktree overrides. Removing a sibling worktree does not remove a separately installed main driver. Use pm merge install in the affected worktree to repair stale, missing, or incompatible commands. A dry run changes neither configuration nor attributes.

Fence coverage contract

Extension assets are tracked by pm-gh1460. Files under extensions/** use Git's built-in merge=text driver, so separate text edits combine and overlapping edits retain normal conflict markers. Git still detects binary content and preserves its conflicted stages. The later .managed-extensions.json rule keeps the structured pm-json driver. The v2 fence grammar remains stable; pm merge install refreshes stale patterns without discarding sibling fences or restoring legacy unversioned markers.

The fenced block is generated by one shared coverage contract (buildMergeAttributePatterns) covering every mergeable artifact class: tracker-wide **/*.toon and **/*.md item patterns, explicit per-type diagnostic patterns, all tracker **/*.jsonl paths under the relationship-event driver with the more-specific history/*.jsonl rule overriding history streams, root settings.json, and every nested **/*.json document. The tracker-wide item rules protect extension-defined type folders even when a receiving branch has not installed the package that registered them; explicit type rows still make active-registry drift diagnosable. The broad JSON rules automatically cover schema, managed-extension, evaluation-corpus, and future package-owned authoritative JSON without another hand-maintained allowlist. The broad JSONL rule is required because RelationshipEventStore supports package-owned custom relative paths anywhere below the tracker root. Two mechanisms keep the committed fence from drifting out of that contract:

  • pm schema add-type / pm schema remove-type refresh the fence automatically when it is installed (warning merge_fence_refreshed); repos inside git that never installed it get the actionable merge_fence_not_installed hint instead.
  • pm validate (the storage_integrity check) audits the committed fence against the active schema's type folders and reports validate_merge_fence_drift with the exact missing/stale attribute lines when they diverge — for example after editing type folders out-of-band. Rerun pm merge install and commit .gitattributes to clear it.

Preview without mutation:

pm merge install --dry-run --json

Artifact semantics

History scalar rebasing and ignored settlement artifacts are tracked by pm-gh1553 and pm-gh1556.

Artifact Driver Merge behavior
Item .toon / .md pm-item-toon / pm-item-markdown Three-way field merge; append-like collections use set union, updated_at uses the latest timestamp, scalar conflicts select the value from the later document update with stable value order as an equal-timestamp tie-break, and canonical serialization recomputes TOON counts.
history/*.jsonl pm-history Preserves the common prefix and both divergent suffixes, orders deterministically, then re-anchors the resulting hash chain.
tracker **/*.jsonl except the later history/*.jsonl override pm-relationship Covers default and package-owned custom relationship event paths, unions divergent suffixes by eventId (timestamp-ordered, ours-first on ties), and renumbers sequence consecutively so the strict-sequence store loader accepts the merged stream.
root settings.json and nested **/*.json pm-json Recursively merges objects per key. Arrays compose when both branches preserve the base and add distinct entries, so independent extension installs and evaluation additions merge without weakening edit/removal conflict detection.

History union validates each event in its original branch before rebasing its effects. A whole metadata-field replacement still assigns its exact value when another branch removed that field; a repeated whole-field removal keeps its event even when absence already satisfies its effect. This covers a branch claim following another branch's release without losing closure or comments. Nested paths and conditional patches remain strict. An unsafe scalar patch refuses with history_union_rebase_conflict and SDK history_merge coordinates (branch, one-based event line, operation, scalar-patch index and JSON pointer). CLI diagnostics name those coordinates in the error message. Preserve all three inputs and both item snapshots for deliberate recovery; verify the resolved history and preview reconciliation before committing.

The tests collection has an additional execution-safety rule. Its semantic identity excludes provenance so the same command/context does not duplicate when branches record different authorship metadata. A test definition newly contributed by the other merge side is persisted with provenance.source_kind=merge_union while retaining its author, creation time, and source ref. pm test --run and pm test-all refuse that command before spawning a process until the receiving clone acknowledges its fingerprint or uses the two-part project-policy plus per-run override documented in Testing. pm validate --check-command-references reports outstanding entries. This is the threat boundary for append-like data that becomes executable after a merge; ordinary notes, files, and other non-executable collections retain normal set-union behavior.

Although acceptance_criteria is serialized as a semicolon-delimited scalar for backward compatibility, the item driver treats its parsed criteria as a collection. Independent additions compose in branch order, removals made by either side remain removed, the field is reported in union_fields, and a lossless merge does not create a scalar conflict decision. This gives repeated pm update --add-ac mutations the same multi-branch preservation guarantee as native append-like metadata without a storage migration.

When both sides change the same item scalar differently, the driver retains the value from the document with the later metadata.updated_at timestamp. Equal timestamps fall back to stable value ordering, so reversing Git's ours/theirs labels still converges to the same result. Item results, driver results, and receipts expose conflict_resolution: latest_document_update and requested_preference_applied: false; each conflict decision adds retained_side and resolution_basis so review automation can distinguish a recency decision from the stable tie-break. The caller's requested_preference remains observable but does not override item scalar convergence. Readers continue to accept legacy preferred_side and stable_value_order receipts and normalize the legacy preferred key. JSON leaf conflicts retain their explicit preferred-side policy. Git keeps the item path conflicted so a human or coordinating agent must review the discarded value and explicitly git add the resolution.

The exact object { "pm_item_scalar_missing": true } is reserved for JSON-stable missing-value evidence. Item merge inputs reject that object as a present metadata value, while the hashing primitive independently separates present and missing domains. This prevents extension data from impersonating a deletion without wrapping every ordinary scalar in receipt output.

The driver result's guidance always points unresolved conflicts to pm merge report. When a clone-local receipt exists, guidance includes its privacy-safe receipt and item ids for exact correlation; discarded values remain confined to the local receipt and never appear in generic logs or tracker history. Tracked by pm-fbrz7p.

For item conflicts, the driver writes a clone-local receipt below the Git directory and a durable privacy-safe sidecar below merge-receipts/ in the tracker. The local receipt contains retained and discarded values so recovery does not depend on a reflog. The tracked sidecar applies the versioned bounded_non_sensitive_scalars_v1 policy. Built-in lifecycle statuses, priority integers from 0 through 4, bounded risk/confidence/severity ordinals, and null are stored with both their value and matching hash. All other values remain hash-only. value_availability distinguishes bounded_inline, mixed, and hash_only, while the clone-local receipt remains clone_local. This lets a fresh-clone reviewer recover ordinary control-plane decisions without publishing titles, descriptions, custom statuses, or other potentially private content. When both copies exist the SDK deduplicates them and prefers the locally recoverable values. After immutable provenance matches, durable reconciled state takes precedence over a stale clone-local pending copy only when verified item history contains a sealed merge_reconcile event with the same complete receipt summary and disposition. An absent, unreadable, invalid, unsealed, or mismatched audit keeps the receipt pending in memory; inspection rewrites neither receipt nor history. History is verified once per affected item in each receipt scan. Historical receipt recovery is tracked by pm-tknnzp. Historical item-state hashes do not authenticate audit context. An older unsealed merge_reconcile summary therefore cannot retain settled state, even when its receipt identity, fields, and value hashes match. Editing that context leaves the legacy item chain valid. Keep these receipts pending for explicit reviewed migration to a modern sealed audit; never retroactively trust the old summary or synthesize an old signature during inspection. If compaction removed the audit, the receipt also stays pending. Preview with pm merge reconcile --dry-run; review its summaries and repair failures and re-apply any intended discarded values. Only with explicit review authority, use pm merge reconcile --force --message "<reviewed receipt disposition and rationale>". That command appends acceptance evidence; it cannot recover missing evidence or restore discarded values. This migration guidance also applies to a lossless receipt whose snapshot proof is unavailable. Copy provenance includes normalized requested_preference_applied, so copies that disagree on whether preference participated cannot share lifecycle state even if history matches one copy. Inspection reports copy_provenance_mismatch, and settlement refuses before either receipt is written. Legacy omission uses the declared conflict policy's default participation value. A local reconciled copy paired with a pending durable copy remains pending, so an interrupted settlement can finish its durable write:

pm merge report
pm merge report --include-reconciled

The underlying public SDK exports are mergeItemDocuments, mergeHistoryStreams, mergeRelationshipEventStreams, mergeJsonDocuments, runMergeDriver, runMergeInstall, installMergeFence, findGitWorkspaceRoot, runMergeReconcile, runMergeReceiptReport, runMergeReceiptEvidenceReport, inspectMergeReceiptEvidence, listMergeReceipts, auditMergeDriverConfiguration, refreshMergeAttributeFenceIfInstalled, buildMergeAttributePatterns, and auditMergeAttributeFence from @unbrained/pm-cli/sdk. installMergeFence accepts explicit tracker and workspace roots, so custom init hosts do not depend on process cwd or CLI globals.

Collection projection is tracked by pm-pftgcz. History union reconstructs each event in its original branch before merging collection values with the item driver's shared policy. Positional comment, doc and test patches from an earlier reconciliation therefore cannot overwrite an unrelated entry at the same array index on another branch. Original event attribution and patches remain in sealed rewrite evidence; replayed collections use the canonical item order and receiving-side linked-test provenance. The SDK reanchor primitive accepts projectPatch for this explicit projection boundary. It retains the replaced patch rather than erasing its source. Exact receipt settlement still requires an authoritative matching snapshot, and newly merged executable tests still require clone-local trust acknowledgement.

listMergeReceipts is the compatibility projection for callers that only need validated receipts. It cannot distinguish an empty evidence store from a store whose candidates were all rejected. Gates and diagnostic integrations should use inspectMergeReceiptEvidence, whose invalid_evidence_count preserves that distinction without returning malformed contents. runMergeReceiptEvidenceReport and pm merge report --json expose the same loss-aware contract through complete, invalid_evidence_count, bounded invalid_evidence[], invalid_evidence_truncated, and clone_local_evidence_resolved. Each rejected candidate reports a stable reason plus its clone_local, durable, or copy-consistency source. Schema and identity failures additionally expose a bounded validation_error such as required_fields, item_path, filename, or durable_decisions. A safe receipt filename is returned as receipt_id; unsafe candidate names are represented only by candidate_name_hash, and malformed contents are never returned. The detail list is capped at 100 rows while the count remains exact, so automated gates stay token-bounded. Directory traversal distinguishes a truly absent store from a non-directory or unreadable ancestor on Windows and POSIX instead of treating platform-specific ENOENT/ENOTDIR spellings as equivalent. Full health also cross-checks the privacy-safe receipt summaries in append-only history against valid pending and reconciled evidence. Missing evidence emits merge_receipt_history_reference_missing:<n> with bounded item, history-line, and receipt-id-or-hash coordinates. Recover an available receipt from an authoritative clone or backup first. For an exact reference whose history-event timestamp predates tracked durable receipts, pm merge reconcile --force can append a merge_reconcile audit event containing the original item, line, receipt id, timestamp, and the closed legacy_clone_local_only reason. Health accepts only that exact coordinate and reports it through accepted_missing_merge_receipt_dispositions; it never rewrites or deletes the original history. The audit event must also occur after the referenced history line; an earlier event cannot pre-authorize a later missing receipt. Missing post-durable evidence remains blocking and cannot be dispositioned through this compatibility path. The CLI exits nonzero when evidence is incomplete, even when the valid-receipt count is zero. Current SDK implementations always emit the new field, while its optional type preserves structural compatibility for existing typed adapters and test fixtures. A structurally valid preferred-era history summary that contains its complete privacy-safe receipt evidence is accepted in place: health counts it as accepted_legacy_merge_receipt_references and does not demand an external receipt file that the older writer never created. Incomplete, contradictory, or modern summaries still fail closed. runMergeReceiptReport remains the compatible valid-only report.

Portable receipt proof

Reconciliation refuses merge_receipt_not_portable before any audit write when an active clone-local receipt lacks a validated tracked counterpart. --force does not bypass this boundary, including for direct SDK history-repair calls. An earlier aborted operation can leave an unreferenced local receipt whose field hashes happen to match a later merge; those hashes do not make its evidence portable. Review and preserve unrelated stale receipts outside the active store, or restore the original valid durable sidecar. Never copy private local receipt values into tracked evidence as a substitute.

inspectMergeReceiptEvidence().durable_receipt_ids identifies validated durable counterparts whose immutable provenance matches the stored blob referenced by the Git index; clone-local replacement refs cannot substitute different evidence. Untracked files and mismatched staged versions cannot authorize an audit write. unstaged_durable_receipt_ids reports valid disk candidates for a read-only preview; clone-local-only evidence remains refused even in preview. Current readers return both arrays; their optional interface properties preserve structural compatibility, and a missing property provides no evidence. Health resolves committed history references against these durable identities, so a local copy cannot hide evidence that a fresh clone will lack. Receipt summaries remain privacy-safe.

Historical receipt reader compatibility

Tracked by pm-2xtv84 and pm-v66zir. Version-1 preferred-era and identified requested_preference/clone_local receipts may omit base, ours, or theirs when the original value was undefined. Readers normalize those slots to the explicit missing-value marker in memory. They still require retained/discarded evidence and valid collections; reading never rewrites the original file. Collection failures expose a bounded validation_path, such as union_fields or decisions[0]. The diagnostic category collections is not a property that should be added to a receipt. The writer now encodes all five scalar slots itself, including undefined retained/discarded values supplied directly through the SDK, before JSON storage.

Paired clone-local and historical hash-only copies accept the original scalar hash encoding throughout inspection and settlement. Compatibility does not apply to durable copies declaring the modern value policy. Changed values or immutable coordinates remain copy-provenance failures. Hash-only evidence does not recover the original private value.

Receipts from an aborted rebase

Tracked by pm-466m0j and pm-gh1405. New receipts created during a merge or rebase capture only its operation kind, original commit, and item blob in the typed MergeReceiptOperation contract. A plain merge captures these before Git publishes MERGE_HEAD: Git must supply its GITHEAD_<incoming object ID> driver environment signal, HEAD must equal ORIG_HEAD, and the driver's ours input must hash to the item blob at that commit. Missing or ambiguous coordinates are omitted. Matching origin references and bytes alone cannot identify a plain merge: cherry-pick and revert also invoke content drivers. Without Git's incoming-head signal, those receipts remain unresolved and cannot receive a plain-merge abandonment audit. Branch labels from the driver environment are never persisted. After aborting, run:

pm merge reconcile --dry-run --json
pm merge reconcile --message "Record restored original Git state" --json

SDK consumers that exhaustively handle MergeReceiptOperation.kind must accept both rebase and merge. Existing rebase coordinates and receipt version remain valid; no stored receipt migration is required.

Settlement requires Git to have left every active merge/rebase/cherry-pick/revert operation, HEAD to match the original commit, and the item in HEAD, index, and working tree to match the original blob. The item history must already be clean. Requiring the original HEAD also rules out a new commit incorporating the abandoned merge's other branch. The history transaction rechecks the proof against its exact protected item snapshot. Apply appends an explicit merge_reconcile event with abandoned_receipts and the reason original_git_state_restored; it then marks both copies reconciled with that settlement reason. The result counts these in receipts.abandoned, separately from applied merge decisions. Preview performs the same eligibility checks and leaves both history and receipts untouched. If receipt persistence fails after the audit commits, retry reuses the identical verified disposition and finishes the receipt writes without appending another audit event. An unrelated earlier audit does not satisfy this check.

The driver-created merge-receipts/<receipt-id>.json sidecar can remain untracked after Git aborts. After reviewed settlement, commit that privacy-safe sidecar together with the item's new history audit. Reconciliation preserves the durable evidence for other worktrees instead of deleting the sidecar.

Applied-merge settlement has the same retry contract, tracked by pm-gh1390. The current item must still satisfy authoritative receipt proof; only an identical receipt context in a sealed event from reanchored, verified history suppresses a repeated provenance event. Matching unsealed legacy context receives a new sealed audit while its original entry remains intact. This also works with durable-only evidence in another worktree. Once that worktree commits the settled sidecar and history, a receiving worktree's stale local pending receipt cannot reopen it. A subsequent pm merge reconcile leaves all three files unchanged.

Old receipts without operation coordinates remain pending for ordinary review. Tracked merge-receipts/ sidecars are durable provenance and must remain tracked. Deleting or ignoring them would lose the evidence needed by other clones.

Cross-branch id collision safety

Tracked by pm-qx95lz.

Item ids are <prefix> plus random base36 characters. Local allocation reserves both live documents and retained history, but cannot see independent creations on another branch. The four-character default is a small, synchronized-workspace setting; it is not a fleet uniqueness guarantee. ids.token_length accepts 4–12. The allocator increases width after 32 local collisions to escape local density; this does not measure concurrent branch activity.

For a shared base containing n reserved ids and m unsynchronized creations, choose width L so m*(m-1)/(2*(36^L-n)) stays below the desired per-sync collision probability. This birthday union bound assumes independent uniform allocation and all branches know the same reserved ids. At one million reserved ids, eight characters keep 1,000 concurrent creations below one in a million; nine characters do so for 10,000 creations. Configure the width before branching:

pm config project set ids_token_length 8

The SDK item merge refuses an empty common ancestor with item_identity_conflict, even for equal item content: document equality alone cannot prove a common creation. The pure merge primitive leaves inputs unchanged. The Git driver preserves both original snapshots in visible conflict markers and names the item in its refusal, tracked by pm-gh1491. Staging these files does not clear the conflict-marker health and storage failures. A copied creation or history prefix alone never authorizes fusion of two independently introduced identities. The history merge also refuses different create events across its inputs, multiple creates in either input, or creations on both sides when the ancestor lacks a create event even when their bytes match, before fast-forwarding or reanchoring. A common ancestor containing the shared create event remains valid.

storage_integrity detects multiple physical documents and a second create event within one history stream, reporting its line in history_unparseable_streams as an invalid lifecycle. This check also protects merges Git resolves without invoking a content driver. pm get and SDK item lookup refuse multiple physical matches with item_identity_ambiguous; the message lists tracker-relative paths and SDK error context exposes a typed paths array. Format preference cannot select a winner. Only candidate paths are probed, so lookup does not enumerate every item in the workspace.

Preserve both branches when a collision is reported. Recover each item from its unambiguous source branch, create the second under a fresh id, and update its references before retrying the merge. Do not repair a fused stream merely to make its hashes pass: a new hash chain does not recover a lost identity.

Within one working tree, create and copy serialize on the candidate id and recheck every built-in and extension-defined type folder before the authoritative write. A raced collision fails with item_id_collision instead of replacing the existing document.

Executable convergence evidence

pm-1tns7o replaces the tag-only property with generated complete-document comparisons. Fixed branch snapshots are folded in original, reversed, and rotated order, with both ours/theirs directions. Cases cover conflicting scalar writes and bodies, collection additions, distinct and equal timestamps, disjoint edits, and optional-field deletion. Independent expected documents are constructed directly for every N-branch case to check retained values and preserved context. A policy table also asserts that the compatibility preferred_side option is directional. The field-class inventories are pinned so changes require an explicit test update.

These properties exercise the declared three-way policies; they do not turn the document-level timestamp into per-field causal provenance. In particular, the N-branch conflict fixture compares competing writes to the same scalar set. Arbitrary histories, ordered executable test definitions with receiving-clone trust, and relationship-event ordering retain their separate conformance contracts.

Settle a lossless merge in one commit

Tracked by pm-gh1475. Pause Git before it creates the merge commit, then stage the audited settlement:

git merge --no-commit --no-ff <branch>
pm merge reconcile --stage
git diff --cached
git commit

--stage first previews reconciliation. It refuses discarded-value decisions, untrusted or unrelated repairs, invalid storage, missing durable evidence, unresolved Git paths, alternate Git indices, and unstaged edits to the reconciliation paths. It never accepts --force. Only the verified history streams and receipt sidecars are added to the index; unrelated staged changes retain their existing state. Validated new sidecars enter the index before any audit history is written. If apply fails, their new index entries are reverted while their files and unrelated staged work remain available for review. Staged receipt deletions remain operator decisions and are refused. --stage --dry-run checks this boundary without applying or staging anything. The result's staged_paths lists the repository-relative artifacts added. Tracker aliases resolve before preview, so proof verification, repair and staging use the same physical tracker root.

Both preview and apply check Git's effective ignore rules before any staging or audit write. An ignored artifact refuses with merge_settlement_review_required, reason: ignored_merge_artifacts, its relative path, and the owning file:line: pattern. Remove or narrow that rule, then retry the preview. Older workspaces may still ignore merge-receipts/ from the former clone-local receipt policy; current receipt sidecars must travel with the merge commit. pm health checks a representative receipt path even before a merge exists and reports merge_artifacts_ignored with the rule coordinates. A file-specific rule is also checked against each actual settlement artifact. Git negations and tracked files retain their native meaning; pm neither force-adds artifacts nor rewrites user ignore rules.

Repositories can explicitly opt into a merge-aware pre-commit hook:

pm merge install --pre-commit-hook --dry-run
pm merge install --pre-commit-hook
git merge --no-commit --no-ff <branch>
git commit

The hook runs guarded settlement only when MERGE_HEAD exists; ordinary commits are unchanged. Installation honors Git's hooks directory, including core.hooksPath, and preserves any hook without the pm ownership header. For an existing hook, integrate pm merge reconcile --stage into the reviewed merge path yourself. The installation result reports settlement_hook.path; removing that owned hook restores the manual workflow. Hooks are clone-local and must be installed explicitly in each clone. No hook is installed by default.

The explicit --no-commit --no-ff step is required. Git's automatic merge commit can capture its tree before a pre-merge-commit hook stages new audit artifacts; that hook cannot provide this single-commit guarantee. Rebase and already committed merges continue to use the explicit reconciliation gate below.

Required post-merge gate

Reconciliation resolves receipt discovery and settlement from the requested tracker. An explicit tracker outside Git does not consume clone-local receipts from an unrelated invocation directory; see pm-q5grv5.

After every branch merge that touches .agents/pm, run:

pm merge reconcile --dry-run --json
# When the preview lists unstaged sidecars, review and stage those files first.
pm merge reconcile --message "Reconcile merged tracker histories" --json
# Required only to accept a receipt that lacks qualifying exact hash proof:
pm merge reconcile --force --message "Accept reviewed merge decisions" --json

The preview reports every drifted stream and pending receipt without mutation. unstaged_durable_receipt_ids identifies valid filesystem sidecars awaiting matching immutable evidence in the Git index. The preview can inspect those sidecars, but ordinary apply refuses to cite them until they are staged. For the default tracker their paths are .agents/pm/merge-receipts/<receipt-id>.json; use git add -- <reviewed sidecar paths> followed by git diff --cached. Use --stage for the guarded lossless workflow above. After ordinary apply, stage the updated history and receipt lifecycle files together before committing. It applies the same exact-snapshot proof requirement as apply: stale or unprovable receipts appear as failed streams in both modes, tracked by pm-ao0bu9. Lossless receipts do not become discarded-value decisions and reconcile without --force, but pm health reports merge_receipts_pending:<n> and remains non-green until the apply pass settles them. pm history-repair cannot clear that receipt finding. When a drifted item also has a pending receipt, the history_drift remediation map prioritizes pm merge reconcile only when canonical item path, changed-field, and merged-value hash evidence all attribute that finding to one or more receipts loaded from the clone-local Git evidence store or the authoritative durable receipt store. Every field declared by each receipt must match its current merged-value hash, even when only a subset appears in the history reconciliation diff. Disjoint valid receipts may collectively cover a multi-field reconciliation; the audit and settlement then retain every individually proven receipt id. Serialized source claims are ignored. Receipt readers validate the complete bounded schema, safe identifiers, filename and item-path identity, timestamps, and bounded decision structure before a sidecar enters health or reconciliation. Reads use size-preflighted, no-follow regular-file descriptors; durable decision values must conform to the declared bounded-inline policy or remain hash-only. Qualifying durable-only receipts are reloaded from the authoritative store and accepted only after exact canonical item path, declared-field, and merged-value hash verification. Legacy receipts, receipts whose declared fields disagree with their hashes, same-item tampering, and drift on unrelated items fail closed to the normal pm history-repair guidance. Health indexes authoritative evidence once by item and reconciliation uses the same per-item groups with a fixed receipt-only worker pool, so committed sidecars cannot amplify drift scans into unbounded parallel repair work. The machine-executable remediation for a missing receipt reference names pm merge reconcile --dry-run. It never publishes --force as an executable hint: the human-readable summary explains that exact eligible pre-durable coordinates may be dispositioned by a separately reviewed force pass. Ordinary pending lossless receipts retain their unforced apply remediation. Apply-mode reconciliation repeats the same proof against the exact item snapshot used by the audited history rewrite. The audit event and settlement include only the individually proven receipt id, so one valid receipt cannot authorize an untrusted same-item sibling. Failed or unproven receipts remain pending unless the coordinator explicitly reviews and supplies --force. Snapshot verification accepts both the current presence-domain digest and the legacy version-1 scalar digest, so already-written receipts remain repairable; new receipts always use the collision-free presence-domain scheme. Receipts with discarded scalar values retain the distinct merge_decisions_unreviewed:<n> finding. Matching authoritative hash proof allows those receipts to settle without --force; without qualifying proof, the apply pass refuses them until the coordinator explicitly supplies --force after review. The history_drift_merge_receipt remediation may therefore emit an unforced apply command that clears merge_decisions_unreviewed when the receipt proves the exact current merged values. This prevents routine repair from hiding unfinished reconciliation while avoiding redundant force for an already-proven canonical snapshot. The same --force boundary also handles an unrecoverable pre-durable clone-local-only history reference. Preview and apply results expose missing_history_references_before, legacy_disposition_eligible, legacy_disposition_recorded, and missing_history_references_after. When coordinates exceed the bounded health response, explicit result guidance requires repeated dry-run and reviewed force passes until health no longer reports truncated coordinate details and the remaining count is zero. An apply result cannot return ok: true while any missing reference or truncated evidence remains. It exits nonzero while either merge-critical validation check is non-green, so CI and explicit post-merge hooks cannot approve unresolved receipts or drift. The apply pass uses the audited history rewrite boundary to append a merge_reconcile event whose patch reproduces the merged item exactly. The event includes privacy-safe receipt provenance; a clean receipt-bearing stream gets a no-op merge event so the merge remains addressable even when replay already matches. The command immediately validates history drift plus storage integrity and exits nonzero when an invariant remains red. Default Git hooks remain unchanged. The explicit merge-aware pre-commit option above includes settlement before committing; a repository-owned post-merge hook can still enforce reconciliation after an already-created merge commit.

The default validation surface includes storage_integrity. It fails on unreadable item documents, history conflict markers, malformed history tails, live items whose latest history operation is delete (a delete/modify resurrection candidate), and unparseable settings/schema files. This prevents the ordinary tolerant read path from turning corruption into a green gate.

A history union can be structurally valid while replayed history and the chosen item document describe different effective state. In that case inspect both authors' events before reconciliation, then run the audited repair:

pm history <item-id> --verify --strict-exit
pm history-repair <item-id> --dry-run
pm history-repair <item-id>
pm merge reconcile --dry-run --json

history-repair records the reconciliation patch and classifies its changed fields against the final item. Append-only collection unions and deterministic reordering are reported as preserved context without a data-loss warning. For native comments, docs and tests, duplicate copies of the same identified record and changes between the known local_mutation/merge_union display markers are also reported as preserved context. Author, creation time, origin, payload and unknown-field changes remain significant. This diagnosis does not authorize linked commands or relax exact receipt hashes. Fields whose replayed values are actually removed or replaced remain loud with discarded event authors/operations and recovery guidance. Re-apply any intended losing mutation as a normal pm update so it remains explicit and auditable.

History events now declare an item-hash epoch. Epochs are immutable writer contracts, not aliases for the current item serializer: epoch 1 sorts linked tests; epoch 2 preserves their insertion order and has both an earlier field-frozen form and a later expanded form because the writer surface grew before the marker advanced; epoch 3 is the current form. Verification accepts both recorded epoch-2 forms without allowing one entry to mix them, and repair preserves the form evidenced by each event. Unversioned streams are verified against the supported legacy canonicalizations. Current-document comparison selects the resolved epoch candidate that matches the chain head. A union merge may consume suffixes written by both epoch-2 forms, but its synthesized output uses one form for the complete re-anchored stream so every stored after_hash is exactly the next stored before_hash. An unknown explicit epoch is reported as unsupported_item_hash_version and repair refuses to guess. This keeps version incompatibility distinct from item corruption and is tracked by pm-2htk4p and pm-2qahia.

New history events also carry record_hash_version and record_hash. Unlike the item anchors, the record hash covers the complete immutable event: author and agent provenance, timestamp, operation, message, context, patch, item-hash epoch, and before/after anchors. A record that carries only one envelope field, uses an unsupported record epoch, or changes after sealing fails verification. Entries created before this envelope remain readable as explicit item_state_only coverage; they are not presented as record-authenticated.

Every maintenance rewrite verifies a present record hash before changing the stream and reseals the output. When anchors or patch representation change, the entry's append-only reanchor_evidence retains the prior anchors, item epoch, patch digest, and prior record envelope. Lenient repair additionally retains the complete replaced patch operations. verifyHistoryRewriteEvidence() reconstructs every available prior envelope and rejects a record that was modified and merely resealed after maintenance. Redaction never copies sensitive patch values into new evidence: it keeps the digest and drops a retained patch if the patch itself matched a redaction rule. Compaction baselines retain the pruned entry count and ordered stream digest plus an explicit individual_pruned_entries_require_pre_compaction_stream limitation. A holder of the pre-compaction stream can therefore validate the checkpoint, while the post-compaction stream does not falsely claim that it can reconstruct content that was intentionally pruned.

Delete versus modify policy

A delete on one branch and an edit on another is not safely resolvable by a generic file driver. The merged workspace must not silently resurrect the item. storage_integrity reports the live document plus delete-terminated history as a hard finding. The coordinator chooses one policy explicitly:

  • Honor deletion: remove the live item document, keep its append-only history, and commit the resolution.
  • Honor modification: restore/recreate through pm so the history contains an explicit post-delete operation and rationale.

Never remove conflict markers manually while leaving the authoritative item and history semantically inconsistent.

Runtime receipts and retention

transactions/ and checkpoints/ are per-branch crash-recovery state, not shared project context. pm init places both below the resolved tracker root in the managed .gitignore block, including custom --pm-path roots.

Each tracker sharing a repository retains its own cache exclusions and merge patterns in either initialization order. Tracker names containing Git wildcard characters are escaped as literal paths, while the generated item/history globs remain active. Unrelated user rules and curated evaluation files are preserved. These contracts are tracked by pm-nl60tbxzkjwp and pm-47wuv8awpqvj.

Ignore rules do not remove files that were already committed. pm health (integrity) and pm validate (storage_integrity) therefore scan Git's index for tracked files below runtime/, search/, locks/, transactions/, and checkpoints/. A finding includes repository-relative paths plus an exact git rm --cached -r -- ... command. That command removes only the indexed copies; local caches and recovery receipts remain on disk under the managed ignore fence. The intentional search/eval-queries.json relevance-evaluation corpus remains tracked and is excluded from this cache diagnostic.

Terminal SDK transaction journals use the same checkpoints.retention_days policy as rollback checkpoints. The default GC sweep includes both receipt classes:

pm gc --dry-run
pm gc --scope transactions --dry-run
pm gc --scope transactions

Only aged committed or compensated journals are removed. applying, compensating, unreadable, and unparseable journals are always retained so cleanup cannot destroy live recovery state.

Temporary-clone acceptance test

Before releasing merge-contract changes, validate the packed package in a temporary Git repository: initialize pm, install the merge contract, create one base item, branch twice, append disjoint metadata/history on both branches, merge, and run the strict validation commands above. Include a same-key conflict case and prove Git leaves it unresolved while the output remains parseable.

The packed first-run matrix exercises the installed README workflow, a real comment/history merge, and MCP on supported platforms.

From docs/MERGE_SAFETY.md in pm 2026.11.13. View on GitHub