# Conformance system — quick reference Day-to-day reference for the manifest-first workflow. For design rationale see `docs/architecture/agent-first-workflow-and-conformance.md` and the interactive `feature-conformance-explainer.html`. --- ## The manifest Every feature has one at `src/feature.manifest.ts`: ```ts import { defineFeature } from "@repo/core-shared/conformance"; export const fooManifest = defineFeature({ name: "foo", requiredCores: [], useCases: { getThing: { mutates: false, audits: [], publishes: [], consumes: [] }, createThing: { mutates: true, audits: ["thing.created"], publishes: ["foo.thing-created"], consumes: [], }, }, realtimeChannels: [], jobs: [], } as const); export type FooManifest = typeof fooManifest; ``` Field reference: | Field | Type | Meaning | | --------------------------- | -------------- | --------------------------------------------------------------------------- | | `name` | string literal | Feature name (kebab-case, matches package name) | | `requiredCores` | string[] | Optional cores this feature requires (e.g. `["audit", "events"]`) | | `useCases..mutates` | boolean | True for create/update/delete; drives whether `__audited` brand is required | | `useCases..audits` | string[] | Audit event types this use case emits via `auditLog.record({ type: "X" })` | | `useCases..publishes` | string[] | Cross-feature events this use case publishes via `bus.publish("X")` | | `useCases..consumes` | string[] | Cross-feature events this use case consumes (via an event handler) | | `realtimeChannels` | string[] | Realtime channels this feature owns | | `jobs` | string[] | Job slugs this feature enqueues | Re-export from `src/index.ts`: ```ts export { fooManifest, type FooManifest } from "./feature.manifest"; ``` ## bindProductionX self-assertion Every feature's `bind-production.ts` calls the assertion at the tail: ```ts import { assertFeatureConformance } from "@repo/core-shared/conformance"; import { fooManifest } from "../feature.manifest"; export function bindProductionFoo(ctx: BindProductionContext): void { // ... bind use cases, wrapped with withSpan + withCapture + (if mutating + audits) withAudit ... assertFeatureConformance( fooContainer, fooManifest, { getThing: FOO_SYMBOLS.IGetThingUseCase, createThing: FOO_SYMBOLS.ICreateThingUseCase, }, ctx, ); } ``` The symbol map declares which container symbol each manifest use-case key resolves to. ## The five gates | Gate | When it fires | What it catches | Severity | | ------------------ | --------------------- | ------------------------------------------------------------------------ | -------------------- | | `tsc` | on save | forgotten wrappers; manifest-derived slot type rejects unwrapped factory | error | | `eslint` | on save / `pnpm lint` | manifest ↔ code drift; missing sibling test; missing manifest | error or warn | | `pnpm dev` | at boot | binding lost its runtime brand; manifest declares more than wired | throws synchronously | | `pnpm conformance` | CI | orphan event consumers across features | exits non-zero | | `pnpm fallow` | ~30–60s | unused exports/files, dupes, circular deps, complexity, AI-change audit | warn (currently) | ## ESLint rules | Rule | Severity | What it does | | ----------------------------------------- | -------- | -------------------------------------------------------------------------------------- | | `conformance/feature-must-have-manifest` | error | Use-case files require a sibling manifest | | `conformance/usecase-must-have-test-file` | error | Every `*.use-case.ts` has a sibling `*.use-case.test.ts` | | `conformance/required-cores-installed` | error | Manifest's `requiredCores` must exist as `core-` packages in pnpm-workspace.yaml | | `conformance/no-undeclared-event-publish` | warn | `bus.publish("X")` literal must match the manifest's `publishes` for the use case | | `conformance/no-undeclared-audit` | warn | `auditLog.record({ type: "X" })` literal must match the manifest's `audits` | ## Workflow ordering for new use cases 1. **Manifest** — add the use case to `feature.manifest.ts` with empty `audits` / `publishes` / `consumes` 2. **Contracts** — export `xInputSchema`, `xOutputSchema`, `IXUseCase` from the use-case file (factory body throws "not implemented") 3. **Tests (red)** — write the test importing the contracts; verify it fails 4. **Implementation (green)** — fill the factory body until tests pass For the fast path: `pnpm turbo gen feature ` scaffolds steps 1 + 2 in a single command. ## Common drift patterns and the gate that catches them - **Forgot `withSpan` at bind time** → tsc TS2322 + boot assertion - **Manifest declares `audits: ["X"]` but factory doesn't call `auditLog.record({type:"X"})`** → no automatic catch yet; future story - **Factory calls `bus.publish("Y")` but manifest doesn't declare it** → `conformance/no-undeclared-event-publish` (warn) - **Feature has use cases but no manifest** → `conformance/feature-must-have-manifest` (error) - **Manifest references `requiredCores: ["X"]` but no `core-X` package exists** → `conformance/required-cores-installed` (error) - **One feature consumes `Y` but no feature publishes `Y`** → `pnpm conformance` orphan check (CI gate) ## Pinning down a drift When a gate fires, the error message tells you what to run. For example: > `Feature blog has use cases but no feature.manifest.ts. Run 'pnpm turbo gen feature blog' or scaffold the manifest manually at packages/blog/src/feature.manifest.ts.` That's the "fix" line — follow it. ## Fallow audit for AI changes When you (the agent) finish a task and are about to commit, run: ``` pnpm fallow:audit ``` This runs `fallow audit --base main`, comparing your branch's diff against main. If your change adds dead exports, dupes, or complexity hotspots, fallow tells you exactly what and where. Fix or accept (with --gate flag to ignore inherited findings). This is the catch-all for whole-codebase drift the per-file gates can't see. --- For the deeper design rationale see `docs/architecture/agent-first-workflow-and-conformance.md` and the interactive `feature-conformance-explainer.html`.