feat(canopy-mq): compile-time EventPayload macro + CI grep lint (event-bus-enforcement Steps 2+4)

Follow-up to the event-bus-enforcement plan, Steps 2 + 4 — both deferred at landing (2026-04-09) when runtime RestrictedFieldDetector was deemed sufficient for UAT.

Step 2 — compile-time EventPayload proc macro

Currently EventPayload is a marker trait. Convert to #[derive(EventPayload)] with a #[deny_field(...)] attribute, so a struct that adds (e.g.) an ssn: String field at construction time fails the build. This complements the existing runtime check by catching violations before they reach Publisher::publish.

Step 4 — CI grep lint

Add a defence-in-depth event-bus-lint GitLab CI job that greps services/*/src/events.rs for the same pattern set as RESTRICTED_FIELDS. Sketch lives in the plan; pull it onto .gitlab-ci.yml directly.

Why deferred

Runtime enforcement (Step 1 + 3 + 5 + 6, all done) already rejects payloads at publish time and is covered by 7+ unit tests. The compile-time + CI layers are pure defence-in-depth and add complexity without proportional safety gain pre-UAT.

References

  • xref:plans/event-bus-enforcement.adoc[event-bus-enforcement plan] (Steps 2, 4 — Deferred)
  • crates/canopy-mq/src/restricted.rs — runtime detector