Repository navigation
Releases: smusali/checkOwners
Releases · smusali/checkOwners
Release list
v0.7.0
What's Changed
- feat(B9): cache pip and analysis state between runs by @smusali in #168
- feat(C2): compute concentration before owner truncation by @smusali in #169
- feat(C3): report criticality-weighted knowledge risk by @smusali in #170
- feat(C4): show knowledge loss after a departure by @smusali in #171
- feat(C8): adapt recency half-life to path cadence by @smusali in #172
- feat(D4): credit co-authors and report merge strategy by @smusali in #173
- feat(E10): add composite knowledge-risk scoring by @smusali in #174
- feat(E12): open a reconciliation pull request by default by @smusali in #175
- chore(deps): bump the github-actions group with 2 updates by @dependabot[bot] in #176
- feat(F4): let teams choose which findings block by @smusali in #177
- feat(G2): stop treating commits as review load by @smusali in #178
- chore(deps): bump the github-actions group with 4 updates by @dependabot[bot] in #179
- fix(G3): separate historical activity from ownership score by @smusali in #180
- chore(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #181
- docs: move planning from repository files to the issue tracker by @smusali in #191
- feat(G6): sample ownership reviews by lookback days by @smusali in #192
- ci(H6): run tests on macOS, Windows, and older Git by @smusali in #194
- feat(J1): replay ownership from a stored baseline by @smusali in #195
- feat(E5): keep manual blocks and print a dry fix plan by @smusali in #196
- feat(report): add SARIF, checks, and diff-scoped review by @smusali in #198
- ci(fuzz): score mutations and stabilize path globs by @smusali in #199
- chore(deps): bump the github-actions group with 7 updates by @dependabot[bot] in #200
- feat(identity): resolve owners and record contributor status by @smusali in #202
- feat(graph): add ownership exports, Louvain, and onboarding by @smusali in #203
- feat: add checkowners audit as the default command by @smusali in #204
- feat(analyze): follow renames, cache blame, score survival by @smusali in #205
- feat(validation): measure scores against later maintainers by @smusali in #206
- ci(fuzz): skip coverage on the nightly pattern run by @smusali in #207
- feat(library): add evidence replay and forge dialects by @smusali in #209
- docs: add a versioned site and project governance by @smusali in #210
- refactor: pre-v0.7.0 cleanup of the research layer, versioning, and layout by @smusali in #213
- chore(release): pin 0.7.0 across package, Action, and changelog by @smusali in #214
Full Changelog: v0.6.0...v0.7.0
v0.6.0
What's Changed
- feat(B7): collapse Action CI onto github-action by @smusali in #134
- fix(C5): keep ownership scores comparable across modes by @smusali in #135
- feat(C6): treat commit count as evidence not eligibility by @smusali in #136
- fix(C7): pin recency to HEAD instead of wall clock by @smusali in #137
- feat(D1): apply ignore-revs and standard blame flags by @smusali in #138
- feat(D2): honor .mailmap as first identity stage by @smusali in #139
- feat(D5): honor .gitattributes linguist exclusions by @smusali in #140
- feat(E3): verify round-trip, size-guard, add explain-path by @smusali in #141
- fix(E4): refuse lossy bracket-path wildcard consolidation by @smusali in #143
- feat(E8): add explain and owners path interrogation by @smusali in #144
- chore(deps): bump codecov/codecov-action from 5.5.5 to 7.1.1 in the github-actions group by @dependabot[bot] in #142
- feat(E11): add ratchet and reason-required suppressions by @smusali in #145
- feat(F1): version scoring models and config schema by @smusali in #146
- feat(F2): publish schema 1.0 for command output by @smusali in #147
- feat(F3): share one exit-code contract across commands by @smusali in #148
- feat(F5): stop treating missing evidence as a complete run by @smusali in #149
- feat(F6): add a staleness contract and atomic cache writes by @smusali in #150
- refactor(G7): remove the drift webhook notifier by @smusali in #151
- test(H1): catch ownership bugs mocks cannot see by @smusali in #152
- test(H2): publish CODEOWNERS corpus and fuzz checks by @smusali in #153
- test(H3): add golden tests for ownership beliefs by @smusali in #154
- feat(I1): add report privacy modes and email tokens by @smusali in #155
- feat(I2): publish the non-performance disclaimer by @smusali in #156
- feat(I3): add Scorecard, audits, and release SBOM by @smusali in #157
- chore(deps): bump the github-actions group with 3 updates by @dependabot[bot] in #158
- feat(K1): expose checkowners as pre-commit hooks by @smusali in #159
- docs(L1): lead with a real ownership drift example by @smusali in #160
- docs(L3): publish limits and project principles by @smusali in #161
- refactor(action): extract install script and rename drift output by @smusali in #162
- refactor(versions)!: reset public contracts to v1 by @smusali in #163
- refactor(analyze): publish helpers and drop duplicate tests by @smusali in #164
- docs: add a glossary and shorten the landing copy by @smusali in #165
- chore(release): pin 0.6.0 across package, Action, and changelog by @smusali in #166
Full Changelog: v0.5.1...v0.6.0
v0.5.1
What's Changed
- docs: unified project state, problem, and solution register by @smusali in #9
- fix(A1): point project URLs at smusali/checkowners by @smusali in #104
- fix(A2): make README links absolute for PyPI by @smusali in #105
- fix(A4): date changelog headings by PyPI day and guard tags by @smusali in #106
- fix(B1): pass GITHUB_TOKEN to CLI steps in CI by @smusali in #107
- fix(B2): pin package install to the Action tag by @smusali in #108
- ci(B3): pin third-party uses to commit SHAs by @smusali in #109
- chore(deps): bump the github-actions group with 5 updates by @dependabot[bot] in #110
- fix(B4): fail-soft PR comments and always write job summary by @smusali in #111
- fix(B5): bound GITHUB_OUTPUT summaries and upload artifacts by @smusali in #112
- fix(B6): paginate PR comment lookup and escape Markdown by @smusali in #113
- fix(B8): unify drift.mode default and Action state dir by @smusali in #114
- fix(C1): name capped owner count as qualified-owners by @smusali in #115
- ci(H5): enforce 85% floor, expand ruff, publish badge by @smusali in #116
- chore(K2): compose extras, lock CI, and add Python 3.14 by @smusali in #117
- docs(L2): drop first-claim and credit competitors honestly by @smusali in #118
- docs(N1): add community on-ramp for outside contributors by @smusali in #129
- chore(A3, v0.5.1): pin 0.5.1 and document the release cut by @smusali in #130
- fix(action): fix the description length by @smusali in #131
New Contributors
- @dependabot[bot] made their first contribution in #110
Full Changelog: v0.5.0...v0.5.1
v0.5.0
[0.5.0] - 2026-07-03
Hardening release driven by testing every command against a real production monorepo (24k commits, 12k active files). Focus: correct CODEOWNERS semantics, analyze performance, per-repo state isolation, and identity resolution.
Added
- CODEOWNERS pattern matching engine (
checkowners/patterns.py) with GitHub's documented gitignore-style semantics:*stays within a path segment,**crosses segments, leading or interior/anchors to the repo root, trailing/matches directory contents,dir/*matches direct children only, and the last matching rule wins. generateconsolidates per-file inference into directory-level rules when every inferred file under a directory shares one owner set (/src/ @aliceinstead of hundreds of per-file lines). New files under a consolidated directory now match a rule. Disable withoutput.consolidate: false.generateandsyncrefuse to overwrite a hand-written CODEOWNERS (one without the machine-generated header) unless--forceis passed.--versionflag; running barecheckownersnow prints help instead of a usage error.- Progress bar (stderr, TTY-only) during the analyze blame pass.
- Local GitHub-noreply email resolution:
12345+login@users.noreply.github.comandlogin@users.noreply.github.commap to@loginwith zero API calls and no token. - Persistent email-to-handle cache at
<state-dir>/handles.json, including remembered misses, so the rate-limited user-search API is only queried once per new email. - Identity merging: when several commit emails resolve to one GitHub handle, their owner entries merge and per-path bus factor is recomputed over distinct people, so one person with two emails no longer reads as a bus factor of two. Decay warnings are remapped to the resolved handle.
- Drift results carry
notesexplaining skipped comparisons (raw emails vs handles, team-owned rules) instead of emitting false drift. balancereportsfallback_reasonwhen the GitHub API path was abandoned, and labels the load column "Commits (proxy)" when counting authorship.
Changed
- Drift detection is now pattern-aware. Inferred files are matched against CODEOWNERS rules with real matching semantics; previously the comparison was literal string equality, so directory rules like
frontend/never matched inferred file paths and real-world files produced near-100% false "missing"/"stale" reports. New categories:missing= file no rule covers,stale= rule matching no tracked file (viagit ls-files),changed= per-rule owner divergence, aggregated and ranked by worst per-file delta. Owner comparison is case-insensitive. - State is keyed per repo (schema v3) at
~/.checkowners/state/<repo-hash>.jsonwith the absolute repo path embedded and verified on load. Previously a single globalstate.jsonmeant analyzing repo A then runningdecayin repo B silently reused repo A's data. - Analyze is parallel and skips unowned files. git blame now runs on a thread pool sized to the CPU count and only on paths where at least one author reaches
min_commits(4-5x fewer files on a real monorepo). Combined effect on a 24k-commit production repo: 80+ minutes to under 3 minutes. validatefollows GitHub's actual CODEOWNERS rules: relative patterns (docs/,apps/*,frontend/package.json) are valid, owner-less rules (GitHub's documented exemption mechanism) are valid, escaped spaces are parsed, and!negation /[...]character ranges are correctly rejected. It previously demanded every pattern start with/or*, failing perfectly valid real-world files. Handle validation now matches GitHub's login rules (no dots, max 39 chars).validate --jsonexits non-zero on an invalid file, matching the human-readable mode.syncis a no-op success when the generated file matches the committed one ("already in sync"); it previously failed with an empty error because git prints "nothing to commit" on stdout.- Downstream commands print a stderr hint when reusing cached state.
notifications.include_unchangednow means "also notify when no drift was detected"; without it, no-drift runs no longer fire webhooks.- Severity's critical signal honors
bus_factor.critical_thresholdinstead of a hardcoded 1. - Review-coverage and balance GitHub scans are bounded to the 200 most recently updated closed PRs and scoped to
GITHUB_REPOSITORY; previously unbounded scans exhausted the API rate limit on mature repos. trendscounts distinct commits per period; a commit touching 12 files previously counted 12 times.bus-factor,expertise, andonboardshare one glob semantic (previously the same pattern matched different path sets per command).- Backup-reviewer suggestions fall back to repo-wide top owners for root-level files.
- Onboarding steps never label a
bus_factor<=1path "easy". - Default exclusions now also cover
package-lock.json,pnpm-lock.yaml,*.min.js,*.min.css,*.map, and the CODEOWNERS file itself (a sync commit would otherwise make whoever runs the tool its inferred owner, perturbing every subsequent run). - Composite Action: fails fast with a clear error on shallow clones (
fetch-depth: 0guidance), installs thegithubextra so handle resolution works in CI, and the PR comment is updated in place (one managed comment per PR, marked resolved when drift clears) instead of posting a new comment on every push. - PyGithub moved from a hard dependency to the
githubextra (with anallconvenience extra); core inference is pure git. Unused GitPython dependency dropped. - graph DOT export escapes quotes and backslashes in node IDs and labels.
Removed
drift.compare_toconfig option: it was parsed and documented but never read by any logic. Configs still containing it are ignored, not rejected.- Dead internal API surface orphaned by the identity-merge rework:
OwnershipMap.handles_only()andgithub.map_owners().
Fixed
- Generated CODEOWNERS never emits
[...]character ranges: bracket-bearing path segments (Next.js dynamic routes like[companyId]) become the valid*wildcard, colliding patterns merge their owners, and literal spaces in patterns are backslash-escaped. GitHub ignores lines with[...], which silently un-owned those paths. Found by dogfooding against a production Next.js monorepo. - Terminal output renders paths like
[companyId]verbatim: user-derived text (paths, reasons, handles) is markup-escaped so Rich no longer swallows bracket segments as style tags. - Webhook notifications no longer crash the CLI on HTTP or network errors; failures log a warning and
notifyreportssent: false. - Rebalance suggestions can no longer propose shifting reviews onto another overloaded reviewer.
- Topology reports one mismatch line per overlapping declared team instead of only the first.
- Tests never touch the developer's real
~/.checkowners(isolated state dir fixture).
v0.4.0
What's Changed
- Release 0.4.0: trends + github-action, review scoring, graph cache, security hardening, org transfer by @smusali in #5
Full Changelog: v0.3.0...v0.4.0
v0.3.0
v0.2.0
v0.1.1
Initial Release: CODEOWNERS inference from git history
Full Changelog: v0.1.0...v0.1.0