Skip to content

docs: COMPATIBILITY.md declaring the external consumer guarantees - #264

Merged
rubenhensen merged 4 commits into
mainfrom
docs/252-compatibility
Jul 28, 2026
Merged

docs: COMPATIBILITY.md declaring the external consumer guarantees#264
rubenhensen merged 4 commits into
mainfrom
docs/252-compatibility

Conversation

@dobby-coder

@dobby-coder dobby-coder Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Closes #252

Writes down what external consumers can rely on, per the spec in the issue body and the support-window numbers proposed in rubenhensen's comment.

What is in the doc

  • Hosted API. /v2 is additive only; a change that cannot be made additively ships under a new prefix with /v2 left running. Enforcement is written as planned (ci: breaking-change gate on api-description.yaml (oasdiff) #249), not as present-tense fact. The /v2/irma alias is written up as deprecated, which is the step-1 announcement #257 asks for.
  • Stored artifacts. Read support never drops, starting at container format VERSION_V3. The doc states plainly that VERSION_V1/VERSION_V2 predate the guarantee and are already rejected by preamble_checked, rather than implying every container ever written still opens.
  • SDK support windows. Your five bullets, unchanged: last two pg-js majors, every pg-wasm a supported pg-js resolves, last E4A.PostGuard major with 0.x as one line, last two pg-core minors, 12 months plus telemetry.
  • Reader list. The window resolved to concrete pins, in a fenced block with a <registry> <package> <versions...> shape so the gates can parse it out of the markdown. Named the four planned consumers, all still open issues, and stated that a gate needing different readers changes this file first.
  • Deprecation. Announce, observe, remove, with the postguard_clients metric named as the observation source and privacybydesign/postguard-ops#64 as the blocker on step 2.

The pins

Checked against the live registries today, not copied from the issue:

crates.io pg-core 0.6.1 0.5.10
npm @e4a/pg-wasm 0.6.1
npm @e4a/pg-js 2.3.3 1.11.0
nuget E4A.PostGuard 0.6.0

Derivation rule is in the doc: highest published patch of each line in the window. pg-wasm resolves to a single version because both @e4a/pg-js@2.3.3 and @e4a/pg-js@1.11.0 depend on ^0.6.1.

Two numbers differ from what the thread and the tooling say, both deliberately:

  • The comment says pg-wasm is "currently 0.6.x" while pg-wasm/Cargo.toml says 0.5.5. npm is right. delivery.yml's publish-wasm job writes pkg/package.json from scratch and stamps it with the released pg-core version, so the crate manifest version never reaches npm. Added this to CLAUDE.md, since it will bite whoever writes the reader-install step in compat gate: published pg-wasm/pg-js old-reader step (Node) #261.
  • postguard-e2e's compat/manifest.json has pg-dotnet.current at 0.5.0, but NuGet serves 0.6.0. That looks like a pending auto-bump on their side rather than something to encode here, so the doc uses the published version. Worth a look if the bump job has been quiet.

Parse check

The block parses with a four-line reader, which is what #260 and #261 will need:

sec = md.split('## Reader list', 1)[1]
block = re.search(r'```\n(.*?)```', sec, re.S).group(1)
for line in block.splitlines():
    if line.strip() and not line.startswith('#'):
        registry, package, *versions = line.split()

Checks

Doc-only, no workflow files. Ran the suite per CLAUDE.md anyway: pg-core (--features test,rust,stream), pg-pkg, pg-cli, pg-ffi all green, cargo fmt --all -- --check clean. The claims about VERSION_V3, the irma|request alias and wire_format.rs were each checked against the code rather than taken from the API description prose.

One thing to decide

The pins live in markdown because you asked for a doc-only PR, so "the document and the test matrix are the same list" holds only as long as the gates parse this file. If you would rather the gates read structured data, the natural move is a compat/readers.json in this repo that COMPATIBILITY.md renders from, or extending postguard-e2e's compat/manifest.json with a window block alongside current. Say which and I will follow up; I did not want to invent the format inside a doc PR.

Review cycle 1

Both blocking items from the consolidated review are fixed in 1a8db6c.

The alias paragraph cited #257 as the reason the alias is kept, while #257 asks to deprecate and remove it and names this file as the place to announce that. It now reads as the announcement: both prefixes still serve the same handlers, the alias is deprecated, new clients use /v2/request/..., removal runs through the process at the bottom of the file, and a deployed client on the alias is not broken by the notice. The spec's own alias note in api-description.yaml is left alone, since editing the promised surface is #257's job.

The reader-list section said the gates install and run this list. All six cited gates are still open issues, checked again just now, so both anchors are hedged the way the /v2 and fixture-corpus sections already were, and the postguard-js#131 envelope gate one section up is now "planned in" too. The list itself did not change.

The reviewer's aside that #265 pins only pg-core =0.6.1 and misses the 0.5.10 this list declares is real, but it is a change to that PR, not this one. Left for #265.

Re-ran the pins against crates.io, npm and NuGet after the edits: unchanged, and both @e4a/pg-js@2.3.3 and @e4a/pg-js@1.11.0 still depend on @e4a/pg-wasm@^0.6.1. The four-line parse check still returns four rows. cargo fmt --all -- --check clean, pg-core (--features test,rust,stream), pg-pkg, pg-cli and pg-ffi green.

Writes down what external consumers can rely on: /v2 additive-only endpoint
stability, the archival read guarantee for containers and envelopes, the SDK
support windows, and the announce/observe/remove deprecation process.

The support window is resolved to a concrete reader list in a parseable block,
so the wire-compat gate (#251, #260, #261), the forward-direction fixture job
and the version sweep can install exactly the versions this file declares.
Pins verified against npm, crates.io and NuGet on 2026-07-27.

Also records in CLAUDE.md that @e4a/pg-wasm's npm version is stamped from the
released pg-core version, not from pg-wasm/Cargo.toml.

Closes #252

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dobby-coder
dobby-coder Bot requested a review from rubenhensen July 27, 2026 15:48

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: request-changes

Rules Dobby 2, cycle 1. Doc-only PR, so the sweep was the docs/process rules: cross-repo link format, closing keywords, conventional PR title, the writing rules, standardized READMEs, and patch-in-comment-gate-is-not-live-yet.

Clean on the process side. Title matches the pr-title.yml semantic check, Closes #252 is same-repo and on its own line against main, rubenhensen is assigned, every cross-repo reference uses a full markdown reference link, and the prose has no banned words, no em dashes and no bold. The reader-list block parses. The pins were spot-checked and the VERSION_V3 and irma|request claims hold (pg-pkg/src/server.rs:308 serves both prefixes).

Two things to fix, both in COMPATIBILITY.md.

1. The /v2/irma alias is presented as kept, but #257 says deprecate and remove, and names this file as the place to announce it. #257's body: "deprecate and remove the /v2/{irma} alias (request is canonical)", process "announce in COMPATIBILITY.md, observe postguard_clients, remove". Line 23 cites #257 as if it supported keeping the alias. Two consequences: an external reader following the link lands on an issue arguing the opposite, and this document's own Deprecation step 1 goes unperformed for the one surface that already has a tracked deprecation.

2. "The gates that execute this list" is present tense, and none of them exist yet. All six cited gates (#251, #260, #261, postguard-e2e#25, postguard-e2e#21, postguard-js#131) are open issues. The Rust half in #265 pins only pg-core =0.6.1, omitting the 0.5.10 this list declares, and its own workflow YAML sits in a PR comment awaiting a maintainer. The document hedges correctly two sections earlier ("Planned enforcement: an oasdiff gate...", "Planned: the append-only corpus..."); the Reader list section should hedge the same way. The list itself is right, the claim about who runs it is not.

One non-blocking note on the postguard-ops#64 link, inline below. Do not change it without asking a maintainer.

Not flipping this out of draft while changes are requested.

Comment thread COMPATIBILITY.md Outdated
Comment thread COMPATIBILITY.md Outdated
Comment thread COMPATIBILITY.md Outdated
Comment thread COMPATIBILITY.md
dobby-coder Bot and others added 2 commits July 27, 2026 16:15
Review cycle 1 on #264 flagged two claims in COMPATIBILITY.md.

The alias paragraph cited #257 as the reason the alias is kept, while #257
asks to deprecate and remove it and names this file as the announcement
venue. The paragraph now carries that announcement: both prefixes still
serve the same handlers, the alias is deprecated, new clients use
/v2/request/..., and removal runs through the process at the bottom of the
file. Deployed clients are unaffected until then.

The reader-list section claimed the compat gates install and run the list
today. All six cited gates (#251, #260, #261, postguard-e2e#21,
postguard-e2e#25, postguard-js#131) are still open issues, so the section
now hedges the way the two sections above it already do.
Step 1 required the announcement in a release changelog entry AND next to
the item, but release-plz generates changelogs from commit subjects and
inserts each version section below the [Unreleased] header, so a hand-written
bullet there is never carried into a dated release. A doc-only announcement
could not satisfy the step, leaving step 3 gating removal on a window with
no start date.

Step 1 now asks for the date next to the item, with the changelog entry
following in the next release of the affected component, and the /v2/irma
alias carries its start date.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: approve

Rules Dobby 2, cycle 2. Sign-off. Reviewed 1a8db6c, then fixed the one open nit myself in a765096 — no bug-severity findings, so this does not go back for another coder cycle.

Rule sweep

Doc-only diff (COMPATIBILITY.md new, one CLAUDE.md bullet, one README.md sentence), so the sweep was the docs/process set: cross-repo link format, closing keywords, conventional PR title, the writing rules, standardized READMEs, no-justification-paragraphs, patch-in-comment-gate-is-not-live-yet, oasdiff-action defaults, self-trigger loops. All clean.

Worth naming because it is the rule this kind of PR usually trips: patch-in-comment-gate-is-not-live-yet, checked in both directions. Every gate the doc names is hedged (Planned enforcement, is planned in, None of those gates runs yet, each still an open issue), and the one thing claimed as live — pg-core/tests/wire_format.rs over the testdata/wire-format-v3/ fixtures — really does run on every PR via build.yml. Nothing understated in the other direction either. .github/workflows/ holds only build.yml, delivery.yml, pr-title.yml, and the doc claims no gate beyond that.

Spot-checked the doc's factual claims against the tree rather than the prose: VERSION_V3 = 2 in pg-core/src/consts.rs, preamble_checked in pg-core/src/util.rs:36 rejecting anything but V3 with Error::IncorrectVersion, the postguard_clients metric in pg-pkg/src/server.rs:31, and the scope("/{_:(irma|request)}") alias in pg-pkg/src/server.rs:308. All accurate. The reader-list block still parses to 4 rows with the four-line reader in the PR body.

The cycle-1 nit, and why I fixed it the other way

The nit was that step 1 of the deprecation process required the announcement in a release changelog entry and next to the item, while this PR only does the second half — so step 3, which gates removal on "the window has expired", had no dated start.

The reviewer offered two cheap fixes. I did not take the first one (add a ### Deprecated bullet under ## [Unreleased] in pg-pkg/CHANGELOG.md) because it does not work in this repo: release-plz.toml sets no changelog template, so entries are generated from commit subjects, and every version section is inserted below the ## [Unreleased] header — visible in all five crate changelogs, each of which has an empty [Unreleased]. A hand-written bullet there would sit above the next release rather than becoming part of it, and would never get dated. It would have looked like a fix while leaving the clock exactly as unstarted.

So I took the second option, in a765096:

  • Step 1 now asks for the date next to the item, with the changelog entry following in the next release of the affected component, and says plainly that an announcement without a date does not start the window. That keeps the clock-start requirement, which is the part with teeth, without demanding a release a doc-only announcement cannot produce.
  • The /v2/irma alias paragraph now reads "deprecated as of 2026-07-27", so the 12-month window has a concrete start.

Nothing else changed. Reader list untouched, pins untouched, parse check still 4 rows, no em dashes or bold introduced.

Left alone deliberately

pg-pkg/api-description.yaml:17-19 still describes the alias as "a legacy alias kept for deployed clients" with no deprecation marker. Editing the promised surface is #257's job, step 1's or permits announcing in this file instead, and the author already argued this in the resolved cycle-1 thread. Informational, not a re-open.

The #265 pin gap the cycle-1 reviewer noted (it pins pg-core =0.6.1 and misses the 0.5.10 this list declares) is real but belongs to that PR.

One open question for you, unchanged from the PR body

The pins live in markdown, so "the document and the test matrix are the same list" holds only while the gates parse this file. If you would rather they read structured data, the author offered a compat/readers.json here that the doc renders from, or a window block alongside current in postguard-e2e's compat/manifest.json. Not a blocker — #260 and #261 can parse the markdown as-is — but worth deciding before three gates hard-code the parser.

Addendum, 2c1d32a: recorded the release-plz [Unreleased] behaviour above as a CLAUDE.md bullet, next to the existing pg-wasm versioning trap. It is the kind of thing that costs a cycle to rediscover.

Flipping out of draft. No advisory reference, nothing embargoed.

@dobby-coder
dobby-coder Bot marked this pull request as ready for review July 27, 2026 16:33
Found while resolving the deprecation-step-1 nit on this PR: the obvious fix
(a ### Deprecated bullet under pg-pkg CHANGELOG.md [Unreleased]) looks right
and does nothing, because release-plz inserts version sections below that
heading. Worth recording so the next run does not spend a cycle on it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@rubenhensen
rubenhensen merged commit 2ba47a1 into main Jul 28, 2026
25 checks passed
@rubenhensen
rubenhensen deleted the docs/252-compatibility branch July 28, 2026 07:20
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.

COMPATIBILITY.md: declare endpoint stability, archival read guarantee, SDK support windows, deprecation process

1 participant