Files
management/analysis/scripts/inv_timestamps.py
T

87 lines
3.0 KiB
Python
Raw Normal View History

"""Measure the 2026-08-07 timestamp anonymisation -> timestamp_anonymisation.tsv.
CLAUDE.md:116-134 requires author *and* committer date of every commit in
the group to be 12:00:00 UTC, so that personal working hours cannot be
read out of the history. This script measures how far that holds.
Upstream fork history is separated out: threadnet-call and ThreadNet-Web
carry thousands of commits by Element/Matrix contributors that were never
this project's to rewrite. Counting those as a leak would be dishonest,
so every row carries the author identity and an `own_identity` flag.
Own identities are listed explicitly rather than guessed, and were read
off the actual author list of the six repos.
"""
import re
from collections import Counter
from common import cell, git, repos, write_tsv
# The one person behind this project, in every spelling that appears in
# the six repos' author fields -- including the malformed one.
OWN_IDENTITIES = {
"thore cimbal <cfx@riot.8shield.net>",
"scrublord macbad <scrublord@mac.bad>",
"scrublordmcbad <gamemaster@axion1337.de>",
"sorb <gamemaster@axion1337.de>",
"sorb <cfxqriot.8shield.net>",
}
# Agent-authored commits: not a person's working hours, but they were made
# during one, so they are reported separately rather than ignored.
AGENT_IDENTITIES = {"claude <noreply@anthropic.com>"}
ANONYMISED = "12:00:00"
def classify(ident):
low = ident.lower()
if low in OWN_IDENTITIES:
return "own"
if low in AGENT_IDENTITIES:
return "agent"
return "upstream-or-bot"
def main():
rows = []
for name, repo in repos():
# Author time forced to UTC: the rule is stated in UTC, and reading
# it in local time silently classifies every commit as non-compliant.
log = git(repo, "log", "--all", "--date=format-local:%H:%M:%S",
"--format=%H%x09%ad%x09%an <%ae>", env_tz="UTC")
main_shas = {
line.strip()
for line in git(repo, "log", "--format=%H", "origin/main").splitlines()
if line.strip()
}
buckets = Counter()
for line in log.splitlines():
if not line.strip():
continue
sha, when, ident = line.split("\t", 2)
anon = when == ANONYMISED
buckets[(classify(ident), anon, sha in main_shas, ident)] += 1
for (who, anon, on_main, ident), n in sorted(buckets.items()):
rows.append([name, who, ident,
"anonymised" if anon else "real-clock-time",
"main" if on_main else "side-branch-only", n])
rows.sort(key=lambda r: (r[0], r[1], r[3], r[4], r[2]))
write_tsv(
"timestamp_anonymisation.tsv",
["repo", "identity_class", "author", "timestamp_state", "reachable_from",
"commits"],
rows,
)
leak = sum(int(r[5]) for r in rows
if r[1] in ("own", "agent") and r[3] == "real-clock-time")
print(f" commits by own/agent identities still carrying real clock time: {leak}")
if __name__ == "__main__":
main()