Files
agentic-dev-template/docs/glossary.md
Danijel Martinek 4dce1df084 docs(coverage): ADR-020 + glossary entries + hook keyword group
Architecture record for the agent-first coverage initiative seeded by
the 2026-05-13 PRD. Captures the durable decisions:

- 4-layer architecture (L0 vitest, L1 diff, L2 aggregate, L3 mutation)
- Manifest-driven coverage band as single source of truth (vitest +
  assertFeatureConformance + pnpm coverage:diff all read from it)
- Cover-the-diff (changed lines), not cover-the-new-code
- Committed coverage/summary.json (no SaaS), trend via git log
- Mutation testing scoped to entities + use-cases, on-demand only
- Machine-first output format (JSON stdout, human stderr)

Glossary gets a new "Coverage" section with 7 entries (coverage band,
L0-L3 layers, diff coverage, mutation testing, mutation score,
coverage/summary.json), plus two relationship rows and a flagged
ambiguity for "coverage" qualifiers.

prompt-context.sh hook gets a 9th keyword group — when a prompt
mentions coverage / uncovered / lcov / mutation / stryker, the
relevant ADR + guide path are injected as additional context for
the turn.

This is the documentation layer of the coverage epic. Implementation
(manifest schema, vitest auto-derive, scripts, boot assertion,
mutation tooling) lands in subsequent stories.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 13:42:26 +02:00

18 KiB
Raw Blame History

Glossary

Canonical vocabulary for template-vertical. Shared by humans and AI agents — every term means the same thing here. Terms specific to this repo's domain (monorepo / Clean Architecture / agent-first workflow / conformance). General programming concepts (DI, retries, errors, etc.) don't belong unless they have a project-specific meaning.

Rules:

  • One sentence per definition. Define what it is, not what it does.
  • Pick one canonical term; list aliases under _Avoid:_.
  • Relationships expressed with bold term names + cardinality.
  • Flag ambiguities under "Flagged ambiguities" with a resolution.
  • Reference ADRs by ID (ADR-NNN); reference paths sparingly (they rot fast).

Packages

Package: A workspace member under packages/ or apps/ with its own package.json and tag. The atomic unit of dependency, build, and boundary enforcement. Avoid: module, library, app (unless specifically apps/).

Tag: The boundary classification on a package (app, core, core-composition, feature, tooling). Enforced by ESLint (eslint-plugin-boundaries) and Turborepo boundaries. See AGENTS.md → Boundary Rules.

Feature (a.k.a. feature package): A vertical slice owning its Clean Architecture layers + integrations under packages/<name>/. Currently: auth, blog, media, marketing-pages, navigation. Avoid: domain, module, vertical (use "feature" or "vertical feature").

Must-have core: A core package the template can't run without — core-shared, core-cms, core-api. Avoid: baseline core, base core.

Optional core: A core package scaffolded on demand via pnpm turbo gen core-package <name>core-realtime, core-events, core-trpc, core-ui, core-audit. See docs/architecture/template-tiers.md.

Core-composition: A tag for packages that compose feature exports — core-api, core-cms, core-trpc. The only packages allowed to import from @repo/<feature>/api or @repo/<feature>/cms subpaths.

Tooling package: A package providing build/lint/test infrastructure — core-eslint, core-typescript, core-testing. May only depend on other tooling.

App: A runtime entry point under apps/web-next, web-tanstack, cms, storybook.

Clean Architecture layers (per feature)

Entities layer (packages/<feature>/src/entities/): Domain models (models/<x>.ts) and domain errors (errors/<domain>.ts + errors/common.ts). No I/O.

Application layer (packages/<feature>/src/application/): Use cases. Pure orchestration over repository + service ports.

Infrastructure layer (packages/<feature>/src/infrastructure/): Repository and service implementations (real Payload-backed + mock).

Interface-adapters layer (packages/<feature>/src/interface-adapters/): Controllers — one per use case. Translate unknown input → use-case input via Zod safeParse; thread the output through a presenter.

Integrations layer (packages/<feature>/src/integrations/): Vendor-specific glue — integrations/api/ (tRPC routers), integrations/cms/ (Payload collections + tasks).

DI folder (packages/<feature>/src/di/): Container, symbols, and the two binders. The wiring layer.

Feature building blocks

Use case: A single business action expressed as a factory: (deps) => async (input) => output. Always paired with a Zod xInputSchema + (non-void) xOutputSchema co-located in the same file. Exports the type alias I*UseCase = ReturnType<typeof xUseCase>. Avoid: command, action, service method.

