ADR 0015: Three embedded project-write modes
Status: Accepted for v0.5.0
Context
Section titled “Context”GraphForge is an embedded engine, but one project may be opened by multiple
threads, processes, or agent clients. The durable generation protocol already
provides immutable snapshots, transaction-addressed attempts, and an atomic
CURRENT boundary. Callers need explicit coordination choices without making
the storage engine a distributed database or adding a network server to core.
Decision
Section titled “Decision”GraphForgeOptions selects exactly one ProjectWriteMode:
SingleWriteris the compatibility default. A competing cross-process writer receivesGF_WRITER_BUSYbefore staging.QueuedWriteradmits mutations through a bounded FIFO queue owned by one facade. Queue capacity is explicit. Snapshot reads bypass the admission queue, and cancellation removes only a request that has not started.OptimisticMultiWriterallows different composite transaction identities to stage in parallel. Committers wait for the short writer-lock promotion boundary, compare their pinned parent with durableCURRENT, and either publish or rebase within the configured finite retry budget.
The optimistic conflict matrix is closed:
| Concurrent work | Outcome |
|---|---|
| Distinct graph creates | Rebase and merge |
| Distinct immutable-ledger identities | Rebase and merge |
| Different properties on one object | Rebase and merge |
| Same property or removed target | GF_WRITE_CONFLICT |
| Delete or administrative work | GF_WRITE_CONFLICT |
| Retry budget consumed | GF_REBASE_EXHAUSTED |
| Same operation and same content | Exact idempotent replay |
| Same operation and changed content | GF_IDEMPOTENCY_CONFLICT |
Only publish_composite_transaction has optimistic replay semantics in
v0.5.0. Arbitrary write Cypher, bulk construction, index administration, and
other mutation APIs remain serialized. After any attempted publication, the
facade workspace, runtime catalog, and generation UUID reconcile to durable
CURRENT; a committed generation is never reported as rolled back.
The modes are local embedded capabilities, not transport protocols. MCP and HTTP remain outside core. An optional extension can expose one authenticated authority over these APIs without changing the on-disk protocol.
Consequences
Section titled “Consequences”Applications keep a zero-configuration safe default and may opt into bounded backpressure or compatible multi-writer throughput. Queue memory cannot grow without limit, retries cannot continue without limit, and conflict outcomes are machine-readable. Remote fleets require an extension or application-owned authority rather than a server dependency in the engine.