Skip to content

docs(spec): editorial clarifications from section 6-8 review - #168

Draft
tnunamak wants to merge 1 commit into
mainfrom
docs/spec-copy-edits-2
Draft

docs(spec): editorial clarifications from section 6-8 review#168
tnunamak wants to merge 1 commit into
mainfrom
docs/spec-copy-edits-2

Conversation

@tnunamak

@tnunamak tnunamak commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a set of narrow editorial edits to spec-core.md addressing spec text that invites misreading — worst case, the "Get stream metadata" endpoint prose reads as if metadata access were ungated (unauthenticated) rather than grant-gated. No normative behavior changes; these are wording, heading-case, and cross-reference fixes.

  • Section 7 opening: "The grant is an immutable consent artifact" -> "A grant is an immutable consent artifact" (definitional article, not a reference to one specific grant).
  • Heading ### time constraint semantics -> ### Time constraint semantics for sentence-case consistency with sibling headings.
  • Section 7: "The request's time_range" -> "The selection request's time_range" to make clear that this resolution happens once, at grant issuance (not on every read).
  • Grant version field description now states plainly it tracks this specification's grant schema version, and clarifies there is no external URL to resolve.
  • Section 7's first reference to the Section 13 TypeScript types now links to Section 13 and states the types are a non-normative convenience mirror of the normative field tables (Sections 5, 6, 7) — on conflict, the field table wins. Added the matching conflict-rule sentence to Section 13's own intro note.
  • "Get stream metadata" endpoint prose reworded to lead with the access gate ("A caller may fetch metadata only for streams its grant covers") before stating that the metadata document itself is returned whole (not redacted per grant) — so it cannot be misread as ungated/unauthenticated access.
  • Effective-filter formula (grant_filter AND request_filter), both where it's defined and in the RS conformance list: clarified in plain language that owner tokens have no grant filter (the effective filter is the request filter alone) and client tokens use grant_filter AND request_filter. See "Research-backed revisions" below for why this replaced an earlier "identity" framing.
  • Introspection response field table (Section 8): the prior text incorrectly implied all listed fields were PDPP extensions; corrected to state that active, client_id, and exp are RFC 7662 fields and authorization_details is RFC 9396. See "Research-backed revisions" below for how provenance is now stated (prose, not a table column).
  • Defined "fan-in" (reading across more than one connected instance of the same source) at its first use in the stream selection parameters table.
  • instance_ids (StreamGrant): added a concrete example — two connected Gmail accounts are two instances of the same source kind, each with its own instance handle.
  • Tombstone text now points to the non-normative "Derived subset streams" discussion in Section 12 for readers who land on the subset/derived-stream mention in the tombstone prose.
  • Normativity convention: Section 1 already states the document-wide normative-unless-marked-otherwise rule, so rather than duplicate it, removed the now-redundant "The following field table is normative" sentence in Section 7 and replaced it with just the Section 13 cross-reference/conflict-rule sentence above.

Skipped: the record-model sentence "The Collection Profile defines the HTTP error for its ingest endpoint" (Section 4, near the RECORD envelope). Checked spec-collection-profile.md first: it defines no HTTP ingest endpoint at all (record ingest there is a JSONL stdin/stdout process protocol, not HTTP), so there is nothing to relocate this sentence to, and it is not redundant with anything already in that document. Left as-is and flagging for a follow-up decision (either the Collection Profile needs an HTTP ingest error contract, or this sentence should be reworded/removed in a separate change).

Research-backed revisions

A follow-up pass checked five spots against prior art in comparable specs and revised them accordingly:

  • expires_at is now optional-and-absent instead of a nullable type. Changed the grant field table, the TypeScript type, and the "continuous access" example from ISO 8601 or null / string | null to plain ISO 8601 / string, with "absent means no expiry." UK Open Banking's ExpirationDateTime uses the same optional-absent pattern ("If this is not populated, the permissions will be open ended"), and FHIR's convention is to omit absent primitives rather than null them. This also removes a redundant "no value" representation (both absent and null previously meant the same thing).
  • purpose_description now has one line of phrasing guidance. Added "Clients SHOULD phrase it as a single sentence addressed to the user," matching how OIDC and SMART on FHIR give inline display-copy guidance for user-facing consent text rather than leaving client authors to guess the register.
  • Introspection response provenance moved from a table column to prose. The previous revision added a "Provenance" column to the field table; this pass reverted that and instead states provenance in a short paragraph under the table (RFC 7662 base fields, the RFC 9396 authorization_details field, and this spec's own pdpp_-prefixed and other extension fields). SMART's scope-table profiles state field provenance this way — prose reads better than a column that's constant for most rows, and keeps the table focused on what implementers actually look up (field name, type, meaning).
  • Replaced "the grant filter is the identity" with plain language. The effective-filter formula's owner-token case was described algebraically ("grant_filter is the identity"); this reads as unnecessary jargon for a one-branch conditional. It now reads: for owner tokens there is no grant filter, so the effective filter is the request filter alone; for client tokens it's grant_filter AND request_filter.
  • Added a forward-compatibility clause to the error model. New sentence ahead of the error-code table: "Clients MUST treat unrecognized error codes as opaque and fall back to the HTTP status class and the error type." This mirrors the spec's own existing pattern for unrecognized purpose codes (Section 6: clients MUST NOT reject solely because a code is unrecognized) — the error-code table needed the same forward-compatibility guarantee it hadn't yet stated for itself.

Test plan

  • pnpm install --frozen-lockfile
  • pnpm spec:check — passed with no drift (9 canonical pairs, 3 site-only extensions, 1 reference-only root spec)

Assisted-by: AI

@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
pdpp Ready Ready Preview Aug 20, 2026 3:43am

Request Review

Signed-off-by: Tim Nunamaker <tnunamak@gmail.com>
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