fix(spec): trim dead webhook triggers undelete + api#3209
Merged
Conversation
WebhookTriggerType declared 5 triggers but only create/update/delete ever
fired. The other two had no event source:
- undelete: the engine has no soft-delete/restore capability (delete is a hard
delete; no deleted_at convention, no restore operation, no
data.record.undeleted emit). The undeleted case in the auto-enqueuer's
action mapper was dead code awaiting a producer that doesn't exist.
- api ("manually triggered"): no manual/programmatic fire path exists — the
only webhook HTTP surface re-queues already-failed deliveries.
Same declared≠enforced pattern as #3184 (validation delete-event) and #3195
(hook events). Trim, contract-first: authoring a webhook on a removed trigger
now fails loudly at os validate / registration instead of registering a
webhook that silently never fires. No shipped webhook metadata used either.
The auto-enqueuer now also warns when a persisted sys_webhook row carries a
trigger it can't map to an emitted record event (drift-guard, mirroring
#3195's registerHook warning) and drops it rather than caching a subscription
that matches nothing. Updated the sys_webhook trigger options + field help
(all locales), docs, and regenerated reference; added rejection + drift-guard
tests.
Reintroduce undelete only with a real restore subsystem, and api only with a
real manual-fire endpoint.
Closes #3196
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCUSMJBsX14C3RQdWFw7N7
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 102 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 18, 2026 12:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #3196.
WebhookTriggerTypedeclared five triggers (create/update/delete/undelete/api) but only the first three ever fired. The other two had no event source and silently no-op'd — the samedeclared ≠ enforcedpattern as #3184 (validationdelete-event) and #3195 (hook events).undelete— the engine has no soft-delete/restore capability at all:deleteis a hard delete, there's nodeleted_atconvention, no restore operation, anddata.record.undeletedis never emitted. Theundeletedcase in the auto-enqueuer's action mapper was dead code awaiting a producer that doesn't exist. (restore/purge/transferappear only as pre-wired permission concepts in plugin-security, deferred to a future M2 per [P0][security] Permission lifecycle ops ungated (allowTransfer/allowRestore/allowPurge) #1883 — nothing dispatches them.)api("manually triggered") — no manual/programmatic fire path exists anywhere; the only webhook HTTP surface (/webhooks/redeliver) re-queues already-failed deliveries.Per the design decision (both confirmed with the user), trim both rather than build out an entire restore subsystem or a manual-fire endpoint. Reintroduce
undeleteonly alongside a real restore subsystem, andapionly alongside a real manual-fire endpoint.Changes
packages/spec/src/automation/webhook.zod.ts—WebhookTriggerTypenarrowed tocreate/update/delete; a "Deliberately NOT triggers" doc block records whyundelete/apiwere removed;objectdescribe no longer references manual webhooks.packages/plugins/plugin-webhooks/src/auto-enqueuer.ts— droppedundeletefrom theCachedSubscriptiontype, the action union, andmapActionToTrigger. Added a drift-guard:parseRownow warns and drops any trigger it can't map to an emitted record event (e.g. a legacysys_webhookrow authored withundelete/api), so a dead trigger can't silently cache a subscription that matches nothing.packages/plugins/plugin-webhooks/src/sys-webhook.object.ts— trigger select options →create/update/delete; field help updated.en/zh-CN/ja-JP/es-ES*.objects.generated.ts) — droppedundelete,apifrom the trigger list and the "manual / API" object hint.content/docs/automation/webhooks.mdx(trigger list + action values); regeneratedcontent/docs/references/automation/webhook.mdx..changeset/— patch (spec + plugin-webhooks).Behavior change
undelete/apinow fails at parse/validate time instead of registering a webhook that never fires. Verified zero shipped/authored webhook metadata used either — the only references were the enum, the authoring-UI options, docs, and a parse-only test.sys_webhookrows with those triggers keep working for their valid triggers; the dead ones are dropped with a warning instead of sitting in the cache.Tests
webhook.test.ts— enum rejectsundelete/api; the multi-trigger case uses the 3 live triggers.auto-enqueuer.test.ts— a legacycreate,undelete,apirow still firescreateand warns (unknown: ['undelete','api']); a row whose only triggers are removed values enqueues nothing.Verified: spec 253 files / 6763 tests green, plugin-webhooks 14 tests green,
check:docs253 files in sync, spec + plugin-webhooks builds green, eslint clean. The'api'references elsewhere are the unrelated automation flow trigger (a live feature), not webhooks.Lineage
Fourth fix in the PD #10 events-enum audit line: #3160 → #3189 → #3195/#3206 → this. Remaining sibling: #3197 (schema-only event surfaces — graphql subscriptions, connector webhooks/triggers, realtime, websocket, record subscriptions).
🤖 Generated with Claude Code
https://claude.ai/code/session_01VCUSMJBsX14C3RQdWFw7N7
Generated by Claude Code