惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
G
GRAHAM CLULEY
Spread Privacy
Spread Privacy
Last Week in AI
Last Week in AI
腾讯CDC
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
C
Cybersecurity and Infrastructure Security Agency CISA
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 司徒正美
爱范儿
爱范儿
雷峰网
雷峰网
The Hacker News
The Hacker News
S
SegmentFault 最新的问题
Cisco Talos Blog
Cisco Talos Blog
博客园 - 聂微东
T
Tor Project blog
I
Intezer
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Schneier on Security
Schneier on Security
T
Tenable Blog
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
AI
AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
O
OpenAI News
博客园 - 【当耐特】
博客园 - Franky
AWS News Blog
AWS News Blog
罗磊的独立博客
J
Java Code Geeks
Know Your Adversary
Know Your Adversary
A
Arctic Wolf
小众软件
小众软件
量子位
SecWiki News
SecWiki News
S
Security Affairs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
N
News and Events Feed by Topic
Apple Machine Learning Research
Apple Machine Learning Research
H
Heimdal Security Blog
Google DeepMind News
Google DeepMind News
IT之家
IT之家

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Я собрал линтер для юридического соответствия сайтов. Сложнее всего было отличить Google Analytics от CSS‑переменной
Павел · 2026-06-22 · via Все публикации подряд на Хабре

Средний

9 мин

210

Коротко. Сервис открывает чужой сайт и считает штраф по КоАП. Внутри двухуровневая проверка по 22 правилам: дешёвые эвристики на cheerio там, где хватает регулярок, и Claude через российский прокси там, где нужно понять смысл текста. На выходе балл от 0 до 100, список нарушений со статьями КоАП и вилкой штрафа. Законы в основе: 152-ФЗ о персональных данных, 242-ФЗ о локализации, закон о рекламе, закон о защите прав потребителей. Ниже стек, архитектура и грабли. Самая обидная грабля в том, что \b в JavaScript не образует границу слова перед кириллицей, и детектор молча слепнет на русском тексте.

Зачем я вообще это делал

У меня небольшой сервисный центр по ремонту техники. В какой‑то момент дошли руки до юридической части собственного сайта, я полез читать 152-ФЗ, и довольно быстро стало ясно: требований к обычному сайту с формой заявки куда больше, чем кажется, и разбросаны они по нескольким законам.

В мае 2025 КоАП по части персональных данных переписали: штрафы выросли в разы, появились оборотные за повторные нарушения, отдельная крупная санкция за утечки. При этом требований к сайту наберётся больше двадцати, и они размазаны по нескольким законам и подзаконным актам. Юрист за разовый аудит просит десятки тысяч. Малый бизнес такое не заказывает, пока не прилетит проверка.

Захотелось собрать что‑то на стыке юриста и линтера: автоматический сканер, который читает сайт и говорит «вот тут нарушение, вот статья, вот порядок суммы». Сначала для себя и своего центра, потом понял, что это нужно не только мне — так появился sitelaw.ru.

Сразу оговорюсь: я не юрист. Балл и вилка штрафа в сервисе это эвристика и оценка порядка риска, а не юридическое заключение. Это важная рамка, к ней ещё вернусь.

Стек

Next.js 16.2.4 + React 19 (App Router)
Playwright (headless Chromium)  рендер JS, перехват сетевых запросов, проверка SSL
cheerio                          статический разбор HTML
@anthropic-ai/sdk                Claude через российский прокси api.proxyapi.ru
@react-pdf/renderer              экспорт отчёта в PDF
PostgreSQL (на VPS)              история проверок, биллинг
shadcn/ui + Tailwind v4          интерфейс
ЮKassa                           платежи
DaData                           автозаполнение реквизитов по ИНН

Хостинг: VPS Beget B, 2 ГБ RAM плюс 4 ГБ swap, nginx ведёт на Next.js через PM2.

Отдельная боль: сборка. Next.js 16 с turbopack на двух гигабайтах падает по памяти. Поэтому билд я делаю локально на Mac, а на сервер уходит rsync собранной .next/. Для маленького сервиса это рабочий компромисс, хотя и нелюбимый.

Первая версия, которая хоть что‑то показывала, собралась за пару часов. А вот калибровка норм, чтобы детектор ссылался на правильную часть статьи и не врал в суммах штрафов, тянется до сих пор. Дальше как раз про то, почему.

Архитектура: эвристики там, где можно, LLM там, где нельзя

Главное решение проекта это разделение проверки на два уровня по стоимости и природе задачи.

Уровень 1: эвристики на cheerio

