Skip to content

conformance-suite: transcribe the locked Core v0.1.0 text - #459

Open
tnunamak wants to merge 1 commit into
mainfrom
fix/conformance-suite-locked-core
Open

tnunamak wants to merge 1 commit into
mainfrom
fix/conformance-suite-locked-core

Conversation

@tnunamak

@tnunamak tnunamak commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The conformance suite's coverage report was measuring a specification that no longer exists. It tells a reader how many of the specification's normative sentences its test cases exercise, by comparing the cases against a catalogue of the 45 numbered items in Section 9 of spec-core.md (the specification's own conformance checklist) and a matrix of quoted sentences. Fixing the specification text for release v0.1.0 rewrote spec-core.md from 1916 to 3254 lines and grew that checklist to 123 items. Against the locked text, 588 sentences expressing mandatory requirements with MUST had no corresponding entry in the quoted-sentence matrix, 42 entries quoted text that no longer exists, and 78 checklist items were missing from the catalogue. To keep the suite running, an earlier change, #457, froze a copy of the old draft and pointed the suite at it, which meant reports named a draft that is no longer the standard.

This change re-transcribes the catalogue and the matrix against the locked spec-core.md and removes the frozen copy. After it, all 123 items are in the checklist catalogue file catalog.ts and all 708 clauses are in the quoted-sentence matrix file matrix.ts: every sentence using the specification's mandatory-requirement wording outside Section 9 is quoted, and both the completeness tests and the specification-difference check (pnpm --filter @pdpp/conformance-suite spec:delta) report zero gaps. Clause ids are renumbered from the locked headings, because the locked text moved subsections and the old ids would have pointed at different sentences.

Each existing link from a clause to a test case was carried to the sentence it now corresponds to. A sentence that is new or rewritten is linked to a case only where that case observes it. The rest are recorded with no case and a note saying what a case would need, or, for 188 MUST clauses, as review-only because no request the suite can send observes the behaviour. A clause whose cases cover only part of it is marked partial, so a passing case cannot read as full coverage. The report now states the true proportion: 84 of 667 MUST clauses have a case, and 38 of the 123 items have one. The earlier list was 119 MUST clauses, 85 of them with a case. No case code changed, no sentence is excluded beyond the one definition of requirement keywords already excluded (from BCP 14, the IETF standard that defines words such as MUST), and running the cases against the implementation used as the suite's reference produces the same outcome for every case. Only the clause table and the specification hash in targets/reference-implementation.expected.json, the file holding expected reference-implementation results, changed.

Some cases assert behaviour the locked text changed. Their clauses no longer cite them, and each clause note records the disagreement. A conforming server can fail these cases:

  • AS-2/view-and-fields-mutually-exclusive, the case for requests containing both the view and fields request fields, expects HTTP status 400 with the error code invalid_request; the locked text instead assigns those requests the error code invalid_authorization_details.
  • AS-6/unregistered-purpose-not-rejected, the case for an authorization detail with an unregistered purpose code, sends that detail without its purpose_description field describing the purpose; the locked text requires the server to reject that detail.
  • AS-14/explicit-consent-required-for-ai-training tests an ai_training purpose code for artificial-intelligence training that confers nothing in the locked text, where that training is a processing permission that remains unsupported pending a separate specification.
  • AS-17/unsupported-version-rejected, the unsupported-version case, expects the server handling authorization to reject an unsupported value of PDPP-Version, the protocol-version identifier; the locked text retires that item and makes version negotiation the duty of the server serving resources.
  • RS-7/tombstone-envelope-survives-sparse-fields, the case checking a deletion marker returned using a client token, requires that marker to include the timestamp fields deleted_at and emitted_at; the locked text gives responses using those tokens neither field.

Three cases pass or are mapped but measure less than their names suggest. AS-9/token-response-carries-granted-authorization-details, the case comparing granted authorization details in a token response with a token-inspection response, reads the streams list directly from each element of the authorization_details collection, while the locked text nests that list inside the element's grant object, so the comparison can match two empty lists. RS-1/list-sort-order-across-instances, the case checking list order across instances, expects ordering first by the cursor field and then by the primary key; the locked default when an authorization grant has no fixed sorting field is ordering first by the instance identifier and then by the key in its canonical representation. The grant-expiry and grant-revocation cases still describe 403 responses, which the locked text now defines as 401, though they accept 401. RS-1/compound-primary-key-canonically-encoded, the case checking the encoding of a key with multiple components, checks for a compact JavaScript Object Notation array of strings, and the locked text names the canonical serialization standard RFC 8785 for the same array. For an array of strings the two are byte-identical, so the case is correct and only its comment is out of date.

I have not run the suite against any implementation other than the pinned reference implementation, and I did not trace whether each carried case-to-clause link still holds beyond comparing the quoted sentence with the case's assertion. The 569 new clauses were classified by rule from their sentence wording, including whether a test request can observe their requirements, so a reviewer should expect to correct some classifications.

To check: use the package manager pnpm to run pnpm --filter @pdpp/conformance-suite verify, which selects the conformance-suite package @pdpp/conformance-suite and runs its verify task for type checking, linting and 356 tests. The continuous-integration job conformance starts the reference implementation at its fixed version and compares every case and clause result to the expectations file; I ran it locally and it matches after regeneration.

Assisted-by: AI

The conformance suite reports how much of the PDPP Core specification
it exercised by comparing its test cases against two inventories: a
catalogue of the numbered items in Section 9 (the specification's own
conformance checklist) and a matrix that quotes each normative sentence.
Both were written against a draft of spec-core.md. The v0.1.0 lock
rewrote that file from 1916 to 3254 lines, so the inventories no longer
described the specification. A previous change froze a copy of the old
draft so the suite could keep running; that left the suite judging text
that is no longer the standard.

This change re-transcribes both inventories against the locked
spec-core.md and removes the frozen copy.

The catalogue now holds all 123 Section 9 items (AS 1-57, RS 1-33,
Client 1-33) instead of 45. The matrix holds 708 clauses instead of
about 130, one for every sentence in the locked text that carries a MUST
keyword, plus the SHOULD and MAY sentences in the sections the matrix
covers. Clause ids are renumbered from the locked headings. Each
earlier mapping from a clause to a test case was carried to the locked
sentence it now corresponds to. A new or rewritten sentence is mapped to
a case only where that case observes it; otherwise the clause records
that no case exists and says what a case would need. Where the locked
text changed behaviour that a case asserts, the clause drops that case
and its note records the disagreement. No case code changed. No
sentence is excluded beyond the one BCP 14 definition already excluded.

The frozen copy, its REUSE.toml path, and the test edits that pointed at
it are reverted, and SPEC_SOURCE names spec-core.md again. The
expectations file for the reference implementation is regenerated: every
case outcome is unchanged, and only the clause table and the spec hash
differ.

Assisted-by: AI
Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pdpp Ready Ready Preview Oct 27, 2026 4:11am UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview — 10fb8e3f Deployed Oct 27, 2026 by vercel[bot]
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.

1 participant