learning_ai_notes/.github/workflows/ci.yml
saravanakumardb1 78433b0e45 feat(ci): one-way UI drift ratchet to prevent regressions
UI8 deferred deleting the legacy global classes (.surface-card,
.surface-muted, .input-shell, .badge) because 69+ call sites in UI6/UI7
territory (dashboard, search, workspaces, notes detail, chat, palace)
still depend on them. Removing the globals before those screens migrate
would visually break the app.

Instead, ship a one-way ratchet that solves the actually-important
problem: prevent NEW legacy usage from creeping in while existing
sites get migrated.

- scripts/ui-drift-ratchet.sh — reads scripts/ui-drift-baseline.json
  and FAILS if any of the four UI drift categories regress above the
  tracked baseline. Pure bash, no jq required, works with grep or
  ripgrep. Uses the same patterns as scripts/ui-drift-audit.sh.
- scripts/ui-drift-baseline.json — checked-in baseline captured today:
  raw controls 38, legacy classes 92, hardcoded colors 0, direct imports 0.
- package.json — adds pnpm run audit:ui:ratchet and
  audit:ui:ratchet:update scripts.
- .github/workflows/ci.yml release-guards job — runs the ratchet as a
  required step plus the existing audit in report mode.
- docs/UI_UX_PLATFORM_CORE_ROADMAP.md — marks the CI-guard checklist
  item complete, documents the path to fully strict mode (drive
  baseline to zero, then delete globals.css legacy classes, then flip
  audit:ui:strict from advisory to required).

Verified:
- Ratchet at baseline: exits 0
- Synthetic regression (added a file with surface-card + raw <input>):
  ratchet correctly exits 1, reporting +1 in each affected category
- pnpm run verify: backend 380/380, web 96/96, mobile 97/97 (no
  behavior change)
2026-05-23 00:13:50 -07:00

305 lines
8.9 KiB
YAML

name: CI — NoteLett
on:
push:
branches: [main]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
release-guards:
name: Release guards — secrets + token/color drift
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat guard scripts
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- name: Install audit tools
run: sudo apt-get update && sudo apt-get install -y ripgrep
- name: Run release guard audit
run: COMMON_PLAT="$GITHUB_WORKSPACE/learning_ai_common_plat" bash scripts/release-guard-audit.sh
- name: Run UI drift ratchet (one-way gate vs scripts/ui-drift-baseline.json)
run: bash scripts/ui-drift-ratchet.sh
- name: Run UI drift audit (report mode, informational)
run: bash scripts/ui-drift-audit.sh || true
backend:
name: Backend — typecheck + test + build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat (for @bytelyst/* packages)
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable pnpm
run: corepack enable
- name: Build @bytelyst/* packages
working-directory: learning_ai_common_plat
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Install workspace dependencies
run: pnpm install --frozen-lockfile
- name: Backend lint
run: pnpm --filter @notelett/backend run lint
- name: Backend typecheck
run: pnpm --filter @notelett/backend run typecheck
- name: Backend tests
run: pnpm --filter @notelett/backend run test
env:
DB_PROVIDER: memory
JWT_SECRET: ci-test-secret-at-least-32-characters-long
- name: Backend build
run: pnpm --filter @notelett/backend run build
web:
name: Web — typecheck + test + build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat (for @bytelyst/* packages)
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable pnpm
run: corepack enable
- name: Build @bytelyst/* packages
working-directory: learning_ai_common_plat
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Install workspace dependencies
run: pnpm install --frozen-lockfile
- name: Web lint
run: pnpm --filter @notelett/web run lint
- name: Web typecheck
run: pnpm --filter @notelett/web run typecheck
- name: Web tests
run: pnpm --filter @notelett/web run test
- name: Web build
run: pnpm --filter @notelett/web run build
web-e2e:
name: Web E2E — Playwright
runs-on: ubuntu-latest
needs: web
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat (for @bytelyst/* packages)
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable pnpm
run: corepack enable
- name: Build @bytelyst/* packages
working-directory: learning_ai_common_plat
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Install workspace dependencies
run: pnpm install --frozen-lockfile
- name: Cache Playwright browsers
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-playwright-
- name: Install Playwright Chromium
run: pnpm --filter @notelett/web exec playwright install --with-deps chromium
- name: Web Playwright E2E
run: pnpm --filter @notelett/web run test:e2e -- --reporter=list
- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: web-playwright-report
path: |
web/playwright-report
web/test-results
if-no-files-found: ignore
docker-build:
name: Docker — backend + web images
runs-on: ubuntu-latest
needs: [backend, web]
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat (for @bytelyst/* packages)
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable pnpm
run: corepack enable
- name: Install common-platform dependencies
working-directory: learning_ai_common_plat
run: pnpm install --frozen-lockfile
- name: Prepare Docker tarball dependencies
run: COMMON_PLAT="$GITHUB_WORKSPACE/learning_ai_common_plat" bash scripts/docker-prep.sh
- name: Build backend image
env:
GITEA_NPM_TOKEN: ${{ secrets.GITEA_NPM_TOKEN }}
run: |
printf '%s' "${GITEA_NPM_TOKEN:-}" > /tmp/gitea_npm_token
DOCKER_BUILDKIT=1 docker build \
--secret id=gitea_npm_token,src=/tmp/gitea_npm_token \
-f backend/Dockerfile \
-t notelett-backend:ci \
.
- name: Build web image
env:
GITEA_NPM_TOKEN: ${{ secrets.GITEA_NPM_TOKEN }}
run: |
printf '%s' "${GITEA_NPM_TOKEN:-}" > /tmp/gitea_npm_token
DOCKER_BUILDKIT=1 docker build \
--secret id=gitea_npm_token,src=/tmp/gitea_npm_token \
--build-arg NEXT_PUBLIC_NOTES_API_URL=http://localhost:4016/api \
--build-arg NEXT_PUBLIC_PLATFORM_SERVICE_URL=http://localhost:4003/api \
-f web/Dockerfile \
-t notelett-web:ci \
.
- name: Restore Docker prep changes
if: always()
run: bash scripts/docker-prep.sh --restore
mobile:
name: Mobile — lint + typecheck + test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout common-plat (for @bytelyst/* packages)
uses: actions/checkout@v4
with:
repository: saravanakumardb1/learning_ai_common_plat
path: learning_ai_common_plat
token: ${{ secrets.GH_PAT }}
- name: Link common-platform workspace path
run: |
ln -sfn "$GITHUB_WORKSPACE/learning_ai_common_plat" ../learning_ai_common_plat
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
cache-dependency-path: pnpm-lock.yaml
- name: Enable pnpm
run: corepack enable
- name: Build @bytelyst/* packages
working-directory: learning_ai_common_plat
run: |
pnpm install --frozen-lockfile
pnpm build
- name: Install workspace dependencies
run: pnpm install --frozen-lockfile
- name: Mobile lint
run: pnpm --filter @notelett/mobile run lint
- name: Mobile typecheck
run: pnpm --filter @notelett/mobile run typecheck
- name: Mobile tests
run: pnpm --filter @notelett/mobile run test