Controller: The thin adapter from unknown input to a use case. One per use case. Co-located top-level function presenter for non-void outputs. Avoid: multi-method controller (forbidden — one verb-noun per file).

Repository: A port for collection-style entity access. Lives in infrastructure/<x>.repository.{ts,mock.ts,interface.ts}. Real impls drop the payload- prefix; mocks use the .mock.ts suffix.

Service: A port for non-collection capabilities (auth, mailer, etc.). Same .ts / .mock.ts / .interface.ts triad as repositories.

Manifest (feature.manifest.ts): The per-feature contract declaring useCases, audits, publishes, consumes, and requiredCores. Source of truth for the conformance system. Always edited before code (manifest-first ordering).

Symbol: A DI token in packages/<feature>/src/di/symbols.ts. Used by Inversify to identify a binding.

Binder: A function that registers DI bindings — bindProductionX(ctx) (real Payload) or bindDevSeedX(ctx) (populated mock). Lives at src/di/bind-production.ts and src/di/bind-dev-seed.ts. Self-asserts conformance at its tail via assertFeatureConformance(...).

bindAll(): The app-level DI dispatcher (e.g. apps/web-next/src/server/bind-production.ts). Picks each feature's binder by env (USE_DEV_SEED, NODE_ENV) and threads a single shared ctx through them. Idempotent.

ctx (a.k.a. bind context): The object passed to every binder. Required fields: tracer, logger, plus config for production. Optional fields: bus, queue, realtime, realtimeRegistry (only when the corresponding optional cores are scaffolded).

Dev-seed: The populated in-memory mock mode. Lives in src/__seeds__/dev.ts per feature, exported as a lazy buildDev<Entities>() function. Selected by USE_DEV_SEED=true or by default when not in production.

Public surface: A feature's allowed import surface — . (contracts: types, errors, schemas, I*UseCase aliases, router type), ./ui (queries, components), ./cms, ./api, ./di/bind-production, ./di/bind-dev-seed. No deep source paths exist in exports maps.

Anchor: A // <gen:*> comment marking where a generator injects code (e.g. <gen:events>, <gen:job-symbols>, <gen:realtime-handlers>). A CI guard at packages/core-eslint/anchors.test.js keeps them present.

Conformance system

Conformance: The 5-gate enforcement chain that keeps a feature's manifest and code in sync. Layers:

  1. TypeScript brands (0s) — Instrumented, Captured, Audited on every wired use case / controller.
  2. ESLint conformance rules (<1s) — five custom rules in core-eslint.
  3. Boot assertion (~3s) — assertFeatureConformance(...) at the tail of every binder.
  4. CI drift gate (pnpm conformance, ~120s) — cross-feature event closure.
  5. Fallow (pnpm fallow, ~3060s) — whole-codebase dead exports / dupes / complexity / AI-change audit.

Brand: A TypeScript phantom type attached to a wired use case / controller — Instrumented (after withSpan), Captured (after withCapture), Audited (after withAudit). Enforces the wrapper composition at bind time.

Manifest-first ordering: The non-negotiable authoring order for any new use case: (1) manifest entry → (2) contracts (xInputSchema, xOutputSchema, IXUseCase) → (3) tests (red) → (4) implementation (green). The generator scaffolds (1)+(2)+test stubs so new features are conformance-compliant by default.

Fallow: The whole-codebase auditor (pnpm fallow) — dead exports, unused files, duplicate code, circular deps, complexity hotspots, AI-change audit drift. The fifth conformance gate. Run pnpm fallow:audit before commits.

Drift: Any disagreement between a feature's manifest and its code. The conformance gates are designed to catch drift at the earliest possible latency.

Coverage

Coverage band: The per-path threshold declared in feature.manifest.ts under coverage.bands — one entry per Clean Architecture layer (entities, use-cases, controllers) plus a baseline for everything else. Single source of truth read by vitest, assertFeatureConformance, and pnpm coverage:diff. See ADR-020.

L0 / L1 / L2 / L3: The four coverage layers (ADR-020). L0 = vitest per-layer thresholds (test-time). L1 = pnpm coverage:diff cover-the-diff gate (post-test, CI + dispatch loop). L2 = pnpm coverage:aggregate → committed coverage/summary.json (observability). L3 = pnpm mutate Stryker mutation testing on entities + use-cases (on-demand, not default).

