From aa5d2d8eb06c6c81eb53c8667e9c56ee7f9bad5d Mon Sep 17 00:00:00 2001 From: Jordan Simonovski Date: Thu, 16 Jul 2026 11:01:07 +1000 Subject: [PATCH 1/3] ci(lint): enforce ESLint warning ceilings instead of suppressing warnings --- packages/api/package.json | 2 +- packages/app/package.json | 2 +- packages/cli/package.json | 2 +- packages/common-utils/package.json | 2 +- packages/hdx-eval/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/api/package.json b/packages/api/package.json index 312a94c86e..e6ffdbb0a9 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -89,7 +89,7 @@ "dev-task": "DOTENV_CONFIG_PATH=.env.development nodemon --exec 'ts-node' --transpile-only -r tsconfig-paths/register -r dotenv-expand/config -r '@hyperdx/node-opentelemetry/build/src/tracing' ./src/tasks/index.ts", "build": "rimraf ./build && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && cp -r ./src/opamp/proto ./build/opamp/", "build:vercel": "rimraf ./build && tsc -p tsconfig.vercel.json && tsc-alias -p tsconfig.vercel.json && cp -r ./src/opamp/proto ./build/opamp/", - "lint": "npx eslint --quiet . --ext .ts", + "lint": "npx eslint . --ext .ts --max-warnings 357", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit && yarn lint:openapi", "ci:int": "DOTENV_CONFIG_PATH=.env.test DOTENV_CONFIG_OVERRIDE=true jest --runInBand --ci --forceExit", diff --git a/packages/app/package.json b/packages/app/package.json index e5b30daa15..ee8fd0c20c 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -14,7 +14,7 @@ "build:clickhouse": "NEXT_PUBLIC_THEME=clickstack NEXT_PUBLIC_IS_LOCAL_MODE=true NEXT_PUBLIC_CLICKHOUSE_BUILD=true next build --webpack && node scripts/prepare-clickhouse-build-export.js", "run:clickhouse": "test -d out && npx rimraf tmp && mkdir tmp && cp -r out tmp/clickstack && echo 'visit http://localhost:3000/clickstack to start' && npx serve tmp -l 3000 || echo 'run build:clickhouse first'", "start": "next start", - "lint": "npx eslint --quiet . --ext .ts,.tsx", + "lint": "npx eslint . --ext .ts,.tsx --max-warnings 740", "lint:fix": "npx eslint . --ext .ts,.tsx --fix", "lint:styles": "stylelint **/*/*.{css,scss}", "ci:lint": "yarn lint && yarn tsc --noEmit && yarn lint:styles --quiet", diff --git a/packages/cli/package.json b/packages/cli/package.json index d62b2583df..22ef191f37 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,7 +33,7 @@ "compile:linux": "bun build src/cli.tsx --compile --target=bun-linux-x64 --outfile dist/hdx-linux-x64", "compile:macos": "bun build src/cli.tsx --compile --target=bun-darwin-arm64 --outfile dist/hdx-darwin-arm64", "compile:macos-x64": "bun build src/cli.tsx --compile --target=bun-darwin-x64 --outfile dist/hdx-darwin-x64", - "lint": "npx eslint --quiet . --ext .ts,.tsx", + "lint": "npx eslint . --ext .ts,.tsx --max-warnings 9", "ci:lint": "yarn lint && yarn tsc --noEmit", "ci:unit": "NODE_OPTIONS=--experimental-vm-modules jest --runInBand --ci --passWithNoTests", "dev:unit": "NODE_OPTIONS=--experimental-vm-modules jest --watchAll --runInBand" diff --git a/packages/common-utils/package.json b/packages/common-utils/package.json index 92d7006597..489159e77c 100644 --- a/packages/common-utils/package.json +++ b/packages/common-utils/package.json @@ -43,7 +43,7 @@ "dev:build": "tsup && tsc --emitDeclarationOnly --declaration", "build": "tsup", "ci:build": "tsup", - "lint": "npx eslint --quiet . --ext .ts", + "lint": "npx eslint . --ext .ts --max-warnings 92", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit", "ci:unit": "jest --runInBand --ci --coverage", diff --git a/packages/hdx-eval/package.json b/packages/hdx-eval/package.json index 7550f4665e..e2d6dd6b0e 100644 --- a/packages/hdx-eval/package.json +++ b/packages/hdx-eval/package.json @@ -33,7 +33,7 @@ "scripts": { "build": "rimraf ./dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json", "dev": "NODE_OPTIONS=--max-old-space-size=8192 ./scripts/env.sh tsx src/cli.ts", - "lint": "npx eslint --quiet . --ext .ts", + "lint": "npx eslint . --ext .ts --max-warnings 3", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit", "ci:unit": "jest --ci --forceExit", From 6f251cc3fb012be18188e219b8e33e13e5734721 Mon Sep 17 00:00:00 2001 From: Jordan Simonovski Date: Thu, 16 Jul 2026 12:14:36 +1000 Subject: [PATCH 2/3] ci(test): enforce coverage floors at current levels Pin Jest coverageThreshold in the unit configs for app, common-utils and hdx-eval to just below each package's measured coverage (measured minus one, rounded down). Coverage can now only ratchet upwards: any decay below these floors fails the build, so the floors rise only when someone raises them deliberately. Also add --coverage to hdx-eval's ci:unit so its threshold is actually collected and enforced. Integration configs are left untouched. The API unit config is deferred to a follow-up until the API unit/int split (#2653) lands. --- packages/app/jest.config.js | 11 +++++++++++ packages/common-utils/jest.config.js | 11 +++++++++++ packages/hdx-eval/jest.config.js | 11 +++++++++++ packages/hdx-eval/package.json | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/packages/app/jest.config.js b/packages/app/jest.config.js index 8691792362..c018531c3b 100644 --- a/packages/app/jest.config.js +++ b/packages/app/jest.config.js @@ -25,4 +25,15 @@ module.exports = { '^ky$': '/src/__mocks__/ky-universal.ts', }, setupFilesAfterEnv: ['/src/setupTests.tsx'], + // Coverage floor pinned just below measured reality so coverage can only + // ratchet up. Decay below these numbers fails the build. Raise them + // deliberately as coverage improves; never lower them silently. + coverageThreshold: { + global: { + statements: 53, + branches: 37, + functions: 38, + lines: 54, + }, + }, }; diff --git a/packages/common-utils/jest.config.js b/packages/common-utils/jest.config.js index 3af5ab5353..dc20747d91 100644 --- a/packages/common-utils/jest.config.js +++ b/packages/common-utils/jest.config.js @@ -15,4 +15,15 @@ module.exports = { moduleNameMapper: { '@/(.*)$': '/$1', }, + // Coverage floor pinned just below measured reality so coverage can only + // ratchet up. Decay below these numbers fails the build. Raise them + // deliberately as coverage improves; never lower them silently. + coverageThreshold: { + global: { + statements: 86, + branches: 78, + functions: 85, + lines: 86, + }, + }, }; diff --git a/packages/hdx-eval/jest.config.js b/packages/hdx-eval/jest.config.js index 4bdc2f8362..f184265f85 100644 --- a/packages/hdx-eval/jest.config.js +++ b/packages/hdx-eval/jest.config.js @@ -12,4 +12,15 @@ module.exports = { moduleNameMapper: { '@/(.*)$': '/$1', }, + // Coverage floor pinned just below measured reality so coverage can only + // ratchet up. Decay below these numbers fails the build. Raise them + // deliberately as coverage improves; never lower them silently. + coverageThreshold: { + global: { + statements: 70, + branches: 55, + functions: 72, + lines: 71, + }, + }, }; diff --git a/packages/hdx-eval/package.json b/packages/hdx-eval/package.json index e2d6dd6b0e..99029566f1 100644 --- a/packages/hdx-eval/package.json +++ b/packages/hdx-eval/package.json @@ -36,7 +36,7 @@ "lint": "npx eslint . --ext .ts --max-warnings 3", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit", - "ci:unit": "jest --ci --forceExit", + "ci:unit": "jest --ci --coverage --forceExit", "dev:unit": "jest --watch", "viewer": "node scripts/viewer/server.js" } From 0a7718c92a3709417e7cb0b9ac67b28932316277 Mon Sep 17 00:00:00 2001 From: Jordan Simonovski Date: Fri, 17 Jul 2026 13:53:42 +1000 Subject: [PATCH 3/3] ci(test): scope app coverage floors to hooks and utils only Replace the app package's single global coverageThreshold with path-scoped floors on ./src/hooks/ and ./src/utils/ (plus the shared ./src/utils.ts). React components now carry no coverage requirement -- unit tests on them tend to be low-value and fragile, and E2E/Storybook cover them better -- while the ratchet still holds on the genuinely unit-testable code. Jest subtracts the globbed paths from the overall pool, so components are ungated. Floors are pinned one point below measured (hooks/utils sit at 73-77% versus the old 53% global -- the gap was almost entirely components). --- packages/app/jest.config.js | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/app/jest.config.js b/packages/app/jest.config.js index c018531c3b..9875aabdc1 100644 --- a/packages/app/jest.config.js +++ b/packages/app/jest.config.js @@ -25,15 +25,30 @@ module.exports = { '^ky$': '/src/__mocks__/ky-universal.ts', }, setupFilesAfterEnv: ['/src/setupTests.tsx'], - // Coverage floor pinned just below measured reality so coverage can only - // ratchet up. Decay below these numbers fails the build. Raise them + // Coverage floors are scoped to hooks/ and utils/ only — the genuinely + // unit-testable code. React components carry no coverage requirement (unit + // tests on them tend to be low-value and fragile; E2E and Storybook cover + // them better). Each floor is pinned just below measured reality so coverage + // can only ratchet up; decay below these numbers fails the build. Raise them // deliberately as coverage improves; never lower them silently. coverageThreshold: { - global: { - statements: 53, - branches: 37, - functions: 38, - lines: 54, + './src/hooks/': { + statements: 72, + branches: 59, + functions: 66, + lines: 73, + }, + './src/utils/': { + statements: 74, + branches: 59, + functions: 72, + lines: 76, + }, + './src/utils.ts': { + statements: 76, + branches: 77, + functions: 75, + lines: 76, }, }, };