feat(github): show table-size estimates in the plan comment - #1230
Draft
aparajon wants to merge 1 commit into
Draft
feat(github): show table-size estimates in the plan comment#1230aparajon wants to merge 1 commit into
aparajon wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds “table size (row estimate)” context to schema change plan rendering by plumbing best-effort, display-only per-table row estimates from engines through storage/proto/API into the plan comment templates.
Changes:
- Extend plan data models (engine → storage/proto/API → webhook templates) with
EstimatedRows,ShardCount, andLargestShardRows. - Implement best-effort row-estimate probing for Spirit (MySQL
information_schema) and PlanetScale/Vitess (per-shard probe + all-or-nothing aggregation). - Render a new
📊 Table sizes (approximate)section in plan comments and update previews/templates + tests accordingly.
Reviewed changes
Copilot reviewed 24 out of 25 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| TEMPLATES.md | Updates rendered examples to include the new “Table sizes” section and updated plan summaries. |
| pkg/webhook/templates/table_sizes_test.go | Adds focused template rendering tests for table size lines (sharded/unsharded/unavailable/omitted). |
| pkg/webhook/templates/preview.go | Adds preview data for table sizes and a helper to create *int64 sample estimates. |
| pkg/webhook/templates/preview_sharded.go | Adds sharded preview scenarios that include table size rendering (including “unavailable” behavior). |
| pkg/webhook/templates/plan.go | Introduces TableSizes + rendering helpers (writeTableSizes, formatTableSize) in the plan template. |
| pkg/webhook/plan.go | Threads size data from TableChangeResponse into template data and omits created tables from the size list. |
| pkg/webhook/plan_test.go | Adds unit coverage ensuring buildPlanCommentData populates TableSizes and omits creates. |
| pkg/webhook/plan_integration_test.go | Adds an integration test asserting plan comments include a row estimate for an altered existing table. |
| pkg/ui/format.go | Adds FormatApproxRows for compact ~-prefixed row estimate formatting. |
| pkg/ui/format_test.go | Adds unit tests for FormatApproxRows. |
| pkg/tern/tablechange_convert.go | Plumbs size fields into storage/proto conversion for table changes. |
| pkg/tern/table_sizes.go | Adds shard-level aggregation logic for row estimates (sum + largest shard + all-or-nothing presence). |
| pkg/tern/local_client.go | Applies shard-aggregation results when building namespace-level views and stored plan data. |
| pkg/tern/local_client_shardplan_test.go | Adds tests covering sharded aggregation behavior (complete, partial, pass-through). |
| pkg/storage/types.go | Extends stored TableChange with size estimate fields. |
| pkg/proto/tern.proto | Extends TableChange proto with optional row-estimate fields and shard count. |
| pkg/proto/ternv1/tern.pb.go | Regenerates Go bindings for the proto additions. |
| pkg/engine/spirit/spirit.go | Adds MySQL information_schema probing for per-table row estimates (best-effort, warn-only on failure). |
| pkg/engine/spirit/spirit_integration_test.go | Adds integration coverage for Spirit plan carrying row estimates for existing tables. |
| pkg/engine/planetscale/table_sizes.go | Adds PlanetScale/Vitess shard-count lookup + per-shard probing and aggregation. |
| pkg/engine/planetscale/table_sizes_test.go | Adds unit tests for shard-count lookup and behavior without a vtgate DSN. |
| pkg/engine/planetscale/plan.go | Wires shard-count lookup + size attachment into the PlanetScale plan path. |
| pkg/engine/engine.go | Extends engine.TableChange with size estimate fields. |
| pkg/apitypes/apitypes.go | Extends TableChangeResponse JSON shape with size estimate fields. |
| pkg/api/proto_helpers.go | Plumbs size estimate fields from proto into API response types. |
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.
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
5 times, most recently
from
September 1, 2026 11:18
da1a735 to
2bdf6f1
Compare
This was referenced Sep 1, 2026
aparajon
force-pushed
the
feat/table-size-capture
branch
from
September 1, 2026 15:52
76d5d90 to
72f24bc
Compare
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
from
September 1, 2026 15:52
2bdf6f1 to
1ad29b1
Compare
aparajon
force-pushed
the
feat/table-size-capture
branch
from
September 1, 2026 16:16
72f24bc to
71e2c80
Compare
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
from
September 1, 2026 16:16
1ad29b1 to
dcbbc8b
Compare
aparajon
force-pushed
the
feat/table-size-capture
branch
from
September 1, 2026 16:27
71e2c80 to
f594eb9
Compare
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
from
September 1, 2026 16:37
dcbbc8b to
f59b115
Compare
aparajon
force-pushed
the
feat/table-size-capture
branch
from
September 1, 2026 20:05
f594eb9 to
1a34552
Compare
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
from
September 1, 2026 20:08
f59b115 to
4c449db
Compare
The plan comment renders a "Table sizes" info section above the plan summary and below any lint warnings, scoped to statements that add an index (detected with the dialect's real parser) since that is the change class whose cost scales with the table. Cross-shard totals show the largest single shard; a table gaining an index with no estimate says so explicitly, and a plan with no index adds renders no section at all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
aparajon
force-pushed
the
feat/plan-table-size-estimates
branch
from
September 1, 2026 21:21
4c449db to
d6619c0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this matters
A plan shows the DDL but not the scale of what it touches:
ADD INDEXor avarcharwidening on a 12-row table and on a 120-million-row table read identically, so the operator judging "how long will this run, and should the instance be scaled first" has nothing to go on. The engines now capture per-table size estimates at plan time; this PR is the surface that puts them in front of the operator.Top of the table-size estimates stack: #1236 formatters → #1237 cost-scaling detection → #1238 engine capture → this PR.
What it does
The plan comment renders the captured estimates as a
📊 Table sizesinfo section above the plan summary, below any lint warnings. The section is scoped to where size is the cost signal: a statement carries a size line unless the dialect's real parser proves it metadata-only (ddl.CostScalesWithTableSize). Index builds, column type changes and widenings, charset conversions, and constraint validations all get a line; plain column adds, drops, renames, and default changes render no section at all, so routine alters and table creations add zero noise. Whether a given alter ultimately runs instant is decided by the server at execution time, so the display errs toward showing the size when a copy is possible.Two display properties worth calling out:
~. They come from statistics and are never exact.size estimate unavailable, never an omission — a failed probe must not read as a small table.Full plan comments as rendered (from TEMPLATES.md):
MySQL plan — the alter adds an index, so
productsgets a size lineSchema Change Plan — Staging
Database:
testapp| Type:MySQL| Schema Name:testappRequested by @jackjackbits at 2026-01-01 00:00:00 UTC · planned from
abcdef1💡 Lint Warnings: 2 advisory findings
users: Columncreated_atusesTIMESTAMPwhich overflows on 2038-01-19. Consider usingDATETIMEinstead.products: Indexidx_categoryon columncategoryis redundant - covered by indexidx_category_priceon columns (category,price)📊 Table sizes:
products: ~2.3M rows · ~1.1 GB📋 Plan: 2 tables to create, 1 table to alter
Sharded Vitess plan — cross-shard totals with the largest single shard
Schema Change Plan — Staging
Database:
commerce| Type:VitessRequested by @jackjackbits at 2026-01-01 00:00:00 UTC · planned from
abcdef1Keyspace:
commerceVSchema
Keyspace:
commerce_shardedVSchema
📊 Table sizes:
customers: ~48.2M rows · ~23.4 GB across 2 shards (largest shard ~24.6M rows)📋 Plan: 2 tables to create, 1 table to alter, 2 vschema updates
Plain column add — metadata-only, so no size section at all
Schema Change Plan — Staging
Database:
testapp| Type:MySQL| Schema Name:testappRequested by @jackjackbits at 2026-01-01 00:00:00 UTC · planned from
abcdef1📋 Plan: 1 table to alter
How it moves us toward the northstar
These estimates are the substrate for honest copy progress under the driver cap: persisted with the plan, they can seed the progress denominator for shards whose waves have not started, turning #1191's "across N of M shards" disclosure into a whole-table bar that converges to engine-reported figures as waves dispatch. This PR completes the plan surface; plan persistence and apply-side seeding follow as their own slice.
Opened by Claude (Fable 5).