Skip to main content

ADR-0004: Expand CI and Deployment Quality Gates (Lint, Format, Typecheck, Docs Integrity)

Purpose

Record the decision to expand the Documentation App’s CI and deployment governance beyond “build-only” to include additional quality gates (linting, formatting, type checking, and documentation integrity checks), and to require those checks before production promotion.

This ADR is a portfolio-critical “enterprise signal”: it demonstrates disciplined SDLC controls, reproducibility, and release governance for a public documentation platform.

Scope

In scope

  • GitHub Actions checks required on PRs and main
  • Vercel Deployment Checks required for promotion to production
  • Minimum set of additional gates:
    • formatting (Prettier)
    • linting (ESLint)
    • TypeScript type checks
    • documentation integrity (Docusaurus build; broken links as hard failures)
    • optional: Markdown lint, spelling, secrets scanning (phased)

Out of scope

  • choosing a monorepo-wide “one tool to rule them all” (e.g., migrating to Biome) unless later justified by a separate ADR
  • detailed tool configuration contents (captured as implementation tasks and referenced from runbooks/docs)

Prereqs / Inputs

  • Decision owner(s): Portfolio maintainer
  • Date: 2026-01-07
  • Status: Proposed (accept on merge with implemented gates)
  • Related ADRs:
    • ADR-0001 (Docusaurus platform choice)
    • ADR-0002 (autogenerated navigation + _category_.json)
    • ADR-0003 (Vercel hosting + previews)
  • Related dossier:
    • docs/60-projects/documentation-app/testing.md
    • docs/60-projects/documentation-app/deployment.md
  • Current baseline assumptions:
    • pnpm is the package manager; lockfile is committed
    • build gate exists (pnpm build) and must fail on broken links
    • PR-only merges to main are required

Decision Record

Title

ADR-0004: Expand CI and Deployment Quality Gates (Lint, Format, Typecheck, Docs Integrity)

Context

The Documentation App is both:

  1. a production-like public system, and
  2. a core portfolio artifact that must demonstrate enterprise delivery discipline.

As content and configuration scale (more docs, more automation, more contributor/agent activity), “build-only” gating is necessary but insufficient:

  • Formatting drift increases review friction and reduces credibility.
  • Linting/type errors in Docusaurus config/theme code can break builds or cause subtle runtime issues.
  • Inconsistent Markdown practices and structural errors increase navigation entropy and broken references.
  • Vercel can create deployments even when GitHub checks are failing unless promotion is gated.

We need a coherent, enforceable quality gate set that:

  • prevents regressions early (PR time)
  • produces deterministic, reproducible builds
  • scales to AI-assisted authoring without sacrificing quality
  • gates production promotion on verified checks

Decision

Implement an expanded CI quality gate framework and require these checks before production promotion:

A) GitHub Actions (required on PR + main)

Minimum required jobs:

  1. Quality job (fast fail)

    • pnpm lint (ESLint)
    • pnpm format:check (Prettier check, no writes)
    • pnpm typecheck (TypeScript type checking)
    • Optional (phase 2): pnpm lint:md (Markdown lint)
  2. Build job (hard integrity gate)

    • pnpm build (must fail on broken links / structural issues)

B) Vercel Deployment Checks (required for production promotion)

Require the corresponding GitHub checks (at minimum):

  • ci / quality
  • ci / build

Production domains must not be assigned (“promoted”) until checks pass.

Alternatives considered

  1. Build-only gate (status quo)

    • Pros: minimal time, minimal setup
    • Cons: allows format drift, type/lint issues, inconsistent docs hygiene; more review burden; lower enterprise credibility
    • Rejected because: does not scale to enterprise documentation scope or AI-assisted contributions.
  2. Pre-commit hooks only (no CI enforcement)

    • Pros: faster developer feedback
    • Cons: unenforceable; contributors/agents can bypass; inconsistent in CI; weaker evidence posture
    • Rejected because: enterprise posture requires server-side enforcement.
  3. Single “mega job” in CI

    • Pros: simplest workflow
    • Cons: slow feedback; harder to parallelize; harder to reason about required checks in Vercel promotion
    • Rejected because: we want a clear split between “quality” (fast) and “build integrity” (hard gate).
  4. Adopt Biome (formatter + linter) instead of ESLint/Prettier

    • Pros: speed, consolidation
    • Cons: migration effort; ecosystem/tooling differences; potential mismatch with Docusaurus/React conventions already expected
    • Deferred: may be reconsidered later via a dedicated ADR if the repo grows significantly.

