Events that actually fire, a receiver a developer can register, and a 202 nobody could read

Contribution Date
Contribution Project
Contribution Details
Events that actually fire, a receiver a developer can register, and a 202 nobody could read The outbox and the sender existed; nothing produced into one and nothing administered them. This is the half that makes them a feature rather than a sixth guard rail with no road. Six event kinds in one place, because a subscription filters on these strings: a producer that invented asset.publish beside asset.published would leave every filtered subscription silently missing half its events, and the mistake is invisible until a customer notices their CMS is out of step. Past tense throughout — an outbox row is written after the change, so every kind is a statement about something that already happened. Emitted from the real code paths, and from both of them where there are two. A metadata edit goes through the single-asset endpoint and through the bulk executor, and a consumer cannot tell which route an edit took — an event that fired for one and not the other would be a cache that goes stale depending on how many assets somebody selected. A no-op emits nothing: re-publishing an already-published asset changes nothing and must announce nothing, or a consumer ends up doing our idempotence for us. Payloads carry ids and never bytes, which is §11's reference-not-copy premise. A metadata event carries the keys that changed rather than the values — a receiver that wants them reads the asset with its own credential and gets what it is allowed to see, whereas a fat payload is damrs deciding at write time what an endpoint's scope will be at read time. Then the SSRF guard exposed a defect the moment I used it. It refused http://127.0.0.1:9099/hook — the shape of every receiver a developer writes — so building a webhook integration locally was impossible without hand-written SQL, a workaround no customer has. Development now permits http and loopback, and nothing else: private and link-local stay refused everywhere, because a development box is often a cloud VM and 169.254.169.254 is the metadata service. Reach is three levels rather than a boolean now, since collapsing loopback and private into "internal" was the mistake. The web client special-cased 204 alone, so the first endpoint to answer 202 with no content threw a JSON parse error inside a successful call — surfacing as "could not retry" for a retry that had worked. It reads the body and decides from that now, which fixes it for every future no-content response rather than for this one. And cargo fmt collapsed a line-continued string literal while keeping its padding, putting "post to one even in development" in a user-facing refusal. Caught by a test asserting the sentence; I then checked every literal in the file for the same damage. Verified end to end against the running stack with an independent Node receiver: two publications and a metadata edit delivered, every signature VERIFIED using only the documented scheme and a fresh timestamp, a deliberate 503 retried to success with the same delivery id, and the metadata payload carrying ["title"] while the value appeared nowhere. 2 producer cases, 2 more db cases, 9 browser cases including axe.
Contribution Author
Bassam Ismail
Files count
0
Patches count
1