Большая часть правил написана обычным кодом. Каждое правило это отдельный файл в lib/rules/*.ts с функцией check(ctx), которая возвращает результат. Примеры:

  • https-ssl.ts смотрит наличие HTTPS, валидность сертификата, версию TLS;

  • cookie-consent.ts ищет баннер согласия и проверяет его структуру: информационная плашка без кнопок это не согласие, одна кнопка «Принять» без альтернативы тоже;

  • legal-requisites.ts ищет на странице ИНН, ОГРН, название юрлица;

  • foreign-services.ts ловит запрещённые и ограниченные сервисы по списку из 46 штук: Google Analytics, Meta Pixel, разные зарубежные шрифты, капчи, виджеты.

Эвристики дешёвые: миллисекунды на сайт, ноль токенов, детерминированный результат. Проблема у них одна, зато большая: ложные срабатывания на регулярках. Про две самые показательные расскажу в разделе про грабли, там интереснее.

Уровень 2: LLM на том, что регуляркой не возьмёшь

Часть вопросов регуляркой решить нельзя в принципе:

  • соответствует ли политика конфиденциальности 152-ФЗ по структуре, а не просто «есть файл по ссылке». Это надо понимать смысл текста на нескольких страницах;

  • к какому типу относится сайт и не попадает ли он под особые требования (медицина, интернет‑магазин, площадка с пользовательским контентом);

  • какой общий риск с учётом всех нарушений вместе.

Здесь подключается Claude. Я использую две модели на три задачи: дешёвую haiku на классификацию и sonnet на оба смысловых разбора, чтобы не платить за классификацию столько же, сколько за глубокий анализ:

Задача

Модель

Классификация типа сайта

claude haiku 4.5

Разбор политики ПДн

claude sonnet 4.6

Сводный риск‑профиль

claude sonnet 4.6

Free‑тариф работает только на эвристиках, без LLM вообще. Это сознательное решение: анонимная проверка должна быть почти бесплатной для меня, иначе любой всплеск трафика вынесет кассу. Полный пайплайн с двумя вызовами sonnet включается только на платных проверках.

Почему российский прокси, а не Anthropic напрямую

Тут техническое решение упирается прямо в предмет сервиса. Я делаю инструмент, который ругает чужие сайты за трансграничную передачу персональных данных без оснований. Если бы я сам слал HTML проверяемых сайтов напрямую в Anthropic в США, я бы делал ровно то, за что мой же сканер снижает балл.

Поэтому запросы к Claude идут через api.proxyapi.ru, российский прокси с оплатой в рублях. Прокси берёт свою наценку, в итоге одна платная проверка обходится примерно в 12 ₽ против сырой токенной цены около двух центов. Дороже, но это согласуется и с позиционированием, и с поданным уведомлением в Роскомнадзор. Бесплатная проверка на одних эвристиках стоит около 0,1 ₽, фактически только классификатор.

prompt caching: главная оптимизация по деньгам

Системный промпт с правилами, шаблонами политик и примерами это несколько тысяч токенов. Без кеша каждая проверка платит за них заново.

Кешируется именно системный префикс с правилами, он передаётся отдельным параметром system. Уникальный HTML проверяемой страницы идёт в messages и не кешируется:

const system = [
  { type: "text", text: SYSTEM_RULES, cache_control: { type: "ephemeral" } },
];
const messages = [
  { role: "user", content: SITE_HTML }, // уникальный для каждой проверки
];

Проверки идут пачкой: пользователь запустил, правила пошли почти одновременно. Поэтому попаданий в кеш много, и стоимость промптовой части падает в несколько раз. Важная деталь, на которой я сначала споткнулся: кешируемый блок должен быть длинным. Минимальный размер для Sonnet 4.6 это 1024 токена. Поставишь cache_control на короткий префикс, и кеш не сработает, причём без ошибки: cache_creation_input_tokens и cache_read_input_tokens в ответе просто придут нулями.

Грабли, ради которых стоит читать дальше

1. \b в JavaScript не образует границу перед кириллицей

Детектор реквизитов искал ИНН и ОГРН по очевидной на вид регулярке вроде /\bИНН\b/. И тихо не находил их вообще ни на одном русском сайте.

Причина в том, что \b в JavaScript опирается на ASCII‑определение «словесного символа». Кириллическая буква для него не словесный символ, поэтому граница \b перед «И» в слове «ИНН» не возникает никогда. Регулярка не падает, не кидает ошибку, она просто молча не матчит. Самый неприятный класс багов: всё зелёное, тесты на латинице проходят, а на проде детектор слепой.

Чинил через negative lookbehind на русскую букву. Заодно это отсекает ложные хвосты вроде «длинный», «старинный», «финн», где «инн» сидит внутри слова:

const m = text.match(/(?<![А-Яа-яЁё])ИНН[\s:№-]*\d{10,12}(?!\d)/i);

Штатное решение тут это флаг u и Unicode property escapes (\p{L}, ES2018). Я выбрал negative lookbehind на класс [А-Яа-яЁё], потому что мне нужно было заодно отсечь хвосты вроде «длинный» и «финн». Мораль простая и злая: если парсите русский текст регулярками, \b и \w по умолчанию вас обманут на кириллице, об этом надо помнить отдельно.

2. Case‑insensitive G- поймал --bg-card

Детектор Google Analytics 4 искал идентификатор формата G-XXXXXXXXXX. В первой версии регулярка была регистронезависимой. И она радостно сработала на CSS‑переменной --bg-card: внутри bg-card сидит подстрока g-c, а с флагом i это совпадает с G-.

В итоге сервис обвинял в трансграничной передаче данных сайты, у которых из «аналитики» был только аккуратный дизайн на CSS‑переменных.

Чинил тремя ограничениями сразу: убрал регистронезависимость, добавил границу слова и оперся на длину идентификатора (в подавляющем большинстве GA4-ID после G- идёт 10 алфанумериков). Это эвристика, а не гарантированная спецификация Google, поэтому я страхуюсь сильным сигналом рядом:

idPatterns: [/\bG-[A-Z0-9]{10}\b/, /\bUA-\d{4,10}-\d+\b/]

Плюс ввёл уровень «сильных» сигналов: вызов gtag(, домен googletagmanager.com. ID‑паттерн засчитывается только когда рядом на странице есть сильный сигнал. Регулярка без контекста это лотерея.

3. Я.Метрика как ложное «нарушение» на собственном сайте

Метрика хостится в России, поэтому по локализации (242-ФЗ) в трансграничный детектор она попадать не должна. Но мой же детектор однажды сработал на ней как на трансграничной аналитике, потому что она местами инициализируется похожим на gtag способом. Это был ложный матч именно трансграничного правила, а не индульгенция Метрике вообще. Лечилось белым списком российских доменов аналитики, который проверяется до того, как сработает общий детектор.

4. Символ рубля, которого нет в шрифте

Первая версия PDF‑отчёта вместо «₽» рисовала «½». Roboto в варианте cyrillic‑ext не содержит символ U+20BD. Пришлось добавить санитайзер, который перед рендером PDF заменяет «₽» на “ руб.«, бесконечность на „без ограничений“, эмодзи вырезает. Мелочь, которая выглядела как издевательство ровно в том месте отчёта, где написана сумма штрафа.»

5. Самая дорогая грабля оказалась не технической, а юридической

Правило может быть идеально написано как код и при этом ссылаться не на ту часть статьи. У меня детектор cookie‑согласия одно время был привязан к части про «совмещение согласий», хотя ловил он отсутствие согласия как такового, а это другой состав и другая вилка штрафа. Код отрабатывал верно, дефект был именно в привязке к норме: её нужно сверять руками, а не доверять первой похожей статье.

Вывод, к которому я пришёл: каждый номер статьи, части и каждую сумму штрафа надо проверять по первоисточнику, а не по памяти и не по тому, что «вроде так было». Сейчас перед изменением любого правила я сверяю норму на сайте официального публикатора. Это медленно и скучно, и без этого инструмент про право быстро накапливает уверенно звучащие, но неточные ссылки.

6. react‑pdf и длинные отчёты

Открытая до сих пор бяка: при девятнадцати и более нарушениях один из блоков react‑pdf перестаёт разрываться по страницам и уезжает за край. На обычном сайте нарушений меньше, но самые «богатые» экземпляры в отчёт не влезают красиво. Лежит в бэклоге с пометкой починить до того, как пойдут платные продажи в товарных количествах.

Что показал прогон, или зачем вообще брать чужие сайты

Детектор без проверки на реальных данных это гипотеза. Чтобы убедиться, что правила ловят осмысленные вещи, а не раздают случайные баллы, я взял одну B2B‑выборку примерно из восьмидесяти сайтов и прогнал её одним заходом по единой формуле. Картина вышла депрессивная и довольно однородная: средний балл около 38 из 100, выше семидесяти набрал ровно один сайт из восьмидесяти. Самые частые срабатывания везде одни и те же: отсутствие или фрагментарность обязательных реквизитов, форма с одним общим чекбоксом вместо раздельных согласий, cookie‑баннер для галочки, сторонние шрифты и аналитика без оснований.

Я не думаю, что это злой умысел. Скорее сайты делали по шаблонам пятилетней давности, когда половины требований ещё не было, и с тех пор юридическую часть никто не пересматривал. Регуляторы работают по жалобам, а не по профилактике, поэтому нарушения остаются невидимыми ровно до первой жалобы.

Чего ещё нет

Чтобы не создавать впечатление законченного продукта, честный список дыр:

  • Регулярный мониторинг. Подписочные тарифы обещают периодическую перепроверку с алертами. Этого функционала пока нет, он первый в очереди. Сейчас сервис умеет разовую проверку.

  • Тот самый react‑pdf на больших отчётах из пункта 6 грабель.

  • GEO и llms.txt. Поисковики сайт уже видят, а вот citability для ИИ‑ответов я ещё не настроил.

  • Парсер свежих штрафов. Хочется показывать пользователю реальные недавние кейсы «вот за это уже штрафуют», пока руки не дошли.

Итог

Получилось собрать работающую штуку, которая за полминуты читает чужой сайт и переводит юридический туман в конкретный список «вот тут, вот статья, вот порядок суммы». Мониторинг пока не сделал, пара упрямых багов рендера тоже на мне. И почти на каждом шаге выяснялось, что сложность не в законе. Сложность в том, чтобы детектор не врал: не молчал там, где нарушение есть, и не паниковал там, где его нет. А когда нашёл, ссылался на ту часть статьи, которая нужна, а не на соседнюю.

Разбор устройства правил и критику стека читаю в комментариях, на граблях я явно ещё не закончил.

Павел