fix(schedule): close review gaps

This commit is contained in:
pku-xht
2026-08-06 06:35:50 +08:00
committed by Tianyi Cui
parent c3058e8d46
commit 2e187ccf14
17 changed files with 235 additions and 78 deletions

View File

@@ -109,6 +109,19 @@ describe('version-1 Schedule decoding and folding', () => {
occurrenceAt: '2026-08-05T12:00:00.000Z',
deliveryMode: 'session-local',
})
const nested = [
scheduleEvent(createData('same-id', 'grandparent prompt'), 0),
scheduleEvent({ version: 1, operation: 'dispatch', id: 'same-id' }, 1),
{ type: 'session/end-seed', seq: 2, time: 1, data: {} } as SessionEvent,
scheduleEvent(createData('same-id', 'parent prompt'), 3),
scheduleEvent({ version: 1, operation: 'dispatch', id: 'same-id' }, 4),
]
expect(scheduleReminderPresentation(nested, 4, 5)).toEqual({
scheduleId: 'same-id',
prompt: 'parent prompt',
occurrenceAt: '2026-08-05T12:00:00.000Z',
deliveryMode: 'session-local',
})
expect(scheduleReminderPresentation(events, 2, 2)).toBeUndefined()
expect(scheduleReminderPresentation([
{ type: 'session/end-seed', seq: 0, time: 1, data: {} },

View File

@@ -277,6 +277,30 @@ describe('Schedule timer and admission runtime', () => {
expect(test.followed).toHaveLength(1)
await owner.dispose()
})
it('rechecks the durable fold after claiming maintenance', async () => {
const test = await harness()
appendAfter(test, 'schedule-1', 1, Date.now() - 1_000)
test.controls.onReserve = () => {
test.controls.onReserve = undefined
test.agent.session.append('schedule/change', {
version: 1,
operation: 'delete',
id: ScheduleId('schedule-1'),
})
}
const owner = ownerFor(test)
owner.start()
await settle()
expect(test.controls.releaseCount).toBe(1)
expect(test.followed).toEqual([])
expect(test.agent.session.events.at(-1)?.data).toMatchObject({ operation: 'delete' })
owner.requestDrive()
await settle()
expect(test.followed).toEqual([])
await owner.dispose()
})
})
describe('Schedule runtime failure and teardown boundaries', () => {
@@ -459,7 +483,7 @@ describe('Schedule runtime failure and teardown boundaries', () => {
expect(unreadable.followed).toEqual([])
})
it('contains owner startup and run failures', async () => {
it('contains owner startup, maintenance, and framing failures', async () => {
const startup = await harness()
const startSpy = vi.spyOn(startup.ctx.agents, 'withoutInitiator')
.mockImplementation(() => { throw new Error('initiator closing') })
@@ -477,6 +501,29 @@ describe('Schedule runtime failure and teardown boundaries', () => {
expect(departedStartup.controls.flushCount).toBe(0)
departedStartSpy.mockRestore()
const maintenanceFailure = await harness()
appendAfter(maintenanceFailure, 'schedule-1', 1, Date.now() - 1_000)
const maintenanceSpy = vi.spyOn(maintenanceFailure.agent, 'runMaintenance')
.mockImplementation(() => Promise.reject(new Error('maintenance failed')))
const maintenanceOwner = ownerFor(maintenanceFailure)
maintenanceOwner.start()
await settle()
expect(maintenanceFailure.followed).toEqual([])
maintenanceOwner.requestDrive()
await settle()
expect(maintenanceSpy).toHaveBeenCalledOnce()
const departedMaintenance = await harness()
appendAfter(departedMaintenance, 'schedule-1', 1, Date.now() - 1_000)
vi.spyOn(departedMaintenance.agent, 'runMaintenance').mockImplementation(() => {
departedMaintenance.disposeAgent()
return Promise.reject(new Error('maintenance failed after detach'))
})
const departedMaintenanceOwner = ownerFor(departedMaintenance)
departedMaintenanceOwner.start()
await settle()
expect(departedMaintenance.followed).toEqual([])
const runFailure = await harness()
appendAfter(runFailure, 'schedule-1', 1, Date.now() - 1_000)
const uuidSpy = vi.spyOn(globalThis.crypto, 'randomUUID').mockImplementation(() => { throw 'message failed' })
@@ -486,7 +533,7 @@ describe('Schedule runtime failure and teardown boundaries', () => {
uuidSpy.mockRestore()
failingOwner.requestDrive()
await settle()
expect(runFailure.followed).toEqual([])
expect(runFailure.followed).toHaveLength(1)
const departedRun = await harness()
appendAfter(departedRun, 'schedule-1', 1, Date.now() - 1_000)