fix: harden paired runtime turn coordination

This commit is contained in:
ejclaw
2026-04-09 13:52:42 +09:00
parent e7a7b538b2
commit 0f994ab2ce
27 changed files with 2108 additions and 295 deletions

View File

@@ -15,6 +15,7 @@ import {
resolveCursorKeyForRole,
resolveQueuedTurnRole,
} from './message-runtime-rules.js';
import { claimPairedTurnExecution } from './paired-follow-up-scheduler.js';
import type {
ExecuteTurnFn,
RoleToChannelMap,
@@ -23,9 +24,30 @@ import type {
Channel,
NewMessage,
PairedTask,
PairedTurnReservationIntentKind,
RegisteredGroup,
} from './types.js';
function resolveQueuedTurnReservationIntent(args: {
task: PairedTask;
turnRole: 'owner' | 'reviewer' | 'arbiter';
hasHumanMessage: boolean;
}): PairedTurnReservationIntentKind {
if (args.turnRole === 'reviewer') {
return 'reviewer-turn';
}
if (args.turnRole === 'arbiter') {
return 'arbiter-turn';
}
if (args.hasHumanMessage) {
return 'owner-turn';
}
if (args.task.status === 'merge_ready') {
return 'finalize-owner-turn';
}
return 'owner-follow-up';
}
export async function runPendingPairedTurnIfNeeded(args: {
chatJid: string;
group: RegisteredGroup;
@@ -79,6 +101,29 @@ export async function runPendingPairedTurnIfNeeded(args: {
return null;
}
if (pendingTurn.channel) {
const claimedUpdatedAt = claimPairedTurnExecution({
chatJid,
runId: args.runId,
task,
intentKind: pendingTurn.intentKind,
});
if (!claimedUpdatedAt) {
args.log.info(
{
chatJid,
taskId: task.id,
taskStatus: task.status,
taskUpdatedAt: task.updated_at,
intentKind: pendingTurn.intentKind,
},
'Skipped paired pending turn because the task revision was already claimed elsewhere',
);
return true;
}
task.updated_at = claimedUpdatedAt;
}
return executePendingPairedTurn({
pendingTurn,
chatJid,
@@ -176,6 +221,34 @@ export async function runQueuedGroupTurn(args: {
return false;
}
if (task) {
const intentKind = resolveQueuedTurnReservationIntent({
task,
turnRole,
hasHumanMessage: hasHumanMsg,
});
const claimedUpdatedAt = claimPairedTurnExecution({
chatJid,
runId,
task,
intentKind,
});
if (!claimedUpdatedAt) {
log.info(
{
taskId: task.id,
taskStatus,
taskUpdatedAt: task.updated_at,
intentKind,
turnRole,
},
'Skipped queued paired turn because the task revision was already claimed elsewhere',
);
return true;
}
task.updated_at = claimedUpdatedAt;
}
if (endSeq !== null) {
advanceLastAgentCursor(
args.lastAgentTimestamps,