From 8da21c04050a52de3860ae85c1ee4efe33fea490 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 00:02:05 +0200 Subject: [PATCH 1/3] =?UTF-8?q?docs(work):=20story=2005=20=E2=80=94=20gene?= =?UTF-8?q?rator=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../05-generator-updates/_story.md | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/work/conformance-system-v1/05-generator-updates/_story.md diff --git a/docs/work/conformance-system-v1/05-generator-updates/_story.md b/docs/work/conformance-system-v1/05-generator-updates/_story.md new file mode 100644 index 0000000..830f154 --- /dev/null +++ b/docs/work/conformance-system-v1/05-generator-updates/_story.md @@ -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: in-progress +feature: turbo-generators +depends-on: [04-ci-drift-gate] +blocks: [06-feature-migrations] +--- + +## Goal +`pnpm turbo gen feature ` 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` + + `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 +- [ ] Story scaffold +- [ ] feature.manifest.ts.hbs template +- [ ] bind-production.ts.hbs update +- [ ] config.ts action wiring +- [ ] Run generator into tmp; verify shape +- [ ] Snapshot regen (if needed) + verify tests pass +- [ ] Final verification + closeout From 300143e7e105bb7092926a2cf178719a1fd083f6 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 00:02:35 +0200 Subject: [PATCH 2/3] feat(generators): emit feature.manifest.ts + self-asserting bind-production --- turbo/generators/config.ts | 5 ++++ .../feature/src/di/bind-production.ts.hbs | 13 +++++++++ .../feature/src/feature.manifest.ts.hbs | 29 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 turbo/generators/templates/feature/src/feature.manifest.ts.hbs diff --git a/turbo/generators/config.ts b/turbo/generators/config.ts index c8f22e2..75b2bba 100644 --- a/turbo/generators/config.ts +++ b/turbo/generators/config.ts @@ -120,6 +120,11 @@ export default function generator(plop: PlopTypes.NodePlopAPI): void { path: "packages/{{kebabCase name}}/src/index.ts", 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 { diff --git a/turbo/generators/templates/feature/src/di/bind-production.ts.hbs b/turbo/generators/templates/feature/src/di/bind-production.ts.hbs index 0e40e01..6832e06 100644 --- a/turbo/generators/templates/feature/src/di/bind-production.ts.hbs +++ b/turbo/generators/templates/feature/src/di/bind-production.ts.hbs @@ -11,6 +11,8 @@ import { {{constantCase name}}_SYMBOLS } from "./symbols"; 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}}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 { const { config, tracer, logger, bus, queue, realtime, realtimeRegistry } = ctx; @@ -73,4 +75,15 @@ export function bindProduction{{pascalCase name}}(ctx: BindProductionContext): v // // // + + // 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, + ); } diff --git a/turbo/generators/templates/feature/src/feature.manifest.ts.hbs b/turbo/generators/templates/feature/src/feature.manifest.ts.hbs new file mode 100644 index 0000000..7bb3900 --- /dev/null +++ b/turbo/generators/templates/feature/src/feature.manifest.ts.hbs @@ -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; From 5bf9a140edd0f1cd3cee623d85d5dc33fce33f8f Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 00:04:56 +0200 Subject: [PATCH 3/3] =?UTF-8?q?docs(work):=20close=20story=2005=20?= =?UTF-8?q?=E2=80=94=20generator=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../05-generator-updates/_story.md | 16 ++++++++-------- docs/work/conformance-system-v1/_epic.md | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/work/conformance-system-v1/05-generator-updates/_story.md b/docs/work/conformance-system-v1/05-generator-updates/_story.md index 830f154..f34deb3 100644 --- a/docs/work/conformance-system-v1/05-generator-updates/_story.md +++ b/docs/work/conformance-system-v1/05-generator-updates/_story.md @@ -3,7 +3,7 @@ id: 05-generator-updates epic: conformance-system-v1 title: Generator updates — emit feature.manifest.ts + self-asserting bind-production type: technical-story -status: in-progress +status: done feature: turbo-generators depends-on: [04-ci-drift-gate] blocks: [06-feature-migrations] @@ -43,10 +43,10 @@ conformance-ready by default. - Backfilling manifests for existing features (milestone vi) ## Tasks -- [ ] Story scaffold -- [ ] feature.manifest.ts.hbs template -- [ ] bind-production.ts.hbs update -- [ ] config.ts action wiring -- [ ] Run generator into tmp; verify shape -- [ ] Snapshot regen (if needed) + verify tests pass -- [ ] Final verification + closeout +- [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 diff --git a/docs/work/conformance-system-v1/_epic.md b/docs/work/conformance-system-v1/_epic.md index 4edaa4d..15e46d6 100644 --- a/docs/work/conformance-system-v1/_epic.md +++ b/docs/work/conformance-system-v1/_epic.md @@ -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.b — Manifest-aware AST rules](03-b-ast-eslint-rules/_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) - [ ] 07 — Migrate auth feature reference (later plan)