feat(github): surface engine throttle pauses and checkpoint resumes - #1039
Conversation
…e fields Spirit's progress API now reports whether a run resumed from a checkpoint and whether (and why) the current phase is throttled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A table paused by the engine's throttler now renders the pause and its trigger (e.g. replica lag) on the PR comment and CLI progress surfaces, so a stalled progress bar reads as a deliberate slowdown rather than a hang. The flag and display reason ride the stored task row through the durable read-model pipeline; the engine stamps them only on tables in a paced phase (row copy, checksum verify) and the drive's write-through clears them when the pause lifts. Reasons are sanitized at the engine boundary before storage so they are safe to render in markdown. A drive claim that reattaches to the engine's durable checkpoint now records one timeline event, so operators can tell a resumed copy from a fresh start after a pod restart or lease handover. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR extends SchemaBot’s end-to-end progress pipeline (engine → durable storage → proto/API → PR comment + CLI) to surface two new Spirit status signals: per-table throttle pauses (with a human-readable trigger) and a “resumed from durable checkpoint” indicator that becomes a single timeline event per drive claim.
Changes:
- Plumbs
throttled/throttle_reasonfrom Spirit through engine progress, storage task rows, proto/API types, and renders it in PR comments + CLI progress output. - Records a one-time “resumed from checkpoint” timeline event per drive claim when Spirit reports it reattached to a durable checkpoint.
- Updates schema (MySQL + Postgres), templates/previews, and bumps the Spirit dependency (and Go patch version).
Reviewed changes
Copilot reviewed 29 out of 31 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| TEMPLATES.md | Adds rendered preview examples showing throttled table output in PR comments and CLI. |
| pkg/webhook/templates/preview.go | Adds a new PR comment preview scenario for a throttled table. |
| pkg/webhook/templates/apply.go | Adds throttling fields to template data and renders the “Paused by throttler” line. |
| pkg/webhook/templates/apply_test.go | Adds unit tests asserting throttling text rendering in apply comments. |
| pkg/webhook/apply.go | Maps stored task throttling fields into webhook comment template data. |
| pkg/tern/local_client.go | Includes throttling fields in the local progress response mapping. |
| pkg/tern/local_client_test.go | Adds tests for checkpoint-resume timeline logging and verifies throttling fields in progress. |
| pkg/tern/local_apply.go | Adds helper to log a resume-from-checkpoint timeline event once per claim. |
| pkg/tern/local_apply_sequential.go | Logs resume-from-checkpoint once per sequential drive claim; persists throttling fields to tasks. |
| pkg/tern/local_apply_grouped.go | Logs resume-from-checkpoint once per atomic/grouped drive claim; persists throttling fields to tasks. |
| pkg/tern/grpc_client.go | Mirrors throttling fields from remote progress into stored tasks. |
| pkg/tern/grpc_client_test.go | Adds coverage verifying throttling fields mirror from remote progress snapshots. |
| pkg/storage/types.go | Extends storage.Task with Throttled and ThrottleReason. |
| pkg/storage/internal/sqlstore/tasks.go | Adds throttling columns to task CRUD SQL and scanning. |
| pkg/storage/internal/sqlstore/tasks_test.go | Adds round-trip test for task throttling columns. |
| pkg/schema/postgres/tasks.sql | Adds throttled and throttle_reason columns to Postgres tasks schema. |
| pkg/schema/mysql/tasks.sql | Adds throttled and throttle_reason columns to MySQL tasks schema. |
| pkg/proto/ternv1/tern.pb.go | Regenerates tern proto bindings with throttling fields on TableProgress. |
| pkg/proto/tern.proto | Adds throttling fields to TableProgress in the tern API. |
| pkg/engine/spirit/spirit.go | Reads Spirit throttle + resume status; sanitizes throttle reason for safe rendering. |
| pkg/engine/spirit/spirit_test.go | Adds tests for throttle scoping behavior and reason sanitization. |
| pkg/engine/engine.go | Extends engine progress types with ResumedFromCheckpoint and throttling fields. |
| pkg/cmd/internal/templates/progress.go | Renders throttling line in CLI progress templates. |
| pkg/cmd/internal/templates/progress_states_test.go | Adds CLI rendering tests for throttling across copy/checksum states. |
| pkg/cmd/internal/templates/progress_parse.go | Plumbs throttling fields from API types into CLI template data. |
| pkg/cmd/internal/templates/preview_sequential.go | Adds CLI preview scenario for a throttled sequential apply. |
| pkg/cmd/internal/templates/preview_comment.go | Adds preview selectors for the new comment + CLI throttle scenarios. |
| pkg/apitypes/apitypes.go | Adds throttling fields to the JSON API progress table response type. |
| pkg/api/progress_handlers.go | Maps throttling fields from proto and local storage into API responses; syncs from tern into tasks. |
| go.sum | Updates checksums for the Spirit dependency bump (and related module resolution). |
| go.mod | Bumps Go patch version and updates Spirit dependency version. |
Files not reviewed (1)
- pkg/proto/ternv1/tern.pb.go: Generated file
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
An unthrottled table must carry no reason, even if the runner reports leftover reason text, so a stale reason can never leak through the read model with the flag down. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A single newline merges into the preceding rows/ETA line wherever standard markdown line-break rules apply, so the pause gets a blank line before it and stands apart from the progress detail. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pause reads as stopped and collides with the operator stop vocabulary; the throttler is backpressure — the copy is slowed and resumes on its own — so the line names it that way on both surfaces. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The lines under a table header (rows, ETA, verified counts) rendered as bare paragraphs everywhere except the estimate-exceeded branch, which bulleted them. Bullet them all: every line under a header is now a list item, matching the CLI's bulleted detail lines, and list items never merge under any markdown line-break mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The throttle marker was its own glyph-led paragraph below the detail lines, visually misaligned with them and inventing a new template element. Move the state to where the eye checks progress — a plain "(throttled)" suffix on the table's header line — and explain the trigger with the same tooltip idiom the estimate-exceeded note uses, as an ℹ️ bullet in the detail list. When the engine reports throttled without a reason, the header annotation stands alone. Both the PR comment and CLI render the same shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sample reason was an invented replica-lag string in a format Spirit never emits, and replica-lag throttling is rare on the Aurora targets operators actually run. Use the commit-latency throttler's real output shape with Spirit's default 100ms threshold instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖 Review findings - created by Kiran's code review agent - for pull/1039, ae354db. Verdict: 8 findings — 6 non-blocking, 2 suggestions, none blocking; CI 33/33 pass — all checks green at verification time (Build, Unit, Lint x4, Integration x3, E2E MySQL/K8s/Vitess/gRPC suites, LocalScale x3, build-and-push, DCO). Non-blocking
General suggestions
The one thing that could have broken, verifiedThe riskiest mechanism is the durable write-through clear semantics — the promise that Verified correct
This review was generated by Claude Code (claude-fable-5). |
The stored throttle pair now behaves as a point-in-time signal everywhere: the gRPC mirror refreshes it on every tick (including ticks that keep stored row totals), so a lifted throttle clears promptly; a reason never travels without the flag; transitionTaskState clears the pair when a task comes to rest, alongside the ETA. Reason sanitization moves to pkg/engine as SanitizeThrottleReason so the remote-ingest boundary shares the engine stamp site's bounds, and the PR comment tooltip escapes inline markdown so an engine reason cannot cut the italic span short. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… level Drive the sequential poll against an engine that reports a resumed copy on every tick and assert a single timeline event, proving the latch holds through the real poll loop rather than only in the helper's unit test. Also reunite an auto-cutover scenario comment with its test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
🤖 Thanks for the thorough review — all eight findings are addressed in three follow-up commits (kept as new commits since the PR is approved):
This reply was written by Claude Code (Claude Fable 5). |
Consumes the resume and throttle fields Spirit now reports through its status API.
Throttle backpressure. A table held back by the engine's throttler now renders the throttle and its trigger on the PR comment and CLI progress surfaces, so a slow progress bar reads as deliberate backpressure — slowed, not stopped — rather than a hang. The table's header line carries a
(throttled)annotation right where the eye checks progress, and the trigger renders as a tooltip bullet using the same idiom as the estimate-exceeded note. The flag and display reason ride the stored task row through the durable read-model pipeline — readers never poll the engine:Rendered on the PR comment (full scenario in TEMPLATES.md, "Second Table Throttled"):
The engine stamps the runner-wide throttle status only on tables participating in a paced phase — a table still copying, or every table during the checksum verify — so a completed table is never rendered as throttled by another table's copy. The stored pair behaves as a point-in-time signal: it refreshes on every progress tick (a lifted throttle clears promptly, including through the remote-progress mirror), a reason never travels without the flag, and it clears when the task comes to rest. Reasons are sanitized at every ingest boundary (whitespace collapse,
|neutralized, rune-safe clamp) and the PR comment escapes inline markdown at render, so an engine-produced reason can never break the comment layout. When the engine reports throttled without a reason, the header annotation stands alone. Table detail lines (rows, ETA, verified counts) now render as a uniform bulleted list on the PR comment, matching the CLI.Checkpoint resumes. A drive claim that reattaches to the engine's durable checkpoint records one timeline event, so operators can tell a resumed copy from a fresh start after a pod restart or lease handover. One event per drive claim is intentional: every claim that resumes is a real engine resume.
Includes the spirit bump that introduces both status fields, the two new task columns in both schema dialects, and new preview scenarios in TEMPLATES.md. The bump also rides along Spirit's other recent main work beyond the status API — binlog watermark visibility, checksum repair-path hardening, and flush/drain improvements — which lands here as part of the dependency update rather than as SchemaBot behavior changes.
🤖 Generated with Claude Code