7.2 KiB
Conformance Milestone v — Generator updates
Goal: pnpm turbo gen feature <name> now emits a feature.manifest.ts declaring the scaffolded use case, and the scaffolded bind-production.ts calls assertFeatureConformance at its tail. New features are conformance-compliant from creation.
Architecture: Two template additions/changes in turbo/generators/templates/feature/:
- NEW:
src/feature.manifest.ts.hbs— emitsdefineFeature({...})with the scaffolded use case declared - UPDATE:
src/di/bind-production.ts.hbs— adds imports forassertFeatureConformance+<name>Manifestand calls the assertion at the tail
Plus one config.ts action to emit the manifest template, and snapshot regeneration if the existing tests snapshot the full file tree.
Tasks
Task 1: Story 05 scaffold
Create docs/work/conformance-system-v1/05-generator-updates/_story.md:
---
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 <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
- [ ] 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
git add docs/work/conformance-system-v1/05-generator-updates/_story.md
git commit -m "docs(work): story 05 — generator updates"
Task 2: feature.manifest.ts.hbs template
Create turbo/generators/templates/feature/src/feature.manifest.ts.hbs:
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;
(No test file for the template itself; the generator's existing snapshot tests will cover that the file is emitted with expected content.)
Task 3: bind-production.ts.hbs update — call assertFeatureConformance at tail
Modify turbo/generators/templates/feature/src/di/bind-production.ts.hbs. Add three new imports at the top (after the existing imports):
import { assertFeatureConformance } from "@repo/core-shared/conformance";
import { {{camelCase name}}Manifest } from "../feature.manifest";
At the very end of the bindProduction{{pascalCase name}} function body — AFTER the // <gen:event-handlers>, // <gen:jobs>, // <gen:realtime-handlers> anchor comments and BEFORE the closing } — add:
// 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,
);
Task 4: config.ts action wiring — emit the manifest
Open turbo/generators/config.ts. Find the actions array for the feature generator. After the action that emits src/index.ts (or in the appropriate position with other src/ files), add an action to emit src/feature.manifest.ts from the new template:
{
type: "add",
path: "{{ turbo_paths.root }}/packages/{{kebabCase name}}/src/feature.manifest.ts",
templateFile: "templates/feature/src/feature.manifest.ts.hbs",
},
If the existing actions use a different path-resolution pattern (e.g., path.join(...)), match that pattern. Read the surrounding actions before adding.
Task 5: Run the generator into tmp + verify
Run a generator invocation against a tmp dir to confirm the output:
cd /tmp && rm -rf gen-test && mkdir gen-test && cd gen-test
# Initialize an empty turbo repo-like structure:
mkdir -p packages
ln -s /Users/danijel/Documents/Projects/template-vertical/.claude/worktrees/conformance-milestone-v/turbo .
Actually, the simpler path: run the existing snapshot tests, which already exercise the generator:
pnpm --filter @repo/turbo-generators test
If they pass (likely with snapshot mismatches because we added a new file), regenerate snapshots:
pnpm --filter @repo/turbo-generators test -- -u
Verify the regenerated snapshots include src/feature.manifest.ts and the updated bind-production with the assertion at the tail.
Commit the regenerated snapshots:
git add turbo/generators/__snapshots__/ turbo/generators/templates/ turbo/generators/config.ts
git commit -m "feat(generators): emit feature.manifest.ts + self-asserting bind-production"
Task 6: Final verification + closeout
Run:
pnpm typecheck
pnpm test
pnpm lint
pnpm conformance
pnpm turbo boundaries
All five pass.
Update docs/work/conformance-system-v1/05-generator-updates/_story.md:
- frontmatter
status: in-progress→done - All
- [ ]→- [x]
Update docs/work/conformance-system-v1/_epic.md. Find:
- [ ] 05 — Generator emits manifest + contracts + test stubs (later plan)
Replace with:
- [x] [05 — Generator updates](05-generator-updates/_story.md)
Commit: docs(work): close story 05 — generator updates.