Diff coverage: The gate that asserts every changed executable line has execution count > 0 in the merged lcov. Cover-the-diff (modified + new lines both count), not cover-the-new-code. Run via pnpm coverage:diff [<base-ref>]. Avoid: patch coverage, delta coverage (use "diff coverage" canonically).

Mutation testing: A test-quality signal that mutates source code and re-runs tests; surviving mutants mean the test exists + executes the code but doesn't actually assert behavior. Scoped to entities/ + application/use-cases/ per feature. Run via pnpm mutate [--filter @repo/<feature>].

Mutation score: The percentage of mutants killed (i.e., caught by tests) out of all mutants generated. Per-feature threshold defaults to 80% (overridable in feature.manifest.ts via coverage.mutationThreshold).

coverage/summary.json: The aggregated per-package + repo-level coverage snapshot, committed on merge to main. Grep-able from git history via git log -- coverage/summary.json. Includes timestamp + commit SHA for correlation with deploys.

Cross-feature mechanisms

Event bus (IEventBus): The vendor-neutral cross-feature pub/sub interface in @repo/core-events. Two implementations: InMemoryEventBus (dev/test, synchronous) and PayloadJobsEventBus (production, durable via Payload tasks). Selected by bindAll(). See ADR-015. Use when: feature A's success must trigger feature B's reaction. Don't use for in-feature flow control — that's a direct use-case call (rule E0).

Event descriptor: A defineEvent(...) declaration with a name (wire format) + Zod payload schema. Lives at packages/<feature>/src/events/<event>.event.ts. Publishers re-export from the feature root; consumers do not.

Event handler: A consumer's reaction to a published event. Lives at packages/<feature>/src/events/handlers/on-<publisher>-<event>.handler.ts. Always private — never re-exported (rule E1, enforced by no-handler-reexport).

Job queue (IJobQueue): The vendor-neutral deferred-work interface in @repo/core-shared/jobs/. Two implementations: InMemoryJobQueue (dev/test, setImmediate) and PayloadJobQueue (production). Feature packages enqueue via IJobQueue only — direct payload.jobs.queue() is ESLint-blocked (rule J0).

Realtime channel descriptor: A defineRealtimeChannel(...) declaration in packages/<feature>/src/realtime/<channel>.channel.ts. Re-exported from the feature root. Carries a Zod payload schema + a scope.

Channel scope: A channel's subscription rule — public | authenticated | role:<name> | user-scoped. See ADR-016.

Broadcaster (IRealtimeBroadcaster): The server-side push interface in @repo/core-realtime. Use cases call broadcaster.broadcast(channel, payload) after the success path.

Realtime handler: A consumer's reaction to an inbound client message on a channel. Lives at packages/<feature>/src/realtime/handlers/*.handler.ts. Always private — never re-exported (rule R1, enforced by no-realtime-handler-reexport).

Audit log: A DPA-compliant record of a use case's side effects. Emitted via auditLog.record(...); declared in the manifest's audits: array. See ADR-018.

Instrumentation

Tracer (ITracer): The span interface in @repo/core-shared/instrumentation/. Three impls: NoopTracer, OtelTracer, RecordingTracer (test-only, from core-testing).

Logger (ILogger): The capture interface. Same three-impl shape as ITracer. Used for exception reporting and structured logs.

Metrics (IMetrics): The counter/gauge/histogram interface. Same three-impl shape.

withSpan / withCapture / withAudit: The three wrapper composers applied at DI bind time. Composition: withSpan(tracer, opts, withCapture(logger, tags, withAudit(auditLog, schema, factory(deps))))withSpan outermost. Together they attach the Instrumented / Captured / Audited brands.

Span: A traced unit of work. Emitted by tracer.startSpan(...) (inline in repos) or withSpan(...) (composed for use cases + controllers).

Capture: The act of recording an exception once. Guarded by the non-enumerable __sentryReported flag so a bubbled error surfaces exactly once.

PII scrub: The server-side scrubbing of email/passwords/tokens/cookies/auth/IPs at the OTel processor layer (PiiScrubSpanProcessor + PiiScrubLogRecordProcessor) before any exporter sees the data. sendDefaultPii: false everywhere, CI grep-enforced. See ADR-017 §7.

Rule 0: The bindAll() decision that selects OTel+Sentry instrumentation when a DSN env var is present, otherwise the Noop chain. Orthogonal to USE_DEV_SEED / NODE_ENV (those control repo bindings, not instrumentation).

Workflow

