KVS concurrent-merge & mergeable refs (conflict-as-data)

The differentiator: a fleet of AI agents pushing to the same branch at high frequency must all land without non-ff rejection and without silent overwrite. This spec is the normative contract for ref advancement, server-side merge, and the conflict-as-data outcome. It is the research-y core; the existing kvs client merge engine (KVS#179/#202) is the head-start.

R1 — Objects never conflict (CAS, content-addressed)

Writing a git object is never blocked or rejected: identical content → identical hash (idempotent); different content → different hash (both stored). Object upload is concurrency-free by construction (kdb-obj CAS, kdb-RFC-006). The only contention point in the system is the mutable ref.

R2 — Ref advance is non-blocking + auto-merging (no locks)

There is no per-repo and no per-ref lock. Concurrent pushes to the same branch do not serialize behind a lock and do not get a non-ff rejection. Each push attaches its commit(s) to the branch DAG and triggers a server-side merge (R3) that advances the branch tip. Fast-forward (incoming is a descendant of tip) skips merge and advances directly (R7).

R3 — Merge mechanism (Driver-selected, RFC-006 §5.2)

The server computes a three-way merge merge(base, tip, incoming):

  • Per-file merge driver selected via .gitattributes (the Driver mechanism,

    RFC-006 §5.2 — zero git-core fork). Default driver = git textual three-way.

  • AST/structure-aware drivers per language where available (the kvs engine,

    KVS#179) — disjoint structural edits to the same file auto-merge where textual three-way would conflict.

  • Drivers are deterministic + pure (same inputs → same merged tree/conflict

    set) so the optimistic retry (R5) converges and replays are stable.

R4 — Conflict = first-class committable object (NEVER reject, NEVER overwrite)

When a driver cannot fully resolve, the merge does not reject the push and does not silently pick a side. It produces a conflict object (jj model, KVS#179): the merge commit records the unresolved regions as structured data (both sides + base, per region), the branch tip advances to that commit, and the ref enters an explicit needs-resolution state surfaced via APIUIMCP. Downstream reads see a well-formed tree (conflict regions rendered deterministically) tagged has_conflicts=true; resolution is a normal follow-up commit that clears the markers. Silent index/tree corruption is forbidden (this is the exact failure this spec exists to prevent).

R5 — Exactly-one-winner serialization (optimistic, bounded retry)

The durable ref store provides a single-statement CAS linearization point (refs→kdb, FLOW-148). The advance loop:

loop (bounded N):
    base ← read branch tip                    # linearization read
    merged ← merge(base, incoming)            # R3, pure
    if CAS(branch tip: base → merged): done   # exactly-one-winner
    else continue                             # another writer won the race; re-read + re-merge

Because objects are CAS (R1) and merge is pure (R3), retry is idempotent and converges (each iteration starts from a newer tip). The retry bound exists only as a livelock backstop; exceeding it is an operational alarm, not a client error. No lock is held across the merge (kdb#769#790#791/#792 off-lock pipelining is the data-plane enabler).

Throughput realization (KVS-233/234, default): N-way optimistic retry is correct but O(N²) under high single-branch contention (every loser re-merges). The host therefore serializes one branch's advances through a single per-branch merge worker that is the branch's sole writer → each incoming is merged exactly once (O(N), no retry storm), while distinct branches and repos stay fully parallel (the fleet is never globally serialized). This is the optimistic model collapsed to its one-winner outcome without the wasted re-merges — not a held lock across the merge. (Impl note: an out-of-process merge worker must import the push's quarantined objects into the shared store before merging — KVS-234.)

R6 — Provenance on every merge (auditability for the AI fleet)

Every server-side merge records which principal/agent contributed which side (KVS#202 provenance trailers + git notes) — human or agent (namespace-tree R-AI). A conflict object records the provenance of each conflicting region's sides. This makes "which agent's concurrent edit caused this conflict" answerable (D8 observability), essential when most writers are agents.

R7 — Fast-forward & force semantics

  • Fast-forward stays fast-forward: if incoming strictly descends tip, advance

    with no merge (cheapest path; the common single-writer case).

  • Force-advance (replace tip with a non-descendant, discarding commits) is an

    explicit, permission-gated, audited operation — never the default of a normal push, and never how a concurrent race is resolved.

R8 — Submit protocol: the refs/for/<branch> pseudo-ref (added 2026-06-10, KVS-232)

git's receive-pack applies the fast-forward check to real branch refs (`refs/heads