Публічний реєстр
Звіт про здоров'я програмного забезпеченнясхема 0.27.0 · метрики 1.13.0 · 2026-07-28 15:02 UTC

wikimedia / mediawiki-tools-codesniffer

Mirror of https://gerrit.wikimedia.org/g/mediawiki/tools/codesniffer. Please see https://www.mediawiki.org/wiki/Developer_access for contributing

PHPGPL-2.0★ 33 зірки⑂ 12 форківз лист. 2012 р.Переглянути на GitHub ↗

wikimedia/mediawiki-tools-codesniffer має індекс здоров’я 55 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (62/100), найнижчий — AI Readiness (35/100). Останнє оновлення було 82 дні тому. Більшість нещодавньої роботи виконують 3 учасники.

55
загалом / 100
Помірний

Індекс здоров'я програмного забезпечення

Метрики згруповано у зважені категорії на шкалі 1–100. Загальна оцінка починається як їхнє середнє; коли публічні дані активують Політику юрисдикцій високого ризику, рейтинг коригується й отримує верхню межу 49 («Під ризиком»). Готовність до ШІ не входить до індексу.

55
Відмінний85-100Зразковий; відповідає практично всім перевіреним критеріям
Добрий70-84Здоровий; незначні прогалини
Помірний50-69Прийнятний, але з помітними прогалинами; рекомендовано перевірку
У зоні ризику30-49Суттєві слабкі місця; впровадження потребує обережності
Критичний1-29Серйозні проблеми (покинутий, єдиний мейнтейнер, без базової гігієни)
ЖиттєздатністьСпільнота тавпровадженняСталість таврядуванняІнженернаякістьБезпекаГотовність доШІ

Профіль оцінок

Кожна вісь — окрема категорія. Форма важить більше, ніж середнє: здоровий об'єкт заповнює всю фігуру, тоді як профіль із піками та провалами означає, що сила в одному вимірі маскує ризик в іншому.

Власність

WikimediaОрганізація
2 188 підписників1 963 публічні репозиторіїз лют. 2009 р.

За цим репозиторієм стоїть організація — спільна, підзвітна опіка, здатна пережити будь-якого окремого мейнтейнера.

Пакетні екосистеми

РеєстрПакетВерсіяЗавантажень / місВерсіїОстання публікаціяТеги
Packagistmediawiki/mediawiki-codesnifferv51.0.075 5976586 днів томуcodesniffermediawiki

Метрики за категоріями

Життєздатність

Чи живий проєкт — чи пишеться код і чи виходять релізи?

62Помірний · 22% загального індексу
Як обчислюється оцінка
18/36Свіжість push — останній push 82 дн. тому
12.5/36Ритм комітів — 18/52 тижнів із комітами
14.8/18Обсяг комітів — 44 комітів за останній рік
5/10OpenSSF Scorecard: Maintained — 6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
Використані вхідні дані
commits_last_year44
human_commit_share1
days_since_last_push82
active_weeks_last_year18
Як обчислюється оцінка
16.2/27Випускає релізи — 65 тегів версій (без релізів GitHub)
36/36Свіжість релізів — останній реліз 86 дн. тому
19.8/27Ритм релізів — реліз кожні ~106,1 дн.
0/10OpenSSF Scorecard: Signed-Releases — немає даних
Використані вхідні дані
releases_count65
latest_release_tagv51.0.0
releases_from_tagsтак
days_since_latest_release86
mean_days_between_releases106,1
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Signed-Releases. Залишкові ваги перенормовано.

Спільнота та впровадження

Чи має проєкт користувачів, завантаження, увагу та влаштовані умови для контриб’юторів?

59Помірний · 18% загального індексу
Як обчислюється оцінка
24.4/60Зірки — 33 зірок
8.7/25Форки — 12 форків
5.6/15Спостерігачі — 11 спостерігачів
Використані вхідні дані
forks12
stars33
watchers11
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (GPL-2.0)
0/18Настанови CONTRIBUTING
13.5/13.5Кодекс поведінки
0/7.2Шаблон issue
0/6.3Шаблон PR
Використані вхідні дані
has_readmeтак
has_licenseтак
has_contributingні
has_issue_templateні
has_code_of_conductтак
has_pull_request_templateні
Як обчислюється оцінка
65/80Щомісячні завантаження — 75 597 завантажень/місяць у packagist
17/20Залежні пакети в реєстрі — залежних пакетів: 352
Використані вхідні дані
packagesmediawiki/mediawiki-codesniffer
dependents352
ecosystemspackagist
total_downloads3 241 095
monthly_downloads75 597

Сталість та врядування

Чи переживе проєкт своїх людей — бас-фактор, реактивність, хто за ним стоїть і як супроводжуються пакети?

62Помірний · 24% загального індексу
Як обчислюється оцінка
36/54Бас-фактор — на 3 контриб’ютор(ів) припадає половина всіх комітів
15.9/22.5Розподіл комітів — головний контриб’ютор — автор 29% комітів
13.5/13.5Широта контриб’юторів — 58 контриб’юторів
10/10OpenSSF Scorecard: Contributors — project has 43 contributing companies or organizations
Використані вхідні дані
bus_factor3
contributors_sampled58
top_contributor_share0,292
Як обчислюється оцінка
0/46.8Вирішення issue — немає issue або даних
0/38.3Прийняття PR — злито 0/3 вирішених PR
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs0
open_issues0
closed_issues0
issue_closed_ratio
closed_unmerged_prs3
Виключено з оцінювання (немає даних або не застосовно): Вирішення issue. Залишкові ваги перенормовано.
Як обчислюється оцінка
30/30Підтримка власника — у власності організації
0/20Верифікований домен
24/25Охоплення власника — 2 188 підписників у wikimedia
25/25Послужний список — 1 963 публічних репозиторіїв, вік облікового запису ~17 р.
Використані вхідні дані
followers2 188
owner_typeOrganization
is_verified
owner_loginwikimedia
public_repos1 963
account_age_days6 365

Супровід пакетів

100Відмінний
Як обчислюється оцінка
25/25Опубліковано й доступно — 1 пакет(ів) у packagist
35/35Свіжість публікацій — остання публікація 86 дн. тому
20/20Історія версій — 65 опублікованих версій
20/20Не застарілий — активний, не deprecated і не yanked
Використані вхідні дані
packagesmediawiki/mediawiki-codesniffer
ecosystemspackagist
any_deprecatedні
min_days_since_publish86

Інженерна якість

Чи наявні базові інженерні практики та документація?

40У зоні ризику · 20% загального індексу

Інженерні практики

30У зоні ризику
Як обчислюється оцінка
0/24Процеси CI
24/24Наявні тести
0/16Конфігурація лінтера
0/9.6Pre-commit-хуки
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — немає даних
Використані вхідні дані
has_ciні
has_testsтак
has_editorconfigні
has_linter_configні
has_precommit_configні
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: CI-Tests. Залишкові ваги перенормовано.

Документація

55Помірний
Як обчислюється оцінка
30/30README
0/25Каталог документації
15/15Сайт документації / домашня сторінка — https://gerrit.wikimedia.org
10/10Опис репозиторію
0/10Теми
0/10Wiki
Використані вхідні дані
topics
has_wikiні
homepagehttps://gerrit.wikimedia.org
has_readmeтак
has_docs_dirні
has_descriptionтак

Безпека

Чи міцні видимі практики безпеки й ланцюга постачання, без непослабленої пов’язаності з юрисдикціями високого ризику?

48У зоні ризику · 16% загального індексу

Стан безпеки

35У зоні ризику
Як обчислюється оцінка
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — branch protection not enabled on development/release branches
0/2.5CI-Tests — немає даних
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/30 approved changesets -- score normalized to 0
2.5/2.5Contributors — project has 43 contributing companies or organizations
0/10Dangerous-Workflow — немає даних
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5Ліцензія — license file detected
3.8/7.5Maintained — 6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
0/5Packaging — немає даних
0/5Pinned-Dependencies — немає даних
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — немає даних
0/7.5Token-Permissions — немає даних
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Використані вхідні дані
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate3,5
Виключено з оцінювання (немає даних або не застосовно): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Залишкові ваги перенормовано.
Як обчислюється оцінка
35/35Прямі залежності без відомих сповіщень — жодна пряма залежність не має відомих сповіщень
0/25Непрямі залежності без відомих сповіщень — транзитивний набір не відокремлюється від залежностей розробки й тестування в цьому обсязі
0/40Немає задавнених сповіщень — жодне сповіщення не має дати публікації
Використані вхідні дані
sourceosv
advisories0
affected_packages0
assessed_packages7
unassessed_packages5
affected_by_severitynone
direct_affected_packages0
Виключено з оцінювання (немає даних або не застосовно): Непрямі залежності без відомих сповіщень, Немає задавнених сповіщень. Залишкові ваги перенормовано. Звірено 7 резолвлених залежностей із OSV. 5 не вдалося оцінити — немає резолвленої версії, непідтримувана екосистема або поза межами звітованого переліку пакетів. Цей репозиторій не публікує пакета, який резолвить індекс, тож натомість оцінено граф залежностей репозиторію. Цей граф змішує закріплені версії для розробки й тестування зі справді постачаними залежностями, тож оцінюються лише задекларовані runtime-залежності; транзитивні знахідки подаються як контекст і в оцінку не входять. Досяжність не аналізується.

Готовність до ШІ

Наскільки репозиторій оснащений для розробки та супроводу за участі ШІ-агентів? Незалежний, експериментальний бейдж — вага 0.0, тож він подається окремо і не впливає на загальний індекс здоров'я.

35У зоні ризику · 0% загального індексу
Як обчислюється оцінка
0/45Інструкції для агентів — немає CLAUDE.md / AGENTS.md / правил редактора
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 80 з 100 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,8
agent_instruction_files
agent_instruction_max_bytes
Як обчислюється оцінка
0/18Розгортання однією командою
22/22Автоматизовані тести
0/11Конфігурація лінтера / форматера
0/11Статична перевірка типів
0/10Відтворюване середовище
0/10Підтверджена практика роботи з агентами — серед останніх 100 комітів немає створених агентом
0/8Автоматизоване супроводження — автоматичних оновлень залежностей не виявлено
0/10OpenSSF Scorecard: Pinned-Dependencies — немає даних
Використані вхідні дані
has_nixні
has_testsтак
lockfiles
has_dockerfileні
typed_languageні
bootstrap_files
has_devcontainerні
has_linter_configні
typecheck_configs
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Pinned-Dependencies. Залишкові ваги перенормовано.
Як обчислюється оцінка
0/45Типізований код — PHP без конфігурації перевірки типів
55/55Керовані розміри файлів — 0/189 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languagePHP
largest_source_bytes26 888
source_files_sampled189
oversized_source_files0

Ключові факти

33зірок GitHub
58контриб'юторів
44комітів за останні 12 місяців
82днів від останнього пушу
65релізів
3бас-фактор
0відкритих issue
Packagistпакетних екосистем

Попередження щодо збору даних

  • Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token

Докладніше

Історія зірок і форків 0 ★ / 12 ⇿
0Зірки
12Форки
63Релізи

Коли додано кожну зірку й форк — зібрано з GitHub і згруповано за днями. Кумулятивне зростання розміщено просто над денними додаваннями, з яких воно складається, тож їх видно одне проти одного: рівномірне органічне накопичення виглядає зовсім інакше, ніж різкий короткочасний сплеск. Там, де цю різницю можна виміряти, її подано як автентичність росту.

