Releases: apstndb/spannerplan
Release list
v0.3.0
Highlights
- Added tableless query-plan rendering through
asciitable.RenderTableless,plantree/referencelayout configuration, andrendertree --layout=tableless/--tableless. The existing table layout remains the default. - Added the experimental
plantree.StructuralSignatureAPI for deterministic, occurrence-ordered comparison of visible relational plan structure. - Plantree traversal now preserves repeated DAG occurrences, rejects relational cycles, applies conservative depth and occurrence budgets, and uses occurrence-local parent-link classification.
- Added a machine-readable ecosystem matrix and a non-blocking pinned-reference integrity canary.
Breaking changes from v0.2.1
- Removed the deprecated
plantree.RowWithPredicates.Keysand.ChildLinks
fields. UseScalarChildLinksfor typed scalar child-link data. - Removed
plantree.ContinuationIndent,ContinuationIndentTree,
ContinuationIndentNodePrefix, andWithContinuationIndent. Use
WithHangingIndent()for node-prefix hanging; omit the option for the
tree-aligned default. - Removed the nested
github.com/apstndb/spannerplan/protoyamlcompatibility package. Importgithub.com/apstndb/protoyamldirectly. - Replaced
QueryPlan.GetLinkType(link)withQueryPlan.LinkTypeInParent(parent, rawChildLinkIndex). Consumers that filter child links must preserve the index from the parent’s rawChildLinksslice. - Removed the deprecated
rendertree --customand--full-scanforms. Use--custom-fileor repeatable--custom-column, and use--known-flagfor known flags. - Adding
Layouttoplantree/reference.RenderConfigcan break unkeyed Go struct literals; use keyed literals. - Plantree rendering and
StructuralSignaturenow reject plans deeper than 256
edges from the root or containing more than 4,096 visible node occurrences.
Handle these failures with
errors.Is(err, plantree.ErrTraversalLimitExceeded)and inspect
*plantree.TraversalLimitErrorwhen limit details are needed.
Compatibility and stability
This is the first non-prerelease release in the v0.3.0 train. It remains a ZeroVer (v0) release and does not promise v1 API stability. The structural-signature token remains spannerplan.structural_signature.v1alpha1 and may change in a future v0 release.
Existing rendering calls and serialized configurations continue to use the prior table layout when layout is omitted. The tableless output is human-oriented text: literal | characters are not escaped, trailing empty cells are omitted, and center-aligned cells are emitted without centering.
Downstream migrations were validated locally against v0.3.0-alpha.3, which
has the same library and CLI source as this release. The final source differs
from alpha.3 only in version-independent README release guidance. Consumers of
spannerplanviz need a version migrated from GetLinkType to occurrence-local
LinkTypeInParent; applications that depend on it transitively should upgrade
that dependency at the same time.
Verification
- Release commit:
6ec3ae9e5e567c70efb5216995037f6f77bce156 - Library and CLI source verified unchanged from
v0.3.0-alpha.3; the only
post-alpha.3 source change is README release guidance go test -v ./...with Go 1.24.13go vet ./...with Go 1.24.13golangci-lint v2.12.2with Go 1.24.13 — 0 issuesgovulncheck v1.5.0with Go 1.26.5 — no reachable vulnerabilities- Local alpha.3 migration gates for
spanner-mycli,spannerplanviz,rendertree-web,spannerplan-rs, and the unpublished TUI - Hosted
testandlintchecks for the README-only PR #62
v0.3.0-alpha.3
Highlights
- Added
asciitable.RenderTableless, which renders caller-defined rows without table borders or headers using a one-character|separator. Multiline cells, including empty physical lines, and display-width-aware right alignment are preserved without padding wide text columns back to table width. - Added
rendertree --layout=tablelessand the--tablelessshortcut. The existing table layout remains the default. - Added
plantree/reference.Layout, theLayoutTableandLayoutTablelessconstants,ParseLayout,WithLayout, andRenderConfig.Layoutso Go, WebAssembly, and JSON-configured consumers can select the tableless layout. - Added focused coverage for multiline rows, empty cells, wrapped compact plans, inline execution statistics, CLI flag conflicts, and reference renderer configuration.
Compatibility
Existing callers and serialized configurations remain on the byte-compatible table layout when the layout field is omitted or empty. Go callers should use keyed reference.RenderConfig literals; adding the Layout field can break unkeyed literals. The tableless representation is human-oriented text rather than an escaped serialization format: literal | is not escaped, trailing empty cells are omitted, empty physical lines and all-empty logical rows are preserved, and physical lines may contain different field counts. Center alignment is not supported by the unpadded tableless representation: center-aligned cells are emitted without centering.
Stability
This remains an intentionally unstable v0 prerelease. The new layout APIs and textual representation are not a stable v1 compatibility promise and may evolve during the v0.3.0 prerelease train.
Verification
go test -v ./...go vet ./...golangci-lint v2.12.2with Go 1.24.13 — 0 issues- Hosted pull-request
testandlintchecks on exact headedce8c7c7377d22b6a76a384fd98c1d5160e445b - Clean
origin/mainverification after squash merge
v0.3.0-alpha.2
Highlights
- Added the experimental
plantree.StructuralSignatureAPI for deterministic, occurrence-ordered comparison of visible relational plan structure. - The current encoding token is
spannerplan.structural_signature.v1alpha1. It includes operator display names, parent link types, recursively typed metadata, predicates, and ordered DAG occurrences while excluding PlanNode IDs and execution statistics. - Metadata encoding is byte-length framed and key-sorted. Invalid, non-JSON, or forward-unknown protobuf states fail closed instead of producing an ambiguous signature.
- Added
ecosystem/matrix.jsonas the machine-readable source for the ecosystem tables inECOSYSTEM.md, with validation and rendering checks. - Added a non-blocking scheduled/manual canary that verifies recorded public consumer refs and their pinned
go.moddependency content without claiming current downstream compatibility.
Stability
This remains an intentionally unstable v0 prerelease. The structural signature is a v1alpha1 experiment, not a stable v1 or cross-version interchange contract; its field set and encoding may change in later alpha releases. It is separate from any future external structured Plantree DTO.
Verification
go test ./...go vet ./...golangci-lint v2.12.2— 0 issuesgo run ./ecosystem/cmd/canary -live— all three recorded public pins passed- Pull-request CI for the ecosystem matrix/canary and structural signature changes
v0.3.0-alpha.1
Highlights
- Removed deprecated Go compatibility aliases and legacy Plantree row fields before v1.
- Removed the nested
github.com/apstndb/spannerplan/protoyamlcompatibility package. Usegithub.com/apstndb/protoyaml v0.1.1directly. - Removed the deprecated
rendertree --customand--full-scanforms. Custom columns remain available through--custom-fileand repeatable--custom-column; known flags use--known-flag. - Plantree traversal now preserves repeated DAG occurrences while rejecting relational cycles on the active traversal path.
- Replaced the ambiguous
QueryPlan.GetLinkType(link)API with occurrence-localQueryPlan.LinkTypeInParent(parent, rawChildLinkIndex), so shared and repeated child nodes receive the correct edge label. - Added conservative Plantree renderer budgets: depth 256 (root depth 0) and 4,096 visible occurrences. Budget failures are available as typed errors and may be raised non-breakingly as real Spanner captures justify it.
Compatibility
This is an intentionally breaking prerelease in the v0 line. Stable or v1 compatibility is not implied. Current first-party consumers have migrated from the removed surfaces.
Verification
go test ./...go vet ./...golangci-lint v2.12.2
v0.2.1
v0.2.1
Documentation and internal dependency housekeeping. No behavior changes; all rendered output and error strings are unchanged.
Added
ECOSYSTEM.md(#50): defines the roles of spannerplan, spannerplan-rs, spannerplanviz, and rendertree-web, the "text in libraries, rasterize at the edge" principle, governance rules (Go-first semantics changes, release-train-pinned parity CI, v0 semver policy), and a compatibility matrix.
Changed
- The input path (
ExtractQueryPlanand friends) now uses the extractedgithub.com/apstndb/protoyamlmodule (#51). Semantics are identical by construction (goccy YAML → protojson withDiscardUnknown); all tests pass with zero golden changes.
Deprecated
- The in-repo
protoyamlpackage is frozen and marked Deprecated (#51). ItsMarshaloutput format was never a designed artifact (an accident of reflection-based encoding). New code should usegithub.com/apstndb/protoyaml, which implements the canonical protojson-over-YAML mapping. The frozen package will be removed in v0.3.0 now that spanner-mycli has migrated (apstndb/spanner-mycli#784).
v0.2.0
Breaking Changes
Newnow returns*ValidationErrorfor plan validation failures, including empty plan input. Existingerrors.Is(err, ErrEmptyPlanNodes)and other category sentinel checks continue to work, and existing error message text is preserved. Code that compared returned errors by direct equality, such aserr == ErrEmptyPlanNodes, should switch toerrors.Is.
New Features
- Added
ErrInvalidPlan, an umbrella sentinel that matches every validation failure returned byNew. - Added
ValidationError, a structured validation error withKind,NodeIndex, andChildIndexfields so callers can inspect invalid plan input without depending on message text. Newnow wraps bothErrInvalidPlanand the specific category sentinel for each validation failure, so callers can choose either broad or specificerrors.Ischecks.- Added executable documentation through
ExampleNew_invalidPlan, showing botherrors.Isanderrors.Asusage.
Compatibility Notes
- Existing validation error strings are intentionally preserved in this release.
- Existing category sentinels still match through
errors.Is. - There are no dependency, CLI, or rendering-output changes in this release.
Validation
go test -v ./...go vet ./...golangci-lint run --timeout=5mgit diff --check v0.1.11..HEAD
v0.1.11
v0.1.11
Patch release after v0.1.10.
Added
- Added intent-based scalar appendix print presets:
basic,enhanced,full, andnone(#45). - Added preset parsing for
rendertree --printandplantree/reference.ParsePrintSections, while preserving comma-separated low-level section names (#45). - Added public
plantree/reference.PrintPreset,ParsePrintPreset,PrintPreset.Sections, andNewPrintSectionshelpers so callers can preserve thenildefault versus explicit-emptyPrintSectionsdistinction (#45). - Added regression coverage for preset parsing, explicit empty/blank appendix suppression, preset/list validation, CLI config behavior, and public reference helpers (#45).
- Added repository-level Gemini Code Assist configuration with
code_review.comment_severity_threshold: HIGH(#46).
Changed
- Updated
rendertree --printhelp and README documentation to describe the new preset values and explicit empty suppression behavior (#45). - Improved repository README navigation with a pkg.go.dev badge and clearer package, command, example, and helper directory overview (#42).
- Reorganized
cmd/rendertreeREADME sections into a clearer hierarchy (#42).
Validation
git diff --check v0.1.10..origin/maingo test ./...mise x -- golangci-lint run --timeout=5m
v0.1.11-alpha.1
v0.1.11-alpha.1
Alpha prerelease for the next patch release after v0.1.10.
Added
- Added intent-based scalar appendix print presets:
basic,enhanced,full, andnone(#45). - Added preset parsing for
rendertree --printandplantree/reference.ParsePrintSections, while preserving comma-separated low-level section names (#45). - Added public
plantree/reference.PrintPreset,ParsePrintPreset,PrintPreset.Sections, andNewPrintSectionshelpers so callers can preserve thenildefault versus explicit-emptyPrintSectionsdistinction (#45). - Added regression coverage for preset parsing, explicit empty/blank appendix suppression, preset/list validation, CLI config behavior, and public reference helpers (#45).
- Added repository-level Gemini Code Assist configuration with
code_review.comment_severity_threshold: HIGH(#46).
Changed
- Updated
rendertree --printhelp and README documentation to describe the new preset values and explicit empty suppression behavior (#45). - Improved repository README navigation with a pkg.go.dev badge and clearer package, command, example, and helper directory overview (#42).
- Reorganized
cmd/rendertreeREADME sections into a clearer hierarchy (#42).
Validation
git diff --check v0.1.10..origin/maingo test ./...mise x -- golangci-lint run --timeout=5m
v0.1.10
Patch release for the rendering-helper and scalar-appendix work merged after v0.1.9.
Added
- Added the public
treerenderpackage for generic ASCII tree rendering.- Provides
Render,RenderTree, andRenderTreeWithOptions. - Provides
DefaultStyleandCompactStyle. - Supports wrapping through
RenderOptions.WrapWidth. - Supports continuation indentation modes including fixed-prefix and anchor-based hanging indentation.
- Exposes
Row.Text,Row.TreePartLines,PrefixMetrics, and related helpers for callers that need stable tree-prefix handling.
- Provides
- Added the public
asciitablepackage for aligned table and appendix rendering.- Provides
RenderTablewith typedTableSpecandColumndefinitions. - Provides
RenderAppendixwith typedAppendixSpecdefinitions. - Supports left, right, and center alignment.
- Preserves multiline table cells without wrapping them unexpectedly.
- Provides
- Added
examples/pgexplainjson, a dependency-free PostgreSQLEXPLAIN (ANALYZE, FORMAT JSON)renderer that demonstrates the generictreerenderandasciitablehelpers.- Supports compact tree output.
- Supports total-width wrapping.
- Generates preorder IDs for PostgreSQL plans, which do not provide stable plan-node IDs.
- Added scalar child-link accessors and documentation in
plantree.RowWithPredicates.TreePartLinesexposes tree prefixes as one line per rendered node-text line.RowWithPredicates.ScalarChildLinkspreserves scalar child links in originalPlanNode.ChildLinksorder.ScalarChildLinkcarries child index, type, variable, description, and the scalar child node.RowWithPredicates.KeysandRowWithPredicates.ChildLinksremain populated as compatibility mirrors.
- Added scalar appendix controls to
cmd/rendertree.--print=predicates,ordering,aggregateselects semantic appendix sections.--print=typedprints all typed scalar links as a raw debug dump.--print=fullprints all scalar links, including unnamed links, as a raw debug dump.--print=""suppresses appendix output.--show-varsshows scalar assignment variable names.--resolve-varsresolves direct scalar variable aliases.--resolve-vars-recursiverecursively expands scalar variable aliases for investigation.
- Added scalar appendix controls to
plantree/reference.- Added
PrintSection,PrintSections,ParsePrintSection, andParsePrintSections. - Added
WithPrintSections,WithShowScalarVars,WithResolveScalarVars, andWithResolveScalarVarsRecursive. - Extended
RenderConfigwithPrintSections,ShowScalarVars,ResolveScalarVars, andResolveScalarVarsRecursive. RenderConfig.PrintSectionsdistinguishes omitted/null config from an explicit empty list, so JSON[]can intentionally suppress appendices.
- Added
- Added the shared internal
internal/scalarappendixpackage used by bothcmd/rendertreeandplantree/reference.- Centralizes scalar appendix parsing, validation, rendering, and scalar variable resolution.
- Keeps public packages as facades rather than exposing internal symbols.
- Added Gemini review style-guide guidance to avoid readability-reducing micro-optimizations and to treat JSON tags as API design choices.
Changed
cmd/rendertreenow reuses the shared scalar appendix implementation instead of carrying its own separate section parsing and rendering logic.plantree/referencenow renders appendices through the shared scalar appendix implementation.asciitableappendix rendering was generalized beyond predicates throughAppendixSpecandRenderAppendix.treerenderis now public instead of only being available under an internal package.- The unreleased predicate-specific
asciitablecompatibility API from the development branch was replaced by the more general appendix API before release. treerenderhanging-indent validation now requiresGetContinuationAnchoronly when wrapping is active.- The golangci-lint GitHub Actions workflow is pinned to a concrete v2 release.
- Local review scratch files are ignored by git.
Fixed
WithHangingIndentandRenderConfig{HangingIndent: true}no longer fail when no wrap width is configured; without wrapping, hanging indent is a no-op.- Empty print-section strings now parse as an explicit empty section list, allowing callers to suppress appendix output.
- Scalar appendix JSON config preserves explicit empty
printSectionsslices while still treating omitted/null as the default predicate appendix.
Merged PRs
- #39:
feat: expose generic render helpers - #40:
feat: add scalar appendix sections - #41:
refactor: share scalar appendix rendering
Validation
go test ./...mise x -- golangci-lint run --timeout=5mgit diff --check v0.1.9..origin/main
v0.1.9
Changes
Added
- Added
QueryPlan.ParentLinks(childIndex)to return every incoming parent child link for a plan node, preserving stable plan traversal order and each parent'sChildLinksorder. - Added
ResolvedParentLink, containing the parentPlanNodeand theChildLinkthat points to the child node. - Added support for treating scalar Full Text Search
Search Predicatechild links as predicates inQueryPlan.IsPredicate, so downstream renderers can surface Full Text Search predicates without custom plan-shape logic. - Added QueryPlan, plantree, and reference renderer tests for simple and compound Full Text Search predicate shapes.
- Added tests covering duplicate incoming links from the same parent, incoming links from multiple parents, empty and out-of-range
ParentLinkslookups, returned-slice isolation, and compatibility with existing single-parent lookup behavior.
Changed
- Preserved existing
GetParentNodeByChildIndexbehavior while adding the all-parent-links API, keeping the existing single-parent map compatible for current callers. - Clarified
QueryPlan.IsVisibledocumentation: it controls operator-tree child-link visibility, hides scalar plan nodes unless the child link type isScalar, and treats nil links as the root node.