PRD: The top-level requirements doc at docs/work/prds/<date>-<slug>.prd.md. Status flows draft → in-review → approved → superseded. pnpm work decompose refuses to run on draft. Avoid: spec (use "spec" only for docs/superpowers/specs/ design docs).

Epic: A large body of work, one folder under docs/work/<epic-slug>/ with _epic.md. Decomposed from a PRD.

Story: One use case or one technical capability, one folder under <epic>/<story-slug>/ with _story.md. Type metadata: user-story or technical-story.

Task: One vertical slice = one PR = one commit. File <slug>.task.md under the story folder.

Slice (a.k.a. vertical slice): A change that exercises every Clean Architecture layer end-to-end for one capability — manifest entry + contracts + tests + impl + DI wiring + integration. The unit of a task.

Sandcastle: The agent dispatch orchestrator (https://github.com/mattpocock/sandcastle). Invoked via pnpm work dispatch --execute. See ADR-019.

_state.json: The orchestrator-managed derived index at docs/work/_state.json. Regenerated from markdown via pnpm work rebuild-state. Committed.

Generator: A pnpm turbo gen <kind> invocation. Generator-first is non-negotiable — agents always prefer the generator over hand-rolled scaffolding. Available kinds: feature, event, job, realtime, core-package, core-ui-component.

Slice = task = PR = commit: The shipping rhythm. One vertical slice closes one task, becomes one PR, lands as one commit.

Modes

Production mode: NODE_ENV=production (and USE_DEV_SEED unset) → bindAll() wires Payload-backed repositories + PayloadJobsEventBus + PayloadJobQueue.

Dev-seed mode: USE_DEV_SEED=true (or default fallback when not in production) → bindAll() wires populated mocks + InMemoryEventBus + InMemoryJobQueue. Developer default so pnpm dev boots without Payload running.

Relationships

  • A PRD decomposes into one or more Epics.
  • An Epic contains one or more Stories.
  • A Story is implemented by one or more Tasks, each a Slice.
  • A Use case is declared in a Manifest before it has code (manifest-first ordering).
  • A Use case has exactly one Controller.
  • A Controller has at most one presenter (omitted for void outputs).
  • A Feature owns its Repositories, Services, Use cases, Controllers, Events, Jobs, Channels, and DI Container.
  • Cross-feature reactions travel through the Event bus; in-feature reactions are direct use-case calls.
  • An Event descriptor is public; its Event handler is always private.
  • A Channel descriptor is public; its Realtime handler is always private.
  • Brands are attached only at DI bind time, by withSpan / withCapture / withAudit.
  • Conformance asserts the Manifest and code agree, at five latency tiers.
  • A Coverage band in the Manifest is read by Vitest (L0), assertFeatureConformance (boot), and pnpm coverage:diff (L1) — one decision, three enforcers.
  • Mutation testing is the third dimension of test quality, after "test file exists" (ESLint structural) and "test executes the code" (L0/L1 coverage).

Flagged ambiguities

  • "feature" — always a vertical feature package; never a CMS-collection field or a generic capability.
  • "service" — a DI-injected port (e.g. IAuthenticationService); not a Kubernetes service, Payload collection, or generic "service object".
  • "handler" — qualify by context: event handler (cross-feature) | realtime handler (inbound socket message) | task handler (Payload job).
  • "schema" — qualify: Zod schema (input/output contracts) | Payload collection schema (CMS field definitions).
  • "config" — qualify: Payload config | Next config | Vitest config | TS config.
  • "bind" — DI binding (bind<I>(SYMBOL).toDynamicValue(...)); not a Function.prototype.bind.
  • "spec"docs/superpowers/specs/ design doc; never a PRD or a Jest spec file.
  • "controller" — one verb-noun pair per file; never a multi-method MVC controller.
  • "module" — avoid for packages (use "package"); reserve for Node ESM/CJS module semantics if needed.
  • "coverage" — qualify when ambiguous: L0 coverage (per-layer thresholds, test-time) | diff coverage / L1 (cover-the-diff gate) | aggregate coverage / L2 (committed summary.json) | mutation coverage / L3 (Stryker mutation score, not line coverage).

Cross-references

  • Architecture: docs/architecture/overview.md, docs/architecture/vertical-feature-spec.md, docs/architecture/agent-first-workflow-and-conformance.md
  • ADRs: docs/decisions/adr-NNN-<slug>.md
  • Workflow: docs/work/README.md, AGENTS.md § "Agent-driven development"
  • Guides: docs/guides/runbook.md, docs/guides/conformance-quickref.md, docs/guides/tdd-workflow.md