v0.1.60
Highlights
PostgreSQL Support (new)
- Declarative planning for PostgreSQL targets — schema files diff against the live database via pg-sprite's diffplan, producing reviewable DDL plans for Postgres the same way MySQL plans work today. (#1008)
- PostgreSQL targets route to their own engine — plan and apply requests for Postgres databases dispatch to the Postgres engine end to end. (#1003)
- Fail-closed verdict gating for Postgres plans — a Postgres plan whose statements cannot be judged safe is blocked, never waved through. (#1004)
- PostgreSQL statement parser behind the DDL seam — Postgres DDL is parsed with libpg_query through the same
StatementParserseam MySQL uses. (#953) - Dialect-aware safety gates and reserved set — pull gates and the reserved-word set resolve per dialect instead of assuming MySQL. (#995)
- MySQL-only features are gated off for Postgres targets — configuration that only makes sense on MySQL is rejected up front for Postgres databases. (#993)
- PostgreSQL storage backend — storage-table schema definitions, an EnsureSchema bootstrapper that fails startup on missing columns, an advisory-lock implementation, and a rotation-surviving
postgresconnpool bring server storage to Postgres. (#936, #946, #992, #938, #976, #985) - Dialect-portable storage SQL — the SQL store's queries, timestamps, and upserts are portable across MySQL and PostgreSQL, pinned by a cross-dialect parity suite. (#1007, #1006, #951, #991, #935)
Embedding & Telemetry
- Telemetry survives host OTel SDK upgrades — the service-name resource override is schemaless, so embedders that upgrade their OpenTelemetry SDK independently no longer fail resource creation on a semantic-convention schema URL conflict. (#1014)
- Best-effort telemetry shutdown and OTLP gRPC support — shutdown flushes what it can instead of aborting on the first error, and OTLP export supports gRPC transport. (#944)
Webhook Durability
- Unlock commands dispatch through the durable inbox — an acknowledged unlock survives pod restarts and redeliveries. (#945)
- Missing webhook deliveries are synthesized for open PR heads — an open PR whose head never got a delivery row is backfilled instead of silently unprocessed. (#987)
- Rollback and rollback-confirm commands expose their retry disposition — transient failures retry; permanent ones surface. (#989, #1000)
- Durable webhook dispatch lifecycle metrics — dispatch outcomes are observable end to end. (#988)
GitHub PR Experience
- Spirit's post-copy phases show in progress displays — operators see catch-up, checksum, and post-checksum instead of a generic running state. (#958)
- Engine error text is sanitized before rendering into PR comments — raw driver/dial errors no longer leak infrastructure detail into public comments. (#891, #986)
- Waiting-for-cutover renders consistently across PR and CLI. (#982)
Operator CLI
- Operator-set volume shows in the status detail box. (#979)
- Command hints render with the wrapper's tool name — hints match how the CLI is actually invoked. (#983)
- Red is reserved for true failures in state colors. (#954)
Storage & Driver Correctness
- Credential reload runs outside the connector mutex — a slow secrets fetch can no longer stall connection acquisition. (#981)
- Pinned-connection discard escape narrowed and SQL rebinding happens exactly once — transaction and pinned-connection paths are safer under rotation. (#952, #950)
- Failed applies are no longer reapplied — a failed apply stays failed until an operator acts. (#955)
- Backend error-classification seam — storage errors classify portably across dialects. (#990)
Observability
- Operator driver pool occupancy gauge — visibility into how much drive capacity is in use. (#980)
- Unauthenticated and break-glass API writes are surfaced. (#956)
Internals
- Docs: apply lifecycle, terminal states, and recovery guidance. (#957)
- Spirit pin advanced to latest main. (#998)
- CI: e2e suites split into parallel jobs, external images pre-pulled, golangci config schema-verified, and stop/start resume deflaked. (#996, #997, #1005, #937)
Contributors
What's Changed
- feat(storage): add PostgreSQL storage-table schema definitions by @Kiran01bm in #936
- test(webhook): stop dual-write test racing the operator claim loop by @Kiran01bm in #937
- test(storage): add cross-dialect storage parity suite by @Kiran01bm in #935
- feat(namedlock): add PostgreSQL advisory-lock implementation by @Kiran01bm in #938
- feat(storage): add PostgreSQL EnsureSchema bootstrapper by @Kiran01bm in #946
- refactor(storage): depend on storage.Storage instead of *mysqlstore.Storage by @Kiran01bm in #947
- fix(github): sanitize engine error text rendered into PR comments by @Kiran01bm in #891
- feat(webhook): dispatch unlock commands through the durable inbox by @Kiran01bm in #945
- feat(storage): rebind transaction and pinned-connection SQL exactly once by @Kiran01bm in #950
- fix(observability): best-effort telemetry shutdown + OTLP gRPC support by @aparajon in #944
- fix(cli): reserve red for true failures in state colors by @aparajon in #954
- feat(observability): surface unauthenticated and break-glass API writes by @aparajon in #956
- refactor(storage): remove reapply of failed applies by @aparajon in #955
- docs: apply lifecycle, operation-layer refresh, and recovery guidance by @aparajon in #957
- feat(github): surface Spirit's post-copy phases in progress displays by @aparajon in #958
- feat(cli): show operator-set volume in the status detail box by @aparajon in #979
- feat(observability): gauge operator driver pool occupancy by @aparajon in #980
- fix(github): unify waiting-for-cutover rendering across PR and CLI by @aparajon in #982
- feat(storage): add postgresconn package with rotation-surviving pool by @Kiran01bm in #976
- fix(storage): narrow the pinned-connection discard escape by @Kiran01bm in #952
- feat(cli): render command hints with a wrapper-passed tool name by @aparajon in #983
- feat(ddl): add a PostgreSQL statement parser behind the seam by @Kiran01bm in #953
- fix(storage): run credential reload outside the connector mutex by @Kiran01bm in #981
- fix(storage): open Postgres bootstrap connections via postgresconn by @Kiran01bm in #985
- fix(github): sanitize remaining rendered engine errors by @Kiran01bm in #986
- Bump spirit to
@main(2026-08-08) by @morgo in #998 - feat(observability): add durable webhook dispatch lifecycle metrics by @Kiran01bm in #988
- feat(webhook): synthesize inbox rows for open PR heads missing a delivery by @Kiran01bm in #987
- refactor(webhook): expose retry disposition for rollback commands by @Kiran01bm in #989
- feat(config): gate MySQL-only features for postgres targets by @Kiran01bm in #993
- ci: split MySQL and gRPC e2e suites into parallel jobs by @Kiran01bm in #996
- feat(storage): add backend error-classification seam by @Kiran01bm in #990
- refactor(storage): unqualify SET targets in no-join UPDATEs by @Kiran01bm in #991
- feat(api): fail PostgreSQL startup on missing schema columns by @Kiran01bm in #992
- refactor(webhook): expose retry disposition for rollback-confirm command by @Kiran01bm in #1000
- feat(schema): finalize Postgres reserved set and make pull gates dialect-aware by @Kiran01bm in #995
- feat(storage): stamp updated_at explicitly on operation and comment writes by @Kiran01bm in #951
- feat(storage): stamp remaining sqlstore timestamps explicitly by @Kiran01bm in #1006
- feat(tern): route postgres targets to the postgres engine by @Kiran01bm in #1003
- feat(api): fail-closed verdict gating for postgres plans by @Kiran01bm in #1004
- ci: verify golangci config against a vendored schema by @Kiran01bm in #997
- test(e2e): deflake multi-table stop/start resume and MySQL cold starts by @Kiran01bm in #1005
- refactor(storage): make remaining sqlstore SQL dialect-portable by @Kiran01bm in #1007
- feat(postgres): implement declarative planning via pg-sprite diffplan by @Kiran01bm in #1008
- fix(observability): make telemetry resource schema-tolerant by @Kiran01bm in #1014
Full Changelog: v0.1.59...v0.1.60