Review follow-ups L + I: drop dead openParty, unify the menu-index parser

L: openParty had no production callers (invite path uses joinParty -> seatLeader,
which seats the leader the same way but reads the owner off the expedition row).
Removed it; the tests now seat the leader through a seatLeaderFixture that wraps
seatLeader in a transaction.

I: promoted parseTemperIndex to parseMenuIndex and routed resolveMagicEquipReply
and handleMasterworkEquipReply through it, replacing two hand-inlined copies of
the same digit parser. Behaviour-preserving (the parsed flag was redundant with
the idx<0 guard); the retry-on-bad-parse disagreement is left as-is since this
is a pure dedup.

Full plugin suite green.

Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
This commit is contained in:
prosolis
2026-07-10 08:55:07 -07:00
parent d7a5333048
commit 1f1fbf0251
6 changed files with 48 additions and 77 deletions

View File

@@ -22,6 +22,24 @@ func seedExpedition(t *testing.T, expeditionID string, owner id.UserID, status s
}
}
// seatLeaderFixture seats the expedition's leader the way the invite path does —
// through seatLeader in its own transaction — reading the owner off the row that
// seedExpedition already wrote. Replaces the retired openParty helper.
func seatLeaderFixture(t *testing.T, expeditionID string) {
t.Helper()
tx, err := db.Get().Begin()
if err != nil {
t.Fatal(err)
}
if err := seatLeader(tx, expeditionID); err != nil {
_ = tx.Rollback()
t.Fatalf("seatLeader %s: %v", expeditionID, err)
}
if err := tx.Commit(); err != nil {
t.Fatal(err)
}
}
func TestParty_SoloExpeditionHasNoRoster(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@solo:example.org")
@@ -53,10 +71,9 @@ func TestParty_OpenIsIdempotent(t *testing.T) {
owner := id.UserID("@lead:example.org")
seedExpedition(t, "exp-1", owner, "active")
// seatLeader is idempotent — a second call on the same expedition is a no-op.
for i := 0; i < 2; i++ {
if err := openParty("exp-1", owner); err != nil {
t.Fatalf("openParty #%d: %v", i+1, err)
}
seatLeaderFixture(t, "exp-1")
}
members, err := partyMembers("exp-1")
if err != nil {
@@ -71,9 +88,7 @@ func TestParty_JoinSeatsMembersLeaderFirst(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@lead2:example.org")
seedExpedition(t, "exp-2", owner, "active")
if err := openParty("exp-2", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-2")
for _, u := range []id.UserID{"@b:x", "@c:x"} {
if err := joinParty("exp-2", u); err != nil {
t.Fatalf("joinParty %s: %v", u, err)
@@ -127,9 +142,7 @@ func TestParty_JoinRefusesFullRoster(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@lead3:example.org")
seedExpedition(t, "exp-3", owner, "active")
if err := openParty("exp-3", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-3")
for _, u := range []id.UserID{"@b:x", "@c:x"} {
if err := joinParty("exp-3", u); err != nil {
t.Fatal(err)
@@ -145,9 +158,7 @@ func TestParty_JoinRefusesDuplicate(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@lead4:example.org")
seedExpedition(t, "exp-4", owner, "active")
if err := openParty("exp-4", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-4")
if err := joinParty("exp-4", "@b:x"); err != nil {
t.Fatal(err)
}
@@ -167,12 +178,8 @@ func TestParty_JoinRefusesPlayerBusyElsewhere(t *testing.T) {
setupEmptyTestDB(t)
seedExpedition(t, "exp-5", "@lead5:example.org", "active")
seedExpedition(t, "exp-6", "@lead6:example.org", "active")
if err := openParty("exp-5", "@lead5:example.org"); err != nil {
t.Fatal(err)
}
if err := openParty("exp-6", "@lead6:example.org"); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-5")
seatLeaderFixture(t, "exp-6")
// Owns their own active expedition.
seedExpedition(t, "exp-own", "@busy:example.org", "active")
@@ -198,9 +205,7 @@ func TestParty_LeaveRemovesMemberButNotLeader(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@lead7:example.org")
seedExpedition(t, "exp-7", owner, "active")
if err := openParty("exp-7", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-7")
if err := joinParty("exp-7", "@b:x"); err != nil {
t.Fatal(err)
}
@@ -217,9 +222,7 @@ func TestParty_LeaveRemovesMemberButNotLeader(t *testing.T) {
}
// Leaving frees the member for their own next run.
seedExpedition(t, "exp-7b", "@lead7b:example.org", "active")
if err := openParty("exp-7b", "@lead7b:example.org"); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-7b")
if err := joinParty("exp-7b", "@b:x"); err != nil {
t.Errorf("departed member could not rejoin elsewhere: %v", err)
}
@@ -229,9 +232,7 @@ func TestParty_DisbandFreesEveryone(t *testing.T) {
setupEmptyTestDB(t)
owner := id.UserID("@lead8:example.org")
seedExpedition(t, "exp-8", owner, "complete")
if err := openParty("exp-8", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-8")
if err := joinParty("exp-8", "@b:x"); err != nil {
t.Fatal(err)
}
@@ -242,9 +243,7 @@ func TestParty_DisbandFreesEveryone(t *testing.T) {
t.Errorf("after disband, partySize = %d, want 1 (no rows)", n)
}
seedExpedition(t, "exp-8b", "@lead8b:example.org", "active")
if err := openParty("exp-8b", "@lead8b:example.org"); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-8b")
if err := joinParty("exp-8b", "@b:x"); err != nil {
t.Errorf("disbanded member still looks busy: %v", err)
}
@@ -257,9 +256,7 @@ func TestParty_ActiveExpeditionForResolvesBothRoles(t *testing.T) {
owner := id.UserID("@lead9:example.org")
member := id.UserID("@member9:example.org")
seedExpedition(t, "exp-9", owner, "active")
if err := openParty("exp-9", owner); err != nil {
t.Fatal(err)
}
seatLeaderFixture(t, "exp-9")
if err := joinParty("exp-9", member); err != nil {
t.Fatal(err)
}