Cooperative Discipline

If you have chosen multi-stream usage, this page is the modelling discipline that keeps you on the safe side of the diagnostic — in Multi-stream with local invariants, where the Dual-Layer Contract stays reference material.

Outside a narrow envelope, concurrent writes lose data silently. The engine has no notion of conflict: when two streams touch the same granule it collapses them by structural rule (last-writer-wins) and signals nothing — the dropped write is gone, with no error and no notification.

That envelope is disjoint writes: concurrent authors operating on structurally disjoint targets, where the fold has nothing to pick between and every submitted intent survives — for as long as the targets stay disjoint, which is on you. Reaching it is a modelling task, not a runtime one — shape the DSM model so the engine never has anything semantically meaningful to choose. That shaping is scope decomposition.

This is the path for multi-stream usage, not a back-stop when the Dual-Layer Contract bites. The import outcomes are what remains if the discipline fails on a specific path.

Important

This is a discipline you engineer, not a feature you enable. There is no general recipe: the shape of the disjointness is specific to your domain, and no pattern here has been validated at scale as a general solution. It is decided in the .dsm before any code is written — and it does not cover strong invariants at all, whatever the decomposition (see What scope decomposition does not solve).

Where the discipline pays off

Before the levers, the diagnostic — because the envelope is not equally reachable in every domain, and both extremes argue against bothering.

Where the domain already carries a real ownership structure — each user owns a subgraph, each workstation an asset, each site an attachment — decomposition costs nothing: it is the modelling you would have done without Commit. But notice what follows. If writes can be routed so they never meet, you did not need the fold in the first place; you were running one stream per scope, and the merge you avoided was never load-bearing.

Where two people genuinely have to edit the same thing, decomposition is not hard but impossible: the shared granule is the work. No .dsm makes two authors of one value disjoint, and a supervisor is required (see When a supervisor is required).

So the discipline is free exactly where it is unnecessary, and unavailable exactly where it is needed. What remains between the two is the band it was made for: work that is mostly disjoint with occasional overlap — several authors on one model, each with a scope they own in practice, colliding rarely and at identifiable places. There, decomposition does the bulk of the work by making collisions rare, and Supervised Reconciliation handles the residue at a cost that stays proportional to how rare they are.

That band is real, and it is narrow. If your application does not sit in it, the discipline on this page will not put it there — the model is where that is decided, and the decision is made once.

Not a Commit quirk

The limit is structural, not a peculiarity of this engine. Any system that merges automatically without supervision — no human at the merge, no semantic rule allowed to refuse — faces the same dual-layer contract.

  • CRDTs converge with semantic validity only where semantic equals structural (counters, grow-only sets); rich-document CRDTs (Automerge, Yjs) keep characters from duplicating or vanishing but cannot guarantee the result means what either author intended.

  • Operational Transformation (Google-Docs-style) needs a central server to arbitrate operation order — remove it and OT collapses back to mechanical reduction; line-based auto-merge shows the same “successful merge, broken build” pattern on textually-disjoint-but-incompatible edits.

No unsupervised system delivers semantic validity — that is the limit the two bullets illustrate, and it is not specific to this engine. Structurally, however, unsupervised systems are not equal: a CRDT converges — the same updates yield the same state whatever order they arrive in — and mechanical reduction does not, since commitMerge is non-commutative. The discipline below buys something narrower than convergence: it keeps the engine from ever having anything semantically meaningful to pick between, so the order it picks in stops mattering to you.

Principle: scope ownership

Disjointness is what makes the union safe — but survival is not yet trust. It earns trust only when disjointness matches ownership — when each writer’s whole intent is the scope they touch. Then the union is every author’s owned intent and nothing is invented. Let a scope be a fragment of a larger intent and disjointness still holds, yet the union answers to no one (see Re-entering the graph).

The shape of that disjointness is application-specific. This page does not prescribe a recipe — what works in one domain may not transfer to another, and no pattern has been validated at scale as a general solution.

Modelling levers

Disjointness is engineered in the .dsm, not at runtime. The DSM language provides the levers — none of them new:

  • Multiple attachments per concept rather than one monolithic struct. Concurrent writers touching different attachments do not collide. See Attachments.

  • set / map / xarray containers for concurrently-edited collections — commutative where used accretively or on disjoint granules: grow-only set union and writes to non-overlapping keys / paths / positions. xarray insert is accretive but not commutative: no concurrent insert is lost, yet the relative order of inserts from different streams is fixed by linearisation order, not by their positions — rely on the element set, not on its order. Concurrent writes to the same element collapse to last-writer-wins, silently dropping one value. Prefer xarray over vector when concurrent inserts must not be lost — vector’s integer indices collide under concurrency; see Vector vs XArray.

  • References that tolerate breakage — accept that a key<X> may outlive its target. This is a whole-application commitment, not just a DSM choice: the app must load robustly, surface the integrity issue, and expose corrective actions to the user. See the ModelIntegrity pattern as an uncommon worked example.

These choices are made in the .dsm before any code is written — which is why the single-stream / multi-stream decision is architectural, not runtime.

What scope decomposition does not solve

Be honest about the limits of the discipline:

  • Strong invariants. Uniqueness across the whole model (no two assets share an SKU, no two users share an email) cannot be enforced by partitioning. Two authors writing into disjoint documents can still both claim the same global identifier. This requires a supervisor — typically a service that mediates allocation. See local vs strong invariants for the canonical definition.

  • Cross-author semantic dependencies. If author B’s work depends on the meaning of what author A produced (and not just its presence), they are not really cooperating on disjoint scope; they are sequential, and need a coordination protocol.

  • Aggregations and analytics. Sums, joins, derived views over multiple authors’ contributions still face the contract at read time. The import outcomes still apply to the derived state, even if every contributor’s individual write was clean.

When a supervisor is required

When the scope cannot be cleanly decomposed — when authors genuinely need to co-edit the same field, or when strong invariants matter — the right answer is not a better reduction algorithm. It is an application-level supervisor: a review UI that surfaces clashes for human arbitration, a semantic gate that refuses commits, a merge UX that asks an operator to pick. That is the supervised regime — the Collaboration row of the summary below.

The arbitration is yours. The engine decides nothing, and the import outcomes it provides are the back-stop at read time, beneath whatever discipline you choose. Supervised Reconciliation documents the supervisor dsviper ships — headless, additive over the public API: it identifies the loci where an intent was lost and applies the decisions you hand it, as CommitMergeResolution decrees. Which intent survives stays your call.

Summary

Regime

How divergence resolves

Where it lives

Deterministic reduction

Structural linearisation — no notion of conflict

The engine — all it can do unsupervised, and less than convergence

Cooperation

Disjointness you engineer and must keep — nothing to pick between

This page — application discipline

Collaboration

Supervisor arbitrates (human / rule)

Identification and application ship; the deciding is yours

The dual-layer contract is described in all three regimes; the discipline you adopt determines whether it stays reference material or becomes load-bearing. Cooperation keeps it on the shelf.

See Also