The spec says what the wire should look like. This says where the work actually stands, which is the part that rots silently: two unpushed commits, nothing deployed, and a trophy case that can only count forward from a deploy that hasn't happened. Also records the decisions already settled (room graph over coordinates, server-side fog cut, mischief shape for equip, no faking treasures from vault contents) so they don't get relitigated, and the landmines that cost money to learn the first time.
8.0 KiB
Adventure expansion — progress & handoff
Last updated 2026-07-17. Companion to adventure_expansion_spec.md (the wire
contract). This file is the state of the work: what's done, what's next, and
what will bite whoever picks it up.
Read this first
adventure_expansion_spec.md— payloads, endpoints, file:line refs into both repos. It supersedes any older sketch of these asks.- This file — where the work actually stands.
The gogobee repo is at /home/reala-misaki/git/gogobee. It runs on millenia
(reala@192.168.1.212). Pete runs on reala@www.parodia.dev (bare ./pete in
a screen session, built on the server, with cgo).
Status of the five asks
| # | Ask | State |
|---|---|---|
| — | Trophy case / timeline ("The record" / "The trail") | Built, tests green, committed, NOT pushed, NOT deployed |
| — | Contract spec for the five | Written (adventure_expansion_spec.md) |
| 4 | Richer item view | Next up. Spec'd. Partly buildable — see below |
| 3 | Room graph → dungeon map + fog of war | Spec'd. Graph already exists in gogobee |
| 5 | equip_orders queue |
Spec'd. Copies mischief |
| 1 | treasure_found → treasures |
Spec'd, but blocked on a gogobee feature — no loot fact exists |
| 2 | LLM-authored dispatches | Spec'd. Do last — inverts a security guarantee |
Build order and the reasoning behind it are in the spec's last section.
⚠️ Unpushed and undeployed
Pete has two unpushed commits on main:
cbe9e67— adventure: keep the facts, not just the sentence we made of them (the trophy case / timeline feature —adventure_eventstable,internal/storage/adventure.go, the who-page sections)5fac163— adventure: pin the gogobee contract before Pete assumes it (the spec)
Nothing is deployed. The record/trail sections are live nowhere.
This is not a neutral delay. Trophies are only countable going forward —
they're built from adventure_events, which only starts filling once the
feature is deployed. Every fact gogobee emits between now and the deploy is
counted by nobody and cannot be counted back out later (the past is prose in the
story feed). The longer it sits, the more of every adventurer's history is
permanently uncountable. Deploy it soon, independent of where the expansion goes.
gogobee's tree has unrelated uncommitted postgame-zone work (combat engine, expedition sim, plan docs). It's mid-flight and not part of this project — leave it alone, and keep adventure-expansion edits in separate files and commits.
Next: ask 4, richer items
Chosen because it's additive-only, has real sources, carries no deploy-order hazard and no security surface, and is the smallest change that visibly improves the who page.
gogobee: itemViews (internal/plugin/pete_roster.go:210-225) currently
sends five of AdvItem's fields and drops two that already exist:
Slot(EquipmentSlot, non-empty for MasterworkGear)SkillSource(string, non-empty for MasterworkGear)
Also worth sending, from adjacent structs:
Desc— resolve at the push site fromMagicItem.Desc(magic_items.go:35-46) orEquipmentDef.Description(adventure_character.go:172-177).AdvItemrows carry no description of their own, which is why this is a push-site join and not a field copy.Attunement(does it need a bond) andAttuned(does it have one). Distinct, and both matter to a player deciding what to wear — the bond cap is 3.
Pete: extend ItemView (internal/storage/detail.go:23-29) to match
peteclient/client.go:356-362, then surface it on the who page.
Rides the private /api/ingest/detail push, so either side can deploy first.
Not buildable — do not spec it in: stat modifiers and requirements are not
modeled anywhere, not merely unsent. No attack/AC/ability deltas exist on
AdvItem or MagicItem; effects derive from Tier/Slot/SkillSource in
combat_stats.go:36 and combat_bridge.go:396,489. "+2 to hit" needs a gogobee
engine change first. Deriving a display-only approximation from Tier/Slot at the
push site is a lie the first time the engine and the display disagree.
Landmines
Things that cost money to learn, or that will cost money if forgotten.
Deploy order is a data-loss rule, not a preference. An unknown event_type
is a 400 on Pete; gogobee retries with backoff to maxAttempts=8 and then
parks the bulletin forever (peteclient/client.go:79-86,
plugin/pete.go:279-281). Pete's handler ships before gogobee emits
treasure_found, or the first treasures are gone permanently. Additive fields
on existing event types are safe in either order.
A limit on the fetch truncates a tally, not a list. EventsBySubject(name, 0)
means unlimited, and anything that counts must pass 0 and cap in the caller
(storage/adventure.go:108-114). A capped read would freeze a veteran's kill
count at 40 forever, reading as a fact rather than a missing page.
INSERT OR IGNORE on the guid is load-bearing, not defensive habit
(storage/adventure.go:45-58). gogobee retries facts whose ack it lost. This is
the only adventure store where a duplicate is permanently wrong — the roster
forgives one by replacing itself; a double-counted boss kill is in the tally
forever.
Only subject earns a trophy, never opponent. A duel Josie lost still
names her (as the opponent in the winner's dispatch). It belongs on her trail,
but crediting it would score a loss as a win. Pinned by
TestTrophyCaseIgnoresOpponentCredit.
Events key on character name, not roster token — that's what a fact carries; gogobee puts no stable character id on the wire. A rename takes the history with it.
Snapshots are dropped on failure, never queued (peteclient/client.go:320-327).
A retried snapshot is a lie about a moment that has passed, and the silence is
what makes Pete's 12-minute staleness timer honest. Asks 3 and 4 ride snapshots:
a dropped push means a stale map, not a wrong one.
The who page's tests render the real template, so a field slip 500s in the
suite — but only on paths the test data reaches. HasHistory false skips the
whole history block, which is why TestWhoHistoryPanels seeds facts through the
real ingest handler.
/api/mischief/claim is misnamed. It's a verdict endpoint; mischief has no
claimed state (storage/mischief.go:37-42). Don't repeat the name in
equip_orders — the spec calls it /api/equip/verdict.
The LLM dispatch guard inversion (ask 2). factGuard only checks the
structured Subject/Opponent fields, which is safe today only because Pete's
templates can print nothing Pete didn't interpolate. The moment gogobee's LLM
authors the prose, the guard is checking fields that are no longer the thing
being rendered, and character names are player-chosen. A prose-level guard is
required in the same change that accepts headline/lede, not as a
follow-up. Templates stop being the renderer and become the safety net — do not
delete them.
Decisions already made (don't relitigate)
- Room graph, not coordinates or a bare trail. Rooms with exits, a real
graph. It already exists in gogobee (
zone_graph.go); the wire throws it away. - Fog of war is a server-side cut, not a CSS style. Send visited nodes plus a
one-hop ring with
kind: "unknown". The map is a public page; "view source to find the boss room" is not fog of war. equip_orderscopies mischief, not escrow. An equip is a desired end state, not a delta, so a replay converges — mischief's precondition exactly. Noclaimedstate, no stale-reoffer window; the poll loop is its own retry.- Equip UI says "queued", never claims it landed. It lands on gogobee's next poll tick, up to 30s out. The order row's status is the truth.
- "Treasures found" won't be faked from vault contents. A bought sword is
not a trophy. Needs a real
treasure_foundfact. - Blank state over a wall of zeroes. Adventurers predating
adventure_eventsrender no record section at all. A clean absence, deliberate.