Skip to content

feat(forensics): knowledge-concentration / key-person (bus-factor) ownership check - #128

Merged
maudlin merged 1 commit into
mainfrom
127-knowledge-concentration-check
Jul 15, 2026
Merged

maudlin merged 1 commit into
mainfrom
127-knowledge-concentration-check

Conversation

@maudlin

@maudlin maudlin commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Closes #127.

Adds the people axis to the git forensics. git-hotspots, change-coupling, bug-fix-density measure the code (what/where is risky). This adds ownership β€” who holds it: contribution concentration, the literal bus factor (authors to reach 50%/80%), sole-authored files, single-owned areas, and orphaned knowledge (sole-owned code whose only author has gone inactive). Pure git log, zero new tooling.

Design β€” see ADR-0010

  • Identity is the correctness risk. Resolution is git's own mailmap-applied %aN/%aE, coalesced by email β€” we never invent alias heuristics. The summary always carries an identity caveat. Demonstrated on a fixture repo: without a .mailmap an author's two emails split them in two and a different contributor falsely reads as the key person (bus factor looks like a healthy 2); with .mailmap they coalesce and the real key-person surfaces at 50% (bus factor 1).
  • Commit-touch ownership is primary (robust to one-off codemods); lines-added informs the concentration headline. Generated/vendored files are dropped up front by reusing the source inventory, so a committed bundle can't crown its committer.
  • Recency drives the orphaned-knowledge signal (absence-is-signal).
  • warn, never fail; non-git / shallow clone / thin history β†’ honest skip (ADR-0003).
  • Optional CHECKUP_OWNERSHIP_ANON=1 anonymises names for shared reports.
  • Thresholds (ownership_keyperson_pct_warn, ownership_sole_author_pct_warn, ownership_orphan_months) tunable via .checkup.yml thresholds + env; literals as defaults so an absent block is byte-identical.

Contents

  • lib/ownership.jq β€” pure, unit-testable transform (authorship rows β†’ record)
  • bin/checkup.sh β€” section 23: git log --numstat + awk normalise β†’ transform β†’ write_parsed
  • lib/config.sh + .checkup.yml.example β€” threshold keys
  • test/ownership.test.sh β€” 28 assertions (maths, thresholds, identity coalescing, orphaned recency, anonymise, honest skip), wired into CI
  • ADR-0010 + README / architecture docs

Verification

  • All 13 suites green locally (incl. the honesty harness, which runs the full engine on a non-git fixture and confirms the honest skip).
  • End-to-end through the real checkup.sh against a synthetic multi-author repo (rename + dual-email author + inactive owner): emits contract-conformant parsed/ownership.json; the renderer surfaces it automatically in Top Problems, the by-file focus map, and its own section β€” no renderer changes.
  • Contract-conformant, deterministic, shellcheck/bash -n clean.

Acceptance criteria (#127)

  • parsed/ownership.json emitted, contract-conformant, absent-git β†’ skip
  • Headline concentration + bus factor; top[] of single-owner areas
  • .mailmap respected; identity caveat surfaced in the summary
  • Generated/vendored files excluded via the existing inventory
  • Deterministic across runs; shallow-clone degrades to honest skip
  • ADR recorded; thresholds documented in .checkup.yml.example

Per ADR-0007 I don't self-merge β€” leaving this for a human to squash-merge once CI is green.

πŸ€– Generated with Claude Code

…nership check (#127)

Adds the PEOPLE axis to the git forensics. hotspots/coupling/bug-fix measure the
code (what/where is risky); `ownership` measures who holds it β€” contribution
concentration, the literal bus factor (authors to reach 50%/80%), sole-authored
files, single-owned areas, and orphaned knowledge (sole-owned code whose only
author has gone inactive). Pure `git log`, no new tooling; a natural fit for a
deterministic localiser (tech due diligence + team prioritisation, ADR-0009).

Design (ADR-0010):
- Identity via git's own mailmap resolution (%aN/%aE), coalesced by email β€” we
  never guess aliases. The summary always carries an identity caveat. This is the
  headline correctness risk: without a .mailmap an author's two emails split them
  in two and the concentration reads falsely low.
- Commit-touch ownership is primary (robust to one-off codemods); lines-added
  informs the concentration headline. Generated/vendored files are dropped up
  front by reusing the source inventory, so a committed bundle can't crown its
  committer.
- Recency drives the orphaned-knowledge signal (absence-is-signal).
- warn, never fail; non-git / shallow clone / thin history β†’ honest skip.
- Optional CHECKUP_OWNERSHIP_ANON=1 anonymises names for shared reports.

Thresholds (keyperson %, sole-author %, orphan months) are tunable via
.checkup.yml thresholds + env, defaulting to the literals so an absent block is
byte-identical. The renderer picks the record up automatically (contract).

- lib/ownership.jq: pure, unit-testable transform (rows β†’ record)
- bin/checkup.sh: section 23 β€” git log + awk normalise, feeds the transform
- lib/config.sh + .checkup.yml.example: threshold keys
- test/ownership.test.sh: 28 assertions on the transform (maths, thresholds,
  identity coalescing, orphaned recency, anonymise, honest skip); wired into CI
- ADR-0010 + README/architecture docs

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VxHXw3RKcV6SBKary5iwcC
@maudlin
maudlin merged commit 3256667 into main Jul 15, 2026
6 checks passed
@maudlin
maudlin deleted the 127-knowledge-concentration-check branch July 15, 2026 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(forensics): knowledge-concentration / key-person (bus-factor) check

1 participant