Artifacts / Architecture 004

The promise and the engine

Why ThoughtStore should define what persistence means while Jazz remains the first system that makes those promises real.

thought streamPrecommit decisionJuly 2026

The short answer

ThoughtStore is a set of promises. Jazz is the engine we are using to fulfill them.

The application needs facts such as “this observation is stored exactly once,” “accepted evidence cannot be rewritten,” and “a completed write survives restart.” Those are thought stream rules. They should not change accidentally when Jazz changes its API, driver, permissions, or sync behavior.

This does not add another process, database, or network hop. In the running program, JazzThoughtStore is still the concrete object doing the work. The contract is the line above it that says which outcomes count as correct.

THOUGHT STREAM
connectorsworkersinspector

Ask to append, read, lease, flush, and rebuild.

ThoughtStore contractobservable promises + shared tests
ADAPTERJazzThoughtStore

Translates each promise into Jazz queries and writes.

ENGINEJazz relational tables

Persistent SQLite locally; sync may be added deliberately later.

One process, one concrete store. The thin line is a behavioral boundary, not a new runtime layer.

An interface names operations. A contract defines outcomes.

The TypeScript interface already exists. It says that every store must offer methods such as appendEvent, listEvents,flush, and close. That is useful, but method names alone do not tell us what happens under pressure.

ThoughtStore contract=TypeScript interface+written invariants+conformance tests

The written invariant might say that (source, idempotencyKey) is unique. The conformance test tries to break that invariant. The Jazz adapter passes only when the observed result is correct.

The current race makes the distinction concrete

Today, the Jazz adapter checks whether an event exists and then inserts it. The existing test proves that two sequential calls deduplicate. Two concurrent writers are a different case.

Writer Aquery: nothing foundinsert event α
Writer Bquery: nothing foundinsert event β
BACKEND RESULTTwo rows may exist.
CONTRACT REQUIRESOne observation becomes one event.
The repair may be entirely Jazz-specific: a uniqueness constraint, serialized append path, transaction, or another atomic primitive. Callers should depend on the one-event outcome, not on which repair Jazz needs.

One suite turns the promise into evidence

A conformance suite runs the same behavioral tests against a store factory. For now that factory always creates JazzThoughtStore. A future backend is possible, but portability is not the reason to do this. The reason is to know whether the current backend actually satisfies thought stream.

PromiseBreak-it testRequired resultToday
Repeat one observationAppend the same source and idempotency key twice.One stored eventProven sequentially
Race one observationMake two writers append the same observation at the same time.One stored eventNot yet proven
Keep evidence immutableAttempt to update or delete an accepted event.Write rejectedNot yet enforced
Survive restartAppend, close the store, reopen it, and read.Same event returnsProven locally
Rebuild a viewDiscard a projection and fold the event log again.Same projection hashProven locally
Synchronize safelyReconnect concurrent writers after conflicting offline work.No lost or duplicate evidenceNot yet proven

The same rule protects historical meaning

The current agents table is operational state. Saving version 2 under the same agent key updates the row that held version 1. An old run can still say agentVersion: 1, but the full version-1 declaration may no longer exist.

CURRENT UPSERT
10:00document-structureversion 1
14:00document-structureversion 2

Only the latest declaration remains easy to resolve.

CONTRACTUAL HISTORY
10:00document-structure@1hash 7e4…
14:00document-structure@2hash 19b…

Each run resolves the exact immutable revision it used.

“What produced this output?” must remain answerable after configuration changes. The current-agent row can stay as a mutable projection beside the revision history.

What this decision changes

  1. 01
    Write the invariants beside the interface.

    Define exact observable behavior for events, revisions, cursors, runs, durability, ordering, and replay.

  2. 02
    Build one conformance suite.

    Run it against the Jazz adapter locally. Add remote and multi-writer cases before claiming sync safety.

  3. 03
    Keep immutable evidence separate from mutable operations.

    Events, document versions, traces, and config revisions are history. Cursors, leases, active bindings, and projections are current state.

  4. 04
    Let Jazz solve Jazz problems.

    Atomicity, permissions, transactions, and sync remain adapter work. Connectors and agents only see the promised outcomes.

What this does not mean

No second service
The adapter runs in the same thought stream process.
No database rewrite
Jazz remains the only implemented backend.
No lowest-common-denominator API
The contract should express thought stream’s actual needs, even when they require Jazz-specific work.
No speculative portability project
Another adapter is built only if a real need appears.

The useful boundary is simple: thought stream owns the meaning of a successful write; Jazz owns how that write becomes durable.

Appearance