Consequences

Positive consequences

  • Stronger, more credible enterprise SDLC posture:
    • style consistency, reduced review overhead
    • type correctness in configuration/theme code
    • earlier detection of errors before they reach production
  • Improved safety for AI-assisted contributions:
    • deterministic gates reduce “silent drift”
  • Production governance strengthens:
    • Vercel promotion is gated on verified checks

Negative consequences / tradeoffs

  • CI runtime increases (more checks)
  • Tooling maintenance required:
    • eslint/prettier/typecheck configs must be kept current
  • Contributors must follow consistent local tooling setup (documented in contributor guides)

Security impact

  • Reduced risk of unsafe/unstable build changes merging
  • Provides a platform for adding additional security controls later (e.g., secret scanning gate, dependency auditing gate)

Operational impact

  • Runbooks must reflect new failure modes:
    • “quality job failing” becomes a deploy blocker
  • Triage paths must distinguish:
    • formatting/lint failures vs build/link failures

Implementation notes (high-level)

1) Add canonical scripts in package.json

Required scripts (names are part of the “contract”):

  • lint → ESLint
  • format:check → Prettier check (no writes)
  • format:write → Prettier write (local use)
  • typechecktsc --noEmit
  • build → Docusaurus build (already present)

Optional phase 2:

  • lint:md → Markdown lint (markdownlint-cli2 or equivalent)
  • lint:links → external link checker (later; avoid gating early due to flakiness)

2) Add minimal configuration files (if not already present)

  • ESLint config (flat or legacy—choose one and standardize)
  • Prettier config
  • TypeScript config suitable for tsc --noEmit (if Docusaurus TS config exists, reuse it)
  • Editor settings (optional) for consistent formatting in VS Code

3) Update GitHub Actions workflow

  • Add a quality job and keep build job.
  • Ensure both run on:
    • pull_request
    • push to main

4) Update Vercel Deployment Checks

  • Import the two checks as requirements for production promotion:
    • ci / quality
    • ci / build

5) Update documentation + runbooks (required for acceptance)

  • Dossier:
    • docs/60-projects/documentation-app/testing.md (describe gates + commands)
    • docs/60-projects/documentation-app/deployment.md (describe promotion gating)
  • Runbooks:
    • rbk-docs-deploy.md (checks required before promotion)
    • rbk-docs-rollback.md (roll back via revert; note checks behavior)
    • rbk-docs-broken-links-triage.md (build gate triage; add pointer for “quality job failing”)
  • Add a short “CI Gates Policy” note under docs/30-devops-platform/ci-cd/ (or equivalent) if that domain exists.

Validation / Expected outcomes

This decision is successful when:

  • On every PR:
    • ci / quality passes (lint + format:check + typecheck)
    • ci / build passes (Docusaurus build, broken links fail)
  • On main:
    • the same checks run and pass deterministically
  • On Vercel:
    • production promotion is blocked until required checks pass
  • Contributor experience:
    • local commands exist and are documented
    • failures are actionable and mapped to runbooks

Failure modes / Troubleshooting

  • Format check fails frequently:
    • ensure Prettier is configured and format:write exists; educate contributors; do not relax the gate.
  • Lint rules too noisy:
    • tune rules carefully and record major policy changes in a follow-up ADR if necessary.
  • Typecheck fails due to incomplete TS config:
    • refine tsconfig to match Docusaurus project layout; keep typecheck scoped to repo TS sources.
  • Vercel waits indefinitely for checks:
    • ensure workflows run on push to main (not PR-only) and that check names are stable.

References

  • Documentation App dossier:
    • docs/60-projects/documentation-app/testing.md
    • docs/60-projects/documentation-app/deployment.md
  • Ops runbooks:
    • docs/50-operations/runbooks/rbk-docs-deploy.md
    • docs/50-operations/runbooks/rbk-docs-rollback.md
    • docs/50-operations/runbooks/rbk-docs-broken-links-triage.md
  • Related ADRs:
    • docs/10-architecture/adr/adr-0001-adopt-docusaurus-for-portfolio-docs.md
    • docs/10-architecture/adr/adr-0002-navigation-governance-autogenerated-and-category-metadata.md
    • docs/10-architecture/adr/adr-0003-hosting-vercel-with-preview-deployments.md