adventure: let a player act from the web, not just read about it

The equip queue proved the reverse pipe works. This gives it verbs that
play the game: pull out of a run from the adventurer page, take today's
bout from the war room.

Its own table and its own poll, not more actions on equip_orders. Every
column of that table is equip vocabulary (item, slot, tier) and these
verbs act on the character rather than on something it is carrying.

Nothing in a request names an adventurer. The session maps to one
localpart and a localpart to one adventurer, so Pete resolves the
character itself and there is no id on the wire to forge.

The panel's copy is kept honest by the verdict: an applied action hides
the offer it has just spent, a refusal puts the button back. Watching it
run is what put that there, along with the strip's layout — gogobee
answers a bout with a whole sentence of damage, which the equip strip's
two-column row squeezed into a column and wrapped the verb.

Claude-Session: https://claude.ai/code/session_012bxpQQJDjC1mTtLN3VVtBQ
This commit is contained in:
prosolis
2026-07-24 18:55:42 -07:00
parent b19ab5eff0
commit 6b0aae9f4a
10 changed files with 1178 additions and 9 deletions
+37
View File
@@ -393,6 +393,43 @@ CREATE TABLE IF NOT EXISTS equip_orders (
CREATE INDEX IF NOT EXISTS idx_equip_orders_pending ON equip_orders(status, created_at);
CREATE INDEX IF NOT EXISTS idx_equip_orders_owner ON equip_orders(owner_sub, created_at DESC);
-- An action an owner asked for from the web — pull out of a run, take today's
-- swing at the Siege — on its way to gogobee. Same reverse-pipe shape as
-- equip_orders and the same guid-as-idempotency-key contract, but a SEPARATE
-- table on purpose: every column of equip_orders is equip vocabulary (item, slot,
-- tier), and these verbs act on the character rather than on something it is
-- carrying. Sharing the table would have meant rows where most columns are
-- meaningless and an action set nobody could read.
--
-- The status ladder:
--
-- pending -> applied (it happened; detail says what)
-- -> rejected_not_running (extract: no expedition to leave)
-- -> rejected_not_leader (extract: a party member can't call it)
-- -> rejected_no_siege (siege_join: nothing camped outside town)
-- -> rejected_already_fought (siege_join: today's bout is already spent)
-- -> rejected_unavailable (no character, or dead)
--
-- Like the equip queue, the underlying game action is NOT idempotent — an extract
-- ends an expedition and a bout spends a day — so gogobee short-circuits on the
-- guid before it mutates anything. token is the roster token the order was placed
-- from; gogobee ignores it (the localpart names the character) but it is what
-- Pete proved ownership against, and it keeps the row self-describing.
CREATE TABLE IF NOT EXISTS adventure_orders (
guid TEXT PRIMARY KEY,
owner_sub TEXT NOT NULL,
owner_localpart TEXT NOT NULL,
token TEXT NOT NULL DEFAULT '',
character_name TEXT NOT NULL DEFAULT '',
action TEXT NOT NULL, -- extract / siege_join
status TEXT NOT NULL, -- see the ladder above
detail TEXT, -- gogobee's human note on the verdict
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_adventure_orders_pending ON adventure_orders(status, created_at);
CREATE INDEX IF NOT EXISTS idx_adventure_orders_owner ON adventure_orders(owner_sub, created_at DESC);
-- A player's private, owner-only expansion — inventory, vault, house, pets —
-- pushed whole by gogobee on the roster tick. Keyed by localpart (== session
-- Username), a *separate keyspace* from the anonymous roster tokens on purpose: