Public record
Software health reportschema 0.27.0 · metrics 1.13.0 · 2026-07-25 04:27 UTC

bluekeyes / go-gitdiff

Go library for parsing and applying patches created by Git

GoMIT★ 151 stars⑂ 28 forkssince Mar 2019View on GitHub ↗

bluekeyes/go-gitdiff holds a health index of 61 out of 100, placing it in the Moderate band. It scores highest on Vitality (70/100) and lowest on Community & Adoption (48/100). It was last updated 4 days ago. A single contributor accounts for most of its recent work.

61
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.

61
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

Billy KeyesPersonal account
93 followers34 public repossince May 2012

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

Package ecosystems

RegistryPackageVersionDownloads / moVersionsLast publish
Gogithub.com/bluekeyes/go-gitdiffv0.9.0-186 days ago

Metrics by category

Vitality

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

70Good · 22% of overall
How it's scored
36/36Push recency — last push 4 days ago
4.8/36Commit cadence — 7/52 weeks with commits
10.6/18Commit volume — 14 commits in the last year
10/10OpenSSF Scorecard: Maintained — 13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
Inputs used
commits_last_year14
human_commit_share0.95
days_since_last_push4
active_weeks_last_year7
How it's scored
27/27Ships releases — 18 releases published
36/36Release recency — latest release 6 days ago
12.6/27Release cadence — a release every ~199.3 days
0/10OpenSSF Scorecard: Signed-Releases — no data
Inputs used
releases_count18
latest_release_tagv0.9.0
releases_from_tagsno
days_since_latest_release6
mean_days_between_releases199.3
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?

48At risk · 18% of overall
How it's scored
35.3/60Stars — 151 stars
11.9/25Forks — 28 forks
0/15Watchers — 1 watchers
Inputs used
forks28
stars151
watchers1
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?

58Moderate · 24% of overall
How it's scored
9/54Bus factor — 1 contributor(s) cover half of all commits
0.7/22.5Commit distribution — top contributor authored 97% of commits
5.4/13.5Contributor breadth — 4 contributors
0/10OpenSSF Scorecard: Contributors — project has 0 contributing companies or organizations -- score normalized to 0
Inputs used
bus_factor1
contributors_sampled4
top_contributor_share0.967
How it's scored
38.7/46.8Issue resolution — 83% of issues closed
35.2/38.3PR acceptance — 46/50 decided PRs merged
0/15OpenSSF Scorecard: Code-Review — Found 0/25 approved changesets -- score normalized to 0
Inputs used
merged_prs46
open_issues5
closed_issues24
issue_closed_ratio0.828
closed_unmerged_prs4
How it's scored
10/30Ownership backing — personal (user) account
0/20Verified domain — not applicable to user accounts
14.2/25Owner reach — 93 followers of bluekeyes
23.2/25Track record — 34 public repos, account ~14 yr old
Inputs used
followers93
owner_typeUser
is_verified
owner_loginbluekeyes
public_repos34
account_age_days5,182
Excluded from scoring (no data or not applicable): Verified domain. Remaining weights renormalized.
How it's scored
25/25Published & resolvable — 1 package(s) on go
35/35Publish recency — latest publish 6 days ago
20/20Version history — 18 published versions
20/20Not deprecated — active, not deprecated or yanked
Inputs used
packagesgithub.com/bluekeyes/go-gitdiff
ecosystemsgo
any_deprecatedno
min_days_since_publish6

Engineering Quality

Are baseline engineering and documentation practices in place?

64Moderate · 20% of overall
How it's scored
24/24CI workflows — 1 workflow(s)
24/24Tests present
16/16Linter config — .golangci.yml
0/9.6Pre-commit hooks
0/6.4.editorconfig
10/20OpenSSF Scorecard: CI-Tests — 14 out of 27 merged PRs checked by a CI test -- score normalized to 5
Inputs used
has_ciyes
has_testsyes
has_editorconfigno
has_linter_configyes
has_precommit_configno

Documentation

50Moderate
How it's scored
30/30README
0/25Documentation directory
0/15Documentation / homepage site
10/10Repository description
10/10Topics — 5 topics
0/10Wiki
Inputs used
topicsgolang, git, diff, patch, gitdiff
has_wikino
homepage
has_readmeyes
has_docs_dirno
has_descriptionyes

Security

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

63Moderate · 16% of overall
How it's scored
7.5/7.5Binary-Artifacts — no binaries found in the repo
0/7.5Branch-Protection — no data
1.2/2.5CI-Tests — 14 out of 27 merged PRs checked by a CI test -- score normalized to 5
0/2.5CII-Best-Practices — no effort to earn an OpenSSF best practices badge detected
0/7.5Code-Review — Found 0/25 approved changesets -- score normalized to 0
0/2.5Contributors — project has 0 contributing companies or organizations -- score normalized to 0
10/10Dangerous-Workflow — no dangerous workflow patterns detected
7.5/7.5Dependency-Update-Tool — update tool detected
5/5Fuzzing — project is fuzzed
2.5/2.5License — license file detected
7.5/7.5Maintained — 13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
0/5Packaging — no data
5/5Pinned-Dependencies — all dependencies are pinned
0/5SAST — SAST tool is not run on all commits -- score normalized to 0
0/5Security-Policy — security policy file not detected
0/7.5Signed-Releases — no data
0/7.5Token-Permissions — detected GitHub workflow tokens with excessive permissions
7.5/7.5Vulnerabilities — 0 existing vulnerabilities detected
Inputs used
sourceopenssf_scorecard
checks_evaluated15
scorecard_versionv5.5.0
checks_inconclusive3
scorecard_aggregate6.3
Excluded from scoring (no data or not applicable): branch_protection, packaging, signed_releases. 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.

66Moderate · 0% of overall
How it's scored
0/45Agent instructions — no CLAUDE.md / AGENTS.md / editor rules
0/15Machine-readable docs (llms.txt)
38.2/40Legible commit history — 68 of 95 human commits state their intent (structured subject or explanatory body)
Inputs used
has_llms_txtno
legible_history_share0.716
agent_instruction_files
agent_instruction_max_bytes
How it's scored
12.6/18One-command bootstrap — go.mod (toolchain convention, no task runner)
22/22Automated tests
11/11Lint / format config — .golangci.yml
11/11Static type checking — Go (statically typed)
0/10Reproducible environment
0/10Demonstrated agent practice — no agent-authored commits among the last 100
8/8Automated maintenance — 5 of the last 100 commits are automated dependency updates
10/10OpenSSF Scorecard: Pinned-Dependencies — all dependencies are pinned
Inputs used
has_nixno
has_testsyes
lockfiles
has_dockerfileno
typed_languageyes
bootstrap_files
has_devcontainerno
has_linter_configyes
typecheck_configs
agent_commit_share0
toolchain_manifestsgo.mod
dependency_bot_commit_share0.05
How it's scored
45/45Type-checkable code — Go (statically typed)
55/55Manageable file sizes — 0/30 source files over 60KB
Inputs used
primary_languageGo
largest_source_bytes16,904
source_files_sampled30
oversized_source_files0

Key facts

151GitHub stars
4contributors
14commits, last 12 months
4days since last push
18releases
1bus factor
5open issues
Gopackage ecosystems

Data collection warnings

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

More detail

Star and fork history 0 ★ / 28 ⇿
0Stars
28Forks
17Releases

When each star and fork was added, collected from GitHub and bucketed by day. Cumulative growth sits directly above the daily additions it is made of, so the two read against each other: steady organic accretion looks nothing like an abrupt, short-lived burst. Where that difference is measurable, it is reported as growth authenticity.

0481216201912019-112023-032026-07
Major 0Minor 8Patch 9

Each point covers 7 days.

OpenSSF Scorecard 6.3 / 10
6.3aggregate

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-25 04:27 UTC

