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:
Codex
2026-06-18 05:24:28 +09:00
parent a621e85432
commit be9f2379c0
9 changed files with 105 additions and 382 deletions

View File

@@ -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 });
});
});