Reviewer/arbiter/owner Codex turns are no longer deferred during the [03:00-08:00 KST] dawn window — they dispatch immediately at all hours. Deletes codex-primer-alignment.ts and every hold call site (gating owner hold + alignment notice, reviewer/arbiter queue hold, warm-up skip, primer anchor-lock). The 08:00 primer still fires; it just no longer holds other consumers. Tradeoff: the 13:00 KST 5h-reset anchoring is no longer enforced. Also adds a user-visible next-step indicator after owner turns that do not end the task (review_ready -> reviewer requested, arbiter_requested -> arbiter called) so a same-looking status line is no longer ambiguous; no extra line on completion to avoid duplicating the owner's final message. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
62 lines
1.6 KiB
TypeScript
62 lines
1.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import type { RegisteredGroup } from './types.js';
|
|
|
|
const { handleSessionCommandMock } = vi.hoisted(() => ({
|
|
handleSessionCommandMock: vi.fn(),
|
|
}));
|
|
|
|
vi.mock('./session-commands.js', () => ({
|
|
handleSessionCommand: handleSessionCommandMock,
|
|
}));
|
|
|
|
import { handleQueuedRunGates } from './message-runtime-gating.js';
|
|
|
|
function makeArgs(overrides: {
|
|
chatJid?: string;
|
|
sendMessage?: () => Promise<void>;
|
|
}) {
|
|
return {
|
|
chatJid: overrides.chatJid ?? 'room-1',
|
|
group: {
|
|
folder: 'room-folder',
|
|
name: 'room',
|
|
isMain: false,
|
|
trigger: '코덱스',
|
|
added_at: new Date().toISOString(),
|
|
} satisfies RegisteredGroup,
|
|
runId: 'run-1',
|
|
missedMessages: [],
|
|
triggerPattern: /^코덱스/,
|
|
timezone: 'Asia/Seoul',
|
|
hasImplicitContinuationWindow: () => false,
|
|
sessionCommandDeps: {
|
|
sendMessage: overrides.sendMessage ?? (async () => {}),
|
|
} as never,
|
|
};
|
|
}
|
|
|
|
describe('message-runtime-gating', () => {
|
|
beforeEach(() => {
|
|
handleSessionCommandMock.mockReset();
|
|
});
|
|
|
|
it('returns session-command results directly when a command is handled', async () => {
|
|
handleSessionCommandMock.mockResolvedValue({
|
|
handled: true,
|
|
success: false,
|
|
});
|
|
|
|
const result = await handleQueuedRunGates(makeArgs({}));
|
|
|
|
expect(result).toEqual({ handled: true, success: false });
|
|
});
|
|
|
|
it('falls through when no session command matched', async () => {
|
|
handleSessionCommandMock.mockResolvedValue({ handled: false });
|
|
|
|
const result = await handleQueuedRunGates(makeArgs({}));
|
|
|
|
expect(result).toEqual({ handled: false });
|
|
});
|
|
});
|