Commit Graph

4 Commits

Author SHA1 Message Date
prosolis
1cbd68a718 news: Pete stops repeating what TwinBee just said in the room
Priority tier is the only thing that makes Pete post a live Matrix beat,
and the only two priority facts gogobee filed - zone_first and death -
are both moments TwinBee narrates in-room as they happen. Every live beat
was an echo. File them as bulletins: still on the site, still in the
daily digest, no second telling to the people who were there.
2026-07-12 22:01:09 -07:00
prosolis
1634bb1970 Pete news code-review fixes: realm-first ordering, parked-row reap, death-emit gate
- emitZoneClearNews: claim realm-first before the name guard so an unnamed
  straggler's first clear seeds news_realm_firsts (else the next named
  clearer is mis-announced as first-ever). Mirrors backfillZoneFirsts.
- RunMaintenance: reap permanently-parked pete_emit_queue rows (unsent,
  >30d) so a durable Pete outage can't accrete rows forever.
- emitDeathNews: gate on Enabled()/newsEmissionOn() before the char DB
  reads; markAdventureDead fires per-member on party wipes + in the sim.
2026-07-11 07:56:41 -07:00
prosolis
ae7ff38996 Pete news: salted per-event GUID token + zone_clear taxonomy
Closes the two deferred code-review follow-ups on the adventure-news
seam, plus folds in two pre-committed WIP fixes.

A. Privacy — the public GUID no longer leaks a stable per-player id.
   Replaced userHash(userID)=sha256(userID)[:6] with
   eventToken(userID, discriminator)=HMAC-SHA256(salt, userID‖disc).
   The salt is 32 random bytes, auto-generated once and persisted in the
   durable news_config table (cached via sync.Once). Because each event
   uses a distinct HMAC message, tokens are a PRF output and are BOTH
   uncomputable from a Matrix handle (no enumeration of a player's
   events, incl. ones anonymized after !news optout) AND mutually
   unlinkable (a named event can't be walked back to a player's other,
   anonymized events). Updated all emit sites: pete.go zone, dnd_combat
   death, adventure_duel rival, dnd_setup arrival, achievements
   milestone, bootstrap x3.

B. Taxonomy — repeat zone clears were mislabeled zone_first. Now emit
   zone_clear (bulletin) vs zone_first (realm-first, priority). Adopted
   the invariant GUID-prefix == event_type, which also fixes latent
   permalink mislabels (achv->milestone, rival->rival_result rendered a
   neutral "Dispatch" on their permalink pages).

Folded-in WIP fixes: create the news_config table b42beec's
newsEmissionOn reads but never created; reap sent pete_emit_queue rows
in RunMaintenance; don't burn a retry attempt when shutdown cancels an
in-flight send.

Tests: TestEventToken (salted/stable/per-event/persisted),
TestEmitZoneClearTaxonomy (first->zone_first, repeat->zone_clear),
updated pete_test.go prefixes. Full internal suite + vet green.

Unshipped. Deploy Pete first (it must know zone_clear), then gogobee.
2026-07-11 07:43:57 -07:00
prosolis
b42beec348 Pete Adventure News: emit seam, !news command, cold-start backfill
gogobee's game-side of Pete's push-based Adventure news feed. Emits
structured event *facts* (not prose) to Pete's ingest endpoint over a
durable queue; Pete owns voice/authoring/publishing.

- internal/peteclient: durable pete_emit_queue + retry sender; Fact
  payload; FEATURE_PETE_NEWS master switch.
- pete.go: emitFact enforces runtime kill-switch + per-player opt-out
  (anonymize, never drop); zone-clear + realm-first tiering; !news
  command (player optout/optin, admin on/off).
- bootstrap_pete_news.go: cold-start backfill replays deaths +
  single-holder achievements + zone realm-firsts, backdated + NoPush,
  idempotent, fires only once the seam is live; seeds news_realm_firsts.
- Emit sites: death, zone_first, rival_result, milestone, arrival.
- db.go: pete_emit_queue, news_optout (+opted_out_at), news_realm_firsts.

Unshipped. Deploy Pete first, then set FEATURE_PETE_NEWS + ingest env.

Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
2026-07-11 00:53:25 -07:00