The publish chain works — the sink received it:
{"kanaal": "objecten", "resource": "object", "kenmerken": {"objectType": "…"},
"hoofdObject": "http://objecten.local:8000/api/v2/objects/a68d4c46-…", …}
The check just looked for the wrong thing. An NRC notification carries hoofdObject /
resourceUrl and kenmerken — never the record data — so the `reference` inside the
RegisterRecord it wrote was never going to appear in the delivered message. Grep the sink
for the object URL instead, which is what identifies the write.
The worker published and NRC answered 400 on every message:
{"hoofdObject":["Voer een geldige URL in."],"resourceUrl":["Voer een geldige URL in."]}
NRC types both as DRF `URLField`, and Django's URLValidator refuses a single-label host.
Objecten fills them from the object `url` DRF built with `request.build_absolute_uri` —
the Host the *caller* used — so `SITE_DOMAIN` never entered into it. Dropped that env pair;
it was a wrong guess at the mechanism.
The fix is on the caller side: keep the `objecten.local` network alias and point every
writer whose writes must be notified at it — the ACL, the gateway integration tests, and
this slice's verify driver. Readers keep the plain service name.
ADR-0029 updated with the real mechanism and the ceiling it leaves: a new writer using
`objecten:8000` gets a 201 and silently no notification.
Registers an abonnement on the `objecten` kanaal pointing at the existing
webhook sink, writes a RegisterRecord exactly as the ACL does on approval, and
waits for the delivery. That is the whole publish chain in one assertion:
Objecten → its celery worker → NRC → nrc-beat → the callback.
Fails today at the first hop, which is the point:
NRC POST /api/v1/abonnement → 400: {"name":"naam","code":"kanaal_naam",
"reason":"Kanaal met deze naam bestaat niet."}
Also splits S-19b (#150) into #152/#153 in BACKLOG.md — the notification wiring
and the projection re-source are independently deployable (CLAUDE.md §13).