test: align prompt and scheduler expectations
This commit is contained in:
@@ -199,7 +199,7 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
expect(auth).toEqual(rotatedAuth);
|
expect(auth).toEqual(rotatedAuth);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses the failover prompt pack for codex-review when it owns an explicit failover lease', () => {
|
it('uses the failover owner prompt pack for codex-review when it owns an explicit failover lease', () => {
|
||||||
vi.mocked(config.isReviewService).mockReturnValue(true);
|
vi.mocked(config.isReviewService).mockReturnValue(true);
|
||||||
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
||||||
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
|
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
|
||||||
@@ -218,10 +218,6 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
path.join(promptsDir, 'codex-review-platform.md'),
|
path.join(promptsDir, 'codex-review-platform.md'),
|
||||||
'review platform prompt\n',
|
'review platform prompt\n',
|
||||||
);
|
);
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-paired-room.md'),
|
|
||||||
'review paired prompt\n',
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(promptsDir, 'owner-common-platform.md'),
|
path.join(promptsDir, 'owner-common-platform.md'),
|
||||||
'owner common platform prompt\n',
|
'owner common platform prompt\n',
|
||||||
@@ -234,11 +230,6 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
path.join(promptsDir, 'codex-review-failover-platform.md'),
|
path.join(promptsDir, 'codex-review-failover-platform.md'),
|
||||||
'failover platform prompt\n',
|
'failover platform prompt\n',
|
||||||
);
|
);
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-failover-paired-room.md'),
|
|
||||||
'failover paired prompt\n',
|
|
||||||
);
|
|
||||||
|
|
||||||
prepareGroupEnvironment(
|
prepareGroupEnvironment(
|
||||||
{ ...group, workDir: path.join(tempRoot, 'workdir') },
|
{ ...group, workDir: path.join(tempRoot, 'workdir') },
|
||||||
false,
|
false,
|
||||||
@@ -264,12 +255,11 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
'owner common platform prompt',
|
'owner common platform prompt',
|
||||||
'failover platform prompt',
|
'failover platform prompt',
|
||||||
'owner common paired prompt',
|
'owner common paired prompt',
|
||||||
'failover paired prompt',
|
|
||||||
'memory briefing',
|
'memory briefing',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds the shared owner prompt fragments to Claude session prompts', () => {
|
it('adds only the shared owner prompt fragments to Claude session prompts', () => {
|
||||||
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
||||||
mockReadEnvFile.mockReturnValue({});
|
mockReadEnvFile.mockReturnValue({});
|
||||||
|
|
||||||
@@ -309,12 +299,11 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
'owner common platform prompt',
|
'owner common platform prompt',
|
||||||
'platform prompt',
|
'platform prompt',
|
||||||
'owner common paired prompt',
|
'owner common paired prompt',
|
||||||
'paired room prompt',
|
|
||||||
'memory briefing',
|
'memory briefing',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns to the normal review prompt stack after failover is cleared', () => {
|
it('returns to the normal owner prompt stack after failover is cleared', () => {
|
||||||
vi.mocked(config.isReviewService).mockReturnValue(true);
|
vi.mocked(config.isReviewService).mockReturnValue(true);
|
||||||
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
||||||
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
|
vi.mocked(serviceRouting.getEffectiveChannelLease).mockReturnValue({
|
||||||
@@ -329,23 +318,6 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
|
|
||||||
const promptsDir = path.join(tempRoot, 'prompts');
|
const promptsDir = path.join(tempRoot, 'prompts');
|
||||||
fs.mkdirSync(promptsDir, { recursive: true });
|
fs.mkdirSync(promptsDir, { recursive: true });
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-platform.md'),
|
|
||||||
'review platform prompt\n',
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-paired-room.md'),
|
|
||||||
'review paired prompt\n',
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-failover-platform.md'),
|
|
||||||
'failover platform prompt\n',
|
|
||||||
);
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(promptsDir, 'codex-review-failover-paired-room.md'),
|
|
||||||
'failover paired prompt\n',
|
|
||||||
);
|
|
||||||
|
|
||||||
prepareGroupEnvironment(group, false, 'dc:test');
|
prepareGroupEnvironment(group, false, 'dc:test');
|
||||||
|
|
||||||
const agentsPath = path.join(
|
const agentsPath = path.join(
|
||||||
@@ -360,11 +332,6 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
|||||||
const agents = fs.readFileSync(agentsPath, 'utf-8');
|
const agents = fs.readFileSync(agentsPath, 'utf-8');
|
||||||
const segments = agents.trim().split('\n\n---\n\n');
|
const segments = agents.trim().split('\n\n---\n\n');
|
||||||
|
|
||||||
expect(segments).toEqual([
|
expect(segments).toEqual(['platform prompt']);
|
||||||
'platform prompt',
|
|
||||||
'review platform prompt',
|
|
||||||
'paired room prompt',
|
|
||||||
'review paired prompt',
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -57,18 +57,19 @@ describe('platform-prompts', () => {
|
|||||||
expect(readPairedRoomPrompt('claude-code')).toBe('Claude paired prompt');
|
expect(readPairedRoomPrompt('claude-code')).toBe('Claude paired prompt');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps codex approval wording role-based while preserving failover identity wording', () => {
|
it('maps Codex paired-room prompts to the shared reviewer prompt while preserving failover identity wording', () => {
|
||||||
const repoRoot = path.resolve(
|
const repoRoot = path.resolve(
|
||||||
path.dirname(fileURLToPath(import.meta.url)),
|
path.dirname(fileURLToPath(import.meta.url)),
|
||||||
'..',
|
'..',
|
||||||
);
|
);
|
||||||
|
|
||||||
const codexPairedPrompt = fs.readFileSync(
|
expect(getPairedRoomPromptPath('codex', repoRoot)).toBe(
|
||||||
path.join(repoRoot, 'prompts', 'codex-paired-room.md'),
|
path.join(repoRoot, 'prompts', 'claude-paired-room.md'),
|
||||||
'utf-8',
|
|
||||||
);
|
);
|
||||||
expect(codexPairedPrompt).toContain('owner-side paired agent');
|
|
||||||
expect(codexPairedPrompt).not.toContain("Claude's review or test plan");
|
const codexPairedPrompt = readPairedRoomPrompt('codex', repoRoot);
|
||||||
|
expect(codexPairedPrompt).toContain('reviewer');
|
||||||
|
expect(codexPairedPrompt).not.toContain('owner-side paired agent');
|
||||||
|
|
||||||
const failoverPlatformPrompt = fs.readFileSync(
|
const failoverPlatformPrompt = fs.readFileSync(
|
||||||
path.join(repoRoot, 'prompts', 'codex-review-failover-platform.md'),
|
path.join(repoRoot, 'prompts', 'codex-review-failover-platform.md'),
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ vi.mock('./github-ci.js', () => ({
|
|||||||
|
|
||||||
import { _initTestDatabase, createTask, getTaskById } from './db.js';
|
import { _initTestDatabase, createTask, getTaskById } from './db.js';
|
||||||
import * as codexTokenRotation from './codex-token-rotation.js';
|
import * as codexTokenRotation from './codex-token-rotation.js';
|
||||||
|
import { TIMEZONE } from './config.js';
|
||||||
import { createTaskStatusTracker } from './task-status-tracker.js';
|
import { createTaskStatusTracker } from './task-status-tracker.js';
|
||||||
import { TASK_STATUS_MESSAGE_PREFIX } from './task-watch-status.js';
|
import { TASK_STATUS_MESSAGE_PREFIX } from './task-watch-status.js';
|
||||||
import * as tokenRotation from './token-rotation.js';
|
import * as tokenRotation from './token-rotation.js';
|
||||||
@@ -144,6 +145,19 @@ import {
|
|||||||
startSchedulerLoop,
|
startSchedulerLoop,
|
||||||
} from './task-scheduler.js';
|
} from './task-scheduler.js';
|
||||||
|
|
||||||
|
function formatExpectedTimeLabel(timestampIso: string): string {
|
||||||
|
return new Intl.DateTimeFormat('ko-KR', {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
hour12: false,
|
||||||
|
timeZone: TIMEZONE,
|
||||||
|
})
|
||||||
|
.format(new Date(timestampIso))
|
||||||
|
.replace(/:/g, '시 ')
|
||||||
|
.replace(/시 (\d{2})$/, '분 $1초');
|
||||||
|
}
|
||||||
|
|
||||||
describe('task scheduler', () => {
|
describe('task scheduler', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
_initTestDatabase();
|
_initTestDatabase();
|
||||||
@@ -206,7 +220,7 @@ describe('task scheduler', () => {
|
|||||||
expect(task?.status).toBe('paused');
|
expect(task?.status).toBe('paused');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('only enqueues tasks owned by the current service agent type', async () => {
|
it('enqueues due tasks across agent types in unified service mode', async () => {
|
||||||
const dueAt = new Date(Date.now() - 60_000).toISOString();
|
const dueAt = new Date(Date.now() - 60_000).toISOString();
|
||||||
createTask({
|
createTask({
|
||||||
id: 'task-claude',
|
id: 'task-claude',
|
||||||
@@ -256,9 +270,17 @@ describe('task scheduler', () => {
|
|||||||
|
|
||||||
await vi.advanceTimersByTimeAsync(10);
|
await vi.advanceTimersByTimeAsync(10);
|
||||||
|
|
||||||
expect(enqueueTask).toHaveBeenCalledTimes(1);
|
expect(enqueueTask).toHaveBeenCalledTimes(2);
|
||||||
expect(enqueueTask.mock.calls[0][0]).toBe('shared@g.us::task:task-codex');
|
expect(
|
||||||
expect(enqueueTask.mock.calls[0][1]).toBe('task-codex');
|
enqueueTask.mock.calls
|
||||||
|
.map(([queueJid, taskId]) => `${queueJid}|${taskId}`)
|
||||||
|
.sort(),
|
||||||
|
).toEqual(
|
||||||
|
[
|
||||||
|
'shared@g.us::task:task-claude|task-claude',
|
||||||
|
'shared@g.us::task:task-codex|task-codex',
|
||||||
|
].sort(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps group-context tasks on the chat queue key', async () => {
|
it('keeps group-context tasks on the chat queue key', async () => {
|
||||||
@@ -1348,12 +1370,19 @@ Check the run.
|
|||||||
nextRun: '2026-03-19T07:04:10.000Z',
|
nextRun: '2026-03-19T07:04:10.000Z',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const expectedCheckedLabel = formatExpectedTimeLabel(
|
||||||
|
'2026-03-19T07:02:10.000Z',
|
||||||
|
);
|
||||||
|
const expectedNextLabel = formatExpectedTimeLabel(
|
||||||
|
'2026-03-19T07:04:10.000Z',
|
||||||
|
);
|
||||||
|
|
||||||
expect(rendered).toContain('CI 감시 중: GitHub Actions run 123456');
|
expect(rendered).toContain('CI 감시 중: GitHub Actions run 123456');
|
||||||
expect(rendered).toContain('- 상태: 대기 중');
|
expect(rendered).toContain('- 상태: 대기 중');
|
||||||
expect(rendered).toContain('- 마지막 확인: 16시 02분 10초');
|
expect(rendered).toContain(`- 마지막 확인: ${expectedCheckedLabel}`);
|
||||||
expect(rendered).toContain('- 경과 시간: 2분 10초');
|
expect(rendered).toContain('- 경과 시간: 2분 10초');
|
||||||
expect(rendered).toContain('- 확인 간격: 1분');
|
expect(rendered).toContain('- 확인 간격: 1분');
|
||||||
expect(rendered).toContain('- 다음 확인: 16시 04분 10초');
|
expect(rendered).toContain(`- 다음 확인: ${expectedNextLabel}`);
|
||||||
expect(rendered).not.toContain('16:02:10');
|
expect(rendered).not.toContain('16:02:10');
|
||||||
expect(rendered).not.toContain('16:04:10');
|
expect(rendered).not.toContain('16:04:10');
|
||||||
});
|
});
|
||||||
@@ -1429,6 +1458,10 @@ Check the run.
|
|||||||
vi.setSystemTime(new Date('2026-03-19T07:02:10.000Z'));
|
vi.setSystemTime(new Date('2026-03-19T07:02:10.000Z'));
|
||||||
await tracker.update('waiting', '2026-03-19T07:04:10.000Z');
|
await tracker.update('waiting', '2026-03-19T07:04:10.000Z');
|
||||||
|
|
||||||
|
const expectedNextLabel = formatExpectedTimeLabel(
|
||||||
|
'2026-03-19T07:04:10.000Z',
|
||||||
|
);
|
||||||
|
|
||||||
expect(editTrackedMessage).toHaveBeenCalledWith(
|
expect(editTrackedMessage).toHaveBeenCalledWith(
|
||||||
'shared@g.us',
|
'shared@g.us',
|
||||||
'msg-123',
|
'msg-123',
|
||||||
@@ -1437,7 +1470,7 @@ Check the run.
|
|||||||
expect(editTrackedMessage).toHaveBeenCalledWith(
|
expect(editTrackedMessage).toHaveBeenCalledWith(
|
||||||
'shared@g.us',
|
'shared@g.us',
|
||||||
'msg-123',
|
'msg-123',
|
||||||
expect.stringContaining('- 다음 확인: 16시 04분 10초'),
|
expect.stringContaining(`- 다음 확인: ${expectedNextLabel}`),
|
||||||
);
|
);
|
||||||
|
|
||||||
const secondState = getTaskById('task-watch-status');
|
const secondState = getTaskById('task-watch-status');
|
||||||
|
|||||||
Reference in New Issue
Block a user