refactor: extract resolveActiveRole() as single source of status→role mapping

resolveCursorKey and resolveChannel both duplicated the same
taskStatus→role switch. Now resolveActiveRole() is the single
mapping, and both functions derive from it.
This commit is contained in:
Eyejoker
2026-03-30 22:58:00 +09:00
parent a91776b067
commit 14d70f345a
2 changed files with 27 additions and 30 deletions

View File

@@ -39,28 +39,30 @@ export function pairedCursorKey(
return isReviewerTurn ? `${chatJid}:reviewer` : chatJid; return isReviewerTurn ? `${chatJid}:reviewer` : chatJid;
} }
/** /** Map task status to the active role. */
* Auto-resolve the cursor key based on current paired task status. export function resolveActiveRole(
* Non-paired rooms always return chatJid. taskStatus?: string | null,
* Paired rooms return role-specific keys so owner/reviewer/arbiter ): 'owner' | 'reviewer' | 'arbiter' {
* cursors are independent. switch (taskStatus) {
*/ case 'review_ready':
case 'in_review':
return 'reviewer';
case 'arbiter_requested':
case 'in_arbitration':
return 'arbiter';
default:
return 'owner';
}
}
/** Cursor key for a role. Owner uses chatJid, others use chatJid:role. */
export function resolveCursorKey( export function resolveCursorKey(
chatJid: string, chatJid: string,
taskStatus?: string | null, taskStatus?: string | null,
): string { ): string {
if (!isPairedRoomJid(chatJid)) return chatJid; if (!isPairedRoomJid(chatJid)) return chatJid;
if (!taskStatus) return chatJid; const role = resolveActiveRole(taskStatus);
switch (taskStatus) { return role === 'owner' ? chatJid : `${chatJid}:${role}`;
case 'review_ready':
case 'in_review':
return `${chatJid}:reviewer`;
case 'arbiter_requested':
case 'in_arbitration':
return `${chatJid}:arbiter`;
default:
return chatJid;
}
} }
export function createImplicitContinuationTracker(idleTimeout: number) { export function createImplicitContinuationTracker(idleTimeout: number) {

View File

@@ -41,6 +41,7 @@ import { isTriggerAllowed, loadSenderAllowlist } from './sender-allowlist.js';
import { import {
advanceLastAgentCursor, advanceLastAgentCursor,
createImplicitContinuationTracker, createImplicitContinuationTracker,
resolveActiveRole,
resolveCursorKey, resolveCursorKey,
filterLoopingPairedBotMessages, filterLoopingPairedBotMessages,
getProcessableMessages, getProcessableMessages,
@@ -536,18 +537,13 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
const arbiterChannel = foundArbiterChannel || channel; const arbiterChannel = foundArbiterChannel || channel;
// Resolve the correct Discord channel for a given task status. // Resolve the correct Discord channel for a given task status.
const resolveChannel = (taskStatus?: string | null): Channel => { const roleToChannel: Record<string, Channel> = {
switch (taskStatus) { owner: channel,
case 'review_ready': reviewer: reviewerChannel,
case 'in_review': arbiter: arbiterChannel,
return reviewerChannel;
case 'arbiter_requested':
case 'in_arbitration':
return arbiterChannel;
default:
return channel;
}
}; };
const resolveChannel = (taskStatus?: string | null): Channel =>
roleToChannel[resolveActiveRole(taskStatus)] ?? channel;
if (isPairedRoomJid(chatJid)) { if (isPairedRoomJid(chatJid)) {
logger.info( logger.info(
@@ -832,8 +828,7 @@ export function createMessageRuntime(deps: MessageRuntimeDeps): {
// Arbiter turns use a dedicated context prompt; regular turns use formatted messages. // Arbiter turns use a dedicated context prompt; regular turns use formatted messages.
const isArbiterTurn = const isArbiterTurn =
taskStatus === 'arbiter_requested' || taskStatus === 'arbiter_requested' || taskStatus === 'in_arbitration';
taskStatus === 'in_arbitration';
let prompt: string; let prompt: string;
if (isArbiterTurn && pendingTaskForChannel) { if (isArbiterTurn && pendingTaskForChannel) {
const arbiterMsgs = labelPairedSenders( const arbiterMsgs = labelPairedSenders(