4 Commits
Author SHA1 Message Date
prosolis b4a276da36 adventure: give a finished run a report worth sharing
The liveblog answers "what is happening" — it is capped, it scrolls, and six
hours after a run ends it is gone, because the adventurer page is about now.
Nothing answered the question asked afterwards, usually by somebody who wasn't
watching: what WAS that run. So a dispatch announcing a clear or a death was a
paragraph about an outcome with no way back to what produced it.

The report is that way back. The whole log uncapped, the numbers rolled up, and
the single worst hit the party took pulled out of the middle where it otherwise
reads as one line among forty. It is stable for a fortnight, which is what makes
it a thing worth linking from a dispatch and worth sending to somebody.

It is assembled from the same beats through the same renderer as the liveblog.
A report that told a different story from the log it was built out of would be
the more convincing of the two and the less true.

The summary is the exception and the only prose on the channel: gogobee's model
reads the finished run back and says what it was about, which is a judgement no
template makes. It rides a summary beat rather than its own endpoint, so it
inherits the whole channel — idempotent, retried, impossible to attach to a run
that doesn't exist — and it passes the same class of guard a dispatch lede does
before it reaches a public page.

Visibility is the adventurer page's rule exactly, and that matters more here
than anywhere: the report outlives the log by a fortnight and is linked from a
public dispatch, so it is the surface most likely to still be reachable after
somebody opts out. Coming off the board closes it, including through links
minted days earlier.

Claude-Session: https://claude.ai/code/session_012bxpQQJDjC1mTtLN3VVtBQ
2026-07-24 17:11:04 -07:00
prosolis 7051e8ffff adventure: give every dispatch a card that looks like what it is
Every dispatch rendered the same image: one violet gradient, a swapped
emoji, a label. A death, a first-ever clear and a legendary hoard were
visually identical — and this image is not decoration. It is the
og:image on every link Pete puts in Matrix and the thumbnail on every
feed card. The most interesting thing that has ever happened in the
realm looked exactly like the most routine.

The card is now keyed on the dispatch GUID instead of the event type,
so the renderer can read the fact behind it and put the actual nouns on
it — the boss's name, the zone, the item, the level. Each family gets
its own palette, and treasure is tinted by the rarity gogobee already
computes and currently spends on an adjective in a sentence.

A realm-first gets visible ceremony. The priority/bulletin split is
already computed upstream and until now it only decided whether Matrix
got pinged; a thing nobody has ever done should also look different
from the ninth time somebody did it. It earns a ribbon on the card and
a badge and a heavier ring in the feed.

Siege cards carry the HP bar, which is the W1 deferral landing. The
siege fact has the boss and the defender count but never the HP, so the
bar comes from the war-room snapshot: the live row while that boss is
still camped, the history once it has closed. When neither has it yet —
the real two-minute window between a win being filed and the push that
explains it — the card renders barless rather than wrong, and caches
for five minutes instead of a day so the unfurl isn't pinned that way.

Nothing needs backfilling. A story with a type-keyed image_url still
serves, and a dispatch with no stored fact degrades to the old emblem.

Two things learned by looking at the rendered output rather than at the
tests, both of which unit tests would never have caught: the feed
thumbnail is a 16/10 crop of a 1200x630 card and was eating the chip
("EGENDARY"), hence advSafeX; and an empty bar under a victory headline
reads at a glance as a wipe, hence the event-aware caption.

Claude-Session: https://claude.ai/code/session_012bxpQQJDjC1mTtLN3VVtBQ
2026-07-24 15:47:44 -07:00
prosolis 6219224ea9 adventure: count the treasures an adventurer has actually found
A treasure_found fact turns loot into a trophy: a story-grade find lands on the
who page as a stat tile, a named row in a Treasures found showcase, and a trail
entry linking back to the dispatch. A realm-first hoard rides the priority tier
the way zone_first does, and gets the same star and callout.

The item name travels in the fact's stakes field, which the events log now keeps
(a new nullable column, backfilled to NULL for older rows). Counting is only ever
from the fact, never the vault snapshot, so a bought sword is never a trophy and a
history that predates the fact is a clean zero.

This is a new event_type, so Pete's ingest must be deployed before gogobee emits
one, or the first finds park forever on the retry ladder.
2026-07-17 09:02:19 -07:00
prosolis cbe9e67b3e adventure: keep the facts, not just the sentence we made of them
gogobee already sends boss/opponent/zone/outcome/level on every dispatch.
renderAdventure melted them into prose and only the prose was persisted, so
"how many bosses has she downed" was answerable only by parsing English back
out of a headline.

adventure_events keeps the fact as fact. It's the one adventure table that's a
log rather than a snapshot: the roster answers where Josie is now and is
replaced every tick; this answers what she has ever done, which no snapshot
can. INSERT OR IGNORE on the guid because gogobee retries a fact whose ack it
lost, and this is the only adventure store where a duplicate is permanently
wrong — the roster forgives one by replacing itself, a double-counted kill is
in the tally forever.

On top of it the who page grows two public sections, counted from dispatches
that were already public: the record (tallies, per-boss and per-zone, realm
firsts, milestones) and the trail (the last 40 facts, each linking to the
dispatch that told it). One read feeds both — the pool is MaxOpenConns(1), so
six COUNT queries would serialize for an answer that fits in memory.

Only the trail is capped. A limit on the read would truncate a *tally* rather
than a list, and a veteran's kill count frozen at 40 reads as a fact instead of
a missing page. Only the subject of a fact earns a trophy: a duel you lost
still names you, and it belongs on your trail but not in your record.

Trophies count forward only. Every adventurer's past is prose in the feed and
can't be counted back out, so they show no record until they next do something
— a clean absence rather than a wall of zeroes.

No treasures: there's no loot fact on the wire, and inventory is current-state
with no history, so counting the vault would score a bought sword as a trophy.
Needs a fact type upstream.
2026-07-16 23:57:23 -07:00