diff --git a/docs/gates.md b/docs/gates.md index fc88f61e..75537e98 100644 --- a/docs/gates.md +++ b/docs/gates.md @@ -112,6 +112,7 @@ project checks needs a row. | coverage | not in the gate; no threshold | Owner decision E32 D4: never enforced; "every regression test seen red" is the bar, and a percentage invites tests written to move it. Out of the lanes since E35: read once, by hand, it found 5 bugs; as a lane it was a number nobody acted on, and the slowest vitest run (the one that flaked). On demand: docs/development.md. | frontend 80% / backend 78% of lines (E32 S1) | | CVE gate | HIGH/CRITICAL with a fix available only | `--ignore-unfixed` + `--severity HIGH,CRITICAL`: a finding with no fix cannot be acted on by an upgrade; it shows in the scan output. A fixable one fails the publish, and the only way past it is `.trivyignore.yaml`. | 0 open (E32 S1) | | npm audit | `--omit=dev --audit-level=high` | What ships to the browser, at high or above. The dev toolchain's advisories were burned down by hand in E32 S1 (18 → 0). | 0 | +| knip | `entry` — one file added | Not a narrowing: knip's Vite plugin reads entries from index.html only, so the shared link's page (`watch.html` → `src/watchMain.tsx`) is named here, or the lane reports that whole entry unused. It adds files to the lane, never takes any out. | 1 entry | | React Compiler | the functions it skips, pinned | `components/compilerCoverage.contract.test.ts` — the list may only shrink. End state: only VirtualGrid (TanStack Virtual, an IncompatibleLibrary) remains. | 93 (E32 S1) → 29 (E32 S3) → 1, VirtualGrid (E32 S4) | ## Accepted findings diff --git a/frontend/knip.jsonc b/frontend/knip.jsonc index e5bb1921..11a391cb 100644 --- a/frontend/knip.jsonc +++ b/frontend/knip.jsonc @@ -1,5 +1,7 @@ { "$schema": "https://unpkg.com/knip@6/schema.json", + // The shared link's page (watch.html): the Vite plugin reads only index.html for entries. + "entry": ["src/watchMain.tsx"], "project": ["**/*.{ts,tsx,js}"], "playwright": { "config": ["playwright.config.ts"], diff --git a/frontend/src/components/ErrorBoundary.tsx b/frontend/src/components/ErrorBoundary.tsx index 727e808d..ede7e369 100644 --- a/frontend/src/components/ErrorBoundary.tsx +++ b/frontend/src/components/ErrorBoundary.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from "react"; import i18n from "../i18n"; import { notify } from "../lib/notifications"; -import { CrashBoundary, type CrashCopy } from "./CrashBoundary"; +import { CrashBoundary, type CrashCopy } from "./ui/CrashBoundary"; const copy = (): CrashCopy => ({ title: i18n.t("errors.boundary.title"), diff --git a/frontend/src/components/listNav.wiring.contract.test.ts b/frontend/src/components/listNav.wiring.contract.test.ts index f4c002c1..c34899a0 100644 --- a/frontend/src/components/listNav.wiring.contract.test.ts +++ b/frontend/src/components/listNav.wiring.contract.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it } from "vitest"; +import { readSources } from "../lib/rawSources.testkit"; // Every rail and every card of a card list is walkable by the keyboard (lib/listNav). Two // opt-in halves, both checked here, because either one missing silently leaves the keyboard out — @@ -79,7 +80,7 @@ export function inList(code: string, pos: number): boolean { const has = (tag: Tag, prop: string) => new RegExp(`\\s${prop}\\b`).test(tag.text); function offenders(): { hits: string[]; tags: number; exempted: Set } { - const files = import.meta.glob("./**/*.tsx", { query: "?raw", import: "default", eager: true }); + const files = readSources(__dirname, "./**/*.tsx"); const hits: string[] = []; const exempted = new Set(); let tags = 0; diff --git a/frontend/src/components/ui/CrashBoundary.tsx b/frontend/src/components/ui/CrashBoundary.tsx index f1958794..5576ea82 100644 --- a/frontend/src/components/ui/CrashBoundary.tsx +++ b/frontend/src/components/ui/CrashBoundary.tsx @@ -1,7 +1,7 @@ import { Component, type ErrorInfo, type ReactNode } from "react"; -import { errorAttrs, log } from "../lib/log"; -import { reloadingForNewBuild } from "../lib/staleBuild"; -import { Button } from "./ui/Button"; +import { errorAttrs, log } from "../../lib/log"; +import { reloadingForNewBuild } from "../../lib/staleBuild"; +import { Button } from "./Button"; export interface CrashCopy { title: string; diff --git a/frontend/src/components/ui/README.md b/frontend/src/components/ui/README.md index 533ba48f..417a6166 100644 --- a/frontend/src/components/ui/README.md +++ b/frontend/src/components/ui/README.md @@ -41,7 +41,7 @@ Counter-examples, deliberately NOT here: `PosterTile` (knows about Plex montage | actions & inputs | `Button`, `IconButton`, `Pressable` (`selectable` when its text is a title or a name), `Chip` + `chipStyles`, `DragHandle` + `OrderButtons` / `useOrderItems` (the non-drag reorder, WCAG 2.5.7) (one per button family, docs/DESIGN.md; a raw `