Files
agentic-dev-template/docs/guides/conformance-quickref.md
danijel-lf b97e6105d3 feat(conformance): wire cross-feature reader pattern into docs and schema
Add reads field to UseCaseManifest, update CLAUDE.md with Q0-Q3 rules,
add ./reader subpath to AGENTS.md exports table, and cascade reader
conventions through conformance quickref, adding-a-feature guide, and
scaffolding guide. Moves gen reader from deferred to planned.
2026-05-28 20:55:34 +02:00

11 KiB
Raw Permalink Blame History

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:

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: [],
      reads: ["auth"], // cross-feature reader dependency
    },
  },
  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.<name>.mutates boolean True for create/update/delete; drives whether __audited brand is required
useCases.<name>.audits string[] Audit event types this use case emits via auditLog.record({ type: "X" })
useCases.<name>.publishes string[] Cross-feature events this use case publishes via bus.publish("X")
useCases.<name>.consumes string[] Cross-feature events this use case consumes (via an event handler)
useCases.<name>.reads string[] Other features whose readers this use case queries (e.g. ["auth"])
realtimeChannels string[] Realtime channels this feature owns
jobs string[] Job slugs this feature enqueues
requiresConsent ConsentCategory[] Consent categories feature use cases require; drives withConsent wrapping + no-undeclared-consent-check
rateLimit RateLimitBudget[] Rate-limit budgets this feature's use cases enforce; drives withRateLimit wrapping + no-undeclared-rate-limit

Re-export from src/index.ts:

export { fooManifest, type FooManifest } from "./feature.manifest";

bindProductionX self-assertion

Every feature's bind-production.ts calls the assertion at the tail:

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 ~3060s 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-<name> 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
conformance/usecase-must-be-wired error Every manifest use case must be bound via wireUseCase({ name: "<key>" }) in bind-production.ts / bind-dev-seed.ts
conformance/no-undeclared-analytics-event warn analytics.track("X") literal must match the manifest's analyticsEvents for the use case
conformance/pii-declaration-must-be-complete warn custom.pii blocks in Payload config files must declare all required fields: category, purpose, exportable, restrictable
conformance/component-must-have-story warn Every component file under src/ must have a sibling .stories.tsx file
conformance/component-must-have-test warn Every component file under src/ must have a sibling .test.tsx file
conformance/atomic-tier-import-direction warn Atomic-design import direction must flow downward (atoms ← molecules ← organisms ← templates ← pages); no upward imports
conformance/no-undeclared-consent-check warn consent.isGranted("X") literal in a use-case file must match a category declared in manifest.requiresConsent; warns if declared categories are never checked
conformance/no-undeclared-rate-limit warn rateLimit.consume(budgetName, ...) call in a use-case file must match a budget name declared in manifest.rateLimit; warns if declared budgets are never consumed

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 <name> scaffolds steps 1 + 2 in a single command.

Common drift patterns and the gate that catches them

  • Forgot withSpan at bind time → tsc TS2322 + usecase-must-be-wired ESLint error + boot assertion + bind-production smoke test
  • Manifest entry has no wireUseCase call in either binderusecase-must-be-wired ESLint error + boot assertion + bind-production smoke test
  • 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 itconformance/no-undeclared-event-publish (warn)
  • Feature has use cases but no manifestconformance/feature-must-have-manifest (error)
  • Manifest references requiredCores: ["X"] but no core-X package existsconformance/required-cores-installed (error)
  • One feature consumes Y but no feature publishes Ypnpm conformance orphan check (CI gate)
  • Factory calls analytics.track("X") but manifest doesn't declare it in analyticsEventsconformance/no-undeclared-analytics-event (warn); add the event slug to the manifest or remove the call

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.