ADR-011: Unified Repository Quality Gates
Status
Accepted
Date
2026-08-14
Context
The repository originally exposed common root commands for:
build
lint
check-types
but testing and Storybook validation were invoked through UI-specific commands:
test-storybook
build-storybook
As a result, local hooks and GitHub Actions needed to know implementation
details of the @repo/ui package.
The repository also needs a clear distinction between:
- repository-owned operations
- workspace-owned tasks
- shared configuration and policy
- implementation-specific tasks
The goal is not to remove every repeated script string.
The goal is to provide a stable repository contract while keeping task ownership and dependency-graph semantics correct.
Decision
Adopt a unified repository quality contract.
The primary developer-facing commands are:
pnpm dev
pnpm build
pnpm test
pnpm lint
pnpm lint:fix
pnpm check-types
pnpm format
pnpm format:check
pnpm verify
Workspace-owned tasks
Tasks whose implementation belongs to an application or package remain defined inside that workspace.
The common workspace task vocabulary is:
dev
build
test
lint
lint:fix
check-types
A workspace defines only the tasks it actually implements.
For example, the repository currently has UI browser tests but does not add
placeholder test scripts to workspaces that do not yet contain tests.
Turborepo discovers and orchestrates participating workspace tasks.
Build contract
The public repository build command is:
pnpm build
It delegates to:
turbo run build build-storybook
The current internal task implementations are:
web#build
→ Next.js production build
docs#build
→ Docusaurus production build
@repo/ui#build-storybook
→ Storybook static production build
Storybook intentionally retains the internal task name:
build-storybook
rather than masquerading as @repo/ui#build.
The UI package currently exports source modules directly and does not produce a library build artifact required by downstream workspace builds.
Keeping Storybook separate preserves the meaning of the normal Turborepo
build dependency graph while the root pnpm build still provides one
developer-facing command for all repository build artifacts.
The corresponding cached output is:
storybook-static/**
Test contract
The public repository test command is:
pnpm test
It delegates to:
turbo run test
Every workspace that defines a real test task automatically participates.
The UI implementation currently runs:
Vitest
+
Storybook test integration
+
Playwright
+
Chromium
No Storybook-specific test alias is exposed as part of the repository contract.
If Web, Docs, or future workspaces add tests, the root pnpm test command does
not need to change.
Test caching
The current Turbo test task uses:
cache: false
Browser tests are currently fast enough that the repository prefers executing them for every quality-gate invocation rather than accepting a cached result.
This decision can be reevaluated when remote caching or a substantially larger test suite is introduced.
Linting and type checking
Lint and type-check execution remain workspace-owned:
web
docs
ui
while their reusable policy is shared.
The distinction is:
ESLint policy
→ shared ESLint configuration
ESLint execution
→ workspace lint task
TypeScript policy
→ shared TypeScript configuration
TypeScript execution
→ workspace check-types task
Repeated workspace script names are therefore part of the task contract rather than unwanted duplication.
Formatting
Formatting remains repository-owned.
The root formatter covers repository-wide files that do not belong to one workspace, including configuration, automation, and root metadata.
The current formatting contract is:
Prettier
→ regular repository files
Remark
→ Docusaurus MDX content
Docusaurus MDX is excluded from Prettier and delegated to the Docs workspace because Remark owns that content.
Formatting is therefore not converted into duplicated workspace-level
format tasks merely for symmetry with other Turbo tasks.
If the repository later adopts genuinely different formatters for different workspace technologies, this decision can be revisited.
Full local verification
The repository exposes:
pnpm verify
as a developer-facing complete validation command.
It composes the public quality commands:
format:check
lint
check-types
test
build
This provides one predictable local verification entry point without exposing the implementation details of Storybook, Next.js, Docusaurus, Vitest, or Playwright.
Lefthook
Pre-commit retains targeted validation where it improves local feedback.
For example, UI browser tests run conditionally when matching UI files are staged.
Pre-push uses the repository quality contract:
format:check
lint
check-types
test
build
Independent pre-push jobs remain parallelized by Lefthook instead of replacing
the hook with the sequential pnpm verify convenience command.
GitHub Actions
GitHub Actions also consumes the repository-owned commands rather than duplicating implementation details.
Fast CI runs:
format:check
lint
check-types
build
Chromium installation
test
The native Full CI matrix runs:
format:check
lint
check-types
build
Because the public build contract includes the Storybook production artifact,
Storybook production builds are validated through pnpm build.
The dedicated browser job installs Chromium and runs:
pnpm test
Browser installation remains environment-specific infrastructure rather than a repository script concern.
Consequences
Positive
- developers have a small and predictable repository command surface
- adding tests to future workspaces does not require changing the root test command
- build artifacts are available through one root command
- Storybook keeps correct internal task semantics
- Lefthook and GitHub Actions depend on repository contracts instead of UI-specific aliases
- shared tooling policy is separated from workspace execution
- formatting continues to cover root and automation files correctly
- the architecture can grow without introducing placeholder scripts
Negative
- the root build command internally aggregates two Turbo task names
- Storybook production builds execute as part of the repository build contract
- browser tests intentionally bypass Turbo task caching
- formatting is not symmetrical with workspace-owned Turbo tasks
These tradeoffs are intentional and reflect task ownership rather than visual uniformity.
Alternatives considered
Make @repo/ui#build run Storybook
Rejected.
Storybook is not currently the library build artifact consumed by dependent workspaces.
Using build for Storybook would blur the meaning of the normal Turbo build
dependency graph.
Keep separate public Storybook commands
Rejected.
Commands such as:
test-storybook
build-storybook
forced Lefthook, CI, and developers to know implementation details that should remain inside the UI workspace.
The internal build-storybook task remains because it represents a real
specialized build operation.
Add format scripts to every workspace
Rejected.
Prettier currently operates across the repository, including root files and automation configuration.
Duplicating the same formatting command across workspaces would not improve task ownership.
Add placeholder test scripts to every workspace
Rejected.
A workspace should expose a task only when it has an implementation worth executing.
Relationship to earlier ADRs
ADR-001 remains authoritative for the use of Turborepo.
ADR-006 remains authoritative for the use of Storybook.
ADR-007 remains authoritative for Remark ownership of Docusaurus MDX.
ADR-009 remains authoritative for the GitHub Actions provider, security model, platform matrix, and original CI architecture.
ADR-010 remains authoritative for Fast CI versus Full CI selection and trigger policy.
This ADR supersedes earlier documentation only for the repository quality command contract and the way local and remote validation invoke those commands.
Follow-up work
- configure branch protection around the stable
CI Gate - add Web and Docs tests when their behavior requires dedicated test suites
- reevaluate test caching when Turborepo remote caching is introduced
- add dedicated Linux musl validation
- continue dependency and security remediation