Skip to content

fix(standards): make the IETF draft describe the protocol that ships - #96

Open
ucekmez wants to merge 1 commit into
feat/schema-driven-conformancefrom
fix/ietf-draft-manifest-parity
Open

fix(standards): make the IETF draft describe the protocol that ships#96
ucekmez wants to merge 1 commit into
feat/schema-driven-conformancefrom
fix/ietf-draft-manifest-parity

Conversation

@ucekmez

@ucekmez ucekmez commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

PR 4 of a stacked series. Base is #95. Not for merge without review.

docs/standards/draft-eep-protocol-core-00.md and schemas/v0.1/eep-manifest.json have drifted until not one field name matches except eep_version:

Draft requires Schema requires
publisher_did did
endpoints.discovery
endpoints.subscribe layers.layer2_webhook
endpoints.stream layers.layer2_sse
endpoints.pulse layers.layer3_ws
supported_layers (array) layers (object)
delivery_methods
conformance_level
supported_content_types, pqc_ready, x402_enabled

A publisher conformant to the shipped schema fails every MUST in the Internet-Draft, and vice versa. Nothing in CI noticed, because nothing compared them.

ROADMAP.md targets IETF/W3C submission at v0.2 (Q3 2026). This is the document a standards reviewer reads first.

Direction taken — please confirm

The draft is rewritten to match the schema, not the reverse.

The schema is implemented by both middleware packages, both reference implementations, and the compliance CLI. The draft has no implementations at all. Changing the schema instead would be a breaking change to a published v0.1 artifact for no protocol benefit.

That said — the draft's shape is arguably the better one for IETF review: a flat endpoints object and an explicit conformance_level read more naturally than a layers object whose members encode tier numbers. If you'd rather carry that shape into a v0.2 schema break, this PR is the wrong direction and I'll redo it. Flagging rather than assuming.

What changed

  • Layer 1 field table restated against eep-manifest.json, with the layers object documented and the rule that at least one Layer 2 endpoint must be populated.
  • endpoints.* references replaced with layers.layer2_sse / layers.layer2_webhook.
  • Envelope section documents eep_version — what implementations actually emit — instead of eepversion / eepdelivery, which nothing emits.
  • scripts/check-draft-schema-parity.mjs + CI job so this drift becomes a build failure.

An open question the draft surfaced

The draft's invented eepversion spelling was arguably more correct than what ships. CloudEvents v1.0.2 restricts context attribute names to lowercase ASCII letters and digits — the underscore is excluded. So eep_version, eep_subscription_id, eep_trust_score and the rest are all non-conformant CloudEvents extension attribute names.

In structured JSON mode this is harmless in practice. It becomes load-bearing in binary content mode, where attributes are carried as ce--prefixed HTTP headers.

I recorded this as an Editor's note in the draft rather than silently renaming: no implementation emits the compliant spelling today, and a rename is a breaking change that deserves its own decision. Options are (a) rename with a deprecation window, or (b) keep underscores in structured mode and define an explicit binary-mode mapping.

Scope

  • Spec / schema only
  • TypeScript package(s)
  • Python package(s)
  • Tests / CI
  • Docs / examples

Checklist

  • I read CONTRIBUTING.md and CODE_OF_CONDUCT.md.
  • Tests added or updated where appropriate (the parity gate is the test).
  • Breaking change? No. No file under schemas/v0.1/ changed — only the draft, which has no implementations.
  • Documentation updated for user-visible behavior.

Verification

Check Result
node scripts/check-draft-schema-parity.mjs ✓ 9 documented fields, 6 required
Gate catches injected drift ✓ exits 1 with a readable diff
git diff --name-only schemas/ 0 files
node scripts/codegen-schema-types.mjs --check no drift
tests/ 164 passed

Notes for reviewers

I verified the gate by injecting drift (adding gates_url to the schema's required) and confirming a non-zero exit with a readable message, rather than only confirming it passes on a clean tree. A gate that has only ever been seen to pass is not evidence of anything.

The gate deliberately allows the draft to omit optional schema properties — the draft scopes itself to the Core tier and shouldn't have to restate the full manifest surface. It only fails on a field the draft invents, a required-ness mismatch, or a schema-required field the draft misses.

Separately: while checking field names I found that the Node reference implementation reads body.callback_url on subscribe, while subscription.request.json mandates delivery_url — so a conformant subscriber's delivery target is silently dropped. Both middleware packages get this right. That's a distinct bug and is coming as its own PR rather than being folded in here.

`docs/standards/draft-eep-protocol-core-00.md` and
`schemas/v0.1/eep-manifest.json` had drifted until not one field name
matched except `eep_version`:

  draft requires    publisher_did, endpoints.discovery,
                    endpoints.subscribe, endpoints.stream,
                    supported_layers, delivery_methods,
                    conformance_level
  schema requires   did, eep_version, layers,
                    supported_content_types, pqc_ready, x402_enabled

A publisher conformant to the shipped schema fails every MUST in the
Internet-Draft, and vice versa. Nothing in CI noticed, because nothing
compared them. ROADMAP.md targets IETF/W3C submission at v0.2, so this
is the document reviewers would read first.

Direction: the draft is rewritten to match the schema, not the reverse.
The schema is implemented by both middleware packages, both reference
implementations and the compliance CLI; the draft has no
implementations at all. Changing the schema instead would be a breaking
change to a published v0.1 artifact for no protocol benefit.

Changes:
- Layer 1 field table restated against `eep-manifest.json`, with the
  `layers` object documented and the rule that at least one Layer 2
  endpoint must be populated.
- `endpoints.stream` / `endpoints.subscribe` references replaced with
  `layers.layer2_sse` / `layers.layer2_webhook`.
- Envelope section documents `eep_version` (what implementations emit)
  instead of `eepversion` / `eepdelivery` (which nothing emits).
- Editor's note recording that the shipped `eep_`-prefixed names violate
  the CloudEvents v1.0.2 attribute-naming rule, which excludes the
  underscore. This is a real problem that becomes load-bearing in binary
  content mode, where attributes become `ce-`-prefixed headers. Recorded
  as an open question rather than silently renamed: no implementation
  emits the compliant spelling today.
- `scripts/check-draft-schema-parity.mjs` plus a CI job, so this class of
  drift is a build failure. The gate parses the draft's delimited field
  table and diffs names and required-ness against the schema; verified
  by injecting drift and confirming a non-zero exit.

No schema changed, so the types drift gate is a no-op here.

Refs: EEP audit 2026-08 finding A1
Signed-off-by: Ugur Cekmez <ucekmez@gmail.com>
Copilot AI lite review requested due to automatic review settings August 26, 2026 18:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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