Skip to content

test: измерване на coverage и ratchet праг в CI (#93)#216

Open
ydimitrof wants to merge 2 commits into
midt-bg:mainfrom
ydimitrof:feat/coverage-ratchet
Open

test: измерване на coverage и ratchet праг в CI (#93)#216
ydimitrof wants to merge 2 commits into
midt-bg:mainfrom
ydimitrof:feat/coverage-ratchet

Conversation

@ydimitrof

Copy link
Copy Markdown

Какво и защо

В monorepo-то нямаше измерване на test coverage — нито @vitest/coverage-*, нито праг, а CI пускаше pnpm test без --coverage. Този PR добавя харнеса от #93: измерване per workspace, ratchet праг който fail-ва CI при спад, и coverage делта видима в PR-а. Само харнесът — новите тестове бяха отделен обхват (#74, вече merged).

  • Измерване: @vitest/coverage-v8 (root devDep) през общ preset vitest.shared.ts; vitest.config.ts за всичките 6 workspace-а с тестове, с експлицитен include — иначе v8 provider-ът брои само файловете, заредени от тестове, и нов непокрит модул би бил невидим за ratchet-а.
  • Ratchet: комитнат coverage-baseline.json (seed-нат от реалните числа) + scripts/check-coverage.mjs — lines% и branches% на всеки workspace не може да падне >0.5pp под baseline-а. При покачване >1pp скриптът подканя --update (локално; никога в CI). Умишлен спад = сваляне на числото в baseline-а в същия PR, видимо на ревю. Общият сбор е информативен, смятан от сумирани covered/total бройки, не осреднени проценти.
  • CI: pnpm test -- --coverage (тестовете се пускат веднъж), ratchet gate със self-test първо (по модела на docs проверката), таблицата с делтите в step summary + artifact coverage-report. Sticky PR коментар само за same-repo PR-и — fork PR-ите получават read-only token независимо от permissions:, затова коментарният job е отделен, гейтнат по head.repo.full_name и continue-on-error; check job-ът остава с read-only token.
  • turbo: test task-ът декларира outputs: ["coverage/**"], така че cache replay възстановява отчетите (проверено: FULL TURBO + наличен coverage-summary.json).
  • Конвенцията е документирана в docs/review-testing.md.

Бележка: apps/web/tsconfig.node.json добавя ../../vitest.shared.ts в include (composite проектът изисква изброени файлове). packages/api-contract е извън baseline-а, докато няма тестове. Sticky-коментарният job може да се провери реално чак на този PR — всичко останало е проверено локално.

Свързан issue

Closes #93.

Вид промяна

  • test / ci / build / chore — поддръжка

Как е тествано

  • pnpm check:coverage:test — 12/12 (node:test, адверсариални случаи: спад отвъд толеранса, спад в толеранса, независим branches ratchet, липсващ отчет/метрика, merge на бройки vs осредняване).
  • pnpm test -- --coverage — 6/6 workspace-а зелени, всеки произвежда coverage/coverage-summary.json.
  • Мутационен тест: baseline на packages/shared +2pp → exit 1 с actionable съобщение; +0.3pp → exit 0 (толеранс).
  • Cache: второ пускане е FULL TURBO и отчетите пак са налични (replay на outputs).
  • pnpm typecheck, pnpm lint, pnpm check:docs — зелени.

Чеклист

  • Комитите следват conventional commits и нямат Co-Authored-By: trailer
  • PR-ът е с един логически обхват и е от форк към midt-bg/sigma:main
  • pnpm typecheck минава
  • pnpm test (поне за засегнатите пакети) минава
  • pnpm lint е чисто
  • Няма комитнати тайни, .env* или .dev.vars
  • Документацията в docs/ е обновена, ако промяната го налага

- @vitest/coverage-v8 през общ preset (vitest.shared.ts); vitest.config.ts
  за всичките 6 workspace-а с тестове, с експлицитен include за да не са
  невидими непокритите модули
- scripts/check-coverage.mjs: per-workspace ratchet (lines/branches срещу
  комитнат coverage-baseline.json, 0.5pp толеранс), markdown таблица с
  делти + информативен общ сбор; --update вдига baseline-а локално
- CI: pnpm test -- --coverage + ratchet gate (self-test първо), artifact
  с отчета, step summary, sticky PR коментар само за same-repo PR-и
  (fork token-ът е read-only); turbo test task пази coverage/** outputs
- документирано в docs/review-testing.md
@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Прегледах #216 стриктно (харнесът за #93).

Сигурност — издържана: trigger е pull_request (не pull_request_target), default token contents: read, а коментарният job с pull-requests: write е гейтнат само за same-repo PR-и (head.repo.full_name == github.repository) + continue-on-error — fork код никога не се изпълнява с write token.

Ratchet — коректен и fail-closed: липсващ отчет = твърда грешка, липсваща метрика = грешка, спад > tolerance = fail; sharedCoverage(include) с експлицитен include (src/**; за web app/**+workers/** — worker-ът е покрит) прави ratchet-а реален, а не фасада; merged total-ът сумира covered/total, не осреднява проценти. Self-тестовете хващат точно спада отвъд толеранса (79% vs 80% baseline → exit 1). Внимателна работа. Одобрявам харнеса.

Две точни бележки — за да не се чете покритието погрешно (не блокер за merge):

1) Derive слоят на ETL е ИЗВЪН обхвата на покритието — по конструкция. apps/etl (18.7%) мери само eop.ts/index.ts (feed client + entry), НЕ деривациите. Accuracy логиката е в scripts/normalize-raw.sql/precompute.sql/refresh-slice.sql/derive-health.sql + import.mjs/ship-domain.mjs — а scripts/ не е coverage workspace (и v8 не инструментира SQL). Значи ratchet-ът нито мери, нито пази derive слоя. Реалният му guard са D1 интеграционните тестове (packages/db/src/{refresh-slice,ship-domain}.test.ts срещу реален sqlite); тях третирайте като ETL-accuracy гейта, и добавете ред в review-testing.md, че coverage% не говори за коректността на derive-а (да не се чете зелено като „ETL е тестван").

2) Сред измерените workspace-и, branch подовете на accuracy слоевете са ниски. packages/db branches 65.5% и packages/config branches 58.3% — там живеят value_flag / деление-гардовете / праговете. Regression-only ratchet ги узаконява; за #98/#99 (гаранция за стойностната база) искайте цел за ПОКАЧВАНЕ на db/config branches, не само под.

Иначе е точно каквото #93 иска и е сигурно направено. Approve; двете бележки са за roadmap-а на покритието.

…ар fix

Адресира ревю находките по PR midt-bg#216:
- validateBaseline: празен/невалиден workspaces обект, изтрит или забравен
  ключ за workspace с test script, stale ключ и traversal/__proto__ ключове
  вече fail-ват gate-а вместо тихо да го изключват
- --update печата per-workspace делти и предупреждава шумно при спад, за да
  не може реална регресия тихо да влезе в нов baseline
- coverage exclude покрива и .test.tsx/.spec.* варианти
- sticky comment: gh api | head пренаписан на два стъпки (pipefail SIGPIPE)
- по-точно съобщение при липсващ отчет след crash-нал vitest процес
@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Прегледах новия връх d16f32c. Хардънингът е стабилен:

  • validateBaseline вече пада затворено при празен/непълен baseline — празни workspaces → грешка вместо тих pass; workspace с test script, но без baseline entry → грешка; и обратно за stale entry. Затваря реалната fail-open дупка (иначе празен baseline = ratchet no-op).
  • pipefail: gh api | head е разделено на две стъпки заради SIGPIPE (141) под default-ния pipefail на runner-а — коректно; pnpm test -- --coverage е директен run, кодът му на изход не се маскира (тестова грешка си пада CI).

Approve остава. Двете ми roadmap бележки (ETL derive извън обхвата на coverage; ниски branch подове на db/config) са проследени в #217 (priority: high) — не блокират този PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Тестове: измерване и праг на coverage в CI

2 participants