Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-31 12:17 UTC

jhuntwork / mere

A mirror repository for the mere package manager

ZigMIT★ 5 stars⑂ 0 forkssince Aug 2019View on GitHub ↗

jhuntwork/mere holds a health index of 50 out of 100, placing it in the Moderate band. It scores highest on Vitality (75/100) and lowest on Community & Adoption (29/100). It was last updated 10 days ago. A single contributor accounts for most of its recent work.

50
overall / 100
Moderate

Software health index

Metrics are grouped into weighted categories on one standardized 1–100 scale. Overall starts as their weighted mean; when public evidence triggers the High-Risk Jurisdiction Policy, the rating is adjusted and receives an At risk ceiling of 49. AI Readiness sits outside the overall score.

50
Excellent85-100Exemplary; meets essentially all checked criteria
Good70-84Healthy; minor gaps
Moderate50-69Acceptable with notable gaps; review recommended
At risk30-49Significant weaknesses; adoption warrants caution
Critical1-29Severe problems (abandoned, single-maintainer, no hygiene)
VitalityCommunity &AdoptionSustainability &GovernanceEngineeringQualitySecurityAI Readiness

Score profile

Each axis is a category. The shape matters more than the average — a healthy subject fills the whole shape, while a spike-and-crater profile means strength in one dimension is masking risk in another.

Ownership

Jeremy HuntworkPersonal account
42 followers23 public repossince Apr 2010

This repository is owned by a personal account. A single-owner project carries more continuity risk than an organization-backed one.

Metrics by category

Vitality

Is the project alive — is code being written and are releases shipping?

75Good · 22% of overall
How it's scored
28.8/36Push recency — last push 10 days ago
9.7/36Commit cadence — 14/52 weeks with commits
18/18Commit volume — 272 commits in the last year
10/10OpenSSF Scorecard: Maintained — 30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year272
human_commit_share1
days_since_last_push10
active_weeks_last_year14
How it's scored
16.2/27Ships releases — 32 version tags (no GitHub releases)
36/36Release recency — latest release 10 days ago
27/27Release cadence — a release every ~11.9 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count32
latest_release_tagv0.16.1
releases_from_tagsyes
days_since_latest_release10
mean_days_between_releases11.9
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.

Community & Adoption

Does the project have users, downloads, attention, and a welcoming setup for contributors?

29Critical · 18% of overall
How it's scored
9.8/60Stars — 5 stars
0/25Forks — 0 forks
0/15Watchers — 2 watchers
Inputs used
forks0
stars5
watchers2
growth_stateunverified
growth_factor_pct100
growth_unverified_reasonno_history
How it's scored
22.5/22.5README
22.5/22.5License — recognized license (MIT)
0/18CONTRIBUTING guide
0/13.5Code of conduct
0/7.2Issue template
0/6.3PR template
Inputs used
has_readmeyes
has_licenseyes
has_contributingno
has_issue_templateno
has_code_of_conductno
has_pull_request_templateno

Sustainability & Governance

Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?

48At risk · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
0/22.5Commit distribution — top contributor authored 100% of commits
1.4/13.5Contributor breadth — 1 contributors
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Inputs used
bus_factor1
contributors_sampled1
top_contributor_share1
How it's scored
46.8/46.8Issue resolution — 100% of issues closed
38.2/38.3PR acceptance — 15/15 decided PRs merged
0/15OpenSSF Scorecard: Code-Review — Found 0/30 approved changesets -- score normalized to 0
Inputs used
merged_prs15
open_issues0
closed_issues1
issue_closed_ratio1
closed_unmerged_prs0
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
11.7/25Owner reach — 42 followers of jhuntwork
22.1/25Track record — 23 public repos, account ~16 yr old
Inputs used
followers42
owner_typeUser
is_verified
owner_loginjhuntwork
public_repos23
account_age_days5,957
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.

Engineering Quality

Are baseline engineering and documentation practices in place?

