test(web): gate the web engine at 100% coverage (vitest v8 + CI)#10
Merged
Conversation
Mirrors the Swift BidLabCore cleanup (#9). PacedFlight computed winRate as `intervalOpportunities > 0 ? ... : 0`, but intervalOpportunities is `Math.max(1, ...)`, so the guard is dead; divide directly. Analytics.power keeps its defensive `se > 0` guard (se is always > 0 because baselineRate is in (0,1)), marked `/* v8 ignore next */` since it is unreachable by construction. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add @vitest/coverage-v8 with coverage scoped to src/engine at 100% thresholds (statements/branches/functions/lines), a coverage.test.ts boundary suite that completes branch coverage (divide-by-zero guards, p==0/1, sd==0, the normal- quantile tails, empty inputs, Result getters), a test:coverage script, and a Web CI workflow running typecheck + the coverage gate on PRs and pushes touching web/. The engine reports 100% on all four metrics; the full suite is 180 tests. The gate is the pure engine; components are UI and covered separately. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
vitest v4's CoverageOptions type no longer includes `all`, so `tsc --noEmit` (the typecheck CI step) rejected vite.config.ts. `include: ['src/engine/**']` already scopes coverage and every engine file is imported by a test, so the 100% result is unchanged (396/396 statements, 204/204 branches, 88/88 functions, 345/345 lines). Verified locally with both `npm run typecheck` and the gate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
scumunna
pushed a commit
that referenced
this pull request
Jun 23, 2026
…0 web) #9 raised the native suite to 5,271 checks and #10 the web suite to 180; update the README and ACCEPTANCE.md to match, and add the CI coverage-gate story (web 100%, native 100% of reachable code). ACCEPTANCE.md's web engine-suite row now includes the added boundary tests (47 -> 80). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows the native coverage work (#9), now for the web side: a 100% coverage gate on the pure TypeScript engine (
web/src/engine), the faithful port ofBidLabCore.Result
vitest run --coverage, scoped tosrc/engine:Full web suite: 180 tests (was 147), all passing.
How it's enforced
@vitest/coverage-v8with a coverage block inweb/vite.config.ts:include: ['src/engine/**'],thresholds: { statements/branches/functions/lines: 100 }.npm run test:coveragefails locally if any engine line, branch, or function is uncovered..github/workflows/web.ymlrunstypecheck+ the coverage gate on every push tomainand PR touchingweb/**(staticnpmsteps only — no untrusted input).What's tested
src/engine/coverage.test.tsis a boundary suite mirroring the SwiftEdgeCoverageTests: divide-by-zero guards (→Infinity/0), distribution special cases (p==0/1,sd==0, thenormalQuantiletails,lgammareflection), empty-input returns,MarketResult/PacedFlightResultgetters, both market models and auction types, and therunMarketfloor-loss/competition-loss/budget-bind branches.Two source tweaks (mirror #9)
pacedFlight.ts: dropped a deadwinRateternary (intervalOpportunitiesisMath.max(1, …), always ≥ 1).analytics.ts: kept the defensivese > 0guard inpower()(unreachable sincebaselineRate ∈ (0,1)), marked/* v8 ignore next */.Scope
The gate is the pure engine (the credibility core). The React components are UI and are not part of this gate — a separate effort if you want component/DOM coverage later.
🤖 Generated with Claude Code