"""Числа в документации сверяются с кодом, а не живут отдельно (#2464). Оба расхождения ниже — реальные, найденные 20.08.2026, и оба были незаметны: цифра в комментарии не проверяется ничем, а расходится тихо при первой же правке констант. • macro_coefficient: комментарий обещал сумму backed-весов 0.45. С #946 inflation стал backed-каналом с весом 0.08, сумма стала 0.53 — комментарий не обновили. • nspd_client.search_by_quarter: docstring обещал 6/11/22 запроса и ~3.6с/~6.6с/~13с. Фактически три из пяти core-слоёв и ВСЕ zouit/risk идут grid-walk'ом по 49 запросов: 150/395/934 запроса, ~90с/~237с/~560с. Занижение в 25-42 раза — а объём запросов здесь прямой фактор WAF-риска. Гейт сверяет то, что НАПИСАНО, с тем, что ВЫЧИСЛЯЕТСЯ из констант. Красное здесь означает «текст разошёлся с кодом», а не «текст непривычно отформатирован». """ from __future__ import annotations import os os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test") import re from pathlib import Path def test_backed_weight_sum_in_comment_matches_constants() -> None: """Сумма из комментария обязана совпасть с суммой backed-констант.""" from app.services.forecasting import macro_coefficient as mc src = Path(mc.__file__).read_text() m = re.search(r"СУММА backed-весов = ([0-9.]+)", src) assert m is not None, "в файле пропала строка «СУММА backed-весов = …» — гейт ослеп" documented = float(m.group(1)) actual = round( mc._W_RATE + mc._W_MORTG_RATE + mc._W_ISSUANCE + mc._W_OVERDUE + mc._W_INFLATION, 4 ) assert documented == actual, ( f"в комментарии сумма backed-весов {documented}, по константам {actual} — " "текст разошёлся с кодом" ) def _documented_request_counts(src: str) -> tuple[int, int, int]: core = re.search(r"core only:.*?= (\d+) запрос", src) zouit = re.search(r"\+zouit:\s*\+\d+\*\d+\s*= (\d+) запрос", src) risks = re.search(r"\+risks:\s*\+\d+\*\d+\s*= (\d+) запрос", src) assert core and zouit and risks, "в docstring пропала смета HTTP-запросов — гейт ослеп" return int(core.group(1)), int(zouit.group(1)), int(risks.group(1)) def test_request_cost_in_docstring_matches_layer_dispatch() -> None: """Смета запросов обязана следовать из _GRID_WALK_LAYERS, а не из памяти автора.""" from app.services.scrapers import nspd_client as nc src = Path(nc.__file__).read_text() doc_core, doc_zouit, doc_risks = _documented_request_counts(src) grid = set(nc._GRID_WALK_LAYERS) core_layers = [ "parcels", "buildings", "territorial_zones", "red_lines", "engineering_structures", ] grid_n = 7 per_grid = grid_n * grid_n core_grid = sum(1 for c in core_layers if c in grid) core_legacy = len(core_layers) - core_grid n_zouit = len(nc.NSPDClient.QUARTER_ZOUIT_LAYERS) n_risks = len(nc.NSPDClient.QUARTER_RISK_LAYERS) exp_core = 1 + core_legacy + core_grid * per_grid exp_zouit = exp_core + n_zouit * per_grid exp_risks = exp_zouit + n_risks * per_grid assert (doc_core, doc_zouit, doc_risks) == (exp_core, exp_zouit, exp_risks), ( f"docstring обещает {doc_core}/{doc_zouit}/{doc_risks} запросов, " f"по диспетчеризации слоёв выходит {exp_core}/{exp_zouit}/{exp_risks}" ) def test_grid_walk_membership_is_not_empty() -> None: """Контроль на сам гейт: если _GRID_WALK_LAYERS опустеет, расчёт станет тавтологически совпадать с любой мелкой цифрой в docstring.""" from app.services.scrapers import nspd_client as nc grid = set(nc._GRID_WALK_LAYERS) assert len(grid) >= 10, f"grid-walk слоёв всего {len(grid)} — смета считается не по тому" assert "territorial_zones" in grid, "core-слой выпал из grid-walk — пересчитать смету"