The promise and the engine
Why ThoughtStore should define what persistence means while Jazz remains the first system that makes those promises real.
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.
Ask to append, read, lease, flush, and rebuild.
Translates each promise into Jazz queries and writes.
Persistent SQLite locally; sync may be added deliberately later.
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.
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.
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.
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.
Only the latest declaration remains easy to resolve.
Each run resolves the exact immutable revision it used.
What this decision changes
- 01Write the invariants beside the interface.
Define exact observable behavior for events, revisions, cursors, runs, durability, ordering, and replay.
- 02Build one conformance suite.
Run it against the Jazz adapter locally. Add remote and multi-writer cases before claiming sync safety.
- 03Keep immutable evidence separate from mutable operations.
Events, document versions, traces, and config revisions are history. Cursors, leases, active bindings, and projections are current state.
- 04Let 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.