adventure: work the five review findings the last pass left open
The extract pre-check is gone. It read a snapshot up to two minutes behind and still got the last word, so somebody who set out over Matrix during a lagging roster push was told they weren't on an expedition for a run gogobee would happily have ended. Same call abandon and leave already made: let it through and let rejected_not_running be the answer. The siege_join check stays, because whether a boss is camped outside town is town-wide and runs on a day-or-longer clock, but it now reads one column through SiegeIsCamped instead of loading every defender row and the whole history to look at one flag. The war-room history insert is OR REPLACE. boss_id is the primary key and it was never settled whether gogobee means the siege instance or the boss type by it, so a duplicate pair used to fail the transaction carrying the live boss and the muster too and freeze the war room on the last good snapshot. A dropped history row is the smaller failure; the open question is noted in the schema. offersToUndo's guard didn't cover the case its comment claimed. A gogobee too old to push seats sends a valid blob with no party key, which decodes to the same empty slice as a solo run, and a party member got shown the button that throws away everyone's day. That needs a new field, so whoDetail gains party_known and the flag gates the empty-list branch alone; the branch that reads the viewer's own seat is self-evidencing and keeps working against any sender. gogobee's half is written up in adventure_party_known_flag.md. And an empty offer list no longer claims "you're already out there", which Pete can't actually know from a game box too old to push offers at all.
This commit is contained in:
+16
-11
@@ -108,15 +108,18 @@ func TestOnlyOneOutstandingOrderPerVerb(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestActionPreChecksAreCourtesyOnly pins both halves of a deliberate asymmetry.
|
||||
// Pete refuses what its own snapshot says is impossible — but the snapshot is up
|
||||
// to two minutes old, so the refusal must be cheap and local (a 409 the button
|
||||
// shows immediately), never a queued order gogobee has to answer.
|
||||
func TestActionPreChecksAreCourtesyOnly(t *testing.T) {
|
||||
// Idle mark: extract refused up front.
|
||||
// TestOnlyTownWideFactsArePreChecked. Pete's copy of the board is up to two
|
||||
// minutes behind the game box, so what it may refuse locally turns on whether
|
||||
// being two minutes late could make the answer wrong. A personal status can:
|
||||
// somebody who set out over Matrix still reads as idle here, and refusing their
|
||||
// extract would deny a run gogobee would have ended. A boss camped outside town
|
||||
// cannot: that is town-wide and runs on a day-or-longer clock.
|
||||
func TestOnlyTownWideFactsArePreChecked(t *testing.T) {
|
||||
// Idle mark: extract goes through anyway, and rejected_not_running is the
|
||||
// answer if the mark really was standing in town.
|
||||
s := seedActions(t, "holymachina", "idle")
|
||||
if w := placeAction(t, s, "holymachina", "extract"); w.Code != 409 {
|
||||
t.Fatalf("extract while idle = %d, want 409", w.Code)
|
||||
if w := placeAction(t, s, "holymachina", "extract"); w.Code != 200 {
|
||||
t.Fatalf("extract while idle = %d, want it queued (%s)", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// No Siege pushed at all: unknown, not "inactive". Pete has never heard from
|
||||
@@ -328,10 +331,12 @@ func TestExpeditionParamsAreResolvedAgainstTheOwnersOffers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// An empty zone list means "already out there", not "nowhere to go" — gogobee
|
||||
// omits the offers entirely while the adventurer is on an expedition. Refusing
|
||||
// An empty zone list is a refusal, and the message says only what Pete saw. It
|
||||
// usually means the adventurer is already out — gogobee omits the offers
|
||||
// entirely while they are down there — but a game box too old to push offers
|
||||
// sends the same empty list, so the copy claims nothing about which. Refusing
|
||||
// cheaply here beats a verdict thirty seconds later saying the same thing.
|
||||
func TestNoZoneOffersMeansAlreadyOut(t *testing.T) {
|
||||
func TestNoZoneOffersMeansNothingOnOffer(t *testing.T) {
|
||||
s := seedOffers(t, "holymachina", "expedition", storage.PlayerDetail{})
|
||||
w := placeParams(t, s, "holymachina", advOrderReq{
|
||||
Action: storage.AdvActionExpedition, Zone: "goblin_warrens", Loadout: "lean",
|
||||
|
||||
Reference in New Issue
Block a user