refactor: strip Phase/Plan/R-number references from source comments

This commit is contained in:
2026-05-13 09:51:45 +02:00
parent 075b729266
commit 17ae157365
66 changed files with 980 additions and 647 deletions

View File

@@ -3,94 +3,93 @@ import { defineContractSuite } from "@repo/core-testing/contract";
import type { IMediaRepository } from "../application/repositories/media.repository.interface.js";
import { mediaFactory } from "../__factories__/media.factory.js";
export const mediaRepositoryContract =
defineContractSuite<IMediaRepository>(
"IMediaRepository",
({ buildSubject, getTracer }) => {
let repo: IMediaRepository;
export const mediaRepositoryContract = defineContractSuite<IMediaRepository>(
"IMediaRepository",
({ buildSubject, getTracer }) => {
let repo: IMediaRepository;
beforeEach(async () => {
mediaFactory.reset();
repo = await buildSubject();
beforeEach(async () => {
mediaFactory.reset();
repo = await buildSubject();
});
// --- getMedia ---
it("getMedia returns undefined for a missing id", async () => {
const result = await repo.getMedia("does-not-exist");
expect(result).toBeUndefined();
});
// --- listMedia ---
it("listMedia returns empty array when no media exists", async () => {
const result = await repo.listMedia();
expect(result).toHaveLength(0);
});
// --- deleteMedia ---
it("deleteMedia removes the item so getMedia returns undefined", async () => {
const seed = mediaFactory.build({ id: "contract-1" });
// @ts-expect-error _store is a test helper on MockMediaRepository
if (typeof repo._store === "function") {
// @ts-expect-error _store is a test helper
await repo._store(seed);
}
await repo.deleteMedia("contract-1");
const result = await repo.getMedia("contract-1");
expect(result).toBeUndefined();
});
it("listMedia with limit returns at most limit items", async () => {
// Only verifiable on mock; for real impl this checks the interface
const result = await repo.listMedia({ limit: 0 });
expect(Array.isArray(result)).toBe(true);
});
it("listMedia with offset skips items", async () => {
const result = await repo.listMedia({ offset: 100 });
expect(Array.isArray(result)).toBe(true);
});
it("getMedia returns undefined for empty string id", async () => {
const result = await repo.getMedia("");
expect(result).toBeUndefined();
});
describe("span emission", () => {
it("getMedia emits media.getMedia span with id attribute", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.getMedia("nonexistent");
const span = tracer.findSpan("media.getMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.id).toBe("nonexistent");
});
// --- getMedia ---
it("getMedia returns undefined for a missing id", async () => {
const result = await repo.getMedia("does-not-exist");
expect(result).toBeUndefined();
it("listMedia emits media.listMedia span with op=repository", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.listMedia({ limit: 10 });
const span = tracer.findSpan("media.listMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.limit).toBe(10);
});
// --- listMedia ---
it("listMedia returns empty array when no media exists", async () => {
const result = await repo.listMedia();
expect(result).toHaveLength(0);
it("deleteMedia emits media.deleteMedia span with id attribute", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.deleteMedia("nonexistent");
const span = tracer.findSpan("media.deleteMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.id).toBe("nonexistent");
});
// --- deleteMedia ---
it("deleteMedia removes the item so getMedia returns undefined", async () => {
const seed = mediaFactory.build({ id: "contract-1" });
// @ts-expect-error _store is a test helper on MockMediaRepository
if (typeof repo._store === "function") {
// @ts-expect-error _store is a test helper
await repo._store(seed);
}
await repo.deleteMedia("contract-1");
const result = await repo.getMedia("contract-1");
expect(result).toBeUndefined();
});
it("listMedia with limit returns at most limit items", async () => {
// Only verifiable on mock; for real impl this checks the interface
const result = await repo.listMedia({ limit: 0 });
expect(Array.isArray(result)).toBe(true);
});
it("listMedia with offset skips items", async () => {
const result = await repo.listMedia({ offset: 100 });
expect(Array.isArray(result)).toBe(true);
});
it("getMedia returns undefined for empty string id", async () => {
const result = await repo.getMedia("");
expect(result).toBeUndefined();
});
describe("span emission (R50)", () => {
it("getMedia emits media.getMedia span with id attribute", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.getMedia("nonexistent");
const span = tracer.findSpan("media.getMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.id).toBe("nonexistent");
});
it("listMedia emits media.listMedia span with op=repository", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.listMedia({ limit: 10 });
const span = tracer.findSpan("media.listMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.limit).toBe(10);
});
it("deleteMedia emits media.deleteMedia span with id attribute", async () => {
if (!getTracer) return;
const tracer = getTracer();
tracer.reset();
await repo.deleteMedia("nonexistent");
const span = tracer.findSpan("media.deleteMedia");
expect(span).toBeDefined();
expect(span!.op).toBe("repository");
expect(span!.attributes.id).toBe("nonexistent");
});
});
},
);
});
},
);

View File

@@ -1,6 +1,9 @@
import { describe, it, expect } from "vitest";
import { ZodError } from "zod";
import { getMediaUseCase, getMediaOutputSchema } from "@/application/use-cases/get-media.use-case";
import {
getMediaUseCase,
getMediaOutputSchema,
} from "@/application/use-cases/get-media.use-case";
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
import { MediaNotFoundError } from "@/entities/errors/media";
import { mediaFactory } from "@/__factories__/media.factory";
@@ -22,15 +25,17 @@ describe("getMediaUseCase", () => {
const repo = new MockMediaRepository();
const useCase = getMediaUseCase(repo);
await expect(useCase({ id: "missing" })).rejects.toThrow(MediaNotFoundError);
await expect(useCase({ id: "missing" })).rejects.toThrow(
MediaNotFoundError,
);
});
it("R25 — parses valid output without error", async () => {
it("parses valid output without error", async () => {
const validMedia = mediaFactory.build({ id: "m-r25" });
expect(() => getMediaOutputSchema.parse(validMedia)).not.toThrow();
});
it("R25 — throws ZodError when repository returns malformed media", async () => {
it("throws ZodError when repository returns malformed media", async () => {
const repo = new MockMediaRepository();
// Store a malformed object (missing required fields) via type cast
await repo._store({ id: "bad", alt: "alt", url: "u" } as never);

View File

@@ -1,6 +1,9 @@
import { describe, it, expect } from "vitest";
import { ZodError } from "zod";
import { listMediaUseCase, listMediaOutputSchema } from "@/application/use-cases/list-media.use-case";
import {
listMediaUseCase,
listMediaOutputSchema,
} from "@/application/use-cases/list-media.use-case";
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
import { mediaFactory } from "@/__factories__/media.factory";
@@ -33,12 +36,12 @@ describe("listMediaUseCase", () => {
expect(result).toHaveLength(2);
});
it("R25 — parses valid output without error", async () => {
it("parses valid output without error", async () => {
const items = [mediaFactory.build(), mediaFactory.build()];
expect(() => listMediaOutputSchema.parse(items)).not.toThrow();
});
it("R25 — throws ZodError when repository returns malformed items", async () => {
it("throws ZodError when repository returns malformed items", async () => {
const repo = new MockMediaRepository();
// Store a malformed object (missing required fields)
await repo._store({ id: "bad", alt: "alt", url: "u" } as never);

View File

@@ -40,8 +40,12 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
mediaContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
}
mediaContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
mediaContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
mediaContainer
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
.toConstantValue(tracer);
mediaContainer
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
.toConstantValue(logger);
if (mediaContainer.isBound(MEDIA_SYMBOLS.IMediaRepository)) {
mediaContainer.unbind(MEDIA_SYMBOLS.IMediaRepository);
@@ -95,9 +99,15 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
]) {
if (mediaContainer.isBound(sym)) mediaContainer.unbind(sym);
}
mediaContainer.bind(MEDIA_SYMBOLS.IGetMediaUseCase).toConstantValue(wrappedGetMedia);
mediaContainer.bind(MEDIA_SYMBOLS.IListMediaUseCase).toConstantValue(wrappedListMedia);
mediaContainer.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase).toConstantValue(wrappedDeleteMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IGetMediaUseCase)
.toConstantValue(wrappedGetMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IListMediaUseCase)
.toConstantValue(wrappedListMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase)
.toConstantValue(wrappedDeleteMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IGetMediaController)
@@ -138,8 +148,7 @@ export async function bindDevSeedMedia(ctx: BindContext): Promise<void> {
),
),
);
// bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator
// output at the <gen:event-handlers> / <gen:jobs> anchors below.
// bus + queue are passed through; generated handlers consume them at the anchors below.
void bus;
void queue;
void realtime;

View File

@@ -19,7 +19,8 @@ import { listMediaController } from "../interface-adapters/controllers/list-medi
import { deleteMediaController } from "../interface-adapters/controllers/delete-media.controller";
export function bindProductionMedia(ctx: BindProductionContext): void {
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx;
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } =
ctx;
// Bind shared instrumentation into feature container
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) {
@@ -28,17 +29,19 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
if (mediaContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
mediaContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
}
mediaContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
mediaContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
mediaContainer
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
.toConstantValue(tracer);
mediaContainer
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
.toConstantValue(logger);
// Real repository
if (mediaContainer.isBound(MEDIA_SYMBOLS.IMediaRepository)) {
mediaContainer.unbind(MEDIA_SYMBOLS.IMediaRepository);
}
const repo = new MediaRepository(config, tracer, logger);
mediaContainer
.bind(MEDIA_SYMBOLS.IMediaRepository)
.toConstantValue(repo);
mediaContainer.bind(MEDIA_SYMBOLS.IMediaRepository).toConstantValue(repo);
// Use cases — wrapped with span + capture at bind time
const wrappedGetMedia = withSpan(
@@ -76,9 +79,15 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
]) {
if (mediaContainer.isBound(sym)) mediaContainer.unbind(sym);
}
mediaContainer.bind(MEDIA_SYMBOLS.IGetMediaUseCase).toConstantValue(wrappedGetMedia);
mediaContainer.bind(MEDIA_SYMBOLS.IListMediaUseCase).toConstantValue(wrappedListMedia);
mediaContainer.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase).toConstantValue(wrappedDeleteMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IGetMediaUseCase)
.toConstantValue(wrappedGetMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IListMediaUseCase)
.toConstantValue(wrappedListMedia);
mediaContainer
.bind(MEDIA_SYMBOLS.IDeleteMediaUseCase)
.toConstantValue(wrappedDeleteMedia);
// Controllers — wrapped with span at bind time
for (const sym of [
@@ -127,8 +136,7 @@ export function bindProductionMedia(ctx: BindProductionContext): void {
),
),
);
// bus + queue are accept-and-forward in Phase 6; consumed by Phase 7 generator
// output at the <gen:event-handlers> / <gen:jobs> anchors below.
// bus + queue are passed through; generated handlers consume them at the anchors below.
void bus;
void queue;
void realtime;

View File

@@ -3,7 +3,7 @@ export { MediaNotFoundError } from "./entities/errors/media";
export { InputParseError } from "./entities/errors/common";
export type { MediaRouter } from "./integrations/api/router";
// Use case schemas + types (Plan 9 R18)
// Use case schemas + types
export {
getMediaInputSchema,
getMediaOutputSchema,

View File

@@ -1,5 +1,8 @@
import { describe, it, expect } from "vitest";
import { RecordingTracer, RecordingLogger } from "@repo/core-testing/instrumentation";
import {
RecordingTracer,
RecordingLogger,
} from "@repo/core-testing/instrumentation";
import { MockMediaRepository } from "@/infrastructure/repositories/media.repository.mock";
import type { Media } from "@/entities/models/media";
@@ -12,8 +15,8 @@ const SAMPLE_MEDIA: Media = {
filesize: 1024,
};
// Mock repo also wraps in spans (R42).
describe("MockMediaRepository emits spans (R42)", () => {
// Mock repo also wraps in spans.
describe("MockMediaRepository emits spans", () => {
it("getMedia emits one span with op='repository' and found attribute", async () => {
const tracer = new RecordingTracer();
const logger = new RecordingLogger();

View File

@@ -36,7 +36,7 @@ describe("mediaRouter", () => {
});
});
describe("mediaRouter (R26 error mapping)", () => {
describe("mediaRouter error mapping", () => {
beforeEach(() => {
mediaContainer.unbindAll();
mediaContainer.load(MediaModule);
@@ -123,7 +123,9 @@ describe("mediaRouter (R26 error mapping)", () => {
mediaContainer
.bind(MEDIA_SYMBOLS.IDeleteMediaController)
.toDynamicValue((ctx) =>
deleteMediaController(ctx.container.get(MEDIA_SYMBOLS.IDeleteMediaUseCase)),
deleteMediaController(
ctx.container.get(MEDIA_SYMBOLS.IDeleteMediaUseCase),
),
);
const caller = mediaRouter.createCaller({});