diff --git a/packages/session-title/session-title/tests/service-contracts.spec.ts b/packages/session-title/session-title/tests/service-contracts.spec.ts index 42819ef542..f3a4a2ab3c 100644 --- a/packages/session-title/session-title/tests/service-contracts.spec.ts +++ b/packages/session-title/session-title/tests/service-contracts.spec.ts @@ -189,6 +189,22 @@ describe('SessionTitleService configuration and refresh boundaries', () => { expect(ctx.sessionTitle.get(session)?.messageSeqs).toEqual([source.seq]) }) + it('reuses a title accepted before the queued fallback commits', async () => { + const ctx = await setup() + const session = startSession(ctx, 'fallback-already-accepted') + const source = appendPrompt(session, 'Reuse the title that wins the fallback race') + + const refresh = ctx.sessionTitle.refresh(session) + session.append('session/title', { + title: 'Already accepted', + messageSeqs: [source.seq], + source: { kind: 'fallback' }, + }) + + await expect(refresh).resolves.toMatchObject({ title: 'Already accepted' }) + expect(session.events.filter(event => event.type === 'session/title')).toHaveLength(1) + }) + it('lets the newest overlapping explicit refresh win', async () => { const ctx = await setup() const session = startSession(ctx, 'refresh-order') @@ -254,6 +270,21 @@ describe('SessionTitleService configuration and refresh boundaries', () => { expect(inactiveError.message).toBe('session-title service disposed') }) + it('suppresses a queued fallback failure after service unload begins', async () => { + const ctx = new Context() + await ctx.plugin(SessionStore) + const fiber = await ctx.plugin(SessionTitleService, CONFIG) + const warn = vi.spyOn(ctx.logger, 'warn').mockImplementation(() => undefined) + const session = startSession(ctx, 'service-unload-started-fallback') + appendPrompt(session, 'Start fallback before unloading the service') + + await Promise.resolve() + await fiber.dispose() + + expect(session.events.some(event => event.type === 'session/title')).toBe(false) + expect(warn).not.toHaveBeenCalled() + }) + it('aborts pending and active provider work and drains ignored cancellation during service unload', async () => { const ctx = new Context() await ctx.plugin(SessionStore)