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

@@ -76,9 +76,7 @@ export const articlesRepositoryContract =
it("getArticles filters by status", async () => {
await repo.createArticle(articleFactory.build({ status: "draft" }));
await repo.createArticle(
articleFactory.build({ status: "published" }),
);
await repo.createArticle(articleFactory.build({ status: "published" }));
const drafts = await repo.getArticles({ status: "draft" });
expect(drafts).toHaveLength(1);
expect(drafts[0]?.status).toBe("draft");
@@ -117,7 +115,7 @@ export const articlesRepositoryContract =
expect(result).toBeUndefined();
});
describe("span emission (R50)", () => {
describe("span emission", () => {
it("getArticles emits articles.getArticles span with op=repository", async () => {
if (!getTracer) return;
const tracer = getTracer();

View File

@@ -1,6 +1,9 @@
import { describe, expect, it } from "vitest";
import { ZodError } from "zod";
import { createArticleUseCase, createArticleOutputSchema } from "@/application/use-cases/create-article.use-case";
import {
createArticleUseCase,
createArticleOutputSchema,
} from "@/application/use-cases/create-article.use-case";
import { MockArticlesRepository } from "@/infrastructure/repositories/articles.repository.mock";
import type { IArticlesRepository } from "@/application/repositories/articles.repository.interface";
@@ -37,7 +40,7 @@ describe("createArticleUseCase", () => {
});
});
describe("createArticleUseCase output validation (R25)", () => {
describe("createArticleUseCase output validation", () => {
it("throws when repository returns a malformed article", async () => {
const repo = {
createArticle: async () => ({ id: 1 }) as unknown as never,

View File

@@ -1,6 +1,9 @@
import { describe, it, expect } from "vitest";
import { ZodError } from "zod";
import { getArticleBySlugUseCase, getArticleBySlugOutputSchema } from "@/application/use-cases/get-article-by-slug.use-case";
import {
getArticleBySlugUseCase,
getArticleBySlugOutputSchema,
} from "@/application/use-cases/get-article-by-slug.use-case";
import { MockArticlesRepository } from "@/infrastructure/repositories/articles.repository.mock";
import { ArticleNotFoundError } from "@/entities/errors/article";
import { articleFactory } from "@/__factories__/article.factory";
@@ -21,11 +24,13 @@ describe("getArticleBySlugUseCase", () => {
it("throws ArticleNotFoundError when slug is missing", async () => {
const repo = new MockArticlesRepository();
const useCase = getArticleBySlugUseCase(repo);
await expect(useCase({ slug: "does-not-exist" })).rejects.toThrow(ArticleNotFoundError);
await expect(useCase({ slug: "does-not-exist" })).rejects.toThrow(
ArticleNotFoundError,
);
});
});
describe("getArticleBySlugUseCase output validation (R25)", () => {
describe("getArticleBySlugUseCase output validation", () => {
it("throws when repository returns a malformed article", async () => {
const repo = {
getArticleBySlug: async () => ({ id: 123 }) as unknown as never,

View File

@@ -1,6 +1,9 @@
import { describe, expect, it } from "vitest";
import { ZodError } from "zod";
import { getArticlesUseCase, getArticlesOutputSchema } from "@/application/use-cases/get-articles.use-case";
import {
getArticlesUseCase,
getArticlesOutputSchema,
} from "@/application/use-cases/get-articles.use-case";
import { MockArticlesRepository } from "@/infrastructure/repositories/articles.repository.mock";
import { articleFactory } from "@/__factories__/article.factory";
@@ -8,7 +11,9 @@ describe("getArticlesUseCase", () => {
it("returns all articles with no filters", async () => {
const repo = new MockArticlesRepository();
articleFactory.reset();
await repo.createArticle(articleFactory.build({ id: "1", title: "A", slug: "a" }));
await repo.createArticle(
articleFactory.build({ id: "1", title: "A", slug: "a" }),
);
const useCase = getArticlesUseCase(repo);
const result = await useCase({});
@@ -19,8 +24,17 @@ describe("getArticlesUseCase", () => {
it("filters by status", async () => {
const repo = new MockArticlesRepository();
articleFactory.reset();
await repo.createArticle(articleFactory.build({ id: "1", title: "A", slug: "a", status: "draft" }));
await repo.createArticle(articleFactory.build({ id: "2", title: "B", slug: "b", status: "published" }));
await repo.createArticle(
articleFactory.build({ id: "1", title: "A", slug: "a", status: "draft" }),
);
await repo.createArticle(
articleFactory.build({
id: "2",
title: "B",
slug: "b",
status: "published",
}),
);
const useCase = getArticlesUseCase(repo);
const result = await useCase({ status: "published" });
@@ -29,7 +43,7 @@ describe("getArticlesUseCase", () => {
});
});
describe("getArticlesUseCase output validation (R25)", () => {
describe("getArticlesUseCase output validation", () => {
it("throws when the repository returns a malformed article", async () => {
const repo = new MockArticlesRepository();
// bypass the mock's createArticle (which is typed) by reaching into _articles directly

View File

@@ -40,8 +40,12 @@ export async function bindDevSeedBlog(ctx: BindContext): Promise<void> {
if (blogContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
blogContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
}
blogContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
blogContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
blogContainer
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
.toConstantValue(tracer);
blogContainer
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
.toConstantValue(logger);
if (blogContainer.isBound(BLOG_SYMBOLS.IArticlesRepository)) {
blogContainer.unbind(BLOG_SYMBOLS.IArticlesRepository);
@@ -93,11 +97,15 @@ export async function bindDevSeedBlog(ctx: BindContext): Promise<void> {
]) {
if (blogContainer.isBound(sym)) blogContainer.unbind(sym);
}
blogContainer.bind(BLOG_SYMBOLS.IGetArticlesUseCase).toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesUseCase)
.toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticleBySlugUseCase)
.toConstantValue(wrappedGetArticleBySlug);
blogContainer.bind(BLOG_SYMBOLS.ICreateArticleUseCase).toConstantValue(wrappedCreateArticle);
blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleUseCase)
.toConstantValue(wrappedCreateArticle);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesController)
@@ -120,7 +128,11 @@ export async function bindDevSeedBlog(ctx: BindContext): Promise<void> {
{ name: "blog.getArticleBySlug", op: "controller" },
withCapture(
logger,
{ feature: "blog", layer: "controller", name: "blog.getArticleBySlug" },
{
feature: "blog",
layer: "controller",
name: "blog.getArticleBySlug",
},
getArticleBySlugController(wrappedGetArticleBySlug),
),
),
@@ -138,8 +150,7 @@ export async function bindDevSeedBlog(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 { getArticleBySlugController } from "../interface-adapters/controllers/ge
import { createArticleController } from "../interface-adapters/controllers/create-article.controller";
export function bindProductionBlog(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 (blogContainer.isBound(INSTRUMENTATION_SYMBOLS.TRACER)) {
@@ -28,8 +29,12 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
if (blogContainer.isBound(INSTRUMENTATION_SYMBOLS.LOGGER)) {
blogContainer.unbind(INSTRUMENTATION_SYMBOLS.LOGGER);
}
blogContainer.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER).toConstantValue(tracer);
blogContainer.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER).toConstantValue(logger);
blogContainer
.bind<ITracer>(INSTRUMENTATION_SYMBOLS.TRACER)
.toConstantValue(tracer);
blogContainer
.bind<ILogger>(INSTRUMENTATION_SYMBOLS.LOGGER)
.toConstantValue(logger);
// Real repository
if (blogContainer.isBound(BLOG_SYMBOLS.IArticlesRepository)) {
@@ -38,7 +43,7 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
const repo = new ArticlesRepository(config, tracer, logger);
blogContainer.bind(BLOG_SYMBOLS.IArticlesRepository).toConstantValue(repo);
// Use cases — wrapped with span + capture at bind time (R41, R44)
// Use cases — wrapped with span + capture at bind time
const wrappedGetArticles = withSpan(
tracer,
{ name: "blog.getArticles", op: "use-case" },
@@ -76,11 +81,15 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
if (blogContainer.isBound(BLOG_SYMBOLS.ICreateArticleUseCase)) {
blogContainer.unbind(BLOG_SYMBOLS.ICreateArticleUseCase);
}
blogContainer.bind(BLOG_SYMBOLS.IGetArticlesUseCase).toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticlesUseCase)
.toConstantValue(wrappedGetArticles);
blogContainer
.bind(BLOG_SYMBOLS.IGetArticleBySlugUseCase)
.toConstantValue(wrappedGetArticleBySlug);
blogContainer.bind(BLOG_SYMBOLS.ICreateArticleUseCase).toConstantValue(wrappedCreateArticle);
blogContainer
.bind(BLOG_SYMBOLS.ICreateArticleUseCase)
.toConstantValue(wrappedCreateArticle);
// Controllers — wrapped with span at bind time
if (blogContainer.isBound(BLOG_SYMBOLS.IGetArticlesController)) {
@@ -113,7 +122,11 @@ export function bindProductionBlog(ctx: BindProductionContext): void {
{ name: "blog.getArticleBySlug", op: "controller" },
withCapture(
logger,
{ feature: "blog", layer: "controller", name: "blog.getArticleBySlug" },
{
feature: "blog",
layer: "controller",
name: "blog.getArticleBySlug",
},
getArticleBySlugController(wrappedGetArticleBySlug),
),
),
@@ -131,8 +144,7 @@ export function bindProductionBlog(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 type { BlogRouter } from "./integrations/api/router";
export { ArticleNotFoundError } from "./entities/errors/article";
export { InputParseError } from "./entities/errors/common";
// Use case schemas + types (Plan 9 R18)
// Use case schemas + types
export {
getArticlesInputSchema,
getArticlesOutputSchema,

View File

@@ -1,9 +1,12 @@
import { describe, it, expect } from "vitest";
import { RecordingTracer, RecordingLogger } from "@repo/core-testing/instrumentation";
import {
RecordingTracer,
RecordingLogger,
} from "@repo/core-testing/instrumentation";
import { MockArticlesRepository } from "@/infrastructure/repositories/articles.repository.mock";
// Mock repo also wraps in spans (R42); easier to assert without booting Payload.
describe("MockArticlesRepository emits spans (R42)", () => {
// Mock repo also wraps in spans; easier to assert without booting Payload.
describe("MockArticlesRepository emits spans", () => {
it("getArticles emits one span with op='repository'", async () => {
const tracer = new RecordingTracer();
const logger = new RecordingLogger();
@@ -31,7 +34,9 @@ describe("MockArticlesRepository emits spans (R42)", () => {
updatedAt: new Date(),
});
expect(tracer.findSpan("articles.createArticle")).toBeDefined();
expect(tracer.findSpan("articles.createArticle")!.attributes.slug).toBe("t");
expect(tracer.findSpan("articles.createArticle")!.attributes.slug).toBe(
"t",
);
});
it("getArticle records found=false for missing id", async () => {

View File

@@ -45,7 +45,7 @@ describe("blogRouter", () => {
});
});
describe("blogRouter (R26 error mapping)", () => {
describe("blogRouter error mapping", () => {
beforeEach(() => {
blogContainer.unbindAll();
blogContainer.load(BlogModule);

View File

@@ -1,5 +1,5 @@
// React Query option builders for blog feature procedures.
// Consumed by apps via the @repo/core-trpc client (wired in Plan 5).
// Consumed by apps via the @repo/core-trpc client.
type TrpcClient = {
blog: {
@@ -23,7 +23,12 @@ export function articleBySlugQuery(client: TrpcClient, slug: string) {
export function listArticlesQuery(
client: TrpcClient,
options?: { status?: string; authorId?: string; limit?: number; offset?: number },
options?: {
status?: string;
authorId?: string;
limit?: number;
offset?: number;
},
) {
return client.blog.listArticles.queryOptions(options);
}