Como funciona
Sem monkey-patching, sem proxies em runtime: apenas o timing certo e Reflect metadata.
O pipeline
DocfyModule.forRoot() roda de forma síncrona durante a fase de NestFactory.create(), antes de SwaggerModule.createDocument() ser chamado. Ele usa require() para carregar cada arquivo de docs companheiro, que executa docs() e escreve metadados Reflect diretamente nos métodos do controller, exatamente como a sintaxe de decorator do TypeScript faria em class-definition time.
Quando SwaggerModule.createDocument() varre por metadados, tudo já está no lugar. Sem monkey-patching, sem proxies em runtime.
Timing
onModuleInit e outros lifecycle hooks disparam depois que SwaggerModule.createDocument() já foi chamado em main.ts. Qualquer abordagem baseada em onModuleInit produziria uma documentação Swagger vazia. É por isso que nestjs-docfy evita esse caminho e usa require() síncrono dentro de forRoot(), que executa durante NestFactory.create(), antes de qualquer lifecycle hook ou chamada do SwaggerModule.
CLI: análise estática
A CLI generate usa ts-morph para análise estática: ela lê a AST do TypeScript sem executar nenhum código do projeto. Todos os paths e glob patterns fornecidos pelo usuário são validados e sanitizados antes do uso.