Skip to main content
← Back to list
01Issue
BugOpenSwamp Club
AssigneesNone

Relationships

#507 Feed-post scoring is a direct domain write, not a consumer of feed_post_approved telemetry

Opened by keeb · 6/1/2026

Summary

Points for an approved feed post are awarded by a direct domain write (contributeFeedPostScore) inside judgePost, not by a consumer of the feed_post_approved telemetry event. The only consumer of that event is the telemetry service's DiscordConsumer (which posts the embed). There is no scoring consumer. This split is what made the #502 orphan unrecoverable by replay and forced a bespoke one-off backfill.

Current behavior

On approval, lib/app/feed/judge-post.ts does two unrelated things down two different roads:

  1. Points (direct-write road): contributeFeedPostScore(...) writes a content:feed-post:<id> contribution straight into user_scores, plus an event_queue refresh nudge so processScoreBatch recomputes totals.
  2. Discord (telemetry road): announceFeedPost(...) emits feed_post_approved → telemetry service DiscordConsumerdiscord_event_queue → discord-bot.

Nothing on the telemetry/consumer side awards score. I traced every consumer of feed_post_approved: only services/telemetry/lib/consumers/discord.ts handles it.

Why this is bad

  • Not replayable. Re-ingesting / re-firing feed_post_approved lights up Discord but awards zero points — there is no consumer to turn the event into score. A missed or half-processed approval therefore cannot be healed by replaying telemetry; it needs a one-off code backfill (see #502).
  • Two sources of truth drift. The event log can say "approved & announced" while the score lives in a separate direct write that may be silently absent — exactly the #502 state (no points, no Discord, telemetry never even emitted).
  • Coupling / inconsistency. Feed-post scoring is welded into the judge orchestration instead of flowing through the event pipeline the way other score sources do.

Expected behavior

feed_post_approved should be picked up by a scoring consumer (alongside the DiscordConsumer) that applies the idempotent content:feed-post:<id> contribution. Then both effects are replayable from the event, single-sourced, and decoupled from the judge orchestration — and the #502 class of orphan heals itself on replay instead of needing a backfill.

Steps to reproduce / investigate

  1. Inspect lib/app/feed/judge-post.ts — note the credit phase calls contributeFeedPostScore directly.
  2. Grep consumers of feed_post_approved: only services/telemetry/lib/consumers/discord.ts.
  3. Confirm lib/app/process-score-batch.ts has no feed-post handling — it only recomputes totals from existing contributions.
  4. Observe that re-firing the telemetry (e.g. via the credit backfill's announceFeedPost) restores Discord but would not, on its own, restore points.

Affected components

  • lib/app/feed/judge-post.ts (credit phase / direct write)
  • lib/app/feed/contribute-feed-post-score.ts
  • lib/app/feed/announce-feed-post.ts (telemetry emit)
  • services/telemetry/lib/consumers/ (where a scoring consumer would sit, next to discord.ts)
  • lib/app/process-score-batch.ts + event_queue (score pipeline)

Scope note

#502 fixes the immediate orphan: it makes the credit phase retriable and adds a one-off backfill for the affected post, deliberately keeping the existing direct-write award path to stay minimal. This issue tracks the deeper fix — move feed-post scoring onto a telemetry consumer so award + announce share the same replayable event.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED

Open

6/1/2026, 4:08:27 AM

No activity in this phase yet.

03Sludge Pulse

Sign in to post a ripple.