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

jhuntwork / mere

A mirror repository for the mere package manager

ZigMIT★ 5 зірок⑂ 0 форківз серп. 2019 р.Переглянути на GitHub ↗

jhuntwork/mere має індекс здоров’я 50 зі 100, що відповідає смузі «Помірний». Найвищий показник — Vitality (75/100), найнижчий — Community & Adoption (29/100). Останнє оновлення було 10 днів тому. Більшість нещодавньої роботи виконує один учасник.

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

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

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

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

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

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

Власність

Jeremy HuntworkОсобистий обліковий запис
42 підписники23 публічні репозиторіїз квіт. 2010 р.

Цей репозиторій належить особистому обліковому запису. Проєкт з єдиним власником несе більший ризик безперервності, ніж підтримуваний організацією.

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

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

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

75Добрий · 22% загального індексу
Як обчислюється оцінка
28.8/36Свіжість push — останній push 10 дн. тому
9.7/36Ритм комітів — 14/52 тижнів із комітами
18/18Обсяг комітів — 272 комітів за останній рік
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Використані вхідні дані
commits_last_year272
human_commit_share1
days_since_last_push10
active_weeks_last_year14
Як обчислюється оцінка
16.2/27Випускає релізи — 32 тегів версій (без релізів GitHub)
36/36Свіжість релізів — останній реліз 10 дн. тому
27/27Ритм релізів — реліз кожні ~11,9 дн.
0/10OpenSSF Scorecard: Signed-Releases — немає даних
Використані вхідні дані
releases_count32
latest_release_tagv0.16.1
releases_from_tagsтак
days_since_latest_release10
mean_days_between_releases11,9
Виключено з оцінювання (немає даних або не застосовно): OpenSSF Scorecard: Signed-Releases. Залишкові ваги перенормовано.

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

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

29Критичний · 18% загального індексу
Як обчислюється оцінка
9.8/60Зірки — 5 зірок
0/25Форки — 0 форків
0/15Спостерігачі — 2 спостерігачів
Використані вхідні дані
forks0
stars5
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
Як обчислюється оцінка
22.5/22.5README
22.5/22.5Ліцензія — визнана ліцензія (MIT)
0/18Настанови CONTRIBUTING
0/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ні

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

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

48У зоні ризику · 24% загального індексу
Як обчислюється оцінка
9/54Бас-фактор — на 1 контриб’ютор(ів) припадає половина всіх комітів
0/22.5Розподіл комітів — головний контриб’ютор — автор 100% комітів
1.4/13.5Широта контриб’юторів — 1 контриб’юторів
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Використані вхідні дані
bus_factor1
contributors_sampled1
top_contributor_share1
Як обчислюється оцінка
46.8/46.8Вирішення issue — закрито 100% issue
38.2/38.3Прийняття PR — злито 15/15 вирішених PR
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Використані вхідні дані
merged_prs15
open_issues0
closed_issues1
issue_closed_ratio1
closed_unmerged_prs0
Як обчислюється оцінка
10/30Підтримка власника — особистий (користувацький) обліковий запис
0/20Верифікований домен — не застосовно до користувацьких облікових записів
11.7/25Охоплення власника — 42 підписників у jhuntwork
22.1/25Послужний список — 23 публічних репозиторіїв, вік облікового запису ~16 р.
Використані вхідні дані
followers42
owner_typeUser
is_verified
owner_loginjhuntwork
public_repos23
account_age_days5 957
Виключено з оцінювання (немає даних або не застосовно): Верифікований домен. Залишкові ваги перенормовано.

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

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

54Помірний · 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. Залишкові ваги перенормовано.

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

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

Безпека

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

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

Стан безпеки

37У зоні ризику
Як обчислюється оцінка
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
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
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
7.5/7.5Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
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,7
Виключено з оцінювання (немає даних або не застосовно): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Залишкові ваги перенормовано.

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

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

35У зоні ризику · 0% загального індексу
Як обчислюється оцінка
0/45Інструкції для агентів — немає CLAUDE.md / AGENTS.md / правил редактора
0/15Машиночитана документація (llms.txt)
40/40Читабельна історія комітів — намір зазначено у 99 з 100 людських комітів (структурований заголовок або пояснювальний текст)
Використані вхідні дані
has_llms_txtні
legible_history_share0,99
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Типізований код — Zig без конфігурації перевірки типів
55/55Керовані розміри файлів — 0/1 файлів вихідного коду понад 60 КБ
Використані вхідні дані
primary_languageZig
largest_source_bytes441
source_files_sampled1
oversized_source_files0

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

5зірок GitHub
1контриб'юторів
272комітів за останні 12 місяців
10днів від останнього пушу
32релізів
1бас-фактор
0відкритих issue
пакетних екосистем

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

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

Докладніше

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

Незалежна, не прив'язана до інструментів оцінка безпеки від відкритого проєкту OpenSSF Scorecard. Кожна перевірка винагороджує практику безпеки, а не інструмент конкретного постачальника. Перевірки, які Scorecard не зміг визначити, позначено н/д і виключено з оцінки безпеки (вони ніколи не зараховуються як нуль).Scorecard v5.5.0 · 2026-07-31 12:16 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
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
н/дDangerous-Workflowno workflows found
0Dependency-Update-Toolno update tool detected
0Fuzzingproject is not fuzzed
10Licenselicense file detected
10Maintained30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
н/д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
Усі залежності 0

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

РеєстрПакетВерсіяЗв'язок
Сповіщення про залежності не оцінено

Звірка сповіщень не відбулася для цього звіту: No resolved dependencies to assess

