Skip to content

Releases: block/schemabot

v0.1.63

Choose a tag to compare

@github-actions github-actions released this 19 Aug 05:22
832db3d

Highlights

Vitess Safety

  • VSchema deletions are treated as unsafe changes — removing a VSchema entry is classified as unsafe and gated accordingly, instead of passing as an ordinary edit. (#1075)
  • In-place vindex mutations are treated as unsafe changes — editing a vindex in place is classified alongside deletions rather than read as a benign rewrite. (#1081)

Apply Correctness

  • A deployment-keyed apply completes only when its generation manifest is satisfied — the dispatcher's declared operation set is the completion authority, so an apply whose siblings are still arriving stays running instead of terminalizing early and refusing later attachments. (#1076)
  • Sequential operation-scoped drives leave the parent apply to the projection — a drive that owns one operation no longer writes the parent's state directly, so the parent reflects the derived verdict over all of its operations. (#1074)

Schema Configuration

  • ignore_namespaces in schemabot.yaml — a repository can exclude namespaces from schema discovery, and the ignored set is reported back so the exclusion is visible rather than silent. (#1073)

CLI

  • pull --lint surfaces schema lint findings — pulling a schema can report lint findings on what it pulled, with unlintable tables and unsupported dialects named explicitly. (#1080)

GitHub PR Experience

  • Throttle reasons are explained inline, with a reference doc — a throttled apply says why it is throttled in the PR and links to the full explanation, rather than showing a stalled count. (#1072)

PostgreSQL

  • Durable controls resolve terminally on typed lifecycle declines — a control request the engine declines for a typed lifecycle reason settles terminally instead of retrying against a decision that will not change. (#1078)
  • The config-to-apply path is covered and the fail-closed plan seam is removed — PostgreSQL planning no longer routes through a seam that blocked plans lacking classifier verdicts. (#1067)

Internals

  • The effective-Vitess-state policy is shared in one helper — the state derivation lives in a single place instead of being restated at each call site. (#1071)
  • Storage parity families are linted against exact time.Time equality — the parity tests compare timestamps exactly rather than through a looser check. (#1070)
  • The release process and its compatibility checks are documented — the repository documents how a release is cut and what compatibility gates it must clear. (#1066)

Upgrade notes

  • The applies table gains expected_operation_keys. On MySQL the self-bootstrapping schema check applies this at startup. On PostgreSQL the bootstrapper creates missing tables but does not alter existing ones, and it fails startup when an expected column is absent, so add this column before deploying.
  • The data plane's chunk-time knob is removed and its lock wait timeout is fixed at 10s. Volume no longer tunes a target chunk time; deployments that relied on volume to influence chunk sizing should expect the engine's own sizing instead. (#1077)
  • Spirit / checkpoint compatibility: unchanged. This release moves the Spirit pin, but the checkpoint table definition (_<table>_chkpnt) is identical to the previous release, so a row copy interrupted by a redeploy resumes from its checkpoint rather than restarting.
  • No toolchain change. This release stays on Go 1.26.6; consumers embedding the module need no toolchain move.

Contributors

Full Changelog: v0.1.62...v0.1.63

v0.1.62

Choose a tag to compare

@github-actions github-actions released this 17 Aug 06:21
1d44aaa

Highlights

GitHub PR Experience

  • Applies explain throttle pauses and checkpoint resumes — when the engine's throttler pauses a row copy or checksum, the PR says so, and a stalled row count reads as a deliberate pause rather than a hang. (#1039)
  • A configurable agent hint on plan comments — deployments can render their own guidance to coding agents alongside a plan. (#895)
  • Over-cap pull requests get a cap-specific blocking check — a PR that exceeds the schema file cap is told exactly that, instead of failing behind a generic check. (#1032)
  • One terminal comment for an exhausted durable command — a command that runs out of retries answers once, at the bottom of the timeline. (#1052)
  • Control requests name the operator who issued them — the plane that records a durable control request carries the caller through to the PR notice and the apply log, even when another plane accepted the command. (#1020, #967)
  • A refused apply names the apply and table holding the database — the refusal points at the blocking work instead of stating that the database is busy. (#1034)
  • Check Run summaries are sanitized — error text on a Check Run summary can no longer leak raw driver or connection detail into a public pull request. (#1044)

Apply Correctness

  • Remote dispatches are keyed by deployment and verified on the way back — a deployment's sibling operations share one remote apply, so the data plane echoes the operation key it resolved and the control plane checks it before persisting remote ids. (#1049, #1050)
  • VSchema-only applies are shaped as a deployment-scoped finalizer — a VSchema change dispatches as a task-less finalizer rather than resurrecting sibling DDL as shard-less work. (#1045)
  • Task-less stop and cancel settle truthfully when the lease is lost — a control request against an apply whose lease has moved reports what actually happened. (#1047)
  • A shutting-down process hands an apply back cleanly — a process going down releases its apply instead of leaving it to time out. (#1019)
  • Queued shards ready for cutover are normalized — a shard that has finished copying is presented consistently regardless of how it queued. (#1035)
  • The revert window is kept for unsafe changes — an unsafe change retains its window to be reverted rather than closing it early. (#1040)
  • The pre-deploy context baseline is bounded to recent history — the baseline reads a recent window instead of the full history. (#1046)

Webhook Durability

  • Lost auto-plans are recovered from check_suite.requested — a plan that never landed is picked back up instead of leaving the PR without one. (#1002)
  • retry_after is honored as a not-before time — a delivery asked to wait is held until its time rather than retried early. (#999)
  • Deliveries that can never succeed are dead-lettered — a permanently failing delivery stops consuming retries. (#1023)
  • Stale auto-plan claims coalesce through a superseded terminal state — a claim overtaken by a newer one resolves instead of lingering. (#1001)
  • Both issue-comment paths share one gate ladder — the durable and direct paths evaluate the same gates in the same order. (#1053)

PostgreSQL & Storage

  • Native-safe PostgreSQL schema changes apply via pg-sprite — PostgreSQL applies run through the pg-sprite engine. (#1025)
  • A storage.dialect switch routes the storage stack — the configured dialect selects the MySQL or PostgreSQL back end. (#1013)
  • PostgreSQL sessions are pinned to UTC — storage sessions no longer inherit the server's timezone. (#1018)

Data Plane

  • Schema pull is delegated to the data plane engine capability — pull runs on the engine that owns the database rather than in the control plane. (#1022)
  • Plan and pull validate the database type against the server config — validation reads the configured types instead of a hardcoded list. (#1031)
  • Managed MySQL connections interpolate query parameters client-side — every connection opened through the shared helper interpolates parameters itself. (#1029)

Observability

  • Engine log routing is correct and race-free — engine log lines reach the right apply log without racing. (#1028)
  • GitHub request metrics distinguish transport failures from 404s — a dial failure and a missing resource are no longer the same signal. (#1024)
  • A resumed or failed drive explains itself in the apply log — the log states why a drive resumed or failed. (#1027)
  • The tern health RPC logs its cause on failure — a failed health check names what went wrong. (#1026)
  • Webhook log severities are right-sized for oncall triage — expected conditions stop logging at warning and above. (#1037)

Upgrade notes

  • pending_drops.enabled now defaults to false. The pending-drops quarantine is opt-in; deployments that relied on the previous default-on behavior must set it explicitly. (#1057)
  • The tasks table gains throttled and throttle_reason. On MySQL the self-bootstrapping schema check applies this at startup. On PostgreSQL the bootstrapper creates missing tables but does not alter existing ones, so apply these columns before deploying.
  • This release requires Go 1.26.6. Consumers embedding the module must be on that toolchain or newer.
  • Upgrade data planes alongside the control plane when running sharded Vitess. A control plane on this version dispatching a sharded or VSchema-only apply to a data plane older than this version fails that dispatch closed, by design (#1050). Non-sharded MySQL applies derive an empty operation key and are unaffected.

Contributors

Full Changelog: v0.1.61...v0.1.62

v0.1.61

Choose a tag to compare

@github-actions github-actions released this 13 Aug 09:27
18e6847

Highlights

GitHub PR Experience

  • Destructive changes to tables another open PR owns are flagged — when a plan drops or destructively alters a table that a different open pull request already claims, the plan comment attributes the change to that PR instead of presenting it as unowned, and every comment an apply acts on carries the disclosure. (#1017)
  • Auto-plan is scoped to the schema a pull request actually proposes — discovery compares the PR's schema files against the default branch, so a pull request stacked on a stale base no longer plans changes it never made. (#1016)
  • Command rejections lead with the database's operators — a rejected command tells you who can authorize it first, instead of burying the operator list under the reason. (#960)
  • Lint warnings render like issues, and long lists fold — warning formatting matches the issues block, and oversized lists collapse instead of flooding the comment. (#959)

Apply Correctness

  • A local drive heartbeats the row it actually owns — lease heartbeats are bound to the claimed row, so a drive can no longer refresh a lease it no longer holds. (#915)
  • A deferred cutover is held — when an operator defers the cutover, the apply waits for the operator instead of proceeding on its own. (#978)
  • VSchema-only work dispatches to remote data planes — work operations that carry no copy task are dispatched over gRPC like every other operation, so VSchema-only changes complete on remote engines. (#961)

PostgreSQL & Storage Portability

  • PostgreSQL dialect nucleus in the shared store core — the store core carries a dialect seam that both MySQL and PostgreSQL back ends render through. (#1010)
  • Public PostgreSQL store constructor — embedders can construct a PostgreSQL-backed store directly. (#1012)
  • Lease-guarded joined DML is portable — the operation store's lease-guarded updates and joined UPDATEs render through the dialect rather than assuming MySQL syntax. (#1011, #1009)

Upgrade note

  • The tasks database index widened. On MySQL, the self-bootstrapping schema check applies this automatically at startup. On PostgreSQL, the bootstrapper creates missing tables but does not alter existing ones — operators running a PostgreSQL-backed store should apply the index change before deploying this version.

Contributors

Full Changelog: v0.1.60...v0.1.61

v0.1.60

Choose a tag to compare

@github-actions github-actions released this 13 Aug 01:47
v0.1.60
acdc028

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 StatementParser seam 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 postgresconn pool 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 tele...
Read more

v0.1.59

Choose a tag to compare

@github-actions github-actions released this 05 Aug 17:52
b99dcea

Highlights

Breaking changes

  • Apply claiming is now operation-level only — the apply-level claim path is gone. The operator_claim_operations server config key no longer exists and must be removed from any deployment values that still set it: config decoding is strict, so an unknown key makes the server exit at startup. (#933, #934)
  • ApplyStore.FindNextApply removed from the storage interface — embedders that claimed applies directly should claim through the operation ladder (ApplyOperations().FindNextApplyOperation) and then take the parent lease with Applies().ClaimApplyByID. (#934)

Apply orchestration

  • Operation-scoped drives execute statements in plan order — tasks for an operation-claimed apply were ordered newest-first, so a multi-statement plan ran in reverse. Ordering is now pinned at the storage layer. (#932)
  • Applies left behind their own settled operations are reconciled — an apply whose operations have all reached a terminal state while the apply's own state lagged is projected forward instead of blocking the target's next apply. (#916)
  • Stop-reconciliation claims are gated on lease staleness — a fresh, actively-driven apply can no longer be claimed out from under its driver. (#907)
  • Conflict checks require lease ownership before trusting local engine memory (#909)
  • Operation leases are released when the parent apply is transiently unclaimable, so a retry is not blocked behind a lease nobody is holding. (#924)

Durable command handling

  • Apply and apply-confirm comment commands are dispatched durably — a restart or webhook redelivery between the command and its dispatch no longer loses the command. (#922)
  • check_run.completed re-folds are durable, so a re-fold survives a restart instead of leaving the aggregate check stale. (#919)
  • Unlock commands expose their retry disposition, letting the dispatcher tell a retryable failure from a permanent one. (#923)
  • A panicking webhook goroutine posts a fixed, user-safe comment instead of leaving the pull request with no response. (#921)

Authorization

  • Per-database operator write scoping for forward-auth — the new operator_groups and operator_environments settings grant a team scoped write access (apply, rollback, plan, control commands, locks) to named databases in named environments, without granting deployment-wide admin. With neither key set, behavior is byte-for-byte unchanged. (#869)

GitHub experience

  • Database operators get their own section on the review-required comment, so it is clear who can approve what. (#931)
  • Relayed control rejections name the apply they refer to (#905)

Engine

  • The execution verdict comes from Spirit's own checks rather than a parallel reimplementation, so refusals stay in step with the engine that enforces them. (#899)
  • Deploy requests keep retrying while the provider is still validating them, instead of failing the apply on a transient validating state. (#900)

CLI

  • status is ordered by last activity, so in-flight schema changes stay visible instead of being pushed off the list by older records. (#926)
  • Authenticated caller attribution keeps the CLI channel and hostname (#930)

Observability

  • A missing durable tenant is reported distinctly from a corrupted one, so the two failure modes can be triaged apart. (#920)

Dependencies

  • Spirit updated to v0.16.1 — brings the statement-level refusal reasons behind the engine verdict change above, plus DDL canonicalization improvements. The checkpoint table format is unchanged, so an in-flight copy interrupted by a redeploy still resumes from its checkpoint rather than restarting. Spirit also dropped its github.com/go-mysql-org/go-mysql fork replace in favor of upstream, and this release mirrors that — embedders carrying the same replace directive should drop it to stay aligned. (#925, #943)

Contributors

Full Changelog: v0.1.58...v0.1.59

v0.1.58

Choose a tag to compare

@github-actions github-actions released this 03 Aug 15:54
56ca39f

Highlights

Direct Execution (new)

  • Direct-routed ALTERs now execute as native MySQL DDL — changes the planner routes to direct execution run under the policy's lock-wait bound instead of a full copy, making small/metadata-only changes fast and safe. (#836)
  • direct_execution policy configuration — a new opt-in config block (enabled, max_table_rows, lock_acquisition_timeout) controls when direct execution is allowed. (#858)
  • Plan-time execution-mode verdicts — plans resolve and display whether each statement will run direct or via copy, so the route is visible before anything applies. (#886)
  • Disclosure and manual confirmation for direct-execution changes — PR comments call out direct-routed statements and require an explicit confirmation before applying. (#839)

GitHub PR Experience

  • Apply is marked as the primary action with ▶️ — the apply instruction stands out from secondary commands in the plan comment. (#896)
  • Failed tables surface their own error — a failed table shows its failure reason directly below its progress row, carried on a new per-table error_message progress field. (#888, #890)
  • Pre-copy failures render without a misleading progress bar — failures before the copy starts no longer show 0% progress. (#880)
  • Remote apply failures surface their reason in the PR comment — instead of a bare failed state. (#878)
  • Support-channel footer shows exactly when it should — offered on unmanaged-schema notices and unsafe-change refusals, and omitted everywhere it was noise. (#884, #871, #883)
  • Bare plans stay silent on non-owning deployments — a bare plan command no longer fans out duplicate comments from deployments that don't own the change. (#870)
  • Multi-deployment detail bodies use derived status — detail sections stay consistent with the aggregate state. (#882)

Driver Correctness

  • Pending operations are only claimed when their apply is still claimable — a driver can no longer pick up work under an apply that has settled or moved on. (#906)
  • Stranded pending operations under settled applies are reaped — leftover operations from interrupted drives are cleaned up instead of wedging future work. (#911)
  • The persisted tenant is authoritative for durable webhook deliveries — redeliveries resolve to the tenant recorded at receipt time. (#872)
  • Gate evaluation failures are distinguished from merit blocks — an evaluation error fails closed and reads as an error, never as a judged "blocked". (#823)

Observability

  • Apply identity on the full drive lifecycle — operator, sequential, grouped, resume/control, task-readiness, gRPC client, engine, and handler log lines all carry the apply's triage identifiers, so a failed or stalled apply can be traced end-to-end from logs alone. (#877, #879, #881, #885, #887, #889, #893, #913, #914, #917)
  • Spirit control-path and apply logs route through the change logger with table context — engine log lines land in the same identity-scoped stream as the rest of the drive. (#918, #875)
  • Stuck-pending apply diagnostics are surfaced and preserved — the diagnosis of why an apply sat pending survives for later triage. (#816)
  • Log fields that collided with reserved log-pipeline attributes were renamed — affected fields index correctly again. (#874)

Internals

  • StatementType is owned by pkg/ddl behind the parser seam — DDL classification no longer leaks parser types across package boundaries. (#908)
  • Docs: where to put the schema directory in namespaced repos. (#849)
  • Spirit pin advanced to latest main. (#894)

Contributors

What's Changed

  • refactor(webhook): distinguish gate evaluation failures from merit blocks by @Kiran01bm in #823
  • fix(github): show support footer only on unsafe-change apply refusals by @aparajon in #871
  • fix(observability): rename log fields that collide with reserved log-pipeline attributes by @aparajon in #874
  • fix(github): keep bare-plan fan-out silent on non-owning deployments by @aparajon in #870
  • fix(observability): carry table context on Spirit apply log lines by @aparajon in #875
  • fix(tests): isolate awssm resolver test from ambient AWS environment by @Kiran01bm in #876
  • refactor(webhook): make the persisted tenant authoritative for durable deliveries by @Kiran01bm in #872
  • feat(observability): bind apply identity to operator drive-scoped logger by @Kiran01bm in #877
  • refactor(github): declare support-footer eligibility at render time by @aparajon in #883
  • fix(github): offer the support channel on unmanaged-schema notices by @aparajon in #884
  • fix(github): surface remote apply failure reason in PR comment by @Kiran01bm in #878
  • feat(observability): bind apply identity to local resume and control logs by @Kiran01bm in #879
  • feat(github): render pre-copy failures without a progress bar by @Kiran01bm in #880
  • feat(github): use derived status in multi-deployment detail bodies by @Kiran01bm in #882
  • feat(api): add the direct_execution policy configuration surface by @aparajon in #858
  • feat(observability): bind apply identity to sequential drive logs by @Kiran01bm in #881
  • fix(observability): preserve drive logger in task readiness checks by @Kiran01bm in #885
  • feat(observability): bind apply identity to grouped drive logs by @Kiran01bm in #887
  • feat(observability): bind identity-scoped logger to gRPC client core remote drive loop by @Kiran01bm in #889
  • feat(github): surface a failed table's error below its row by @Kiran01bm in #888
  • Bump spirit to @main (e94e99be2c1b) by @morgo in #894
  • feat(engine): resolve plan-time execution-mode verdicts under the direct execution policy by @aparajon in #886
  • feat(engine): execute direct-routed ALTERs as native MySQL DDL under the policy's lock bound by @aparajon in #836
  • feat(api): carry per-table error_message on TableProgress by @Kiran01bm in #890
  • feat(github): disclose direct-execution changes and require manual confirmation by @aparajon in #839
  • feat(observability): complete gRPC client apply-identity logger adoption by @Kiran01bm in #893
  • fix(github): mark the apply instruction as the primary action with ▶️ by @aparajon in #896
  • feat(observability): surface and preserve stuck-pending apply diagnostics by @Kiran01bm in #816
  • docs(namespaces): where to put the schema directory by @Kiran01bm in #849
  • refactor(ddl): own StatementType in pkg/ddl behind the parser seam by @Kiran01bm in #908
  • ci: pre-pull external Docker images with bounded retry by @Kiran01bm in #912
  • feat(observability): carry the apply identity into Spirit engine log records by @Kiran01bm in #913
  • feat(observability): carry full apply attrs on operator lifecycle logs by @Kiran01bm in #914
  • feat(observability): carry the apply identity into handler lifecycle log records by @Kiran01bm in #917
  • fix(operator): only claim pending operations whose apply is still claimable by @aparajon in #906
  • fix(operator): reap stranded pending operations left under settled applies by @aparajon in #911
  • feat(observability): route Spirit control-path logs through the change logger by @Kiran01bm in #918

Full Changelog: v0.1.57...v0.1.58

v0.1.57

Choose a tag to compare

@github-actions github-actions released this 29 Jul 02:52
c3bdbe2

Highlights

Webhook delivery

  • Durable replay no longer wedges on one wide payload — The durable dispatch claim query selected every column, including the delivery payload, under an ordering no index satisfies, so MySQL filesorted the payload into each sort record. A single delivery larger than sort_buffer_size failed the claim query with Error 1038 (HY001): Out of sort memory on every poll, permanently stalling durable replay behind that one row. FindNext now claims in two steps — a narrow ordered key scan, then a keyed fetch of the payload — so claim latency and memory no longer scale with payload size. (#860)

GitHub checks

  • Aggregate deployments stay off databases they have not registered — On repositories with no directory allowlist, schema-config discovery kept every config it found, so an aggregate leader configured with no databases of its own would try to plan a participant's database and turn a DatabaseNotConfiguredError into failing aggregate checks plus a "Plan Failed" comment on routine fan-out PRs. Discovery now keeps only configs the deployment actually registers. (#865)

Authorization

  • Read-tier access for gateway-verified service callersforward_auth previously had a single lane: an authenticating proxy forwarding a human's identity headers. A service calling the API as itself was rejected as untrusted even when a mesh gateway had already terminated and verified its client certificate, and the only workaround — trusting that gateway as a proxy — would have let anything behind it self-assert user and group headers into the write tier. A second, read-only lane now grants gateway-verified service callers read-tier access without that escalation, configured by forward_auth.trusted_gateway_spiffe, forward_auth.read_service_spiffe, and the optional forward_auth.caller_spiffe_header. The lane fails closed — gateways without callers (or callers without a gateway) refuse to start, it requires SPIFFE-anchored proxy trust, a SPIFFE ID may never be both a trusted proxy and a trusted gateway, service callers are denied the write tier (service_caller_write), and an empty config disables the lane entirely. All three keys are new and optional, so existing configuration is unaffected. (#864)

Observability

  • Untrusted-proxy denials name the identity that arrived — An untrusted_proxy denial logged only the path and the remote address, which behind a sidecar is always loopback, leaving an operator unable to answer what identity the request presented. The denial log now carries xfcc_uris (the SPIFFE URI SVIDs parsed from X-Forwarded-Client-Cert) and xfcc_uri_count, so a missing trust-anchor entry is visible directly in the log line. (#863)

Storage

  • Never-written task readiness fields removed — Per-shard readiness has always been folded into canonical task state before it leaves the engine, so the persisted tasks.ready_to_complete column and the ShardProgress.ready_to_complete proto field were never written or read. Both are gone: the column is dropped from the embedded tasks schema, and proto field 8 is reserved, keeping the wire format compatible with older peers. Two upgrade notes: EnsureSchema refuses the resulting DROP COLUMN unless storage.allow_destructive_schema_changes is set, so the column is simply left in place by default (a warning is logged, startup continues) — do not enable that flag until every process reading the table is on this version or newer; and, as always, upgrade the control plane before any consumer that reads ShardProgress. (#861)
  • Advisory lockers injected per target — The last package-level namedlock.Locker bindings are replaced by per-target injection, and a target with no locker now fails closed instead of opening a connection. (#859)

Dependencies

  • Spirit updated to v0.15.2-0.20260727035859-220f8b6cfca1 — Picks up read-side copier autoscaling and the matching connection-pool sizing; no schemabot source changes were required. Spirit / checkpoint compatibility: the checkpoint table format (_<table>_chkpnt) is unchanged across this range — pkg/checkpoint is byte-identical between the old and new pins — so a copy that is in flight when the process restarts resumes from its checkpoint instead of restarting from zero. (#855)

Maintenance

  • Latest plan-comment lookup uses slices.Backward — Behavior-preserving rewrite of the newest-first scan in the webhook plan-comment path. (#825)

Contributors

Full Changelog: v0.1.56...v0.1.57

v0.1.56

Choose a tag to compare

@github-actions github-actions released this 28 Jul 10:21
5027d30

Highlights

Configuration

  • Per-database environment promotion order — A database entry may now override the server-wide environment_order with its own promotion sequence, so databases that promote through different environment chains (for example qa → sandbox → production alongside qa → staging → production) can coexist on one server. The override replaces the server-wide order entirely for that database's promotion gating and is validated fail-fast at startup in both directions. (#854)

Storage

  • EnsureSchema routes through per-dialect dispatch — Storage schema bootstrap now dispatches per storage dialect instead of assuming MySQL inline, cleaning the seam for future storage dialects with no behavior change. (#851)

Testing

  • Pending-drops gate pinned as MySQL-only — Added regression coverage pinning that the pending-drops safety gate resolves its target only for MySQL databases. (#852)

Contributors

Full Changelog: v0.1.55...v0.1.56

v0.1.55

Choose a tag to compare

@github-actions github-actions released this 27 Jul 20:26
1092ff5

Highlights

Engine

  • Production-proven Spirit run settings, with an optional spirit: config block — schema changes now run with tuned defaults (autoscaled write threads, checkpoint max age, checksum yield timeout); the new server-level spirit: block exists only to deviate from them, and per-database metadata can override. (#840)
  • Conformance suite with typed rejections — engines now report completed and missing changes through typed rejections, backed by a cross-engine conformance suite. (#842)
  • Plans containing engine-blocked changes are rejected up front — an apply whose plan includes a change the engine refuses is rejected at plan time instead of failing mid-apply. (#838)
  • Spirit test containers gate on a real SQL handshake — test MySQL containers are considered ready only after a successful handshake, hardening the engine test suite. (#850)

GitHub Integration

  • Promotion-check-name override for shared prior environments — fleets that share one staging instance across several production instances can point the promotion gate at the shared instance's check name via promotion-check-name. (#847)
  • Unscoped rollback and control commands fan out in tenant mode — rollback and control commands without an explicit scope now reach every tenant deployment they apply to. (#848)
  • Single-responder replies for missing -e and empty unlock on fan-out — fan-out commands with a missing environment flag or nothing to unlock get one clear reply instead of a chorus. (#857)
  • Aggregate Check Run rewinds publish a fresh run — rewinding a concluded aggregate check to in-progress publishes a new Check Run so the status is never stuck on the concluded one. (#811)
  • Leader aggregate title says tenant applies are pending — the aggregate check title now reflects pending tenant applies instead of reading as idle. (#846)

Data Plane

  • Engine terminal truth wins before pending stop/cancel commands are consumed — a change the engine already finished can no longer be flipped by a stale queued stop or cancel. (#843)
  • On-start volume convergence skipped for tasks without row-copy work — restarts no longer run needless convergence for tasks that copy no rows. (#844)
  • Stop/cancel against an already-completed deploy request settles as completed — cancelling a change whose deploy request already finished records the truthful terminal state. (#841)

Observability

  • Single-statement Spirit logs route to the apply log stream — logs from single-statement changes now land in the same per-apply stream as multi-statement ones. (#856)

Contributors

Full Changelog: v0.1.54...v0.1.55

v0.1.54

Choose a tag to compare

@github-actions github-actions released this 24 Jul 22:03
6bbfd73

Highlights

Plan & Apply Safety

  • Engine-blocked changes are disclosed in the plan comment — When the engine will deterministically refuse a statement at apply time, the plan comment now says so up front instead of letting the apply fail later. (#798)
  • Plan-time execution-mode verdicts — The planner records how the engine will execute each table change (default path vs blocked, with a reason), surfaced through the API and plan output. (#802)
  • Durable webhook inbox covers more eventsmerge_group, push, and PR-close events now route through the durable inbox, so a pod restart or redelivery can't drop them. (#780)

CLI

  • status summarizes and filters by stateschemabot status now tallies applies by state, and supports --state and --last <window> to narrow the list. (#828, #829, #826)
  • databases --name filter — Filter the database list by name. (#827)
  • checks backfill exits nonzero when work remains — Scripting a backfill sweep can now gate on the exit code instead of parsing output. (#830)
  • logs -n returns the newest entries — Tail semantics: the most recent N log entries, not the oldest. (#820)
  • Control commands accept 202 Accepted — Asynchronously acknowledged control responses are treated as success instead of an error. (#833)
  • unlock targets locks held under another database type — Unlock now points at the actual held lock when the database is registered under a different type. (#810)
  • Onboard verification names the offenders — Failed onboard verification lists the offending tables and stray files instead of a generic error. (#801)

PlanetScale / Vitess

  • Missing branch VSchema treated as empty — Keyspace diffs no longer fail when a branch has no VSchema yet. (#832)
  • Idempotent cancel with throttled control retransmission — Cancelling a PlanetScale apply is now idempotent, and remote control commands are retransmitted with a throttle instead of a tight loop. (#809)

Server & Reliability

  • Storage pool connection churn reduced — Raised the storage pool's idle connection ceiling and made pool limits configurable via a new optional pool config section. (#831)
  • Spirit updated to latest main — Brings in the latest upstream fixes. The Spirit checkpoint format is unchanged: an in-flight schema change interrupted by a redeploy resumes from its checkpoint as usual. (#815)

Contributors

New Contributors

  • @jemiahw made their first contribution in #814 — welcome! 🎉

Full Changelog: v0.1.53...v0.1.54