From e44cf8b804726ae4ac29297c36ff8a2181e12c35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 19 Jul 2026 14:55:46 +0200 Subject: [PATCH] test(workouts): guard the insight queue against silent provisioning loss Nothing warms this queue and no read path triggers it, so an unregistered name fails open in the worst way: every send resolves, every job vanishes, and the symptom is indistinguishable from the surface's honest empty state. --- .../__tests__/workout-insight-queue.test.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/lib/jobs/__tests__/workout-insight-queue.test.ts diff --git a/src/lib/jobs/__tests__/workout-insight-queue.test.ts b/src/lib/jobs/__tests__/workout-insight-queue.test.ts new file mode 100644 index 000000000..4fdc3ca15 --- /dev/null +++ b/src/lib/jobs/__tests__/workout-insight-queue.test.ts @@ -0,0 +1,71 @@ +/** + * v1.4.37 dead-queue guard for the `workout-insight-generate` queue. + * + * This queue fails open in the worst possible way. Nothing warms it, no cron + * touches it, and no read path triggers it — the ONLY thing that ever puts work + * on it is the arrival spine's dispatch. So if the queue name is missing from + * `allQueues`, pg-boss never provisions it, every `boss.send` resolves + * successfully, every job vanishes, and the only symptom is that no workout + * ever gets a paragraph. That is indistinguishable from the feature's own + * honest empty state, which is exactly why it needs a structural guard rather + * than a behavioural one. + * + * Source-text assertions over the registrar, matching the shape of the sibling + * `*-queue.test.ts` guards. + */ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +import { describe, expect, it } from "vitest"; + +const statusRegistrar = readFileSync( + join(__dirname, "..", "reminder", "register-status.ts"), + "utf8", +); + +describe("workout-insight-generate queue wiring", () => { + it("provisions the queue in the allQueues list", () => { + const allQueues = statusRegistrar.match( + /const allQueues\s*=\s*\[([\s\S]*?)\];/, + ); + expect(allQueues).not.toBeNull(); + expect(allQueues![1]).toMatch(/\bWORKOUT_INSIGHT_GENERATE_QUEUE\b/); + }); + + it("binds a boss.work handler that drains it", () => { + expect(statusRegistrar).toMatch( + /boss\.work[\s\S]{0,300}WORKOUT_INSIGHT_GENERATE_QUEUE[\s\S]{0,300}handleWorkoutInsightGenerate/, + ); + }); + + it("runs the provider path serially", () => { + // This IS the provider path the spine deliberately does not walk. Widening + // the concurrency would let one sync's worth of workouts fan out into + // parallel completions. + expect(statusRegistrar).toMatch( + /WORKOUT_INSIGHT_GENERATE_QUEUE[\s\S]{0,300}localConcurrency:\s*WORKOUT_INSIGHT_GENERATE_CONCURRENCY/, + ); + }); + + it("has no cron schedule — it is dispatched by arrival only", () => { + // A cron here would be a standing invitation to regenerate, which is the + // saturation surface the design refuses. + expect(statusRegistrar).not.toMatch( + /\[WORKOUT_INSIGHT_GENERATE_QUEUE,\s*\w+_CRON\]/, + ); + }); + + it("is reached from the spine only through the generator-free module", () => { + // The spine's zero-spend claim is a module-graph property. If the worker + // dispatch imported the generator, the provider clients would become + // reachable from `data-arrival.ts` and the isolation guard would go red. + const worker = readFileSync( + join(__dirname, "..", "data-arrival.ts"), + "utf8", + ); + expect(worker).toMatch( + /from "@\/lib\/jobs\/workout-insight-generate-shared"/, + ); + expect(worker).not.toMatch(/from "@\/lib\/jobs\/workout-insight-generate"/); + }); +});