Releases: BlueprintLabIO/tidebase
v0.5.0
Tidebase v0.5.0
The "production posture" release: authoritative lifecycle, queues, schedules, cancellation, real migrations, opt-in auth, and a production-grade Python SDK. Tidebase still never executes your code — v0.5 adds the power to decide when it runs.
Authoritative lifecycle & cancellation
- Single-source run lifecycle:
pending/queued → running → completed/failed/cancelled, withfailure_class(e.g.max_retries) recorded on terminal failures. POST /runs/:id/cancel— durable, idempotent, one-way. In-flight workers observe cancellation at step/gate boundaries (RunCancelledError/RunCancelled);complete/failafter cancel are refused.- Run deadlines (
deadlineMs): overdue runs are cancelled automatically with reasondeadline.
Queues (a job IS a run)
POST /queues/:queue/enqueue/tide.enqueue()— dedupe keys (exactly one active run per key, enforced by a partial unique index), delayed jobs, priority,maxAttemptswith exponential backoff.- Pull dispatch:
POST /queues/claim(SKIP LOCKED, per-queue concurrency caps and rate limits) +tide.work()worker loops in both SDKs. - Push dispatch: configure a queue
invokeUrland Tidebase delivers signedrun.invokewebhooks to your app.
Cron schedules
PUT /schedules/:namewith 5-field UTC cron (dependency-free parser). Fires enqueue with a fire-time dedupe key, making double-fires structurally impossible across replicas.
Reconciler
One advisory-locked loop: requeues/fails expired-lease runs, dispatches recovery webhooks for stalled runs, cancels past-deadline runs, enqueues due schedules, dispatches push queues. Multi-replica safe.
Migrations
Versioned runner (schema_migrations, advisory-locked, applied in order). pnpm migrate standalone; TIDEBASE_AUTO_MIGRATE=0 makes boot fail fast on pending migrations for expand/contract deploy discipline. The v0.5 migration is expand-only.
Auth (from the v0.4 line, included here)
Opt-in shared-token auth via TIDEBASE_API_KEY — timing-safe bearer on every surface except /health, ?token= on the SSE endpoint only, Studio support via VITE_TIDEBASE_API_KEY.
Python SDK
sdk-python/ (PyPI: tidebase, zero dependencies): full run/step/state/gate/fanout/usage parity, queues/schedules/cancel, @tide.workflow decorators, tide.work() loops, and tidebase.aio.AsyncTidebase — async def workflows and steps with the same checkpoint protocol.
Studio
Queues view (depth, caps, dispatch mode), schedules view, and a Cancel button on active runs.
Tests
84 TypeScript tests (76 server + 8 SDK) and 9 Python integration tests, all invariant-driven against real Postgres, including concurrency probes for dedupe, claims, caps, cron double-fire, and cancellation. New: docs/production.md — the operational model, replay contract, and failure modes in one page.
Tidebase v0.3.0
Tidebase v0.3.0
v0.3.0 hardens the guarantees Tidebase already claimed. It adds the first test suite — 57 invariant tests run against real Postgres in CI — and fixes the concurrency bugs that suite uncovered.
Highlights
- Added an invariant-driven test suite covering checkpoint replay, lease fencing, event-log integrity, gate resolution, fanout idempotence, recovery webhooks, and channel deliveries (
docs/testing.md). - Added GitHub Actions CI:
pnpm verify(typecheck, build, full test suite) on every push and pull request. - Fixed an event-sequence race: concurrent writers to the same run could collide on
unique(run_id, seq)and fail with a 500. Event appends are now serialized per run with an advisory lock. - Fixed a step-lease race: two workers beginning the same step for the first time concurrently could both be granted
execute, with the second silently stealing the first worker's lease. First-begins are now serialized per(run, step); the same fix covers concurrent gate begins. - Fixed SDK step retries: a retryable failure releases the lease server-side, but the SDK retried with the dead lease and could never commit the eventual success. Each retry now re-begins the step to acquire a fresh lease.
- Channel webhook deliveries are now dispatched after the transaction commits. Previously the HTTP call to your endpoint ran inside the database transaction, so a slow or hung channel endpoint could block every other writer to the same run.
- Aligned the SDK's default resume classification with the server: a failing step with no declared side effects (or read-only ones) is now classified
safe_replayinstead offail_hard. External writes without an idempotency key still park inmanual_review. - Request validation errors now return
400with the Zod issues instead of a bare500.
Why It Matters
Tidebase's job is to be the layer you trust when worker processes crash, retry, and race each other. That trust should rest on executable proof, not on careful reading of the SQL. The test suite encodes each product guarantee — "completed steps never re-execute", "the event log has no gaps", "a gate resolves exactly once" — as a test against a real database, with concurrency probes for the guarantees that only matter under contention.
Three of those probes failed on first run. All three bugs are fixed in this release, and the tests that caught them now run in CI on every change.
Behavior Changes
- Channel deliveries are recorded inside the transaction (as
pending) but delivered after commit. Delivery status still updates todeliveredorfailedbefore the triggering API call returns. - A failing SDK step with no declared side effects reports
safe_replayinstead offail_hard, matching the server's own classification. Declarereplay: 'never'if a step must not be replayed. - Invalid request bodies return
400with structured issues instead of500.
Compatibility Notes
No storage changes. No API shape changes. Existing workflows continue to work; SDK retries now actually commit their eventual success, which previously failed with a 409 after any retry.
Tidebase v0.2.0
Tidebase v0.2.0
v0.2.0 adds the first durable history primitives on top of Tidebase's existing checkpoint model.
Highlights
- Added versioned state streams.
- Added state versions for every
run.state.set()andrun.state.patch(). - Added
run.state.save(label)for labeled milestone versions. - Added snapshot convenience APIs backed by labeled state versions.
- Added child-run edges for parent/child run trees.
- Added SDK helpers for
run.child()andrun.fanout(). - Added checkpointed fanout joins via
join:<name>steps.
Why It Matters
Tidebase now has a coherent foundation for time travel and forking without turning snapshots into a separate state concept:
current state = latest version in a stream
snapshot = labeled state version
time travel = read an older version
fork = start new state/run context from an older version
restore = append a new version based on an older version
Subagent workflows can now be represented as observable run trees. A parent run can create child runs idempotently, wait for them, and checkpoint the joined result so parent resume does not duplicate completed subagent work.
New SDK Shape
await run.state.patch({ progress: 0.5 })
await run.state.save('before-approval', {
reason: 'user is about to approve sending'
})
await run.snapshots.create('draft-v1', {
target: { type: 'report', id: reportId },
state: draft,
reason: 'first complete draft'
})const results = await run.fanout('research-options', [
{
name: 'flights',
workflow: researchFlights,
input: { destination }
},
{
name: 'hotels',
workflow: researchHotels,
input: { destination }
}
])Storage Changes
New tables:
state_streamsstate_versionsrun_edges
The existing run_state table remains as the latest-state cache for backwards compatibility.
Compatibility Notes
Existing run.state.set() and run.state.patch() calls continue to work. They now also append state versions automatically.
The snapshot APIs are convenience APIs over labeled state versions. Tidebase does not own app-specific restore behavior; your app decides what restore or fork means for its own state targets.