From dd67034eec47189db8bf9f16e965811c662c9bcc Mon Sep 17 00:00:00 2001 From: Kiran Muddukrishna Date: Fri, 11 Sep 2026 11:13:16 +1000 Subject: [PATCH 1/3] docs: add capabilities query recipes Help people and automation query the same embedded support matrix that generates the documentation, without scraping Markdown or connecting to a database. --- README.md | 3 +++ docs/capabilities-contract.md | 2 +- docs/capabilities.md | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5585ccd..e1a9342 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ build plan live in [docs/](docs/) — start with is [docs/vision.md](docs/vision.md); the canonical support matrix — is this change supported today, planned, or out of scope — is [docs/capabilities.md](docs/capabilities.md). +The same embedded matrix is queryable for automation with +`pg-sprite capabilities --json`. ## What pg-sprite does not do yet @@ -179,6 +181,7 @@ ever commits a change — every other command is read-only or fully offline. | `diff` | required | Introspect the live table (read-only) and materialize the desired-state file on a scratch schema inside a transaction that is always rolled back; prints the plan, changes nothing | | [`pull`](docs/pull.md) | required | Introspect each supported table in a schema and create one desired-state file per table; existing files are never overwritten, and a zero-change `diff` verifies the baseline | | `status` | required | Read-only view over `pg_stat_activity` for live pg-sprite sessions on the connected database | +| `capabilities` | none | Print the embedded support matrix as a compact table, or as the versioned automation contract with `--json` | | `fmt` | none | Canonicalize a schema file — parser only | | `lint` | none | Flag patterns the engine would refuse, rewrite, or gate, from the DDL text alone | | `suggest` | none | Map risky DDL to the safer native form the engine would run, with typed caveats; advisory, always exits 0 | diff --git a/docs/capabilities-contract.md b/docs/capabilities-contract.md index bbf736c..a8d1c17 100644 --- a/docs/capabilities-contract.md +++ b/docs/capabilities-contract.md @@ -268,7 +268,7 @@ Implementation order is, with each step marked as it ships: 2. add `pg-sprite capabilities`, including `--json` and the embedded binary version; *(done)* 3. add the regenerate-and-diff CI gate to the normal pipeline; and *(pending)* -4. add documentation and `jq` recipes for consumers. *(pending)* +4. add documentation and `jq` recipes for consumers. *(done)* The generator is part of the first step rather than a cleanup step: there is never an intermediate state in which two hand-maintained matrices are authoritative. diff --git a/docs/capabilities.md b/docs/capabilities.md index 757a9b4..a3ad879 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -12,6 +12,7 @@ refused form would take, what an operator who accepts a maintenance window can d ## Contents +- [Query the matrix](#query-the-matrix) - [What pg-sprite is — and why it exists](#what-pg-sprite-is--and-why-it-exists) - [The support model: three tiers](#the-support-model-three-tiers) - [The engine path](#the-engine-path) @@ -28,6 +29,25 @@ refused form would take, what an operator who accepts a maintenance window can d - [Why typed refusal, not passthrough](#why-typed-refusal-not-passthrough) - [Deliberately operator-owned](#deliberately-operator-owned) +## Query the matrix + +This page is generated from the matrix embedded in the pg-sprite binary. Run +`pg-sprite capabilities` for a compact table, or use `pg-sprite capabilities --json` +for automation. Both forms read embedded data only and do not connect to PostgreSQL. +The [machine-readable capabilities contract](capabilities-contract.md) defines the JSON +schema and versioning rules. + +```sh +# All T2 rows. +pg-sprite capabilities --json | jq '.capabilities[] | select(.tier == "t2")' + +# Everything the declarative door refuses. +pg-sprite capabilities --json | jq '.capabilities[] | select(.front_doors.diff == "refused")' + +# Rows owned by another tool class. +pg-sprite capabilities --json | jq '.capabilities[] | select(.owning_tool_class != null)' +``` + ## What pg-sprite is — and why it exists pg-sprite is an **online schema-change engine** for PostgreSQL: it takes one table-shape From e72510e9c837cad4f376a1e2c0b49073a2b2a179 Mon Sep 17 00:00:00 2001 From: Kiran Muddukrishna Date: Fri, 11 Sep 2026 13:36:08 +1000 Subject: [PATCH 2/3] docs: keep capabilities recipes canonical Clarify that only marker-delimited support tables are generated from the YAML source of truth. Keep operator jq recipes in the capabilities guide and link to them from the contract doc. --- docs/capabilities-contract.md | 16 ++++------------ docs/capabilities.md | 7 ++++--- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/docs/capabilities-contract.md b/docs/capabilities-contract.md index a8d1c17..481bce1 100644 --- a/docs/capabilities-contract.md +++ b/docs/capabilities-contract.md @@ -172,18 +172,10 @@ Array order is source order and therefore stable for display, but consumers shou select by fields or `id`, not array position. The command reads only embedded data and does not connect to PostgreSQL. -The contract must support these queries: - -```sh -# All T2 rows. -pg-sprite capabilities --json | jq '.capabilities[] | select(.tier == "t2")' - -# Everything the declarative door refuses. -pg-sprite capabilities --json | jq '.capabilities[] | select(.front_doors.diff == "refused")' - -# Rows owned by another tool class. -pg-sprite capabilities --json | jq '.capabilities[] | select(.owning_tool_class != null)' -``` +The contract must support the `jq` recipes in the operator guide's +[Query the matrix](capabilities.md#query-the-matrix) section: selecting rows by tier, +by a front door's disposition, and by owning tool class. That section is the one copy of +the recipes; this contract only fixes the field names they select on. Human output may render a compact table, but JSON field names and enum values are the automation contract. Stable JSON means deterministic content and closed vocabulary; diff --git a/docs/capabilities.md b/docs/capabilities.md index a3ad879..0925a95 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -31,9 +31,10 @@ refused form would take, what an operator who accepts a maintenance window can d ## Query the matrix -This page is generated from the matrix embedded in the pg-sprite binary. Run -`pg-sprite capabilities` for a compact table, or use `pg-sprite capabilities --json` -for automation. Both forms read embedded data only and do not connect to PostgreSQL. +The marker-delimited regions of this page are generated from +`pkg/capabilities/capabilities.yaml`; the surrounding guidance is hand-written. Run +`pg-sprite capabilities` for a compact table, or use `pg-sprite capabilities --json` for +automation. Both forms read the embedded YAML data only and do not connect to PostgreSQL. The [machine-readable capabilities contract](capabilities-contract.md) defines the JSON schema and versioning rules. From 420c7d6b21d7c3a331bf5a0d4e39346bf2bc7dbb Mon Sep 17 00:00:00 2001 From: Kiran Muddukrishna Date: Fri, 11 Sep 2026 13:59:56 +1000 Subject: [PATCH 3/3] docs: make the jq recipes answer the questions consumers ask MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Query-the-matrix recipes selected by tier, by one door's disposition, and by owning tool class, but each was either redundant with a tier filter or silently incomplete. Add a lookup by id (the first thing a consumer asks) and a filter by engine_path (a roadmap cut no tier filter can express). Note that both doors carry the same disposition on every row today, so the door filter is a hook for future divergence, not a way to find differences. Note that the owning-tool-class filter returns only the white and blue rows: the red rows name no owner because PostgreSQL has no online mechanism for them, so the filter is not the full out-of-scope set. Carry the contract's "select by fields or id, never by array position" rule onto the operator page next to the recipes, so the guidance travels with the commands it governs. The contract's summary of the recipe kinds now lists id lookup and engine path too. The contract's step list said "implementation order", but the recipes never depended on the CI gate: reword the lead-in so only the first step is a prerequisite and the rest land independently, which is what the done/pending marks already show. 🤖 Generated with Amp (Claude Opus 4.6) --- docs/capabilities-contract.md | 10 ++++++---- docs/capabilities.md | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/docs/capabilities-contract.md b/docs/capabilities-contract.md index 481bce1..4592d88 100644 --- a/docs/capabilities-contract.md +++ b/docs/capabilities-contract.md @@ -173,9 +173,10 @@ select by fields or `id`, not array position. The command reads only embedded da does not connect to PostgreSQL. The contract must support the `jq` recipes in the operator guide's -[Query the matrix](capabilities.md#query-the-matrix) section: selecting rows by tier, -by a front door's disposition, and by owning tool class. That section is the one copy of -the recipes; this contract only fixes the field names they select on. +[Query the matrix](capabilities.md#query-the-matrix) section: looking a row up by `id`, +and selecting rows by tier, by engine path, by a front door's disposition, and by owning +tool class. That section is the one copy of the recipes; this contract only fixes the +field names they select on. Human output may render a compact table, but JSON field names and enum values are the automation contract. Stable JSON means deterministic content and closed vocabulary; @@ -253,7 +254,8 @@ artifact. The generated `docs/capabilities.md` remains the human-facing home. This decision does not build sortable HTML tables or a documentation site. It also does not change any capability, tier, refusal, or runtime behavior. -Implementation order is, with each step marked as it ships: +Implementation proceeds in these steps, each marked as it ships. Only the first step is a +prerequisite for the others; the rest land independently: 1. add the typed package, `pkg/capabilities/capabilities.yaml`, validator, generator, and markers together, making the repository single-source on day one; *(done)* diff --git a/docs/capabilities.md b/docs/capabilities.md index 0925a95..cc479ce 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -36,16 +36,25 @@ The marker-delimited regions of this page are generated from `pg-sprite capabilities` for a compact table, or use `pg-sprite capabilities --json` for automation. Both forms read the embedded YAML data only and do not connect to PostgreSQL. The [machine-readable capabilities contract](capabilities-contract.md) defines the JSON -schema and versioning rules. +schema and versioning rules. Array order is source order and stable for display, but select +rows by `id` or by field, never by array position. ```sh +# Is this one operation supported today? Look a row up by its id. +pg-sprite capabilities --json | jq '.capabilities[] | select(.id == "add-column-no-default-or-constant-default")' + # All T2 rows. pg-sprite capabilities --json | jq '.capabilities[] | select(.tier == "t2")' -# Everything the declarative door refuses. +# What is waiting on the copy engine, across tiers. +pg-sprite capabilities --json | jq '.capabilities[] | select(.engine_path == "copy_and_swap")' + +# Everything the declarative door refuses. Both doors carry the same disposition on +# every row today; the map exists so they can diverge, so query the door you use. pg-sprite capabilities --json | jq '.capabilities[] | select(.front_doors.diff == "refused")' -# Rows owned by another tool class. +# Rows another tool class owns: the ⚪ and 🔵 rows. The ❌ rows name no owner, because +# PostgreSQL offers no online mechanism for them, so this is not the full out-of-scope set. pg-sprite capabilities --json | jq '.capabilities[] | select(.owning_tool_class != null)' ```