From a372eeda86deef9a71e8a40499649a4a7e500c6b Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Wed, 13 May 2026 13:04:42 +0200 Subject: [PATCH] docs: add canonical glossary + install mattpocock skills adapted for repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docs/glossary.md is the shared vocabulary source for humans and agents. Resolves every cross-cutting term used in this repo (feature, use case, manifest, slice, conformance, dispatch, ...) with one-sentence definitions, relationships, and flagged ambiguities. Linked from CLAUDE.md "Read First" and AGENTS.md preamble so every session loads it early. .claude/skills/ installs four mattpocock skills adapted to this monorepo: - to-prd: writes to docs/work/prds/ with the repo's PRD frontmatter + merged user-stories/implementation/testing sections - grill-with-docs: points at docs/decisions/ + docs/glossary.md; adds feature.manifest.ts + conformance-rule cross-checks - grill-me: minor — adds pnpm work / fallow / manifest shortcuts - handoff: adds the repo's specific don't-duplicate artifacts list Also fixes a missed "Phase-1" residual in CLAUDE.md's Read First section. Co-Authored-By: Claude Opus 4.7 (1M context) --- .claude/skills/grill-me/SKILL.md | 18 ++ .claude/skills/grill-with-docs/SKILL.md | 106 ++++++++ .../skills/grill-with-docs/glossary-format.md | 62 +++++ .claude/skills/handoff/SKILL.md | 36 +++ .claude/skills/to-prd/SKILL.md | 108 ++++++++ AGENTS.md | 2 + CLAUDE.md | 3 +- docs/glossary.md | 253 ++++++++++++++++++ 8 files changed, 587 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/grill-me/SKILL.md create mode 100644 .claude/skills/grill-with-docs/SKILL.md create mode 100644 .claude/skills/grill-with-docs/glossary-format.md create mode 100644 .claude/skills/handoff/SKILL.md create mode 100644 .claude/skills/to-prd/SKILL.md create mode 100644 docs/glossary.md diff --git a/.claude/skills/grill-me/SKILL.md b/.claude/skills/grill-me/SKILL.md new file mode 100644 index 0000000..8ea7bed --- /dev/null +++ b/.claude/skills/grill-me/SKILL.md @@ -0,0 +1,18 @@ +--- +name: grill-me +description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when the user wants to stress-test a plan, get grilled, or mentions "grill me". Use grill-with-docs instead when the plan should cross-check against ADRs + glossary + manifests. +--- + +Interview the user relentlessly about every aspect of this plan until you reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. + +Ask the questions **one at a time**, waiting for feedback before continuing. + +If a question can be answered by exploring the codebase, explore the codebase instead. Useful shortcuts in this repo: + +- `pnpm work status` — current epics and ready stories +- `cat packages//src/feature.manifest.ts` — declared use cases / events / audits +- `ls docs/decisions/` — ADRs by number +- `pnpm fallow` — dead exports, dupes, complexity hotspots +- grep manifests across all features: `grep -r "publishes:" packages/*/src/feature.manifest.ts` + +When grilling pulls in ADR / glossary / manifest cross-checks and you want to update those docs inline, switch to `grill-with-docs` instead. diff --git a/.claude/skills/grill-with-docs/SKILL.md b/.claude/skills/grill-with-docs/SKILL.md new file mode 100644 index 0000000..733094a --- /dev/null +++ b/.claude/skills/grill-with-docs/SKILL.md @@ -0,0 +1,106 @@ +--- +name: grill-with-docs +description: Stress-test a plan against this repo's domain glossary, ADRs, conformance rules, and feature manifests. Update docs/glossary.md inline as terms crystallize; offer ADRs sparingly. Use when the user wants to harden a plan before it becomes a PRD. +--- + + + +Interview the user relentlessly about every aspect of this plan until you reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. + +Ask the questions **one at a time**, waiting for feedback on each before continuing. + +If a question can be answered by exploring the codebase, explore the codebase instead of asking. The repo has fast feedback loops — run `pnpm work status`, grep manifests, read feature `feature.manifest.ts`, check ADRs. Speculation is a last resort. + + + + + +## Repo doc map + +This repo uses a **single context** with these doc locations: + +``` +/ +├── docs/ +│ ├── glossary.md ← lazy-create when first term resolves +│ ├── decisions/ ← ADRs (adr-NNN-.md, 3-digit zero-pad) +│ │ ├── adr-001-monorepo-tool.md +│ │ ├── adr-018-audit-and-compliance.md +│ │ └── ... +│ ├── architecture/ ← long-form specs + workflow design +│ ├── work/ ← PRDs, epics, stories, tasks +│ └── guides/ ← how-to runbooks +└── packages//src/feature.manifest.ts ← per-feature contract +``` + +There is **no `CONTEXT.md` or `CONTEXT-MAP.md`** — this repo uses `docs/glossary.md` (create lazily) plus the per-feature `feature.manifest.ts` files for machine-readable domain shape. Don't create the multi-context layout (`CONTEXT-MAP.md`) unless this becomes a polyrepo. + +## During the session + +### Challenge against the glossary + manifests + +When the user introduces a term that conflicts with `docs/glossary.md` (if it exists) or with a `feature.manifest.ts` entry, call it out immediately: + +> "Your glossary defines `cancellation` as the act of voiding an unsent invoice, but you seem to mean the user-initiated subscription teardown — which is it?" + +> "`auth.signIn` exists in `packages/auth/src/feature.manifest.ts` with that exact slug — are you adding a new use case or extending the existing one?" + +### Sharpen fuzzy language + +When the user uses vague or overloaded terms, propose a precise canonical term: + +> "You're saying `account` — do you mean a `User` (entity in `packages/auth`) or a Payload-collection record? Those are distinct." + +### Discuss concrete scenarios + +When domain relationships are being discussed, stress-test them with specific scenarios. Invent edge cases that force precision about boundaries between concepts. Lean on the existing feature set — auth, blog, media, marketing-pages, navigation — for grounding examples. + +### Cross-reference with code + +When the user states how something works, verify it against the code. Look at: + +- The feature's `feature.manifest.ts` for declared use cases, audits, publishes, consumes +- `packages//src/application/use-cases/` for the actual shape +- `packages//src/di/bind-production.ts` for what's wired +- `docs/decisions/adr-NNN-*.md` for the decision history + +If you find a contradiction, surface it: + +> "You said cross-feature reactions happen through the bus, but `packages/auth/src/feature.manifest.ts` shows `publishes: []` — has this been wired yet?" + +### Cross-reference with ADRs + +Before recommending an approach, scan `docs/decisions/` for relevant ADRs. If your recommendation contradicts a current-status ADR, surface that explicitly: + +> "You're proposing direct cross-feature imports, but `adr-006-vertical-feature-packages.md` plus rule R20 in the ESLint config forbid that — events (`core-events`) are the sanctioned path. Want to use events, or do you want to reopen the ADR?" + +### Cross-reference with conformance rules + +The conformance system (`docs/architecture/agent-first-workflow-and-conformance.md`) defines hard contracts: + +- Every use case has a manifest entry → contracts → tests → impl (in that order) +- TS brands (`Instrumented`, `Captured`, `Audited`) attached at DI bind time +- ESLint rules enforce manifest ↔ code alignment +- `pnpm conformance` enforces cross-feature event closure + +If the plan would violate any of these, flag it. + +### Update `docs/glossary.md` inline + +When a term is resolved during the conversation, append it to `docs/glossary.md` right then — don't batch. Lazy-create the file when the first term is resolved. Use the format in [glossary-format.md](./glossary-format.md). + +Only include terms meaningful to **this repo's domain** (template / monorepo / agent-first workflow / clean architecture / vertical features). Skip general programming concepts. Skip implementation details — those belong in code or ADRs. + +### Offer ADRs sparingly + +Only offer to create an ADR when all three are true: + +1. **Hard to reverse** — the cost of changing your mind later is meaningful +2. **Surprising without context** — a future reader will wonder "why did they do it this way?" +3. **Result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons + +If any is missing, skip the ADR. The repo's ADRs follow a long-form `Context → Decision → Alternatives considered → Consequences → Related` shape (see `docs/decisions/adr-015-events-and-jobs.md` for a representative example). Number is next-highest in `docs/decisions/` zero-padded to 3 digits (`adr-020-...`, `adr-021-...`). + +If the grill produced a major refactor decision rather than a new feature, lead the user to an ADR; if it produced a feature plan, lead to a PRD via `to-prd`. + + diff --git a/.claude/skills/grill-with-docs/glossary-format.md b/.claude/skills/grill-with-docs/glossary-format.md new file mode 100644 index 0000000..aa682ec --- /dev/null +++ b/.claude/skills/grill-with-docs/glossary-format.md @@ -0,0 +1,62 @@ +# docs/glossary.md Format + +## Structure + +```md +# Glossary + +Domain vocabulary for `template-vertical`. Terms specific to this repo — clean architecture, vertical features, agent workflow, conformance. General programming concepts don't belong here; implementation details belong in code or ADRs. + +## Architecture + +**Feature**: +A vertical slice owning its Clean Architecture layers (entities → application → infrastructure → DI → integrations). +_Avoid_: module, domain, app. + +**Use case**: +A single business action exposed by a feature, implemented as a factory `(deps) => async (input) => output`. Each one has a manifest entry, a Zod input/output schema pair, a colocated test, and a controller. +_Avoid_: command, action, handler. + +**Manifest**: +The `feature.manifest.ts` file that declares a feature's use cases, audits, publishes, consumes, and required core packages. Source of truth for conformance gates. + +**Conformance**: +The 5-gate enforcement system (TS brands → ESLint → boot assertion → `pnpm conformance` → fallow) that keeps manifest and code aligned. + +## Workflow + +**PRD**: +The top-level requirements doc at `docs/work/prds/-.prd.md` that seeds an epic. + +**Epic**: +A large body of work containing stories. Folder at `docs/work//_epic.md`. + +**Story**: +One use case or technical capability. Folder under the epic, file `_story.md`. + +**Task**: +One vertical slice = one PR = one commit. File `.task.md` under the story folder. + +## 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** +- A **Use case** is declared in a **Manifest** before it has code +- **Conformance** asserts that the **Manifest** and the code agree + +## Flagged ambiguities + +- (none yet — append here when conflicts are resolved during grilling) +``` + +## Rules + +- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others as aliases to avoid. +- **Flag conflicts explicitly.** When grilling surfaces ambiguity, capture both meanings under "Flagged ambiguities" with the resolution. +- **Keep definitions tight.** One sentence max. Define what it IS, not what it does. +- **Show relationships.** Use bold term names; express cardinality where obvious. +- **Only domain terms specific to this repo.** General programming concepts (timeouts, retries, errors, DI) don't belong even if used heavily. Before adding, ask: is this concept unique to template-vertical, or generic? +- **Group under subheadings** when natural clusters emerge (Architecture, Workflow, Instrumentation, etc.). + +This repo is **single-context**: one `docs/glossary.md`, no `CONTEXT-MAP.md`. Don't switch to multi-context layout unless the repo splits. diff --git a/.claude/skills/handoff/SKILL.md b/.claude/skills/handoff/SKILL.md new file mode 100644 index 0000000..45ca92c --- /dev/null +++ b/.claude/skills/handoff/SKILL.md @@ -0,0 +1,36 @@ +--- +name: handoff +description: Compact the current conversation into a handoff document for another agent to pick up. Use when the user wants to transition work to a fresh session, switch worktrees, or hand off to a subagent. +argument-hint: "What will the next session be used for?" +--- + +Write a handoff document summarising the current conversation so a fresh agent can continue the work. Save it to a path produced by `mktemp -t handoff-XXXXXX.md` (read the file before you write to it). + +Suggest the skills the next session should use, if any. In this repo, the common follow-ups are: + +- `grill-with-docs` — stress-test the plan before coding +- `to-prd` — materialize the plan into `docs/work/prds/-.prd.md` +- `superpowers:writing-plans` — author the implementation plan +- `superpowers:subagent-driven-development` — dispatch implementer + reviewer subagents per task + +## Don't duplicate + +Reference these artifacts by path or URL rather than inlining their content: + +- PRDs (`docs/work/prds/*.prd.md`), epics (`docs/work//_epic.md`), stories (`_story.md`), tasks (`*.task.md`) +- ADRs (`docs/decisions/adr-NNN-*.md`) +- AGENTS.md and CLAUDE.md (the next agent loads these automatically) +- `_state.json` (orchestrator-derived; the next agent regenerates it from markdown via `pnpm work rebuild-state`) +- Commit messages, diffs, PR descriptions — link the SHA / PR number +- Existing plans under `docs/superpowers/plans/` + +## Do capture + +- The active **goal** in one sentence +- **In-flight branch / worktree** and any uncommitted state (e.g. `git status` summary, dangling commits) +- **Decisions made in conversation** that haven't yet landed in a PRD or ADR +- **Blockers** and proposed next steps +- **Skills to invoke first** in the next session +- If the user passed arguments, treat them as the next session's focus and tailor the doc accordingly + +Keep the document short — it's a baton, not a thesis. diff --git a/.claude/skills/to-prd/SKILL.md b/.claude/skills/to-prd/SKILL.md new file mode 100644 index 0000000..2af52c7 --- /dev/null +++ b/.claude/skills/to-prd/SKILL.md @@ -0,0 +1,108 @@ +--- +name: to-prd +description: Turn the current conversation context into a PRD and write it to docs/work/prds/. Use when the user wants to materialize the discussion into a draft PRD that feeds the pnpm work pipeline. +--- + +This skill takes the current conversation context and codebase understanding and produces a PRD. Do NOT interview the user — just synthesize what you already know. If you need to interview first, invoke `grill-with-docs` instead. + +The PRD lives on the filesystem (this repo does not use an issue tracker for work). The downstream pipeline is `pnpm work decompose` → epic + stories → tasks → sandcastle dispatch (see `docs/architecture/agent-first-workflow-and-conformance.md`). + +## Process + +1. **Explore the repo if you haven't already.** Use the project's domain vocabulary throughout (check `docs/glossary.md` if it exists, otherwise lift terms from `docs/architecture/vertical-feature-spec.md` §6 and the feature packages' `feature.manifest.ts`). Respect any ADRs in the area you're touching — they're at `docs/decisions/adr-NNN-.md`. Use `pnpm work status` to see in-flight epics. + +2. **Sketch the major modules / packages.** Identify which existing packages (`packages//`, `packages/core-*/`) you'll modify and which new ones — if any — you'll create. Actively look for **deep modules**: small interface, deep implementation, rarely-changing surface. The vertical-feature-package shape (entities → application → infrastructure → DI) is the default unit; resist scaffolding new core packages unless required. + + Check with the user that this module sketch matches their expectations. Confirm which modules they want tests written for. (The conformance system already mandates tests for every use case + controller; this question is about extra coverage — repository contract suites, integration tests, etc.) + +3. **Pick a slug + date** for the PRD filename: `docs/work/prds/-.prd.md`. Use today's date. + +4. **Write the PRD using the template below**, then save it. Status starts at `draft`. The decomposer (`pnpm work decompose`) refuses to run on `draft` PRDs — the human flips it to `approved` after review. + + + +```markdown +--- +id: - +title: +type: prd +status: draft +author: +elicitation-session: +created: +--- + +## Problem + +What's broken or missing today? Who hurts because of it? Frame it from the user's perspective (where "user" may be a developer using the template, an end-user of an app built on it, or an AI agent operating in the codebase). + +## Goal + +What state are we trying to reach? One or two sentences. + +## In scope + +- Bullets of what this PRD covers. + +## Out of scope + +- Bullets of what's explicitly excluded. The explicit no-s are as valuable as the yes-s. + +## Constraints + +- Non-negotiables: existing ADRs to respect, conformance rules, performance budgets, compliance requirements, etc. +- Reference ADRs by ID: `ADR-014`, `ADR-017`, etc. + +## Success criteria + +- Verifiable outcomes. "Feature X passes `pnpm typecheck && pnpm test && pnpm conformance` green" is concrete; "feature X is great" is not. + +## User stories + +A numbered list. Cover all aspects of the feature, including edge cases. + +1. As a ``, I want ``, so that ``. +2. ... + +## Implementation decisions + +Decisions captured here so the decomposer (and downstream agents) don't re-litigate them. Include: + +- Modules to be built / modified (by package or feature name — no file paths; those rot fast) +- Interface shapes (Zod schemas, TypeScript types, tRPC procedures) — describe in prose; inline only if a snippet encodes the decision more precisely than prose (e.g., a Zod schema, a discriminated union, a state machine) +- Architectural choices (DI factory shape, withSpan/withCapture wrapping, manifest entries, anchor placements) +- Schema changes (Payload collections, database migrations) +- Cross-feature interactions (event publish/consume pairs, realtime channels, audit emissions) +- Optional-core requirements (does this feature require `core-events`? `core-realtime`? `core-audit`?) + +Do NOT include specific file paths or full code snippets — they go stale quickly. Prefer prose plus inline contracts (schemas, types) where they tighten the decision. + +## Testing decisions + +- What "good test" means for this feature (behavior through public interfaces, not implementation details) +- Which modules get repository contract suites (any new `IXRepository`) +- Which modules get use-case unit tests (every use case — that's a conformance rule) +- Integration / e2e coverage: which apps, which Playwright specs +- Prior art in the codebase: pointers to similar test patterns to mirror + +## Open questions + +- Q1: `` — `` +- Q2: ... + +## Out of scope (deferred) + +Things that are tempting to include but should be a separate PRD. + +## Further notes + +Anything else: stakeholders, related PRDs (`Builds on `, `Supersedes `), external references. +``` + + + +## After writing + +- Verify the file lives at `docs/work/prds/-.prd.md`. +- Tell the user the path and remind them to review and flip `status: draft → approved` before running `pnpm work decompose`. +- If new domain terms were introduced or sharpened during synthesis, append them to `docs/glossary.md` (lazy-create if missing) — same rules as `grill-with-docs`. diff --git a/AGENTS.md b/AGENTS.md index 61cec71..d292fe4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,6 +2,8 @@ This is a **Turborepo + pnpm monorepo** organized by vertical features. Each feature package owns its own Clean Architecture layers (entities, application, infrastructure, interface-adapters) and integrations (CMS collections, tRPC routers, UI components). Core packages provide foundation: primitives, design system, CMS composition, API aggregation, and tRPC client platform. +> **Vocabulary:** Every cross-cutting term used in this repo (feature, use case, manifest, slice, conformance, dispatch, etc.) is defined in [`docs/glossary.md`](./docs/glossary.md). When in doubt about what a term means **here**, check the glossary first — it's the single source for shared vocabulary between humans and agents. + ## Agent-driven development This template assumes agents (Claude, Codex, etc.) will author most feature work. The orchestration substrate is [Sandcastle](https://github.com/mattpocock/sandcastle) — see [ADR-019](./docs/decisions/adr-019-sandcastle-for-agent-orchestration.md). Day-to-day entry points: diff --git a/CLAUDE.md b/CLAUDE.md index 0c83d56..eb1fa49 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,11 +44,12 @@ Turborepo + pnpm monorepo organized by vertical features. Each feature (`auth`, ## Read First +- `docs/glossary.md` — **Canonical vocabulary** for the monorepo. Resolves "what does X mean here?" for every cross-cutting term (feature, use case, manifest, conformance, slice, dispatch, etc.). Shared between humans and agents. - `AGENTS.md` — Package map, boundary rules, per-package conventions - `docs/architecture/overview.md` — High-level architecture and package responsibilities - `docs/architecture/vertical-feature-spec.md` — Design spec with rationale and decision log - `docs/guides/scaffolding-a-feature.md` — `turbo gen feature` reference (fast path; prefer this over the manual walkthrough) -- `docs/guides/adding-a-feature.md` — End-to-end new feature walkthrough (manual path; for cases the generator's Phase-1 scope doesn't cover) +- `docs/guides/adding-a-feature.md` — End-to-end new feature walkthrough (manual path; for cases the generator's scope doesn't cover) - `docs/guides/events-and-jobs.md` — publish/consume/schedule cookbook (cross-feature events + background jobs; _requires `gen core-package events`_) - `docs/guides/realtime.md` — Socket.IO channels, broadcasts, handlers (_requires `gen core-package realtime`_) - `docs/guides/audit-and-compliance.md` — DPA-compliant audit logging cookbook (_requires `gen core-package audit`_) diff --git a/docs/glossary.md b/docs/glossary.md new file mode 100644 index 0000000..784dcaf --- /dev/null +++ b/docs/glossary.md @@ -0,0 +1,253 @@ +# 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//`. 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 ` — `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//api` or `@repo//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//src/entities/`): +Domain models (`models/.ts`) and domain errors (`errors/.ts` + `errors/common.ts`). No I/O. + +**Application layer** (`packages//src/application/`): +**Use cases**. Pure orchestration over repository + service ports. + +**Infrastructure layer** (`packages//src/infrastructure/`): +**Repository** and **service** implementations (real Payload-backed + mock). + +**Interface-adapters layer** (`packages//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//src/integrations/`): +Vendor-specific glue — `integrations/api/` (tRPC routers), `integrations/cms/` (Payload collections + tasks). + +**DI folder** (`packages//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`. +_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/.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//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()` 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 `// ` comment marking where a generator injects code (e.g. ``, ``, ``). 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`, ~30–60s) — 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. + +## 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//src/events/.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//src/events/handlers/on--.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//src/realtime/.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:` | `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//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/-.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//` with `_epic.md`. Decomposed from a PRD. + +**Story**: +One use case or one technical capability, one folder under `//` with `_story.md`. Type metadata: `user-story` or `technical-story`. + +**Task**: +One vertical slice = one PR = one commit. File `.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 ` 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. + +## 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(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. + +## 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-.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`