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..4592d88 100644 --- a/docs/capabilities-contract.md +++ b/docs/capabilities-contract.md @@ -172,18 +172,11 @@ 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: 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; @@ -261,14 +254,15 @@ 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)* 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..cc479ce 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,35 @@ 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 + +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. 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")' + +# 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 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)' +``` + ## What pg-sprite is — and why it exists pg-sprite is an **online schema-change engine** for PostgreSQL: it takes one table-shape