0246810121112015-062020-122026-07
Мажорні 39Мінорні 15Патчі 8

Кожна точка охоплює 11 днів.

OpenSSF Scorecard 3.5 / 10
3.5сукупно

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-28 15:02 UTC

10Binary-Artifactsno binaries found in the repo
0Branch-Protectionbranch protection not enabled on development/release branches
н/дCI-Testsno pull request found
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/30 approved changesets -- score normalized to 0
10Contributorsproject has 43 contributing companies or organizations
н/дDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
5Maintained6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5
н/дPackagingpackaging workflow not detected
н/дPinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
н/дSigned-Releasesno releases found
н/дToken-PermissionsNo tokens found
10Vulnerabilities0 existing vulnerabilities detected
Прямі залежності 1
РеєстрПакетОбмеження версіїМаніфест
Packagistsquizlabs/php_codesniffer3.13.5composer.json
Усі залежності 12

Повний розв'язаний набір залежностей із графа залежностей GitHub: 1 прямих і 11 непрямих (транзитивних) пакетів. Транзитивне замикання є повним, коли в репозиторії закомічено lockfile.

РеєстрПакетВерсіяЗв'язок
Packagistsquizlabs/php_codesniffer3.13.5пряма
Packagistcomposer/semverнепряма
Packagistcomposer/spdx-licensesнепряма
Packagistext-domнепряма
Packagistext-mbstringнепряма
Packagistmediawiki/mediawiki-phan-config0.20.0непряма
Packagistmediawiki/minus-x2.0.1непряма
Packagistphpнепряма
Packagistphp-parallel-lint/php-console-highlighter1.0.0непряма
Packagistphp-parallel-lint/php-parallel-lint1.4.0непряма
Packagistphpcsstandards/phpcsextra1.5.0непряма
Packagistphpunit/phpunit10.5.63непряма
Сповіщення про залежності 0

Цей репозиторій не публікує пакета, який розпізнає індекс, тож оцінено його власний граф залежностей — 7 пакетів, серед яких є й піниї розробки та тестування, що ніколи не постачаються: 0 мають відомі сповіщення, з них 0 прямі. 5 не вдалося оцінити — немає резолвленої версії, непідтримувана екосистема або поза наведеним переліком пакетів.

Жодне відоме сповіщення не стосується оцінених залежностей.

