Skip to content

Commit 6b0a5af

Browse files
devlux76CopilotCopilot
authored
enforce coverage 80 (#87)
* feat: add coverage enforcement for tests and update CI configuration * Enforce minimum 80% test coverage in CI + local pre-push hook * Relax branch coverage enforcement while keeping 80% minimum line/function/statement coverage * Fix vitest coverage config: remove unsupported 'all' option * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <[email protected]> * Opt into Node.js 24 for GitHub Actions (force JS actions to Node 24) * Pin @vitest/coverage-v8 to latest (#88) * Initial plan * Update @vitest/coverage-v8 to latest to match all other dependencies Co-authored-by: devlux76 <[email protected]> --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: devlux76 <[email protected]> * Run guard:model-derived and guard:hotpath-policy on pre-push and fix model-derived guard false positives * Fix guard-hotpath-policy to allow lib/core/HotpathPolicy.ts --------- Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 0a2d2c6 commit 6b0a5af

File tree

9 files changed

+121
-7
lines changed

9 files changed

+121
-7
lines changed

.github/workflows/auto-label.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ permissions:
1111
jobs:
1212
label:
1313
runs-on: ubuntu-latest
14+
env:
15+
# Opt into Node.js 24 for JavaScript actions (GitHub Actions default will bump to Node 24 in 2026).
16+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
1417
steps:
1518
- name: Label PR by changed files
1619
uses: actions/labeler@v5

.github/workflows/ci.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ on:
88
jobs:
99
test:
1010
runs-on: ubuntu-latest
11+
env:
12+
# Opt into Node.js 24 for actions (GitHub Actions will default to Node.js 24 in 2026).
13+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
1114
steps:
1215
- name: Checkout
1316
uses: actions/checkout@v4
@@ -26,8 +29,8 @@ jobs:
2629
- name: Typecheck
2730
run: bun run build
2831

29-
- name: Test
30-
run: bun run test:unit
32+
- name: Test (coverage enforcement)
33+
run: bun run test:coverage
3134

3235
- name: Guard — model-derived numerics
3336
run: bun run guard:model-derived

.husky/pre-push

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/bin/sh
2+
. "$(dirname "$0")/_/husky.sh"
3+
4+
# Enforce minimum coverage locally before pushing.
5+
# This mirrors the CI coverage enforcement and keeps merge-ready branches aligned.
6+
bun run test:coverage
7+
8+
# Also run project guards locally (same as CI) so issues are caught before push.
9+
bun run guard:model-derived
10+
bun run guard:hotpath-policy

bun.lock

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/sharing/SubgraphImporter.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ function isValidPage(p: unknown): p is Page {
4141
typeof page.pageId === "string" && page.pageId.length > 0 &&
4242
typeof page.content === "string" &&
4343
typeof page.embeddingOffset === "number" &&
44-
typeof page.embeddingDim === "number" && page.embeddingDim > 0
44+
// This check is a validation guard, not a hardcoded model numeric.
45+
typeof page.embeddingDim === "number" && page.embeddingDim > 0 // model-derived-ok
4546
);
4647
}
4748

@@ -103,7 +104,7 @@ async function importNodes(
103104
signature: "",
104105
// Mark as "no local embedding yet"; downstream code can choose to re-embed.
105106
embeddingOffset: 0,
106-
embeddingDim: 0,
107+
embeddingDim: 0, // model-derived-ok
107108
};
108109

109110
// Optionally verify that pageId matches SHA-256(content)

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "eslint .",
1010
"test": "bun run lint && bun run build && vitest run tests/*.test.ts tests/**/*.test.ts",
1111
"test:unit": "vitest run tests/*.test.ts tests/**/*.test.ts",
12+
"test:coverage": "vitest run --coverage",
1213
"test:watch": "vitest tests/*.test.ts tests/**/*.test.ts",
1314
"dev:harness": "bun scripts/runtime-harness-server.mjs",
1415
"test:browser": "playwright test",
@@ -19,6 +20,7 @@
1920
"test:all": "bun run test:unit && bun run test:runtime",
2021
"guard:model-derived": "bun scripts/guard-model-derived.mjs",
2122
"guard:hotpath-policy": "bun scripts/guard-hotpath-policy.mjs",
23+
"prepare": "husky install",
2224
"benchmark:dummy": "vitest bench --watch=false tests/benchmarks/DummyEmbedderHotpath.bench.ts",
2325
"benchmark:query-latency": "vitest bench --watch=false tests/benchmarks/QueryLatency.bench.ts",
2426
"benchmark:storage-overhead": "vitest bench --watch=false tests/benchmarks/StorageOverhead.bench.ts",
@@ -33,10 +35,12 @@
3335
"devDependencies": {
3436
"@eslint/js": "latest",
3537
"@playwright/test": "latest",
38+
"@vitest/coverage-v8": "latest",
3639
"@webgpu/types": "latest",
3740
"electron": "latest",
3841
"eslint": "latest",
3942
"fake-indexeddb": "latest",
43+
"husky": "latest",
4044
"typescript": "latest",
4145
"typescript-eslint": "latest",
4246
"vitest": "latest"

scripts/guard-hotpath-policy.mjs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ const IGNORED_DIRS = new Set([
3131
"tests",
3232
]);
3333

34-
/** The only file allowed to define raw numeric hotpath policy constants. */
35-
const ALLOWED_SOURCE_FILE = "core/HotpathPolicy.ts";
34+
/** The only file(s) allowed to define raw numeric hotpath policy constants. */
35+
const ALLOWED_SOURCE_FILES = new Set([
36+
"core/HotpathPolicy.ts",
37+
"lib/core/HotpathPolicy.ts",
38+
]);
3639

3740
/**
3841
* Field names that must not receive hardcoded numeric literals outside the
@@ -108,7 +111,7 @@ async function main() {
108111
const violations = [];
109112

110113
for (const relativePath of tsFiles) {
111-
if (relativePath === ALLOWED_SOURCE_FILE) {
114+
if (ALLOWED_SOURCE_FILES.has(relativePath)) {
112115
continue;
113116
}
114117

scripts/guard-model-derived.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ const IGNORED_DIRS = new Set([
1515
]);
1616

1717
const ALLOWED_SOURCE_FILES = new Set([
18+
// These files are the canonical source of model-derived numeric constants.
19+
// They are explicitly allowed to contain hardcoded model profile values.
1820
"core/ModelDefaults.ts",
1921
"core/BuiltInModelProfiles.ts",
22+
"lib/core/ModelDefaults.ts",
23+
"lib/core/BuiltInModelProfiles.ts",
2024
]);
2125

2226
const MODEL_FIELD_PATTERN =

vitest.config.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { defineConfig } from "vitest/config";
2+
3+
export default defineConfig({
4+
test: {
5+
include: ["**/*.test.ts", "**/*.spec.ts"],
6+
coverage: {
7+
provider: "v8",
8+
enabled: !!process.env.CI,
9+
clean: true,
10+
include: ["lib/**/*.ts"],
11+
reporter: ["text", "html"],
12+
reportsDirectory: "coverage",
13+
exclude: [
14+
// Runtime configuration + platform-specific code that is not testable in this environment
15+
"lib/CreateVectorBackend.ts",
16+
"lib/WasmVectorBackend.ts",
17+
"lib/WebGLVectorBackend.ts",
18+
"lib/WebGPUVectorBackend.ts",
19+
"lib/WebNNVectorBackend.ts",
20+
// Pure type definitions (no executable JS generated)
21+
"**/*.d.ts",
22+
"**/types.ts",
23+
"**/VectorBackend.ts",
24+
"**/ModelProfile.ts",
25+
"**/QueryResult.ts",
26+
"**/WebNNTypes.*",
27+
// Test and tooling files
28+
"tests/**",
29+
"benchmarks/**",
30+
"scripts/**",
31+
"docker/**",
32+
"node_modules/**",
33+
],
34+
thresholds: {
35+
// Enforce a minimum test coverage baseline. We focus on line/statement/function
36+
// coverage; branch coverage is tracked but may vary substantially across
37+
// complex control flows (e.g., optional platform APIs). Adjust this if we
38+
// decide to enforce strict branch coverage in the future.
39+
lines: 80,
40+
functions: 80,
41+
branches: 0,
42+
statements: 80,
43+
},
44+
},
45+
},
46+
});

0 commit comments

Comments
 (0)