Как это считается
Формула публикуется вместе с результатом. Стыдно показать формулу – значит, ранжировать рано.
Оси считаются отдельно и в одно число не сводятся. Сложите «этим пользуются» с «это ещё живо», и получится топ, про который нельзя сказать, что в нём сложено.
adoption: этим пользуются?
Есть ли следы реального использования, а не только пресс-релиз?
Каждый компонент считаем как log(1+значение) / log(1+опора). Логарифм здесь потому, что расстояние между 1k и 10k звёзд важнее расстояния между 100k и 110k. Опора (`ref`) – максимум по тем записям карты, у которых компонент есть; прогон пересчитывает её заново и печатает в data/scores.json, чтобы число можно было воспроизвести. Опора именно максимум. Возьми мы перцентиль пониже, всё, что выше p90, упиралось бы в единицу, и десяток самых заметных записей выглядел бы одинаково. Шкала относительная: «на фоне остальной карты». Другой у нас нет, и читать это надо буквально – смена состава карты двигает числа. Итог – взвешенное среднее по тем компонентам, которые у записи есть. Веса нормируем на присутствующие: запись с одним HN не сравнить с записью, у которой есть и токены, и звёзды. Чтобы это не потерялось, рядом стоит `coverage`: доля весов, которую вообще удалось измерить. Значение adoption без coverage читать нельзя.
| компонент | вес | источник | что именно меряет | измерено | опора шкалы |
|---|---|---|---|---|---|
openrouter_tokensтокены через OpenRouter | 0,50 | openrouter-apps | единственный прямой замер потребления, а не внимания | 6 зап. | 582 243 646 036 токенов за неделю |
github_starsзвёзды репозитория | 0,30 | github-api | внимание разработчиков; накопленный итог, не прирост | 24 зап. | 164 323 звёзд |
hn_points_maxочки лучшего обсуждения на HN | 0,20 | hn-algolia | ранний сигнал интереса, до медиа | 150 зап. | 2 153 очков, окно 180 дней |
В каталоге каждый компонент есть и сам по себе: своей меткой на карточке и своей сортировкой. Сравнивать между записями честно только значения одного компонента: токены с очками HN несоизмеримы, и сводное число это различие как раз прячет. Поэтому сводная сортировка подписана оговоркой, а рядом с ней стоят три отдельные.
Веса ниже – произвол, и признать это честнее, чем обосновывать задним числом. Поэтому в данные идёт и итог, и каждый компонент со своим источником и датой: несогласие с весами лечится пересчётом. Второе ограничение – здесь абсолютные значения, динамики пока нет. Прирост за 90 дней поймал бы новичка, накопленный итог награждает старое. Динамика появится, когда накопится история прогонов.
liveness: это ещё живо?
Есть ли признаки жизни у продукта прямо сейчас?
Класс ставим по последнему коммиту в репозитории записи; релиз и статус ссылки идут рядом как свидетельства. liveness – класс, а не балл, поэтому с adoption он не складывается.
| класс | правило | записей в карте |
|---|---|---|
| активен | коммит за последние 60 дней | 22 из 348 |
| замедлился | последний коммит 60–180 дней назад | 1 из 348 |
| затих | последнего коммита больше 180 дней | 1 из 348 |
| не отвечает | репозиторий заархивирован или ссылка не открылась при проверке | 1 из 348 |
| не измеряется | репозитория в записи нет, машиночитаемых признаков жизни тоже | 323 из 348 |
Репозиторий есть у меньшинства записей: у закрытого SaaS признаков жизни в машиночитаемом виде просто нет. Статус ссылки сам по себе жизнью не считается, работающий сайт бывает и у брошенного продукта. Поэтому запись без репозитория получает «не измеряется».
fit: подходит под конкретную задачу?
Что делать человеку, который пришёл с задачей, а не с названием продукта?
Только эта ось отвечает на вопрос, с которым человек приходит. Первые две – гигиена: они отсеивают мёртвое и маргинальное, но выбор за человека не делают. Продукт с 40k звёзд не лучше продукта с 3k, если задача другая.
Здесь правило вместо числа. У задачи есть уточняющие вопросы с заранее объявленными вариантами ответа; правило перечисляет, какие ответы должны совпасть, какие записи карты оно называет и почему именно их. Первое сработавшее правило идёт ответом «сначала», остальные сработавшие идут за ним. На странице видно всё целиком: что сработало и почему. Исход помечен классом: «ничего не покупать», «поднять у себя» или «отдельный продукт». Ради первого слой задач и заводился. Большинство вопросов «какой AI для X» закрывается внутри уже оплаченной подписки, а каталог, который об этом молчит, продаёт вместо того, чтобы помогать. Правила и записи карты связаны по id. Правило, которое ссылается на несуществующую или снятую с публикации запись, останавливает сборку: в интерфейсе такой ответ выглядел бы как «варианта нет», и заметить это было бы некому.
| исход | сколько правил | что значит |
|---|---|---|
| отдельный продукт | 58 правил | придётся завести ещё один аккаунт и ещё один счёт |
| поднять у себя | 22 правила | открытый код: платите железом и временем, не подпиской |
| ничего не покупать | 4 правила | работает внутри того, что уже оплачено или уже стоит |
Эту ось никто не измерял. Adoption и liveness мы считаем по источникам с датами, а правила задач написал человек по опыту, и они устаревают вместе с отраслью. Ставить их в один ряд с посчитанным было бы подлогом, поэтому здесь нет ни числа, ни сортировки. У каждой задачи есть поле `reviewed`. Пока оно пустое, на задаче прямо в интерфейсе стоит пометка «черновик»: правила уже работают, но автор их ещё не подтвердил.
Модели: общий score не считается
Формула для моделей стоит в roadmap.md. Данных на неё хватает уже на 0.90 весов: quality_index (0.35) и price_efficiency (0.20) закрывает Artificial Analysis, adoption (0.25) – OpenRouter, availability (0.10) – число провайдеров в каталоге. Открыт последний компонент, human_preference (0.10): это LMArena, источник приоритета 3. Решение зафиксировано 2026-08-01 в data/methodology-decisions.yaml: facts-only до появления LMArena. Модельный уровень отдаёт факты порознь – качество, цену, скорость, длину контекста и число провайдеров. Их можно сортировать по одному показателю, но они не складываются в общий порядок. Если источники расходятся, на странице моделей показаны оба числа со своими источниками; режимы рассуждения Artificial Analysis тоже не усредняются.
Откуда числа
Ни одного числа без источника и даты. У каждого сигнала две даты: когда значение стало таким и когда источник это подтвердил в последний раз. Иначе ежедневный прогон давал бы дифф из одних дат. Источник промолчал – прежнее значение остаётся и получает пометку «не подтверждено»; выдумать его нельзя.
| источник | что даёт | чем сшивается с записью | кого не видит |
|---|---|---|---|
openrouter-modelsOpenRouter /api/v1/models | список моделей, цены за токен, длина контекста, модальности, knowledge_cutoff, hugging_face_id, benchmarks | имя вендора = имя записи после нормализации | модели, которых нет у провайдеров OpenRouter; закрытые внутренние |
openrouter-appsOpenRouter Rankings / apps | потребление токенов по моделям и приложениям – единственный прямой замер использования продуктов | домен origin_url приложения = домен записи | продукты с прямым контрактом с провайдером (Cursor) через OpenRouter не ходят и не видны вообще; в рейтинге только первые 20 за окно |
models-devmodels.dev | каталог моделей и провайдеров в машиночитаемом виде | id или имя провайдера = имя записи после нормализации | то, что не заведено в каталог его составителями |
github-apiGitHub API | звёзды и их динамика, последний коммит, релизы, контрибьюторы | поле github записи. Не заполнено – сигнала нет, угадывать репозиторий по имени нельзя | закрытый SaaS без репозитория – а это большая часть продуктового слоя |
hn-algoliaHN Algolia | запуски и обсуждения с очками – ранний сигнал, до медиа | домен ссылки в истории = домен записи. По имени не сшиваем: «Cursor» на HN – ещё и курсор в SQL | неанглоязычное и то, что не запускалось на HN |
huggingfaceHugging Face API | скачивания за 30 дней и лайки по открытым весам – моделям и организациям | hf_id модели из каталога (пришёл от OpenRouter) – для моделей; для записей карты организация HF, чьё имя или fullname точно совпали с именем записи, плюс поле hf_id записи | закрытые веса: у GPT и Claude на HF нет ничего. Скачивание веса – не пользователь: одна CI-сборка тянет модель столько же раз, сколько живой человек |
artificial-analysisArtificial Analysis | качество, цена, скорость в единой шкале | слаг или имя создателя модели точно совпали с именем записи карты – для записей; для моделей нормализованный слаг AA, совпавший с ключом каталога (модель, которой в каталоге нет, по слагу AA не заводится: плодить двойников с разной пунктуацией хуже, чем не сшить) | модели вне их замеров; ноль в цене и скорости у них значит «не мерили», а не «ноль» |
npmnpm registry | скачивания пакета за 30 дней – прокси реального внедрения | поле npm записи. Не заполнено – сигнала нет: имя пакета угадывать нельзя так же, как репозиторий | продукты без публичного пакета; CI, зеркала и транзитивные зависимости раздувают числа – установка не равна выбору |
pypiPyPI (pypistats) | скачивания пакета за 30 дней | поле pypi записи | то же, что у npm |
link-checkcheck_links.py | статус ссылки и last_verified – вход оси liveness | – | антибот-защита (blocked) про судьбу продукта не говорит ничего |
Расхождение источников не усредняется: если у одной модели цена или длина контекста у двух каталогов разная, в данных лежат оба числа со своими источниками. Усреднить их значит потерять сам факт расхождения.
Четвёртый исход: «не измеряется»
Он полноправный. Для закрытого SaaS без репозитория, без OpenRouter и без запуска на HN честный ответ – пустые оси и фактические характеристики. Пустая ось значит «нечем измерить», а не «плохой продукт». Дорисовать число, чтобы строка таблицы не выглядела бедно, – ровно то, за что этот проект ругает чужие каталоги.