Skip to content

remove per-write doltCommit from bun adapter#1

Open
timsehn wants to merge 2 commits into
doltlitefrom
fix/adapter-strip-auto-dolt-commit
Open

remove per-write doltCommit from bun adapter#1
timsehn wants to merge 2 commits into
doltlitefrom
fix/adapter-strip-auto-dolt-commit

Conversation

@timsehn
Copy link
Copy Markdown

@timsehn timsehn commented May 11, 2026

Summary

The DoltliteClientAdapter in db.doltlite.bun.ts used to fire dolt_commit('-A','-m',…) after every autocommit write to a tracked table, and again after every wrapped transaction. This is the suspected cause of opencode's read-after-write failure on session creation (lines 305–308 of the captured SQL log on doltlite 0.10.0): INSERT INTO session returns changes=1, four immediately subsequent SELECT WHERE id=? return rows=0.

A secondary problem: the inTx flag was only set inside adapter.transaction(fn). Code that called db.exec("BEGIN TRANSACTION") directly — json-migration.ts does this — bypassed the gate, so each tracked-table insert inside that raw transaction called doltCommit while the SQL transaction was still open.

Both go away if the adapter stops trying to mirror SQL transactions into dolt history. dolt_commit is now strictly explicit; callers can snapshot at meaningful boundaries (shutdown, idle ticks, user action) instead of paying it on every write.

What's left in the adapter:

  • client.transaction(fn).immediate() — drizzle-bun-sqlite needs bun:sqlite's transaction shape
  • stmt.values() — drizzle-bun-sqlite reads rows-as-arrays through this

That's the entire surface drizzle-orm/bun-sqlite actually uses. 140 lines down to ~70.

Follow-up not in this PR

There is no automatic dolt snapshot anywhere now. A periodic + on-shutdown call to Database.Client().$client.doltCommit(…) (or equivalent hook in opencode's lifecycle) would restore that, with the right cadence.

Test plan

New packages/opencode/test/storage/db-adapter.test.ts pins the read-after-write contract through the same Drizzle entry points opencode uses:

  • autocommit INSERTSELECT sees the row
  • BEGIN IMMEDIATE / INSERT / COMMIT → 4 retried SELECTs (the exact failing pattern from the log) all return rows=1
  • BEGIN DEFERRED variant — same
  • ROLLBACK throws and discards the insert
  • 5 sequential BEGIN IMMEDIATE transactions are all visible afterwards

Existing coverage:

  • 5/5 new adapter tests pass
  • 40/41 storage tests pass (the one fail — db.test.ts:12, expects opencode-local.db vs current .ddb — is unrelated and pre-existed this branch)
  • 43/43 SyncEvent + control-plane tests pass — these exercise the actual Database.transaction({behavior:"immediate"}) → projector → INSERT → COMMIT → SELECT path
  • 2388/2402 full opencode suite passes

🤖 Generated with Claude Code

Tim and others added 2 commits May 11, 2026 11:42
The DoltliteClientAdapter used to fire dolt_commit('-A','-m',...) after
every autocommit write to a tracked table, and again after every wrapped
transaction. This was the suspected cause of opencode's read-after-write
failure on session creation (lines 305-308 of the captured SQL log on
0.10.0): INSERT INTO session returns changes=1, four immediately
subsequent SELECT WHERE id=? return rows=0.

In addition, the inTx flag was only set by adapter.transaction(fn) —
code that called db.exec("BEGIN") directly (json-migration.ts) would
bypass the gate, so each tracked-table insert inside that raw
transaction would call doltCommit while the SQL transaction was still
open.

Both problems go away if the adapter stops trying to mirror SQL
transactions into dolt history. dolt_commit is now strictly explicit;
callers can snapshot at meaningful boundaries (shutdown, idle ticks,
user action) instead of paying it on every write.

The adapter is now a thin polyfill that adds the two methods
drizzle-orm/bun-sqlite expects but @dolthub/doltlite doesn't expose:
client.transaction(fn).immediate() and stmt.values().

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The db query / db migrate / interactive shell paths all opened the
database via bun:sqlite directly, which doesn't recognize doltlite's
content-addressed file format — every invocation failed with
"file is not a database".

Switch:
- db [query]: use @dolthub/doltlite's DatabaseSync (read-only) and
  print rows in either tsv or json format
- db (no args): spawn the doltlite binary (same convention sqlite3 had,
  on $PATH)
- db migrate: open via the bun adapter from db.doltlite.bun.ts so the
  drizzle bun-sqlite migrator gets a compatible client

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant