From 4cefa5cd883614765d864902753e38054b24a804 Mon Sep 17 00:00:00 2001 From: "shaggy (mosaic-dev box)" Date: Tue, 11 Aug 2026 18:37:54 -0500 Subject: [PATCH] fix(gateway): resolve InteractionCoordinationService handoff factory via optional DI token (#1145) root cause: emitDecoratorMetadata reflected the third constructor parameter as Function and Nest attempted to resolve it fix: optional HANDOFF_ID_FACTORY injection token, no production provider, preserving undefined -> crypto.randomUUID() default and unchanged positional construction TDD: real CoordModule red at Function index [2], then green; test overrides only unrelated AuthGuard because its AUTH provider comes from AppModule's global AuthModule context Closes #1145 --- .../coord/interaction-coordination.di.test.ts | 19 +++++++++++++++++++ .../coord/interaction-coordination.service.ts | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 apps/gateway/src/coord/interaction-coordination.di.test.ts diff --git a/apps/gateway/src/coord/interaction-coordination.di.test.ts b/apps/gateway/src/coord/interaction-coordination.di.test.ts new file mode 100644 index 00000000..75b63e20 --- /dev/null +++ b/apps/gateway/src/coord/interaction-coordination.di.test.ts @@ -0,0 +1,19 @@ +import 'reflect-metadata'; +import { Test } from '@nestjs/testing'; +import { describe, expect, it } from 'vitest'; +import { CoordModule } from './coord.module.js'; +import { InteractionCoordinationService } from './interaction-coordination.service.js'; +import { AuthGuard } from '../auth/auth.guard.js'; + +describe('CoordModule DI (compiled-metadata boot)', () => { + it('resolves InteractionCoordinationService through Nest DI', async () => { + const moduleRef = await Test.createTestingModule({ imports: [CoordModule] }) + .overrideGuard(AuthGuard) + .useValue({ canActivate: (): boolean => true }) + .compile(); + expect(moduleRef.get(InteractionCoordinationService)).toBeInstanceOf( + InteractionCoordinationService, + ); + await moduleRef.close(); + }); +}); diff --git a/apps/gateway/src/coord/interaction-coordination.service.ts b/apps/gateway/src/coord/interaction-coordination.service.ts index cf16e64a..a1035af9 100644 --- a/apps/gateway/src/coord/interaction-coordination.service.ts +++ b/apps/gateway/src/coord/interaction-coordination.service.ts @@ -1,4 +1,4 @@ -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, Optional } from '@nestjs/common'; import { InteractionCoordinationClient, type CoordinationObservation, @@ -13,6 +13,7 @@ import type { CreateHandoffDto } from './interaction-coordination.dto.js'; export const COORDINATION_PORT = Symbol('COORDINATION_PORT'); export const COORDINATION_CONFIG = Symbol('COORDINATION_CONFIG'); +export const HANDOFF_ID_FACTORY = Symbol('HANDOFF_ID_FACTORY'); const HANDOFF_TRACKING_TTL_MS = 60 * 60 * 1_000; const MAX_TRACKED_HANDOFFS = 1_000; @@ -60,6 +61,8 @@ export class InteractionCoordinationService { constructor( @Inject(COORDINATION_PORT) private readonly port: InteractionCoordinationPort, @Inject(COORDINATION_CONFIG) private readonly config: InteractionCoordinationConfig, + @Optional() + @Inject(HANDOFF_ID_FACTORY) private readonly handoffIdFactory: () => string = (): string => crypto.randomUUID(), ) {}