mirror of
https://github.com/prosolis/gogobee.git
synced 2026-09-14 10:51:09 +00:00
adventure: read a finished run back and tell Pete what it was about
Two halves of the same gap. A dispatch announcing a clear, a retreat or a death said how an expedition ended and gave a reader no way to reach what happened in it — so those three facts now carry the run they concluded, and Pete's permalink can open the log behind the headline. Finding that run is done by asking what is actually true at the moment a dispatch is filed rather than by threading a run id through five call sites that have already let go of it. Both guards on that lookup are load-bearing: a run with no beats behind it would mint a link to a 404, and without the recency window a campaign death at the Empty Throne would attach itself to whatever dungeon that player last walked. The other half is the summary. Every line of the liveblog is assembled by Pete out of a beat's own nouns, which is right for a log — it has to be exactly what happened, in order. But a report is read afterwards and the question it answers is not "what happened", it is "what was that run", and that is a judgement. So this is the one piece of prose on the channel, and it earns the model far better than a dispatch headline does. It runs on the roster ticker, not at the moment the run ends. A run ending is already a chokepoint with a dispatch being authored against it, and a second generation there would stall the command that killed the boss. One per tick, and a run that can't be summarised is closed out with an empty beat rather than retried forever — the row is what stops the sweep picking it up again, and a report with no summary is still the log and the numbers. The prompt states the one permitted name twice and forbids arithmetic: a model asked to write warmly about a party will invent a second member of it, and a total it works out itself will contradict the exact totals printed beside it. Both were seen against the real box before this was tightened. Claude-Session: https://claude.ai/code/session_012bxpQQJDjC1mTtLN3VVtBQ
This commit is contained in:
@@ -85,6 +85,49 @@ func runHasEndBeat(runID string) bool {
|
||||
return err == nil && n > 0
|
||||
}
|
||||
|
||||
// latestRunIDForNews is the run a just-filed dispatch is about, or "" when there
|
||||
// isn't one to point at.
|
||||
//
|
||||
// The three dispatches that end an expedition — a clear, a retreat, a death —
|
||||
// are all emitted *after* the run they concluded has been closed, and two of
|
||||
// them from call sites several frames away from the run row. So rather than
|
||||
// thread a run id through five signatures and hope the lifetimes line up, this
|
||||
// asks the question that is actually true at that moment: what is the last run
|
||||
// this player started. A player has one run at a time and a dispatch about their
|
||||
// expedition ending is about that one. Multi-region is the case worth stating:
|
||||
// each region gets its own run, and the last one started is the one they were
|
||||
// standing in when it ended, which is the log the dispatch should open.
|
||||
//
|
||||
// Two clauses do the real work and neither is optional:
|
||||
//
|
||||
// - The `pete_run_beat` check. Runs exist with no beats behind them — from
|
||||
// before the liveblog shipped, or with the seam off — and handing Pete a run
|
||||
// id it has nothing for would mint a dispatch link to a 404.
|
||||
// - The recency window. Not every death happens in a dungeon: the campaign
|
||||
// path kills people at the Empty Throne, and without this a death that had
|
||||
// nothing to do with any expedition would link to whatever run that player
|
||||
// last walked, possibly days ago. An expedition-ending dispatch is filed
|
||||
// seconds after its run closes, so "still open, or closed just now" is the
|
||||
// honest test for "this dispatch is about that run".
|
||||
func latestRunIDForNews(userID id.UserID) string {
|
||||
if userID == "" || !peteclient.Enabled() {
|
||||
return ""
|
||||
}
|
||||
var runID string
|
||||
err := db.Get().QueryRow(`
|
||||
SELECT r.run_id
|
||||
FROM dnd_zone_run r
|
||||
WHERE r.user_id = ?
|
||||
AND (r.completed_at IS NULL OR r.completed_at >= datetime('now', '-10 minutes'))
|
||||
AND EXISTS (SELECT 1 FROM pete_run_beat b WHERE b.run_id = r.run_id)
|
||||
ORDER BY r.started_at DESC, r.rowid DESC
|
||||
LIMIT 1`, string(userID)).Scan(&runID)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return runID
|
||||
}
|
||||
|
||||
// runBeatPushOK mirrors rosterPushOK: log the transitions, stay quiet otherwise.
|
||||
var runBeatPushOK bool
|
||||
|
||||
|
||||
Reference in New Issue
Block a user