ledger: git author census 2026-10-30 (48 identities, 2253 commits, git log)
This commit is contained in:
1 parent
a8f8c39f74
commit
036f6d2163
3 files changed
+241
No files matched your search
@@ -0,0 +1,49 @@
|
||||
rank,author,commits
|
||||
1,Timmy <timmy@stackchain.ai>,464
|
||||
2,ledger <ledger@agents.invalid>,257
|
||||
3,spark <spark@agents.invalid>,220
|
||||
4,Volt <volt@agents.invalid>,178
|
||||
5,timmy <timmy@stackchain.ai>,156
|
||||
6,Zephyrus Sparkborn <zephyrus-sparkborn@agents.invalid>,132
|
||||
7,beam <beam@agents.invalid>,119
|
||||
8,Merlin <merlin@agents.invalid>,118
|
||||
9,sol <sol@agents.invalid>,99
|
||||
10,quill <quill@agents.invalid>,87
|
||||
11,forge <forge@agents.invalid>,62
|
||||
12,Timmy <timmy@alexanderwhitestone.com>,49
|
||||
13,timmy <timmy@agents.invalid>,41
|
||||
14,Timmy <timmy@agents.invalid>,38
|
||||
15,volt <volt@agents.invalid>,33
|
||||
16,sphinx <sphinx@agents.invalid>,32
|
||||
17,null <null@agents.invalid>,28
|
||||
18,volt <volt@troupe.local>,23
|
||||
19,Mercury <mercury@agents.invalid>,22
|
||||
20,pipe <pipe@localhost>,18
|
||||
21,timmy <timmy@alexanderwhitestone.com>,10
|
||||
22,volt <volt@troupe.invalid>,9
|
||||
23,zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.forge.alexanderwhitestone.com>,7
|
||||
24,troupe-pipe <pipe@agents.invalid>,6
|
||||
25,Volt <volt@alexanderwhitestone.com>,5
|
||||
26,volt <volt@stackchain.ai>,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-30)
|
||||
|
||||
Source: `git log` of the troupe worktree (`d9e4a66`, 2253 commits
|
||||
reachable from HEAD). Extracted 2026-10-30.
|
||||
|
||||
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 | 20.59 |
|
||||
| 2 | ledger <ledger@agents.invalid> | 257 | 11.41 |
|
||||
| 3 | spark <spark@agents.invalid> | 220 | 9.76 |
|
||||
| 4 | Volt <volt@agents.invalid> | 178 | 7.90 |
|
||||
| 5 | timmy <timmy@stackchain.ai> | 156 | 6.92 |
|
||||
| 6 | Zephyrus Sparkborn <zephyrus-sparkborn@agents.invalid> | 132 | 5.86 |
|
||||
| 7 | beam <beam@agents.invalid> | 119 | 5.28 |
|
||||
| 8 | Merlin <merlin@agents.invalid> | 118 | 5.24 |
|
||||
| 9 | sol <sol@agents.invalid> | 99 | 4.39 |
|
||||
| 10 | quill <quill@agents.invalid> | 87 | 3.86 |
|
||||
| 11 | forge <forge@agents.invalid> | 62 | 2.75 |
|
||||
| 12 | Timmy <timmy@alexanderwhitestone.com> | 49 | 2.17 |
|
||||
| 13 | timmy <timmy@agents.invalid> | 41 | 1.82 |
|
||||
| 14 | Timmy <timmy@agents.invalid> | 38 | 1.69 |
|
||||
| 15 | volt <volt@agents.invalid> | 33 | 1.46 |
|
||||
| 16 | sphinx <sphinx@agents.invalid> | 32 | 1.42 |
|
||||
| 17 | null <null@agents.invalid> | 28 | 1.24 |
|
||||
| 18 | volt <volt@troupe.local> | 23 | 1.02 |
|
||||
| 19 | Mercury <mercury@agents.invalid> | 22 | 0.98 |
|
||||
| 20 | pipe <pipe@localhost> | 18 | 0.80 |
|
||||
| 21 | timmy <timmy@alexanderwhitestone.com> | 10 | 0.44 |
|
||||
| 22 | volt <volt@troupe.invalid> | 9 | 0.40 |
|
||||
| 23 | zephyrus-sparkborn <zephyrus-sparkborn@users.noreply.forge.alexanderwhitestone.com> | 7 | 0.31 |
|
||||
| 24 | troupe-pipe <pipe@agents.invalid> | 6 | 0.27 |
|
||||
| 25 | Volt <volt@alexanderwhitestone.com> | 5 | 0.22 |
|
||||
| 26 | volt <volt@stackchain.ai> | 5 | 0.22 |
|
||||
| 27 | volt <volt@alexanderwhitestone.com> | 4 | 0.18 |
|
||||
| 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: 2253 commits** across 48 distinct author identities.
|
||||
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Git author census: extract author identities + commit counts from the worktree
|
||||
git history, write a table, and (as 'check') verify the artifact against a fresh
|
||||
recompile from `git log`. Pure extraction; no fabricated numbers.
|
||||
"""
|
||||
import csv
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
REPO = "/root/troupe-standup"
|
||||
LEDGER_DIR = REPO + "/wizard-work/ledger"
|
||||
CSV_NAME = "2026-10-30-git-author-census.csv"
|
||||
MD_NAME = "2026-10-30-git-author-census.md"
|
||||
ASN_DATE = "2026-10-30"
|
||||
|
||||
|
||||
def git_author_census():
|
||||
"""Recompute from git; returns {author_identity: count} with identity = 'Name <email>'."""
|
||||
proc = subprocess.run(
|
||||
["git", "log", "--format=%an|%ae"],
|
||||
cwd=REPO,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
counts = {}
|
||||
for raw in proc.stdout.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_dir = __import__("os")
|
||||
os_dir.makedirs(LEDGER_DIR, exist_ok=True)
|
||||
|
||||
csv_path = 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 = 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("Source: `git log` of the troupe worktree (`d9e4a66`, {total} commits\n".format(total=total))
|
||||
f.write("reachable from HEAD). Extracted {date}.\n\n".format(date=ASN_DATE))
|
||||
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
|
||||
|
||||
|
||||
def verify(csv_path, md_path):
|
||||
expected = git_author_census()
|
||||
total = sum(expected.values())
|
||||
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))
|
||||
# independent total from the commit object count
|
||||
proc = subprocess.run(
|
||||
["git", "rev-list", "--count", "HEAD"], cwd=REPO,
|
||||
check=True, capture_output=True, text=True)
|
||||
if proc.stdout.strip() != str(total):
|
||||
errs.append("rev-list total {} != census total {}".format(proc.stdout.strip(), total))
|
||||
# md should contain the total and the correct number of rows
|
||||
md = open(md_path).read()
|
||||
if "Total: {} commits".format(total) not in md:
|
||||
errs.append("MD missing total line")
|
||||
if str(len(expected)) not in md.split("across ")[-1].split(" distinct")[0]:
|
||||
errs.append("MD row count wrong")
|
||||
|
||||
if errs:
|
||||
print("FAIL:")
|
||||
for e in errs:
|
||||
print(" - " + e)
|
||||
return 1
|
||||
print("PASS: {} author identities, {} commits; {} CSV rows + MD match a fresh "
|
||||
"recompile from `git log` and `git rev-list --count HEAD`.".format(
|
||||
len(expected), total, len(body)))
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
mode = sys.argv[1] if len(sys.argv) > 1 else "check"
|
||||
if mode == "generate":
|
||||
csv_path, md_path, total = write_artifacts(git_author_census())
|
||||
print("wrote", csv_path)
|
||||
print("wrote", md_path)
|
||||
print("total commits:", total)
|
||||
return 0
|
||||
if mode == "check":
|
||||
csv_path = LEDGER_DIR + "/" + CSV_NAME
|
||||
md_path = LEDGER_DIR + "/" + MD_NAME
|
||||
return verify(csv_path, md_path)
|
||||
print("usage: check_git_author_census.py [generate|check]", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user