10Binary-Artifactsno binaries found in the repo
n/aBranch-Protectioninternal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
5CI-Tests14 out of 27 merged PRs checked by a CI test -- score normalized to 5
0CII-Best-Practicesno effort to earn an OpenSSF best practices badge detected
0Code-ReviewFound 0/25 approved changesets -- score normalized to 0
0Contributorsproject has 0 contributing companies or organizations -- score normalized to 0
10Dangerous-Workflowno dangerous workflow patterns detected
10Dependency-Update-Toolupdate tool detected
10Fuzzingproject is fuzzed
10Licenselicense file detected
10Maintained13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10
n/aPackagingpackaging workflow not detected
10Pinned-Dependenciesall dependencies are pinned
0SASTSAST tool is not run on all commits -- score normalized to 0
0Security-Policysecurity policy file not detected
n/aSigned-Releasesno releases found
0Token-Permissionsdetected GitHub workflow tokens with excessive permissions
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": [
        "golang",
        "git",
        "diff",
        "patch",
        "gitdiff"
      ],
      "is_fork": false,
      "size_kb": 4077,
      "has_wiki": false,
      "homepage": null,
      "languages": {
        "Go": 174128
      },
      "pushed_at": "2026-07-20T13:04:16Z",
      "created_at": "2019-03-11T04:50:36Z",
      "owner_type": "User",
      "updated_at": "2026-07-24T03:00:41Z",
      "description": "Go library for parsing and applying patches created by Git ",
      "is_archived": false,
      "is_disabled": false,
      "license_spdx": "MIT",
      "default_branch": "master",
      "license_spdx_raw": "MIT",
      "primary_language": "Go",
      "significant_languages": [
        "Go"
      ]
    },
    "owner": {
      "blog": "https://billykeyes.dev/",
      "name": "Billy Keyes",
      "type": "User",
      "login": "bluekeyes",
      "company": null,
      "location": "Pittsburgh, PA",
      "followers": 93,
      "avatar_url": "https://avatars.githubusercontent.com/u/1745813?v=4",
      "created_at": "2012-05-16T13:49:06Z",
      "is_verified": null,
      "public_repos": 34,
      "account_age_days": 5182
    },
    "license": {
      "state": "standard",
      "spdx_id": "MIT",
      "raw_spdx": "MIT",
      "file_present": true,
      "scorecard_found": true,
      "profile_has_license": true
    },
    "activity": {
      "releases": [
        {
          "tag": "v0.9.0",
          "kind": "minor",
          "published_at": "2026-07-18T21:59:23Z"
        },
        {
          "tag": "v0.8.1",
          "kind": "patch",
          "published_at": "2025-01-08T03:38:43Z"
        },
        {
          "tag": "v0.8.0",
          "kind": "minor",
          "published_at": "2024-08-20T03:16:58Z"
        },
        {
          "tag": "v0.7.4",
          "kind": "patch",
          "published_at": "2024-07-19T03:44:16Z"
        },
        {
          "tag": "v0.7.3",
          "kind": "patch",
          "published_at": "2024-05-06T03:29:52Z"
        },
        {
          "tag": "v0.7.2",
          "kind": "patch",
          "published_at": "2024-03-07T05:37:16Z"
        },
        {
          "tag": "v0.7.1",
          "kind": "patch",
          "published_at": "2023-03-17T05:05:51Z"
        },
        {
          "tag": "v0.7.0",
          "kind": "minor",
          "published_at": "2022-10-01T22:43:44Z"
        },
        {
          "tag": "v0.6.1",
          "kind": "patch",
          "published_at": "2022-03-18T20:57:53Z"
        },
        {
          "tag": "v0.6.0",
          "kind": "minor",
          "published_at": "2021-08-20T00:59:27Z"
        },
        {
          "tag": "v0.5.2",
          "kind": "patch",
          "published_at": "2021-07-19T18:50:30Z"
        },
        {
          "tag": "v0.5.1",
          "kind": "patch",
          "published_at": "2021-04-24T22:26:48Z"
        },
        {
          "tag": "v0.5.0",
          "kind": "minor",
          "published_at": "2020-10-24T03:50:18Z"
        },
        {
          "tag": "v0.4.0",
          "kind": "minor",
          "published_at": "2020-06-16T05:14:32Z"
        },
        {
          "tag": "v0.3.0",
          "kind": "minor",
          "published_at": "2020-04-19T05:28:28Z"
        },
        {
          "tag": "v0.2.1",
          "kind": "patch",
          "published_at": "2020-02-01T19:01:23Z"
        },
        {
          "tag": "v0.2.0",
          "kind": "minor",
          "published_at": "2020-01-28T07:01:23Z"
        },
        {
          "tag": "v0.1.0",
          "kind": "minor",
          "published_at": "2020-01-10T06:21:31Z"
        }
      ],
      "recent_commits": [
        {
          "oid": "0927b543c7730d28b21ceef164fd0ed7a6a53f93",
          "body": null,
          "is_bot": true,
          "headline": "Bump actions/setup-go from 6.5.0 to 7.0.0 (#80)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-20T13:04:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "703f876c1784f15ce871acd16a5de80b660baf4f",
          "body": null,
          "is_bot": false,
          "headline": "Add apply limits to the differences list (#79)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-07-18T18:51:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "12fda45f4844a93af9b67620e3b29961273aeac8",
          "body": null,
          "is_bot": false,
          "headline": "Remove deprecated report card badge (#78)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-07-18T18:49:18Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "51e5b1f36268acb8ef30ee035c54573fa035b63d",
          "body": "Applying a binary fragment can use a lot of memory in two ways:\n\n1. Inflating a large amount of literal data\n2. Processing a delta instruction stream with many copy operations\n\nClients could theoretically protect against the first by checking\nfragment sizes for all binary fragments before the apply,\n[…]\nc. This was required to\ngenerate the test patches for applies over the limit. The `.hex` files\nare not used directly by the test, but provide the source input for the\npatches as processed by `bin.go`.",
          "is_bot": false,
          "headline": "Limit binary fragment size during applies (#77)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-07-18T18:45:01Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "61f6dcbea813962a15b5fe2747ff72f8b8d9bb4e",
          "body": "When parsing a binary fragment, the library attempted to decompress the\npatch data before checking the expected size and without specifying any\nlimit. This allowed a malicious patch to include an \"inflate bomb\" as a\nbinary fragment, forcing the library to allocate excessive memory during\nparsing.\n\nT\n[…]\nr.\nHowever, applying a patch can still write large amounts of data to the\nclient-provided writer in ways the client can't easily prevent. A future\ncommit will enforce limits at apply time to fix this.",
          "is_bot": false,
          "headline": "Fix unbounded inflate parsing binary fragments (#76)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-07-18T18:36:51Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "706d29dcff874458fe3b952090b089741af0b2ac",
          "body": "The apply logic trusted the line counts of the incoming patch when\nallocating memory for preimages. This meant a patch could specify a very\nlarge old position in a fragment and force the library to allocate\nexcessive memory before checking if the source actually contains that\nmany lines.\n\nTo fix thi\n[…]\nocated before we reach the end of the source\nfile. Most practical patches should only require one or two reads.\n\nAlso fix a related panic that could happen with an old position close to\nmath.MaxInt64.",
          "is_bot": false,
          "headline": "Fix potential OOM in Apply (#75)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-07-18T17:28:49Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1d1f2a6b4598e1cc4f6f1f2ead3831a7977d771b",
          "body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump golangci/golangci-lint-action from 9.2.1 to 9.3.0 (#73)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-07-06T23:40:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eb5290733643ed5775c5f032146fc020d4ece19d",
          "body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump actions/setup-go from 6.4.0 to 6.5.0 (#72)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-30T00:54:47Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d9b22e9ad4a118577ccc7a44da18be8abd8d52a8",
          "body": "Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0.\n- [Release notes](https://github.com/actions/checkout/releases)\n- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)\n- [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b43\n[…]\nirect:production\n  update-type: version-update:semver-major\n...\n\nSigned-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump actions/checkout from 6.0.3 to 7.0.0 (#71)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-22T17:10:48Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "66b40fd1c95631e1f9a4f0abacde8ff51e9d78f8",
          "body": "Signed-off-by: dependabot[bot] <support@github.com>\nCo-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>",
          "is_bot": true,
          "headline": "Bump actions/checkout from 6.0.2 to 6.0.3 (#70)",
          "author_name": "dependabot[bot]",
          "author_login": "dependabot[bot]",
          "committed_at": "2026-06-08T12:52:32Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "08f3e635d607a2a0db5178bc8f42b19832bdd6ab",
          "body": "This only updates to Go 1.21 baseline, which is what the module still\nspecifies as the minimum version. I'll need to run this again when\nmoving to Go 1.25 or 1.26 as minimum.",
          "is_bot": false,
          "headline": "Run 'go fix' to modernize code (#69)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-05-25T16:11:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6d3702d6db4ae46086b9a97959e736569760c92b",
          "body": null,
          "is_bot": false,
          "headline": "Run tests with Go 1.25 (#68)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-05-25T15:39:49Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c4be319555b33071b5562cefd31f044414911eb5",
          "body": null,
          "is_bot": false,
          "headline": "Pin GitHub actions to SHAs and enable Dependabot (#67)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2026-05-25T15:36:51Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "17bd72f0e2e89a2c6aa03de29fc2583a7ec07943",
          "body": "Previously, this returned an io.ErrUnexpectedEOF. This is not wrong, in\nthat we did unexpectedly hit the end of the input file, but it is vague\nand implies a possible library bug rather than a problem with the patch\nor the input. This condition is really a conflict, as the changes\ndescribed by the patch are not compatible with the state of the input.",
          "is_bot": false,
          "headline": "Report short sources as conflicts during apply (#63)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-09-04T00:26:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7413262a184380473b5cad4b12a2a061ecbc86c9",
          "body": null,
          "is_bot": false,
          "headline": "Update golangci-lint to v2 (#61)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-04-01T01:37:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0896f01926d529e4c0781f72c7957aa942e2068f",
          "body": "In issue #57, it was reported that the library could not apply some\npatches generated by BSD `diff` because of the way that variant reports\nchanges in files without trailing newlines. Since the library behavior\nmatches Git, I don't consider this a bug, but update the README to\nmention that the support for standard unified diffs is only for the GNU\nvariant of the `diff` tool.",
          "is_bot": false,
          "headline": "Clarify that we only support GNU diff",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-03-29T20:27:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "823d31db22199232e1400cddc39f06d890380055",
          "body": "This worked, but completes the test coverage in combination with the\ntest that adds a final newline and one that leaves the missing newline\nin place.",
          "is_bot": false,
          "headline": "Add a test for removing the last newline in a file (#59)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-03-05T04:14:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fffa3cca9bd29785ec7f99ea6921de60e32a724a",
          "body": "Include file names in the header (now that we can actually parse them)\r\nand fix a bad find-and-replace that changed \"differ\" to \"fmer\". Add a\r\nnew test to verify that binary files without data format correctly.",
          "is_bot": false,
          "headline": "Fix binary headers in formatted patches (#56)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-01-08T03:35:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "14da3d30f70427ec8b41b66f944f364e2e6aff83",
          "body": "Some patches may include one or more file paths as part of the binary\r\nheader when there is no binary data. Git accounts for this by only\r\nchecking the prefix and suffix of the line, but I missed that logic when\r\nimplementing this originally.",
          "is_bot": false,
          "headline": "Parse binary headers with file paths (#55)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2025-01-08T03:27:03Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8584cd59afe0fd5af926a98ea3ef650fa4b1f952",
          "body": "This enables clients to move back and forth between parsed objects and\r\ntext patches. The generated patches are semantically equal to the parsed\r\nobject and should re-parse to the same object, but may not be\r\nbyte-for-byte identical to the original input.\r\n\r\nIn my testing, formatted text patches are\n[…]\nta to the same stream. This isn't exposed publicly right\r\nnow, but will be useful if there's a need for more flexible formatting\r\nfunctions in the future, like formatting to a user-provided io.Writer.",
          "is_bot": false,
          "headline": "Add String() methods to parsed types (#48)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-08-11T18:57:07Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "9e0997ef65150db9392595ab9f2a1df593d48d22",
          "body": "The minimum Go version for the package is now Go 1.21. This is because a\r\nfuture change will use the 'slices' package in test code. Note that non-test\r\ncode in the package should still be compatible with older versions of Go.\r\n\r\nAs part of this, also update the golangci-lint version to one that works\r\nwith Go 1.21, which required replacing some deprecated linters.",
          "is_bot": false,
          "headline": "Update Go and golangci-lint versions (#49)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-08-11T18:39:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0a4e55f9a190b500835e10d187ca4f88a96917e2",
          "body": "While empty patches with only a header were parsable, the parser\r\ndiscarded the preamble content. This meant callers had to handle this\r\ncase specially. Now, if we reach the end of the input without finding a\r\nfile, Parse() returns the full content of the patch as the preamble.",
          "is_bot": false,
          "headline": "Return preamble when a patch has no files (#46)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-07-15T03:44:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a00d2ccaf7332549eaa3af918b614ac73ee8c8e3",
          "body": "When GitHub creates patches for Dependabot PRs, it generates a \"From:\"\r\nline that is not valid according to RFC 5322: the address spec contains\r\nunquoted special characters (the \"[bot]\" in \"dependabot[bot]\"). While\r\nthe 'net/mail' parser makes some exceptions to the spec, this is not one\r\nof them, s\n[…]\n email address as the name\r\n   and drop any separate name component.\r\n\r\n2. When parsing mail-formatted patches, use ParsePatchIdentity to parse\r\n   the \"From:\" line instead of the 'net/mail' function.",
          "is_bot": false,
          "headline": "Follow git logic when parsing patch identities (#44)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-05-06T03:16:19Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "3f2ea5c16e0a9d685e1b91b6b8bfc0fbf4cb5d6a",
          "body": "Git is actually more lenient here than I thought. As long as the\r\nidentity contains the \"<>\" delimiters, Git will allow an empty email, so\r\nwe should accept the same thing. I also discovered that an identity with\r\nonly an email set will use the email as the name, so I've implemented\r\nthat behavior as well.",
          "is_bot": false,
          "headline": "Accept empty emails in ParsePatchIdentity (#42)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-03-07T05:32:38Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "13e8639a0b49cb49741b05f11ac52c530d2d38f0",
          "body": null,
          "is_bot": false,
          "headline": "Clarify that Parse expects a single patch",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2024-02-25T20:39:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "981bc4b60c4490e10d9f8ca8cfd7833e303c399e",
          "body": "If a patch is passed through a system that converts line endings to\r\n'\\r\\n', mode lines end up with trailing whitespace that confuses\r\nstrconv.ParseInt. In Git, this is avoided by using strtoul() for parsing,\r\nwhich stops at the first non-digit character.\r\n\r\nChanging line endings in patch content itself will cause other problems\r\nso it is best to avoid this transform, but if it does happen, it\r\nshouldn't cause a parse error.",
          "is_bot": false,
          "headline": "Fix parsing of mode lines with trailing space (#38)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-12-26T22:56:30Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1575e0c4ef9322a5685ff76bd40b53363a98799e",
          "body": null,
          "is_bot": false,
          "headline": "Remove warning about apply API changes",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-10-01T21:50:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "03daf96518a95647d85122e6d107ee63c0bc5b58",
          "body": "When processing mail-formatted patches, the default cleanup removed all\r\nleading content in square brackets, but this pattern is often used to\r\nidentify tickets or other information that should remain in the commit\r\ntitle. Git supports disabling this the the `-k` and `-b` flags, which we\r\nsimulate w\n[…]\ns that are (probably) part of\r\nthe actual commit message.\r\n\r\nNote that because of the mail parsing library, we cannot replicate the\r\n`-k` flag exactly and always clean leading and trailing whitespace.",
          "is_bot": false,
          "headline": "Add option to control patch subject cleaning (#36)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-10-01T21:47:39Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "dc43dbf8c7a47db0157e6261151531db188b3e3f",
          "body": "Use standard string functions instead of removing leading whitespace in\r\na custom loop. This also makes the distinction between the two types of\r\nmail header parsing a bit clearer.",
          "is_bot": false,
          "headline": "Slightly simplify patch header parsing (#34)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-10-01T05:43:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "071689e91f0247ca1fbd40fec4c955d7d5bfa713",
          "body": "The previous version of the golangci-lint action would install its own\r\nversion of Go, which eventually conflicted with the old pinned version\r\nof the linter I was using. Upgrade the action to avoid this, but also\r\nupdate Go and the linter while I'm here.",
          "is_bot": false,
          "headline": "Test with Go 1.19, upgrade golangci-lint (#35)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-10-01T05:41:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "75930390c9440405f4941e70e3897cb328afdc09",
          "body": "Remove the Applier type and replace it with TextApplier and\r\nBinaryApplier, both of which operate on fragments instead of on full\r\nfiles. Move the logic that previously existed in Applier.ApplyFile to\r\nthe top-level Apply function.\r\n\r\nAlso restructure arguments and methods to make it clear that appliers\r\nare one-time-use objects. The destination is now set when creating an\r\napplier and the Reset() method was replaced by Close().",
          "is_bot": false,
          "headline": "Split apply logic by fragment type (#32)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-03-20T19:20:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8764d8180fdd2a5100249b300011d61bb594c9cc",
          "body": null,
          "is_bot": false,
          "headline": "Add note about apply API changes to README",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2022-03-18T21:13:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "52645c60d0415a26817e7cdf90ca66b8806f46b9",
          "body": "Co-authored-by: Noah Goldstein <goldstein.w.n@gmail.com>",
          "is_bot": false,
          "headline": "Use ioutil for compatibility with older Go versions (#31)",
          "author_name": "goldsteinn",
          "author_login": "goldsteinn",
          "committed_at": "2022-02-28T02:32:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f23f745615837c8bc9804b790f1eb24a8042069c",
          "body": null,
          "is_bot": false,
          "headline": "Add note about fuzz testing to README",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-09-19T04:16:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4f540371d0aa2a79f0540bf654a591c8bc7adae6",
          "body": "This fixes two issues:\r\n\r\n  1. Fragments with only context lines were accepted\r\n  2. Fragments with only a \"no newline\" marker caused a panic\r\n\r\nThe panic was found by go-fuzz. While fixing that issue, I\r\ndiscovered the first problem with other types of empty fragments while\r\ncomparing behavior against 'git apply'.\r\n\r\nAlso extract some helper functions and modify the loop conditions to\r\nclean things up while making changes in this area.",
          "is_bot": false,
          "headline": "Return errors for empty text fragments (#29)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-09-12T22:51:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b6a90110a3bf32b68d27477c96f540a7fbfb536f",
          "body": "Found by go-fuzz.",
          "is_bot": false,
          "headline": "Fix out-of-bounds panic parsing timestamps (#28)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-09-09T18:24:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "53bcdf7e5d94b09bf31b6e2915a7aa51d1f50b36",
          "body": "If a file was an exact multiple of 1024 bytes (the size of an internal\r\nbuffer) and was missing a final newline, the LineReaderAt implementation\r\nwould drop the last line, leading to an unexpected EOF error on apply.\r\n\r\nIn addition to fixing the bug, slightly change the behavior of\r\nReadLineAt to re\n[…]\nt really\r\n     serve a purpose.\r\n\r\nThis is technically a breaking change for external implementations but\r\nan implementation that exactly followed the \"spec\" was already broken in\r\ncertain edge cases.",
          "is_bot": false,
          "headline": "Fix EOF error for some files without final newline (#27)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-08-20T00:32:18Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b5756546a116ebe3ba2be7f83d6c85803903d998",
          "body": null,
          "is_bot": false,
          "headline": "Decode quoted-printable UTF8 in email subjects (#25)",
          "author_name": "Javier Campanini",
          "author_login": "jmcampanini",
          "committed_at": "2021-07-19T18:45:58Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3772c9eb6544df2bf61020b86080961a3eab6844",
          "body": "Git does not quote file names containing spaces when generating header\r\nlines. However, I misread the Git implementation and thought it used\r\nspaces as a name terminator by default, implying that names with spaces\r\nwould be quoted.\r\n\r\nRewrite the the name parsing code to better match Git. Specifical\n[…]\n Also account for spaces in file\r\nnames when parsing file metadata.\r\n\r\nFinally, allow trailing spaces on file names, which seem to be allowed\r\nby Git (although this sounds like a terrible idea to me.)",
          "is_bot": false,
          "headline": "Fix parsing for file names with spaces (#24)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-04-24T22:23:31Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "b6666095cfbb3691e8fb77d597d099fc9373c08f",
          "body": null,
          "is_bot": false,
          "headline": "Remove deprecated actions commands (#22)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-03-19T21:47:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8cd57be48511a1fc996955051cc100e5f2de27d4",
          "body": null,
          "is_bot": false,
          "headline": "Update development status in README",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2021-02-19T21:09:28Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b846b2cee04a0ba5f87d41a59f0595789e092682",
          "body": "`git am` will accept patches which aren't fully RFC-compliant, as long\r\nas they start with `From` and have a `Subject` line. Relax\r\nParsePatchHeader() so that it will accept such patches as well.\r\n\r\nSpecifically, it will tolerate patches of the form:\r\n\r\n    From: <foo@company.com>\r\n\r\nIn this case, t\n[…]\n field will contain `foo@company.com\r\n<foo@company.com>`.  Duplicate this behavior.\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
          "is_bot": false,
          "headline": "Relax email header requirements (#20)",
          "author_name": "George Dunlap",
          "author_login": "gwd",
          "committed_at": "2020-10-31T23:00:50Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "1bd59c4f1123687f522447da120db26f61e787f2",
          "body": "...when parsing emails, similar to `git am`.\r\n\r\nAdd a new field, `BodyAppendix` to PatchHeader.\r\n\r\nModify `scanMessageBody` to accept a boolean argument saying whether\r\nto separate out the appendix or not.  Do this by keeping two string\r\nbuilders, and having it switch to the appendix builder when it\n[…]\n, but not a commit\r\nmessage.\r\n\r\nAdd some tests to verify that it works as expected.\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
          "is_bot": false,
          "headline": "Remove \"appendix\" information from commit message (#19)",
          "author_name": "George Dunlap",
          "author_login": "gwd",
          "committed_at": "2020-10-24T03:39:43Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "379b893435ec14b9317c0b3a1c8b34abc12f436e",
          "body": "Primarily to get rid of [PATCH] at the front, but while we're here\r\njust be generally compatible with `git am`:\r\n\r\n * Remove `re` and variations\r\n * Remove whitespace\r\n * Remove anything in brackets\r\n\r\nBut only at the very beginning of the subject.\r\n\r\nStore anything removed in this way in PatchHeade\n[…]\n\n\r\nInspired by\r\nhttps://github.com/git/git/blob/master/mailinfo.c:cleanup_subject()\r\n\r\nSigned-off-by: George Dunlap <george.dunlap@citrix.com>\r\nCo-authored-by: George Dunlap <george.dunlap@citrix.com>",
          "is_bot": false,
          "headline": "Remove email decorations from patch titles (#17)",
          "author_name": "George Dunlap",
          "author_login": "gwd",
          "committed_at": "2020-09-16T03:25:25Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "864dd3fb4f9b5ad65b19f6dfb59ca00b713f773e",
          "body": null,
          "is_bot": false,
          "headline": "Replace godoc.org badge with pkg.go.dev badge",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-09-13T04:43:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d3116e7b7ed5bb989c11f5274313853f292f88d9",
          "body": "Removed the distinction between parsed and raw dates and simply return\r\nan error for unsupported date formats. Arbitrary date support was\r\nprobably a premature optimization and would be better supported by a\r\nmethod to register custom date parsing functions.\r\n\r\nSimple time.Time fields make the structure easier to use and mean that\r\na zero value always indicates the patch did not include a date.",
          "is_bot": false,
          "headline": "Make patch date parsing simpler and stricter (#15)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-06-16T05:07:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3b83ad722ac956654c7c37906c8620ab5fc074d",
          "body": "A closer look at the Git source shows that the rfc2822 and default\r\nformats do not zero-pad days, so we need to accept single-digit days\r\nwhen parsing. The single-digit pattern will also accept the padded\r\nformat, so there's no loss of functionality.\r\n\r\nChange the parsing test to use single-digit values to emphasize when\r\npadding is required and when it is not.",
          "is_bot": false,
          "headline": "Allow unpadded days in patch headers (#14)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-06-11T04:34:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "4fa98017427b0c44e6beb259671560f4da2ea512",
          "body": "When applying a text fragment that deletes all content in the file, make\r\nsure there is no content left in the source after using all the lines in\r\nthe fragment. If there is is extra content, it's a conflict: something\r\nadded more lines to the file after generating the patch.",
          "is_bot": false,
          "headline": "Check for leftover content after a full delete (#9)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-05-03T20:39:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "b5ae0bd4434ae4510cd57155d61e60fc946879bf",
          "body": "Git usually refers to the whole thing (title + body) as the \"commit\r\nmessage\", so using different terms for the parts clarifies things. Also\r\nadd a new Message() function that returns the combined string.",
          "is_bot": false,
          "headline": "Rename PatchHeader.Message to .Body (#7)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-04-27T03:00:20Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "546a186b3920aef09b37078b3756e13ff8e3fd4d",
          "body": null,
          "is_bot": false,
          "headline": "Fix minor documentation issues",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-04-19T05:39:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5609b2d456190ab7c7dfb77b6245b09531001adf",
          "body": null,
          "is_bot": false,
          "headline": "Fix typo in comment",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-04-19T05:23:12Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f0da09b10f3d63c12111490105e5af7a76a7c26e",
          "body": "This function parses patch headers (the preamble returned by the\r\nexisting Parse function) to extract information about the commit that\r\ngenerated the patch. This is useful when patches are an interchange\r\nformat and this library is applying commits generated elsewhere.\r\n\r\nBecause of the variety of header formats, parsing is fairly lenient and\r\nbest-effort, although certain invalid input does cause errors.\r\n\r\nThis also extracts some test utilities from the apply tests for reuse.",
          "is_bot": false,
          "headline": "Add ParsePatchHeader and related types (#6)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-04-19T05:21:55Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c2035adeda6b63c67678ce0bccf1e8d0ec828a02",
          "body": null,
          "is_bot": false,
          "headline": "Add Apply convenience function to match Parse (#5)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-04-11T22:21:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "34ea1730662faa6b12e10b312fce1b17101d9908",
          "body": null,
          "is_bot": false,
          "headline": "Add apply example to README",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-02-01T21:30:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bedbab3f65436ca9e85e67ee9f6229b6128c2b37",
          "body": "Use golangci-lint to coordinate linting instead of installing tools\r\nindividually. The workflow installs the binary directly instead of using\r\none of the existing public actions.",
          "is_bot": false,
          "headline": "Use GitHub actions for testing and linting (#3)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-02-01T21:19:05Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "09f3004fce1ceb2ec686d644439c5135687d29bf",
          "body": "copyFrom and copyLinesFrom did not increment the start offset after\r\nreading, so the same lines were copied over and over again.",
          "is_bot": false,
          "headline": "Fix flushing when data is larger than the buffer (#2)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-02-01T18:58:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "bb5b8f69fda3a361dd8c75dca7d3a5f7662d6dab",
          "body": null,
          "is_bot": false,
          "headline": "Update README.md",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-28T06:55:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c979654ba5a25265fbc0189470f2b1ea78ba92d0",
          "body": null,
          "is_bot": false,
          "headline": "Update README with apply status",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-28T06:42:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "9fc14fddb0177442728a7154b8ba10aa125ac2bc",
          "body": "Also refactor the apply tests to use a common type now that there are\nthree variants that do almost the same thing for each test.",
          "is_bot": false,
          "headline": "Add tests for file-level application",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-28T06:35:13Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "19ec1a24b41791a03a9fae056a1a7eb9426a5e11",
          "body": "Applying a file now rejects future text fragment applies under the\nassumption that all relevant fragments were part of the file.",
          "is_bot": false,
          "headline": "Improve detection of in-progress application",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T23:02:42Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0f3872a5a4c234c851e41be371673d1d0436f1b2",
          "body": null,
          "is_bot": false,
          "headline": "Fix panic with empty input in LineReaderAt",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T21:37:09Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "fa88623500b0f12ae6c59f0207d3dcd08899a29d",
          "body": "Try to avoid confusion about whether variables refer to byte or line\ncounts/positions. It still isn't perfect, but I'm not sure how to\nfurther clarify without being overly verbose.",
          "is_bot": false,
          "headline": "Improve clarity of LineReaderAt implementation",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T06:27:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "206a57eb7a98a9e3907169f846dcf1b44c286259",
          "body": "This adds minimal new coverage, since the apply tests already exercise\nthis, but it's complicated enough that dedicated tests will be helpful.",
          "is_bot": false,
          "headline": "Add tests for LineReaderAt implementation",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T06:26:21Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "18058d1e151e780b7617d574c037b8a4e948816c",
          "body": "This removes the distinction between \"strict\" and \"fuzzy\" application\nby allowing future methods on Applier that control settings. It also\navoids state tracking in the text fragment apply signature by moving it\ninto the Applier type.\n\nWhile in practice, an Applier will be used once and discarded, the\ncapability is provided to reset it for multiple uses.",
          "is_bot": false,
          "headline": "Move apply methods to an Applier type",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T01:01:43Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3d1274d16e8feeec692cd6314f970a8a0ba1fb7d",
          "body": "This is no longer used for text application, so revert the parser back\nto using StringReader.",
          "is_bot": false,
          "headline": "Remove unused LineReader interface",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T00:57:23Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0b7af3feaad275c6be1e7af533bbf70f474d354a",
          "body": "This is functionally equivalent to the previous version (except for one\nerror case), but uses the new interface. I think the code is simpler\noverall because it removes the line tracking.",
          "is_bot": false,
          "headline": "Implement text application using LineReaderAt",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T00:56:33Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f3702115a63389c389b539e089b62c8115d2cdac",
          "body": "This is a line-oriented parallel to io.ReaderAt, meant for text applies.\nWhile the mapping isn't quite as clean as in the binary case, a text\napply still reads a fixed chunk of lines starting at a specific line\nnumber and modifies them. This also allows a consistent interface for\nstrict and fuzzy ap\n[…]\ns data in chunks,\nindexing line boundaries as it goes. This is probably not the most\nefficient way to implement this interface, but it works and allows file\napplication to take a consistent interface.",
          "is_bot": false,
          "headline": "Add LineReaderAt interface and implementation",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T00:56:32Z",
          "body_truncated": true,
          "is_coding_agent": false
        },
        {
          "oid": "131a046908d88466f69c7f6c29155c41826159ae",
          "body": "This better matches the actual contract of the delta patch, which reads\nfixed size chunks of the source files at arbitrary positions.",
          "is_bot": false,
          "headline": "Use io.ReaderAt to implement binary applies",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-26T00:48:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a34334d6ef2a4cb27da1d6e5fd6b1e642189f368",
          "body": "These cover some of the possible errors with delta fragments. Many of\nthe same tests could be implemented slightly easier by testing the\nhelper functions, but the infrastructure is already set up to test the\nfull function.\n\nThis is made easier by the bin.go CLI, which can parse and encode binary\npatch data. Once parsed, fragments were manipulated with truncate and\ndd, encoded, and placed in the patch files.",
          "is_bot": false,
          "headline": "Add error tests for BinaryFragment#Apply",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-17T06:43:56Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "194589f0011e57dcb6b07f8e7cc2abad0a05eab6",
          "body": "This ensures a default size is used for large copy instructions.",
          "is_bot": false,
          "headline": "Add test for large binary delta application",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-17T05:52:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "c50036a466abfec0293862e737ac176b58a9f991",
          "body": null,
          "is_bot": false,
          "headline": "Abstract common file loading in apply tests",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-17T05:52:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "79aa2a9a77ed453b27e3e3f51244a2b9cba0ca4a",
          "body": "Covers basic literal and delta application. Input files were created by\nusing dd and the 'conv=notrunc' option to modify sections of files\ncreated from /dev/urandom. All file start with two null bytes to\nconvince Git they are binary.",
          "is_bot": false,
          "headline": "Add positive tests for BinaryFragment#Apply",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-17T05:52:40Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1d21957e2c6d87b9b38290d5588ceb74a6a6335",
          "body": "Currently untested, but based on code I validated against some generated\npatches. Tests comming in a future commit.",
          "is_bot": false,
          "headline": "Implement binary fragment application",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-15T06:49:14Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "32887c7120ec446889df755e8175e9ea17d51a53",
          "body": "Tests now use errors.Is, a Go 1.13 feature.",
          "is_bot": false,
          "headline": "Update to Go 1.13 in go.mod",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-14T06:14:17Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "eb5f3de78cf0166f0c6cc2b5f1479667ddd6e230",
          "body": "Conflict errors are now represented by an exported type that is\ncompatible with errors.Is instead of using the method defined on\nApplyError. This makes the tests slightly cleaner and should be more\nidiomatic for clients.",
          "is_bot": false,
          "headline": "Improve conflict error detection",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-13T06:09:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1b341e06931ea0f2dbec738d04d7f7362a8bcee0",
          "body": "These cover the errors that can happen with a single fragment and no\nadditional manipulation by the caller of ApplyStrict.",
          "is_bot": false,
          "headline": "Add error tests for TextFragment#ApplyStrict",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-13T06:09:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "6a055aa600880e6fa43d3022e951a9b6aea29995",
          "body": "This ensures the line number is used and application isn't based only on\nmatching context lines.",
          "is_bot": false,
          "headline": "Add exact line test for TextFragment#ApplyStrict",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-13T06:08:15Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "774281f01b714f03d4a951d8e8baf391d30093b2",
          "body": "This matches the type used for positions in text fragments.",
          "is_bot": false,
          "headline": "Standardize on int64 for line numbers",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-10T06:11:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "7bd4e0bb0e868592a89659173e287c1656c0c6f1",
          "body": "io.EOF was not properly accounted for when dealing with patches that are\nmissing trailing newline characters.",
          "is_bot": false,
          "headline": "Fix EOF handling in TextFragment#ApplyStrict",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-10T06:05:24Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "02f7ff4f795c073809952e5fadd64d489d304dd0",
          "body": "These cover all of the cases (I think) where application should succeed.",
          "is_bot": false,
          "headline": "Add positive tests for TextFragment#ApplyStrict",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-09T07:04:44Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ae704236bb956be9202a2b9aa514f66325638b5e",
          "body": "This wraps the underlying error with optional position information and\nprovides a way to test if the error was due to a conflict. At the\nmoment, details about the conflict are not exposed outside of the\nmessage string.",
          "is_bot": false,
          "headline": "Return ApplyError when ApplyString fails",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-08T06:59:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "93d46e805c6e469c239d6cbb9b481b63f4a7d27e",
          "body": "Text fragment application is implemented but untested and with several\nTODOs, binary fragment application is unimplemented and will panic.",
          "is_bot": false,
          "headline": "Add initial pass at ApplyStrict functions",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-06T04:37:59Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "25bee8cf2fa8310deebe6fe6ebbf16bc83236abe",
          "body": "Applying a fragment requires the content to match the stored counts, so\nthere must be a way to check this. Parsed fragments should always be\nvalid, but manually created or modified fragments may be invalid.",
          "is_bot": false,
          "headline": "Add validation function for text fragment",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-06T04:36:01Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d471b7e1a3ed7e1c3074f0ce2fac7b1ab5d5b71d",
          "body": "When applying, we need to copy all data after the last fragment line.\nThis function provides a way to get back the possibly-buffered io.Reader\nthat backs the LineReader.",
          "is_bot": false,
          "headline": "Add internal function to unwrap LineReaders",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-05T07:32:16Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "3ec1c74c34ac0faed0e91f105ca6417b60be47b6",
          "body": "Document the method as part of the type so it is processed by godoc.",
          "is_bot": false,
          "headline": "Improve docs for StringReader and LineReader",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-05T04:03:00Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "a1f934e8520f5a84a6e4a79fc7990c9128570666",
          "body": "LineReader is a wrapper around StringReader that counts line numbers.\nThis is not currently used by the parser, but will be used by the apply\nfunctions.",
          "is_bot": false,
          "headline": "Add LineReader and StringReader interfaces",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2020-01-04T20:02:37Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "f65047b16578b268507c17b5fcbd36516d2edcad",
          "body": null,
          "is_bot": false,
          "headline": "Avoid buffering when reader supports ReadString",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-27T23:15:50Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "1c950ee8546936cd292c3e14a83602eaa132bd6a",
          "body": "The tests were already split up in this way, so it makes sense to have\nthe parsing functions split as well.",
          "is_bot": false,
          "headline": "Split source files by patch type (text/binary)",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-18T04:36:46Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d42fb0e93f544fbd87cf86ddbce5dd6c173d4ede",
          "body": null,
          "is_bot": false,
          "headline": "Fix spelling mistakes, add Go Report Card badge",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T02:53:39Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ef3359a9693a9bf9f0f3b01b2cef1d4c91e79d17",
          "body": null,
          "is_bot": false,
          "headline": "Add a package-level documentation comment",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T02:44:06Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "37fcc9a950fc67b28ccf2c37c0cb63e6cc3fff75",
          "body": null,
          "is_bot": false,
          "headline": "Update status and add example in README",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T02:35:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "31777bd4b50c8c918e27a3aeac3614df9f328a8a",
          "body": null,
          "is_bot": false,
          "headline": "Add parser advancement tests for binary parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T02:27:34Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "16539ad031a615bb7e31a0dae0ce9cb6a38eaf60",
          "body": null,
          "is_bot": false,
          "headline": "Add tests for parsing full binary fragments",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T02:18:08Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "d104a6c22ab0ec7ab96064205873094beaac2a99",
          "body": null,
          "is_bot": false,
          "headline": "Add error case tests for binary chunk parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-15T00:10:35Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "62569e0d07695333b7bc1cfe12e2bbe961ac035e",
          "body": "These are fairly basic as the decoder is also exercised by the fragment\nparsing tests, but they cover some errror cases that may not be covered\notherwise.",
          "is_bot": false,
          "headline": "Add dedicated tests for base85 decoding",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-14T22:50:07Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "8ce8cba533b0f680f66b763fbe02836ef6557ce6",
          "body": "Git uses a unique Base85 encoding with different characters than the\nascii85 encoding implemented by Go, so add a custom decoding function.\nOnce decoded, use zlib instead of the raw DEFLATE algorithm to\ndecompress the data.\n\nThese issues were caught by some basic parsing tests which are added\nhere as well.",
          "is_bot": false,
          "headline": "Fix binary chunk decoding and inflating",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-14T05:32:25Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "22fb5076be8429672f3d4d86bac3aad3df001455",
          "body": null,
          "is_bot": false,
          "headline": "Add test for binary fragment header parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-13T22:54:52Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "ddafbc8ba3335c4c188835f90863de055ebb1f84",
          "body": "Parse the fragment header separately from the fragment chunk, which\nmakes each function a bit more understandable.",
          "is_bot": false,
          "headline": "Split up binary parsing to match text parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-11T06:03:19Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "0cfd720d4f475df383ae7ed66377d1b9e6f14c72",
          "body": null,
          "is_bot": false,
          "headline": "Add test for binary marker parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-11T06:02:48Z",
          "body_truncated": false,
          "is_coding_agent": false
        },
        {
          "oid": "5a521ed05f62a91cac9c231deb86d8aad617f919",
          "body": "Parse forward and optionally reverse fragments, decoding and inflating\nthe ascii85 encoded data in a binary patch. This is completely untested\nat the moment and probably has obvious and stupid bugs.",
          "is_bot": false,
          "headline": "Implement binary fragment parsing",
          "author_name": "Billy Keyes",
          "author_login": "bluekeyes",
          "committed_at": "2019-04-10T05:54:41Z",
          "body_truncated": false,
          "is_coding_agent": false
        }
      ],
      "releases_count": 18,
      "commits_last_year": 14,
      "latest_release_at": "2026-07-18T21:59:23Z",
      "latest_release_tag": "v0.9.0",
      "releases_from_tags": false,
      "days_since_last_push": 4,
      "active_weeks_last_year": 7,
      "days_since_latest_release": 6,
      "mean_days_between_releases": 199.3
    },
    "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": [
        {
          "name": "github.com/bluekeyes/go-gitdiff",
          "exists": true,
          "license": null,
          "keywords": [],
          "ecosystem": "go",
          "matches_repo": true,
          "registry_url": "https://pkg.go.dev/github.com/bluekeyes/go-gitdiff",
          "is_deprecated": false,
          "latest_version": "v0.9.0",
          "repository_url": "https://github.com/bluekeyes/go-gitdiff",
          "versions_count": 18,
          "total_downloads": null,
          "dependents_count": null,
          "deprecation_note": null,
          "maintainers_count": null,
          "monthly_downloads": null,
          "first_published_at": null,
          "latest_published_at": "2026-07-18T18:51:55Z",
          "latest_version_yanked": null,
          "days_since_latest_publish": 6
        }
      ]
    },
    "popularity": {
      "forks": 28,
      "stars": 151,
      "watchers": 1,
      "fork_history": {
        "days": [
          {
            "date": "2019-11-01",
            "count": 1
          },
          {
            "date": "2020-07-10",
            "count": 1
          },
          {
            "date": "2020-09-11",
            "count": 1
          },
          {
            "date": "2021-03-04",
            "count": 1
          },
          {
            "date": "2021-10-19",
            "count": 1
          },
          {
            "date": "2022-02-26",
            "count": 1
          },
          {
            "date": "2022-05-23",
            "count": 1
          },
          {
            "date": "2023-05-14",
            "count": 1
          },
          {
            "date": "2023-07-06",
            "count": 1
          },
          {
            "date": "2023-07-19",
            "count": 1
          },
          {
            "date": "2024-08-21",
            "count": 1
          },
          {
            "date": "2025-01-01",
            "count": 1
          },
          {
            "date": "2025-01-07",
            "count": 1
          },
          {
            "date": "2025-03-04",
            "count": 1
          },
          {
            "date": "2025-05-05",
            "count": 1
          },
          {
            "date": "2026-01-11",
            "count": 1
          },
          {
            "date": "2026-01-22",
            "count": 1
          },
          {
            "date": "2026-05-08",
            "count": 1
          },
          {
            "date": "2026-07-16",
            "count": 1
          }
        ],
        "complete": true,
        "collected": 19,
        "total_forks": 28
      },
      "star_history": null,
      "open_issues_and_prs": 5
    },
    "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": [
        "go.mod"
      ],
      "largest_source_bytes": 16904,
      "source_files_sampled": 30,
      "oversized_source_files": 0,
      "agent_instruction_files": [],
      "agent_instruction_max_bytes": null
    },
    "dependencies": {
      "manifests": [
        "go.mod"
      ],
      "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": [
        "go"
      ],
      "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": 46,
        "open_issues": 5,
        "closed_ratio": 0.828,
        "closed_issues": 24,
        "closed_unmerged_prs": 4
      },
      "bus_factor": 1,
      "bot_contributors": 1,
      "top_contributors": [
        {
          "type": "User",
          "login": "bluekeyes",
          "commits": 145,
          "avatar_url": "https://avatars.githubusercontent.com/u/1745813?v=4"
        },
        {
          "type": "User",
          "login": "gwd",
          "commits": 3,
          "avatar_url": "https://avatars.githubusercontent.com/u/1247773?v=4"
        },
        {
          "type": "User",
          "login": "jmcampanini",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/316848?v=4"
        },
        {
          "type": "User",
          "login": "goldsteinn",
          "commits": 1,
          "avatar_url": "https://avatars.githubusercontent.com/u/35538541?v=4"
        }
      ],
      "contributors_sampled": 4,
      "top_contributor_share": 0.967
    },
    "quality_signals": {
      "has_ci": true,
      "has_tests": true,
      "ci_workflows": [
        "go.yml"
      ],
      "has_docs_dir": false,
      "linter_configs": [
        ".golangci.yml"
      ],
      "has_editorconfig": false,
      "has_linter_config": true,
      "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": null,
            "reason": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#branch-protection"
          },
          {
            "name": "CI-Tests",
            "score": 5,
            "reason": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
            "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/25 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": 10,
            "reason": "no dangerous workflow patterns detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dangerous-workflow"
          },
          {
            "name": "Dependency-Update-Tool",
            "score": 10,
            "reason": "update tool detected",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#dependency-update-tool"
          },
          {
            "name": "Fuzzing",
            "score": 10,
            "reason": "project is 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": "13 commit(s) and 1 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": 10,
            "reason": "all dependencies are pinned",
            "documentation_url": "https://github.com/ossf/scorecard/blob/c395761df6afe1a69e476bc60a013a94bcbc153f/docs/checks.md#pinned-dependencies"
          },
          {
            "name": "SAST",
            "score": 0,
            "reason": "SAST tool is not run on all commits -- score normalized to 0",
            "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": 0,
            "reason": "detected GitHub workflow tokens with excessive permissions",
            "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": "0927b543c7730d28b21ceef164fd0ed7a6a53f93",
        "ran_at": "2026-07-25T04:27:11Z",
        "aggregate_score": 6.3,
        "scorecard_version": "v5.5.0"
      },
      "has_codeql_workflow": false,
      "has_security_policy": false,
      "has_dependabot_config": true
    },
    "contribution_flow": {
      "collected": true,
      "ci_last_run_at": "2026-07-20T13:04:38Z",
      "oldest_open_prs": [],
      "last_merged_pr_at": "2026-07-20T13:04:14Z",
      "ci_last_conclusion": "SUCCESS",
      "oldest_open_issues": [
        {
          "number": 10,
          "created_at": "2020-05-03T20:23:58Z",
          "last_comment_at": "2022-01-24T06:47:37Z",
          "last_comment_author": "bluekeyes"
        },
        {
          "number": 12,
          "created_at": "2020-05-04T04:50:02Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 26,
          "created_at": "2021-07-19T18:48:30Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 30,
          "created_at": "2021-10-25T00:32:19Z",
          "last_comment_at": null,
          "last_comment_author": null
        },
        {
          "number": 65,
          "created_at": "2026-01-15T05:02:31Z",
          "last_comment_at": "2026-01-16T00:30:04Z",
          "last_comment_author": "bluekeyes"
        }
      ]
    }
  },
  "config": {
    "disabled_metrics": [],
    "disabled_categories": [],
    "disabled_components": {}
  },
  "source": {
    "url": "https://github.com/bluekeyes/go-gitdiff",
    "host": "github.com",
    "name": "go-gitdiff",
    "owner": "bluekeyes"
  },
  "metrics": {
    "overall": {
      "key": "overall",
      "band": "moderate",
      "name": "Overall health",
      "note": null,
      "notes": [],
      "value": 61,
      "inputs": {
        "security": 63,
        "vitality": 70,
        "community": 48,
        "governance": 58,
        "engineering": 64
      },
      "components": []
    },
    "categories": [
      {
        "key": "vitality",
        "band": "good",
        "name": "Vitality",
        "value": 70,
        "weight": 0.22,
        "metrics": [
          {
            "key": "development_activity",
            "band": "moderate",
            "name": "Development activity",
            "note": null,
            "notes": [],
            "value": 61,
            "inputs": {
              "commits_last_year": 14,
              "human_commit_share": 0.95,
              "days_since_last_push": 4,
              "active_weeks_last_year": 7
            },
            "components": [
              {
                "key": "push_recency",
                "name": "Push recency",
                "detail": "last push 4 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "push_recency",
                    "params": {
                      "days": 4
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_cadence",
                "name": "Commit cadence",
                "detail": "7/52 weeks with commits",
                "points": 4.8,
                "status": "partial",
                "details": [
                  {
                    "code": "commit_cadence_weeks",
                    "params": {
                      "weeks": 7
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "commit_volume",
                "name": "Commit volume",
                "detail": "14 commits in the last year",
                "points": 10.6,
                "status": "partial",
                "details": [
                  {
                    "code": "commits_last_year",
                    "params": {
                      "count": 14
                    }
                  }
                ],
                "max_points": 18
              },
              {
                "key": "openssf_scorecard_maintained",
                "name": "OpenSSF Scorecard: Maintained",
                "detail": "13 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 10",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "release_discipline",
            "band": "good",
            "name": "Release discipline",
            "note": "Excluded from scoring (no data or not applicable): OpenSSF Scorecard: Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "openssf_scorecard_signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 84,
            "inputs": {
              "releases_count": 18,
              "latest_release_tag": "v0.9.0",
              "releases_from_tags": false,
              "days_since_latest_release": 6,
              "mean_days_between_releases": 199.3
            },
            "components": [
              {
                "key": "ships_releases",
                "name": "Ships releases",
                "detail": "18 releases published",
                "points": 27,
                "status": "met",
                "details": [
                  {
                    "code": "releases_published",
                    "params": {
                      "count": 18
                    }
                  }
                ],
                "max_points": 27
              },
              {
                "key": "release_recency",
                "name": "Release recency",
                "detail": "latest release 6 days ago",
                "points": 36,
                "status": "met",
                "details": [
                  {
                    "code": "release_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 36
              },
              {
                "key": "release_cadence",
                "name": "Release cadence",
                "detail": "a release every ~199.3 days",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "release_cadence",
                    "params": {
                      "gap": 199.3
                    }
                  }
                ],
                "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": 6,
              "days_since_last_human_commit_is_floor": false
            },
            "components": [
              {
                "key": "project_is_still_maintained",
                "name": "Project is still maintained",
                "detail": "last human commit 6 days ago",
                "points": 100,
                "status": "met",
                "details": [
                  {
                    "code": "abandonment_maintained",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 100
              }
            ]
          }
        ],
        "description": "Is the project alive — is code being written and are releases shipping?"
      },
      {
        "key": "community",
        "band": "at_risk",
        "name": "Community & Adoption",
        "value": 48,
        "weight": 0.18,
        "metrics": [
          {
            "key": "popularity",
            "band": "at_risk",
            "name": "Popularity & adoption",
            "note": null,
            "notes": [],
            "value": 47,
            "inputs": {
              "forks": 28,
              "stars": 151,
              "watchers": 1,
              "growth_state": "unverified",
              "growth_factor_pct": 100,
              "growth_unverified_reason": "no_history"
            },
            "components": [
              {
                "key": "stars",
                "name": "Stars",
                "detail": "151 stars",
                "points": 35.3,
                "status": "partial",
                "details": [
                  {
                    "code": "stars",
                    "params": {
                      "count": 151
                    }
                  }
                ],
                "max_points": 60
              },
              {
                "key": "forks",
                "name": "Forks",
                "detail": "28 forks",
                "points": 11.9,
                "status": "partial",
                "details": [
                  {
                    "code": "forks",
                    "params": {
                      "count": 28
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "watchers",
                "name": "Watchers",
                "detail": "1 watchers",
                "points": 0,
                "status": "missed",
                "details": [
                  {
                    "code": "watchers",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": "moderate",
        "name": "Sustainability & Governance",
        "value": 58,
        "weight": 0.24,
        "metrics": [
          {
            "key": "maintainer_resilience",
            "band": "critical",
            "name": "Maintainer resilience (bus factor)",
            "note": null,
            "notes": [],
            "value": 15,
            "inputs": {
              "bus_factor": 1,
              "contributors_sampled": 4,
              "top_contributor_share": 0.967
            },
            "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 97% of commits",
                "points": 0.7,
                "status": "partial",
                "details": [
                  {
                    "code": "top_contributor_share",
                    "params": {
                      "share": 97
                    }
                  }
                ],
                "max_points": 22.5
              },
              {
                "key": "contributor_breadth",
                "name": "Contributor breadth",
                "detail": "4 contributors",
                "points": 5.4,
                "status": "partial",
                "details": [
                  {
                    "code": "contributors_sampled",
                    "params": {
                      "count": 4
                    }
                  }
                ],
                "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": "good",
            "name": "Issue & PR responsiveness",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "merged_prs": 46,
              "open_issues": 5,
              "closed_issues": 24,
              "issue_closed_ratio": 0.828,
              "closed_unmerged_prs": 4
            },
            "components": [
              {
                "key": "issue_resolution",
                "name": "Issue resolution",
                "detail": "83% of issues closed",
                "points": 38.7,
                "status": "partial",
                "details": [
                  {
                    "code": "issues_closed_share",
                    "params": {
                      "share": 83
                    }
                  }
                ],
                "max_points": 46.75
              },
              {
                "key": "pr_acceptance",
                "name": "PR acceptance",
                "detail": "46/50 decided PRs merged",
                "points": 35.2,
                "status": "partial",
                "details": [
                  {
                    "code": "decided_prs_merged",
                    "params": {
                      "merged": 46,
                      "decided": 50
                    }
                  }
                ],
                "max_points": 38.25
              },
              {
                "key": "openssf_scorecard_code_review",
                "name": "OpenSSF Scorecard: Code-Review",
                "detail": "Found 0/25 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": 59,
            "inputs": {
              "followers": 93,
              "owner_type": "User",
              "is_verified": null,
              "owner_login": "bluekeyes",
              "public_repos": 34,
              "account_age_days": 5182
            },
            "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": "93 followers of bluekeyes",
                "points": 14.2,
                "status": "partial",
                "details": [
                  {
                    "code": "owner_followers",
                    "params": {
                      "count": 93,
                      "login": "bluekeyes"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "track_record",
                "name": "Track record",
                "detail": "34 public repos, account ~14 yr old",
                "points": 23.2,
                "status": "partial",
                "details": [
                  {
                    "code": "public_repos",
                    "params": {
                      "count": 34
                    }
                  },
                  {
                    "code": "account_age_years",
                    "params": {
                      "years": 14
                    }
                  }
                ],
                "max_points": 25
              }
            ]
          },
          {
            "key": "package_maintenance",
            "band": "excellent",
            "name": "Package maintenance",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "packages": [
                "github.com/bluekeyes/go-gitdiff"
              ],
              "ecosystems": "go",
              "any_deprecated": false,
              "min_days_since_publish": 6
            },
            "components": [
              {
                "key": "published_resolvable",
                "name": "Published & resolvable",
                "detail": "1 package(s) on go",
                "points": 25,
                "status": "met",
                "details": [
                  {
                    "code": "packages_published",
                    "params": {
                      "count": 1,
                      "ecosystems": "go"
                    }
                  }
                ],
                "max_points": 25
              },
              {
                "key": "publish_recency",
                "name": "Publish recency",
                "detail": "latest publish 6 days ago",
                "points": 35,
                "status": "met",
                "details": [
                  {
                    "code": "publish_recency",
                    "params": {
                      "days": 6
                    }
                  }
                ],
                "max_points": 35
              },
              {
                "key": "version_history",
                "name": "Version history",
                "detail": "18 published versions",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "published_versions",
                    "params": {
                      "count": 18
                    }
                  }
                ],
                "max_points": 20
              },
              {
                "key": "not_deprecated",
                "name": "Not deprecated",
                "detail": "active, not deprecated or yanked",
                "points": 20,
                "status": "met",
                "details": [
                  {
                    "code": "package_not_deprecated",
                    "params": {}
                  }
                ],
                "max_points": 20
              }
            ]
          }
        ],
        "description": "Will the project survive its people — bus factor, responsiveness, who backs it, and package upkeep?"
      },
      {
        "key": "engineering",
        "band": "moderate",
        "name": "Engineering Quality",
        "value": 64,
        "weight": 0.2,
        "metrics": [
          {
            "key": "engineering_practices",
            "band": "good",
            "name": "Engineering practices",
            "note": null,
            "notes": [],
            "value": 74,
            "inputs": {
              "has_ci": true,
              "has_tests": true,
              "has_editorconfig": false,
              "has_linter_config": true,
              "has_precommit_config": false
            },
            "components": [
              {
                "key": "ci_workflows",
                "name": "CI workflows",
                "detail": "1 workflow(s)",
                "points": 24,
                "status": "met",
                "details": [
                  {
                    "code": "ci_workflows",
                    "params": {
                      "count": 1
                    }
                  }
                ],
                "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": ".golangci.yml",
                "points": 16,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "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": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
                "points": 10,
                "status": "partial",
                "details": [],
                "max_points": 20
              }
            ]
          },
          {
            "key": "documentation",
            "band": "moderate",
            "name": "Documentation",
            "note": null,
            "notes": [],
            "value": 50,
            "inputs": {
              "topics": [
                "golang",
                "git",
                "diff",
                "patch",
                "gitdiff"
              ],
              "has_wiki": false,
              "homepage": null,
              "has_readme": true,
              "has_docs_dir": false,
              "has_description": true
            },
            "components": [
              {
                "key": "readme",
                "name": "README",
                "detail": null,
                "points": 30,
                "status": "met",
                "details": [],
                "max_points": 30
              },
              {
                "key": "documentation_directory",
                "name": "Documentation directory",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 25
              },
              {
                "key": "documentation_homepage_site",
                "name": "Documentation / homepage site",
                "detail": null,
                "points": 0,
                "status": "missed",
                "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": "5 topics",
                "points": 10,
                "status": "met",
                "details": [
                  {
                    "code": "topics_count",
                    "params": {
                      "count": 5
                    }
                  }
                ],
                "max_points": 10
              },
              {
                "key": "wiki",
                "name": "Wiki",
                "detail": null,
                "points": 0,
                "status": "missed",
                "details": [],
                "max_points": 10
              }
            ]
          }
        ],
        "description": "Are baseline engineering and documentation practices in place?"
      },
      {
        "key": "security",
        "band": "moderate",
        "name": "Security",
        "value": 63,
        "weight": 0.16,
        "metrics": [
          {
            "key": "security_posture",
            "band": "moderate",
            "name": "Security posture",
            "note": "Excluded from scoring (no data or not applicable): Branch-Protection, Packaging, Signed-Releases. Remaining weights renormalized.",
            "notes": [
              {
                "code": "excluded_no_data",
                "params": {
                  "components": [
                    "branch_protection",
                    "packaging",
                    "signed_releases"
                  ]
                }
              },
              {
                "code": "weights_renormalized",
                "params": {}
              }
            ],
            "value": 63,
            "inputs": {
              "source": "openssf_scorecard",
              "checks_evaluated": 15,
              "scorecard_version": "v5.5.0",
              "checks_inconclusive": 3,
              "scorecard_aggregate": 6.3
            },
            "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": "internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md",
                "points": 0,
                "status": "excluded",
                "details": [
                  {
                    "code": "no_data",
                    "params": {}
                  }
                ],
                "max_points": 7.5
              },
              {
                "key": "ci_tests",
                "name": "CI-Tests",
                "detail": "14 out of 27 merged PRs checked by a CI test -- score normalized to 5",
                "points": 1.2,
                "status": "partial",
                "details": [],
                "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/25 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 dangerous workflow patterns detected",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              },
              {
                "key": "dependency_update_tool",
                "name": "Dependency-Update-Tool",
                "detail": "update tool detected",
                "points": 7.5,
                "status": "met",
                "details": [],
                "max_points": 7.5
              },
              {
                "key": "fuzzing",
                "name": "Fuzzing",
                "detail": "project is fuzzed",
                "points": 5,
                "status": "met",
                "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": "13 commit(s) and 1 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": "all dependencies are pinned",
                "points": 5,
                "status": "met",
                "details": [],
                "max_points": 5
              },
              {
                "key": "sast",
                "name": "SAST",
                "detail": "SAST tool is not run on all commits -- score normalized to 0",
                "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": "detected GitHub workflow tokens with excessive permissions",
                "points": 0,
                "status": "missed",
                "details": [],
                "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": 3
            },
            "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": "moderate",
        "name": "AI Readiness",
        "value": 66,
        "weight": 0,
        "metrics": [
          {
            "key": "ai_agent_context",
            "band": "at_risk",
            "name": "Agent context & guidance",
            "note": null,
            "notes": [],
            "value": 38,
            "inputs": {
              "has_llms_txt": false,
              "legible_history_share": 0.716,
              "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": "68 of 95 human commits state their intent (structured subject or explanatory body)",
                "points": 38.2,
                "status": "partial",
                "details": [
                  {
                    "code": "legible_history",
                    "params": {
                      "legible": 68,
                      "sampled": 95
                    }
                  }
                ],
                "max_points": 40
              }
            ]
          },
          {
            "key": "ai_verify_loop",
            "band": "good",
            "name": "Verify loop (build / test / typecheck)",
            "note": null,
            "notes": [],
            "value": 75,
            "inputs": {
              "has_nix": false,
              "has_tests": true,
              "lockfiles": [],
              "has_dockerfile": false,
              "typed_language": true,
              "bootstrap_files": [],
              "has_devcontainer": false,
              "has_linter_config": true,
              "typecheck_configs": [],
              "agent_commit_share": 0,
              "toolchain_manifests": [
                "go.mod"
              ],
              "dependency_bot_commit_share": 0.05
            },
            "components": [
              {
                "key": "one_command_bootstrap",
                "name": "One-command bootstrap",
                "detail": "go.mod (toolchain convention, no task runner)",
                "points": 12.6,
                "status": "partial",
                "details": [
                  {
                    "code": "toolchain_convention",
                    "params": {
                      "files": "go.mod"
                    }
                  }
                ],
                "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": ".golangci.yml",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "file_list",
                    "params": {
                      "files": ".golangci.yml"
                    }
                  }
                ],
                "max_points": 11
              },
              {
                "key": "static_type_checking",
                "name": "Static type checking",
                "detail": "Go (statically typed)",
                "points": 11,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "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": "5 of the last 100 commits are automated dependency updates",
                "points": 8,
                "status": "met",
                "details": [
                  {
                    "code": "dependency_bot_commits",
                    "params": {
                      "count": 5,
                      "sampled": 100
                    }
                  }
                ],
                "max_points": 8
              },
              {
                "key": "openssf_scorecard_pinned_dependencies",
                "name": "OpenSSF Scorecard: Pinned-Dependencies",
                "detail": "all dependencies are pinned",
                "points": 10,
                "status": "met",
                "details": [],
                "max_points": 10
              }
            ]
          },
          {
            "key": "ai_code_legibility",
            "band": "excellent",
            "name": "Code legibility for models",
            "note": null,
            "notes": [],
            "value": 100,
            "inputs": {
              "primary_language": "Go",
              "largest_source_bytes": 16904,
              "source_files_sampled": 30,
              "oversized_source_files": 0
            },
            "components": [
              {
                "key": "type_checkable_code",
                "name": "Type-checkable code",
                "detail": "Go (statically typed)",
                "points": 45,
                "status": "met",
                "details": [
                  {
                    "code": "statically_typed_language",
                    "params": {
                      "language": "Go"
                    }
                  }
                ],
                "max_points": 45
              },
              {
                "key": "manageable_file_sizes",
                "name": "Manageable file sizes",
                "detail": "0/30 source files over 60KB",
                "points": 55,
                "status": "met",
                "details": [
                  {
                    "code": "oversized_source_files",
                    "params": {
                      "kb": 60,
                      "sampled": 30,
                      "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-25T04:27:26.138221Z",
  "schema_version": "0.27.0",
  "badge_url": "https://raw.githubusercontent.com/inspect-software/badges/main/v1/b/bluekeyes/go-gitdiff.svg",
  "full_name": "bluekeyes/go-gitdiff",
  "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 statisticsGo.