fix(housekeeping): serialize set-rank intents
CI / runtime-diagnostics (pull_request) Canceled after 0s
CI / check (pull_request) Canceled after 0s
CI / deploy (pull_request) Canceled after 0s
CI / release (pull_request) Canceled after 0s

This commit is contained in:
Simo committed 2026-09-03 21:29:29 +02:00
1 parent 48096833ec
commit 2c5db2168b
2 files changed
+21 -2

No files matched your search

@@ -922,7 +922,7 @@ async function executeRconMutation(
.select({ rank: User.rank })
.from(User)
.where(eq(User.id, userId))
.limit(1);
.for("update");
if (!target) {
throw new SystemMutationFailure(
"NOT_FOUND",
@@ -12,6 +12,7 @@ const doubles = vi.hoisted(() => ({
createEmulatorRankInTransaction: vi.fn(),
dbDelete: vi.fn(),
dbExecute: vi.fn(),
dbForUpdate: vi.fn(),
dbInsert: vi.fn(),
dbSelect: vi.fn(),
dbTransaction: vi.fn(),
@@ -117,10 +118,11 @@ function updateChain(result: Promise<unknown> = Promise.resolve(undefined)) {
}
function limitedSelection(rows: readonly unknown[]) {
doubles.dbForUpdate.mockResolvedValueOnce(rows);
return {
from: () => ({
where: () => ({
for: () => Promise.resolve(rows),
for: doubles.dbForUpdate,
limit: () => Promise.resolve(rows),
}),
}),
@@ -310,6 +312,23 @@ describe("durable rank synchronization", () => {
expect(doubles.rconSetRank).not.toHaveBeenCalled();
});
it("locks the user row before committing a set-rank intent", async () => {
doubles.dbSelect.mockImplementationOnce(() =>
limitedSelection([{ rank: 3 }]),
);
doubles.dbExecute.mockResolvedValue([[{ id: 4 }]]);
doubles.rconSetRank.mockResolvedValue(true);
const result = await systemMutationService.execute(
serviceContext(PERMS.RCON_EXECUTE),
"rcon.set-rank",
{ userId: 8, rank: 4 },
);
expect(result).toMatchObject({ ok: true });
expect(doubles.dbForUpdate).toHaveBeenCalledWith("update");
});
it("returns the durable recovery key when set-rank RCON fails after commit", async () => {
doubles.dbSelect.mockImplementationOnce(() =>
limitedSelection([{ rank: 3 }]),