docs(web): методологията описва точно таблата — формули, обхват, изключения#193
docs(web): методологията описва точно таблата — формули, обхват, изключения#193StanislavBG wants to merge 26 commits into
Conversation
…ns, overrun index)
The popover often renders inside a thead th whose white-space: nowrap is inherited by every line of the card, so long summaries and the mono readout ran past the right edge. Reset wrapping on .metric-info-pop (white-space: normal + overflow-wrap: anywhere), widen the card to 320px clamped to the viewport (min(320px, 100vw - 16px)), and add the JS shift-into-viewport + coarse-pointer 44px hit area so all copies of the component behave identically.
The обзор cross lens now re-runs the combo chart, year cards and totals server-side for the ticked CPV groups (repeatable ?cpv, validated 5-digit codes, deduped, capped at 10), and the chart stretches to fill its card against the CPV list. One aggregate scan via an OR of half-open cpv_code index ranges; ?cpv stays keyed in the edge cache (CWE-349) with UI-canonicalized ordering, and selection changes are announced via an sr-only status line.
The by-sector aggregate grouped on substr(t.cpv_code, 1, 2) and then ran cpvDivision() over the already-truncated prefix, so a dirty code like ' 45000000' resolved to division '4' there while the leaderboard (cpvDivision over the full code) resolved it to 45 — the same contract landed in different CPV sectors on the two surfaces. Select the full t.cpv_code, GROUP BY it in SQL, and run cpvDivision() on the full code in JS exactly like the leaderboard mapping; the existing merge folds all codes onto their canonical division and re-applies secLimit post-merge. Test covers a dirty leading char flowing through both surfaces to the same division.
…he full cpv_code Grouping by the full cpv_code fixed the dirty-code divergence but returned one row per distinct 8-digit code — 582 rows on the local corpus (thousands at scale) shipped out of D1 for a 15-row table. SECTOR_KEY_SQL strips the separator characters real codes carry and takes substr(clean, 1, 2) only when the cleaned code provably starts with two digits (in which case it IS cpvDivision(code)); anything else falls through as the full raw code for the JS re-key to fold in. Exact cpvDivision semantics, division-sized result set, still no pre-merge LIMIT truncation. Adds a sqlite3-CLI integration test pinning SECTOR_KEY_SQL ≡ cpvDivision across the dirt corpus, and a unit test pinning the GROUP BY key against both traps (naive substr, full-code blowup).
Every column header in „Кои институции раздуват най-много" and „Раздуване по сектори" now carries the same ⓘ MetricInfo popover the headline KPIs use: what the metric is, how it is computed (grounded in the SQL — growth is SUM(delta)/SUM(signing), €-weighted, not an average of percents), and the honest inclusion caveat (annex_count > 0, current > signing, signing ≥ €1 000). Table header cells get white-space: nowrap so the ⓘ never wraps the label. Also: the „Договори по мащаб" leaderboard rows gain right-side breathing room (row padding-right var(--s-3)) so value text and truncated titles no longer touch the card edge; the inset lives on the row, so the selected highlight still reads full-width and the proportional bar-track math is untouched in normal and fullscreen mode.
…compare lens (review)
…ючения Добавя раздел „Аналитичните изгледи" в /methodology с описание на всяко табло (Анализи, Обзор, Конкуренция, Раздуване, Потоци, Карта, Мрежа, Договори): какво показва визуалът, формулата с думи, обхватът и изключенията, и честните уговорки — сверено ред по ред срещу кода. Само документация; без промяна в поведението.
f5f8fb5 to
7413f87
Compare
|
@todorkolev готов за ревю 🙏 — rebase-нат на main, CI зелен, prettier-чист, CSS промените в styles/* (app.css само @import). Резолвнати нишки. Approve-ни когато ти е удобно. |
|
Проверих PR #193 внимателно — целият собствен diff, всяко фактическо твърдение в текста срещу кода на loader-ите и заявките, плюс сигурност и цялост на данните. Обхват на промянатаВъпреки че diff-ът срещу Сигурност и цялост на данните
Сверяване на твърденията срещу кода (цялост)Тъй като PR-ът обещава „сверено ред по ред срещу кода", проверих локално всяко число и формула. Всички съвпадат точно:
Не открих нито едно разминаване между текста и поведението на кода. Уговорките („ориентир, не заключение", „ръстът не е нередност", „типичната цена е само ориентир") са честни и точно поставени — точно това, което искаме от методологична страница пред граждани. Бележки (незадължителни, не блокиращи)
CI е зелен, prettier/typecheck минават, 377 теста зелени (документационна промяна не добавя тестова повърхност — приемливо тук). Благодаря за изрядно свършената работа — рядко се вижда методология, сверена буквално срещу заявките. ВЕРДИКТ: Approve на същество — да се слее само след стека #169–#172 (draft, blocked по дизайн). Няма проблеми със сигурността или целостта на данните. |
|
Одобрявам Ревю на PR #193 — „методологията описва точно таблата"Прегледах промяната строго, с акцент върху сигурност, цялост на данните и точност спрямо кода. Разграничих собствената промяна на PR-а от подлежащия стек. Обхват — какво реално въвежда този PRДифът показва ~9,6 хил. реда, но собствената промяна е един-единствен комит ( Промяната е само документация: нов раздел „7. Аналитичните изгледи" в Сигурност / OWASPЧисто — тук няма атакуема повърхност:
Цялост на данните — сверих всяко твърдение ред по ред срещу кодаТова е същината при документация, която обещава „сверено срещу кода". Всички числени твърдения съвпадат точно:
Не открих нито едно разминаване между текста и поведението на кода. Съответствие с описанието на PR-аОписанието твърди „единственият променен файл е Дребни, незадължителни бележки (не блокират)
Отлична, честна и точна работа — тонът „ориентир, не заключение" е спазен навсякъде. |
|
Ре-проверих раздел 7 срещу кода — една точна неточност по стойностната база (иначе HHI/конкуренция и праговете за раздуване са верни): Формулировките, че договорите с непотвърдена стойност „се изключват от сумите" (увод на раздел 7, ~ред 408) и „не се сумират" („Договори — обзор", ~ред 536), са неверни за сайт-широките суми в евро:
Т.е. договор с типо €5 млрд, маркиран value_suspect, НЕ се вади от /trends, /contracts, /competition, /regions — влиза при proc estimate. Читателят е упътен обратното. Коригирайте двете места: value_suspect договорите се включват при прогнозната си стойност (или „суровата стойност се заменя с прогнозна", ако това е замисълът). NB: за „Раздуване след анекси" (~ред 482) твърдението е вярно — там annex_suspect има NULL |
Both the section-7 intro and the /contracts description said implausible-value contracts are excluded from site-wide EUR sums. They're actually repaired to the procedure's estimated value and included (normalize-raw.sql:357) — trend/competition/home totals sum them at that value. Only the overrun view is correctly described as excluding them (no current value to compare against).
|
Благодаря — §7 вече е точен: „…влизат в сумите по прогнозната стойност на процедурата, не по подадената — с изключение на „Раздуване след анекси"" (ред 409-410). Това затваря основната находка. Едно остатъчно разминаване: §6 редът „Непотвърдени стойности" (ред 210) още казва „стойността им се изключва от сумите", което сега противоречи на §7 (влизат по прогнозна). Читател само на §6 остава подведен. Изравни §6 — напр. „суровата стойност се заменя с прогнозната, която влиза в сумите" вместо „се изключва". (Ред 397 — чужда валута без намерен курс → NULL |
Какво
Разширява
/methodologyс нов раздел „7. Аналитичните изгледи: какво показват и как се смятат" — по едно описание за всяко аналитично табло, сверено ред по ред срещу кода на loader-ите и заявките, а не преразказано по памет.За всяко табло: какво показва визуалът, формулата с думи, обхватът и изключенията, и честните уговорки — в съществуващия тон (неутрален, описателен, „ориентир, не заключение"), на български, с препратки към речника и раздела за стойността.
Обхванати табла: Анализи (индекс), Договори — обзор (три ъгъла + типични цени по CPV), Конкуренция (една оферта + HHI), Раздуване след анекси, Потоци, Карта, Мрежа, Договори.
Ключови сверявания срещу кода:
bids_received = 1, само с известен брой оферти, ≥ 20 договора); HHI = сбор от квадратите на дяловете (0–1, ≥ 0,25 висока концентрация, ≥ 2 доставчика).Обхват
Само документация — няма промяна в поведението.
methodology.tsxе единственият променен файл.Проверки
pnpm --filter @sigma/web typecheck— зеленоprettier --check .— зеленоpnpm --filter @sigma/web test— 377 теста зелениЗависимости
Draft: зависи от стека #169–#172, защото описва таблата, които те въвеждат (петте карти на
/analytics, обзорът на/trends,/overruns). Ще се извади от draft, след като стекът се слее.