Сповіщення означає, що версія, записана в графі залежностей, потрапляє в уражений діапазон. Досяжність не аналізується, а граф містить піниї розробки й тестування — знахідка може стосуватися інструментів, а не поставленого коду.

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1953,
      "has_wiki": false,
      "homepage": "https://gerrit.wikimedia.org",
      "languages": {
        "PHP": 471985,
        "Shell": 151
      },
      "pushed_at": "2026-05-06T19:49:58Z",
      "created_at": "2012-11-01T19:33:40Z",
      "owner_type": "Organization",
      "updated_at": "2026-07-21T10:57:57Z",
      "description": "Mirror of https://gerrit.wikimedia.org/g/mediawiki/tools/codesniffer. Please see https://www.mediawiki.org/wiki/Developer_access for contributing",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "GPL-2.0",
      "default_branch": "master",
      "license_spdx_raw": "GPL-2.0",
      "primary_language": "PHP",
      "significant_languages": [
        "PHP"
      ]
    },
    "owner": {
      "blog": "https://www.wikimedia.org",
      "name": "Wikimedia",
      "type": "Organization",
      "login": "wikimedia",
      "company": null,
      "location": "United States of America",
      "followers": 2188,
      "avatar_url": "https://avatars.githubusercontent.com/u/56668?v=4",
      "created_at": "2009-02-21T20:22:30Z",
      "is_verified": null,
      "public_repos": 1963,
      "account_age_days": 6365
    },
    "license": {
      "state": "standard",
      "spdx_id": "GPL-2.0",
      "raw_spdx": "GPL-2.0",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v51.0.0",
          "kind": "major",
          "published_at": "2026-05-03T06:29:24Z"
        },
        {
          "tag": "v50.0.0",
          "kind": "major",
          "published_at": "2026-02-10T11:49:03Z"
        },
        {
          "tag": "v49.0.0",
          "kind": "major",
          "published_at": "2026-01-11T00:02:41Z"
        },
        {
          "tag": "v48.0.0",
          "kind": "major",
          "published_at": "2025-09-04T20:12:57Z"
        },
        {
          "tag": "v47.0.0",
          "kind": "major",
          "published_at": "2025-05-04T07:30:05Z"
        },
        {
          "tag": "v46.0.0",
          "kind": "major",
          "published_at": "2025-01-27T21:05:44Z"
        },
        {
          "tag": "v45.0.0",
          "kind": "major",
          "published_at": "2024-10-29T17:38:15Z"
        },
        {
          "tag": "v44.0.0",
          "kind": "major",
          "published_at": "2024-08-10T11:11:32Z"
        },
        {
          "tag": "v43.0.0",
          "kind": "major",
          "published_at": "2024-01-29T16:06:37Z"
        },
        {
          "tag": "v42.0.0",
          "kind": "major",
          "published_at": "2023-09-21T13:34:41Z"
        },
        {
          "tag": "v41.0.0",
          "kind": "major",
          "published_at": "2023-02-25T22:10:21Z"
        },
        {
          "tag": "v40.0.1",
          "kind": "patch",
          "published_at": "2022-11-01T20:02:35Z"
        },
        {
          "tag": "v40.0.0",
          "kind": "major",
          "published_at": "2022-11-01T19:15:19Z"
        },
        {
          "tag": "v39.0.0",
          "kind": "major",
          "published_at": "2022-05-04T16:19:01Z"
        },
        {
          "tag": "v38.0.0",
          "kind": "major",
          "published_at": "2021-10-21T18:15:41Z"
        },
        {
          "tag": "v37.0.0",
          "kind": "major",
          "published_at": "2021-07-20T17:50:07Z"
        },
        {
          "tag": "v36.0.0",
          "kind": "major",
          "published_at": "2021-04-29T02:21:21Z"
        },
        {
          "tag": "v35.0.0",
          "kind": "major",
          "published_at": "2021-01-28T20:56:31Z"
        },
        {
          "tag": "v34.0.0",
          "kind": "major",
          "published_at": "2020-12-05T07:12:58Z"
        },
        {
          "tag": "v33.0.0",
          "kind": "major",
          "published_at": "2020-10-30T16:03:08Z"
        },
        {
          "tag": "v32.0.0",
          "kind": "major",
          "published_at": "2020-10-26T15:57:52Z"
        },
        {
          "tag": "v31.0.0",
          "kind": "major",
          "published_at": "2020-05-26T19:06:48Z"
        },
        {
          "tag": "v30.0.0",
          "kind": "major",
          "published_at": "2020-02-19T12:55:25Z"
        },
        {
          "tag": "v29.0.0",
          "kind": "major",
          "published_at": "2020-01-09T18:09:25Z"
        },
        {
          "tag": "v28.0.0",
          "kind": "major",
          "published_at": "2019-10-09T13:13:13Z"
        },
        {
          "tag": "v27.0.0",
          "kind": "major",
          "published_at": "2019-10-03T10:34:50Z"
        },
        {
          "tag": "v26.0.0",
          "kind": "major",
          "published_at": "2019-05-10T23:43:13Z"
        },
        {
          "tag": "25.0.0",
          "kind": "major",
          "published_at": "2019-04-05T21:56:35Z"
        },
        {
          "tag": "v24.0.0",
          "kind": "major",
          "published_at": "2019-02-06T03:17:18Z"
        },
        {
          "tag": "v23.0.0",
          "kind": "major",
          "published_at": "2018-11-14T01:45:17Z"
        },
        {
          "tag": "v22.0.0",
          "kind": "major",
          "published_at": "2018-09-02T08:19:25Z"
        },
        {
          "tag": "v21.0.0",
          "kind": "major",
          "published_at": "2018-07-26T03:51:46Z"
        },
        {
          "tag": "v20.0.0",
          "kind": "major",
          "published_at": "2018-05-24T18:18:33Z"
        },
        {
          "tag": "19.4.0",
          "kind": "minor",
          "published_at": "2021-01-12T21:27:05Z"
        },
        {
          "tag": "19.3.0",
          "kind": "minor",
          "published_at": "2021-01-12T20:41:09Z"
        },
        {
          "tag": "v19.2.0",
          "kind": "minor",
          "published_at": "2019-02-06T04:15:49Z"
        },
        {
          "tag": "19.1.0",
          "kind": "minor",
          "published_at": "2018-10-23T00:24:06Z"
        },
        {
          "tag": "v19.0.0",
          "kind": "major",
          "published_at": "2018-05-24T17:18:06Z"
        },
        {
          "tag": "v18.0.0",
          "kind": "major",
          "published_at": "2018-04-13T18:30:54Z"
        },
        {
          "tag": "v17.0.0",
          "kind": "major",
          "published_at": "2018-03-28T17:44:06Z"
        },
        {
          "tag": "v16.0.1",
          "kind": "patch",
          "published_at": "2018-02-24T07:47:50Z"
        },
        {
          "tag": "v16.0.0",
          "kind": "major",
          "published_at": "2018-02-15T06:07:17Z"
        },
        {
          "tag": "v15.0.0",
          "kind": "major",
          "published_at": "2017-12-29T20:25:40Z"
        },
        {
          "tag": "v14.1.0",
          "kind": "minor",
          "published_at": "2017-10-21T02:22:31Z"
        },
        {
          "tag": "v14.0.0",
          "kind": "major",
          "published_at": "2017-10-21T02:04:11Z"
        },
        {
          "tag": "v13.0.0",
          "kind": "major",
          "published_at": "2017-09-24T03:33:15Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2017-08-30T06:01:51Z"
        },
        {
          "tag": "v0.11.1",
          "kind": "patch",
          "published_at": "2017-08-13T18:23:02Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2017-08-11T02:17:24Z"
        },
        {
          "tag": "v0.10.1",
          "kind": "patch",
          "published_at": "2017-07-23T00:59:17Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2017-07-01T00:43:26Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2017-06-20T02:10:42Z"
        },
        {
          "tag": "v0.8.1",
          "kind": "patch",
          "published_at": "2017-07-05T20:52:44Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2017-05-04T19:15:03Z"
        },
        {
          "tag": "v0.8.0-alpha.1",
          "kind": "prerelease",
          "published_at": "2016-09-22T03:45:15Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2016-05-28T01:08:59Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2016-05-06T19:53:37Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2016-05-06T19:34:07Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2016-02-17T10:22:13Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2015-12-29T01:03:51Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2015-10-23T07:51:32Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2015-09-26T21:34:16Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2015-06-19T16:36:59Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2015-06-02T18:42:05Z"
        },
        {
          "tag": "0.1.0",
          "kind": "minor",
          "published_at": "2015-01-05T21:59:34Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "9fd2bf1d8e772ce9ee253862574235a2b38f4215",
          "body": "Depends-On: I5f3bd59cdc1e6f398e8969802ecc4260789f4630\nDepends-On: I3eb0b7cb85d0ba3d37261c8d61ec873f1573be31\nDepends-On: Id92677e30a1f59cc516c933cbcac45ca6aad6aee\nChange-Id: I5b0fe75e6b42cab54227a837f4dd42373b164550",
          "is_bot": false,
          "headline": "Deprecate $wgLang",
          "author_name": "MGChecker",
          "author_login": "MGChecker",
          "committed_at": "2026-05-06T19:49:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f1d68132f2cca6fd36b7816988a53450909ca88d",
          "body": "Change-Id: I4e434cf0b67178c9e6b07f04cd436d47655f93c9",
          "is_bot": false,
          "headline": "Drop support for PHP 8.2",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-05-03T10:23:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d8a2f4be6d5abe217dfb3b2483263b3c233603f",
          "body": "Depends-On: I1134415f9bba7ea01e65012b49c9b5e3c37c092a\nChange-Id: Ida6e9ac70450a83f86ecc49e5782d2a0cb1a37d9",
          "is_bot": false,
          "headline": "Drop support for composer/spdx-licenses 1.5.*",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-05-03T10:23:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d9f3595b7e9c73b1f725b0074ac04670c707211e",
          "body": "Change-Id: I72481161760355c75948250d4466b24e316df5f1",
          "is_bot": false,
          "headline": "Release v51.0.0",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2026-05-03T06:29:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c76359921d059406b676bea55120354289693dca",
          "body": "Change-Id: Ie16f985f9f9d9783e11aae32cbdb3ed15275ad94",
          "is_bot": false,
          "headline": "Upgrading phpcsstandards/phpcsextra (1.4.0 => 1.5.0)",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-05-03T00:45:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ec8fa24c896e2c4f6a2df919f9f4ac2f7f67cc1e",
          "body": "Change-Id: I4f79666a5f88b4fd839aaf333e036455898a9ae8",
          "is_bot": false,
          "headline": "Allow composer/spdx-licenses 1.6.0",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-05-02T12:58:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3f4ae40d82ded6c90d067e10b9d7b93bea27d258",
          "body": "Require strict types on function calls to php internal functions or\non function calls within the library.\n\nBug: T422722\nChange-Id: I2120639553e59b6cdb0134b30c64d091b914e888",
          "is_bot": false,
          "headline": "chore: Declare strict types on all php files",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-04-19T21:24:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "afb70141ee55be78be69e862a1f89e78b8cae3ed",
          "body": "File::findExtendedClassName is documented to return also false,\nFile::getDeclarationName is documented to return also null.\n\nChange-Id: I6b2de10b7a75b861efe61c5cd0ac5b68b6a4c9c7",
          "is_bot": false,
          "headline": "chore: Handle possible false/null in PHPUnitTestTrait",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-04-19T21:24:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "16d8b3bd4b88833fe36439519bb6a89efedcb13e",
          "body": "Deprecated in php8.2\nhttps://wiki.php.net/rfc/remove_utf8_decode_and_utf8_encode\n\nChange-Id: I5aa0657da64b38e10cd47c7aa2a10d6e23e9b056",
          "is_bot": false,
          "headline": "ForbiddenFunctionsSniff: Add utf8_encode and utf8_decode",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-04-14T10:06:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8ff6fc7e72c0a6f93580abaca518f31e9b2fb3ba",
          "body": "Bug: T410854\nChange-Id: Iae83297046e1e44974cfbf2f13f86ef3e4c59841",
          "is_bot": false,
          "headline": "Fix NullableTypeSniff for union types",
          "author_name": "MGChecker",
          "author_login": "MGChecker",
          "committed_at": "2026-04-02T17:31:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ded2a13a9007982a636bb9731408c57ad778e734",
          "body": "It is always enabled and statically linked since PHP 8.0, so there is\nno need to check for it unlike with older versions.\n\n https://wiki.php.net/rfc/always_enable_json\n\nBug: T401078\nChange-Id: I5ae2a3bc22e197f53fd6d868f2ba608a6f9f0565",
          "is_bot": false,
          "headline": "build: Don't list json as a required extension",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-03-29T21:06:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bc675aa4fc75f541498b7545e8f512909462d543",
          "body": "Follow-Up: I479542e2ee50685c227ca3a433c7a1d105bf7e6d\nChange-Id: I2f7c8aa23d252152b011e9ceda6a87a8c1536a43",
          "is_bot": false,
          "headline": "build: Updating mediawiki/mediawiki-phan-config to 0.20.0",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-03-07T20:53:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "433ad3f94672ead361dbe5196aa8a703572e61ec",
          "body": "Bug: T406326\nChange-Id: Ief727117b8e927204289f803f7cf516b2398a57d",
          "is_bot": false,
          "headline": "build: Upgrade mediawiki-phan-config for PHP 8.5 support",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2026-02-12T17:54:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8f8ba0099b59f26c908f8d3b299ba01fb9a0e1dc",
          "body": "This entirely replaces the parameter type regexp, fixing some bugs, but\nin a way that is possibly breaking; and it marks more functions as\ndeprecated. Hence it is not appropriate for a minor/patch release.\n\nChange-Id: Ic5d017422af39864744603241dbc45d7fe99f1f7",
          "is_bot": false,
          "headline": "Release v50.0.0",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2026-02-10T11:49:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "956a332af26cefb3912c2ac70d1eca65e3af3e4a",
          "body": "The previous bespoke regex was missing complex union types, for example\narrays containing variadic callables, and nested array shapes. Also,\nsome parts of it were working in unclear ways, like the \"type wrapped in\nbraces\" actually matching array shapes, or the \"plain letters\" actually\nmatching space\n[…]\nSo, import the union type regexps for phan, which handle all these edge\ncases. Then add the few special cases we want on top of that.\n\nBug: T410187\nChange-Id: I450b9ebb1095b434750990714b94debd8e6aa2dd",
          "is_bot": false,
          "headline": "Use parameter type regex from phan",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2026-02-10T00:38:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "60150901985dc0643d0e1274976f9249b98b1e2c",
          "body": "Change-Id: I6166f4c1bc345f6d43989e078b751fae37b7297d",
          "is_bot": false,
          "headline": "build: Upgrade mediawiki/minus-x from 2.0.0 to 2.0.1",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-29T21:21:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cf13be32f7ca83a963bd19e105f9dc33a1d16b13",
          "body": "Bug: T415723\nChange-Id: Id2b372d8da32479a192f89d9e35c5ad5f7b010df",
          "is_bot": false,
          "headline": "build: Upgrade PHPUnit from 10.5.58 to 10.5.63 to unblock CI",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2026-01-27T23:42:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8d1b6553e57976f2daff36e9e4f6d438547ee433",
          "body": "Change-Id: I7430909b1e70ef8db31128f4115be6082f979e1d",
          "is_bot": false,
          "headline": "ForbiddenFunctionsSniff: Add more deprecated php internal functions",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-01-18T01:17:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cbed3a74027cb2c9d9622d73d03a6ce408508bc1",
          "body": "Change-Id: Ic5c5728e481324b12ed9a1affbf7c161e914a0ff",
          "is_bot": false,
          "headline": "build: Upgrade mediawiki/minus-x from 1.1.3 to 2.0.0",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-13T00:42:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "15219ac40cd18f259a7170270165c0a7b47af10a",
          "body": "Change-Id: I98fadd962d247f1481d8ec381ff43826e1e2c721",
          "is_bot": false,
          "headline": "Release v49.0.0",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-11T00:02:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1b27533361b43f8a341bc11e2322df8793bcc68",
          "body": "Change-Id: Ibb108885fd61ce4eacf6aea2ff5382ec263edee8",
          "is_bot": false,
          "headline": "Use tabs instead of spaces in phpunit.xml.dist",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-10T23:45:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "077caad0788c29ed5cf7caaed2ff812e66cb3709",
          "body": "Allowed with php8.2\nAlso use const for a static variable and inline the function,\nas const can also be build by other consts\n\nChange-Id: I39296c8bad3caacdc7dc9bf177213c8d62de4e4b",
          "is_bot": false,
          "headline": "chore: Use const in traits",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2026-01-10T22:03:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "719255ced59bbbf189897b7aad9cd5add72e4856",
          "body": "Change-Id: I89d2478e1d2a00c7f4a7f1d20a6c5c73ba6ffd08",
          "is_bot": false,
          "headline": "Drop support for PHP 8.1",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-10T20:04:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "77fa933638e539167f813a3d54186bd2dd6cd9ae",
          "body": "This repo is a libup canary repo\n\nChange-Id: I4dd9cfc9de73be3ee499dd5a1ee767b37d58d676",
          "is_bot": false,
          "headline": "build: Updating mediawiki/mediawiki-phan-config to 0.18.0",
          "author_name": "Alexander Vorwerk",
          "author_login": "ZabeMath",
          "committed_at": "2026-01-10T19:50:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0cc39024d16b6243f96cd1d53971cb0ea7cd0a99",
          "body": "Why\n- I accidentally downloaded the wrong version because the current version information was a little buried\n\nWhat\n- update README.md to mention latest version as 48.0.0 instead of 40.0.1\n- add links to places where the latest version can be accurately looked up\n\nChange-Id: Ib2da341ccf4d2c0beb73fcaa0b7ec6deef3b50c6",
          "is_bot": false,
          "headline": "readme: update version information",
          "author_name": "Novem Linguae",
          "author_login": "NovemLinguae",
          "committed_at": "2026-01-05T12:40:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "64f6ca2c828dd2c75a754342e500d24199cf6447",
          "body": "Change-Id: I60dfe2478d0ca4e507518e21dc06fb5decde228b",
          "is_bot": false,
          "headline": "ForbiddenFunctionsSniff: Add some deprecated php internal functions",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-12-29T17:20:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "598040b3764b341fcc28d428286680d126f784e6",
          "body": "Some of php predefined variables are removed or deprecated,\nremove them from the internal list to treat them as invalid.\n\nReference:\n- $php_errormsg, deprecated in php7.2, removed in php8.0\n- $HTTP_RAW_POST_DATA, deprecated in php5.6, removed in php7.2\n- $http_response_header, deprecated in php8.5\n\nBug: T413540\nChange-Id: I024f7d3eeb2e1c23d61af6fe132294922cf01514",
          "is_bot": false,
          "headline": "ValidGlobalNameSniff: Treat deprecated or removed globals as invalid",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-12-28T19:06:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0af2e089ee7e5bcb1249b63dc24d2c524e263fe8",
          "body": "Bug: T411741\nChange-Id: I07261e0fec42ea4ff5d7ec06b200defdee291413",
          "is_bot": false,
          "headline": "AssignmentInReturnSniff: Ignore arrow functions",
          "author_name": "SomeRandomDeveloper",
          "author_login": "SomeMWDev",
          "committed_at": "2025-12-04T01:11:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09ac7af0d9eb1b6521d3aaff7d92d942aa314069",
          "body": "I'm not sure if a standard exists for this, but we try to be very\npermissive, to avoid confusing error messages as reported in the task.\n\nBug: T410187\nChange-Id: I5be62b74d238e4cf6986fce667256488b4d0bbff",
          "is_bot": false,
          "headline": "FunctionCommentSniff: Parse callable parameter syntax",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-11-17T15:12:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc27dc8e8170eae2dea100b6e1a0c8f064334c73",
          "body": "…bid @phan-template and @psalm-template in favour of @template\n\nBug: T410185\nChange-Id: I92e0c12b67245d8d821c530dbbe39ab0bc2b7830",
          "is_bot": false,
          "headline": "MediaWiki.Commenting.FunctionAnnotations.NonNormalizedAnnotation: For…",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-11-17T15:08:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ea472b3c5d07af45d83b8deeaa1da5684d89e348",
          "body": "Bug: T409228\nChange-Id: If9c7b0b575f83f192af956e63cfd9940d88c1ced",
          "is_bot": false,
          "headline": "UnusedUseStatementSniff: add support for more annotations",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-11-15T01:01:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "38ffbf59e4805072f9f504c75a560f41bb2e6614",
          "body": "- https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.3\n- https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.4\n- https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.5\n\nBug: T404305\nChange-Id: I5c3091b7ef14714481a2f2270c18fed4a328f0c5",
          "is_bot": false,
          "headline": "Upgrade squizlabs/php_codesniffer from 3.13.2 to 3.13.5",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-11-14T20:13:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ca3ee875a18b41dc550e42bd24a498cb4072ee02",
          "body": "Bug: T392430\nChange-Id: I38ac36544bdb766e3811bb6dada0a537829a89c8",
          "is_bot": false,
          "headline": "UnusedUseStatementSniff: Ignore const when searching class names",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-11-14T19:57:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "39e35165660ab432cc42b434efb6f6ebf4d69361",
          "body": "- Update PHPUnit config for version 10 with `--migrate-configuration`\n- Enabled options to display all notices, deprecations, etc.\n\nChange-Id: I42726a658d43efc833c52f81abeb4db61f7df224",
          "is_bot": false,
          "headline": "build: Update phpunit/phpunit to 10.5.58",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-10-30T20:38:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d46ca2334d5e1c5be10bf28e01f6010cfbff212",
          "body": "Bug: T272803\nBug: T335006\nBug: T393853\nBug: T397047\nBug: T397781\nBug: T398060\nBug: T398711\nBug: T401074\nBug: T402593\nBug: T403736\nChange-Id: I71479d9a497edefdc633ff1b53fbd81b2de17d5a",
          "is_bot": false,
          "headline": "HISTORY: Tag as v48.0.0",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-09-04T20:12:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "efe3188e4b68f530a5ae6310214dcc17c02682a3",
          "body": "The new tokens from php8 for union types are not skipped when searching\nfor the context. This also includes readonly token.\n\nThe error message includes the token with its content, that makes the\nerror message read harder, but still possible to see the real error\nwithout this adjustment.\n\nChange-Id: Id2195bddc637b8f0b8848c6d89ca403dfa079dcb",
          "is_bot": false,
          "headline": "EmptyTagSniff: Improve error message for union-typed properties",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:33:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "00586acb9ca7dd8b40e1b9484e37bbb7aeefe589",
          "body": "New tokens from php8 are not skipped when searching visibility token\n\nChange-Id: I1e27afd09dd6560cadefb459c600c0824af8b44d",
          "is_bot": false,
          "headline": "RedundantVarNameSniff: Detect union-typed properties",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:22:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "30d4a394b118186e57aa7df579c5d5503f704507",
          "body": "There is no more need to handle the nullable operator special\n\nBug: T398711\nChange-Id: I036eecd7ff7f0607a59ed7427416436c555554a0",
          "is_bot": false,
          "headline": "FunctionCommentSniff: Remove PHP71NullableDocOptionalArg error",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:21:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a50ad0c43d58b2af3d1bb6ea251de0d8cd69726a",
          "body": "- https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.1\n- https://github.com/PHPCSStandards/PHP_CodeSniffer/releases/tag/3.13.2\n\nBug: T403736\nChange-Id: Ic9834d48129c8c12ffc2d3ef21596aac48ecc0bd",
          "is_bot": false,
          "headline": "Upgrade squizlabs/php_codesniffer from 3.13.0 to 3.13.2",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:17:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "21c4faa554cef9532a7055938a4788da2190000f",
          "body": "Validate namespace names:\n- Not using wrong casing of \"MediaWiki\"\n- Not using \"phpunit\" namespace (mostly autogenerated)\n- Not using underscores (similiar to function and class names)\n- Not using lower camel case\n\nBug: T397047\nChange-Id: I61ff4a26f5d4821ff2e45099edd63a3741b9e2f3",
          "is_bot": false,
          "headline": "Add new NamespaceNameSniff to check naming conventions",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:12:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9fca6b1d34190771dbbd71a6d197eeefe38ad633",
          "body": "New tokens from php8 are not skipped when searching visibility token\n\nChange-Id: Idec1ddb77097ae09c3161b34b2a89a4f7ed978b5",
          "is_bot": false,
          "headline": "PropertyAnnotationsSniff: Detect union-typed properties",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:11:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d8e84908c51046b253b48ab7255a611e7a3c36d",
          "body": "New tokens from php8 are not skipped when searching visibility token\n\nChange-Id: I656092431ef8fef6e921b31f74059fcfdee4d6ce",
          "is_bot": false,
          "headline": "PropertyDocumentationSniff: Detect union-typed properties",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T17:10:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d1f3d9200b95901eda529705262792ba2b9d41e",
          "body": "Bug: T401074\nChange-Id: I384601c9828918fca4e4314a2ef30f0eab1f8289",
          "is_bot": false,
          "headline": "tests: Add generic pass for constructor property promotion",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-09-04T15:25:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d61dcc42c8eba7c0b3a8441e3078c8cf431b7ce",
          "body": "Bug: T402593\nChange-Id: Ib3819bce55613e05e2c0c28130a75d2c6284a2d1",
          "is_bot": false,
          "headline": "composer.json: Relax constraint for composer/semver",
          "author_name": "Reedy",
          "author_login": "reedy",
          "committed_at": "2025-09-04T14:45:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fc06159295ceafa486456bff4488759bba413892",
          "body": "Change-Id: I239d0854cb932c64320084ec84928bd66668fd71",
          "is_bot": false,
          "headline": "build: Updating mediawiki/mediawiki-phan-config to 0.17.0",
          "author_name": "libraryupgrader",
          "author_login": null,
          "committed_at": "2025-08-08T07:13:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a0d9b417bf37d510b2559e8d66ceb372aaaeaca0",
          "body": "Change-Id: Icf4d2da2b3078eb0e1bbdfb7c7aa4081cf70d4e7",
          "is_bot": false,
          "headline": "PhpunitAnnotationsSniff: Allow @maximumDuration annotation",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-08-01T20:34:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3c56765b30df918ff61ca6f83201d2d76f463b7c",
          "body": "Change-Id: I116aeb86c70eace2ae43a2de0e36bd1e07ecd871",
          "is_bot": false,
          "headline": "build: Use autoload-dev for tests in composer.json",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-07-28T08:29:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8e6c6906f48f32ba05ddcb3f418acbb143f4666",
          "body": "See review comments on I6c065131b56619c17c9d585263b4069265fd98fd\n\nChange-Id: I607125b736b5763cfa76bdbddb0c6148c4da7b8e",
          "is_bot": false,
          "headline": "ClassAnnotationsSniff: Allow @private",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-07-28T07:47:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7a0cf3ff09bd17231d659757b8d4ac6e467a9886",
          "body": "Doc related annotations\n- @example\n- @experimental\n\nAllow some class modifier as annotation\n- @abstract\n- @extends\n- @final\n- @implements\n\nAllow following phan annotations on class comments:\n- @inherits\n- @phan-forbid-undeclared-magic-properties\n\nChange-Id: I714e0f7204f1c55117e36100414c3ace6c61ef59",
          "is_bot": false,
          "headline": "ClassAnnotationsSniff: Add more annotations",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-07-27T09:03:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "789ac9e5023672a9295d763f8445105cd67c1f40",
          "body": "Usable with phan 5.3.0\nhttps://github.com/phan/phan/issues/4152\n\nChange-Id: Id572b79775088c982ccafe9956901151a355f330",
          "is_bot": false,
          "headline": "Annotations: Allow @no-named-arguments on function or class",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-07-17T20:12:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3b90b08cf52a8c121eabfbaffa9e4d450249c25f",
          "body": "Analogous to PropertyDocumentationSniff (and parts of\nFunctionCommentSniff). For now, this only checks spacing in the doc\ncomment, but it could later be expanded to check more things.\n\nChange-Id: I599b5971ece2213603fbcb06747f229b21913770",
          "is_bot": false,
          "headline": "Add new ClassDocumentationSniff",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-07T14:39:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "121703f55a818d37658ad56e7642633dc4cbf111",
          "body": "In I044ef8847d12ae, we went with the more specific version because I\nwasn't sure if there were any tools outside phan for which the\n`@template` annotations worked differently.\n\nToday it seems clear that all tools that support `@template` support\nroughly the same syntax, so it makes sense to allow the unprefixed\nversion.\n\nBug: T397781\nChange-Id: I22873f2b5bf3398843d29935039ef6099d597838",
          "is_bot": false,
          "headline": "Allow the `@template` annotation",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-07T14:08:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d56e07dca864cc4fe855a97e142303d8e07d5114",
          "body": "Similar to the existing FunctionAnnotationsSniff and\nPropertyAnnotationsSniff.\n\nBug: T398060\nChange-Id: I3fbe7f74074149a203be1f1693fe5d95e04d896e",
          "is_bot": false,
          "headline": "Add ClassAnnotationsSniff to check for disallowed class annotations",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T23:44:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "66d8d4b159484c63d179d0c8b4d1511194fa95bd",
          "body": "This lets us share more code between FunctionAnnotationsSniff and\nPropertyAnnotationsSniff; and in a subsequent patches, a similar sniff\nfor classes.\n\nAlso bring the lists of allowed annotations all in the same place, and\ndeduplicate them by keeping a list of annotations allowed everywhere.\n\nThe lis\n[…]\nd, with the exception of\n`@phan-read-only` and `@phan-write-only` now being allowed on\nproperties, since the former is needed for this very patch.\n\nChange-Id: Ifd8db9b4c94b00bcc388d7d685ccfeb9244bc7d8",
          "is_bot": false,
          "headline": "Introduce CommentAnnotationsTrait to deduplicate some code for doc tags",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T22:49:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "a9ad233938a123cdee08b752ca63ab63d7301f2c",
          "body": "Change-Id: Ic715b21ee4adf0452c6f257394f55eb582372401",
          "is_bot": false,
          "headline": "build: Update mediawiki-phan-config to 0.16.0",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T22:44:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ecc19356267eb926f8b5edeffa53a1666b475360",
          "body": "Forbid empty doc comments, and comments with empty lines at the start or\nend. All issues are autofixable.\n\nChange-Id: I4179400c923cee2b8aeb75667c6ddd22b1b73021",
          "is_bot": false,
          "headline": "Check doc comment formatting for functions and properties",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T21:36:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "778c7974249008a98dc6a9631fdc3905864c05b2",
          "body": "Bug: T398060\nChange-Id: Ic535acc31d23cabf3239710be24385551e665f41",
          "is_bot": false,
          "headline": "Add sniff to check comments before classes",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T21:32:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "46f7e4e6f912523824fc98eada9d4da1831057ec",
          "body": "PHPUnit ignores empty lines after class and function comments, so we\nshould do the same. Also, if we need to get a class/function, we already\ndetermined that the comment contains a PHPUnit annotation anyway.\n\nAlso allow attributes between the comment and the class or function.\n\nChange-Id: I0b30d845c84bb0e66ff98b424bcf5d336abeefec",
          "is_bot": false,
          "headline": "Allow empty lines after comment in PHPunitAnnotationsSniff",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-07-06T17:49:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "13c9553a50c9ea18b3925b256e77f4385ce09664",
          "body": "Similiar to the existing FunctionAnnotationsSniff validate the\nannotations on phpDoc-blocks for class properties against an allow list.\n\nRemove @phan-var from the FunctionAnnotationsSniff\n\nBug: T398060\nChange-Id: I111ce0eba0f35cafa78fcdfa027bcd458ff2978b",
          "is_bot": false,
          "headline": "New PropertyAnnotationsSniff to validate property annotations",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-28T21:51:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f0a6d435d9c8b94ed5c9870a4a4cb44062358353",
          "body": "Check more tokens:\n- readonly is new in php8.1 (written after visibility)\n- final is new in php8.4 (written before visibility)\n\nChange-Id: Ia361f06c72b1c0d3f63d33583adc75c373c3fcab",
          "is_bot": false,
          "headline": "RedundantVarNameSniff: Check for readonly and final",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-28T20:45:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b446de1832fbdce7f32b0cec04c26ab42ae991b",
          "body": "Check more tokens:\n- readonly is new in php8.1 (written after visibility)\n- final is new in php8.4 (written before visibility)\n- anon classes are possible since php7\n\nUse array_key_last, since php8.1 functions are allowed\n\nChange-Id: I5b3964e433cf80e94d3953acde795589f29806c8",
          "is_bot": false,
          "headline": "PropertyDocumentationSniff: Check for readonly, final and anon classes",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-28T19:30:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e25b084c1db7955d9db1b27231d4757c7efc90a1",
          "body": "PHP itself produce a warning with php8\n\nChange-Id: Ie8d0219cbb563d93cfa3c0077f2d6b7dcfe5f7ab",
          "is_bot": false,
          "headline": "Remove FinalPrivateSniff",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-18T21:41:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0d983eb9aaee4e72ca72420b9cbe389bf593e63a",
          "body": "Remove symfony/polyfill-php80 as no longer needed.\nIt is still required by phan/phan and not uninstalled\n\nChange-Id: Icafffd8c39f8362c7c6dafbc26424125247fe244",
          "is_bot": false,
          "headline": "build: Require php 8.1",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-18T21:41:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d2242dd3000e5689b79bd1caa344c67f8a88a19",
          "body": "When coding without an IDE, I often copy-paste `use` statements\nbetween files, and sometimes I end up with duplicate identical uses.\nI wish that PHPCBF would fix them for me.\n\nIf any conflicting `use` statements are not identical, report\na non-fixable issue.\n\nChange-Id: I2113c4dcb43965146db2ff8fb54206d147664b9e",
          "is_bot": false,
          "headline": "UnusedUseStatementSniff: Also report duplicate/conflicting uses",
          "author_name": "Bartosz Dziewoński",
          "author_login": "MatmaRex",
          "committed_at": "2025-06-16T21:04:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3e2d4697f161b6e30f3409ef414ac55a451fb5f",
          "body": "Due to a change in phpcsstandards/phpcsutils, this repo needs newer\nphpcsstandards/phpcsextra to pass tests.\n\nThe indirect dependency phpcsstandards/phpcsutils is updated from 1.0.12\nto 1.1.0 and sniff error codes changed as sniffs now detect errors\noutside the closure scope.\nThis is fixed in the di\n[…]\ns update to 1.1.0\n\nhttps://github.com/PHPCSStandards/PHPCSUtils/releases/tag/1.1.0\nhttps://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.4.0\n\nChange-Id: I82c21c8e28bb621830f44e38c8fa08d4eb3460c6",
          "is_bot": false,
          "headline": "Upgrade phpcsstandards/phpcsextra from 1.3.0 to 1.4.0",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-16T18:16:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "caba63154ede69ad1a65852d54acdd0929898ea1",
          "body": "Note that we're dropping the use of upstream's newly-deprecated sniff,\nSquiz.CSS.SemicolonSpacing\n\nBug: T393853\nChange-Id: Iad48fa8b3ae348d13890ba91594fcaff7fa9f25b",
          "is_bot": false,
          "headline": "Upgrade squizlabs/php_codesniffer from 3.12.2 to 3.13.0",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-06-02T17:41:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "24b9829e363cb4d7c1e0f80a31fd407018d84096",
          "body": "No need to check the functions of anon classes used in test files\n\nChange-Id: I4e6961ac126972597949dc91285f519ef1856bc4",
          "is_bot": false,
          "headline": "PHPUnitTypeHintsSniff: Skip anon classes",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-06-02T17:11:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "288186ec0d08c15184d6dbc4c2b4abb849b5e523",
          "body": "For parity with @phan-suppress-next-line; I don't think these were omitted\non purpose.\n\nNote, @phan-suppress-current-line should not be needed here.\n\nChange-Id: Ie998000268277cd6a0e38e08903344f62f28068b",
          "is_bot": false,
          "headline": "FunctionAnnotationsSniff: allow more phan suppressions",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-05-30T20:57:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e84dd7fcb6c6c0f1e757af41b547f4d03523358",
          "body": "They should be equivalent.\n\nBug: T335006\nChange-Id: I6f13dfcb80e0b051114d5eeff977daebc88d2016",
          "is_bot": false,
          "headline": "Replace NestedFunctionsSniff with upstream InnerFunctionsSniff",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-05-27T15:41:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a42d6663ea937d7f1a14e88d9984d6eee820144f",
          "body": "Only function starting with get* or is* are required to document the\nreturn value with @return or with return type. Require it for all\nparameterless functions.\n\nNeeds check for live coding in FunctionComment to pass example in\nvariadic_argument_incomplete.php without require documentation.\n\nBug: T272803\nChange-Id: I1efd60ddb98fd1091d894c5ff121097e86253246",
          "is_bot": false,
          "headline": "Require documentation for parameterless function with return value",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-05-15T16:23:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ed516d39b93c7012a905156fb2d60071eb4e8b9d",
          "body": "Forbid new annotations from PHPUnit 10\nhttps://github.com/sebastianbergmann/phpunit/commit/263079aaafb0251c0e72a2a60402ac8a5cb8b244\nThere are similiar to @backupGlobals or @backupStaticAttributes\n\nChange-Id: Ibd5aed0623e50d87899b9a5e425dcc7988b31c2e",
          "is_bot": false,
          "headline": "PhpunitAnnotationsSniff: Forbid new @exclude*FromBackup annotations",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-05-05T19:17:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "12eb62747f590d58b8e6d0463baa31c96ceb23ef",
          "body": "See changelog: https://github.com/PHPCSStandards/PHPCSExtra/releases/tag/1.3.0\n\nChange-Id: Ia8cc2651b4bf061a5f7a2dd571858ab731a761af",
          "is_bot": false,
          "headline": "build: Upgrade phpcsstandards/phpcsextra to 1.3.0",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-05-05T18:04:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b48ff19466020a5577869f5e7a285f3fd2603f69",
          "body": "Deprecated in upstream version 3.12.1, see\nhttps://github.com/PHPCSStandards/PHP_CodeSniffer/issues/921. Call-time\npass-by-reference is no longer a thing since PHP 5.4.\n\nChange-Id: I3b5523160bf2b70f4b0dfbb71004dfbf5c801b35",
          "is_bot": false,
          "headline": "Drop Generic.Functions.CallTimePassByReference",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-05-05T17:18:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3780a2706ecf565ecd2bd2aacdc3c4f6d7b54553",
          "body": "Change-Id: Id74a1c2c6444df5a37446dca73c069145cdedac6",
          "is_bot": false,
          "headline": "PHPUnit sniffs: Avoid error on live coding about missing scope opener",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-05-04T15:09:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "056bb337d5229699356884563431b9cc6521ad14",
          "body": "Change-Id: Id86cd3501d02505a438ba49c1be968bdaac0a6ea",
          "is_bot": false,
          "headline": "HISTORY: Tag as v47.0.0",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-05-04T07:30:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cb08456a9728373232fd242faee4292dc0d14f53",
          "body": "Upstream changes now mean that our tests now trigger one extra\nSquiz.WhiteSpace.ScopeKeywordSpacing.Incorrect, but one fewer\nSquiz.WhiteSpace.FunctionSpacing.Before, and the fixer removes\nthe empty line before the start of a function block now.\n\nChange-Id: I066fc8a88d5d58405939715eed38af6df4a1d923",
          "is_bot": false,
          "headline": "Upgrade squizlabs/php_codesniffer from 3.11.3 to 3.12.2",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-05-04T07:28:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ff49a386618d6fd415a4c79ea1cf6d80a2234d8",
          "body": "Ensure a data provider function starts with provide or\nends with Provider. This allows to apply further checks on data provider\nfunctions later, like a check for static functions (T333745)\n\nDocumented at\nhttps://www.mediawiki.org/w/index.php?title=Manual:PHP_unit_testing/Writing_unit_tests&oldid=6864877#Data_providers\n\nAlso check for punctation like \"()\" at end and remove with autofix\n\nBug: T337098\nChange-Id: Ie83678177d227ff4684c77f54b6d3e42e2ff468e",
          "is_bot": false,
          "headline": "PhpunitAnnotationsSniff: Enforce naming convention for @dataProvider",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-05-01T04:31:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e1d17a7ec10979b45da1078cfae135431d7ef436",
          "body": "When checking for unnecessary whitespace within parentheses, look for\nthe next non-whitespace token before the closer parenthesis, rather than\ntrying to count the tokens. This allows us to catch more cases of\nunnecessary whitespace, as demonstrated by the new tests.\n\nFor arrays (short or long), pres\n[…]\nnthesis, so it's easier to see what is being done.\n\nAdd a few test cases, and disable the rule for long arrays as it's not\nrelevant to this sniff.\n\nChange-Id: Id8a9bb037a485574a8423540d049e118ccb7598c",
          "is_bot": false,
          "headline": "SpaceyParenthesisSniff: detect unnecessary whitespace in more cases",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-04-01T19:25:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "7ae053eb0dac8e243db3bfa4e1a0298f01f2690a",
          "body": "Use `findPrevious` to jump to the last non-whitespace token, instead of\nassuming that all whitespace will be in a single token. This allows us\nto catch extra newlines.\n\nChange-Id: Ia17553957913c522544568d56c24c2cf7e26596f",
          "is_bot": false,
          "headline": "SpaceyParenthesisSniff: account for multiple spaces before parens",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-04-01T19:25:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "756d2e8009c582c6ea71eb8d33dcc7ff595bfc30",
          "body": "The sniff does nothing to distinguish between function calls and\nfunction declarations. So, generalize the error message to avoid any\npotential confusion.\n\nI think the assumption of \"array or function\" should always be true as\nlong as the code is valid, but I didn't prove it.\n\nChange-Id: I6031f5f0c24482d6d87399a1f20e39a379dbd61f",
          "is_bot": false,
          "headline": "SpaceyParenthesisSniff: avoid wrong guesses of function calls",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-04-01T19:25:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9d9868fc82f78586a777ffb127907382338cb04d",
          "body": "- Drop the wfFailedExamples / wfPassedExamples boilerplate. We need to\n  define functions for some test cases. The tautological doc comment and\n  pointless `@return void` are also just a waste of space.\n- Move tests from generic test files to the sniff-specific file. This\n  part is a follow-up to I04a2e34ec55a568.\n- Add names to the various test cases.\n\nThe limitations seen in the tests will be fixed in Ia17553957913c522.\n\nChange-Id: I6b8521f8b667fd19fd4f724648250f205d85ce78",
          "is_bot": false,
          "headline": "Consolidate tests for space before parenthesis",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-04-01T19:24:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "315bb4a7f99c117f4d288d1b41f1b81789f3379b",
          "body": "Same condition and comments are used on UnusedUseStatementSniff and\nUnsortedUseStatementsSniff classes.\nMove the closure check in the loop to run it per bracketed namespace,\nChange the empty() check with a level check to handle global and\nnamespace scope.\n\nChange-Id: I0e6e0b831ae32a377b8bf99dfb71d48b7735cd65",
          "is_bot": false,
          "headline": "Allow EmptyLinesBetweenUseSniff to work with bracketed namespaces",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-04-01T16:06:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "747840d7591fceabbc5dfaa4d01fe20bd7dec189",
          "body": "For typed properties the comment before should be ignored when the\ncomment style is not a doc-block /** */.\nFor fully typed functions (arguments and return type) the comment before\nshould be ignored when the comment style is not a doc-block /** */.\n\nMove the check for T_COMMENT into the existing if block to avoid the\nnot-condition and make reuse of the code for \"fully typed\" easier.\n\nBug: T375033\nChange-Id: I04f50dc57c7f3a179c44e5851570b1691895d89d",
          "is_bot": false,
          "headline": "Relax WrongStyle warning for property and function documentations",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-03-22T19:50:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37f8a3549a26e1d1adc110005a446e13daabf978",
          "body": "--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]\n    Select only files that are Added (A), Copied (C), Deleted (D),\nModified (M), Renamed (R), ...\n\nWhen Gerrit detects a file rename,\nthe Add + Delete flags does not select the file\n\nBug: T388319\nChange-Id: I6f1f0e62a3ff8a09225ee80d2fa102078d30a174",
          "is_bot": false,
          "headline": "utils: Include renamed files when using bootstrap-ci.php",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-03-18T17:29:36Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8b3d8d3aeb8befc583c94b1975bd40116325ee4b",
          "body": "Done in 9423de5e37,\nbut lost on some rebase afterwards (53f4c763ae / aa5f2b5248 ).\n\nRequire the newline via tests by removing the prepareOutput() part\nfor the expected file\n\nFollow-Up: I048dc72b1caa1acb5f0a278859314d57c6112d03\nChange-Id: Ibd3147ee152c3b676c8aa9672b4b499c6395b458",
          "is_bot": false,
          "headline": "Readd newline at end of all .expect files",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2025-03-17T21:20:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ada22f4aba53edc2002390c372c50109f4416a0f",
          "body": "Currently, our ruleset is very permissive with closure declarations, and\ndoes not flag code that would normally be flagged for normal\n(non-closure) declarations. Turns out the\nOpeningFunctionBraceKernighanRitchieSniff sniff has a configurable\n`checkClosures` property, false by default and that we never enabled.\n\nThe added tests documents the unwanted behaviour. A subsequent patch\nwill enable the closure checks, to show the differences.\n\nChange-Id: Ic9a9f82c5ac4708982e51b48232cc56606821b92",
          "is_bot": false,
          "headline": "Add tests for closure declarations",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-03-17T21:10:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3a6622777ed1cdf294b6bcea8fdb650cc587c89",
          "body": "The sniff in question never checked that it was actually dealing with\nnamespace `use`. This led to an edge case under the following\nconditions:\n- The first `use` statement in the file belongs to a closure.\n- There is at least another `use` after that.\n- The second `use ` statement is the first non-e\n[…]\n for example, see PS 4 of Ic9a9f82c5ac47.\n\nOTOH, checking for closure `use` is cheap and only needs to be done once\nper per file, so just do that.\n\nChange-Id: Id99b1f35234e9b85481c078dc8cb83203a800b8c",
          "is_bot": false,
          "headline": "EmptyLinesBetweenUseSniff: fix edge case with closures",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-03-17T21:08:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3806162bcd1a7427fcf7da69cba4cbb38c899a3d",
          "body": "I was recently confused as to why phpcs was analyzing fewer files in CI than it was locally. Providing some basic output might help readers of CI logs to understand what phpcs is doing.\n\nChange-Id: I1b25b059ba134e6a33e8e5e9d839b9cb3524c027",
          "is_bot": false,
          "headline": "Add basic output to bootstrap-ci.php",
          "author_name": "Ollie",
          "author_login": "outdooracorn",
          "committed_at": "2025-03-13T23:34:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "53f4c763ae0a493bdae4381438e7683d539119b0",
          "body": "This is an addition of tests for style inconsistencies that I have\npersonally seen recently. Some of these are covered by existing\nsniffs, and so the test documents that. Others aren't, in particular:\n- We do not enforce that function call parentheses are adjacent to the\n  function name (ref CC/PHP:\n[…]\nof each parameter).\n\nSome of these test cases might be moved to more specific test files if\nand when we enable new sniffs that catch those issues.\n\nChange-Id: I04a2e34ec55a56800e3dffa67d3d9e038872a330",
          "is_bot": false,
          "headline": "Add tests for miscellaneous style inconsistencies seen in the wild",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-03-03T23:27:46Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6bd8a9ac4c10bf393dcd9ef32e3402399128a9e5",
          "body": "Bug: T328529\nBug: T371048\nBug: T378552\nBug: T379674\nChange-Id: I11f928e3de0163d29e5f1c493e272a6e0d714502",
          "is_bot": false,
          "headline": "HISTORY: Tag as v46.0.0",
          "author_name": "Jakob Warkotsch",
          "author_login": "jakobw",
          "committed_at": "2025-01-27T21:05:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8983532e577ea45109a62e79e22cf26200629393",
          "body": "Bug: T379674\nChange-Id: I4af17202b16ecc664068d99a053982923e641e26",
          "is_bot": false,
          "headline": "Raise PHP CodeSniffer from 3.11.1 to 3.11.3",
          "author_name": "Reedy",
          "author_login": "reedy",
          "committed_at": "2025-01-27T15:03:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "aa5f2b5248612102aa8647b6ba4e722f26800106",
          "body": "Partial revert of I1e85a43e3f5626ca017893f25553d6a9fbcaaaf0, which\ndisabled the ScopeIndent sniff on this test file due to upstream issue\nhttps://github.com/squizlabs/PHP_CodeSniffer/issues/3808.\n\nThis has now been resolved in 3.11, so the exclusion can be removed.\n\nChange-Id: I22d18849d0207528bf14ca6709a74523f20a6ff3",
          "is_bot": false,
          "headline": "Re-enable ScopeIndent sniff on test that was previously failing",
          "author_name": "Daimona Eaytoy",
          "author_login": "Daimona",
          "committed_at": "2025-01-12T23:44:31Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3a616961bcacabc56ad39ed0ab354e6c05fffcb6",
          "body": "Update AssignmentInReturnSniff for the BC break in\nhttps://github.com/PHPCSStandards/PHP_CodeSniffer/pull/647.\n\nBug: T379674\nChange-Id: I01009b858466b7c678c799d8c99207f3395b7a5d",
          "is_bot": false,
          "headline": "Raise PHP CodeSniffer from 3.10.3 to 3.11.1",
          "author_name": "James D. Forrester",
          "author_login": "jdforrester",
          "committed_at": "2025-01-12T23:39:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9479c6bfde10439bb64929ec14a5f5a0666da50b",
          "body": "Bug: T328529\nChange-Id: Ia8f1d8de3183e3e55af5ff88d8ce451e2fb2a9fc",
          "is_bot": false,
          "headline": "StaticClosureSniff: Work on fn() too",
          "author_name": "Reedy",
          "author_login": "reedy",
          "committed_at": "2025-01-10T12:11:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7bf21d735904dc44010cc21919187a8c0ae0b0a6",
          "body": "Change-Id: Iedbf7ba6574ef32c3fcf772bb7d219e093a43901",
          "is_bot": false,
          "headline": "build: Updating mediawiki/mediawiki-phan-config to 0.15.1",
          "author_name": "libraryupgrader",
          "author_login": null,
          "committed_at": "2025-01-10T06:18:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "82f8c837886262e0b6e0ef86a989e3219ada2c3d",
          "body": "New in PHPUnit 9.1\nhttps://github.com/sebastianbergmann/phpunit/issues/4148\n\nChange-Id: Ie147e7446e8edf1febf56cab7f69e0c33584395d",
          "is_bot": false,
          "headline": "Allow use of @preCondition and @postCondition PHPUnit annotations",
          "author_name": "Umherirrender",
          "author_login": "umherirrender",
          "committed_at": "2024-12-13T23:32:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6939f62e11fc840b02afef39a05a6b7cfbf6fa17",
          "body": "Change-Id: Ic48bdb85ecf7acc885f7311214424bbf7492cb7b",
          "is_bot": false,
          "headline": "build: Updating mediawiki/mediawiki-phan-config to 0.15.0",
          "author_name": "libraryupgrader",
          "author_login": null,
          "committed_at": "2024-12-10T04:50:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "46219203f89ed91711f661db01e5d901c304f1f2",
          "body": "The mixed type (PHP 8+) already includes 'null'. So trying to fix that\nto '?mixed' fails with a type error.\n\nBug: T378552\nChange-Id: I8e3034888942ed398d6459f45bc3404d358fc289",
          "is_bot": false,
          "headline": "NullableTypeSniff: 'mixed' is already nullable",
          "author_name": "Taavi Väänänen",
          "author_login": "supertassu",
          "committed_at": "2024-12-09T19:24:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fd6ecb5ffbe353507ca05387176db02f0f41f6fe",
          "body": "This feature improves code consistency and readability by ensuring that arrays with PHP symbols (e.g., constants, variables) follow a consistent alphabetical order.\n\nBug: T371048\nChange-Id: Ia125bdc9d82853bcebbc6fdaa83057824dc1059a",
          "is_bot": false,
          "headline": "Support sorting PHP symbols in arrays",
          "author_name": "Muhammad Yasser Jazirahly",
          "author_login": "MuhammadJaziraly",
          "committed_at": "2024-12-02T09:16:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d54068835d534ad246588e20dc88850b98768610",
          "body": "Change-Id: Ib20093e38abb3e7cc2befc4dacc0fb69e4c7360a",
          "is_bot": false,
          "headline": "build: Updating phpunit/phpunit to 9.6.21",
          "author_name": "libraryupgrader",
          "author_login": null,
          "committed_at": "2024-11-28T23:17:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 65,
      "commits_last_year": 44,
      "latest_release_at": "2026-05-03T06:29:24Z",
      "latest_release_tag": "v51.0.0",
      "releases_from_tags": true,
      "days_since_last_push": 82,
      "active_weeks_last_year": 18,
      "days_since_latest_release": 86,
      "mean_days_between_releases": 106.1
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 50,
      "has_issue_template": false,
      "has_code_of_conduct": true,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": [
        {
          "name": "mediawiki/mediawiki-codesniffer",
          "exists": true,
          "license": "GPL-2.0-or-later",
          "keywords": [
            "codesniffer",
            "mediawiki"
          ],
          "ecosystem": "packagist",
          "matches_repo": true,
          "registry_url": "https://packagist.org/packages/mediawiki/mediawiki-codesniffer",
          "is_deprecated": false,
          "latest_version": "v51.0.0",
          "repository_url": "https://github.com/wikimedia/mediawiki-tools-codesniffer",
          "versions_count": 65,
          "total_downloads": 3241095,
          "dependents_count": 352,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": 75597,
          "first_published_at": null,
          "latest_published_at": "2026-05-03T06:29:24Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 86
        }
      ]
    },
    "popularity": {
      "forks": 12,
      "stars": 33,
      "watchers": 11,
      "fork_history": {
        "days": [
          {
            "date": "2015-06-03",
            "count": 1
          },
          {
            "date": "2015-11-29",
            "count": 1
          },
          {
            "date": "2016-04-01",
            "count": 1
          },
          {
            "date": "2016-04-20",
            "count": 1
          },
          {
            "date": "2017-04-07",
            "count": 1
          },
          {
            "date": "2017-06-14",
            "count": 1
          },
          {
            "date": "2020-01-01",
            "count": 1
          },
          {
            "date": "2020-01-19",
            "count": 1
          },
          {
            "date": "2022-04-25",
            "count": 1
          },
          {
            "date": "2024-11-27",
            "count": 1
          },
          {
            "date": "2026-07-27",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 11,
        "total_forks": 12
      },
      "star_history": null,
      "open_issues_and_prs": 0
    },
    "ai_readiness": {
      "has_nix": false,
      "example_dirs": [],
      "has_llms_txt": false,
      "has_dockerfile": false,
      "has_mcp_signal": false,
      "bootstrap_files": [],
      "api_schema_files": [],
      "has_devcontainer": false,
      "typecheck_configs": [],
      "toolchain_manifests": [],
      "largest_source_bytes": 26888,
      "source_files_sampled": 189,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "composer.json"
      ],
      "advisories": {
        "error": null,
        "scope": "repository_graph",
        "source": "osv",
        "findings": [],
        "collected": true,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 7,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 5,
        "direct_affected_count": 0
      },
      "ecosystems": [
        "packagist"
      ],
      "dependencies": [
        {
          "name": "squizlabs/php_codesniffer",
          "manifest": "composer.json",
          "ecosystem": "packagist",
          "version_constraint": "3.13.5"
        }
      ],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [
          {
            "name": "squizlabs/php_codesniffer",
            "direct": true,
            "version": "3.13.5",
            "ecosystem": "packagist"
          },
          {
            "name": "composer/semver",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "composer/spdx-licenses",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "ext-dom",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "ext-mbstring",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "mediawiki/mediawiki-phan-config",
            "direct": false,
            "version": "0.20.0",
            "ecosystem": "packagist"
          },
          {
            "name": "mediawiki/minus-x",
            "direct": false,
            "version": "2.0.1",
            "ecosystem": "packagist"
          },
          {
            "name": "php",
            "direct": false,
            "version": null,
            "ecosystem": "packagist"
          },
          {
            "name": "php-parallel-lint/php-console-highlighter",
            "direct": false,
            "version": "1.0.0",
            "ecosystem": "packagist"
          },
          {
            "name": "php-parallel-lint/php-parallel-lint",
            "direct": false,
            "version": "1.4.0",
            "ecosystem": "packagist"
          },
          {
            "name": "phpcsstandards/phpcsextra",
            "direct": false,
            "version": "1.5.0",
            "ecosystem": "packagist"
          },
          {
            "name": "phpunit/phpunit",
            "direct": false,
            "version": "10.5.63",
            "ecosystem": "packagist"
          }
        ],
        "collected": true,
        "truncated": false,
        "total_count": 12,
        "direct_count": 1,
        "indirect_count": 11
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 0,
        "open_issues": 0,
        "closed_ratio": null,
        "closed_issues": 0,
        "closed_unmerged_prs": 3
      },
      "bus_factor": 3,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "umherirrender",
          "commits": 278,
          "avatar_url": "https://avatars.githubusercontent.com/u/1174884?v=4"
        },
        {
          "type": "User",
          "login": "legoktm",
          "commits": 139,
          "avatar_url": "https://avatars.githubusercontent.com/u/81392?v=4"
        },
        {
          "type": "User",
          "login": "thiemowmde",
          "commits": 118,
          "avatar_url": "https://avatars.githubusercontent.com/u/6576639?v=4"
        },
        {
          "type": "User",
          "login": "DannyS712",
          "commits": 65,
          "avatar_url": "https://avatars.githubusercontent.com/u/46829944?v=4"
        },
        {
          "type": "User",
          "login": "Daimona",
          "commits": 64,
          "avatar_url": "https://avatars.githubusercontent.com/u/38216014?v=4"
        },
        {
          "type": "User",
          "login": "jdforrester",
          "commits": 46,
          "avatar_url": "https://avatars.githubusercontent.com/u/881572?v=4"
        },
        {
          "type": "User",
          "login": "reedy",
          "commits": 31,
          "avatar_url": "https://avatars.githubusercontent.com/u/67615?v=4"
        },
        {
          "type": "User",
          "login": "hashar",
          "commits": 29,
          "avatar_url": "https://avatars.githubusercontent.com/u/281689?v=4"
        },
        {
          "type": "User",
          "login": "ZabeMath",
          "commits": 19,
          "avatar_url": "https://avatars.githubusercontent.com/u/35405030?v=4"
        },
        {
          "type": "User",
          "login": "paladox",
          "commits": 16,
          "avatar_url": "https://avatars.githubusercontent.com/u/5727000?v=4"
        }
      ],
      "contributors_sampled": 58,
      "top_contributor_share": 0.292
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": false,
      "linter_configs": [],
      "has_editorconfig": false,
      "has_linter_config": false,
      "has_precommit_config": false
    },
    "security_signals": {
      "lockfiles": [],
      "scorecard": {
        "checks": [
          {
            "name": "Binary-Artifacts",
            "score": 10,
            "reason": "no binaries found in the repo",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#binary-artifacts"
          },
          {
            "name": "Branch-Protection",
            "score": 0,
            "reason": "branch protection not enabled on development/release branches",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": null,
            "reason": "no pull request found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#ci-tests"
          },
          {
            "name": "CII-Best-Practices",
            "score": 0,
            "reason": "no effort to earn an OpenSSF best practices badge detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#cii-best-practices"
          },
          {
            "name": "Code-Review",
            "score": 0,
            "reason": "Found 0/30 approved changesets -- score normalized to 0",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#code-review"
          },
          {
            "name": "Contributors",
            "score": 10,
            "reason": "project has 43 contributing companies or organizations",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#contributors"
          },
          {
            "name": "Dangerous-Workflow",
            "score": null,
            "reason": "no workflows found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 0,
            "reason": "no update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 0,
            "reason": "project is not fuzzed",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#fuzzing"
          },
          {
            "name": "License",
            "score": 10,
            "reason": "license file detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#license"
          },
          {
            "name": "Maintained",
            "score": 5,
            "reason": "6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#maintained"
          },
          {
            "name": "Packaging",
            "score": null,
            "reason": "packaging workflow not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#packaging"
          },
          {
            "name": "Pinned-Dependencies",
            "score": null,
            "reason": "no dependencies found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "no SAST tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#sast"
          },
          {
            "name": "Security-Policy",
            "score": 0,
            "reason": "security policy file not detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#security-policy"
          },
          {
            "name": "Signed-Releases",
            "score": null,
            "reason": "no releases found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#signed-releases"
          },
          {
            "name": "Token-Permissions",
            "score": null,
            "reason": "No tokens found",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#token-permissions"
          },
          {
            "name": "Vulnerabilities",
            "score": 10,
            "reason": "0 existing vulnerabilities detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#vulnerabilities"
          }
        ],
        "commit": "9fd2bf1d8e772ce9ee253862574235a2b38f4215",
        "ran_at": "2026-07-28T15:02:39Z",
        "aggregate_score": 3.5,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": false
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": null,
      "oldest_open_prs": [],
      "last_merged_pr_at": null,
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/wikimedia/mediawiki-tools-codesniffer",
    "host": "github.com",
    "name": "mediawiki-tools-codesniffer",
    "owner": "wikimedia"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 55,
      "inputs": {
        "security": 48,
        "vitality": 62,
        "community": 59,
        "governance": 62,
        "engineering": 40
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "moderate",
        "name": "Vitality",
        "value": 62,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "commits_last_year": 44,
              "human_commit_share": 1,
              "days_since_last_push": 82,
              "active_weeks_last_year": 18
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 82 days ago",
                "points": 18,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 82
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "18/52 weeks with commits",
                "points": 12.5,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 18
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "44 commits in the last year",
                "points": 14.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 44
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5",
                "points": 5,
                "status": "partial",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "good",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 80,
            "inputs": {
              "releases_count": 65,
              "latest_release_tag": "v51.0.0",
              "releases_from_tags": true,
              "days_since_latest_release": 86,
              "mean_days_between_releases": 106.1
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "65 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 65
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 86 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 86
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~106.1 days",
                "points": 19.8,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 106.1
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "openssf_scorecard_signed_releases",
                "name": "OpenSSF Scorecard: Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "abandonment",
            "band": "excellent",
            "name": "Abandonment",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "cap": null,
              "state": "maintained",
              "guards": [],
              "signals": [],
              "red_flag": false,
              "multiplier_pct": 100,
              "declared_reason": null,
              "unverified_reason": null,
              "unanswered_open_prs": null,
              "unanswered_open_issues": null,
              "days_since_last_merged_pr": null,
              "days_since_last_human_commit": 82,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 82 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 82
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "moderate",
        "name": "Community & Adoption",
        "value": 59,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 39,
            "inputs": {
              "forks": 12,
              "stars": 33,
              "watchers": 11,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "33 stars",
                "points": 24.4,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 33
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "12 forks",
                "points": 8.7,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 12
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "11 watchers",
                "points": 5.6,
                "status": "partial",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 11
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 65,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": true,
              "has_pull_request_template": false
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 22.5,
                "status": "met",
                "details": [],
                "max_points": 22.5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "recognized license (GPL-2.0)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "GPL-2.0"
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributing_guide",
                "name": "CONTRIBUTING guide",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "code_of_conduct",
                "name": "Code of conduct",
                "detail": null,
                "points": 13.5,
                "status": "met",
                "details": [],
                "max_points": 13.5
              },
              {
                "key": "issue_template",
                "name": "Issue template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.2
              },
              {
                "key": "pr_template",
                "name": "PR template",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.3
              }
            ]
          },
          {
            "key": "ecosystem_adoption",
            "band": "good",
            "name": "Ecosystem adoption (downloads)",
            "note": null,
            "notes": [],
            "value": 82,
            "inputs": {
              "packages": [
                "mediawiki/mediawiki-codesniffer"
              ],
              "dependents": 352,
              "ecosystems": "packagist",
              "total_downloads": 3241095,
              "monthly_downloads": 75597
            },
            "components": [
              {
                "key": "monthly_downloads",
                "name": "Monthly downloads",
                "detail": "75,597 downloads/month across packagist",
                "points": 65,
                "status": "partial",
                "details": [
                  {
                    "code": "downloads_monthly",
                    "params": {
                      "count": 75597,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 80
              },
              {
                "key": "registry_dependents",
                "name": "Registry dependents",
                "detail": "352 packages depend on it",
                "points": 17,
                "status": "partial",
                "details": [
                  {
                    "code": "registry_dependents",
                    "params": {
                      "count": 352
                    }
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "moderate",
        "name": "Sustainability & Governance",
        "value": 62,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "good",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "bus_factor": 3,
              "contributors_sampled": 58,
              "top_contributor_share": 0.292
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "3 contributor(s) cover half of all commits",
                "points": 36,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 3
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 29% of commits",
                "points": 15.9,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 29
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "58 contributors",
                "points": 13.5,
                "status": "met",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 58
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 43 contributing companies or organizations",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "critical",
            "name": "Issue & PR responsiveness",
            "note": "Excluded from scoring (no data or not applicable): Issue resolution. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "issue_resolution"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 1,
            "inputs": {
              "merged_prs": 0,
              "open_issues": 0,
              "closed_issues": 0,
              "issue_closed_ratio": null,
              "closed_unmerged_prs": 3
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "no issues or no data",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_issues_or_data",
                    "params": {}
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "0/3 decided PRs merged",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 0,
                      "decided": 3
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              }
            ]
          },
          {
            "key": "stewardship",
            "band": "good",
            "name": "Ownership & stewardship",
            "note": null,
            "notes": [],
            "value": 79,
            "inputs": {
              "followers": 2188,
              "owner_type": "Organization",
              "is_verified": null,
              "owner_login": "wikimedia",
              "public_repos": 1963,
              "account_age_days": 6365
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "organization-owned",
                "points": 30,
                "status": "met",
                "details": [
                  {
                    "code": "owner_organization",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "2,188 followers of wikimedia",
                "points": 24,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 2188,
                      "login": "wikimedia"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "1963 public repos, account ~17 yr old",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 1963
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 17
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "mediawiki/mediawiki-codesniffer"
              ],
              "ecosystems": "packagist",
              "any_deprecated": false,
              "min_days_since_publish": 86
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on packagist",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "packagist"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 86 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 86
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "65 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 65
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "at_risk",
        "name": "Engineering Quality",
        "value": 40,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "at_risk",
            "name": "Engineering practices",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_ci_tests"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 30,
            "inputs": {
              "has_ci": false,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": false,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 24
              },
              {
                "key": "tests_present",
                "name": "Tests present",
                "detail": null,
                "points": 24,
                "status": "met",
                "details": [],
                "max_points": 24
              },
              {
                "key": "linter_config",
                "name": "Linter config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 16
              },
              {
                "key": "pre_commit_hooks",
                "name": "Pre-commit hooks",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 9.6
              },
              {
                "key": "editorconfig",
                "name": ".editorconfig",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 6.4
              },
              {
                "key": "openssf_scorecard_ci_tests",
                "name": "OpenSSF Scorecard: CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "topics": [],
              "has_wiki": false,
              "homepage": "https://gerrit.wikimedia.org",
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://gerrit.wikimedia.org",
                "points": 15,
                "status": "met",
                "details": [],
                "max_points": 15
              },
              {
                "key": "repository_description",
                "name": "Repository description",
                "detail": null,
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "topics",
                "name": "Topics",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 48,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "at_risk",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): CI-Tests, Dangerous-Workflow, Packaging, Pinned-Dependencies, Signed-Releases, Token-Permissions. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "ci_tests",
                    "dangerous_workflow",
                    "packaging",
                    "pinned_dependencies",
                    "signed_releases",
                    "token_permissions"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 35,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 3.5
            },
            "components": [
              {
                "key": "binary_artifacts",
                "name": "Binary-Artifacts",
                "detail": "no binaries found in the repo",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "branch_protection",
                "name": "Branch-Protection",
                "detail": "branch protection not enabled on development/release branches",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "no pull request found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 2.5
              },
              {
                "key": "cii_best_practices",
                "name": "CII-Best-Practices",
                "detail": "no effort to earn an OpenSSF best practices badge detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "code_review",
                "name": "Code-Review",
                "detail": "Found 0/30 approved changesets -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "contributors",
                "name": "Contributors",
                "detail": "project has 43 contributing companies or organizations",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "dangerous_workflow",
                "name": "Dangerous-Workflow",
                "detail": "no workflows found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "no update tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is not fuzzed",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "license",
                "name": "License",
                "detail": "license file detected",
                "points": 2.5,
                "status": "met",
                "details": [],
                "max_points": 2.5
              },
              {
                "key": "maintained",
                "name": "Maintained",
                "detail": "6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5",
                "points": 3.8,
                "status": "partial",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "packaging",
                "name": "Packaging",
                "detail": "packaging workflow not detected",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "pinned_dependencies",
                "name": "Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "no SAST tool detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "security_policy",
                "name": "Security-Policy",
                "detail": "security policy file not detected",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 5
              },
              {
                "key": "signed_releases",
                "name": "Signed-Releases",
                "detail": "no releases found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "token_permissions",
                "name": "Token-Permissions",
                "detail": "No tokens found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "vulnerabilities",
                "name": "Vulnerabilities",
                "detail": "0 existing vulnerabilities detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              }
            ]
          },
          {
            "key": "dependency_advisories",
            "band": "excellent",
            "name": "Dependency advisories",
            "note": "Excluded from scoring (no data or not applicable): Indirect dependencies free of known advisories, No advisories left outstanding. Remaining weights renormalized. Matched 7 resolved dependencies against OSV; 5 could not be assessed (no resolved version, an unsupported ecosystem, or beyond the reported package list). This repository publishes no package the index resolves, so the repository dependency graph was assessed instead. That graph mixes development and test pins with shipped dependencies, so only the declared runtime dependencies are scored; transitive findings are reported as context and excluded from the score. Reachability is not analyzed.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "indirect_dependencies_free_of_known_advisories",
                    "no_advisories_left_outstanding"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              },
              {
                "code": "advisories_scope_repository",
                "params": {
                  "assessed": 7
                }
              },
              {
                "code": "advisories_unassessed",
                "params": {
                  "count": 5
                }
              },
              {
                "code": "advisories_repo_graph_caveat",
                "params": {}
              },
              {
                "code": "advisories_reachability",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "source": "osv",
              "advisories": 0,
              "affected_packages": 0,
              "assessed_packages": 7,
              "unassessed_packages": 5,
              "affected_by_severity": "none",
              "direct_affected_packages": 0
            },
            "components": [
              {
                "key": "direct_dependencies_free_of_known_advisories",
                "name": "Direct dependencies free of known advisories",
                "detail": "no direct dependency carries a known advisory",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "no_direct_advisories",
                    "params": {}
                  }
                ],
                "max_points": 35
              },
              {
                "key": "indirect_dependencies_free_of_known_advisories",
                "name": "Indirect dependencies free of known advisories",
                "detail": "transitive set not separable from development and test dependencies in this scope",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_scope_not_separable",
                    "params": {}
                  }
                ],
                "max_points": 25
              },
              {
                "key": "no_advisories_left_outstanding",
                "name": "No advisories left outstanding",
                "detail": "no advisory carries a publication date",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "advisories_no_publication_date",
                    "params": {}
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "malicious_dependencies",
            "band": "excellent",
            "name": "Malicious dependencies",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "source": "osv",
              "meaning": "reported as a malicious package by the OpenSSF corpus; the remedy is removal or moving off the compromised name, never an upgrade of the same artifact. Versions the registry has since pulled are listed but not scored",
              "packages": [],
              "red_flag": false,
              "assessed_packages": 7,
              "malicious_packages": 0,
              "direct_malicious_packages": 0,
              "withdrawn_malicious_packages": 0,
              "installable_malicious_packages": 0
            },
            "components": [
              {
                "key": "no_dependency_reported_as_a_malicious_package",
                "name": "No dependency reported as a malicious package",
                "detail": "no dependency is reported as a malicious package",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "no_malicious_dependencies",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          },
          {
            "key": "high_risk_jurisdiction_exposure",
            "band": "excellent",
            "name": "High-Risk Jurisdiction Exposure",
            "note": "Only high-confidence self-published location evidence affects this multiplier. Ambiguous matches are review-only; country evidence is not proof of nationality, citizenship, legal registration, malicious intent, or sanctions status.",
            "notes": [
              {
                "code": "jurisdiction_evidence_limits",
                "params": {}
              }
            ],
            "value": 100,
            "inputs": {
              "meaning": "self-published location evidence; not nationality or citizenship",
              "red_flag": false,
              "exposures": [],
              "policy_countries": [
                "Russia",
                "Iran",
                "North Korea"
              ],
              "review_only_matches": 0,
              "assessed_self_published_locations": 17
            },
            "components": [
              {
                "key": "policy_exposure_multiplier",
                "name": "Policy exposure multiplier",
                "detail": "no confirmed policy-scope location match",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "jurisdiction_no_match",
                    "params": {}
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Are visible security and supply-chain practices strong, with no malicious dependency and no unresolved high-risk jurisdiction exposure?"
      },
      {
        "key": "ai_readiness",
        "band": "at_risk",
        "name": "AI Readiness",
        "value": 35,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 40,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.8,
              "agent_instruction_files": [],
              "agent_instruction_max_bytes": null
            },
            "components": [
              {
                "key": "agent_instructions",
                "name": "Agent instructions",
                "detail": "no CLAUDE.md / AGENTS.md / editor rules",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_instructions",
                    "params": {}
                  }
                ],
                "max_points": 45
              },
              {
                "key": "machine_readable_docs_llms_txt",
                "name": "Machine-readable docs (llms.txt)",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 15
              },
              {
                "key": "legible_commit_history",
                "name": "Legible commit history",
                "detail": "80 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 80,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "critical",
            "name": "Verify loop (build / test / typecheck)",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_pinned_dependencies"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 24,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": false,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": false,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [],
              "dependency_bot_commit_share": 0
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 18
              },
              {
                "key": "automated_tests",
                "name": "Automated tests",
                "detail": null,
                "points": 22,
                "status": "met",
                "details": [],
                "max_points": 22
              },
              {
                "key": "lint_format_config",
                "name": "Lint / format config",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 11
              },
              {
                "key": "reproducible_environment",
                "name": "Reproducible environment",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              },
              {
                "key": "demonstrated_agent_practice",
                "name": "Demonstrated agent practice",
                "detail": "no agent-authored commits among the last 100",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_agent_authored_commits",
                    "params": {
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "automated_maintenance",
                "name": "Automated maintenance",
                "detail": "no automated dependency updates observed",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_dependency_automation",
                    "params": {}
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "no dependencies found",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "moderate",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 55,
            "inputs": {
              "primary_language": "PHP",
              "largest_source_bytes": 26888,
              "source_files_sampled": 189,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "PHP without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "PHP"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/189 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 189,
                      "oversized": 0
                    }
                  }
                ],
                "max_points": 55
              }
            ]
          }
        ],
        "description": "How well is the repo equipped to be developed and maintained with AI coding agents? An independent, experimental badge — weight 0.0, so it is surfaced on its own and does not affect the overall health score."
      }
    ],
    "metrics_version": "1.13.0"
  },
  "warnings": [
    "Star history unavailable: GitHub GraphQL error: Resource not accessible by personal access token"
  ],
  "report_type": "repository",
  "generated_at": "2026-07-28T15:02:56.681419Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/w/wikimedia/mediawiki-tools-codesniffer.svg",
  "full_name": "wikimedia/mediawiki-tools-codesniffer",
  "license_state": "standard",
  "license_spdx": "GPL-2.0"
}

Оцінки — це сигнали, а не гарантії. Вони відображають публічно видимі практики на GitHub — це не аудит коду й не гарантія безпеки.

Відсутні дані виключаються, а ваги перенормовуються — нуль за відсутність ніколи не ставиться. Методологія версіонована й відкрита: метрики v1.13.0, схема v0.27.0 — повна методологія · вікі метрик.

Як окремий результат виглядає на тлі всього реєстру: сукупна статистикаPackagist.