Merge branch 'worktree-conformance-milestone-v': conformance milestone v — generator updates
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
id: 05-generator-updates
|
||||||
|
epic: conformance-system-v1
|
||||||
|
title: Generator updates — emit feature.manifest.ts + self-asserting bind-production
|
||||||
|
type: technical-story
|
||||||
|
status: done
|
||||||
|
feature: turbo-generators
|
||||||
|
depends-on: [04-ci-drift-gate]
|
||||||
|
blocks: [06-feature-migrations]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
`pnpm turbo gen feature <name>` produces a feature that's conformance-
|
||||||
|
compliant out of the box: ships a `feature.manifest.ts` declaring the
|
||||||
|
scaffolded use case, and the scaffolded `bind-production.ts` calls
|
||||||
|
`assertFeatureConformance` at its tail.
|
||||||
|
|
||||||
|
## Why
|
||||||
|
Today, generating a new feature does NOT emit a manifest, so
|
||||||
|
`feature-must-have-manifest` would warn the moment the developer saves.
|
||||||
|
And `bindProductionX` doesn't self-assert. New features should be
|
||||||
|
conformance-ready by default.
|
||||||
|
|
||||||
|
## Done when
|
||||||
|
- `feature.manifest.ts.hbs` template exists, declaring the scaffolded
|
||||||
|
`getX` use case with mutates: false / empty arrays
|
||||||
|
- `bind-production.ts.hbs` imports `assertFeatureConformance` +
|
||||||
|
`<name>Manifest` and calls the assertion at the tail
|
||||||
|
- `config.ts` action emits the manifest file
|
||||||
|
- Running `pnpm turbo gen feature demo` into a tmp dir produces a
|
||||||
|
feature directory containing a valid `feature.manifest.ts`
|
||||||
|
- Existing snapshot tests pass (regenerate snapshots if needed)
|
||||||
|
|
||||||
|
## In scope
|
||||||
|
- Manifest template
|
||||||
|
- bind-production template update
|
||||||
|
- config.ts action wiring
|
||||||
|
- Snapshot regen
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
- Multi-use-case feature scaffolding
|
||||||
|
- Generator changes to other generators (event/job/realtime)
|
||||||
|
- Backfilling manifests for existing features (milestone vi)
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
- [x] Story scaffold
|
||||||
|
- [x] feature.manifest.ts.hbs template
|
||||||
|
- [x] bind-production.ts.hbs update
|
||||||
|
- [x] config.ts action wiring
|
||||||
|
- [x] Run generator into tmp; verify shape
|
||||||
|
- [x] Snapshot regen (if needed) + verify tests pass
|
||||||
|
- [x] Final verification + closeout
|
||||||
@@ -36,6 +36,6 @@ See `docs/architecture/feature-conformance-explainer.html` and
|
|||||||
- [x] [03.a — Structural rules](03-a-structural-eslint-rules/_story.md)
|
- [x] [03.a — Structural rules](03-a-structural-eslint-rules/_story.md)
|
||||||
- [x] [03.b — Manifest-aware AST rules](03-b-ast-eslint-rules/_story.md)
|
- [x] [03.b — Manifest-aware AST rules](03-b-ast-eslint-rules/_story.md)
|
||||||
- [x] [04 — CI drift gate](04-ci-drift-gate/_story.md)
|
- [x] [04 — CI drift gate](04-ci-drift-gate/_story.md)
|
||||||
- [ ] 05 — Generator emits manifest + contracts + test stubs (later plan)
|
- [x] [05 — Generator updates](05-generator-updates/_story.md)
|
||||||
- [ ] 06 — Documentation rewrite (later plan)
|
- [ ] 06 — Documentation rewrite (later plan)
|
||||||
- [ ] 07 — Migrate auth feature reference (later plan)
|
- [ ] 07 — Migrate auth feature reference (later plan)
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void {
|
|||||||
path: "packages/{{kebabCase name}}/src/index.ts",
|
path: "packages/{{kebabCase name}}/src/index.ts",
|
||||||
templateFile: "templates/feature/src/index.ts.hbs",
|
templateFile: "templates/feature/src/index.ts.hbs",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "add",
|
||||||
|
path: "packages/{{kebabCase name}}/src/feature.manifest.ts",
|
||||||
|
templateFile: "templates/feature/src/feature.manifest.ts.hbs",
|
||||||
|
},
|
||||||
|
|
||||||
// Entities — models + errors
|
// Entities — models + errors
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import { {{constantCase name}}_SYMBOLS } from "./symbols";
|
|||||||
import { {{pascalCase entity}}Repository } from "../infrastructure/repositories/{{kebabCase entity}}.repository";
|
import { {{pascalCase entity}}Repository } from "../infrastructure/repositories/{{kebabCase entity}}.repository";
|
||||||
import { get{{pascalCase entity}}UseCase } from "../application/use-cases/get-{{kebabCase entity}}.use-case";
|
import { get{{pascalCase entity}}UseCase } from "../application/use-cases/get-{{kebabCase entity}}.use-case";
|
||||||
import { get{{pascalCase entity}}Controller } from "../interface-adapters/controllers/get-{{kebabCase entity}}.controller";
|
import { get{{pascalCase entity}}Controller } from "../interface-adapters/controllers/get-{{kebabCase entity}}.controller";
|
||||||
|
import { assertFeatureConformance } from "@repo/core-shared/conformance";
|
||||||
|
import { {{camelCase name}}Manifest } from "../feature.manifest";
|
||||||
|
|
||||||
export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): void {
|
export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): void {
|
||||||
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx;
|
const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx;
|
||||||
@@ -73,4 +75,15 @@ export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): v
|
|||||||
// <gen:event-handlers>
|
// <gen:event-handlers>
|
||||||
// <gen:jobs>
|
// <gen:jobs>
|
||||||
// <gen:realtime-handlers>
|
// <gen:realtime-handlers>
|
||||||
|
|
||||||
|
// Boot-time conformance check: refuses to start if any use-case binding
|
||||||
|
// is missing a required brand (withSpan / withCapture / withAudit).
|
||||||
|
assertFeatureConformance(
|
||||||
|
{{camelCase name}}Container,
|
||||||
|
{{camelCase name}}Manifest,
|
||||||
|
{
|
||||||
|
get{{pascalCase entity}}: {{constantCase name}}_SYMBOLS.IGet{{pascalCase entity}}UseCase,
|
||||||
|
},
|
||||||
|
ctx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { defineFeature } from "@repo/core-shared/conformance";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {{camelCase name}} feature's conformance manifest. Drives binding-slot
|
||||||
|
* types in `di/bind-production.ts` and is read by ESLint, the boot
|
||||||
|
* assertion, and the CI drift gate.
|
||||||
|
*
|
||||||
|
* Conventions:
|
||||||
|
* - `mutates: true` for any use case that creates, updates, or deletes state
|
||||||
|
* - `audits` lists every audit event the use case emits (must match calls
|
||||||
|
* to `auditLog.record(...)` in the factory body — ESLint enforces this)
|
||||||
|
* - `publishes` / `consumes` cover cross-feature events through `IEventBus`
|
||||||
|
*/
|
||||||
|
export const {{camelCase name}}Manifest = defineFeature({
|
||||||
|
name: "{{kebabCase name}}",
|
||||||
|
requiredCores: [],
|
||||||
|
useCases: {
|
||||||
|
get{{pascalCase entity}}: {
|
||||||
|
mutates: false,
|
||||||
|
audits: [],
|
||||||
|
publishes: [],
|
||||||
|
consumes: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
realtimeChannels: [],
|
||||||
|
jobs: [],
|
||||||
|
} as const);
|
||||||
|
|
||||||
|
export type {{pascalCase name}}Manifest = typeof {{camelCase name}}Manifest;
|
||||||
Reference in New Issue
Block a user