import assert from 'node:assert/strict'; import { buildContinuityGateBlock, evaluateContinuity, hasValidDispatchReceipt, receiptMatchesPayload, } from '../src/continuity/evaluator.mjs'; function test(name, fn) { try { fn(); console.log(`ok - ${name}`); } catch (error) { console.error(`not ok - ${name}`); throw error; } } const validReceipt = { planId: 'plan-1', currentTask: 'task-7', nextDerivedAction: { type: 'message_subagent', task: 'continue' }, dispatchedAt: '2026-04-24T09:00:00.000Z', }; test('recognizes minimum valid dispatch receipt', () => { assert.equal(hasValidDispatchReceipt(validReceipt), true); }); test('matches payload against valid receipt', () => { const payload = { planId: 'plan-1', currentTask: 'task-7', nextDerivedAction: { type: 'message_subagent', task: 'continue' }, }; assert.equal(receiptMatchesPayload(payload, validReceipt), true); }); test('fails when completion has next action and no receipt', () => { const result = evaluateContinuity({ planId: 'plan-1', currentTask: 'task-7', taskState: 'complete', nextDerivedAction: { type: 'message_subagent' }, replyClosureState: 'completed', dispatchReceipt: null, }); assert.equal(result.ok, false); assert.equal(result.reason, 'missing_dispatch_receipt'); }); test('fails auto-next boundary without dispatch', () => { const result = evaluateContinuity({ planId: 'plan-1', currentTask: 'task-8', taskState: 'complete', nextTaskKnown: true, sameApprovedPlan: true, taskBoundaryStop: true, nextTaskId: 'task-9', nextDerivedAction: { type: 'message_subagent', task: 'continue' }, replyClosureState: 'completed', dispatchReceipt: null, }); assert.equal(result.ok, false); assert.equal(result.reason, 'missing_auto_next_dispatch'); }); test('passes allowed terminal state', () => { const result = evaluateContinuity({ planId: 'plan-1', currentTask: 'task-7', taskState: 'complete', nextDerivedAction: { type: 'message_subagent' }, replyClosureState: 'waiting_user', dispatchReceipt: null, }); assert.equal(result.ok, true); }); test('renders hard-gate block', () => { const text = buildContinuityGateBlock({ ok: false, status: 'continuity_failure', verdict: 'continuity_failure', reason: 'missing_dispatch_receipt', }); assert.match(text, /APPROVED_PLAN_CONTINUITY_GATE/); assert.match(text, /HARD_GATE/); }); console.log('continuity.evaluator.test.mjs PASS');