ledger: 2026-10-31 git-author census (snapshot 0c27162, 2350 commits, 48 identities)
This commit is contained in:
1 parent
026d252a86
commit
dceddcd75b
3 files changed
+267
No files matched your search
@@ -0,0 +1,49 @@
|
||||
rank,author,commits
|
||||
1,Timmy <timmy@stackchain.ai>,464
|
||||
2,ledger <ledger@agents.invalid>,280
|
||||
3,spark <spark@agents.invalid>,240
|
||||
4,Volt <volt@agents.invalid>,182
|
||||
5,timmy <timmy@stackchain.ai>,156
|
||||
6,Zephyrus Sparkborn <zephyrus-sparkborn@agents.invalid>,132
|
||||
7,beam <beam@agents.invalid>,132
|
||||
8,Merlin <merlin@agents.invalid>,118
|
||||
9,sol <sol@agents.invalid>,113
|
||||
10,quill <quill@agents.invalid>,97
|
||||
11,forge <forge@agents.invalid>,62
|
||||
12,Timmy <timmy@alexanderwhitestone.com>,49
|
||||
13,timmy <timmy@agents.invalid>,41
|
||||
14,Timmy <timmy@agents.invalid>,39
|
||||
15,volt <volt@agents.invalid>,38
|
||||
16,sphinx <sphinx@agents.invalid>,32
|
||||
17,null <null@agents.invalid>,28
|
||||
18,volt <volt@troupe.local>,27
|
||||
19,Mercury <mercury@agents.invalid>,22
|
||||
20,pipe <pipe@localhost>,18
|
||||
21,timmy <timmy@alexanderwhitestone.com>,10
|
||||
22,volt <volt@troupe.invalid>,10
|
||||
23,volt <volt@stackchain.ai>,7
|
||||
24,zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.forge.alexanderwhitestone.com>,7
|
||||
25,troupe-pipe <pipe@agents.invalid>,6
|
||||
26,Volt <volt@alexanderwhitestone.com>,5
|
||||
27,volt <volt@alexanderwhitestone.com>,4
|
||||
28,Volt <volt@stackchain.ai>,3
|
||||
29,argus <argus@troupe>,3
|
||||
30,zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.github.com>,3
|
||||
31,Cassian Assayborn <cassian@agents.invalid>,2
|
||||
32,Timmy <timmy@stackchain.invalid>,2
|
||||
33,Volt <volt@troupe.local>,2
|
||||
34,zephyrus-sparkborn <zephyrus-sparkborn@agents.invalid>,2
|
||||
35,Argus <argus@agents.invalid>,1
|
||||
36,Cassian Assayborn <cassian@forge.local>,1
|
||||
37,Timmy <timmy@localhost>,1
|
||||
38,Timmy <timmy@stachain.ai>,1
|
||||
39,Timmy <timmy@stacktimmy.invalid>,1
|
||||
40,Volt <timmy@stackchain.ai>,1
|
||||
41,Volt <volt@stackchain.local>,1
|
||||
42,rockachopa <alexpaynex@gmail.com>,1
|
||||
43,sentinel <sentinel@troupe-standup.internal>,1
|
||||
44,timmy <timmy@alexandrewswhitestone.com>,1
|
||||
45,timmy <timmy@hermes>,1
|
||||
46,volt <spark@agents.invalid>,1
|
||||
47,zephyrus-sparkborn <zephyrus-sparkborn@noreply.local>,1
|
||||
48,zephyrus-sparkborn <zephyrus@alexanderwhitestone.com>,1
|
||||
|
@@ -0,0 +1,61 @@
|
||||
# Git author census (2026-10-31)
|
||||
|
||||
Snapshot: `git log` of the troupe worktree at `0c2716235852ac9823082fb8938f1a6387fc4640`
|
||||
(2350 commits reachable before the census commit landed).
|
||||
|
||||
Identity key is the author name plus email in `Name <email>` form as
|
||||
recorded by git; no canonicalization (e.g. `Timmy` vs `timmy`, or a
|
||||
stackchain.ai vs agents.invalid address, stays a distinct row).
|
||||
|
||||
| rank | author | commits | pct |
|
||||
|---:|---|---:|---:|
|
||||
| 1 | Timmy <timmy@stackchain.ai> | 464 | 19.74 |
|
||||
| 2 | ledger <ledger@agents.invalid> | 280 | 11.91 |
|
||||
| 3 | spark <spark@agents.invalid> | 240 | 10.21 |
|
||||
| 4 | Volt <volt@agents.invalid> | 182 | 7.74 |
|
||||
| 5 | timmy <timmy@stackchain.ai> | 156 | 6.64 |
|
||||
| 6 | Zephyrus Sparkborn <zephyrus-sparkborn@agents.invalid> | 132 | 5.62 |
|
||||
| 7 | beam <beam@agents.invalid> | 132 | 5.62 |
|
||||
| 8 | Merlin <merlin@agents.invalid> | 118 | 5.02 |
|
||||
| 9 | sol <sol@agents.invalid> | 113 | 4.81 |
|
||||
| 10 | quill <quill@agents.invalid> | 97 | 4.13 |
|
||||
| 11 | forge <forge@agents.invalid> | 62 | 2.64 |
|
||||
| 12 | Timmy <timmy@alexanderwhitestone.com> | 49 | 2.09 |
|
||||
| 13 | timmy <timmy@agents.invalid> | 41 | 1.74 |
|
||||
| 14 | Timmy <timmy@agents.invalid> | 39 | 1.66 |
|
||||
| 15 | volt <volt@agents.invalid> | 38 | 1.62 |
|
||||
| 16 | sphinx <sphinx@agents.invalid> | 32 | 1.36 |
|
||||
| 17 | null <null@agents.invalid> | 28 | 1.19 |
|
||||
| 18 | volt <volt@troupe.local> | 27 | 1.15 |
|
||||
| 19 | Mercury <mercury@agents.invalid> | 22 | 0.94 |
|
||||
| 20 | pipe <pipe@localhost> | 18 | 0.77 |
|
||||
| 21 | timmy <timmy@alexanderwhitestone.com> | 10 | 0.43 |
|
||||
| 22 | volt <volt@troupe.invalid> | 10 | 0.43 |
|
||||
| 23 | volt <volt@stackchain.ai> | 7 | 0.30 |
|
||||
| 24 | zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.forge.alexanderwhitestone.com> | 7 | 0.30 |
|
||||
| 25 | troupe-pipe <pipe@agents.invalid> | 6 | 0.26 |
|
||||
| 26 | Volt <volt@alexanderwhitestone.com> | 5 | 0.21 |
|
||||
| 27 | volt <volt@alexanderwhitestone.com> | 4 | 0.17 |
|
||||
| 28 | Volt <volt@stackchain.ai> | 3 | 0.13 |
|
||||
| 29 | argus <argus@troupe> | 3 | 0.13 |
|
||||
| 30 | zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.github.com> | 3 | 0.13 |
|
||||
| 31 | Cassian Assayborn <cassian@agents.invalid> | 2 | 0.09 |
|
||||
| 32 | Timmy <timmy@stackchain.invalid> | 2 | 0.09 |
|
||||
| 33 | Volt <volt@troupe.local> | 2 | 0.09 |
|
||||
| 34 | zephyrus-sparkborn <zephyrus-sparkborn@agents.invalid> | 2 | 0.09 |
|
||||
| 35 | Argus <argus@agents.invalid> | 1 | 0.04 |
|
||||
| 36 | Cassian Assayborn <cassian@forge.local> | 1 | 0.04 |
|
||||
| 37 | Timmy <timmy@localhost> | 1 | 0.04 |
|
||||
| 38 | Timmy <timmy@stachain.ai> | 1 | 0.04 |
|
||||
| 39 | Timmy <timmy@stacktimmy.invalid> | 1 | 0.04 |
|
||||
| 40 | Volt <timmy@stackchain.ai> | 1 | 0.04 |
|
||||
| 41 | Volt <volt@stackchain.local> | 1 | 0.04 |
|
||||
| 42 | rockachopa <alexpaynex@gmail.com> | 1 | 0.04 |
|
||||
| 43 | sentinel <sentinel@troupe-standup.internal> | 1 | 0.04 |
|
||||
| 44 | timmy <timmy@alexandrewswhitestone.com> | 1 | 0.04 |
|
||||
| 45 | timmy <timmy@hermes> | 1 | 0.04 |
|
||||
| 46 | volt <spark@agents.invalid> | 1 | 0.04 |
|
||||
| 47 | zephyrus-sparkborn <zephyrus-sparkborn@noreply.local> | 1 | 0.04 |
|
||||
| 48 | zephyrus-sparkborn <zephyrus@alexanderwhitestone.com> | 1 | 0.04 |
|
||||
|
||||
**Total: 2350 commits** across 48 distinct author identities.
|
||||
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the 2026-10-31 git-author census for the troupe-standup repo.
|
||||
|
||||
Extract: author identities and commit counts from a pinned snapshot of the
|
||||
worktree git history, and write a table (CSV + markdown).
|
||||
|
||||
The census is a report ON the repo, committed AFTER it. To keep the check
|
||||
honest (not a self-referential tautology), the artifact is verified against
|
||||
the git snapshot it describes (SNAPSHOT), not against HEAD which includes the
|
||||
census commit itself. SNAPSHOT is pinned to the pre-census tip so the check
|
||||
stays stable as the repo keeps evolving.
|
||||
|
||||
Run:
|
||||
python3 build_2026-10-31_git_author_census.py # generate
|
||||
python3 build_2026-10-31_git_author_census.py check # verify against SNAPSHOT
|
||||
"""
|
||||
|
||||
import csv
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
REPO = "/root/troupe-standup"
|
||||
LEDGER_DIR = os.path.join(REPO, "wizard-work", "ledger")
|
||||
CSV_NAME = "2026-10-31-git-author-census.csv"
|
||||
MD_NAME = "2026-10-31-git-author-census.md"
|
||||
ASN_DATE = "2026-10-31"
|
||||
# Pre-census tip of main: the commit this census is a report ON.
|
||||
SNAPSHOT = "0c2716235852ac9823082fb8938f1a6387fc4640"
|
||||
|
||||
|
||||
def git_log(base):
|
||||
proc = subprocess.run(
|
||||
["git", "log", base, "--format=%an|%ae"],
|
||||
cwd=REPO,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
return proc.stdout
|
||||
|
||||
|
||||
def git_author_census(base):
|
||||
"""Recompute from git; {author_identity: count}, identity = 'Name <email>'."""
|
||||
counts = {}
|
||||
for raw in git_log(base).splitlines():
|
||||
if not raw:
|
||||
continue
|
||||
name, _, email = raw.partition("|")
|
||||
key = "{} <{}>".format(name.strip(), email.strip())
|
||||
counts[key] = counts.get(key, 0) + 1
|
||||
return counts
|
||||
|
||||
|
||||
def write_artifacts(counts):
|
||||
total = sum(counts.values())
|
||||
rows = sorted(counts.items(), key=lambda kv: (-kv[1], kv[0]))
|
||||
os.makedirs(LEDGER_DIR, exist_ok=True)
|
||||
|
||||
csv_path = os.path.join(LEDGER_DIR, CSV_NAME)
|
||||
with open(csv_path, "w", newline="") as f:
|
||||
w = csv.writer(f)
|
||||
w.writerow(["rank", "author", "commits"])
|
||||
for i, (k, v) in enumerate(rows, 1):
|
||||
w.writerow([i, k, v])
|
||||
|
||||
md_path = os.path.join(LEDGER_DIR, MD_NAME)
|
||||
with open(md_path, "w") as f:
|
||||
f.write("# Git author census ({date})\n\n".format(date=ASN_DATE))
|
||||
f.write("Snapshot: `git log` of the troupe worktree at `{snapshot}`\n".format(
|
||||
snapshot=SNAPSHOT))
|
||||
f.write("({total} commits reachable before the census commit landed).\n\n".format(
|
||||
total=total))
|
||||
f.write("Identity key is the author name plus email in `Name <email>` form as\n")
|
||||
f.write("recorded by git; no canonicalization (e.g. `Timmy` vs `timmy`, or a\n")
|
||||
f.write("stackchain.ai vs agents.invalid address, stays a distinct row).\n\n")
|
||||
f.write("| rank | author | commits | pct |\n")
|
||||
f.write("|---:|---|---:|---:|\n")
|
||||
for i, (k, v) in enumerate(rows, 1):
|
||||
pct = 100.0 * v / total if total else 0.0
|
||||
f.write("| {rank} | {author} | {commits} | {pct:.2f} |\n".format(
|
||||
rank=i, author=k, commits=v, pct=pct))
|
||||
f.write("\n**Total: {total} commits** across {n} distinct author identities.\n".format(
|
||||
total=total, n=len(rows)))
|
||||
|
||||
return csv_path, md_path, total, SNAPSHOT
|
||||
|
||||
|
||||
def verify():
|
||||
expected = git_author_census(SNAPSHOT)
|
||||
total = sum(expected.values())
|
||||
csv_path = os.path.join(LEDGER_DIR, CSV_NAME)
|
||||
md_path = os.path.join(LEDGER_DIR, MD_NAME)
|
||||
|
||||
with open(csv_path, newline="") as f:
|
||||
rows = list(csv.reader(f))
|
||||
|
||||
errs = []
|
||||
if not rows or rows[0] != ["rank", "author", "commits"]:
|
||||
errs.append("CSV header wrong: {!r}".format(rows[0] if rows else None))
|
||||
body = rows[1:]
|
||||
if len(body) != len(expected):
|
||||
errs.append("row count {} != author count {}".format(len(body), len(expected)))
|
||||
for i, row in enumerate(body, 1):
|
||||
if len(row) != 3:
|
||||
errs.append("bad row width: {!r}".format(row))
|
||||
continue
|
||||
rank, author, commits = row
|
||||
if str(i) != rank:
|
||||
errs.append("rank mismatch at row {}: {!r}".format(i, rank))
|
||||
exp = expected.get(author)
|
||||
if exp is None:
|
||||
errs.append("author not in recomputed census: {!r}".format(author))
|
||||
elif str(exp) != commits:
|
||||
errs.append("commits mismatch for {!r}: artifact {} expected {}".format(
|
||||
author, commits, exp))
|
||||
|
||||
proc = subprocess.run(
|
||||
["git", "rev-list", "--count", SNAPSHOT],
|
||||
cwd=REPO, check=True, capture_output=True, text=True)
|
||||
if proc.stdout.strip() != str(total):
|
||||
errs.append("snapshot commit total {} != census total {}".format(
|
||||
proc.stdout.strip(), total))
|
||||
|
||||
md = open(md_path).read()
|
||||
if "Total: {} commits".format(total) not in md:
|
||||
errs.append("MD missing total line for {total}".format(total=total))
|
||||
|
||||
if errs:
|
||||
print("FAIL:")
|
||||
for e in errs:
|
||||
print(" - " + e)
|
||||
return 1
|
||||
|
||||
print("PASS: snapshot `{snapshot}` = {total} commits, {n} author identities; "
|
||||
"{rows} CSV rows + MD match a fresh recompile from `git log {snapshot}`.".format(
|
||||
snapshot=SNAPSHOT, total=total, n=len(expected), rows=len(body)))
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
mode = sys.argv[1] if len(sys.argv) > 1 else "generate"
|
||||
if mode == "generate":
|
||||
csv_path, md_path, total, snapshot = write_artifacts(git_author_census(SNAPSHOT))
|
||||
print("snapshot {snapshot} total commits:".format(snapshot=snapshot), total)
|
||||
print("wrote", csv_path)
|
||||
print("wrote", md_path)
|
||||
return 0
|
||||
if mode == "check":
|
||||
return verify()
|
||||
print("usage: build_2026-10-31_git_author_census.py [generate|check]",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user