Skip to content

Lesson 06 — Why database transactions cannot control the outside world ​

Outcome ​

Add the Operation concept and use a fake external effect to understand durable intent.

Why this comes now ​

The next milestones touch Git and processes. Before that, learn the failure mode that causes many orchestrators to get stuck after crashes.

Understand ​

SQLite can atomically change SQLite. It cannot atomically start Claude, create a directory, or run Git. If you mutate DB state and then perform I/O, a crash between them creates disagreement. If you perform I/O first and DB fails, you get the opposite disagreement.

Forge records an Operation in the same transaction as the domain intent, commits it, then a worker performs the side effect. “Command accepted” means intent is durable—not that the outside world finished.

Build the real project ​

  1. Add Operation types: kind, aggregate target, idempotency key, status, attempt, timestamps, structured payload/result/error.
  2. Add operations table/migration/repository.
  3. Create a simple application command that updates a harmless domain/test record and inserts a fake WRITE_MARKER Operation transactionally.
  4. Prove that the Operation exists even before a worker runs it.
  5. Document which future actions will become Operations.

Completion gate ​

A test commits domain change + Operation atomically. Inject a transaction failure and prove neither commits. Explain in a test name/comment why the external effect is not run inside the transaction.

Pitfalls to avoid ​

Do not build Kafka-style infrastructure. Do not turn every database update into an Operation. Operations exist for external side effects/recovery boundaries.

References ​

OPERATIONS_AND_RECOVERY.md, T3 Code architecture: https://github.com/pingdotgg/t3code/blob/main/docs/internals/overview.md

Checkpoint ​

Write one short Learning Log note describing a crash boundary you now understand better.

Forge is local-first. The docs are part of the product engineering system.