docs(adr): rename ADR-012 — drop Lazar; update title + content + cross-refs
- Rename docs/decisions/adr-012-lazar-conformance.md → adr-012-feature-conventions.md - Strip "Lazar", "Plan 8/9/10/11", "refactor-logs" refs from all ADRs, architecture docs, HTML explainers, and feature/core AGENTS.md files - Update all incoming links in docs/, packages/*/AGENTS.md, HTML explainers Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1401,7 +1401,7 @@ footer .colophon {
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
|
||||
.fade-in { animation: fadeIn 0.32s ease; }
|
||||
|
||||
/* ─── §06 Tracing & error capture (Plan 10) ─────────────────────────── */
|
||||
/* ─── §06 Tracing & error capture ───────────────────────────────────── */
|
||||
|
||||
.trace-h3 {
|
||||
font-family: "Fraunces", serif;
|
||||
@@ -2533,7 +2533,7 @@ const wrappedCtrl = withSpan(
|
||||
|
||||
<div class="badge-row">
|
||||
<div class="badge"><strong>360 tests</strong>across 15 suites · contracts run 2× per repo</div>
|
||||
<div class="badge"><strong>R25 + R26</strong>output-validation + error-mapping (Plan 9)</div>
|
||||
<div class="badge"><strong>output-validation + error-mapping</strong>use-case schemas + router middleware</div>
|
||||
<div class="badge"><strong>defineFactory · defineContractSuite</strong>both live in @repo/core-testing</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2558,14 +2558,9 @@ const wrappedCtrl = withSpan(
|
||||
<h5>Decisions</h5>
|
||||
<a href="../decisions/adr-008-per-feature-di-containers.md">adr-008 · per-feature DI</a>
|
||||
<a href="../decisions/adr-011-tdd-foundation.md">adr-011 · TDD foundation</a>
|
||||
<a href="../decisions/adr-012-lazar-conformance.md">adr-012 · Lazar conformance</a>
|
||||
<a href="../decisions/adr-012-feature-conventions.md">adr-012 · feature conventions</a>
|
||||
<a href="../decisions/adr-013-input-output-unification.md">adr-013 · I/O unification</a>
|
||||
</div>
|
||||
<div class="foot-col">
|
||||
<h5>Refactor logs</h5>
|
||||
<a href="../superpowers/refactor-logs/2026-05-05-lazar-pattern-conformance.md">2026-05-05 · Plan 8</a>
|
||||
<a href="../superpowers/refactor-logs/2026-05-06-input-output-unification.md">2026-05-06 · Plan 9</a>
|
||||
</div>
|
||||
<div class="foot-col">
|
||||
<h5>Guides</h5>
|
||||
<a href="../guides/adding-a-feature.md">adding-a-feature.md</a>
|
||||
@@ -2585,13 +2580,13 @@ const LAYERS = {
|
||||
entities: {
|
||||
tag: "domain",
|
||||
title: "Entities — the <em>nouns</em>",
|
||||
body: "Pure domain shapes with zero outside knowledge. Every model is a Zod schema with a co-located <code>z.infer</code> type. Errors live one folder over and set <code>this.name = \"<ClassName>\"</code> in the constructor — that's R6 from Plan 9.",
|
||||
body: "Pure domain shapes with zero outside knowledge. Every model is a Zod schema with a co-located <code>z.infer</code> type. Errors live one folder over and set <code>this.name = \"<ClassName>\"</code> in the constructor.",
|
||||
meta: "Examples · <strong>Article, User, Cookie, Page, Header, Media · ArticleNotFoundError, AuthenticationError, InputParseError</strong>"
|
||||
},
|
||||
application: {
|
||||
tag: "rules",
|
||||
title: "Application — the <em>verbs</em>",
|
||||
body: "Use cases live here, plus the interfaces they consume. After Plan 9 every use case is a factory: <code>(deps) ⇒ async (input) ⇒ result</code>. The file owns its <code>xInputSchema</code>, its <code>xOutputSchema</code>, and the runtime <code>.parse(...)</code> call before returning. Repository and service interfaces sit next door, blissfully unaware of who implements them.",
|
||||
body: "Use cases live here, plus the interfaces they consume. Every use case is a factory: <code>(deps) ⇒ async (input) ⇒ result</code>. The file owns its <code>xInputSchema</code>, its <code>xOutputSchema</code>, and the runtime <code>.parse(...)</code> call before returning. Repository and service interfaces sit next door, blissfully unaware of who implements them.",
|
||||
meta: "Examples · <strong>getArticlesUseCase, signInUseCase, deleteMediaUseCase</strong> · IArticlesRepository, IAuthenticationService"
|
||||
},
|
||||
infrastructure: {
|
||||
@@ -2603,7 +2598,7 @@ const LAYERS = {
|
||||
adapters: {
|
||||
tag: "transport boundary",
|
||||
title: "Interface adapters — <em>controllers</em>",
|
||||
body: "One controller per use case (Lazar's rule). It takes <code>unknown</code> input, runs <code>safeParse</code> against the use-case's schema, throws <code>InputParseError</code> on failure, calls the use case, then runs the result through a top-level <code>function presenter(value)</code> defined in the same file. Identity is fine — <code>return value;</code> — but the function form always exists so adding a transform later is one edit.",
|
||||
body: "One controller per use case. It takes <code>unknown</code> input, runs <code>safeParse</code> against the use-case's schema, throws <code>InputParseError</code> on failure, calls the use case, then runs the result through a top-level <code>function presenter(value)</code> defined in the same file. Identity is fine — <code>return value;</code> — but the function form always exists so adding a transform later is one edit.",
|
||||
meta: "Examples · <strong>getArticlesController · signInController · deleteMediaController</strong> (void return — no presenter)"
|
||||
},
|
||||
di: {
|
||||
@@ -2621,13 +2616,13 @@ const LAYERS = {
|
||||
integrations: {
|
||||
tag: "outside world",
|
||||
title: "Integrations — <em>tRPC + CMS</em>",
|
||||
body: "Where the feature meets the framework. <code>integrations/api/procedures.ts</code> (Plan 9) builds an <code>xProcedure</code> with <code>defineErrorMiddleware</code> applied — it owns the feature's domain-error → <code>TRPCError</code> mapping. <code>router.ts</code> uses that procedure plus <code>.input(xInputSchema)</code> imported from the use case. <code>cms/</code> exports Payload collection / global definitions consumed by <code>core-cms</code>.",
|
||||
body: "Where the feature meets the framework. <code>integrations/api/procedures.ts</code> builds an <code>xProcedure</code> with <code>defineErrorMiddleware</code> applied — it owns the feature's domain-error → <code>TRPCError</code> mapping. <code>router.ts</code> uses that procedure plus <code>.input(xInputSchema)</code> imported from the use case. <code>cms/</code> exports Payload collection / global definitions consumed by <code>core-cms</code>.",
|
||||
meta: "api/procedures.ts · api/router.ts · cms/collections/<x>.ts · cms/globals/<x>.ts"
|
||||
},
|
||||
ui: {
|
||||
tag: "frontend surface",
|
||||
title: "UI — <em>queries & components</em>",
|
||||
body: "Plan 9 split the public surface: feature root (<code>@repo/blog</code>) exports <em>contracts only</em> — types, errors, schemas, IUseCase aliases, router type, constants. <code>./ui</code> exports React Query option builders and (eventually) components. Apps import schemas from the root for forms, queries from <code>./ui</code> for hooks. No mixing.",
|
||||
body: "Feature root (<code>@repo/blog</code>) exports <em>contracts only</em> — types, errors, schemas, IUseCase aliases, router type, constants. <code>./ui</code> exports React Query option builders and (eventually) components. Apps import schemas from the root for forms, queries from <code>./ui</code> for hooks. No mixing.",
|
||||
meta: "ui/index.ts · ui/query.ts · @repo/<feature>/ui subpath in package.json"
|
||||
},
|
||||
testing: {
|
||||
@@ -2898,7 +2893,7 @@ ${F.errorMap.map(([err, code]) => ` [${err}, "${code}"],`).join("\n")}
|
||||
file: `packages/${F.name}/src/${useCaseFile}`,
|
||||
tag: "business logic",
|
||||
prose: F.outputSchemaName ?
|
||||
`The use case is a curried factory — <code>(deps) ⇒ async (input) ⇒ result</code>. It calls the repository, then runs <code>${F.outputSchemaName}.parse(result)</code> before returning. That last <code>.parse</code> is a Plan 9 contract: the use case <em>guarantees</em> what comes out, so a misbehaving repo fails loudly here, not silently downstream.` :
|
||||
`The use case is a curried factory — <code>(deps) ⇒ async (input) ⇒ result</code>. It calls the repository, then runs <code>${F.outputSchemaName}.parse(result)</code> before returning. That last <code>.parse</code> is the output contract: the use case <em>guarantees</em> what comes out, so a misbehaving repo fails loudly here, not silently downstream.` :
|
||||
`Void-output use case: takes input, calls the repository, returns nothing. No <code>xOutputSchema</code> means no <code>parse</code> at the end — there's nothing to validate. The presenter rule (R11) carves out an exception for these: void in, void out, no presenter.`,
|
||||
code: F.outputSchemaName ?
|
||||
`export const ${F.useCase}UseCase =
|
||||
|
||||
Reference in New Issue
Block a user