feat(events): publish certificate-exchange status changes to NATS - #5
Merged
paullatzelsperger merged 3 commits intoAug 13, 2026
Merged
Conversation
Certo held CX-0135 exchange state and emitted nothing, so the only way to
observe an exchange reaching FULFILLED or REJECTED was to poll its
management API. It now publishes those status changes as CloudEvents onto
the platform's shared edc-events JetStream stream, in the same envelope
shape and subject space the EDC runtimes use, so existing consumers of
that stream see certo's events alongside the connector's.
Subjects are events.certificate.exchange.<status>; types follow the
CX-0000 §2.3 reverse-DNS convention already used by CcmEvents. Both are
bound together in one catalogue enum (ExchangeEventType) so a consumer
routing on the subject and switching on the type can never see them
disagree, and a test asserts the mapping is total over FulfillmentStatus
and AcceptanceStatus -- a status that maps to nothing would publish
nothing, silently.
Emission hangs off Spring Data's @DomainEvents rather than the ~13
service call sites: every status mutation already funnels through the
aggregates' transition methods, and save() is already called after each
one, so recording there means a transition cannot be missed by forgetting
a publish call. The domain records facts; it does not publish them.
Two things that would each have silently lost events:
- fallbackExecution = true on the @TransactionalEventListener is
required, not defensive. pollAcceptance/publish (provider) and
initiateRequest/pollRequest/retrieve (consumer) are declared
@transactional(NOT_SUPPORTED) and commit through an inner
TransactionTemplate, so by delivery time there is no surrounding
transaction and Spring would discard those events -- losing the
provider-initiated publish path entirely.
- The consumer's updateFulfillment mirrors whatever the provider last
reported and is called on every poll, so it records an event only
when the status actually changes.
AFTER_COMMIT means a rolled-back transition announces nothing. Publish
failures are logged and swallowed, matching the EDC bridge: the state
change has already committed, and failing the API call would misreport
work that was done.
The CloudEvents `source` is the emitting application's hostname (the pod
name under Kubernetes), as in every other platform producer; the emitting
tenant travels in the CX-0000 §2.1.2 sourcebpn extension and in the
payload's participantContextId.
Off by default at the application level (certo.events.nats.enabled), so
local runs and the test suite need no broker; the chart turns it on. The
chart reuses the platform's shared `edc-events` NATS identity rather than
requiring a user of its own, which depends on core-platform-distribution
provisioning it and on certo's ServiceAccount being listed there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jimmarino
approved these changes
Aug 13, 2026
paullatzelsperger
force-pushed
the
feat/nats-exchange-events
branch
from
August 13, 2026 07:07
0b1c6cd to
5c88778
Compare
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.
Certo held CX-0135 exchange state and emitted nothing — observing an exchange reaching
FULFILLEDorREJECTEDmeant polling the management API. It now publishes those status changes as CloudEvents onto the platform's sharededc-eventsJetStream stream, in the same envelope the EDC runtimes use, so existing consumers of that stream see them alongside the connector's.events.certificate.exchange.<status>, typesorg.catena-x.ccm.CertificateExchange<Status>.v1— both from one catalogue enum, with a test asserting it covers everyFulfillmentStatusandAcceptanceStatus.@DomainEvents, not the ~13 service call sites: every mutation already goes through the aggregates' transition methods and is followed bysave(), so no transition can be missed by forgetting a publish call.AFTER_COMMITdelivery, so a rolled-back transition announces nothing.fallbackExecution = trueis required, not defensive — five exchange operations are@Transactional(NOT_SUPPORTED)and their events would otherwise be discarded.certo.events.nats.enabled), so local runs and tests need no broker; the chart turns it on and reuses the platform's sharededc-eventsNATS identity (feat(nats): collapse NATS users into three shared identities eclipse-cfm/core-platform-distribution#19).