fix(paired): remove dawn Codex primer-alignment hold; add owner routing indicator
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>
This commit is contained in:
@@ -1,25 +1,14 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { RegisteredGroup } from './types.js';
|
||||
|
||||
const { handleSessionCommandMock, getEffectiveChannelLeaseMock } = vi.hoisted(
|
||||
() => ({
|
||||
handleSessionCommandMock: vi.fn(),
|
||||
getEffectiveChannelLeaseMock: vi.fn(),
|
||||
}),
|
||||
);
|
||||
const { handleSessionCommandMock } = vi.hoisted(() => ({
|
||||
handleSessionCommandMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./session-commands.js', () => ({
|
||||
handleSessionCommand: handleSessionCommandMock,
|
||||
}));
|
||||
|
||||
vi.mock('./service-routing.js', () => ({
|
||||
getEffectiveChannelLease: getEffectiveChannelLeaseMock,
|
||||
}));
|
||||
|
||||
import {
|
||||
beginPrimerAnchor,
|
||||
endPrimerAnchor,
|
||||
} from './codex-primer-alignment.js';
|
||||
import { handleQueuedRunGates } from './message-runtime-gating.js';
|
||||
|
||||
function makeArgs(overrides: {
|
||||
@@ -49,16 +38,6 @@ function makeArgs(overrides: {
|
||||
describe('message-runtime-gating', () => {
|
||||
beforeEach(() => {
|
||||
handleSessionCommandMock.mockReset();
|
||||
getEffectiveChannelLeaseMock.mockReset();
|
||||
// Default: claude owner, no failover → no alignment hold.
|
||||
getEffectiveChannelLeaseMock.mockReturnValue({
|
||||
owner_agent_type: 'claude-code',
|
||||
owner_failover_active: false,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
endPrimerAnchor();
|
||||
});
|
||||
|
||||
it('returns session-command results directly when a command is handled', async () => {
|
||||
@@ -72,49 +51,11 @@ describe('message-runtime-gating', () => {
|
||||
expect(result).toEqual({ handled: true, success: false });
|
||||
});
|
||||
|
||||
it('falls through when no command and the room owner is not on Codex', async () => {
|
||||
it('falls through when no session command matched', async () => {
|
||||
handleSessionCommandMock.mockResolvedValue({ handled: false });
|
||||
beginPrimerAnchor(); // force the alignment window on, isolate provider check
|
||||
|
||||
const result = await handleQueuedRunGates(makeArgs({}));
|
||||
|
||||
expect(result).toEqual({ handled: false });
|
||||
});
|
||||
|
||||
it('holds a codex-owner turn during the alignment window and notifies once', async () => {
|
||||
handleSessionCommandMock.mockResolvedValue({ handled: false });
|
||||
getEffectiveChannelLeaseMock.mockReturnValue({
|
||||
owner_agent_type: 'codex',
|
||||
owner_failover_active: false,
|
||||
});
|
||||
beginPrimerAnchor();
|
||||
const sendMessage = vi.fn(async () => {});
|
||||
|
||||
const first = await handleQueuedRunGates(
|
||||
makeArgs({ chatJid: 'room-codex', sendMessage }),
|
||||
);
|
||||
const second = await handleQueuedRunGates(
|
||||
makeArgs({ chatJid: 'room-codex', sendMessage }),
|
||||
);
|
||||
|
||||
expect(first).toEqual({ handled: true, success: true });
|
||||
expect(second).toEqual({ handled: true, success: true });
|
||||
// Notice deduped: sent once across repeated holds in the same window.
|
||||
expect(sendMessage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('holds a claude-owner room when global failover routes the owner to Codex', async () => {
|
||||
handleSessionCommandMock.mockResolvedValue({ handled: false });
|
||||
getEffectiveChannelLeaseMock.mockReturnValue({
|
||||
owner_agent_type: 'claude-code',
|
||||
owner_failover_active: true,
|
||||
});
|
||||
beginPrimerAnchor();
|
||||
|
||||
const result = await handleQueuedRunGates(
|
||||
makeArgs({ chatJid: 'room-failover' }),
|
||||
);
|
||||
|
||||
expect(result).toEqual({ handled: true, success: true });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user