recipe-manager/.harness/docs/styling-governance.md

2.7 KiB

T06 — Styling Guardrails + Lightweight Governance

Date: 2026-03-27
Scope: recipe-manager/frontend

Why this exists

The styling stabilization pass established a token + primitive contract. This governance doc keeps that contract from drifting back into mixed styling modes.

Canonical styling contract (short version)

  1. Tokens are defined in one place: src/styles/tokens.css
  2. Build UI from shared primitives first: src/components/ui/primitives.tsx + ui-* classes from src/index.css
  3. Use tokenized values in classes/styles: var(--...) or Tailwind theme aliases mapped to tokens
  4. Do not add new raw Tailwind palette utilities (e.g. bg-blue-500, text-slate-600) in stabilized shared surfaces
  5. Do not hardcode hex colors in className (e.g. bg-[#1f2937]) for app UI

Reference docs:

  • ./styling-token-contract.md
  • ./ui-primitive-contract.md
  • ./t05-legacy-style-debt-cleanup.md

Lightweight automated guardrail

A scoped check is available:

cd frontend
npm run style:guardrails

Current guard scope (intentional, low-risk):

  • src/App.tsx
  • src/components/MissionControlPanel.tsx
  • src/components/ui/primitives.tsx

What it flags:

  • direct palette utility classes (bg-blue-*, text-slate-*, etc.)
  • hex colors in arbitrary utility classes (bg-[#...], text-[#...], etc.)

If violations are found in guarded files, the script exits non-zero.

Contributor checklist (copy into PR template/comments as needed)

  • New UI uses Ui* primitives or existing ui-* classes where possible
  • Any new visual token was added to tokens.css first
  • No new hardcoded palette utility classes in stabilized shell/shared primitive areas
  • No new hardcoded hex colors in class utilities for app surfaces
  • npm run style:guardrails passes
  • npm run lint passes

Review heuristics for agents/contributors

When touching frontend UI, quickly answer:

  1. "Can this use an existing Ui* primitive?"
  2. "If I need a new color/radius/shadow, did I add a semantic token first?"
  3. "Am I introducing a second styling path that future edits will copy?"

If the answer to (3) is yes, pause and refactor to the contract.

Intentional limitations (for now)

  • The guard script is scoped, not repo-wide, because existing pages still contain known legacy palette usage (tracked in T01/T04).
  • The check is intentionally simple regex-based (fast, no lint plugin churn).
  • This is not wired into heavy CI yet; it is run locally and can be added to future CI once high-drift pages are migrated.

Expansion path after T04/T07

As additional pages are stabilized, add them to frontend/scripts/style-guardrails.mjs scope to progressively tighten enforcement without breaking current workflows.