54Moderate · 20% of overall
How it's scored
0/24CI workflows
24/24Tests present
0/16Linter config
0/9.6Pre-commit hooks
0/6.4.editorconfig
0/20OpenSSF Scorecard: CI-Tests — no data
Inputs used
has_cino
has_testsyes
has_editorconfigno
has_linter_configno
has_precommit_configno
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: CI-Tests. Remaining weights renormalized.

Documentation

90Excellent
How it's scored
30/30README
25/25Documentation directory
15/15Documentation / homepage site — https://codeberg.org/merelinux/mere
10/10Repository description
0/10Topics
10/10Wiki
Inputs used
topics
has_wikiyes
homepagehttps://codeberg.org/merelinux/mere
has_readmeyes
has_docs_diryes
has_descriptionyes

Security

Are visible security and supply-chain practices strong, without unresolved high-risk jurisdiction exposure?

37At risk · 16% of overall
How it's scored
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 — no data
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 — no data
0/7.5Dependency-Update-Tool — no update tool detected
0/5Fuzzing — project is not fuzzed
2.5/2.5License — 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 — no data
0/5Pinned-Dependencies — no data
0/5SAST — no SAST tool detected
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — no data
0/7.5Token-Permissions — no data
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated12
scorecard_versionv5.5.0
checks_inconclusive6
scorecard_aggregate3.7
Excluded from scoring (no data or not applicable): ci_tests, dangerous_workflow, packaging, pinned_dependencies, signed_releases, token_permissions. Remaining weights renormalized.

AI Readiness

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.

35At risk · 0% of overall
How it's scored
0/45Agent instructions — no CLAUDE.md / AGENTS.md / editor rules
0/15Machine-readable docs (llms.txt)
40/40Legible commit history — 99 of 100 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.99
agent_instruction_files
agent_instruction_max_bytes
How it's scored
0/18One-command bootstrap
22/22Automated tests
0/11Lint / format config
0/11Static type checking
0/10Reproducible environment
0/10Demonstrated agent practice — no agent-authored commits among the last 100
0/8Automated maintenance — no automated dependency updates observed
0/10OpenSSF Scorecard: Pinned-Dependencies — no data
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileno
typed_languageno
bootstrap_files
has_devcontainerno
has_linter_configno
typecheck_configs
agent_commit_share0
toolchain_manifests
dependency_bot_commit_share0
Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Pinned-Dependencies. Remaining weights renormalized.
How it's scored
0/45Type-checkable code — Zig without a type-check config
55/55Manageable file sizes — 0/1 source files over 60KB
Inputs used
primary_languageZig
largest_source_bytes441
source_files_sampled1
oversized_source_files0

Key facts

5GitHub stars
1contributors
272commits, last 12 months
10days since last push
32releases
1bus factor
0open issues
package ecosystems

Data collection warnings

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

More detail

OpenSSF Scorecard 3.7 / 10
3.7aggregate

Independent, tool-agnostic security assessment from the open-source OpenSSF Scorecard. Each check rewards a security practice, not a specific vendor's tool. Checks Scorecard could not determine are marked n/a and excluded from the security score (never counted as zero).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
n/aCI-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
n/aDangerous-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
n/aPackagingpackaging workflow not detected
n/aPinned-Dependenciesno dependencies found
0SASTno SAST tool detected
0Security-Policysecurity policy file not detected
n/aSigned-Releasesno releases found
n/aToken-PermissionsNo tokens found
10Vulnerabilities0 existing vulnerabilities detected
All dependencies 0

Full resolved dependency set from the GitHub dependency graph: 0 direct and 0 indirect (transitive) packages. The transitive closure is complete when the repository commits a lockfile.

RegistryPackageVersionRelation
Dependency advisories not assessed

Advisory matching could not run for this report: No resolved dependencies to assess

Raw JSON report machine-readable
{
  "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"
}

Scores are signals, not warranties. They reflect publicly visible practices on GitHub — not a code audit, and not a security guarantee.

Missing data is excluded and weights renormalized, never scored as zero. Methodology is versioned and open: metrics v1.13.0, schema v0.27.0 — full methodology · metrics wiki.

How one result sits in the wider record: aggregate statistics.