Extract + unit-test the phantom auto-continue injection path

Move the storeMessage → enqueueMessageCheck side effect out of the delivery
callback into scheduleAutoContinueForPhantomFinal so the injection path is
directly unit-tested: an auto-continue outcome for a delivered final injects the
corrective nudge as an ipc_injected_human message and re-enqueues a turn, while
a non-auto-continue outcome or an undelivered final does nothing. Behavior is
identical to the inline version — this only adds test coverage and a no-op
refactor, so no redeploy is required.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Codex
2026-08-25 23:12:18 +09:00
parent bc9ba1c2d2
commit 007e95fe40
3 changed files with 127 additions and 21 deletions

View File

@@ -1,10 +1,12 @@
import { beforeEach, describe, expect, it } from 'vitest';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import {
applyPhantomNotificationGuard,
isPhantomNotificationDeadEnd,
PHANTOM_CONTINUE_NUDGE,
PHANTOM_NOTIFICATION_NOTICE,
resolvePhantomFinalOutcome,
scheduleAutoContinueForPhantomFinal,
_resetPhantomAutoContinueForTests,
} from './phantom-notification-guard.js';
@@ -158,3 +160,71 @@ describe('resolvePhantomFinalOutcome', () => {
expect(outcome.kind).toBe('notice');
});
});
describe('scheduleAutoContinueForPhantomFinal', () => {
it('injects the corrective nudge and re-enqueues when the dead-end final delivered', () => {
const storeMessage = vi.fn();
const enqueueMessageCheck = vi.fn();
const scheduled = scheduleAutoContinueForPhantomFinal({
outcomeKind: 'auto-continue',
delivered: true,
chatJid: 'dc:test-room',
groupFolder: 'test-room',
runId: 'run-xyz',
storeMessage,
enqueueMessageCheck,
});
expect(scheduled).toBe(true);
expect(storeMessage).toHaveBeenCalledTimes(1);
expect(storeMessage).toHaveBeenCalledWith(
expect.objectContaining({
chat_jid: 'dc:test-room',
content: PHANTOM_CONTINUE_NUDGE,
is_from_me: false,
is_bot_message: false,
message_source_kind: 'ipc_injected_human',
}),
);
expect(enqueueMessageCheck).toHaveBeenCalledWith('dc:test-room', 'test-room');
});
it('does nothing when the outcome is not auto-continue', () => {
const storeMessage = vi.fn();
const enqueueMessageCheck = vi.fn();
const scheduled = scheduleAutoContinueForPhantomFinal({
outcomeKind: 'notice',
delivered: true,
chatJid: 'dc:test-room',
groupFolder: 'test-room',
runId: 'run-xyz',
storeMessage,
enqueueMessageCheck,
});
expect(scheduled).toBe(false);
expect(storeMessage).not.toHaveBeenCalled();
expect(enqueueMessageCheck).not.toHaveBeenCalled();
});
it('does nothing when the final was not delivered', () => {
const storeMessage = vi.fn();
const enqueueMessageCheck = vi.fn();
const scheduled = scheduleAutoContinueForPhantomFinal({
outcomeKind: 'auto-continue',
delivered: false,
chatJid: 'dc:test-room',
groupFolder: 'test-room',
runId: 'run-xyz',
storeMessage,
enqueueMessageCheck,
});
expect(scheduled).toBe(false);
expect(storeMessage).not.toHaveBeenCalled();
expect(enqueueMessageCheck).not.toHaveBeenCalled();
});
});