Release v0.71.0 — SQL Server storage parity
Date: 2026-04-16
Tag: v0.71.0
Summary
SQL Server reaches full feature parity with Postgres across all runtime paths. Multi-tenant mode, scheduling, DLQs, render-usage analytics, and tenant CRUD now work identically on both database backends. File mode remains single-tenant and non-scheduling by construction.
This release also closes two C.0b multi-tenant operational debt items (audit purge cross-tenant iteration, OIDC archived-tenant guard) and fixes a config validation nesting bug that silently accepted SCHEDULE_ENABLED=true in filesystem asset mode.
What shipped
Release A — SQL Server single-tenant feature parity
- 4 T-SQL migrations (007–010):
schedules,schedule_executions,schedule_delivery_dlq,batch_webhook_dlq,render_usagetables with full index parity, UTC defaults, and tenant_id columns from inception. - 4 new store implementations:
SqlServerScheduleStore,SqlServerScheduleExecutionStore,SqlServerScheduleDeliveryDlqStore,SqlServerBatchWebhookDlqStore,SqlServerRenderUsageStore. claimPending()uses CTE-based atomic UPDATE withREADPAST + UPDLOCK + ROWLOCKfor lock-contention-safe single-row claiming (pending->rendering).- Monday-aligned week bucketing for render-usage rollups (avoids
DATEDIFF(week, ...)Sunday anchor). SCHEDULE_ENABLED=trueconfig gate updated to accept bothpostgresandsqlserver.
Release B — SQL Server multi-tenant parity
SqlServerTenantStore(full ITenantStore port): slug validation, reserved IDs, name trimming, explicitupdated_aton every mutation, JSON metadata round-trip.- Real
TenantStatusCachefor SQL Server (queriestenants.archived_at), replacing the single-tenant no-op shim. - 16
assertActiveguard sites across 5 SQL Server stores, mirroring Postgres exactly. - Tenant-prefixed asset filenames for non-default tenants (mirrors Postgres
${tenantId}/${uuidSlug}rule). MULTI_TENANT_ENABLED=trueconfig gate lifted for SQL Server. Only file mode is rejected.TenantValidationErrorextracted to sharedstorage/tenant-errors.ts.
C.0b operational cleanup
- Audit purge cross-tenant: new
purgeAllOlderThan(before)method onIAuditEventStore(all 3 backends + instrumented wrapper). Scheduler now purges all tenants on the operational clock, not just'default'. - OIDC archived-tenant guard:
assertActive(OIDC_DEFAULT_TENANT, 'oidc_auto_provision')beforeaddUserin the OIDC auto-provision path. Surfaces archive drift at provision time instead of the next mint.
Config validation fix
SCHEDULE_ENABLED storage-mode gate, SCHEDULE_SMTP_* prerequisites, and SCHEDULE_S3_* credential checks were nested inside the if (ASSET_BINARY_STORE === 's3') branch in config.ts. In the default filesystem asset mode, SCHEDULE_ENABLED=true with STORAGE_MODE=file silently parsed and startup skipped the engine. Hoisted to top level with regression tests.
Docs + website sync
- Current operator docs (README, deployment-guide, api-guide, editor-guide, evaluator-guide, mvp-scope) updated to reflect SQL Server support.
- Super-admin example fixed:
tenantId: "*"->tenantId: null. - Website marketing copy (index.astro, features.astro) updated.
openapi.jsonand SDK typings regenerated.- Stale “Postgres-only” comments cleaned across codebase.
Breaking changes
None. All changes are additive or fix previously-broken validation paths.
Residual notes
- Audit purge default-tenant-only loop is now fixed (purges all tenants).
- Three lower-severity shared multi-tenant items remain parked (not SQL Server gaps): readiness probe tenant-table check, schedule-engine active metric default-only, startup SVG audit default-only. These affect both backends equally.
- Historical release notes (v0.65.0–v0.70.0) are left as snapshots and not updated to reflect current behavior.
- Existing single-tenant SQL Server deployments with flat asset filenames under the
defaulttenant are unaffected — the prefixing rule preservesdefaultflat. Retroactive prefixing is not applied.