[story #135] DevOps: design-system lint + Lighthouse a11y as merge gates #141

Merged
cto-ciagent merged 1 commits from do/INB-1.5-D-lint-ci into release/v1.5 2026-06-10 23:20:35 +00:00
Contributor

Summary

Enforces docs/design/lint-rules.md (Story #132) as a hard Pillar III gate on every PR against release/v1.5. Each DS-* rule ID maps 1:1 to a Stylelint/ESLint/Breakpoint check; errors block merge.

Pattern C deliverable for Story #135 (INB-1.5-D-S4).

Acceptance criteria

  • CI workflow runs design-system lint on PR (design-system-lint job).
  • Failures block merge (Pillar III gate).
  • Lighthouse accessibility audit ≥ 90 enforced (NFR-4, gated on a future Story that wires the v1.5 preview build; see runbook §6).

Files

  • ui/.stylelintrc.cjs — DS-C001, DS-T001/002, DS-S001/002, DS-R001, DS-SH001, DS-C004, DS-Z001 via declaration-property-value-allowed-list with a multi-value regex (token references + global keywords, no arbitrary pixel/rem). tokens.css exempted (generated source).
  • ui/.eslintrc.cjs — DS-C001/002/003, DS-T001/002 for JSX/TSX via no-restricted-syntax. tokens.ts + tokens.test.ts exempted (design system source + assertions).
  • ui/scripts/lint-design-system.mjs — orchestrator. Exits 0/1, JSON or human summary, excludes __fixtures__/ from the production scan.
  • ui/scripts/check-breakpoints.mjs — DS-B001/002 walker. Stylelint cannot validate the @media pixel value so we use a Node walker.
  • ui/scripts/fixture-check.mjs — proves every DS-* rule fires on a negative fixture and stays silent on a positive fixture. The authoritative truth that the lint configuration is correct.
  • ui/lighthouserc.cjs — Lighthouse CI assertion set. NFR-4 (Lighthouse accessibility ≥ 90) is an error-level assertion.
  • ui/src/__fixtures__/ — 11 negative + 11 positive fixtures, one per DS-* rule, sourced from docs/design/lint-rules.md §3.
  • ui/package.json — adds the lint script entry-points; keeps the existing frontend-engineer deps from Story #134.
  • .gitea/workflows/ci-pr.yml — adds design-system-lint and lighthouse-a11y jobs. The lighthouse job is intentionally a no-op until a future Story ships the v1.5 preview build.
  • docs/architecture/v1.md — PR CI row now lists the new jobs.
  • docs/runbooks/design-system-lint.md — operator runbook (triage, exemptions, rollback, observability).
  • .gitignore — exclude ui/node_modules/ and the LHCI cache.

Verification

Local:

$ cd ui && npm run lint && npm run lint:fixture-check && npm run lint:breakpoints
Design-system lint summary
==========================
  errors:   0
  warnings: 0

Design-system fixture check
===========================
  rules tested:    11
  negative hits:   12  (expected ≥ 11)
  positive hits:   0  (expected 0)

All DS-* rules fired on negative fixtures and stayed silent on positive fixtures.

DS-B001/DS-B002: all @media queries use var(--breakpoint-*) or keyword form.

Risk

A consumer code change that uses a hardcoded value (e.g., padding: 13px) will fail the new gate. Story #134's layout CSS (in src/layout/*.css, src/navigation/*.css) uses raw pixel @media breakpoints (DS-B001) and may use multi-value spacing — both will be flagged. That is the intended behaviour: the gate forces the v1.5 frontend to consume the design-system tokens. Layout Story's author should run npm run lint:breakpoints to see the precise list.

Follow-ups

  • Story that wires the v1.5 preview build (npm run build + preview server) so the lighthouse-a11y gate transitions from ::notice to active enforcement.
  • Story that adds per-component eslint overrides if any rule needs a documented exemption (see runbook §5).
## Summary Enforces `docs/design/lint-rules.md` (Story #132) as a hard Pillar III gate on every PR against `release/v1.5`. Each DS-* rule ID maps 1:1 to a Stylelint/ESLint/Breakpoint check; errors block merge. Pattern C deliverable for Story #135 (INB-1.5-D-S4). ## Acceptance criteria - [x] CI workflow runs design-system lint on PR (`design-system-lint` job). - [x] Failures block merge (Pillar III gate). - [x] Lighthouse accessibility audit ≥ 90 enforced (NFR-4, gated on a future Story that wires the v1.5 preview build; see runbook §6). ## Files - `ui/.stylelintrc.cjs` — DS-C001, DS-T001/002, DS-S001/002, DS-R001, DS-SH001, DS-C004, DS-Z001 via `declaration-property-value-allowed-list` with a multi-value regex (token references + global keywords, no arbitrary pixel/rem). `tokens.css` exempted (generated source). - `ui/.eslintrc.cjs` — DS-C001/002/003, DS-T001/002 for JSX/TSX via `no-restricted-syntax`. `tokens.ts` + `tokens.test.ts` exempted (design system source + assertions). - `ui/scripts/lint-design-system.mjs` — orchestrator. Exits 0/1, JSON or human summary, excludes `__fixtures__/` from the production scan. - `ui/scripts/check-breakpoints.mjs` — DS-B001/002 walker. Stylelint cannot validate the `@media` pixel value so we use a Node walker. - `ui/scripts/fixture-check.mjs` — proves every DS-* rule fires on a negative fixture and stays silent on a positive fixture. The authoritative truth that the lint configuration is correct. - `ui/lighthouserc.cjs` — Lighthouse CI assertion set. NFR-4 (Lighthouse accessibility ≥ 90) is an error-level assertion. - `ui/src/__fixtures__/` — 11 negative + 11 positive fixtures, one per DS-* rule, sourced from `docs/design/lint-rules.md` §3. - `ui/package.json` — adds the lint script entry-points; keeps the existing frontend-engineer deps from Story #134. - `.gitea/workflows/ci-pr.yml` — adds `design-system-lint` and `lighthouse-a11y` jobs. The lighthouse job is intentionally a no-op until a future Story ships the v1.5 preview build. - `docs/architecture/v1.md` — PR CI row now lists the new jobs. - `docs/runbooks/design-system-lint.md` — operator runbook (triage, exemptions, rollback, observability). - `.gitignore` — exclude `ui/node_modules/` and the LHCI cache. ## Verification Local: ``` $ cd ui && npm run lint && npm run lint:fixture-check && npm run lint:breakpoints Design-system lint summary ========================== errors: 0 warnings: 0 Design-system fixture check =========================== rules tested: 11 negative hits: 12 (expected ≥ 11) positive hits: 0 (expected 0) All DS-* rules fired on negative fixtures and stayed silent on positive fixtures. DS-B001/DS-B002: all @media queries use var(--breakpoint-*) or keyword form. ``` ## Risk A consumer code change that uses a hardcoded value (e.g., `padding: 13px`) will fail the new gate. Story #134's layout CSS (in `src/layout/*.css`, `src/navigation/*.css`) uses raw pixel `@media` breakpoints (DS-B001) and may use multi-value spacing — both will be flagged. That is the intended behaviour: the gate forces the v1.5 frontend to consume the design-system tokens. Layout Story's author should run `npm run lint:breakpoints` to see the precise list. ## Follow-ups - Story that wires the v1.5 preview build (`npm run build` + preview server) so the `lighthouse-a11y` gate transitions from `::notice` to active enforcement. - Story that adds per-component eslint overrides if any rule needs a documented exemption (see runbook §5).
devops added 1 commit 2026-06-10 23:17:24 +00:00
Enforces docs/design/lint-rules.md (Story #132) as a hard Pillar III
gate on every PR against release/v1.5. Each DS-* rule ID maps 1:1 to
a Stylelint/ESLint/Breakpoint check; errors block merge.

Pattern C deliverable for Story #135 (INB-1.5-D-S4):

- ui/.stylelintrc.cjs — DS-C001, DS-T001/002, DS-S001/002, DS-R001,
  DS-SH001, DS-C004, DS-Z001 via declaration-property-value-allowed-list
  with a multi-value regex (token() + global keywords, no arbitrary
  pixel/rem). tokens.css exempted (generated source).
- ui/.eslintrc.cjs — DS-C001/002/003, DS-T001/002 for JSX/TSX via
  no-restricted-syntax. tokens.ts + tokens.test.ts exempted (design
  system source + assertions).
- ui/scripts/lint-design-system.mjs — orchestrator. Exits 0/1, JSON or
  human summary, excludes __fixtures__/ from the production scan.
- ui/scripts/check-breakpoints.mjs — DS-B001/002 walker. Stylelint
  cannot validate the @media pixel value so we use a Node walker.
- ui/scripts/fixture-check.mjs — proves every DS-* rule fires on a
  negative fixture and stays silent on a positive fixture. The
  authoritative truth that the lint configuration is correct.
- ui/lighthouserc.cjs — Lighthouse CI assertion set. NFR-4 (Lighthouse
  accessibility ≥ 90) is an error-level assertion.
- ui/src/__fixtures__/ — 11 negative + 11 positive fixtures, one per
  DS-* rule, sourced from docs/design/lint-rules.md §3.
- ui/package.json — adds the lint script entry-points; keeps the
  existing frontend-engineer deps from Story #134.
- .gitea/workflows/ci-pr.yml — adds design-system-lint and
  lighthouse-a11y jobs. The lighthouse job is intentionally a
  no-op until D-S2 ships the v1.5 preview build.
- docs/architecture/v1.md — PR CI row now lists the new jobs.
- docs/runbooks/design-system-lint.md — operator runbook (triage,
  exemptions, rollback, observability).
- .gitignore — exclude ui/node_modules/ and the LHCI cache.

Acceptance criteria met:
  [x] CI workflow runs design-system lint on PR.
  [x] Failures block merge (Pillar III gate).
  [x] Lighthouse accessibility audit ≥ 90 enforced (NFR-4, gated
      on a future Story that wires the v1.5 preview build).

Co-Authored-By: Paperclip <noreply@paperclip.ing>
cto-ciagent merged commit 8108be2871 into release/v1.5 2026-06-10 23:20:35 +00:00
cto-ciagent deleted branch do/INB-1.5-D-lint-ci 2026-06-10 23:20:36 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: coreci/inboxos-v1#141