Звіт у форматі JSON машиночитний
{
  "data": {
    "repo": {
      "topics": [],
      "is_fork": false,
      "size_kb": 1000,
      "has_wiki": true,
      "homepage": "https://codeberg.org/merelinux/mere",
      "languages": {
        "Zig": 2931532,
        "Shell": 1719,
        "Python": 441,
        "Vim Script": 4179
      },
      "pushed_at": "2026-07-21T02:04:13Z",
      "created_at": "2019-08-23T14:17:58Z",
      "owner_type": "User",
      "updated_at": "2026-07-21T01:53:45Z",
      "description": "A mirror repository for the mere package manager",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "main",
      "license_spdx_raw": "MIT",
      "primary_language": "Zig",
      "significant_languages": [
        "Zig"
      ]
    },
    "owner": {
      "blog": "https://merelinux.org/",
      "name": "Jeremy Huntwork",
      "type": "User",
      "login": "jhuntwork",
      "company": null,
      "location": "New York, NY",
      "followers": 42,
      "avatar_url": "https://avatars.githubusercontent.com/u/239626?v=4",
      "created_at": "2010-04-08T15:38:11Z",
      "is_verified": null,
      "public_repos": 23,
      "account_age_days": 5957
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.16.1",
          "kind": "patch",
          "published_at": "2026-07-21T01:53:28Z"
        },
        {
          "tag": "v0.16.0",
          "kind": "minor",
          "published_at": "2026-07-21T00:57:08Z"
        },
        {
          "tag": "v0.15.2",
          "kind": "patch",
          "published_at": "2026-07-18T18:15:34Z"
        },
        {
          "tag": "v0.15.1",
          "kind": "patch",
          "published_at": "2026-07-18T16:10:39Z"
        },
        {
          "tag": "v0.15.0",
          "kind": "minor",
          "published_at": "2026-07-18T01:07:42Z"
        },
        {
          "tag": "v0.14.0",
          "kind": "minor",
          "published_at": "2026-06-04T17:07:24Z"
        },
        {
          "tag": "v0.13.2",
          "kind": "patch",
          "published_at": "2026-06-01T00:59:01Z"
        },
        {
          "tag": "v0.13.1",
          "kind": "patch",
          "published_at": "2026-05-28T14:36:43Z"
        },
        {
          "tag": "v0.13.0",
          "kind": "minor",
          "published_at": "2026-05-20T13:47:43Z"
        },
        {
          "tag": "v0.12.2",
          "kind": "patch",
          "published_at": "2026-04-04T22:38:04Z"
        },
        {
          "tag": "v0.12.1",
          "kind": "patch",
          "published_at": "2026-04-03T22:47:41Z"
        },
        {
          "tag": "v0.12.0",
          "kind": "minor",
          "published_at": "2026-04-03T21:44:43Z"
        },
        {
          "tag": "v0.11.1",
          "kind": "patch",
          "published_at": "2026-04-03T18:13:09Z"
        },
        {
          "tag": "v0.11.0",
          "kind": "minor",
          "published_at": "2026-04-02T13:33:43Z"
        },
        {
          "tag": "v0.10.4",
          "kind": "patch",
          "published_at": "2026-04-01T16:52:10Z"
        },
        {
          "tag": "v0.10.3",
          "kind": "patch",
          "published_at": "2026-03-31T20:05:26Z"
        },
        {
          "tag": "v0.10.2",
          "kind": "patch",
          "published_at": "2026-03-31T02:13:54Z"
        },
        {
          "tag": "v0.10.1",
          "kind": "patch",
          "published_at": "2026-03-30T22:15:20Z"
        },
        {
          "tag": "v0.10.0",
          "kind": "minor",
          "published_at": "2026-03-30T20:02:54Z"
        },
        {
          "tag": "v0.9.7",
          "kind": "patch",
          "published_at": "2026-03-29T21:51:08Z"
        },
        {
          "tag": "v0.9.5",
          "kind": "patch",
          "published_at": "2026-03-29T21:20:46Z"
        },
        {
          "tag": "v0.9.4",
          "kind": "patch",
          "published_at": "2026-03-29T20:43:20Z"
        },
        {
          "tag": "v0.9.2",
          "kind": "patch",
          "published_at": "2026-03-29T20:10:42Z"
        },
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-03-26T02:50:55Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2026-03-25T04:53:51Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2026-03-25T04:23:58Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2026-03-25T02:16:48Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2026-03-24T03:48:10Z"
        },
        {
          "tag": "v0.6.5",
          "kind": "patch",
          "published_at": "2026-03-23T12:38:57Z"
        },
        {
          "tag": "v0.6.4",
          "kind": "patch",
          "published_at": "2026-03-22T01:16:16Z"
        },
        {
          "tag": "v0.6.3",
          "kind": "patch",
          "published_at": "2026-03-22T00:35:11Z"
        },
        {
          "tag": "v0.6.2",
          "kind": "patch",
          "published_at": "2026-03-21T21:46:50Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "83bd82c434c2b7bcc854f6dc750206d970427025",
          "body": null,
          "is_bot": false,
          "headline": "release: v0.16.1",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-21T01:53:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7e24d3858606250ce2b4754de08fcdf2deff433b",
          "body": "…25) from fix/logical-store-symlinks into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/125",
          "is_bot": false,
          "headline": "Merge pull request 'Use logical store paths for profile symlinks' (#1…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-21T01:51:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "903be35af5b546236a37017c6bee6571211e6887",
          "body": "Profile symlinks embedded the physical --root prefix\n({root}/mere/store/...), which dangles inside the build\nnamespace: it bind-mounts {root}/mere onto /mere, so the store\nis only reachable at /mere/store/..., not at the host path.\nexecve(\"/bin/sh\") then failed with ENOENT before any output,\nproduci\n[…]\n/\") logical and physical are\nidentical.\n\nVerified: full test suite passes and mere dev build --root now\nruns the build script (fails only on an unrelated utmpx.h/musl\nrecipe issue, out of scope here).",
          "is_bot": false,
          "headline": "Use logical store paths for profile symlinks",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-21T01:47:42Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "6262108214248749ecbe2117698114cf82b209f3",
          "body": "Bump version for automated release.\n\nUpdates README.md install-instructions download URLs to match.",
          "is_bot": false,
          "headline": "release: v0.16.0",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-21T00:57:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "92d0993768de30720d621cf61ce1536c67caf14f",
          "body": "…namespace' (#124) from fix/namespace-mere-root-bind into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/124",
          "is_bot": false,
          "headline": "Merge pull request 'Use opts.mere_root instead of hardcoded /mere in …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-21T00:55:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "954d6bc8f7cbb6e400e0f67d9bdb413949be8eef",
          "body": "…23) from metadata-property-passthrough into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/123",
          "is_bot": false,
          "headline": "Merge pull request 'Pass recipe metadata through release publish' (#1…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-21T00:52:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1f2c03b3ab12f1da6da45cdbb882e4ccb5b26b1",
          "body": "buildSyntheticRoot bind-mounted the host's /mere unconditionally,\nwhich breaks when --root points to a different location. Profile\nsymlinks resolve against the store at the specified root, but the\nnamespace was mounting the wrong /mere over them.\n\nAdd mere_root field to EnvOptions (defaults to \"/mere\" for backward\ncompat). Both shell.zig and build_orchestrator.zig now pass\n{root}/mere derived from the --root flag.",
          "is_bot": false,
          "headline": "Use opts.mere_root instead of hardcoded /mere in namespace",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-21T00:50:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9e25a248a30aecf94a963f8c80348e8c311c4a08",
          "body": "release publish was dropping the properties column when copying packages\nfrom the dev repo to the release output. Import correctly built and\nstored the metadata JSON (description, url, licenses, source_urls) from\nmeta.kdl, but publish passed null to insertPackageTransaction — so the\nrelease repo.db \n[…]\n→ dev repo properties column → release repo.db properties\ncolumn.\n\nVerified end-to-end via swamp mere-pkgd-e2e workflow: build → publish →\nquery properties column confirms all metadata fields present.",
          "is_bot": false,
          "headline": "Pass recipe metadata through release publish",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-19T17:15:00Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "5ae686ef376b77dde7646aa79b555a225087a77a",
          "body": "Reviewed-on: https://codeberg.org/merelinux/mere/pulls/122",
          "is_bot": false,
          "headline": "Merge pull request 'release: v0.15.2' (#122) from v0.15.2 into main",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-18T18:15:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d6a52d67047ce657d571fcf0928fb53c882def8",
          "body": "Bump version for automated release.\n\nUpdates README.md install-instructions download URLs to match.",
          "is_bot": false,
          "headline": "release: v0.15.2",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T18:11:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e405354b28bb8e33d79d83ecec23ffd15a3f03dc",
          "body": "…from import-log-package-details into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/121",
          "is_bot": false,
          "headline": "Merge pull request 'Log package details on successful import' (#121) …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-18T18:10:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f312cb79a5222b2072c6585a821e9d805c37de88",
          "body": "Emit an info-level log line for each package as it is imported,\nshowing name, version, release, and architecture. Previously only\nthe total count was reported at the CLI level, with no per-package\nvisibility during the import process.",
          "is_bot": false,
          "headline": "Log package details on successful import",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T18:06:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4cf070582f6cba42150573e13fd5d707a6e143f8",
          "body": "…20) from fix/prune-by-version-not-id into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/120",
          "is_bot": false,
          "headline": "Merge pull request 'Use version comparison for retention pruning' (#1…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-18T18:03:27Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7fe4aa04f5462d0e7e2e31352ed0f00d12f41132",
          "body": "pruneOldVersions previously used ORDER BY id DESC to determine\nwhich packages to keep, meaning insertion order decided retention.\nIf packages were imported out of order, the newest version could\nbe pruned while an older one was kept.\n\nRewrite to fetch all versions for a (name, arch) pair, sort using\n[…]\ne resolver and\ngetLatestPackagesByNameArch), and prune everything below the top\nkeep_count.\n\nAlso fix collectPruneCandidates in release.zig to use the same\nversion-comparison approach for consistency.",
          "is_bot": false,
          "headline": "Use version comparison for retention pruning",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T17:59:44Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c60ae9e679a12ee0cd98da611508d02d68946d06",
          "body": "Bump version for automated release.\n\nAlso, switch CI runners to docker-aarch64 where possible for faster\nbuilds. Extract test step into its own job on aarch64, gating both\nrelease builds. Only release-x86_64 stays on docker since it must\nproduce the x86_64 binary.\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/119",
          "is_bot": false,
          "headline": "v0.15.1 (#119)",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T16:10:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1d32ad0e095dceecc7232e87685ed3e3734bc139",
          "body": "…ilding' (#118) from release-publish-merge-semantics into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/118",
          "is_bot": false,
          "headline": "Merge pull request 'Merge new packages into output DB instead of rebu…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-18T14:58:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "17b6c6b6c0ba018108a87211d0af76d403ed246a",
          "body": "release publish no longer clears the output repo.db on every\ninvocation. Instead it preserves the existing published state and\nmerges in new packages from the dev repo, skipping duplicates.\n\nRetention (keep 3 per name+arch) is applied across the full output\nDB after insertion. Orphaned archive files\n[…]\nows.\n\nThis makes the output directory the single source of truth for what\nis currently published, allowing pkgd to treat the dev repo as an\nephemeral staging area rather than a persistent accumulator.",
          "is_bot": false,
          "headline": "Merge new packages into output DB instead of rebuilding",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T14:46:37Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "bba6a369a247b1a03593128e6f9de7344d57bc6b",
          "body": "Bump version for automated release.\n\nUpdates README.md's install-instructions download URLs to match.\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/117",
          "is_bot": false,
          "headline": "release: v0.15.0 (#117)",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-18T01:07:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "191acea802e09e26dd453f5fa80d0e98ac1db115",
          "body": "…ease-publish into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/116",
          "is_bot": false,
          "headline": "Merge pull request 'Add mere release publish command' (#116) from rel…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-18T00:37:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05820557275f84ea20f9da72daa239a4b122f9e6",
          "body": "Implements specification 9.9 (Release Publication Requirements): a\nnew mere release publish --dev-repo --output [--key] command that\nbuilds a signed public release (repo.db, repo.db.sig, packages/) from\na dev repository as the sole source of truth, applying keep-count\nretention and failing loudly be\n[…]\nput are explicit, caller-supplied paths\nrather than workstation conventions, so this can run against\narbitrary directories in a server context (see the pkgd service,\nwhich shells out to this command).",
          "is_bot": false,
          "headline": "Add mere release publish command",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-17T21:16:21Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "27a727bbd32c94993ebe3eb2d881b6e2e10f7e5e",
          "body": "… errors to FileSystem' (#115) from sign-verifysignature-error-mapping into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/115",
          "is_bot": false,
          "headline": "Merge pull request 'Stop collapsing verifySignature's public-key-load…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-15T21:41:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "982e7893bd056f8be66228be29496547498e4feb",
          "body": "verifySignature caught every PublicKey.loadFromFile error and mapped\nit to a generic SignError.FileSystem, even though loadFromFile already\nreturns the fully-specific SignError itself - same pattern as\ngetFileHash. Propagate the error directly instead of remapping it.",
          "is_bot": false,
          "headline": "Stop collapsing verifySignature's public-key-load errors to FileSystem",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-13T18:23:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f99287aab69f2fa0b13e1481a3c407582c63f70e",
          "body": "…sage' (#114) from extract-libarchive-message-strings into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/114",
          "is_bot": false,
          "headline": "Merge pull request 'Match libarchive's actual absolute-path error mes…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-13T17:27:11Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "07271d79f76b95bf109699469d093794c28cd3be",
          "body": "classifyLibarchiveMessage checked for \"Absolute path\" and \"Bad path\",\nneither of which libarchive ever actually produces (checked against\nthe vendored 3.8.2 source: archive_write_disk_posix.c's\nARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS branch emits \"Path is\nabsolute\" via fsobj_error's \"%s%s\" concatenat\n[…]\nr anywhere in libarchive). Currently harmless since mere never\nsets that flag, but would silently fail to classify the message if\nit's added later for defense-in-depth. Fixed to match the real string.",
          "is_bot": false,
          "headline": "Match libarchive's actual absolute-path error message",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-13T16:26:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9a9121c22ffd3f93d77348878761a4b32f5a4934",
          "body": "…air' (#113) from repo-history-atomic-commit into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/113",
          "is_bot": false,
          "headline": "Merge pull request 'Publish repo.db and repo.db.sig atomically as a p…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-13T00:22:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4244eb2d49253b15d87e17c8bc30f63614d08ac6",
          "body": "Staged.commit published the staged db and sig via two independent,\nnon-atomic copyFile calls. A crash between them left a mismatched\npair on disk - fails closed (every subsequent verify rejects the\nmismatch) but leaves the repo unusable until manually re-signed.\n\nAdded replaceLiveDbAndSigWithRollback, mirroring repocache.zig's\nexisting replaceCachedDbAndSigWithRollback: back up whatever is\ncurrently live, rename the new db and sig into place, and roll back\nto the backups on any partial failure.",
          "is_bot": false,
          "headline": "Publish repo.db and repo.db.sig atomically as a pair",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-12T23:34:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a11408b36dbb3c2599ffa5384700a408040372a0",
          "body": "…mentInternal' (#112) from kdl-parse-node-double-free into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/112",
          "is_bot": false,
          "headline": "Merge pull request 'Fix double-free of a KDL node on OOM in parseDocu…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-12T22:44:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "784df46d21238be773b0c4edd23f1a47bbb38613",
          "body": "KDL_EVENT_START_NODE registered errdefer new_node.deinit() right after\nNode.init, but never cancelled it once new_node was successfully\nappended into nodes or parent.children. A later failure in the same\nbranch (node_stack.append OOMing) fired that errdefer and\nparseDocumentInternal's own nodes-clea\n[…]\nne node.\n\nFixed with the same appended-flag pattern already used elsewhere in\nthis codebase for this exact ownership-transfer shape: the errdefer\nonly fires if the node was never handed off to a list.",
          "is_bot": false,
          "headline": "Fix double-free of a KDL node on OOM in parseDocumentInternal",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-12T22:08:58Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ad9266aabdbf1e032e47aae32caef4faa82a85a1",
          "body": "…) from build-cache-locking into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/111",
          "is_bot": false,
          "headline": "Merge pull request 'Add locking around the on-disk build cache' (#111…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-12T19:37:04Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0ec5033d61ac99453492337301a2b40d8dd6bdd5",
          "body": "gc() and the various storeXForKey() functions mutated the same\non-disk trees (keys/, artifacts/) with zero coordination, unlike the\npackage store's Context.acquireStoreLock(). Two concrete races:\ngc() could delete a just-persisted artifact before its key record was\nwritten (self-healing - the next b\n[…]\nePackageArchiveForKey().\n\nclear() now skips deleting its own .lock file while iterating\ncache_root's entries, since that file is cache infrastructure the lock\njust created, not cache content to clear.",
          "is_bot": false,
          "headline": "Add locking around the on-disk build cache",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-12T17:27:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "af370e6803dbf815eaeb15927b95c368cd38bac8",
          "body": "…rBuild; fix leaks and a double-free in repo_sources.zig' (#110) from repo-caches-diagnostic-context-guard into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/110",
          "is_bot": false,
          "headline": "Merge pull request 'Preserve diagnostic context in createRepoCachesFo…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T22:49:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "be29782f3f05a90e983b07357d57cd24e3f5584a",
          "body": "…d a double-free in repo_sources.zig\n\ncreateRepoCachesForBuild unconditionally overwrote whatever diagnostic\ncontext repo_sources.createCaches already set (e.g. a specific repo\nname and \"failed to initialize repository cache\") with a generic\n\"config\"/\"failed to create repo caches from config\", incon\n[…]\nror after the second\n  defer double-freed it.\n\nAlso fixed test_helpers.createTestRepoConfig, which referenced a\nnonexistent .ctx field on RepoConfig - needed for the new\ncreateRepoCachesForBuild test.",
          "is_bot": false,
          "headline": "Preserve diagnostic context in createRepoCachesForBuild; fix leaks an…",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T21:33:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "df5599acd1472d7aa2242db115530ecfa418c41e",
          "body": "…e failure diagnostics' (#109) from namespace-phase-error-detail into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/109",
          "is_bot": false,
          "headline": "Merge pull request 'Include the specific namespace error name in phas…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T17:33:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1b193cf902df2fe38d20e1f34d2f842b26a5590",
          "body": "runOneNamespacePhase set a static \"failed to fork and enter env\" message\nregardless of which of namespace.EnvError's ~20 variants (uid-map\nfailure, overlayfs unavailable, disabled user namespaces, mount\nfailures, etc.) actually occurred, with no way for an operator to tell\nthem apart from the message alone. Interpolate @errorName(err) into the\ndiagnostic details via setDiagnosticContextFmt instead of the static\nstring.",
          "is_bot": false,
          "headline": "Include the specific namespace error name in phase failure diagnostics",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T17:04:26Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9c5dae61988390acbbb348b07d660b9ae07a1bd2",
          "body": "…ileSystem error' (#108) from sign-getfilehash-error-mapping into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/108",
          "is_bot": false,
          "headline": "Merge pull request 'Stop collapsing getFileHash errors to a generic F…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T16:41:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "05a82d3bbb9e4c89eb966a5b3a6b588482f8e06e",
          "body": "getFileHash's catch on hash.calculateFileHash mapped every possible\nerror - including OutOfMemory and PermissionDenied - to a generic\nSignError.FileSystem, discarding the specific error calculateFileHash\nhad already computed. This backs defaultSigner (used when signing repo\ndatabases), and repositor\n[…]\n is to\njust propagate the error directly instead of remapping it - the\nAccessDenied/EndOfStream/Unexpected branches being collapsed over were\nalready dead code, since HashError can never produce them.",
          "is_bot": false,
          "headline": "Stop collapsing getFileHash errors to a generic FileSystem error",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T16:10:15Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e1ec2dbaa8845ca537e2693b1860fdc3c6dd3b9e",
          "body": "…on-bomb-sized payload' (#107) from extract-decompression-bomb-limit into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/107",
          "is_bot": false,
          "headline": "Merge pull request 'Reject archive entries that declare a decompressi…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T15:50:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "2b20b06468eb3657aaea43cf7ecb00970ea68014",
          "body": "extractWithLibarchive extracted every entry regardless of its declared\nuncompressed size, with no ceiling. The signed-install path is tempered\nby install.zig's whole-archive hash verification against trusted repo\nmetadata before extraction runs, but mere dev import (import.zig) and\nbuild-source unpa\n[…]\nhich\nrejects any entry whose archive_entry_size() exceeds a 4 GiB ceiling,\nwith a diagnostic message naming the entry and stating the declared\nsize and the limit rather than a generic \"invalid input\".",
          "is_bot": false,
          "headline": "Reject archive entries that declare a decompression-bomb-sized payload",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T15:24:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "375ab9de6a4a0164dc9ef829dfe2c6b579519ab6",
          "body": "…on restore' (#106) from build-cache-archive-restore-verify into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/106",
          "is_bot": false,
          "headline": "Merge pull request 'Re-verify cached archive hash before trusting it …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T13:52:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eef3869fc86a2f54253912da324761ac889af8cf",
          "body": "restorePackageArchiveForKey copied a cached package archive out of the\nbuild cache and returned its recorded archive_hash/signature verbatim,\nwith no check that those still matched the file's actual bytes. This\nwas asymmetric with storePackageArchiveForKey, which does verify before\ncaching. If the c\n[…]\nnow returns null instead of a mismatched hash/signature pair. Verified\nthe test fails without the fix (a non-null result is returned and\nleaked, since nothing frees a hit the caller wasn't expecting).",
          "is_bot": false,
          "headline": "Re-verify cached archive hash before trusting it on restore",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T13:32:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d8fb21e64aa77e97dff10514ea93e4054ab7eae4",
          "body": "…ntinueOnError' (#105) from split-staging-partial-cache into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/105",
          "is_bot": false,
          "headline": "Merge pull request 'Don't cache a partial split-stage result under Co…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T13:02:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "835fbb69c4ba6e3fd720ad9f355506938c45167d",
          "body": "Under FailurePolicy.ContinueOnError, stageSplitPackages can skip a\nsub-package that failed to stage and still return successfully (the\nerror is only recorded via split_staging_errors_encountered).\nrestoreOrStageSplitPackages unconditionally persisted that result to\nthe build cache regardless of the \n[…]\nkages, forcing one package to\nfail on the first call only. Verified the test fails without the fix\n(the second call restores the cached 1-package result instead of\nre-staging both) and passes with it.",
          "is_bot": false,
          "headline": "Don't cache a partial split-stage result under ContinueOnError",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T12:14:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ce618c0dd8e9154d35d27813187f08e237feaef6",
          "body": "…rtifact' (#104) from packaging-archive-hash-double-free into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/104",
          "is_bot": false,
          "headline": "Merge pull request 'Fix double-free of archive_hash in createPackageA…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T02:11:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7ca3c456436fb0dae08314bb180acc658de3e3f0",
          "body": "Two late-stage error branches in createPackageArtifact (the\nresult_package_name and result_signature dupe failures) manually freed\narchive_hash even though an errdefer registered earlier for archive_hash\nwas still armed, causing a double-free when OOM struck at either of\nthose two allocation sites.\n\n[…]\n to\ndeterministically reproduce the double-free. Verified the test fails\nagainst the unfixed code (GeneralPurposeAllocator reports the double\nfree at the exact two call sites) and passes with the fix.",
          "is_bot": false,
          "headline": "Fix double-free of archive_hash in createPackageArtifact",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T01:47:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "37bda82b7f1eb1768fcb771a3d9e289a26e8afe7",
          "body": "…y versions, not names' (#103) from build-cache-dependency-versions into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/103",
          "is_bot": false,
          "headline": "Merge pull request 'Key the build profile cache on resolved dependenc…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-10T01:18:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "06b2f123d3d78dadf7488355e648667141d49d84",
          "body": "computeProfileRealizeKey hashed a recipe's dependency *names* but never\nthe versions actually resolved for them. Dependency resolution is\ndynamic (an unpinned \"openssl\" resolves to whatever's newest in the\nsynced repo), so a repo sync that bumps a build-time dependency to a\nnew version was invisible\n[…]\nther than a second repo sync.\n\nAdded a regression test proving the key changes when a dependency's\nresolved content hash changes (and stays stable when it doesn't);\nconfirmed it fails without the fix.",
          "is_bot": false,
          "headline": "Key the build profile cache on resolved dependency versions, not names",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-10T00:34:04Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "67eeb7d8c1b88d0e9bc95be970cd654763035ae6",
          "body": "…fore touching the store' (#102) from pin-profile-store-lock into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/102",
          "is_bot": false,
          "headline": "Merge pull request 'Acquire the store lock in pin/profile commands be…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T22:50:53Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bab6852428ac8942e95b21cab4b853be01e21261",
          "body": "pin add, profile create --from, profile apply, and profile delete all\ncreate or reference store content or gc-roots without holding the\nstore lock that install/uninstall/generation commands already use. A\nconcurrent mere store clean's mark phase can miss a store path these\ncommands are about to refe\n[…]\nat pre-creates a valid, real store path (so\npin.create would legitimately succeed if reached) and blocks lock\nacquisition by pre-creating mere/.lock as a directory; confirmed it\nfails without the fix.",
          "is_bot": false,
          "headline": "Acquire the store lock in pin/profile commands before touching the store",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T21:48:20Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f41648ebc0426261b4c18939a9050aab079522a0",
          "body": "…tParser.parse' (#101) from parser-end-of-flags-separator into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/101",
          "is_bot": false,
          "headline": "Merge pull request 'Handle -- as an end-of-flags separator in Argumen…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T15:51:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "58fcca708cc4102da56d064d0b664872fe5690a2",
          "body": "ArgumentParser.parse had no handling for a literal \"--\" argument: it\nwould be matched by the startsWith(arg, \"--\") long-flag branch with an\nempty flag name and rejected as InvalidInput. cli.zig's one current\ncaller happens to strip \"--\" and everything after it before calling\nparse(), so this never s\n[…]\n\nAdded src/cli/parser.zig to build.zig's test_modules (same pattern as\ncommand.zig) since it had no test coverage at all; added tests\ncovering the new -- handling, confirmed they fail without the fix.",
          "is_bot": false,
          "headline": "Handle -- as an end-of-flags separator in ArgumentParser.parse",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T15:33:02Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ea14fe30807d4c1a65ef04976a0b0da9b193ccb3",
          "body": "…f curl+sha256sum' (#100) from vendor-deps-build-zig-zon into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/100",
          "is_bot": false,
          "headline": "Merge pull request 'Fetch vendored C deps via build.zig.zon instead o…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T15:15:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bc738e90301f36bdf538ec8440302f8f04a1b92d",
          "body": "Source acquisition for the vendored C libraries was a hand-rolled\nshell script (curl + sha256sum + tar) run at build time, participating\nin none of Zig's package infrastructure: no global cache dedup, no\n`--fetch` offline-build support, and a checksum format (sha256 hex)\nduplicating what Zig's own f\n[…]\n.zon's shape (only\n.version is ever read), which broke the moment .dependencies was\nadded. Letting Zig infer the type from the import directly makes it\nrobust against future build.zig.zon changes too.",
          "is_bot": false,
          "headline": "Fetch vendored C deps via build.zig.zon instead of curl+sha256sum",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T14:42:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "caec571e923c569303832e737d319e0d147d60a1",
          "body": "…cond disk read' (#99) from repo-db-verify-deserialize into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/99",
          "is_bot": false,
          "headline": "Merge pull request 'Open cached repo.db from verified bytes, not a se…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T03:18:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "651c505e6b00c91d29c9502d86749a40d552a3c7",
          "body": "RepoCache.ensureRepository hashed repo.db to verify its signature and\nthen let Repository.init reopen the same path fresh via sqlite3_open_v2,\nuntied to the hash that had just been checked. A file swapped in that\nwindow would make the verification meaningless for whatever sqlite\nactually read.\n\nsign\n[…]\nead the verified bytes through to this new path; the two\nother verifyWithTrustedFingerprints callers (repo_sources.zig,\nsyncLocal's download-then-rename flow) just needed to free the new\nreturn field.",
          "is_bot": false,
          "headline": "Open cached repo.db from verified bytes, not a second disk read",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T03:03:13Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "c504a31a2fb34ef68683d8f2e12a51080299cef3",
          "body": "…re dev import' (#98) from import-verify-before-parse into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/98",
          "is_bot": false,
          "headline": "Merge pull request 'Verify manifest signature before parsing it in me…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T02:30:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fe17e830666c2b81a488d61d63cf03ad5a4f3a81",
          "body": "prepareVerifiedImport built a Package struct from the manifest before\nchecking its signature at all: readManifestAndCreatePackage decoded\nand used manifest.v1 first, and verifyManifestSignatureAndGetSigner\nonly checked the signature afterward against a separate fresh read.\nUntrusted content got pars\n[…]\ng the file\nagain. A malformed manifest with no valid signature is now rejected\nas SignatureInvalid rather than leaking InvalidInput from decoding\nuntrusted bytes before the signature was ever checked.",
          "is_bot": false,
          "headline": "Verify manifest signature before parsing it in mere dev import",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T02:17:05Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "16866d641dd56acbc2db4ad2a2cb630d65dfc04e",
          "body": "…not a second disk read' (#97) from manifest-verify-toctou into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/97",
          "is_bot": false,
          "headline": "Merge pull request 'Parse manifest.v1 from the exact bytes verified, …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T01:35:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "cbfe0ca354bf3092213aafec2cb9e59dc2e3d5b4",
          "body": "Manifest signature verification hashed/verified the file's bytes in\nmemory and then discarded them; the caller separately re-opened and\nre-read the same path to get bytes for parsing. Swapping the file's\ncontent in that window would make the verified signature meaningless\nfor whatever actually got p\n[…]\nmselves (owned by ctx.allocator) instead of just a fingerprint, so\ninstall.zig can decode the manifest directly from them. Updated the\nother two callers (import.zig, verify.zig) to free the new field.",
          "is_bot": false,
          "headline": "Parse manifest.v1 from the exact bytes verified, not a second disk read",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T01:13:14Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "0121943bc849df74ff3015f7fec507ab11717abd",
          "body": "…before/after atomic rename' (#96) from fsync-store-admission into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/96",
          "is_bot": false,
          "headline": "Merge pull request 'fsync staged package content and store directory …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-09T00:41:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b8ab09a4275ec30a0f9944ae8e917bbd0fe00c6e",
          "body": "…rename\n\nStore admission renamed staged package content into its final\ncontent-addressed path with no fsync anywhere in the sequence, so a\npower loss right after \"install succeeded\" could leave a store object\nwith truncated or corrupted data despite appearing to exist. Recursively\nfsync the staging tree's file data and directory entries before the\nrename, and fsync the store's parent directory afterward to make the\nrename itself durable.",
          "is_bot": false,
          "headline": "fsync staged package content and store directory before/after atomic …",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-09T00:07:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6f293ff61a9ef1cb6a1830da792f5c51580ebc70",
          "body": "…ardcoded exit codes' (#95) from cli-error-boundary-helper into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/95",
          "is_bot": false,
          "headline": "Merge pull request 'Consolidate CLI error-boundary handling and fix h…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-08T23:09:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a58c162136b186b32a97bbb32b3e89606866b24f",
          "body": "install.zig, uninstall.zig, profile.zig, and shell.zig each duplicated\nthe same ~30-line block mapping a caught error to a CommandResult:\nresolve the diagnostic context, format a user-friendly message, dupe\nit, done. Every call site hardcoded exit_code = 1 regardless of the\nactual error, so a Permis\n[…]\nd Zig 0.16 rejects that for a standalone test root). Added real\nregression tests for errorResult's exit-code mapping and diagnostic\ncontext folding; confirmed the exit-code test fails without the fix.",
          "is_bot": false,
          "headline": "Consolidate CLI error-boundary handling and fix hardcoded exit codes",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-08T22:17:38Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "51dbb52870ebd92f99d57ada9b9bb51bfd27907c",
          "body": "…le with a passthrough command' (#94) from shell-passthrough-profile-arg into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/94",
          "is_bot": false,
          "headline": "Merge pull request 'Fix mere shell ignoring the positional profile fi…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-08T21:43:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ddf79419fb99588511536cacd9eb9604189f7f7d",
          "body": "…h command\n\nresolveProfileName only consulted the positional profile.kdl argument\nwhen args.passthrough was empty, but the command's own usage message\ndocuments the file and a passthrough command being used together\n(`mere shell [profile.kdl] -- <command> [args...]`). Using that\ndocumented form sile\n[…]\nperly-scoped\nsrc/cli/-rooted module wired through build.zig - worth doing, but a\nseparate piece of work from this fix. Verified manually by tracing the\nbefore/after logic against the documented usage.",
          "is_bot": false,
          "headline": "Fix mere shell ignoring the positional profile file with a passthroug…",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-08T20:31:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "49aff509c43d960d828aa516f08b35e835710dd5",
          "body": "…y-required packages' (#93) from uninstall-cascade-multiple-packages into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/93",
          "is_bot": false,
          "headline": "Merge pull request 'Fix uninstall --cascade for multiple independentl…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-08T18:23:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ddfc9768e536cd3aa232f88834b5aaf8e9292946",
          "body": "Cascade only ever accounted for the first requested package still\nfound in the resolution: it computed one cascade round, re-resolved\nonce, then unconditionally broke out of the loop. A second requested\nremoval still pulled in by a different, unrelated dependent was never\nre-checked against the new \n[…]\n roots left to re-resolve.\n\nAdded a regression test with two packages independently required by\ndifferent dependents; confirmed it reproduces both bugs independently\nbefore landing the fix for either.",
          "is_bot": false,
          "headline": "Fix uninstall --cascade for multiple independently-required packages",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-08T18:13:56Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "92b36634199bd5d8bcb28e04b9a3d923cc4624e2",
          "body": "…rsions' (#92) from fix-cross-package-provider into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/92",
          "is_bot": false,
          "headline": "Merge pull request 'Fix cross-package provider selection comparing ve…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-04T12:58:02Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "950a080d3e57d962a5fb9e7b3c1f0e1ae658ebb4",
          "body": "When multiple packages provide the same soname (e.g. libglvnd and\nmesa both providing libEGL.so.1), compareCandidates sorted them by\nversion number. This is meaningless across different package names —\n\"26.0.3\" vs \"1.7.0\" says nothing about which is the better provider.\nThe result was that mesa alwa\n[…]\ner than hiding it behind\nmeaningless version comparison.\n\nTests:\n- Cross-package providers, different priority -> higher-priority wins\n- Cross-package providers, same priority -> ConflictingProvisions",
          "is_bot": false,
          "headline": "Fix cross-package provider selection comparing versions",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-04T04:14:53Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "59d8878e927ba6cec3061236eb507a839d7f1676",
          "body": "…not just on download' (#91) from reverify-cached-repo-db into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/91",
          "is_bot": false,
          "headline": "Merge pull request 'Re-verify cached repo.db every time it's opened, …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-03T19:56:29Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7510358b2c61abb31be14914ca7e4ce42b99cf37",
          "body": "sync() only verified signatures when it actually downloaded a fresh\ndb. Once cached, a repo.db was trusted forever afterward with no\nre-check - ensureRepository() just opened it. A repo.db tampered with\ndirectly on disk after being verified (local attacker, or corruption)\nwould go undetected on ever\n[…]\nall.zig\nand search.zig.\n\nAdded a regression test: a repo verified once, then tampered with\non-disk without a following sync, must be rejected on the next fresh\nopen. Verified it fails without the fix.",
          "is_bot": false,
          "headline": "Re-verify cached repo.db every time it's opened, not just on download",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-03T16:30:41Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "e00173c905e99ff6deaf20bcbe196c0b6dc89eb3",
          "body": "…onfig.kdl' (#90) from verify-local-repo-signature into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/90",
          "is_bot": false,
          "headline": "Merge pull request 'Verify signatures for file:// repos declared in c…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-03T14:44:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0c29606496be35c0affb8b09d24aac1e6f98a54a",
          "body": "syncLocal() was a no-op: sync() on a local (file://) repo never\nverified anything. Auto-discovered dev repos under /mere/dev/repo/\nare safe because repo_sources.zig verifies before ever constructing a\nRepoCache, but a file:// repo declared directly in config.kdl reached\nthis path with its own truste\n[…]\nlocal sync verified nothing.\nFixed both to sign the file that's actually read. Added a regression\ntest proving a local repo signed with an untrusted key is rejected;\nverified it fails without the fix.",
          "is_bot": false,
          "headline": "Verify signatures for file:// repos declared in config.kdl",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-03T14:25:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d07c11f5e119850f00a22c7343bb83c4fb92784c",
          "body": "…from generation-keep-gc-root into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/89",
          "is_bot": false,
          "headline": "Merge pull request 'Create GC roots when keeping a generation' (#89) …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-03T13:29:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "13604e6d12b0efcf727e9a4c4f5cc2575a5662c5",
          "body": "…from remove-system-init-flag into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/88",
          "is_bot": false,
          "headline": "Merge pull request 'Remove --system flag from mere store init' (#88) …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-03T13:18:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "e3731bb33872c0d724dfdbceb7275b5bdfa83aa7",
          "body": "createSystemLayout operated on hardcoded absolute host paths (/bin,\n/lib, /etc, ...) regardless of --root, making it the only place in the\ncodebase that could touch the real host filesystem instead of staying\nscoped to the configured root - and a real risk when bootstrapping a\nnew system into a moun\n[…]\nnagement and belongs in a separate installer,\nwhich will need to exist anyway. mere store init now only ever touches\npaths under --root.\n\nNo dedicated tests existed for --system or createSystemLayout.",
          "is_bot": false,
          "headline": "Remove --system flag from mere store init",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-03T13:06:45Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "d9b5bc7a1a9edfaaf7a7c6e7c176eda85c9dd3ee",
          "body": "…kages' (#87) from verify-archive-hash-before-extract into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/87",
          "is_bot": false,
          "headline": "Merge pull request 'Verify archive_hash before caching downloaded pac…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-03T12:49:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3858051761434d4e2ae9515cf05fb3b7db2a0a13",
          "body": "prefetchMissingPackageArchives and ensurePackageArchiveCached both\ndownloaded package archives with DownloadOptions{} - no expected_hash -\neven though the signed repo db already carries the correct archive_hash\nfor every package. A tampered mirror or corrupted transfer would be\nsilently cached and l\n[…]\nt\ndidn't match their dummy archive bodies; fixed them to use the real\nhash of the body now that it's actually checked. Added a regression\ntest that a tampered archive gets rejected before it's cached.",
          "is_bot": false,
          "headline": "Verify archive_hash before caching downloaded packages",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-03T12:18:33Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9d03ab04dbda12b926f0031c661d4fa7eddaa836",
          "body": "handleKeep only wrote the .keep marker file, never a GC-root symlink.\nmere store clean's reachability walk only follows gc-roots symlinks, so\na kept generation's directory would survive pruning but the store\nobjects it references would still get deleted - breaking the advertised\nrollback. Sync GC roots via gcroots.updateRoots (which already accounts\nfor explicit keeps) right after keepGeneration/unkeepGeneration.",
          "is_bot": false,
          "headline": "Create GC roots when keeping a generation",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-02T17:10:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1876cf92eb139d3426a766247e2be8e81bd89565",
          "body": "…otless-store-init into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/85",
          "is_bot": false,
          "headline": "Merge pull request 'Allow rootless mere store init' (#85) from fix/ro…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-02T16:42:10Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "affef78407bf9eb0b4577e491d196c0aff341473",
          "body": "…ce log error handling' (#86) from fix/store-mutation-locking into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/86",
          "is_bot": false,
          "headline": "Merge pull request 'Serialize mutating store operations and fix servi…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-07-02T16:41:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35e78a3826c5b506c71d15a5582b27f0d76865fb",
          "body": "Add a process-wide store lock (blocking exclusive flock on\n<root>/mere/.lock, reentrant within a Context) and wire it into every\nmutating command: install, uninstall, store generation\nactivate/keep/unkeep/delete, and store clean. Concurrent mere\ninvocations against the same root were previously unse\n[…]\net unnarrowed - only the exe target reaches this\npath, so zig build test never caught it) and a diagnostic-swallowing\nbug in serviceFailure's PermissionDenied branch that dropped context\nset upstream.",
          "is_bot": false,
          "headline": "Serialize mutating store operations and fix service log error handling",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-07-02T16:29:03Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "f7762666c7f623c94e38e519d1d303a204a8b379",
          "body": "`mere store init` gated on uid 0 and unconditionally chowned every\ndirectory to root:root. With a user-writable MERE_ROOT this gating\ncontributed nothing (filesystem permissions already control access)\nbut it blocked rootless installs entirely.\n\n- Drop the uid 0 check in `init.initialize()`. Filesys\n[…]\nre-test profile create test` succeeds\n- `mere --root /tmp/mere-test install -p test busybox` downloads,\n  signature-verifies, extracts to store, materializes profile\n- Profile binary runs without sudo",
          "is_bot": false,
          "headline": "Allow rootless mere store init",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-26T19:34:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "8a1dc01df76a5c545c035659205ecf688e51e6f3",
          "body": "…refactor/drop-rollback-protection into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/84",
          "is_bot": false,
          "headline": "Merge pull request 'Drop rollback protection enforcement' (#84) from …",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-25T14:28:57Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "946f7870c2912a559461e287e28b84136744432d",
          "body": null,
          "is_bot": false,
          "headline": "Merge branch 'main' into refactor/drop-rollback-protection",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-25T13:58:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "709a3a84b164c726fa64a93bd0b850f58c2752f1",
          "body": "… refactor/declared-arch-only into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/83",
          "is_bot": false,
          "headline": "Merge pull request 'Require explicit package architecture' (#83) from…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-25T13:57:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09a3b8e72cca94671498d0ca2ec965ff5a92d57b",
          "body": "Rollback protection turned out to be a poor fit for Mere at its\ncurrent scale. The protection it offered (rejecting older signed\npackages on install) defends against a narrow attack: a mirror or\nnetwork attacker substituting an older, validly-signed package for\na newer one. With one repo, one signin\n[…]\nollback bullets and prose throughout\n- Mark created_at as informational\n\nManifest schema is unchanged. Generation rollback (the user-facing\nmere store generation activate flow) is unrelated and stays.",
          "is_bot": false,
          "headline": "Drop rollback protection enforcement",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-25T13:55:06Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3375335359a24ebdabf738a6d0592653cc8c35c6",
          "body": "Recipes now declare which architectures they support. The\nprevious design tried to infer the target arch from package\ncontents, with \"any\" as a fallback when nothing was\ndetectable. That experiment didn't pay off. Auto-detection\nconfirmed what was already known in the easy cases, but got\nit wrong in\n[…]\nit is simpler and safer. \"any\" is now an opt-in\nclaim that a recipe author makes deliberately. Without a\ndeclaration, a package takes the build host's architecture.\n\nDependency inference is unchanged.",
          "is_bot": false,
          "headline": "Require explicit package architecture",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-25T12:49:59Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "fdbc5c8268fcd97972addd4363cb0fbf10abc641",
          "body": "…er-abstraction into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/82",
          "is_bot": false,
          "headline": "Merge pull request 'init provider abstraction' (#82) from init-provid…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-09T15:57:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "390c20204f9a9be515a40f7f623a57828ad82f3f",
          "body": "Keep init-provider configuration errors specific as they pass through service management. Service commands now report unsupported configured providers and format config diagnostics instead of collapsing provider and config failures into generic service errors.\n\nAlso include the invalid provider value in config diagnostics so mistakes point directly at the setting that needs correction.",
          "is_bot": false,
          "headline": "Preserve service provider diagnostics",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-09T11:54:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d9dd0c8e5321141093b74d22ef402b9202111db3",
          "body": "Add a typed init-provider setting to Mere configuration and route both runtime service commands and package-time service artifact generation through it.\n\ns6-rc remains the default and only implemented provider. dinit is recognized as a provider name, but selecting it now fails explicitly at the provider boundary instead of silently emitting or executing s6-rc behavior.\n\nAlso include services.zig in the aggregate test root so service facade tests run with the full suite.",
          "is_bot": false,
          "headline": "Wire init provider selection",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-09T11:54:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "35e62f7eb4cecc95f0707a76496922cb667bae9e",
          "body": "Add an active-provider entry point for package-time service artifact generation and move the existing s6-rc source directory writer behind s6-rc-specific function names.\n\nBehavior is unchanged: recipe service blocks still emit s6-rc source directories under usr/share/s6-rc/sources. This makes the package-time provider boundary explicit before adding alternate artifact generators such as dinit.",
          "is_bot": false,
          "headline": "Name s6-rc service artifact generation",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-09T11:54:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "43a215b03fc1ea44102ad1802035f8713ea268c1",
          "body": "Move service command handling behind a provider-neutral services module. The CLI no longer issues s6-rc commands directly for lifecycle, status, listing, or log operations; it delegates to src/services.zig instead.\n\nThe current provider remains s6-rc and behavior is intended to stay the same. This creates the runtime boundary needed before adding alternate init providers such as dinit.",
          "is_bot": false,
          "headline": "Introduce service provider facade",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-09T11:54:45Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "42c2118ce9f1cfeb7afa694cb5b334f1c93e4ef4",
          "body": "…#81) from fix/bubble-file-hash-errors into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/81",
          "is_bot": false,
          "headline": "Merge pull request 'Bubble file path into calculateFileHash errors' (…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-09T11:49:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bb7e47c03825bf216ff54e261182c5e033d0f329",
          "body": "calculateFileHash now takes *Context instead of Allocator and calls\nctx.setDiagnosticContext with the failing path and original error name\non any I/O failure. This ensures users see which file failed and why,\nrather than a generic \"filesystem error\" with no context.\n\nAlso removes redundant allocator\n[…]\npy,\nwhich caused arena allocations to escape cleanup.\n\nRoot cause of #75: missing signing key mapped FileNotFound to FileSystem\nwith no path context preserved. User now sees the actual path and error.",
          "is_bot": false,
          "headline": "Bubble file path into calculateFileHash errors",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-08T17:11:12Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dfae3e9a62f6d58304fcb67bccc2e030fd472f7a",
          "body": "Reviewed-on: https://codeberg.org/merelinux/mere/pulls/80",
          "is_bot": false,
          "headline": "Merge pull request 'release: v0.14.0' (#80) from v0.14.0 into main",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-04T17:07:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8e49dfe30bfcaecf08ce546a9d2ec419b7423cbf",
          "body": null,
          "is_bot": false,
          "headline": "release: v0.14.0",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-04T16:45:54Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c3dc7f90854363f0221e569c9847c957fe61750f",
          "body": "…ror-messages into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/79",
          "is_bot": false,
          "headline": "Merge pull request 'fix/cache-error-messages' (#79) from fix/cache-er…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-04T16:44:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5411fa19b77f3e7448d6050eb048eb4e43820dc",
          "body": "The rootless support PR (#78) added a guard that skips\nrollback-state updates when running unprivileged. The\nexisting \"fails hard on rollback-state update after\nadmission\" test relied on running unprivileged and chmod'ing\nthe cache directory to trigger PermissionDenied — the new\nguard makes that pat\n[…]\nvileged, finalizeAdmittedStoreObject succeeds and\ndoes not write a rollback-state file. Error propagation in\nthe privileged path is the standard switch-and-return pattern\nused throughout the codebase.",
          "is_bot": false,
          "headline": "Test the rootless guard in finalizeAdmittedStoreObject",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-04T16:36:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "ed85634accaecfebee375ad160869379569952fb",
          "body": "When restorePackageArchiveRequest failed, the same generic\n\"failed to resolve package cache\" message was returned for\nevery CacheError variant (OutOfMemory, FileSystem,\nPermissionDenied, InvalidInput). Users hitting the failure\nhad no way to tell whether they were looking at a permissions\nproblem, a\n[…]\nOOM, or invalid input.\n\nReplace the catch-all `else` branch with explicit handling\nof each variant, surfacing a distinct hint in the diagnostic\nmessage. The PackageError mapping is unchanged.\n\nRef #75",
          "is_bot": false,
          "headline": "Distinguish CacheError variants in package staging",
          "author_name": "Jeremy Huntwork",
          "author_login": "jhuntwork",
          "committed_at": "2026-06-04T16:36:30Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "34d84905b559b7c2c262c746cb386cb69657d06a",
          "body": "…t into main\n\nReviewed-on: https://codeberg.org/merelinux/mere/pulls/78",
          "is_bot": false,
          "headline": "Merge pull request 'rootless-support' (#78) from feat/rootless-suppor…",
          "author_name": "jhuntwork",
          "author_login": null,
          "committed_at": "2026-06-03T23:31:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 32,
      "commits_last_year": 272,
      "latest_release_at": "2026-07-21T01:53:28Z",
      "latest_release_tag": "v0.16.1",
      "releases_from_tags": true,
      "days_since_last_push": 10,
      "active_weeks_last_year": 14,
      "days_since_latest_release": 10,
      "mean_days_between_releases": 11.9
    },
    "community": {
      "has_readme": true,
      "has_license": true,
      "has_description": true,
      "has_contributing": false,
      "health_percentage": 42,
      "has_issue_template": false,
      "has_code_of_conduct": false,
      "has_pull_request_template": false
    },
    "ecosystem": {
      "packages": []
    },
    "popularity": {
      "forks": 0,
      "stars": 5,
      "watchers": 2,
      "fork_history": {
        "days": [],
        "complete": true,
        "collected": 0,
        "total_forks": 0
      },
      "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": 441,
      "source_files_sampled": 1,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [],
      "advisories": {
        "error": "No resolved dependencies to assess",
        "scope": "repository_graph",
        "source": null,
        "findings": [],
        "collected": false,
        "malicious": [],
        "truncated": false,
        "by_severity": {},
        "advisory_count": 0,
        "affected_count": 0,
        "assessed_count": 0,
        "malicious_count": 0,
        "assessed_package": null,
        "unassessed_count": 0,
        "direct_affected_count": 0
      },
      "ecosystems": [],
      "dependencies": [],
      "all_dependencies": {
        "error": null,
        "source": "github-sbom",
        "packages": [],
        "collected": true,
        "truncated": false,
        "total_count": 0,
        "direct_count": 0,
        "indirect_count": 0
      }
    },
    "maintainership": {
      "issues": {
        "open_prs": 0,
        "merged_prs": 15,
        "open_issues": 0,
        "closed_ratio": 1,
        "closed_issues": 1,
        "closed_unmerged_prs": 0
      },
      "bus_factor": 1,
      "bot_contributors": 0,
      "top_contributors": [
        {
          "type": "User",
          "login": "jhuntwork",
          "commits": 167,
          "avatar_url": "https://avatars.githubusercontent.com/u/239626?v=4"
        }
      ],
      "contributors_sampled": 1,
      "top_contributor_share": 1
    },
    "quality_signals": {
      "has_ci": false,
      "has_tests": true,
      "ci_workflows": [],
      "has_docs_dir": true,
      "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": 0,
            "reason": "project has 0 contributing companies or organizations -- score normalized to 0",
            "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": 10,
            "reason": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
            "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": "83bd82c434c2b7bcc854f6dc750206d970427025",
        "ran_at": "2026-07-31T12:16:29Z",
        "aggregate_score": 3.7,
        "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": "2026-07-21T01:53:43Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2024-07-23T04:12:55Z",
      "ci_last_conclusion": null,
      "oldest_open_issues": []
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/jhuntwork/mere",
    "host": "github.com",
    "name": "mere",
    "owner": "jhuntwork"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 50,
      "inputs": {
        "security": 37,
        "vitality": 75,
        "community": 29,
        "governance": 48,
        "engineering": 54
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 75,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 66,
            "inputs": {
              "commits_last_year": 272,
              "human_commit_share": 1,
              "days_since_last_push": 10,
              "active_weeks_last_year": 14
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 10 days ago",
                "points": 28.8,
                "status": "partial",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "14/52 weeks with commits",
                "points": 9.7,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 14
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "272 commits in the last year",
                "points": 18,
                "status": "met",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 272
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "excellent",
            "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": 88,
            "inputs": {
              "releases_count": 32,
              "latest_release_tag": "v0.16.1",
              "releases_from_tags": true,
              "days_since_latest_release": 10,
              "mean_days_between_releases": 11.9
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "32 version tags (no GitHub releases)",
                "points": 16.2,
                "status": "partial",
                "details": [
                  {
                    "code": "version_tags_no_releases",
                    "params": {
                      "count": 32
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 10 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~11.9 days",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 11.9
                    }
                  }
                ],
                "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": 10,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 10 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 10
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "critical",
        "name": "Community & Adoption",
        "value": 29,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "critical",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "forks": 0,
              "stars": 5,
              "watchers": 2,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "5 stars",
                "points": 9.8,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "0 forks",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 0
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "2 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 2
                    }
                  }
                ],
                "max_points": 15
              }
            ]
          },
          {
            "key": "community_health",
            "band": "moderate",
            "name": "Community health",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "has_readme": true,
              "has_license": true,
              "has_contributing": false,
              "has_issue_template": false,
              "has_code_of_conduct": false,
              "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 (MIT)",
                "points": 22.5,
                "status": "met",
                "details": [
                  {
                    "code": "license_standard",
                    "params": {}
                  },
                  {
                    "code": "license_spdx",
                    "params": {
                      "spdx": "MIT"
                    }
                  }
                ],
                "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": 0,
                "status": "missed",
                "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
              }
            ]
          }
        ],
        "description": "Does the project have users, downloads, attention, and a welcoming setup for contributors?"
      },
      {
        "key": "governance",
        "band": "at_risk",
        "name": "Sustainability & Governance",
        "value": 48,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 10,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 1,
              "top_contributor_share": 1
            },
            "components": [
              {
                "key": "bus_factor",
                "name": "Bus factor",
                "detail": "1 contributor(s) cover half of all commits",
                "points": 9,
                "status": "partial",
                "details": [
                  {
                    "code": "bus_factor",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 54
              },
              {
                "key": "commit_distribution",
                "name": "Commit distribution",
                "detail": "top contributor authored 100% of commits",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "1 contributors",
                "points": 1.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "max_points": 13.5
              },
              {
                "key": "openssf_scorecard_contributors",
                "name": "OpenSSF Scorecard: Contributors",
                "detail": "project has 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "responsiveness",
            "band": "excellent",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 85,
            "inputs": {
              "merged_prs": 15,
              "open_issues": 0,
              "closed_issues": 1,
              "issue_closed_ratio": 1,
              "closed_unmerged_prs": 0
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "100% of issues closed",
                "points": 46.8,
                "status": "met",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 100
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "15/15 decided PRs merged",
                "points": 38.2,
                "status": "met",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 15,
                      "decided": 15
                    }
                  }
                ],
                "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": "moderate",
            "name": "Ownership & stewardship",
            "note": "Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "verified_domain"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 55,
            "inputs": {
              "followers": 42,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "jhuntwork",
              "public_repos": 23,
              "account_age_days": 5957
            },
            "components": [
              {
                "key": "ownership_backing",
                "name": "Ownership backing",
                "detail": "personal (user) account",
                "points": 10,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_personal",
                    "params": {}
                  }
                ],
                "max_points": 30
              },
              {
                "key": "verified_domain",
                "name": "Verified domain",
                "detail": "not applicable to user accounts",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "not_applicable_to_user_accounts",
                    "params": {}
                  }
                ],
                "max_points": 20
              },
              {
                "key": "owner_reach",
                "name": "Owner reach",
                "detail": "42 followers of jhuntwork",
                "points": 11.7,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 42,
                      "login": "jhuntwork"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "23 public repos, account ~16 yr old",
                "points": 22.1,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 23
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 16
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 54,
        "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": "excellent",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 90,
            "inputs": {
              "topics": [],
              "has_wiki": true,
              "homepage": "https://codeberg.org/merelinux/mere",
              "has_readme": true,
              "has_docs_dir": true,
              "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": 25,
                "status": "met",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": "https://codeberg.org/merelinux/mere",
                "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": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "at_risk",
        "name": "Security",
        "value": 37,
        "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": 37,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 12,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 6,
              "scorecard_aggregate": 3.7
            },
            "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 0 contributing companies or organizations -- score normalized to 0",
                "points": 0,
                "status": "missed",
                "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": "30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10",
                "points": 7.5,
                "status": "met",
                "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": "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": 2
            },
            "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.99,
              "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": "99 of 100 human commits state their intent (structured subject or explanatory body)",
                "points": 40,
                "status": "met",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 99,
                      "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": "Zig",
              "largest_source_bytes": 441,
              "source_files_sampled": 1,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Zig without a type-check config",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "no_typecheck_config_language",
                    "params": {
                      "language": "Zig"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/1 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 1,
                      "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-31T12:17:04.796925Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/j/jhuntwork/mere.svg",
  "full_name": "jhuntwork/mere",
  "license_state": "standard",
  "license_spdx": "MIT"
}

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

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

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