feat(webhooks): webhook framework — inbound verify + outbound dispatch + spec block (#184)#191
Merged
Merged
Conversation
added 6 commits
May 31, 2026 09:21
…pters (#185) Foundation sub-package for the webhook epic (#184): HMAC-SHA256/512 + Ed25519 signers (constant-time verify), SignerRegistry, EnvSecretResolver, inbound dedupe contract + InMemory/Redis adapters, and the outbound Delivery value object + DeliveryStatus enum + store contract with InMemory/Redis adapters. No coupling to univeros/http.
Greens the PR's Static Analysis and Determinism gates: - Rector: catch-var rename, never return types on always-throwing helpers, import ordering / quote-escape autofixes across the webhooks code + tests. - Determinism (#74): regenerate .agent/ on PHP 8.3 (the gate's minor) so the new univeros/webhooks package + scaffold additions are indexed (codemaps/webhooks.md, packages/webhooks.md, manifest.json, scaffold codemap).
- WebhookHandler: onTransientFailure/deadLetter always throw, so they're typed never; drop the now-unreachable return statements PHPStan flagged (deadCode.unreachable at WebhookHandler.php:125). - Regenerate .agent/ manifests so the determinism gate sees the new univeros/webhooks package (MANIFEST.md, packages/webhooks.md, packages/scaffold.md).
a767da1 to
e5a741e
Compare
This was referenced May 31, 2026
Closed
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.
Webhook framework — epic #184
Ships the
univeros/webhookssub-package and its scaffolder integration: storage contracts + signing primitives, an inbound PSR-15 verify middleware, an outbound dispatcher with retry / dead-letter / replay, and awebhook:spec block the scaffolder wires automatically. Closes the second "Laravel AI-era property-gap" (alongside idempotency, #171).Sub-issues delivered in this PR
univeros/webhooks: storage contracts + adapters + signing primitives #185 —
univeros/webhooksfoundation (1581c18)HMAC-SHA256 / HMAC-SHA512 / Ed25519 signers (constant-time verify via
hash_equals/ sodium),SignerRegistry,EnvSecretResolver, inboundInboundDeduplicatorInterface+ InMemory/Redis adapters, outboundDeliveryvalue object +DeliveryStatusenum +DeliveryStoreInterfacewith InMemory/Redis adapters. No coupling touniveros/http.WebhookVerifyMiddleware: inbound PSR-15 (signature + timestamp window + dedupe) #186 —
WebhookVerifyMiddleware+ActionAwareWebhookVerifyMiddleware(4c45b24)Inbound PSR-15: signature check, timestamp replay window (past + future), event-id dedupe with synthetic fallback, idempotent replay (
200+Webhook-Replayed: true). Handler throw or 5xx releases the dedupe claim so the sender can retry. Body rebuilt for downstream handlers. Auto-wiring variant reads the Action's staticwebhook()accessor.WebhookDispatcher + Messenger handler: outbound POST with retry / dead-letter / replay #187 —
WebhookDispatcher+ Messenger handler + retry/DLQ + replay CLI (7a740dc)Application-facing dispatcher records a
Deliveryand dispatches aWebhookMessageviauniveros/messaging. Worker-sideWebhookHandlerperforms the signed POST (X-Signature/X-Timestamp/X-Event-Id/X-Delivery-Id), retries transient 5xx/network viaRecoverableMessageHandlingException, dead-letters afterRetryPolicy::maxAttemptsviaUnrecoverableMessageHandlingException.bin/altair webhook:replay <id>(full id or unique prefix) +bin/altair webhook:show-failed.webhook: spec block + scaffolder integration (AST + parser + validator + emitter wiring) #188 —
webhook:spec block + scaffolder integration (cb28d48)WebhookSpecAST node, parser + validator (direction / signer / secret-name / duration / retry rules),webhook()accessor emitted on inbound Actions,WebhookDispatcherBindingEmitteremittingapp/Webhooks/<Name>WebhookDispatcher.phpfor outbound specs. Byte-identical scaffold output when the block is absent.Verification
tests/Scaffold+tests/Determinism: 250 passing — no regressions, determinism intact.src/Altair/Webhooks+src/Altair/Scaffold: 0 errors.Still open (tracked, not in this PR yet)
x-altair-webhookround-trip activation (forward emit + reverse import + drift gate) +docs/openapi/*updates.docs/packages/webhooks.md+ package README +tokens-to-shipbenchmark variant.WebhooksConfigurationDI wiring (bindSignerRegistry::default(),EnvSecretResolver, InMemory defaults, register CLI commands).Test plan
vendor/bin/phpunit tests/Webhooks --no-coveragevendor/bin/phpunit tests/Scaffold tests/Determinism --no-coveragevendor/bin/phpstan analyse src/Altair/Webhooks src/Altair/Scaffold --memory-limit=1Gcomposer qa(cs + stan + test with coverage driver)Part of #184.