Skip to content

feat(ir)!: name a webhook binding's event - #735

Open
fuad-daoud wants to merge 3 commits into
mainfrom
feat/ir-webhook-name
Open

fuad-daoud wants to merge 3 commits into
mainfrom
feat/ir-webhook-name

Conversation

@fuad-daoud

Copy link
Copy Markdown
Collaborator

Summary

An OpenAPI 3.1 webhook's key is the name of the event the provider will send, not a URL, but the compiler stores it in HTTPBinding.URITemplate:

webhooks:
  "{tenant}.created":
    post: {…}

lowers to a binding with "uriTemplate":"{tenant}.created" and "isWebhook":true. Storing it where RFC 6570 templates go makes {tenant} read as a template variable that nothing binds, and leaves no field naming the event.

Change

ir.HTTPBinding gains WebhookName string (json:"webhookName,omitempty") beside IsWebhook, holding the webhooks-map key verbatim — a declared fact like Operation.Tags or Naming.Source, not a neutral name channel and not a template. A webhook binding carries that key in WebhookName and leaves URITemplate empty. An empty webhooks-map key is legal and leaves the field empty.

Nothing else moves: the operation's ID (mount pointer), Name (the operationId, or the synthesized hint), group, params, request and responses are unchanged. The synthesized hint for a webhook without an operationId stays method + webhook name (post_tenant_created) — the naming token is the map key, not the now-empty template.

irverify gains ir/webhook-uri-template: a binding with IsWebhook set that populates URITemplate selects a field a webhook does not, and a consumer would have two answers and no way to tell which to trust. Only the negative half is a contract — an empty webhooks key is legal, so requiring a non-empty WebhookName would fire on a legal document this compiler itself produces. This lives in irverify because a document decoded from JSON, written by another compiler, or rewritten by a pass is beyond what the compiler's own tests can hold.

Callbacks are a different construct (a runtime expression, sometimes irreducible) and are left as they are; the same class of defect there is tracked separately.

Breaking

IRVersion moves to 0.7.0. HTTPBinding gains a JSON key, and a webhook binding no longer writes uriTemplate — that key held an event name, not a template — so a consumer pinned to 0.6.0 finds the event name in no key it reads.

Test plan

  • make gate green; coverage is exactly 100%.
  • End to end on the issue's document: "webhookName":"{tenant}.created", no uriTemplate, isWebhook true, ID op/openapi/webhooks/{tenant}.created/post, hint post_tenant_created.
  • New operation test on the brace-key document, with and without an operationId, pinning the hint — taking the naming token from the empty uriTemplate instead would redden it.
  • irverify test: a webhook binding naming its event, a webhook with an empty key, and a path binding are all clean; a planted IsWebhook + URITemplate reports ir/webhook-uri-template at <binding>.URITemplate.
  • The four webhook goldens drop uriTemplate and gain webhookName; the other goldens change only in the irVersion line.
  • unwitnessed.golden.txt is unchanged — WebhookName is witnessed by the corpus.

Merge ordering

This branch and the tuple-openness branch (#734) both set IRVersion to 0.7.0 from the same base. Whichever merges second must rebase and take 0.8.0, re-anchoring ir/document_test.go's three literals and regenerating its goldens. If #734 lands first, rebase this onto main and bump to 0.8.0.

fuad-daoud and others added 2 commits September 30, 2026 19:03
An OpenAPI 3.1 webhooks entry is keyed by the name of the event the
provider sends, not a URL, so its operation's HTTPBinding carries that
key in WebhookName and leaves URITemplate empty. Storing it where RFC
6570 templates go made {tenant} read as a template variable nothing
binds.

WebhookName is the map key verbatim, a declared fact like Operation.Tags
or Naming.Source, not a neutral name channel and not a template. A
webhook binding carries no URITemplate; an empty webhooks key is legal
and leaves WebhookName empty. The synthesized naming hint is unchanged
(method + the webhook name).

irverify gains ir/webhook-uri-template: a webhook binding that populates
URITemplate selects a field a webhook does not, which the compiler's own
tests cannot hold for a foreign or pass-rewritten document.

IRVersion moves to 0.7.0: HTTPBinding gains a key, and a consumer pinned
to 0.6.0 that read a webhook's event name out of uriTemplate finds it in
no key it reads. Closes #624.
Resolve the conflicts with main and bring the doc comments this branch
adds under the 100-word cap main now enforces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCzyGPq9DQ7RLfagZm2JB5
Main took irVersion 0.7.0 for group IDs and idSpaces, so this change moves to 0.8.0: the constant, its ir-design.md history entry, the neighbour rows of TestCompatibleVersion and every golden. The webhook verify fixture gains a group ID and declares its ID spaces, which main's checks now require.
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