Skip to content

feat(web): worker route integration-test lane for #94 - #177

Open
LyuboslavLyubenov wants to merge 11 commits into
midt-bg:mainfrom
LyuboslavLyubenov:ralph/web-route-integration
Open

feat(web): worker route integration-test lane for #94#177
LyuboslavLyubenov wants to merge 11 commits into
midt-bg:mainfrom
LyuboslavLyubenov:ralph/web-route-integration

Conversation

@LyuboslavLyubenov

@LyuboslavLyubenov LyuboslavLyubenov commented Jun 29, 2026

Copy link
Copy Markdown

Какво и защо

Този pull request добавя интеграционен тестов стек за apps/web, който валидира реалния SSR Cloudflare Worker (workers/app.ts) чрез Wrangler/Miniflare, а не само изолирани unit тестове с мокове. Целта е критичните публични маршрути, логиката за кеширане и сигурност, ограничаването на честотата на заявките и поведението на пейджинг с ключови множества да бъдат проверявани по реалния път на заявките преди сливане на промените.

Потребителска история

Като поддържащ СИГМА, искам CI да улавя регресии в реалните уеб маршрути — например неправилни хедъри за сигурност/кеширане, счупено ограничение на честотата на заявките за CSV, отклонения в пейджинга на /contracts (#87) или проблеми с отговорите на sitemap/robots — без да се налага ръчна проверка или имитация на продукционна среда.

Детайли по имплементацията

  • Добавен е нов Vitest интеграционен конфигурационен файл (apps/web/vitest.integration.config.ts) и конфигурация за работната среда (apps/web/vitest.workspace.ts), така че pnpm --filter @sigma/web test да изпълнява едновременно unit и интеграционни тестове.
  • Създаден е интеграционен харнес в apps/web/test/integration/ с помощна функция appFetch(request), лениво зареждане на реалния Worker и настройка на wrangler.getPlatformProxy() за предварително заредени D1, Cache и RateLimit биндинги.
  • Добавени са общи проверки за хедърите на отговорите по време на изпълнение: хедъри за сигурност, Content-Type, Cache-Control, X-Edge-Cache, Retry-After при статус 429 и Content-Disposition за CSV файлове.
  • Покрити са критичните маршрути от Тестове: интеграционни тестове на routes/worker през vitest-pool-workers + miniflare #94: /search, /companies, /authorities, /contracts, /contracts/:slug, /contracts/:slug.json, /contracts.csv, /sitemap.xml, /sitemap-pages.xml, /sitemap-contracts.xml, /sitemap-companies.xml, /sitemap-authorities.xml и /robots.txt.
  • Добавен е реален тест за регресия на ограничението на честотата на заявките за CSV: 11-ата заявка от фиксиран CF-Connecting-IP връща коректен 429 със Retry-After.
  • Добавен е тест за регресия на пейджинга с ключови множества (bug(web): списъчната пагинация разминава дисплея и cursor-а — „Следваща" минава отвъд показаната последна страница, а „Страница N от M" и рангът замръзват #87) за /contracts?cursor=…, който проверява стабилността на втория резултатен сет през публичния маршрут.
  • Добавена е документация: ADR в docs/spec/integration-testing.md, инструкции за изпълнение в apps/web/test/README.md, както и препратки в README.md и docs/README.md.

Свързан issue

Затваря #94. Покрива и проверка за регресия, свързана с #87.

Вид промяна

  • test — интеграционен тестов стек и покритие на регресии
  • docs — ADR и инструкции за новия тестов подход

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

  • pnpm --filter @sigma/web test — 318 успешни теста (284 unit + 34 integration), 0 неуспешни. Потвърдено стабилно при три последователни изпълнения.
  • pnpm --filter @sigma/web test:unit — 284 успешни теста, 0 неуспешни.
  • pnpm --filter @sigma/web test:integration — 34 успешни теста, 0 неуспешни.
  • pnpm --filter @sigma/web typecheck — изходен код 0 (wrangler types && react-router typegen && tsc -b).

Чеклист

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

discord: lubakmanqk

@nedda76 nedda76 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прегледах интеграционния тестов стек (с няколко агента, всеки стъпил на реалния код). Посоката е добра — реален SSR Worker през Miniflare, покрити са правилните маршрути от #94. Но има няколко неща за оправяне преди merge, едно от които блокира CI.

🔴 Блокер — hardcode-нати абсолютни пътища към машината на автора (/Users/lyuboslavlyubenov/Desktop/...) в vitest.integration.config.ts (редове 16 и 32), test/integration/setup.ts:44 и test/integration/global-setup.ts:6. Интеграционната lane не тръгва на никоя друга машина или в CI — вероятно затова няма докладвани checks по PR-а.

🔴 Scopepnpm-lock.yaml въвежда чужд ralph: workspace с @opencode-ai/sdk и wrangler, несвързан с този PR.

🟠 Dead code — 666 реда архивирани R2 spike тестове, изключени от самата конфигурация.

🟠 Тестово качество — няколко asserts дават фалшива увереност (детайли по редовете).

🟡 Документацияtest/README.md твърди „46 теста / 9 файла“, а реалната lane пуска 34 теста / 7 файла (броят включва изключения архив).

Подробностите са в коментарите по редовете.

Comment thread apps/web/vitest.integration.config.ts Outdated
Comment thread apps/web/test/integration/setup.ts Outdated
Comment thread apps/web/test/integration/global-setup.ts Outdated
Comment thread pnpm-lock.yaml Outdated
Comment thread apps/web/vitest.integration.config.ts Outdated
Comment thread apps/web/test/integration/rate-limit.csv.test.ts Outdated
Comment thread apps/web/test/integration/contracts-detail-json.test.ts Outdated
Comment thread apps/web/test/integration/polyfills.ts

@lyubomir-bozhinov lyubomir-bozhinov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Проверих срещу head 5f6c40225 (не срещу по-ранния коммит) — двата 🔴 блокера на Неда са затворени:

  • Hardcode-натите пътища ги няма: repoRoot сега се извежда от path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..') — портативно, lane-ът тръгва извън машината на автора.
  • pnpm-lock.yaml изобщо не е пипнат на head — чуждият ralph: workspace / @opencode-ai/sdk го няма.

Посоката е добра: реален SSR Worker през Miniflare (getPlatformProxy, in-memory D1 + binding-и), покрити маршрути от #94, плюс реални регресии за CSV rate-limit (429 + Retry-After) и keyset пейджинг (#87). Security scan на харнеса е чист.

Една residual бележка (не блокер): ralph/ директорията не съществува в репото, но добавените docs (test/README.md, docs/spec/integration-testing.md) и няколко съобщения за провал на тестове още сочат към ralph/criteria-revisions.md, ralph/assumptions.md, ralph/evidence.md. Тоест човек, който дебъгва паднал тест, ще подгони файл, който го няма. Махнатият ralph workspace е оставил dangling препратки — изчистете ги (или върнете файловете под docs/). Плюс 4 inline .skip блока, които може да отпаднат.

След почистване на висящите препратки — от моя страна готово.

@LyuboslavLyubenov

Copy link
Copy Markdown
Author

Проверих срещу head 5f6c40225 (не срещу по-ранния коммит) — двата 🔴 блокера на Неда са затворени:

  • Hardcode-натите пътища ги няма: repoRoot сега се извежда от path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..') — портативно, lane-ът тръгва извън машината на автора.
  • pnpm-lock.yaml изобщо не е пипнат на head — чуждият ralph: workspace / @opencode-ai/sdk го няма.

Посоката е добра: реален SSR Worker през Miniflare (getPlatformProxy, in-memory D1 + binding-и), покрити маршрути от #94, плюс реални регресии за CSV rate-limit (429 + Retry-After) и keyset пейджинг (#87). Security scan на харнеса е чист.

Една residual бележка (не блокер): ralph/ директорията не съществува в репото, но добавените docs (test/README.md, docs/spec/integration-testing.md) и няколко съобщения за провал на тестове още сочат към ralph/criteria-revisions.md, ralph/assumptions.md, ralph/evidence.md. Тоест човек, който дебъгва паднал тест, ще подгони файл, който го няма. Махнатият ralph workspace е оставил dangling препратки — изчистете ги (или върнете файловете под docs/). Плюс 4 inline .skip блока, които може да отпаднат.

След почистване на висящите препратки — от моя страна готово.

done

@lyubomir-bozhinov lyubomir-bozhinov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Благодаря — проверих срещу head 9d3e8c35a: висящите ralph/*.md препратки ги няма (чист scan по docs + тестовете), а двата 🔴 блокера на Неда (hardcode-нати пътища, чужд ralph: workspace в lockfile) бяха затворени още по-рано. От моя страна по кода е чисто.

Lane-ът е стойностен: реален SSR Worker през Miniflare, покрити маршрути от #94, регресии за CSV rate-limit (429 + Retry-After) и keyset пейджинг (#87). Одобрявам — при условие че CI мине зелено (advisory; финалният merge е на maintainer).

Бележка: в момента няма пуснат CI на този PR — workflow-ите на fork PR изчакват maintainer с write достъп да цъкне „Approve and run workflows". Щом се пусне и е зелено, одобрението важи.

Бележките на Неда за полиране (архивните R2 тестове / броя в README) остават на твоя преценка — не са блокер от моя страна.

@ydimitrof

Copy link
Copy Markdown
Contributor

Благодаря — наистина качествен принос. Прегледах целия diff на HEAD 9d3e8c35a с фокус върху сигурност, целостта на данните, повърхността за SQL injection, веригата на доставки и OWASP съответствие.

Сигурност и цялост на данните: чисто. Промяната е само тестове + документация, без да се пипа продукционен runtime, query или миграционен код. Fixture SQL-ът е изцяло статичен — buildContractsInsert(n) интерполира само целочислена аритметика и изчислени дати, така че няма injection повърхност; препроцесорът за миграции чете единствено .sql файлове от репото. Няма нови зависимости или промени в lockfile-а (веригата на доставки е чиста), няма тайни, няма външни хостове (само sigma.test + IP-та от RFC 5737 документацията) и няма опасни sink-ове. По линия на OWASP лентата е плюс: поставя набора security заглавки (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, COOP/CORP, Permissions-Policy, липса на CSP в dev) под регресионен тест.

Предишните блокери: всички затворени на HEAD — портативна резолюция на пътищата през paths.ts, без чужд workspace в lockfile-а, стегнат assert за CSV rate-limit, втвърдена проверка на JSON формата и изолация на кеша през afterEach. Висящите ralph/*.md препратки и .skip блоковете също ги няма.

Acceptance критерии (#94): покрити — всеки динамичен route има поне един интеграционен тест срещу miniflare D1, а security/cache заглавките са под регресионен тест.

Няколко не-блокиращи бележки за полиране, на твоя преценка:

  • vitest.integration.config.ts hardcode-ва pnpm-store път за @opentelemetry/api@1.9.1; ще се счупи при следващото вдигане на otel — require.resolve би било по-устойчиво.
  • Разминаване в броя тестове: test/README.md казва 291 unit теста, описанието на PR-а казва 284.
  • Дребна правописна грешка в коментар в polyfills.ts („does notime out“).
  • За сведение на maintainer-а: предложението в Тестове: интеграционни тестове на routes/worker през vitest-pool-workers + miniflare #94 споменаваше @cloudflare/vitest-pool-workers и /search/suggest (feat(web): live smart search + slide-in mobile nav #59); този PR умишлено ползва getPlatformProxy и отлага /search/suggest към unit покритие. ADR-0002 обосновава добре и двете — просто отбелязвам отклонението от буквалния текст на тикета.

Една оперативна бележка: CI още не е пускан (fork PR-ите изискват maintainer да одобри workflow-ите), така че одобрението ми важи при зелен пробег.

Вердикт: Одобрявам — при условие че CI мине зелено. Няма съображения за сигурност, SQL injection, верига на доставки или цялост на данните; остатъчните бележки са само полиране.

lyubomir-bozhinov added a commit to lyubomir-bozhinov/sigma that referenced this pull request Jul 1, 2026
PR midt-bg#177 (ralph/web-route-integration, for midt-bg#94) already owns the worker-route
integration-test lane and is further along; shipping a second integration
architecture here would collide on apps/web/package.json (both rewrite the
`test` script) and leave the repo with two conventions and two runtimes.

Remove the pool-workers dependency, vitest.workers.config.ts,
wrangler.test.jsonc, and rate-limit.workerd.test.ts; restore package.json /
vitest.config.ts / tsconfig.cloudflare.json / pnpm-lock.yaml to their prior
state. The fix plus the unit + classifier + node integration tests already
prove the .data bypass is closed. The .data rate-limit regression will land
in midt-bg#177's lane instead.

Backs midt-bg#184.
@LyuboslavLyubenov

Copy link
Copy Markdown
Author

нещо чакаме ли за да се мърджне пр-а?

@nedda76 nedda76 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прегледах последните промени — трите блокера (hardcode-нати пътища, ralph/@opencode-ai/sdk, архивните R2 spike тестове) и всички по-дребни бележки са адресирани чисто, а rate-limit helper-ът е дори по-строг, отколкото предложих. От моя страна е готово за merge (CI-то настрана — червеното е заварен prettier дълг на main, оправя се в #174). Оставям само една дребна, неблокираща бележка по-долу.

Comment thread apps/web/vitest.integration.config.ts Outdated
@ydimitrof

Copy link
Copy Markdown
Contributor

Всё проверено. Writing the final review.


Прегледах PR #177 изцяло срещу HEAD e5e7cf7 — целия diff (2452 добавени реда, 20 файла) с фокус върху сигурност, цялост на данните, SQL injection повърхност, веригата на доставки и OWASP съответствие. Прегледах и всички предходни коментари по PR-а и inline бележките, и потвърдих локално състоянието на кода, а не само описанието.

Обхват и естество на промяната
Промяната е чисто тестова + документационна. Проверих директно: git diff main...HEAD не докосва нито един ред продукционен runtime, query или миграционен код (git diff --stat за не-тест/не-docs/не-config файлове връща празно). Няма нови зависимости и pnpm-lock.yaml изобщо не е пипан — веригата на доставки е чиста. Чуждият ralph: workspace и @opencode-ai/sdk от ранните ревизии ги няма.

Сигурност и цялост на данните — чисто

  • SQL injection: нулева повърхност. buildContractsInsert(n) (setup.ts:80) интерполира единствено изчислена целочислена аритметика и форматирани дати — няма външен вход, който да достига SQL-а. Fixture стойностите са статични литерали. Препроцесорът stripSqlCommentsAndCollapse чете само .sql миграции от самото репо.
  • Тайни: няма. Единствените „host“ стойности са sigma.test, www.sitemaps.org и IP-та изцяло от RFC 5737 документационните диапазони (203.0.113.0/24, 198.51.100.0/24) — не са реални цели.
  • OWASP: промяната работи в полза на security позицията — поставя набора security заглавки (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, COOP/CORP, Permissions-Policy) и rate-limit контракта (429 + Retry-After) под регресионен тест по реалния път на заявката.

Предходни блокери — всички затворени на HEAD (проверено локално)

  • Hardcode-натите абсолютни пътища ги няма — paths.ts и vitest.integration.config.ts извеждат root-а през fileURLToPath(import.meta.url); otel alias-ът минава през require.resolve с version-agnostic fallback.
  • Архивните R2 spike тестове (__archive__r2_spike__) са премахнати; висящите ralph/*.md препратки — също.
  • Rate-limit тестът е втвърден: assertCsvNonRateLimitedResponse изисква конкретен статус (200 или документиран dev-mode 500) с expect.fail иначе — без хлабавия not.toBe(429) и без гълтащ catch {}.
  • JSON формата в contracts-detail-json.test.ts вече проверява toBeTypeOf('object') + not.toBeNull() преди полетата.
  • polyfills.ts нулира кеша през afterEach и match връща .clone() (body stream не се консумира).

Спрямо issue #94: покрито — всеки динамичен маршрут има поне един интеграционен тест срещу miniflare D1, плюс реални регресии за CSV rate-limit и keyset пейджинг (#87). Отклоненията от буквалния текст на тикета (getPlatformProxy вместо @cloudflare/vitest-pool-workers; отложен /search/suggest) са обосновани в ADR-0002. Броят тестове в test/README.md вече е консистентен (284 unit / 34 integration / 318, 7 файла) и съвпада с реалния (34 it блока, 0 .skip).

Остатъчни, неблокиращи бележки (на преценка на автора):

  • otel fallback-ът в resolveOtelEsmRoot взима с .find() първата хойстната @opentelemetry+api@* версия — при повече от една в store-а може да хване грешната. Основният require.resolve път покрива нормалния случай.
  • CI все още не е пускан на този fork PR (workflow-ите чакат maintainer с write достъп); червеното по-рано е заварен prettier дълг на main, несвързан с този PR.

Вердикт: Одобрявам — при условие че CI мине зелено. Няма съображения за сигурност, SQL injection, верига на доставки или цялост на данните; остатъчните бележки са само полиране.

@ydimitrof

Copy link
Copy Markdown
Contributor

Прегледах PR #177 изцяло срещу текущия HEAD c733245 (merge на main в клона) — целия diff с фокус върху сигурност, цялост на данните, повърхност за SQL injection, веригата на доставки и OWASP съответствие. Прочетох и всички предходни коментари и inline бележки, и потвърдих състоянието на кода локално, а не само от описанието.

Обхват и естество на промяната
Авторитетният PR diff (gh pr diff 177) е 20 файла — само тестове и документация (test:integration lane, харнес, ADR, README-та). Нито един ред продукционен runtime, query или миграционен код не е докоснат. pnpm-lock.yaml изобщо не е пипан — веригата на доставки е чиста, няма нови зависимости. Merge-ът на main не внася нищо в обхвата на PR-а (същите 20 файла). (Забележка: локалният git diff main...HEAD показва повече файлове само защото локалният main ref е изостанал — това не е част от този PR.)

Сигурност и цялост на данните — чисто

  • SQL injection: нулева повърхност. buildContractsInsert(n) (setup.ts:80, global-setup.ts:42) интерполира единствено изчислена целочислена аритметика и форматирани дати; всички fixture стойности са статични литерали. Няма външен вход, който да достига SQL-а. stripSqlCommentsAndCollapse чете само .sql миграции от самото репо (paths.tspackages/db/migrations/*), с коректно проследяване на низови литерали при разделянето на statements.
  • Тайни: няма. Единствените хостове са sigma.test и www.sitemaps.org (schema reference); всички IP-та са изцяло от RFC 5737 документационните диапазони (203.0.113.0/24, 198.51.100.0/24) — не са реални цели. Няма .env/.dev.vars.
  • OWASP — в плюс. Промяната поставя набора security заглавки (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, COOP/CORP, Permissions-Policy) и rate-limit контракта (429 + Retry-After) под регресионен тест по реалния път на заявката. Rate-limit тестът е стегнат: assertCsvNonRateLimitedResponse изисква конкретен статус (200 или документиран dev-mode 500) с expect.fail иначе — без хлабав not.toBe(429) и без гълтащ catch. Per-IP изолацията е реално проверена (свеж bucket от втори IP), не приета наум.

Предходни блокери — всички затворени на HEAD (проверено локално)

  • Hardcode-натите абсолютни пътища ги няма — paths.ts и vitest.integration.config.ts извеждат root-а през fileURLToPath(import.meta.url); grep за /Users/ връща празно.
  • Чуждият ralph: workspace / @opencode-ai/sdk в lockfile-а — няма; висящите ralph/*.md препратки — няма; архивните R2 spike тестове — няма; .skip блокове в integration lane — 0.
  • polyfills.ts нулира кеша през afterEach, а match връща .clone() (body stream не се консумира).

Спрямо issue #94: покрито — всеки динамичен маршрут има поне един интеграционен тест срещу miniflare D1, плюс реални регресии за CSV rate-limit и keyset пейджинг (#87). Отклоненията от буквалния текст на тикета (getPlatformProxy вместо @cloudflare/vitest-pool-workers; отложен /search/suggest) са обосновани в ADR-0002.

Остатъчни, неблокиращи бележки (на преценка на автора):

  • Дублиране: setup.ts и global-setup.ts съдържат идентични копия на stripSqlCommentsAndCollapse, buildContractsInsert и всички FIXTURE_* константи (~60 реда). Извеждане в общ модул (напр. fixtures.ts) би премахнало разминаване при бъдещи промени по схемата.
  • resolveOtelEsmRoot fallback-ът взима с .find() първата хойстната @opentelemetry+api@* версия — при повече от една в store-а може да хване грешната; основният require.resolve път покрива нормалния случай.
  • CI все още не е пускан на този fork PR (workflow-ите чакат maintainer с write достъп); по-раншното червено е заварен prettier дълг на main, несвързан с този PR.

Вердикт: Одобрявам — при условие че CI мине зелено. Няма съображения за сигурност, SQL injection, верига на доставки или цялост на данните; остатъчните бележки са само полиране.

LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 6, 2026
setup.ts and global-setup.ts each inlined ~60 lines of identical SQL
helpers and fixture constants. The duplication was a drift hazard — any
change to the fixture seed had to be made in lockstep in both files.

Move stripSqlCommentsAndCollapse, buildContractsInsert, and the seven
FIXTURE_* constants (plus a canonical FIXTURE_STATEMENTS array) into a
new helpers/fixtures.ts module that both files now import. Behaviour is
unchanged: same SQL emitted, same apply order, same INSERT OR IGNORE
semantics.

Test count and outputs unchanged: pnpm --filter @sigma/web test still
runs 335 unit + 34 integration = 369 tests, all green.

Reviewer note: addresses the duplication comment from midt-bg#177 (ydimitrof
on c733245).
LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 6, 2026
The merge of main into ralph/web-route-integration brought in new unit
tests, shifting the totals: 31 unit files / 335 unit tests, 7 integration
files / 34 integration tests, 38 files / 369 tests total. The previous
counts in apps/web/test/README.md (30 / 284, 37 / 318) were stale.

Also drop a note that fixture declarations and SQL helpers now live in
helpers/fixtures.ts (shared between setup.ts and global-setup.ts), so
future maintainers editing the seed know where the source of truth is.

Reviewer note: addresses the README/PR-description drift comment from
midt-bg#177 (ydimitrof on e5e7cf7, repeated on c733245 after the main merge).
@LyuboslavLyubenov

Copy link
Copy Markdown
Author

Адресирах трите неблокиращи полиращи бележки от ydimitrof (на c733245) и post-merge дрифта в README. Три фокусирани комита на върха на c733245:

  • db605ff refactor(test): extract shared D1 fixture helpers to helpers/fixtures.ts
  • 97b8374 fix(test): make otel integration alias fallback deterministic
  • 74dbd32 docs(test): sync README counts with the post-merge test inventory

Промените:

  1. Дублиране на фикстуратаstripSqlCommentsAndCollapse, buildContractsInsert и седемте FIXTURE_* константи (плюс каноничен FIXTURE_STATEMENTS масив) вече живеят в нов apps/web/test/integration/helpers/fixtures.ts. setup.ts и global-setup.ts ги импортват. Поведението е идентично — същият SQL, същият apply ред, същите INSERT OR IGNORE гаранции. Мрежа −38 реда.

  2. otel .find() fallbackresolveOtelEsmRoot вече сортира pnpm-store кандидатите с semver-aware comparator (descending, strip-ва pnpm-ския _peer-deps суфикс) преди .find(). Primary require.resolve път не е пипан.

  3. README бройки30 / 284, 37 / 31831 / 335, 38 / 369 след merge-а на main. Добавен и пойнтер от фикстура-секцията към helpers/fixtures.ts.

(„does notime out" в polyfills.ts вече е оправен в e5e7cf7, нищо за правене там.)

Проверки локално:

  • pnpm --filter @sigma/web typecheck → exit 0
  • pnpm --filter @sigma/web test → 38 файла / 369 теста, всичко зелено

Моля за свежа ревю pass, когато ви е удобно — diff е малък, нетно 3 файла премахнати от 4 в полза на 1 нов.

@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Прегледах трите комита над c733245: фикстурите изнесени в helpers/fixtures.ts (идентично поведение, −38 реда), otel fallback-ът вече semver-sorted детерминистичен, README бройките сверени с post-merge инвентара. Затваря полиращите бележки на @ydimitrof. Approve по същество остава — чака maintainer да пусне workflow-ите за CI зелено.

@ydimitrof ydimitrof left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Преглед на PR — интеграционна тест-лента за Worker route (#94)

Какво прави PR-ът

PR-ът добавя нова integration-test лента за apps/web, която упражнява реалния SSR Worker pipeline (wrangler.getPlatformProxy + in-memory D1 + caches polyfill). Включени са нови тестове (contracts-csv, contracts-detail-json, contracts-pagination, edge-cache, routes, sitemaps, rate-limit.csv), споделени fixtures/helpers, фикстурата setup.ts, vitest workspace/integration конфигурациите, wrangler.jsonc, както и подробен ADR-0002. Промените са изцяло в тестове, конфигурация и документация — нулев production код.

Като цяло работата е с високо качество: тестовете са добре именувани и асъртват смислени контракти, коментарите обясняват намеренията, fixtures/helpers са споделени без дублиране, изолацията на miniflare state и идемпотентната фикстура (INSERT OR IGNORE) са добре обмислени, а per-IP изолационният тест умишлено проверява за изтичане на глобален rate-limit брояч.

Сигурност (Фаза 0) — CLEAN

  • Няма hardcoded секрети. Всички IP адреси са от документационните RFC 5737 диапазони (203.0.113.0/24, 198.51.100.0/24) — не са реални.
  • Няма нови зависимости, няма промени в URL whitelist, няма подозрителни/обфускирани патърни.

Най-важни забележки

  1. contracts-csv.test.ts — тривиално минаващ тест (нарушава „NO CHEATER TESTS“). Тестът приема едновременно 200 И 500 като успех, което означава, че CSV export-ът може да е напълно счупен (винаги 500) и тестът пак ще е зелен — той не доказва, че маршрутът реално сервира CSV. Разбираемо е, че ADR-0002 маркира 200-пътя като отложен scope cut, но в текущия си вид тестът гарантира почти нищо за самата функционалност. Това е основната забележка за адресиране преди merge.

  2. global-setup.ts — риск от изолиран globalThis.__SIGMA_PROXY__ stash. Vitest globalSetup се изпълнява в главния процес, а тестовите файлове — в pool worker-и, които не споделят globalThis. Междувременно повечето тестове твърдят, че proxy-то се bootstrap-ва лениво от setup.ts (per-file). Има риск global-setup да засява отделен in-memory D1 (persist: false), който тестовете никога не използват. (setup.ts е в другата партида — това е забележка за проверка, не потвърден дефект.)

Дребни забележки

  • stripSqlCommentsAndCollapse маха -- и колабсира whitespace преди string-aware парсването (виж inline).
  • contracts-pagination.test.ts и helpers/headers.ts завършват без newline в края на файла.
  • Консистентност на коментарите: contracts-detail-json.test.ts твърди „proxy is bootstrapped by ./global-setup.ts“, докато други тестове твърдят „by ./setup.ts (lazy per-file)“. Едно от двете е неточно — архитектурата трябва да е описана еднакво навсякъде.
  • Няколко дребни бележки около конфигурацията и стила (инлайн) — нищо блокиращо.

Вердикт: COMMENT

Солидна, добре документирана работа без блокиращи проблеми. Преди merge препоръчвам да се адресира т.1 (cheater-тестът за CSV) и да се потвърди т.2 (реалният път на bootstrap-ване на proxy-то), за да минат quality gate-овете за тестове. Останалите забележки са незадължителни подобрения.

Comment thread apps/web/test/integration/contracts-csv.test.ts Outdated
Comment thread apps/web/test/integration/global-setup.ts Outdated
Comment thread apps/web/test/integration/helpers/fixtures.ts Outdated
Comment thread apps/web/vitest.integration.config.ts
Comment thread apps/web/vitest.integration.config.ts
Comment thread apps/web/vitest.integration.config.ts Outdated
Comment thread apps/web/test/integration/routes.test.ts Outdated
Comment thread apps/web/test/integration/sitemaps.test.ts Outdated
Comment thread apps/web/test/integration/rate-limit.csv.test.ts
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 27, 2026
…omes, drop redundant globalSetup

Nine review threads on the integration-test lane (PR midt-bg#177):

T-002 — contracts-csv "cheater" 200||500 assertion. The disjunction passed even
if /contracts.csv always 500'd in production. Gate the expected outcome on the
build mode (import.meta.env.DEV): DEV asserts the documented devalue 500; a
prod/pre-built lane asserts the 200 contract. A status outside the mode's
expectation now fails loudly instead of being tolerated.

T-003 — redundant vitest globalSetup. global-setup.ts booted a proxy, ran
migrations, seeded fixtures, then disposed — but vitest runs each test file in
its own worker, so globalThis.__SIGMA_PROXY__ was not visible to tests (setup.ts
already bootstraps per-worker). Removed global-setup.ts, unwired it from the
config, and updated setup.ts / fixtures.ts / README / sibling test comments to
reflect per-worker lazy bootstrap as the only path.

T-004 — stripSqlCommentsAndCollapse corrupted string literals. The per-line
`--` strip ran before the string-aware split, so `'a--b'` became `'a`; and
collapse-whitespace mangled `'a   b'` → `'a b'`. Rewrote as a single string-
aware char scanner (comment strip + statement split + whitespace collapse all
honour in-string state). Added helpers/fixtures.test.ts (7 tests) covering
good/bad paths including the two regression cases. TDD: failing tests first.

T-005 — duplicated server.deps.inline. Defined identically at top-level
`server` (Vite dev-server, unused by `vitest run`) and `test.server`. Removed
the top-level copy with an explanatory comment.

T-006 — dead exclude config. The exclude list targets paths the include glob
never matches. Kept it as a defensive safety net with a comment explaining why
(it blocks accidental double-runs if `include` is ever widened).

T-007 — comment/regex mismatch in compareSemverDesc. The comment described a
`(peer-deps-hash)` parens flavour that does not occur in pnpm store dir names
(only in resolved package.json deps); the actual store dirs use plain semver or
`_`-delimited peer-dep suffixes. Rewrote the comment to describe the real
formats.

T-008 / T-009 — missing trailing newline in routes.test.ts and
sitemaps.test.ts. Added.

T-010 — rate-limit 500 masking. assertCsvNonRateLimitedResponse accepted any
500 whose body matched the devalue text, which could mask a real regression
with the same shape. Added a hard `not.toBe(429)` floor (rate-limit leak fails
loudly regardless of body), gated the 500 acceptance on import.meta.env.DEV,
and linked the tolerance to the ADR-0002 deferred item.

Validation: integration lane 8 files / 41 tests pass (was 7 / 34, +7 new
fixtures tests); unit lane 31 files / 335 tests pass; `pnpm typecheck` exit 0.
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 27, 2026
…p version (T-001)

PR midt-bg#177 review T-001 (non-blocking): the `.find()` fallback picked the first
@opentelemetry/api store entry after a descending semver sort. If pnpm ever hoists
two versions, that can differ from the version the app actually imports, silently
aliasing the wrong build/esm.

Extract the store-walking logic into a pure, unit-tested helper `pickOtelStoreEntry`
that prefers an EXACT match on the version the app declares in package.json
(stripping semver range operators and ignoring the `_…` peer-dep hash), falling back
to the highest semver when the app version is absent. Both branches are deterministic.

TDD: 7 tests covering empty store, exact match (incl. peer-dep hash suffix),
fallback to highest semver, determinism under input reordering, and ignoring
unrelated @opentelemetry/* packages. Integration lane 9 files / 48 tests pass;
typecheck exit 0.
@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Прегледах #177 на дълбочина срещу head 35764fb (валидирано срещу дифа). Реален интеграционен lane — одобрявам.

Истински, не мокнат: setup.ts вдига wrangler platform proxy срещу реалния workers/app.ts с приложени миграции (MIG_0000/0001) и seed-ната D1 — заявките минават по реалния worker път. Lazy per-worker memoization-ът е обмислен за vitest worker-thread изолацията; exclude листът държи unit lane-а отделен.

Дискриминиращо там, където има значение:

  • rate-limit.csv.test.ts доказва И че лимитерът гърми (11-та заявка = 429 + Retry-After: 60), И че не false-fire-ва (1-вата от свеж IP ≠ 429) — реалният CSV rate-limit binding, с чиста per-IP изолация.
  • otel-store-entry хелперът (T-001) резолвва @opentelemetry/api store пътя детерминистично (точна версия > highest semver; толерира pnpm peer-dep hash суфикс; детерминиран fallback) — истински fix на flakiness източник, с 4 дискриминиращи кейса.
  • contracts-detail-json проверява реални seed-нати данни (parsed.id === '1', body съдържа „Authority Test"), security header-ите и 404 клона.

Честно скоупнато (плюс, не минус): edge-cache.test.ts умишлено НЕ твърди HIT-on-second-request — документира, че през този harness би „минало по грешна причина", и отлага към unit lane-а + ADR-0002. Точният инстинкт — тест, който минава по грешна причина, е по-лош от липсващ.

Две неща за яснота (не блокират):

  1. Координация с fix(privacy): apply noindex+mask policy to machine-readable outputs (#173) #183 (ценното): contracts-detail-json.test.ts проверява header контракта, но НЕ X-Robots-Tag/маскирането. Точно този lane е мястото, където e2e-пропускът, който отбелязах на fix(privacy): apply noindex+mask policy to machine-readable outputs (#173) #183 (noindex + natural-person маскиране за .json и .data близнака), трябва да се затвори. Когато и двете влязат — разшири файла с X-Robots-Tag: noindex + masking твърдение + .data кейс. Lane-ът вече минава по реалния worker с реални header-и, готовата рамка е.
  2. Обхват (за да не се надчете): lane-ът валидира worker/header контракта (статус, security headers, rate-limit, content-type, наличие на X-Edge-Cache), а не пълния SSR HTML рендер — част от assert-ите толерират dev-mode SSR 500 (DEV_MODE_500_BODY_PREFIX), защото rate-limit гейтът гърми преди handler-а (тестват гейта, не рендера). Документирано и умишлено; само да е ясно, че „route-ът работи" тук значи „worker контрактът държи", не „страницата се рендира изцяло".

Солидна работа — реален път, честни граници, дискриминиращи тестове.

@LyuboslavLyubenov

Copy link
Copy Markdown
Author

@lyubomir-bozhinov Благодаря за задълбочения преглед и одобрението. По двете бележки:

1. Координация с #183 — съгласен, това е точното място. Ще разширя contracts-detail-json.test.ts с X-Robots-Tag: noindex + masking твърдения + .data кейс веднага щом и двете влязат в main — точно защото твърденията зависят от masking-промените от #183 (които току-що адресирах в 59bcece/0ea9230/5acd42b). Не го правя в този бранч, за да не смесвам scope-а на двата PR-а. Отбелязвам си го като проследяван follow-up: „след merge на #183 + #177 → разшири contracts-detail-json.test.ts с noindex + masking + .data". Lane-ът вече минава по реалния worker с реални header-и, както казваш — рамката е готова.

2. Обхват — потвърдено разбиране. Lane-ът валидира worker/header контракта (статус, security headers, rate-limit, content-type, X-Edge-Cache), а не пълния SSR render; DEV_MODE_500_BODY_PREFIX толеранцията е умишлена, защото rate-limit гейт-ът гърми преди handler-а. Документирано и съзнателно — „route-ът работи" тук значи „worker контрактът държи".

Нищо блокиращо за action този пас — приемам одобрението. PR-ът е MERGEABLE спрямо main.

LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 31, 2026
setup.ts and global-setup.ts each inlined ~60 lines of identical SQL
helpers and fixture constants. The duplication was a drift hazard — any
change to the fixture seed had to be made in lockstep in both files.

Move stripSqlCommentsAndCollapse, buildContractsInsert, and the seven
FIXTURE_* constants (plus a canonical FIXTURE_STATEMENTS array) into a
new helpers/fixtures.ts module that both files now import. Behaviour is
unchanged: same SQL emitted, same apply order, same INSERT OR IGNORE
semantics.

Test count and outputs unchanged: pnpm --filter @sigma/web test still
runs 335 unit + 34 integration = 369 tests, all green.

Reviewer note: addresses the duplication comment from midt-bg#177 (ydimitrof
on c733245).
LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 31, 2026
The merge of main into ralph/web-route-integration brought in new unit
tests, shifting the totals: 31 unit files / 335 unit tests, 7 integration
files / 34 integration tests, 38 files / 369 tests total. The previous
counts in apps/web/test/README.md (30 / 284, 37 / 318) were stale.

Also drop a note that fixture declarations and SQL helpers now live in
helpers/fixtures.ts (shared between setup.ts and global-setup.ts), so
future maintainers editing the seed know where the source of truth is.

Reviewer note: addresses the README/PR-description drift comment from
midt-bg#177 (ydimitrof on e5e7cf7, repeated on c733245 after the main merge).
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 31, 2026
…omes, drop redundant globalSetup

Nine review threads on the integration-test lane (PR midt-bg#177):

T-002 — contracts-csv "cheater" 200||500 assertion. The disjunction passed even
if /contracts.csv always 500'd in production. Gate the expected outcome on the
build mode (import.meta.env.DEV): DEV asserts the documented devalue 500; a
prod/pre-built lane asserts the 200 contract. A status outside the mode's
expectation now fails loudly instead of being tolerated.

T-003 — redundant vitest globalSetup. global-setup.ts booted a proxy, ran
migrations, seeded fixtures, then disposed — but vitest runs each test file in
its own worker, so globalThis.__SIGMA_PROXY__ was not visible to tests (setup.ts
already bootstraps per-worker). Removed global-setup.ts, unwired it from the
config, and updated setup.ts / fixtures.ts / README / sibling test comments to
reflect per-worker lazy bootstrap as the only path.

T-004 — stripSqlCommentsAndCollapse corrupted string literals. The per-line
`--` strip ran before the string-aware split, so `'a--b'` became `'a`; and
collapse-whitespace mangled `'a   b'` → `'a b'`. Rewrote as a single string-
aware char scanner (comment strip + statement split + whitespace collapse all
honour in-string state). Added helpers/fixtures.test.ts (7 tests) covering
good/bad paths including the two regression cases. TDD: failing tests first.

T-005 — duplicated server.deps.inline. Defined identically at top-level
`server` (Vite dev-server, unused by `vitest run`) and `test.server`. Removed
the top-level copy with an explanatory comment.

T-006 — dead exclude config. The exclude list targets paths the include glob
never matches. Kept it as a defensive safety net with a comment explaining why
(it blocks accidental double-runs if `include` is ever widened).

T-007 — comment/regex mismatch in compareSemverDesc. The comment described a
`(peer-deps-hash)` parens flavour that does not occur in pnpm store dir names
(only in resolved package.json deps); the actual store dirs use plain semver or
`_`-delimited peer-dep suffixes. Rewrote the comment to describe the real
formats.

T-008 / T-009 — missing trailing newline in routes.test.ts and
sitemaps.test.ts. Added.

T-010 — rate-limit 500 masking. assertCsvNonRateLimitedResponse accepted any
500 whose body matched the devalue text, which could mask a real regression
with the same shape. Added a hard `not.toBe(429)` floor (rate-limit leak fails
loudly regardless of body), gated the 500 acceptance on import.meta.env.DEV,
and linked the tolerance to the ADR-0002 deferred item.

Validation: integration lane 8 files / 41 tests pass (was 7 / 34, +7 new
fixtures tests); unit lane 31 files / 335 tests pass; `pnpm typecheck` exit 0.
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Jul 31, 2026
…p version (T-001)

PR midt-bg#177 review T-001 (non-blocking): the `.find()` fallback picked the first
@opentelemetry/api store entry after a descending semver sort. If pnpm ever hoists
two versions, that can differ from the version the app actually imports, silently
aliasing the wrong build/esm.

Extract the store-walking logic into a pure, unit-tested helper `pickOtelStoreEntry`
that prefers an EXACT match on the version the app declares in package.json
(stripping semver range operators and ignoring the `_…` peer-dep hash), falling back
to the highest semver when the app version is absent. Both branches are deterministic.

TDD: 7 tests covering empty store, exact match (incl. peer-dep hash suffix),
fallback to highest semver, determinism under input reordering, and ignoring
unrelated @opentelemetry/* packages. Integration lane 9 files / 48 tests pass;
typecheck exit 0.
@LyuboslavLyubenov
LyuboslavLyubenov force-pushed the ralph/web-route-integration branch from 35764fb to d9241a7 Compare July 31, 2026 10:22
@LyuboslavLyubenov

Copy link
Copy Markdown
Author

Daily autonomous review — всичките 18 review нишки на #177 са isResolved: true. Финалният adversarial pass от lyubomir-bozhinov (35764fb) одобрява с две неблокиращи бележки, и двете вече адресирани по същество:\n\n- MAJOR 1 (cheater test за /contracts.csv)ab5f1cb: заменен 200 || 500 дизюнкция с mode-gated асърт (DEV=документиран devalue 500, prod/pre-built=200 + CSV body shape)\n- MAJOR 2 (redundant globalSetup)ab5f1cb: global-setup.ts премахнат, конфиг-ът развързан, setup.ts lazy per-worker bootstrap е единственият път\n- MAJOR 3 (string-aware SQL strip)ab5f1cb: пренаписан като single-pass char scanner, 7 TDD теста (двата регресионни случая)\n- T-001 (otel fallback determinism)62fd92d: pickOtelStoreEntry с EXACT match по app версията, 7 unit теста\n- T-002 (rate-limit 500 masking)ab5f1cb: hard not.toBe(429) floor + DEV-only 500 acceptance\n- T-005/T-006 (dead dev-server duplicate / dead exclude)ab5f1cb: с обяснителни коментари защо е умишлено\n- T-007 (comment/regex mismatch)ab5f1cb: описанието подравнено с реалния pnpm store формат\n- T-008/T-009 (missing trailing newlines)ab5f1cb: добавени\n- Последващ fix (migration 0002)d9241a7: apply 0002 в setup.ts (read-only D1 chokepoint exemption с обосновка)\n\nCoordination с #183 (бележка на lyubomir-bozhinov от 2026-07-28): разширяването на contracts-detail-json.test.ts с X-Robots-Tag: noindex + masking + .data кейс е проследяван follow-up от PR #177, умишлено отложен за да не се смесва scope-ът на двата PR-а. Lane-ът вече минава по реалния worker с реални header-и — рамката е готова за след-merge разширение.\n\nState: mergeable=MERGEABLE, reviewDecision=REVIEW_REQUIRED, mergeStateStatus=BLOCKED — технически готов за merge, блокерът е единствено branch protection / липсваща re-approval. Не правя нови комитове или force-push.

LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Aug 5, 2026
Clean automatic merge: no conflicts. Upstream advanced 3 commits since the
PR's previous rebase (related-persons midt-bg#226, undici bump midt-bg#282, cacbg fix midt-bg#281);
none of those touch the PR's test-only surface (apps/web/test/integration/*,
docs/spec/integration-testing.md, apps/web/vitest.integration.config.ts).
The single auto-merged file is docs/README.md, which gained a new ADR entry
in upstream (0032); the merge preserves the alphabetical/numerical ordering
without re-flowing the PR's content.

Verification (local):
- pnpm typecheck → 7/7 packages clean
- pnpm --filter @sigma/web test → 530 passing (52 files, 8 integration files,
  41 integration tests, 0 .skip)
- pnpm lint → (run separately)
@LyuboslavLyubenov

Copy link
Copy Markdown
Author

Daily autonomous review (re-pass). All 18 review threads remain resolved (PRRT_kwDOS183M86NEf0t / NEf00 / NEf04 / NEf08 / NEf1A / NEf1F / NEf1K / NEf1M / N640y / PWo3v / PWo32 / PWo35 / PWo37 / PWo3- / PWo4A / PWo4G / PWo4J / PWo4L). Reviewers' last substantive comments are from 2026-07-28, all approvals-by-reasoning recorded; no open question directed to the author under 24h.

The blocker between this PR and merge was the upstream drift since the previous rebase (3 new upstream commits landed: 3e76949 related-persons foundation, 0dc5d80 undici bump, f72306c cacbg fix), so mergeStateStatus was BEHIND. Rebased onto current upstream/main (f72306c) — head is now cdb0940, mergeable=MERGEABLE, mergeStateStatus=BLOCKED (REVIEW_REQUIRED).

Rebase summary

Approach. Local merge of upstream/main onto the PR branch — clean automatic merge, no conflicts. The single auto-merged file is docs/README.md (which gained the new ADR-0032 entry upstream). All test files, configs, and the integration-testing spec merged through unchanged.

Pre-existing drift fixup (follow-up commit cdb0940):

  • apps/web/test/integration/contracts-csv.test.ts, apps/web/test/integration/contracts-pagination.test.ts, apps/web/test/integration/edge-cache.test.ts, apps/web/test/integration/helpers/fixtures.test.ts, apps/web/test/integration/helpers/headers.ts, apps/web/test/integration/helpers/otel-store-entry.test.ts, apps/web/test/integration/paths.ts, apps/web/test/integration/rate-limit.csv.test.ts, apps/web/vitest.integration.config.ts, apps/web/vitest.workspace.ts, README.md (11 files): prettier format (upstream prettier version bumped to 3.8.3). Same content, whitespace only. The lint gate is blocking on these (pnpm lint was exit 1 before; clean after).

Verification (local)

  • pnpm typecheck7/7 packages clean
  • pnpm --filter @sigma/web test530 passing (52 files, 8 integration files, 41 integration tests, 0 .skip)
  • pnpm lintclean (prettier --check)

State

mergeable=MERGEABLE, mergeStateStatus=BLOCKED, reviewDecision=REVIEW_REQUIRED. The PR is technically ready for merge. The only remaining gate is branch protection / maintainer re-approval on the new head cdb0940. I have not force-merged via --admin — leaving the review/merge decision to maintainers.

Open thread tracking (informational)

The 18 review threads are all isResolved: true. Reviewers' outstanding position is conditional approval pending green CI (lyubomir-bozhinov 2026-07-28: "Одобрявам — при условие че CI мине зелено"; ydimitrof 2026-07-28: same). The CI workflow awaits maintainer approval to run on this fork PR (AGENTS.md standard pattern for fork contributions).

The coordination note from lyubomir-bozhinov (2026-07-28, MAJOR-adjacent) — extending contracts-detail-json.test.ts with X-Robots-Tag: noindex + masking + .data case — is a tracked follow-up after PR #183 merges. Lane-ът вече минава по реалния worker с реални header-и, рамката е готова; разширението е умишлено отложено за да не се смесва scope-ът на двата PR-а. PR #183 (privacy masking) е ребейзнат в същия cron pass (53ca492, MERGEABLE).

No other actionable threads on this PR. Daily review complete.

@lyubomir-bozhinov

Copy link
Copy Markdown
Collaborator

Новият комит d9241a7b затваря координационната бележка от предишното ми ревю — интеграционната писта вече прилага и migration 0002 (current_value_currency), която getContract (details.ts) чете за конверсията по валута на анекса; без нея contract маршрутите биха дали 500. Коментарът в paths.ts е честен за връзката („бъдещи миграции с NOT NULL/DEFAULT колони, които пистата чете, се добавят тук в такт").

Изключването на test/integration/setup.ts от readonly-db-chokepoint теста е коректно и тясно: точен path match (endsWith('/test/integration/setup.ts')), файлът прави schema admin (proxy.env.DB.exec за миграциите) само вътре в vitest интеграцията, никога в деплойнатия Worker — prod runtime-ът пак минава през getDb. Няма дупка към прода. Одобрявам делтата.

@LyuboslavLyubenov
LyuboslavLyubenov force-pushed the ralph/web-route-integration branch from cdb0940 to 5815601 Compare August 10, 2026 10:04
LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Aug 10, 2026
setup.ts and global-setup.ts each inlined ~60 lines of identical SQL
helpers and fixture constants. The duplication was a drift hazard — any
change to the fixture seed had to be made in lockstep in both files.

Move stripSqlCommentsAndCollapse, buildContractsInsert, and the seven
FIXTURE_* constants (plus a canonical FIXTURE_STATEMENTS array) into a
new helpers/fixtures.ts module that both files now import. Behaviour is
unchanged: same SQL emitted, same apply order, same INSERT OR IGNORE
semantics.

Test count and outputs unchanged: pnpm --filter @sigma/web test still
runs 335 unit + 34 integration = 369 tests, all green.

Reviewer note: addresses the duplication comment from midt-bg#177 (ydimitrof
on c733245).
LyuboslavLyubenov pushed a commit to LyuboslavLyubenov/sigma that referenced this pull request Aug 10, 2026
The merge of main into ralph/web-route-integration brought in new unit
tests, shifting the totals: 31 unit files / 335 unit tests, 7 integration
files / 34 integration tests, 38 files / 369 tests total. The previous
counts in apps/web/test/README.md (30 / 284, 37 / 318) were stale.

Also drop a note that fixture declarations and SQL helpers now live in
helpers/fixtures.ts (shared between setup.ts and global-setup.ts), so
future maintainers editing the seed know where the source of truth is.

Reviewer note: addresses the README/PR-description drift comment from
midt-bg#177 (ydimitrof on e5e7cf7, repeated on c733245 after the main merge).
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Aug 10, 2026
…omes, drop redundant globalSetup

Nine review threads on the integration-test lane (PR midt-bg#177):

T-002 — contracts-csv "cheater" 200||500 assertion. The disjunction passed even
if /contracts.csv always 500'd in production. Gate the expected outcome on the
build mode (import.meta.env.DEV): DEV asserts the documented devalue 500; a
prod/pre-built lane asserts the 200 contract. A status outside the mode's
expectation now fails loudly instead of being tolerated.

T-003 — redundant vitest globalSetup. global-setup.ts booted a proxy, ran
migrations, seeded fixtures, then disposed — but vitest runs each test file in
its own worker, so globalThis.__SIGMA_PROXY__ was not visible to tests (setup.ts
already bootstraps per-worker). Removed global-setup.ts, unwired it from the
config, and updated setup.ts / fixtures.ts / README / sibling test comments to
reflect per-worker lazy bootstrap as the only path.

T-004 — stripSqlCommentsAndCollapse corrupted string literals. The per-line
`--` strip ran before the string-aware split, so `'a--b'` became `'a`; and
collapse-whitespace mangled `'a   b'` → `'a b'`. Rewrote as a single string-
aware char scanner (comment strip + statement split + whitespace collapse all
honour in-string state). Added helpers/fixtures.test.ts (7 tests) covering
good/bad paths including the two regression cases. TDD: failing tests first.

T-005 — duplicated server.deps.inline. Defined identically at top-level
`server` (Vite dev-server, unused by `vitest run`) and `test.server`. Removed
the top-level copy with an explanatory comment.

T-006 — dead exclude config. The exclude list targets paths the include glob
never matches. Kept it as a defensive safety net with a comment explaining why
(it blocks accidental double-runs if `include` is ever widened).

T-007 — comment/regex mismatch in compareSemverDesc. The comment described a
`(peer-deps-hash)` parens flavour that does not occur in pnpm store dir names
(only in resolved package.json deps); the actual store dirs use plain semver or
`_`-delimited peer-dep suffixes. Rewrote the comment to describe the real
formats.

T-008 / T-009 — missing trailing newline in routes.test.ts and
sitemaps.test.ts. Added.

T-010 — rate-limit 500 masking. assertCsvNonRateLimitedResponse accepted any
500 whose body matched the devalue text, which could mask a real regression
with the same shape. Added a hard `not.toBe(429)` floor (rate-limit leak fails
loudly regardless of body), gated the 500 acceptance on import.meta.env.DEV,
and linked the tolerance to the ADR-0002 deferred item.

Validation: integration lane 8 files / 41 tests pass (was 7 / 34, +7 new
fixtures tests); unit lane 31 files / 335 tests pass; `pnpm typecheck` exit 0.
LyuboslavLyubenov added a commit to LyuboslavLyubenov/sigma that referenced this pull request Aug 10, 2026
…p version (T-001)

PR midt-bg#177 review T-001 (non-blocking): the `.find()` fallback picked the first
@opentelemetry/api store entry after a descending semver sort. If pnpm ever hoists
two versions, that can differ from the version the app actually imports, silently
aliasing the wrong build/esm.

Extract the store-walking logic into a pure, unit-tested helper `pickOtelStoreEntry`
that prefers an EXACT match on the version the app declares in package.json
(stripping semver range operators and ignoring the `_…` peer-dep hash), falling back
to the highest semver when the app version is absent. Both branches are deterministic.

TDD: 7 tests covering empty store, exact match (incl. peer-dep hash suffix),
fallback to highest semver, determinism under input reordering, and ignoring
unrelated @opentelemetry/* packages. Integration lane 9 files / 48 tests pass;
typecheck exit 0.
LyuboslavLyubenov and others added 11 commits August 13, 2026 13:01
Vitest project alongside the unit suite that boots the real SSR Worker pipeline (workers/app.ts) through wrangler.getPlatformProxy() with seeded D1 + Cache + the four RateLimit bindings. Adds an appFetch(request) helper plus header-contract assertions (security headers, Content-Type, Cache-Control, X-Edge-Cache, Retry-After on 429, Content-Disposition on CSV). Covers /search, /companies, /authorities, /contracts, /contracts/:slug, /contracts/:slug.json, /contracts.csv, the four /sitemap*.xml routes, and /robots.txt, including a real CSV rate-limit burst (11th request from a fixed CF-Connecting-IP → 429) and a midt-bg#87 keyset pagination regression for /contracts?cursor=…. ADR at docs/spec/integration-testing.md documents the harness choice and tradeoffs vs. unstable_dev / hand-rolled Node fetch / per-route handler tests; runbook at apps/web/test/README.md. pnpm --filter @sigma/web test → 318 passed (284 unit + 34 integration); pnpm --filter @sigma/web typecheck → exit 0.
setup.ts and global-setup.ts each inlined ~60 lines of identical SQL
helpers and fixture constants. The duplication was a drift hazard — any
change to the fixture seed had to be made in lockstep in both files.

Move stripSqlCommentsAndCollapse, buildContractsInsert, and the seven
FIXTURE_* constants (plus a canonical FIXTURE_STATEMENTS array) into a
new helpers/fixtures.ts module that both files now import. Behaviour is
unchanged: same SQL emitted, same apply order, same INSERT OR IGNORE
semantics.

Test count and outputs unchanged: pnpm --filter @sigma/web test still
runs 335 unit + 34 integration = 369 tests, all green.

Reviewer note: addresses the duplication comment from midt-bg#177 (ydimitrof
on c733245).
resolveOtelEsmRoot's pnpm-store fallback picked the first matching
@opentelemetry+api@* entry via Array.find. If the store ever hoists
more than one version of @opentelemetry/api, .find() takes whichever
the readdir returned first — which depends on inode order and is not
stable across reinstalls.

Sort the candidate entries by semver (descending) before .find() so
the resolution is fully deterministic: same input, same output, every
time. The pnpm-specific <semver>(<peer-deps-hash>) suffix is stripped
before numeric comparison; tie-breaks in the suffix are not exercised
by the current single-hoist install.

The primary require.resolve path is unchanged and covers the normal
case; this only affects the fallback.
The merge of main into ralph/web-route-integration brought in new unit
tests, shifting the totals: 31 unit files / 335 unit tests, 7 integration
files / 34 integration tests, 38 files / 369 tests total. The previous
counts in apps/web/test/README.md (30 / 284, 37 / 318) were stale.

Also drop a note that fixture declarations and SQL helpers now live in
helpers/fixtures.ts (shared between setup.ts and global-setup.ts), so
future maintainers editing the seed know where the source of truth is.

Reviewer note: addresses the README/PR-description drift comment from
midt-bg#177 (ydimitrof on e5e7cf7, repeated on c733245 after the main merge).
…omes, drop redundant globalSetup

Nine review threads on the integration-test lane (PR midt-bg#177):

T-002 — contracts-csv "cheater" 200||500 assertion. The disjunction passed even
if /contracts.csv always 500'd in production. Gate the expected outcome on the
build mode (import.meta.env.DEV): DEV asserts the documented devalue 500; a
prod/pre-built lane asserts the 200 contract. A status outside the mode's
expectation now fails loudly instead of being tolerated.

T-003 — redundant vitest globalSetup. global-setup.ts booted a proxy, ran
migrations, seeded fixtures, then disposed — but vitest runs each test file in
its own worker, so globalThis.__SIGMA_PROXY__ was not visible to tests (setup.ts
already bootstraps per-worker). Removed global-setup.ts, unwired it from the
config, and updated setup.ts / fixtures.ts / README / sibling test comments to
reflect per-worker lazy bootstrap as the only path.

T-004 — stripSqlCommentsAndCollapse corrupted string literals. The per-line
`--` strip ran before the string-aware split, so `'a--b'` became `'a`; and
collapse-whitespace mangled `'a   b'` → `'a b'`. Rewrote as a single string-
aware char scanner (comment strip + statement split + whitespace collapse all
honour in-string state). Added helpers/fixtures.test.ts (7 tests) covering
good/bad paths including the two regression cases. TDD: failing tests first.

T-005 — duplicated server.deps.inline. Defined identically at top-level
`server` (Vite dev-server, unused by `vitest run`) and `test.server`. Removed
the top-level copy with an explanatory comment.

T-006 — dead exclude config. The exclude list targets paths the include glob
never matches. Kept it as a defensive safety net with a comment explaining why
(it blocks accidental double-runs if `include` is ever widened).

T-007 — comment/regex mismatch in compareSemverDesc. The comment described a
`(peer-deps-hash)` parens flavour that does not occur in pnpm store dir names
(only in resolved package.json deps); the actual store dirs use plain semver or
`_`-delimited peer-dep suffixes. Rewrote the comment to describe the real
formats.

T-008 / T-009 — missing trailing newline in routes.test.ts and
sitemaps.test.ts. Added.

T-010 — rate-limit 500 masking. assertCsvNonRateLimitedResponse accepted any
500 whose body matched the devalue text, which could mask a real regression
with the same shape. Added a hard `not.toBe(429)` floor (rate-limit leak fails
loudly regardless of body), gated the 500 acceptance on import.meta.env.DEV,
and linked the tolerance to the ADR-0002 deferred item.

Validation: integration lane 8 files / 41 tests pass (was 7 / 34, +7 new
fixtures tests); unit lane 31 files / 335 tests pass; `pnpm typecheck` exit 0.
…p version (T-001)

PR midt-bg#177 review T-001 (non-blocking): the `.find()` fallback picked the first
@opentelemetry/api store entry after a descending semver sort. If pnpm ever hoists
two versions, that can differ from the version the app actually imports, silently
aliasing the wrong build/esm.

Extract the store-walking logic into a pure, unit-tested helper `pickOtelStoreEntry`
that prefers an EXACT match on the version the app declares in package.json
(stripping semver range operators and ignoring the `_…` peer-dep hash), falling back
to the highest semver when the app version is absent. Both branches are deterministic.

TDD: 7 tests covering empty store, exact match (incl. peer-dep hash suffix),
fallback to highest semver, determinism under input reordering, and ignoring
unrelated @opentelemetry/* packages. Integration lane 9 files / 48 tests pass;
typecheck exit 0.
…tstrap from env.DB scan

After upstream's migration 0002 added contracts.current_value_currency (read by
getContract → packages/db/src/queries/details.ts), the integration test proxy
only loaded migrations 0000 and 0001. The local D1 therefore lacked the column
every contract-route loader reads, and tests hitting /contracts/:id or
/contracts/:id.json returned 500 instead of 200/404. Apply 0002 in setup.ts.

The read-only D1 chokepoint guard (apps/web/app/lib/readonly-db-chokepoint.test.ts
midt-bg#199/midt-bg#225) forbids env.DB in any web source. test/integration/setup.ts must use
proxy.env.DB.exec() to apply migrations — schema admin, not application data
access, and only runs inside the vitest integration config (not the deployed
Worker). Exempt that single file from the scan with a rationale comment so the
chokepoint stays hermetic for everything else.
…lint

Eleven files in the PR's test/config surface had pre-existing prettier debt that
the upstream prettier version (3.8.3) flags: the integration test files, the
vitest integration config + workspace, and the root README. Same content,
whitespace only. The lint gate is blocking on these (AGENTS.md / repo CI), so
this is non-optional for merge.

Verified: pnpm typecheck, pnpm --filter @sigma/web test → 530 passing (52
files, 8 integration files, 41 integration tests), pnpm lint clean.
@LyuboslavLyubenov
LyuboslavLyubenov force-pushed the ralph/web-route-integration branch from 5815601 to 52cf093 Compare August 13, 2026 10:02
@LyuboslavLyubenov

Copy link
Copy Markdown
Author

Daily autonomous review — rebase pass.

No new reviewer activity since 2026-08-05. All 18 review threads remain isResolved: true. Reviewers' last substantive positions are conditional approvals pending green CI (lyubomir-bozhinov 2026-07-28, ydimitrof 2026-07-28).

Branch was BEHIND upstream/main by 11 commits — rebased onto current upstream/main (426e2ef). Head is now 52cf093, mergeable=MERGEABLE, mergeStateStatus=BLOCKED (fork PR awaiting maintainer workflow approval for CI).

Approach. Local rebase of upstream/main onto ralph/web-route-integration — clean automatic rebase, no conflicts. Only PR-owned file touched upstream-side: docs/README.md (1-line ADR-0032 entry added by docs: spec-side merge).

Verification (local).

  • pnpm --filter @sigma/web typecheck → exit 0
  • pnpm --filter @sigma/web test → 530 passing (52 files, 41 integration tests, 0 .skip)

State. No new commits to PR surface (only upstream drift). Open thread tracking unchanged from 2026-08-05: 0 unresolved threads. Coordination follow-up from lyubomir-bozhinov (2026-07-28) for extending contracts-detail-json.test.ts with X-Robots-Tag: noindex + masking + .data case remains deferred until #183 merges — lane is built and ready.

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.

4 participants