{"schema_version":"1.1","name":"TechRole Index: методические разборы","canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights","language":"ru-RU","citation_guidance_url":"https://win-702hpohbtiv.tail044b19.ts.net/citation","articles":[{"slug":"median-vs-average-salary","title":"Медиана против среднего: как читать зарплатные вилки","description":"Почему одно среднее значение не описывает зарплатную выборку и какие поля нужны для воспроизводимой цитаты.","kicker":"Статистика без ловушек","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":6,"keywords":["медиана зарплаты","средняя зарплата","P25","P75","зарплатная вилка"],"introduction":"Медиана и среднее отвечают на разные вопросы. Если свести их к одной подписи «типичная зарплата», редкие высокие вилки, неполные диапазоны и маленькая выборка могут изменить вывод сильнее, чем реальное состояние наблюдений.","sections":[{"heading":"Что именно измеряют две величины","paragraphs":["Среднее складывает все допустимые наблюдения и делит сумму на их число. Оно использует расстояние между значениями, поэтому несколько очень высоких вилок способны заметно сдвинуть результат. Медиана выбирает центральное положение упорядоченной выборки и обычно устойчивее к редким крайним значениям.","Ни одна величина не является автоматически правильнее. Среднее полезно для оценки суммарного уровня значений, медиана - для положения центра. Разница между ними сама по себе является сигналом формы распределения, а не ошибкой, которую нужно спрятать."]},{"heading":"Почему сначала нужен корректный midpoint","paragraphs":["TechRole Index рассчитывает midpoint только для полной вилки с нижней и верхней границей. Одностороннее «от 200 000» нельзя превращать в 200 000: это нижняя граница, а не центр предложения. Такое наблюдение учитывается в coverage и отдельных bound-показателях, но не подменяет midpoint.","После фильтрации совместимых наблюдений проверяется валюта, налоговый статус и размер выборки. Gross, net и unknown не объединяются одной средней. Если совместимых midpoint меньше установленного порога, итог остаётся пустым с пометкой «Недостаточно данных»."]},{"heading":"Зачем показывать P25, P75 и n","paragraphs":["Квартили P25 и P75 очерчивают центральную половину наблюдений. Широкий интервал предупреждает, что одно центральное число скрывает большой разброс. Узкий интервал при маленьком n тоже не гарантирует устойчивость: следующая небольшая порция данных может заметно изменить границы.","Размер выборки n позволяет отличить расчёт от впечатления. Для цитаты недостаточно написать «медиана 180 тысяч». Нужны профессия, seniority, период, валюта, tax basis, n и ссылка на каноническую страницу."]},{"heading":"Как сравнивать две профессии","paragraphs":["Сначала убедитесь, что совпадают период, seniority, география, валюта и налоговый статус. Затем сравните n и coverage, после этого медиану и межквартильный интервал. Среднее используйте как дополнительный показатель чувствительности к высоким или низким значениям.","Если у одной роли quality gate пройден, а у другой нет, корректный вывод звучит как «для второй роли недостаточно совместимых наблюдений». Подставлять ноль или переносить значение соседнего уровня нельзя."]}],"checklist":["Проверить, что midpoint построен только по полным вилкам.","Не смешивать gross, net и unknown.","Публиковать медиану вместе с P25-P75 и n.","Сравнивать только одинаковые периоды и seniority."],"references":[{"label":"Методология TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Глоссарий показателей","href":"https://win-702hpohbtiv.tail044b19.ts.net/glossary"},{"label":"Статус и происхождение данных","href":"https://win-702hpohbtiv.tail044b19.ts.net/data-status"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/median-vs-average-salary","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/median-vs-average-salary/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/median-vs-average-salary/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/median-vs-average-salary/cite/ris"}},{"slug":"insufficient-data-is-not-zero","title":"Почему «Недостаточно данных» лучше красивого нуля","description":"Как отличать отсутствие наблюдений, непройденный quality gate и настоящее нулевое значение.","kicker":"Честные пропуски","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":5,"keywords":["недостаточно данных","нулевое значение","quality gate","размер выборки"],"introduction":"Ноль является измерением. Пустое значение является состоянием знания. Если заменить второе первым, график станет аккуратнее, но смысл данных изменится: роль без достаточной выборки будет выглядеть как роль с доказанным нулевым спросом или нулевой зарплатой.","sections":[{"heading":"Три разных состояния","paragraphs":["Первое состояние - наблюдений действительно нет. Второе - записи есть, но после проверки валюты, границ вилки, seniority и tax basis совместимая выборка слишком мала. Третье - корректно измеренное значение равно нулю, например в конкретный день не найдено классифицированных публикаций.","Эти состояния должны кодироваться по-разному. В JSON отсутствующая статистика остаётся null или не публикуется, а честный count равен 0. В интерфейсе это соответственно «Недостаточно данных» и «0 публикаций»."]},{"heading":"Что делает quality gate","paragraphs":["Quality gate проверяет минимальный размер выборки и совместимость наблюдений до публикации агрегата. Он не доказывает абсолютную точность, но не позволяет одному или нескольким значениям выглядеть устойчивой рыночной оценкой.","Порог должен быть известен читателю. В TechRole Index зарплатные midpoint публикуются при n не меньше 20. Coverage и число записей с зарплатой показываются отдельно, чтобы скрытый агрегат не выглядел отсутствием исходных наблюдений."]},{"heading":"Почему заполнение соседним значением опасно","paragraphs":["Нельзя автоматически переносить медиану Middle на Junior, значение Backend на узкую специализацию или предыдущий месяц на новый период. Это уже модельная оценка, а не наблюдаемый агрегат. Если такая оценка когда-либо понадобится, она должна иметь отдельное имя, версию и диапазон неопределённости.","Нулём также нельзя заполнять пропуск ради сортировки. Для ранжирования лучше явно отправлять недостаточные значения в отдельную группу и объяснять причину."]},{"heading":"Как цитировать отсутствие","paragraphs":["Корректная формулировка: «За указанный период найдено N публикаций, но совместимых полных вилок для уровня Senior меньше минимальной выборки 20, поэтому медиана не публикуется». Она сообщает и наблюдение, и ограничение.","Некорректная формулировка: «Зарплата Senior равна нулю» или «спроса нет», если система лишь не смогла подтвердить показатель."]}],"checklist":["Разделять no records, insufficient sample и measured zero.","Показывать порог quality gate рядом с результатом.","Не заполнять пропуск соседней ролью или периодом без отдельной модели.","В цитате указывать число исходных и совместимых наблюдений."],"references":[{"label":"Методология TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Открытые данные CSV","href":"https://win-702hpohbtiv.tail044b19.ts.net/open-data.csv"},{"label":"Как цитировать","href":"https://win-702hpohbtiv.tail044b19.ts.net/citation"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/insufficient-data-is-not-zero","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/insufficient-data-is-not-zero/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/insufficient-data-is-not-zero/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/insufficient-data-is-not-zero/cite/ris"}},{"slug":"publications-vs-active-vacancies","title":"Публикации против активных вакансий: два разных временных ряда","description":"Почему поток созданных записей нельзя выдавать за исторический остаток одновременно активных вакансий.","kicker":"Спрос во времени","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":6,"keywords":["публикации вакансий","активные вакансии","временной ряд","creation date"],"introduction":"Количество публикаций за день измеряет поток новых записей. Количество активных вакансий на дату измеряет состояние набора записей. Эти ряды могут двигаться в разные стороны и требуют разных исходных событий.","sections":[{"heading":"Поток и остаток","paragraphs":["Публикация относится к одной дате создания. Если за неделю создано сто записей, поток равен ста. Но часть записей может закрыться в тот же день, часть оставаться активной месяц, а часть быть повторной публикацией. Из одного creation date нельзя восстановить ежедневный остаток активных вакансий.","Для ряда активных вакансий нужны либо надёжные даты открытия и закрытия, либо ежедневные snapshots статуса. Без них линия активного спроса будет реконструкцией с неподтверждёнными предположениями."]},{"heading":"Что показывает официальный слой","paragraphs":["Официальный слой TechRole Index группирует классифицированные записи «Работы России» по дате создания внутри скользящего 180-дневного окна. Поэтому заголовок и методология называют их публикациями.","Поле total_publications можно суммировать по периоду, но нельзя читать как число одновременных рабочих мест. Даже уникальный external ID не сообщает, сколько дней запись сохраняла активный статус между двумя наблюдениями."]},{"heading":"Как сравнивать периоды","paragraphs":["Для потока публикаций сравнивают одинаковые окна: например, текущие семь дней с предыдущими семью. Следует учитывать календарные эффекты, неполные дни и изменение полноты ingestion. Один высокий день не доказывает устойчивый тренд.","Для active-stock ряда сравнивают snapshots на согласованных временных точках. Такой ряд должен документировать частоту снимков и правило обработки пропущенного статуса."]},{"heading":"Безопасная формулировка вывода","paragraphs":["Говорите «найдено N классифицированных публикаций за период» и прикладывайте date_from/date_to. Если анализируется изменение, называйте два сравниваемых окна.","Не заменяйте термин на «N активных вакансий», «N открытых позиций» или «рынок вырос на X%», если исходный ряд не содержит соответствующего состояния."]}],"checklist":["Определить, измеряется поток событий или остаток состояния.","Для active stock требовать snapshots или даты закрытия.","Сравнивать одинаковые завершённые окна.","Сохранять слова «публикации» и период в цитате."],"references":[{"label":"Исследование 180-дневного слоя","href":"https://win-702hpohbtiv.tail044b19.ts.net/research"},{"label":"Статус и происхождение данных","href":"https://win-702hpohbtiv.tail044b19.ts.net/data-status"},{"label":"Документация открытого API Работа России","href":"https://trudvsem.ru/opendata/api"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/publications-vs-active-vacancies","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/publications-vs-active-vacancies/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/publications-vs-active-vacancies/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/publications-vs-active-vacancies/cite/ris"}},{"slug":"gross-net-unknown-salary","title":"Gross, net и unknown: почему неизвестную зарплату нельзя назвать gross","description":"Правило совместимости налогового статуса зарплат и причины раздельной публикации слоёв.","kicker":"Совместимость зарплат","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":6,"keywords":["gross зарплата","net зарплата","налоговый статус","salary basis"],"introduction":"Одинаковая валюта не делает зарплаты сопоставимыми. Сумма до удержания налога, сумма после удержания и сумма с неизвестным основанием являются тремя разными состояниями данных.","sections":[{"heading":"Tax basis является частью измерения","paragraphs":["Зарплата 200 000 RUB gross и 200 000 RUB net не означают одинаковое предложение. Если источник не гарантирует basis, аналитическая система не должна выбирать его по умолчанию или выводить из размера суммы.","Поле unknown сохраняет отсутствие знания. Это не промежуточный синоним gross, а запрет на незаметное объединение с подтверждённой gross-выборкой."]},{"heading":"Почему автоматическое преобразование не решает проблему","paragraphs":["Чтобы преобразовать net в gross, нужны подтверждённый исходный basis, применимое налоговое правило и дата. Если basis неизвестен, формула не знает направление преобразования. Любой выбранный коэффициент создаёт вымышленную точность.","Курс валюты решает другую задачу. Он переводит денежную единицу, но не определяет, удержан ли налог. Наличие официального курса ЦБ не разрешает менять unknown на gross."]},{"heading":"Как TechRole Index разделяет слои","paragraphs":["Подготовленная аналитическая витрина содержит gross-метрики. Официальные публикации «Работы России» хранят salary_gross_status=unknown и публикуются отдельным блоком с явной подписью.","Сравнение возможно внутри каждого совместимого слоя. Между слоями можно сравнивать coverage, число публикаций и наличие вилок, но объединённую медиану без нормализуемого basis считать нельзя."]},{"heading":"Что должно быть в цитате","paragraphs":["Рядом с зарплатой укажите currency, seniority, период, n и tax basis. Для unknown используйте буквальную оговорку «gross/net источником не определён».","Если в материале нужны только gross-значения, официальный unknown-слой следует исключить из расчёта, а не переименовать."]}],"checklist":["Считать currency и tax basis независимыми полями.","Не угадывать basis по сумме или названию источника.","Не применять налоговую формулу к unknown.","Публиковать unknown отдельным слоем с явной оговоркой."],"references":[{"label":"Статус и происхождение данных","href":"https://win-702hpohbtiv.tail044b19.ts.net/data-status"},{"label":"Методология зарплат","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Источники","href":"https://win-702hpohbtiv.tail044b19.ts.net/sources"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/gross-net-unknown-salary","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/gross-net-unknown-salary/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/gross-net-unknown-salary/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/gross-net-unknown-salary/cite/ris"}},{"slug":"cbr-requested-vs-effective-date","title":"Requested date против effective date в курсе валют","description":"Как выходные и даты действия курса влияют на воспроизводимость пересчёта зарплат.","kicker":"Валютный provenance","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":5,"keywords":["курс ЦБ","effective date","requested date","валютный курс"],"introduction":"Запросить курс на конкретную дату и получить курс, действующий на эту дату, не всегда означает получить запись с тем же календарным числом. Выходные и праздники делают requested date и effective date разными полями.","sections":[{"heading":"Две даты отвечают на разные вопросы","paragraphs":["Requested date фиксирует намерение расчёта: для какого календарного дня система запросила данные. Effective date приходит от источника и сообщает, к какой дате относится опубликованный набор курсов.","Если запрос сделан для воскресенья, официальный ответ может содержать последний установленный курс с более ранней effective date. Переписывать её воскресеньем означает приписать источнику несуществующую публикацию."]},{"heading":"Зачем сохранять исходный номинал","paragraphs":["Некоторые валюты публикуются не за одну единицу, а за номинал 10, 100 или больше. Rate-to-RUB должен нормализовать значение на одну единицу, но snapshot обязан позволять проверить исходные value и nominal.","Иначе повторный расчёт может дать расхождение даже при совпадающих датах и коде валюты."]},{"heading":"Идемпотентный snapshot","paragraphs":["Надёжный ключ snapshot включает provider, requested date и currency. Повторный запуск не создаёт случайную новую версию, а сверяет или обновляет ту же запись вместе с effective date.","Расчётная запись должна ссылаться на конкретный snapshot, а не запрашивать «текущий курс» во время каждого чтения. Так результат остаётся воспроизводимым после изменения официального курса."]},{"heading":"Граница применения курса","paragraphs":["Официальный курс подтверждает валютное преобразование, но не исправляет неизвестный gross/net, неполную вилку или несовместимый период. Эти проверки выполняются отдельно.","В цитате пересчитанного значения нужны currency source, requested date, effective date и правило nominal normalization."]}],"checklist":["Сохранять requested и effective date отдельно.","Нормализовать официальный nominal на одну единицу.","Ссылаться на snapshot, а не на плавающий текущий курс.","Не считать курс решением неизвестного tax basis."],"references":[{"label":"Источники TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/sources"},{"label":"XML-сервисы Банка России","href":"https://www.cbr.ru/development/sxml/"},{"label":"Описание архитектуры","href":"https://win-702hpohbtiv.tail044b19.ts.net/about"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/cbr-requested-vs-effective-date","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/cbr-requested-vs-effective-date/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/cbr-requested-vs-effective-date/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/cbr-requested-vs-effective-date/cite/ris"}},{"slug":"reproducible-etl-provenance","title":"Воспроизводимый ETL: provenance, quality gate и честная ошибка","description":"Какие следы нужны от источника до публичного агрегата, чтобы результат можно было проверить и исправить.","kicker":"Инженерия доверия","publishedAt":"2026-07-20","updatedAt":"2026-07-20","readingMinutes":7,"keywords":["ETL","data provenance","quality gate","классификация вакансий","Dagster"],"introduction":"Воспроизводимость начинается не с красивого dashboard, а с ответа на вопрос: из какой записи, каким правилом и в каком запуске появился показатель. Если эта цепочка потеряна, исправление превращается в ручное угадывание.","sections":[{"heading":"Идентичность источника и записи","paragraphs":["Каждая вакансия получает source code и внешний identifier. Уникальность пары защищает от повторной вставки одной записи при пересечении поисковых запросов. Название сайта в тексте payload не заменяет проверяемый provider provenance.","Raw payload хранится по privacy allowlist: для аналитики нужны профессиональные поля, но не контакты и адреса. Оригинальный источник, query и run сохраняются отдельно от нормализованных значений."]},{"heading":"Версия классификации","paragraphs":["Профессия и seniority являются результатом классификации, поэтому рядом нужны classifier version и confidence. Объяснимые alias, regex и exclusion rules остаются основным механизмом; uncertain запись не должна автоматически получать уверенный slug.","Локальная модель может предложить ограниченный результат только после rules и schema validation. Её ответ имеет confidence cap и не получает права самостоятельно публиковать агрегат."]},{"heading":"Транзакция и состояние запуска","paragraphs":["Ingestion run фиксирует started_at, finished_at, число просмотренных и изменённых записей, ошибки и параметры. Незавершённый старый run нельзя оставлять вечным running: следующий запуск переводит его в failed с явной причиной прерывания.","Запись данных и итогового состояния должна быть согласована транзакционно. Частичная ошибка не должна выглядеть успешным полным обновлением."]},{"heading":"Quality gate перед публикацией","paragraphs":["До агрегата проверяются валюта, полнота вилки, tax basis, sample size и временное окно. Метрика публикуется только из совместимого слоя. Новая загрузка не обязана перезаписывать существующую витрину, если источник не даёт достаточной совместимости.","Честная ошибка включает безопасное описание причины и request/run ID, но не query с персональными значениями, email или полный payload. Наблюдаемость должна помогать найти этап, не создавая вторую утечку данных."]},{"heading":"Что делает результат цитируемым","paragraphs":["Публичный результат связывает каноническую сущность, период, n, методологию, источник и дату ingestion. Машиночитаемые JSON/CSV повторяют те же оговорки, что видимый HTML.","Если правило изменилось, новая classifier/scoring version позволяет объяснить расхождение. Старое число не переписывается задним числом без следа решения."]}],"checklist":["Сохранять source, external ID, query и ingestion run.","Версионировать classifier и scoring rules.","Не считать interrupted run успешным.","Пропускать агрегат через compatibility и sample-size gates.","Синхронизировать оговорки HTML, JSON, CSV и citation metadata."],"references":[{"label":"Методология TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Источники и provenance","href":"https://win-702hpohbtiv.tail044b19.ts.net/sources"},{"label":"Открытый Data Package","href":"https://win-702hpohbtiv.tail044b19.ts.net/datapackage.json"},{"label":"Исследование официального слоя","href":"https://win-702hpohbtiv.tail044b19.ts.net/research"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/reproducible-etl-provenance","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/reproducible-etl-provenance/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/reproducible-etl-provenance/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/reproducible-etl-provenance/cite/ris"}},{"slug":"what-180-days-of-publications-means","title":"180 дней публикаций вакансий: что на самом деле измеряет временной ряд","description":"Как читать 180-дневное окно по дате создания записи, не превращая публикации в снимок одновременно активных вакансий.","kicker":"Временная семантика","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":7,"keywords":["180 дней вакансий","дата публикации вакансии","временной ряд спроса","creation date","активные вакансии"],"introduction":"Ряд по датам создания отвечает на вопрос о потоке новых публикаций, а не о запасе открытых позиций в каждый день. Эти величины могут двигаться в одну сторону, но не являются взаимозаменяемыми: для восстановления активного остатка нужны надёжные даты открытия, закрытия, повторного открытия и удаления каждой записи.","sections":[{"heading":"Событие публикации и состояние вакансии","paragraphs":["Дата создания записи описывает событие: в этот день источник впервые показал конкретную публикацию. Сумма событий за день позволяет сравнивать интенсивность появления предложений и строить одинаково определённый ряд даже тогда, когда источник не хранит полную историю дальнейших статусов.","Число активных вакансий является состоянием. Для него на конец каждого дня нужно знать, какие записи уже появились и какие ещё не закрылись. Если API отдаёт только текущий статус или не гарантирует историю закрытий, задним числом получить корректный daily stock невозможно. Подмена потока состоянием завышает или занижает рынок непредсказуемо."]},{"heading":"Как устроено окно 180 дней","paragraphs":["Границы периода включаются явно: date_from и date_to сопровождают агрегат и машиночитаемые выгрузки. Нулевая точка внутри окна означает, что классифицированных публикаций с этой датой создания не найдено; она не означает, что в этот день работодатели не держали открытых вакансий этой профессии.","Скользящий итог меняется сразу по двум причинам: в окно входят новые дни и одновременно выпадают самые старые. Поэтому разницу двух 180-дневных сумм нельзя без оговорки назвать приростом рынка. Для короткого тренда TechRole Index сравнивает соседние семидневные средние, сохраняя одинаковую длину окон."]},{"heading":"Дедупликация, задержка и повторная публикация","paragraphs":["Одна запись идентифицируется парой source и external ID. Повторное получение того же объекта не создаёт новое событие. Новая запись работодателя с другим идентификатором может быть самостоятельной публикацией, даже если её текст похож; без доказуемой связи нельзя автоматически объявить её дублем старой.","Последний ingestion может прийти позже даты создания записи. Поэтому рядом с периодом нужна дата загрузки, а незавершённый run не должен выглядеть полным обновлением. Если источник исправил прошлую запись, воспроизводимый процесс обновляет нормализованные поля, но сохраняет происхождение и след запуска."]},{"heading":"Как сравнивать и цитировать ряд","paragraphs":["Сравнивайте профессии на одном источнике, одном календарном окне и одной версии классификации. Узкая роль может иметь меньше публикаций не только из-за спроса, но и из-за терминологии: работодатели используют соседние названия, а строгий классификатор сознательно не принимает неоднозначные совпадения.","Корректная цитата называет показатель публикациями по дате создания, указывает date_from, date_to, итоговое число, источник и canonical URL профессии или исследования. Формулировка «активных вакансий за 180 дней» смешивает состояние и поток; её следует заменить на «классифицированных публикаций за период»."]}],"checklist":["Назвать показатель публикациями по creation date, а не активными вакансиями.","Указать обе включённые границы 180-дневного окна.","Не интерпретировать нулевой день как отсутствие всех открытых позиций.","Сверить источник, ingestion date и версию классификации.","Сравнивать тренды только на окнах одинаковой длины."],"references":[{"label":"Исследование 180-дневного слоя","href":"https://win-702hpohbtiv.tail044b19.ts.net/research"},{"label":"Статус и происхождение данных","href":"https://win-702hpohbtiv.tail044b19.ts.net/data-status"},{"label":"Источники TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/sources"},{"label":"Открытые данные по профессиям","href":"https://win-702hpohbtiv.tail044b19.ts.net/open-data.json"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/what-180-days-of-publications-means","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/what-180-days-of-publications-means/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/what-180-days-of-publications-means/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/what-180-days-of-publications-means/cite/ris"}},{"slug":"seniority-title-vs-experience-signals","title":"Junior, Middle, Senior: как заголовок и опыт дают разные сигналы","description":"Почему seniority нельзя надёжно определить одним словом в title и как разрешать конфликт между заголовком, опытом и обязанностями.","kicker":"Классификация уровня","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":7,"keywords":["Junior Middle Senior","seniority вакансии","опыт работы","классификация вакансий","уровень разработчика"],"introduction":"Seniority — нормализованный аналитический признак, а не универсальное поле работодателя. Слово Senior в заголовке является сильным сигналом, но отсутствие слова не делает роль Middle, а диапазон опыта может конфликтовать с обязанностями. Поэтому правило должно сохранять неопределённость вместо удобного, но ложного уровня.","sections":[{"heading":"Какие сигналы доступны","paragraphs":["Явные маркеры Junior, Middle, Senior, Lead, стажёр и их русские варианты дают наиболее объяснимое основание. Они проверяются вместе с отрицаниями и контекстом: «не junior», «junior mentor» и название команды с таким словом не должны срабатывать как одинаковая вакансия начального уровня.","Диапазон требуемого опыта является отдельным сигналом. Он полезен, когда title нейтрален, но не образует глобальную шкалу: два года для одной узкой технологии и два года для руководящей роли означают разное. Обязанности, самостоятельность и управление людьми помогают проверить результат, но хуже подходят для единственного жёсткого regex."]},{"heading":"Почему сигналы конфликтуют","paragraphs":["Работодатель может назвать позицию Middle и потребовать пять лет опыта, опубликовать Senior без числового требования или искать Junior с обязанностями полноценного владельца системы. Это свойство исходных данных, а не ошибка, которую допустимо скрыть переносом в ближайшую удобную корзину.","При конфликте явный заголовок, структурированный опыт и текст получают заранее описанные приоритеты. Результат сопровождается confidence и версией классификатора. Если сильные признаки расходятся, честный итог unknown полезнее для агрегата: он не загрязняет сравнение зарплат по уровням."]},{"heading":"Смешанные и руководящие роли","paragraphs":["Lead и руководитель не всегда являются просто Senior. В одних вакансиях это технический уровень, в других — отдельная функция с наймом, бюджетом и ответственностью за команду. Если продукт публикует только Junior/Middle/Senior, правило приведения должно быть явным или такая запись должна остаться вне seniority-среза.","Фразы «готовы рассмотреть от Junior до Middle» описывают диапазон, а не единственную метку. Размножение одной вакансии по двум уровням удваивает count и искажает зарплату. Без отдельной модели диапазона безопаснее исключить её из level-specific агрегата, сохранив в общем числе публикаций."]},{"heading":"Как проверять качество seniority","paragraphs":["Нужна размеченная выборка с примерами явных уровней, нейтральных title, отрицаний, диапазонов и конфликтов. Проверяются precision по каждому уровню и доля unknown; рост coverage ценой массового переноса неоднозначных записей не считается улучшением.","В цитате level-specific зарплаты указываются seniority, число совместимых наблюдений n и версия правила. Нельзя переносить медиану Middle на Junior при пустой выборке. Публичные JSON и HTML должны одинаково показывать, где уровень определён, а где данных недостаточно."]}],"checklist":["Разделять явный title, опыт и текстовые обязанности как разные сигналы.","Обрабатывать отрицания, диапазоны и Lead-роль до присвоения уровня.","Сохранять unknown при сильном конфликте признаков.","Не дублировать одну вакансию в нескольких seniority-корзинах.","Цитировать level-метрику вместе с n и версией классификации."],"references":[{"label":"Методология классификации","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Глоссарий показателей","href":"https://win-702hpohbtiv.tail044b19.ts.net/glossary"},{"label":"Открытые seniority-срезы","href":"https://win-702hpohbtiv.tail044b19.ts.net/open-data.csv"},{"label":"Воспроизводимый ETL","href":"https://win-702hpohbtiv.tail044b19.ts.net/insights/reproducible-etl-provenance"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/seniority-title-vs-experience-signals","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/seniority-title-vs-experience-signals/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/seniority-title-vs-experience-signals/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/seniority-title-vs-experience-signals/cite/ris"}},{"slug":"zero-matches-for-narrow-roles","title":"Ноль совпадений у узкой роли: отсутствие сигнала не равно исчезновению профессии","description":"Как интерпретировать роль без уверенных совпадений, учитывать precision и recall классификатора и не делать вывод о полном отсутствии спроса.","kicker":"Честный нулевой результат","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":6,"keywords":["ноль вакансий","узкие IT роли","precision recall","классификация профессий","отсутствие данных"],"introduction":"Ноль классифицированных публикаций является точным результатом запроса и правил, но слабым основанием для утверждения, что профессии нет на рынке. Узкая роль может называться иначе, входить в более широкую позицию или отсутствовать именно в выбранном источнике и периоде. Вывод должен сохранять эти границы.","sections":[{"heading":"Что именно равно нулю","paragraphs":["Нулевой count означает, что после дедупликации и применения текущей версии классификатора ни одна запись в заданном источнике и окне не прошла порог уверенного соответствия. Это наблюдение о pipeline, а не универсальная перепись работодателей, команд или фактически выполняемых задач.","Если записи были просмотрены, ноль отличается от технически отсутствующей загрузки. Поэтому статус ingestion, границы периода и число обработанных объектов должны быть доступны рядом. Невыполненный run и корректно рассчитанный ноль нельзя кодировать одним пустым значением."]},{"heading":"Precision против recall","paragraphs":["Высокий precision требует принимать только совпадения, для которых название и контекст действительно описывают роль. Это защищает узкие профессии от чужих вакансий, но снижает recall: часть релевантных записей с необычным названием останется unknown или попадёт в более широкую категорию.","Механическое добавление каждого возможного синонима повышает число совпадений, но может превратить показатель в смесь. Например, отдельный инструмент встречается в требованиях десятков ролей и не делает каждую из них профессией специалиста по этому инструменту. Alias должен проверяться на размеченных положительных и отрицательных примерах."]},{"heading":"Таксономия и границы источника","paragraphs":["Работа может существовать как специализация внутри Backend, Data Engineering или Security, не появляясь самостоятельным title. В этом случае ноль говорит о способе упаковки вакансий. Полезно проверять соседние роли и технологический стек, не суммируя их автоматически с целевой сущностью.","Один open-data источник имеет собственный охват работодателей, регионов и правил публикации. Даже идеальная классификация не видит предложения вне него. Сравнение нескольких источников допустимо только при раздельном provenance, совместимых лицензиях и дедупликации; приписывать одному источнику записи другого нельзя."]},{"heading":"Ответственный вывод","paragraphs":["Корректная формулировка: «за указанный период в этом источнике классификатор не нашёл уверенных совпадений». Она проверяема и оставляет место для альтернативных названий. Формулировка «вакансий нет» сильнее имеющихся данных и должна использоваться только при действительно полном наблюдении рынка, которого агрегатор обычно не имеет.","Нулевые роли полезны для улучшения таксономии. Список unknown title можно анализировать без публикации персональных данных, добавлять подтверждённые alias и повторно считать историю с новой версией. Старый результат при этом не исчезает: версия объясняет, почему два расчёта различаются."]}],"checklist":["Указать источник, период и версию классификатора нулевого результата.","Отличить корректный count=0 от отсутствующей или незавершённой загрузки.","Не повышать recall ценой непроверенных alias и чужих профессий.","Проверить соседние роли без автоматического сложения их counts.","Формулировать вывод как отсутствие уверенных совпадений, а не профессии."],"references":[{"label":"Исследование официального слоя","href":"https://win-702hpohbtiv.tail044b19.ts.net/research"},{"label":"Статус данных","href":"https://win-702hpohbtiv.tail044b19.ts.net/data-status"},{"label":"Каталог 50 профессий","href":"https://win-702hpohbtiv.tail044b19.ts.net/professions"},{"label":"Методология TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/zero-matches-for-narrow-roles","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/zero-matches-for-narrow-roles/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/zero-matches-for-narrow-roles/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/zero-matches-for-narrow-roles/cite/ris"}},{"slug":"profession-index-0-100-not-a-promise","title":"Индекс профессии 0–100: сравнительный сигнал, а не карьерное обещание","description":"Из каких компонентов складывается TechRole Index, зачем нужны percentile rank и версия весов и почему score не предсказывает личную зарплату.","kicker":"Как читать рейтинг","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":7,"keywords":["индекс профессии","рейтинг IT профессий","score 0 100","percentile rank","карьерная аналитика"],"introduction":"Число от 0 до 100 удобно для сортировки нескольких сигналов, но у него нет физической единицы. Score 80 не означает зарплату на 20% выше score 60 и не даёт 80-процентной вероятности трудоустройства. Это положение профессии внутри конкретной версии сравнительной модели и конкретной даты данных.","sections":[{"heading":"Шесть компонентов и их веса","paragraphs":["Текущая формула объединяет спрос 30%, уровень зарплаты 25%, рост спроса 20%, доступность для начинающих 10%, удалённую работу 10% и стабильность/качество 5%. Веса выражают продуктовую модель сравнения, а не найденный природный закон; новая схема получает новую scoring version.","Компоненты нельзя читать без исходных показателей. Высокий спрос может сочетаться с низкой долей Junior, а высокая зарплата — с маленькой выборкой. Breakdown нужен именно для того, чтобы одинаковый итоговый score не скрывал две разные структуры преимуществ и ограничений."]},{"heading":"Нормализация и percentile rank","paragraphs":["Вакансии логарифмируются, чтобы крупнейшая категория не подавляла остальные только масштабом. Денежные и growth-экстремумы ограничиваются, затем признаки переводятся в percentile rank среди профессий текущего набора. Поэтому 70 описывает относительное положение, а не абсолютный порог рынка.","Состав сравниваемых профессий влияет на rank: добавление новых сущностей или изменение coverage способно сдвинуть score даже при прежнем исходном значении роли. Для сравнения во времени нужны одинаковая scoring version, дата и universe, а не только два числа из разных выпусков."]},{"heading":"Качество данных и пропущенные компоненты","paragraphs":["Salary component допускается только после quality gate, а confidence остаётся отдельным признаком. Нельзя заменять недостаточную зарплатную выборку нулём: ноль искусственно накажет узкую роль. Политика пропуска или перенормировки должна быть частью версии и одинаково применяться ко всем профессиям.","Публичный teaser не должен позволять восстановить закрытый breakdown. Сервер сначала определяет entitlement, затем формирует ответ; JSON-LD и открытые индексы содержат только разрешённые поля. Отсутствие Premium-компонента в публичном HTML не означает его нулевой вклад в расчёт."]},{"heading":"Для каких решений индекс полезен","paragraphs":["Индекс помогает сформировать shortlist и задать вопросы: какие роли сочетают спрос и доступность Junior, где зарплатный сигнал подтверждён, где рост нестабилен. Следующий шаг — открыть breakdown, период, выборку и описание профессии, а не выбирать карьеру по первой строке таблицы.","Личное решение зависит от навыков, региона, языка, интереса, допустимого риска и конкретных работодателей. Эти данные не входят в общий market score. Поэтому корректная цитата называет версию индекса сравнительной, указывает дату и не превращает её в обещание офера, дохода или срока поиска."]}],"checklist":["Проверить scoring version, дату и состав сравниваемых профессий.","Открыть breakdown вместо вывода только по итоговому числу.","Не трактовать разницу score как процент зарплаты или вероятности офера.","Сверить confidence и sample size зарплатного компонента.","Использовать индекс для shortlist, а не как персональный карьерный прогноз."],"references":[{"label":"Формула и веса индекса","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Рейтинг профессий","href":"https://win-702hpohbtiv.tail044b19.ts.net/top"},{"label":"Глоссарий метрик","href":"https://win-702hpohbtiv.tail044b19.ts.net/glossary"},{"label":"Сравнение профессий","href":"https://win-702hpohbtiv.tail044b19.ts.net/compare"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/profession-index-0-100-not-a-promise","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/profession-index-0-100-not-a-promise/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/profession-index-0-100-not-a-promise/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/profession-index-0-100-not-a-promise/cite/ris"}},{"slug":"server-side-paywall-ssr-json-ld","title":"Серверный paywall: как не раскрыть Premium-метрики через SSR и JSON-LD","description":"Почему скрыть карточку CSS недостаточно, где проверять entitlement и как изолировать Premium-поля в API, cache, SSR и structured data.","kicker":"Граница доступа","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":8,"keywords":["server side paywall","SSR безопасность","JSON-LD Premium","entitlement","защита API"],"introduction":"Paywall является границей данных, а не визуальным эффектом. Если закрытое значение уже попало в HTML, RSC payload, JSON API, structured data или общий cache, размытие карточки ничего не защищает. Решение принимается на сервере до сериализации и повторяется для каждого представления.","sections":[{"heading":"Почему клиентское скрытие не работает","paragraphs":["CSS blur, условный React-компонент после hydration и disabled button изменяют экран, но не сетевой ответ. Пользователь может открыть source, DevTools или запросить endpoint напрямую. Поисковый и AI-crawler тоже читает исходный HTML и JSON-LD, а не коммерческое намерение интерфейса.","Нельзя отправлять Premium-поля с надеждой, что клиент их проигнорирует. Это касается score breakdown, длинной истории, точных закрытых срезов и внутренних идентификаторов. Публичный teaser создаётся отдельной серверной схемой, где запрещённые поля отсутствуют, а не равны скрытому значению."]},{"heading":"Auth, entitlement и формирование ответа","paragraphs":["Сначала сервер валидирует сессию или токен, затем определяет действующую подписку и разрешённую глубину данных. Только после этого выполняется выборка или projection. Проверка одного флага на странице недостаточна, если соседний API route возвращает полную модель без той же политики.","Fail-safe поведение различается по контуру. Недоступный auth rate-limit в production закрывает вход, а недоступный read cache может безопасно перейти к PostgreSQL, потому что entitlement уже рассчитан. Cache не становится источником полномочий и не имеет права расширять доступ."]},{"heading":"Изоляция cache и машиночитаемых представлений","paragraphs":["Public и Premium ответы получают разные cache keys с фактически разрешённым периодом. Key хешируется, чтобы не оставлять slug, query или пользовательские данные в Redis/metrics. Сначала вычисляется access tier, потом читается cache; обратный порядок создаёт риск выдать тёплый Premium-ответ бесплатному запросу.","JSON-LD, RSS, llms.txt, open-data и citation metadata считаются самостоятельными публичными контрактами. Они включают открытые описания, provenance и явно разрешённые агрегаты, но не копируют закрытые поля из внутренней модели. Visible HTML и structured data должны совпадать по смыслу."]},{"heading":"Как доказать отсутствие утечки","paragraphs":["Contract tests сравнивают anonymous, free и Premium ответы, проверяют HTML source, RSC/JSON, JSON-LD и cache isolation. Полезен canary-показатель, который существует только в Premium fixture: его отсутствие ищется по всем публичным endpoint и собранным страницам.","Тестируются истечение подписки, повторный запрос после Premium cache hit, отказ Redis и параллельные пользователи разных tiers. Логи и Prometheus labels также не должны содержать email, path params или токены. Защита считается полной только когда закрытое значение не покинуло серверный trust boundary."]}],"checklist":["Проверять entitlement до query projection, cache и сериализации.","Использовать разные public/Premium cache keys и фактическую глубину истории.","Исключить закрытые поля из HTML, RSC, API, JSON-LD, RSS и LLM-файлов.","Проверять expiry, Redis failure и последовательность Premium→free запросов.","Не помещать пользовательские идентификаторы в metrics и cache key text."],"references":[{"label":"Тарифы и граница Premium","href":"https://win-702hpohbtiv.tail044b19.ts.net/pricing"},{"label":"Публичный AI index","href":"https://win-702hpohbtiv.tail044b19.ts.net/ai-index.json"},{"label":"Методология и открытые поля","href":"https://win-702hpohbtiv.tail044b19.ts.net/methodology"},{"label":"Редакционные и privacy-принципы","href":"https://win-702hpohbtiv.tail044b19.ts.net/about"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/server-side-paywall-ssr-json-ld","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/server-side-paywall-ssr-json-ld/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/server-side-paywall-ssr-json-ld/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/server-side-paywall-ssr-json-ld/cite/ris"}},{"slug":"llm-friendly-open-text-dataset-citation","title":"LLM-friendly публикация: открытый текст, Dataset и citation metadata без магической разметки","description":"Что действительно помогает AI и поисковым системам находить и корректно цитировать данные: видимый текст, canonical сущности, provenance и стандартные форматы.","kicker":"Машинная обнаруживаемость","publishedAt":"2026-07-21","updatedAt":"2026-07-21","readingMinutes":8,"keywords":["LLM friendly сайт","AI цитируемость","Dataset JSON-LD","llms.txt","citation metadata"],"introduction":"Специальный файл не заставляет модель процитировать сайт. Машинная обнаруживаемость появляется, когда полезный текст доступен без входа, сущности имеют устойчивые canonical URL, structured data совпадает с видимой страницей, а цифра сопровождается периодом, n, источником и готовой библиографической записью.","sections":[{"heading":"Сначала индексируемый видимый текст","paragraphs":["Основное объяснение должно находиться в SSR HTML и быть понятно человеку: что измерено, за какой период, каким методом и с какими ограничениями. Текст, спрятанный только в client-side запросе или изображении, сложнее обнаружить и проверить. Внутренние ссылки соединяют профессию, методологию, источник и исследование.","Каждая страница получает один title, description, h1 и canonical. Сотни вариаций с переставленными словами не добавляют знания и выглядят как doorway pages. Лучше меньше самостоятельных материалов, каждый из которых отвечает на отдельный вопрос и ссылается на первичное основание."]},{"heading":"Structured data должно повторять содержание","paragraphs":["Occupation, Dataset, DataCatalog и TechArticle JSON-LD описывают те же сущности, которые видны на странице. Dataset связывает creator, temporal coverage, variableMeasured, distribution и license/terms context. Разметка не должна раскрывать Premium-поле или обещать live-данные, если видимый слой является подготовленным baseline.","Синтаксически валидный JSON-LD ещё не доказывает качество. Автоматический crawl проверяет canonical, noindex, дубли title/description и парсинг каждого script. После публикации на стабильном домене разметка дополнительно проверяется инструментами поисковых систем и фактическим индексированием."]},{"heading":"LLM-указатели и переносимые форматы","paragraphs":["llms.txt и llms-full.txt являются дополнительными текстовыми картами: они перечисляют публичные разделы, правила интерпретации и canonical URL. Они полезны crawler, который решил их прочитать, но не заменяют sitemap, robots, RSS и нормальную навигацию. Нельзя обещать поддержку со стороны каждой модели.","JSON/CSV дают воспроизводимые значения, Data Package перечисляет ресурсы, CSL-JSON, BibTeX и RIS помогают перенести ссылку в библиотечный менеджер. Link rel=cite-as и готовый текст цитаты уменьшают вероятность, что период, source или налоговый статус потеряются при пересказе."]},{"heading":"Что измерять и чего не делать","paragraphs":["После стабильного домена измеряются coverage sitemap, indexed canonical URL, обращения к data endpoints, ссылки на конкретные материалы и корректность цитат. Само число созданных страниц или backlinks ничего не говорит о полезности. Реферальный домен ценен, когда он ведёт читателя к проверяемому материалу по теме.","Сетки пустых сайтов, автокомментарии, покупные ссылки и скрытый текст создают риск санкций и не добавляют доказательности. Этичное продвижение строится на собственном исследовании, техническом разборе, открытых metadata и сотрудничестве с площадками, где аудитории действительно нужен этот набор данных."]}],"checklist":["Публиковать основное объяснение в доступном SSR HTML.","Связывать canonical сущность с методологией, provenance, периодом и n.","Проверять совпадение JSON-LD с видимым публичным содержимым.","Давать JSON/CSV, Data Package и стандартные citation formats.","Не использовать doorway pages, скрытый текст и автоматический ссылочный спам."],"references":[{"label":"Полный LLM-контекст TechRole Index","href":"https://win-702hpohbtiv.tail044b19.ts.net/llms-full.txt"},{"label":"Schema.org DataCatalog и Dataset","href":"https://win-702hpohbtiv.tail044b19.ts.net/open-data.json"},{"label":"Форматы цитирования","href":"https://win-702hpohbtiv.tail044b19.ts.net/citation"},{"label":"Google: AI features and your website","href":"https://developers.google.com/search/docs/appearance/ai-features"},{"label":"Google: Dataset structured data","href":"https://developers.google.com/search/docs/appearance/structured-data/dataset"}],"canonical_url":"https://win-702hpohbtiv.tail044b19.ts.net/insights/llm-friendly-open-text-dataset-citation","citation_urls":{"csl_json":"https://win-702hpohbtiv.tail044b19.ts.net/insights/llm-friendly-open-text-dataset-citation/cite/csl-json","bibtex":"https://win-702hpohbtiv.tail044b19.ts.net/insights/llm-friendly-open-text-dataset-citation/cite/bibtex","ris":"https://win-702hpohbtiv.tail044b19.ts.net/insights/llm-friendly-open-text-dataset-citation/cite/ris"}}]}