The module-level cache prevents repeated loads after initialization, but two concurrent first calls can both see extractor as null before either pipeline promise resolves. A document upload and a query arriving together could therefore start two model initializations.
I would cache the initialization promise immediately, then clear it if loading fails so a later request can retry. A fixture with two simultaneous generateEmbedding calls and one rejected initialization would cover both concurrency and recovery. That keeps the browser architecture lightweight while making the claim that the model loads exactly once true during startup as well as steady use.
The module-level cache prevents repeated loads after initialization, but two concurrent first calls can both see extractor as null before either pipeline promise resolves. A document upload and a query arriving together could therefore start two model initializations.
I would cache the initialization promise immediately, then clear it if loading fails so a later request can retry. A fixture with two simultaneous generateEmbedding calls and one rejected initialization would cover both concurrency and recovery. That keeps the browser architecture lightweight while making the claim that the model loads exactly once true during startup as well as steady use.