Epic #382. Surfaced by #389 (metrics read-model): three aggregates can't be populated today because the pipeline never emits the events that would carry them — the read-model correctly refuses to fabricate them.
The gap (event-handler architecture):
Avg quality — null in the read-model. CurationRatings (#378 W6) are staff-authored Mongo data, never published as an event, so the projection has nothing to fold. Needs an art.asset.rated (or art.asset.quality.scored) event on art.asset.lifecycle emitted whenever a rating/quality score is set.
True accept-rate — today #389 exposes pipeline success (completed ÷ (completed+failed)). A real curation accept-rate needs an art.asset.review.resolved / art.asset.curation.decided event (approved vs. rejected) when a staff curation decision lands.
Review-backlog — currently a live indexed count over art-assets.flaggedForReview (isolated behind IArtStudioReviewBacklogReader) because the safety flag is set inline with no distinguishable event. Fine as-is, but an art.asset.flagged/unflagged event would let the projection own it consistently with the rest.
Scope: add these publishers at the points where the state actually changes (curation rating write path; staff review-resolution; safety-flag set/clear), on the existing art.asset.lifecycle topic exchange with W3C trace context (ActivityHelper) — then extend the #389ArtStudioMetricsProjector (pure fold) + read-model to consume them. Additive/inert to existing consumers (topic fan-out).
Deps:#389 (read-model + projector to extend). Type: backend, event-handler-driven. Populates the Metrics dashboard (#391) + Activity panel (#390) with real quality/curation numbers instead of proxies. Test: projector folds the new events into avg-quality / accept-rate / backlog correctly (unit); publishers emit on the real state-change paths (unit).
Epic #382. Surfaced by #389 (metrics read-model): three aggregates can't be populated today because **the pipeline never emits the events that would carry them** — the read-model correctly refuses to fabricate them.
**The gap (event-handler architecture):**
- **Avg quality** — `null` in the read-model. `CurationRatings` (#378 W6) are staff-authored Mongo data, never published as an event, so the projection has nothing to fold. Needs an `art.asset.rated` (or `art.asset.quality.scored`) event on `art.asset.lifecycle` emitted whenever a rating/quality score is set.
- **True accept-rate** — today #389 exposes *pipeline success* (completed ÷ (completed+failed)). A real curation accept-rate needs an `art.asset.review.resolved` / `art.asset.curation.decided` event (approved vs. rejected) when a staff curation decision lands.
- **Review-backlog** — currently a live indexed count over `art-assets.flaggedForReview` (isolated behind `IArtStudioReviewBacklogReader`) because the safety flag is set inline with no distinguishable event. Fine as-is, but an `art.asset.flagged`/`unflagged` event would let the projection own it consistently with the rest.
**Scope:** add these publishers at the points where the state actually changes (curation rating write path; staff review-resolution; safety-flag set/clear), on the existing `art.asset.lifecycle` topic exchange with W3C trace context (`ActivityHelper`) — then extend the #389 `ArtStudioMetricsProjector` (pure fold) + read-model to consume them. Additive/inert to existing consumers (topic fan-out).
**Deps:** #389 (read-model + projector to extend). **Type:** backend, event-handler-driven. Populates the Metrics dashboard (#391) + Activity panel (#390) with real quality/curation numbers instead of proxies.
**Test:** projector folds the new events into avg-quality / accept-rate / backlog correctly (unit); publishers emit on the real state-change paths (unit).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Epic #382. Surfaced by #389 (metrics read-model): three aggregates can't be populated today because the pipeline never emits the events that would carry them — the read-model correctly refuses to fabricate them.
The gap (event-handler architecture):
nullin the read-model.CurationRatings(#378 W6) are staff-authored Mongo data, never published as an event, so the projection has nothing to fold. Needs anart.asset.rated(orart.asset.quality.scored) event onart.asset.lifecycleemitted whenever a rating/quality score is set.art.asset.review.resolved/art.asset.curation.decidedevent (approved vs. rejected) when a staff curation decision lands.art-assets.flaggedForReview(isolated behindIArtStudioReviewBacklogReader) because the safety flag is set inline with no distinguishable event. Fine as-is, but anart.asset.flagged/unflaggedevent would let the projection own it consistently with the rest.Scope: add these publishers at the points where the state actually changes (curation rating write path; staff review-resolution; safety-flag set/clear), on the existing
art.asset.lifecycletopic exchange with W3C trace context (ActivityHelper) — then extend the #389ArtStudioMetricsProjector(pure fold) + read-model to consume them. Additive/inert to existing consumers (topic fan-out).Deps: #389 (read-model + projector to extend). Type: backend, event-handler-driven. Populates the Metrics dashboard (#391) + Activity panel (#390) with real quality/curation numbers instead of proxies.
Test: projector folds the new events into avg-quality / accept-rate / backlog correctly (unit); publishers emit on the real state-change paths (unit).
✅ Merged to master via spikersoft-backend#101. Curation event publisher landed —
RateGalleryAssetCommandHandler+ModerateGallerySubmissionCommandHandlerpublishart.asset.rated/art.asset.curation.decided(best-effort, post-SaveChanges). Build 0 errors; 534 ArtStudio tests green.