Skip to content

docs: record the machine-readable capabilities matrix contract - #95

Merged
Kiran01bm merged 4 commits into
mainfrom
kiran01bm/cm1-capabilities-contract
Sep 9, 2026
Merged

docs: record the machine-readable capabilities matrix contract#95
Kiran01bm merged 4 commits into
mainfrom
kiran01bm/cm1-capabilities-contract

Conversation

@Kiran01bm

@Kiran01bm Kiran01bm commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Records the single-source, machine-readable contract for pg-sprite's capabilities matrix.

Why

The support matrix is a public product contract, but its Markdown tables cannot be consumed safely by CLI users, automation, or CI. We need one typed source that preserves the readable page while giving machines stable fields and closed vocabularies.

What

  • Decide on one validated YAML source embedded by pkg/capabilities.
  • Define the lossless row schema, front-door coverage, engine paths, and the refusal vocabulary the matrix shares with verdicts (a verdict class field is a separate decision; the matrix uses the same words when it ships).
  • Specify marker-based Markdown generation — per-section table markers plus a summary pair around the derived per-tier counts — and a regenerate-and-diff CI gate.
  • Specify the versioned-at-the-binary JSON shape and concrete jq queries.
  • Record rejected JSON, Go-literal, and dual-maintenance alternatives and the implementation sequence.

Shape

┌───────────────────────┐     ┌──────────────────────┐     ┌────────────────────────┐
│ capabilities.yaml     │────▶│ Markdown generator   │────▶│ capabilities.md tables │
└───────────┬───────────┘     └──────────┬───────────┘     └───────────┬────────────┘
            │                            │                             │
            │ go:embed                   │ regenerate                  │ committed
            ▼                            ▼                             ▼
┌───────────────────────┐     ┌─────────────────────────────────────────────────────┐
│ pkg/capabilities      │     │ CI gate: regenerate, then require an empty git diff │
└───────────┬───────────┘     └─────────────────────────────────────────────────────┘
            │
            ▼
┌────────────────────────────────────────┐
│ pg-sprite capabilities --json          │
└────────────────────────────────────────┘

🤖 Drafted with Amp (Claude Opus 4.6); reviewed and edited by the author.

@Kiran01bm
Kiran01bm marked this pull request as ready for review September 9, 2026 22:56
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Kiran01bm
Kiran01bm merged commit 3f47c51 into main Sep 9, 2026
9 checks passed
Kiran01bm added a commit that referenced this pull request Sep 9, 2026
Add a machine-readable refusal class contract so consumers can route
every refusal without reinterpreting overloaded reason strings.

## Why

Existing refusal reasons explain the immediate cause but conflate
capability gaps, work owned by another tool class, permanent safety
decisions, run-site conditions, and pg-sprite's own defects.
`unsupported-statement` and `unsupported-partitioned-parent` each span
several of those categories, and the split runs one level below the
reason: along the typed cause (`PartitionRefusalCause`,
`CreateShapeCause`, admission sentinels) that the code already carries.

## What

- Define five additive classes: `capability-boundary`,
`no-online-safety-problem`, `by-design`, `environmental`, and
`invariant-violation` (the refusal-verdict face of the fail-closed
`ErrInvariantViolation` rule).
- Define structured owner values for `no-online-safety-problem` routing:
`data-change-runner`, `provisioning`, `direct-operator` (the ⚪ half of
T3), `declarative-front-door`.
- Key the map on the typed cause where one exists and on the refusal
site where none does: one table per cause set, plus the site-keyed table
for the rest. Name the parse-boundary work (`pkg/statement`
distinguishing the kinds behind the `KindOther` catch-all) that
classification requires.
- Pin the map to the code: `docs_test.go` guards in `pkg/verdict`,
`pkg/executor`, and `pkg/preflight` fail when a `Reason`,
`CreateShapeCause`, or `PartitionRefusalCause` exists without a row
(adds `preflight.PartitionRefusalCauses()`).
- Cite RF-5 (what `by-design` encodes) and RF-6 (which already separates
the not-implemented from the version-gated partitioned-parent case);
name the invariant rollout step 2 adds once the field ships.
- Bring `capabilities-contract.md`'s shared-vocabulary section into
agreement (fifth class, `direct-operator`), and add the design to the
documentation index.

Ordering: #95 (capabilities contract) has merged, so the cross-link here
is live. #96 (CI runs Go tests on docs-only PRs) is independent; this PR
touches Go test files, so full CI runs on it regardless.

## Before / after

Two refusals with the same `reason`, `unsupported-partitioned-parent`,
on PostgreSQL 16:

```text
Before: the consumer sees one reason and cannot tell the two apart

  CREATE INDEX ... ON parts_parent (col)           ALTER TABLE parts_parent
      │                                              ADD FOREIGN KEY ... NOT VALID
      ▼                                                  │
  refused, reason: unsupported-partitioned-parent        ▼
  (the partition-aware build is not implemented yet)  refused, reason: unsupported-partitioned-parent
      │                                              (PostgreSQL 16 cannot do this; 18 can)
      ▼                                                  │
  consumer: "unsupported" — wait? upgrade? give up?      ▼
                                                     consumer: the same guess, same reason string

After: the class is read off the typed cause, so each refusal names its own next step

  CREATE INDEX ... ON parts_parent (col)           ALTER TABLE parts_parent
      │                                              ADD FOREIGN KEY ... NOT VALID
      ▼                                                  │
  cause: parent-concurrent-index-build                   ▼
      │                                              cause: parent-not-valid-foreign-key
      ▼                                                  │
  reason: unsupported-partitioned-parent                 ▼
  class:  capability-boundary                        reason: unsupported-partitioned-parent
      │                                              class:  environmental
      ▼                                                  │
  consumer: wait for the pg-sprite release               ▼
            that adds the partition-aware flow       consumer: upgrade the server to 18; same
                                                               statement and same pg-sprite then run
```

The other cause sets follow the same rule: a `CREATE INDEX CONCURRENTLY`
on a table born this run is `by-design` (use the plain build), and a
`planRefusal` for a disposition this build does not know is
`invariant-violation` (report a pg-sprite bug, do not wait or retry).

🤖 Drafted with Amp (Claude Opus 4.6); reviewed and edited by the author.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants