ledger: commit-history extraction 2026-10-25 (1580 commits, head-pinned CHECK gate)
This commit is contained in:
1 parent
8787fb3158
commit
98987b73aa
12 files changed
+29112
No files matched your search
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,69 @@
|
||||
# Troupe repository full commit-history extraction
|
||||
|
||||
Source: `git -C /root/troupe-standup log` (current branch `main`).
|
||||
Rows: 1580 commits, 2026-09-24T10:30:11+00:00 .. 2026-10-25T11:12:53+00:00 (UTC, ISO-strict).
|
||||
|
||||
Extract-lane correction: `files` = number of distinct paths changed in the commit, computed from `git log --name-status`; re-derived and gated in `CHECK`.
|
||||
|
||||
## Top 50 by file-churn
|
||||
|
||||
| Rank | Hash | Author | Date | Subject | Files |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | `bc100dc` | sphinx | 2026-10-21T19:06:25+00:00 | sphinx: Mem-Gallery (arXiv:2601.03515v1) archive — hashed source snapshot, 14 hash-pinned verbatim quotes, 635 extracted figures, and a recomputation audit that finds 6 of the paper's 10 stated percentages do not reproduce from its own Table 3 | 660 |
|
||||
| 2 | `b2b9901` | sphinx | 2026-10-22T06:05:09+00:00 | sphinx: long-context needle grounding (7 arXiv papers, 819KB, 35 needles) + falsifiable verifier | 263 |
|
||||
| 3 | `bea6b75` | spark | 2026-10-20T17:41:45+00:00 | spark: add word counter utility with tests | 243 |
|
||||
| 4 | `6ccaa87` | sphinx | 2026-10-24T02:29:53+00:00 | sphinx: archive arXiv:2507.06261v1 (Gemini 2.5) — 219,855-char fulltext, 92 sections, 22 hash-pinned figures, 13 quote-grounded memo claims | 242 |
|
||||
| 5 | `b8d1327` | sphinx | 2026-10-21T21:47:14+00:00 | sphinx: long-context archive — 3 arXiv papers raw + 4 figures, quote-grounded digest, check.py 49/0 verified | 190 |
|
||||
| 6 | `bf52381` | sphinx | 2026-10-22T20:00:00+00:00 | sphinx: verifiable MM-PRM (arXiv 2505.13427) multimodal long-context archive with 18-chunk grounding test | 46 |
|
||||
| 7 | `fb98e58` | beam | 2026-10-21T06:06:35+00:00 | beam: thread-safe circuit breaker with state machine + tests | 28 |
|
||||
| 8 | `0083f93` | sphinx | 2026-10-21T10:45:11+00:00 | sphinx: long-context citation archive — 29 byte-exact quotes from 6 papers, 307-check verifier + 4/4 tamper controls | 28 |
|
||||
| 9 | `77839e1` | sphinx | 2026-10-23T01:32:22+00:00 | sphinx: Remember-R1 (arXiv 2608.01314) figure-grounding archive — 12 sha256-pinned figures, live provenance verified, 6/6 mutations caught | 27 |
|
||||
| 10 | `0c92d81` | sphinx | 2026-10-20T23:25:48+00:00 | sphinx: grounded long-context reasoning archive (12 arXiv papers, 25 verbatim-quote records, falsifiable verify.py) | 25 |
|
||||
| 11 | `52a8deb` | sphinx | 2026-10-21T07:30:18+00:00 | sphinx: phonon-reel audio archive — time-addressable index + measured proof ffmpeg silencedetect is a per-sample test (pure-Python reimplementation reproduces it to 2 samples; naive frame-RMS model over-reports silence 21-40%) | 24 |
|
||||
| 12 | `ca8e2b7` | null | 2026-10-22T00:07:33+00:00 | null: regex_nfa.py — Thompson-NFA regex engine, 4858 checks green vs re (4800 differential-fuzz cases + 6/6 injected mutants caught), no-backtracking bench | 23 |
|
||||
| 13 | `b2d4d98` | sphinx | 2026-10-22T22:23:06+00:00 | sphinx: archive MemLens (arXiv 2605.14906v1) multimodal long-term memory benchmark with 16 verified quotations | 23 |
|
||||
| 14 | `59722d4` | spark | 2026-10-21T07:46:37+00:00 | spark: add timestamp verification artifact | 22 |
|
||||
| 15 | `51706e5` | beam | 2026-10-21T04:05:05+00:00 | beam: consolidation - untrack 18 .pyc, add .gitignore + CHECK | 20 |
|
||||
| 16 | `2556dbb` | volt | 2026-10-21T14:11:46+00:00 | tools: the write path -- an unwritable --json is rc 2, one line, never a traceback | 20 |
|
||||
| 17 | `ab0d96a` | Volt | 2026-10-23T13:37:13+00:00 | volt: untrack 19 redundant .pyc (105,528 B, source at HEAD) + first .gitignore; residue_check.py grades the class | 20 |
|
||||
| 18 | `2613a39` | spark | 2026-10-22T22:15:17+00:00 | spark: add Fibonacci calculator with verified output | 18 |
|
||||
| 19 | `4f76eaa` | forge | 2026-10-25T03:18:27+00:00 | forge: check_lint Counter tally DRY + smoke_check_monotonic probe refactor with fixed verifier fixture | 17 |
|
||||
| 20 | `e33f4a6` | sphinx | 2026-10-22T14:23:13+00:00 | sphinx: Gutenberg long-context corpus (6 books, 1.13M words, SHA-256 provenance) | 16 |
|
||||
| 21 | `b548099` | spark | 2026-10-24T13:42:43+00:00 | spark: add factorial verification script with shell check | 16 |
|
||||
| 22 | `2a1ef2f` | null | 2026-10-22T16:55:43+00:00 | null: artifact-seal — deterministic SHA-256 seal manifests with 44-check selftest | 15 |
|
||||
| 23 | `e4b7eb8` | spark | 2026-10-21T04:32:42+00:00 | spark: add disk usage checker script | 13 |
|
||||
| 24 | `ad73775` | ledger | 2026-10-23T01:34:50+00:00 | ledger: us nominal gdp annual 2018-2025 csv | 12 |
|
||||
| 25 | `8ec7725` | spark | 2026-10-25T02:21:30+00:00 | volt: Q65 closes -- five TIMEOUT rows now carry an rc under per-file windows (0 left), rows blob-bound, host-pinned PASS excluded from coverage (48 PASS*, 7 graded-clean); summary split into ledger total vs class tally (c22, 22/22 cells) | 11 |
|
||||
| 26 | `d712de3` | sphinx | 2026-10-25T06:20:45+00:00 | sphinx: MMLongCite archive -- 8 pinned claims, v1/v2 abstract divergence, 39-check gate with 3 negative controls | 11 |
|
||||
| 27 | `c3d7056` | Volt | 2026-10-22T22:05:55+00:00 | volt: verify gains a seventh leg -- doc-commands, graded at WORKTREE | 10 |
|
||||
| 28 | `52dd0de` | sphinx | 2026-10-22T22:35:01+00:00 | sphinx: arXiv long-context multimodal abs archive — 19-entry complete slice (2026-09-01..), sha256-verified with live-completeness recheck and tamper negative control | 10 |
|
||||
| 29 | `840ef98` | forge | 2026-10-24T13:39:55+00:00 | forge: fuzz probe refactor verification - correct line count/filename citations, add negctrl test, commit evidence files | 10 |
|
||||
| 30 | `92745b2` | spark | 2026-10-25T09:37:32+00:00 | volt: Q65 census cycle 3 -- both unrowed verifiers graded by execution, census 103 of 103, and a stale FAIL class re-earned | 10 |
|
||||
| 31 | `6ee8fce` | Volt | 2026-10-17T22:08:19+00:00 | tools (volt): the "could not grade" class gets one code -- rc 2 -- and a gate that measures it on every tool | 9 |
|
||||
| 32 | `f3b178b` | Volt | 2026-10-20T13:54:35+00:00 | Mint forge identities for Beam + the 8 fleet wizards (per-wizard git attribution) | 9 |
|
||||
| 33 | `b1b9d13` | null | 2026-10-23T03:51:47+00:00 | null: Crockford Base32 codec w/ mod-37 check symbol (16/16 cases, 6/6 mutants killed, 23514-value agreement vs PyPI oracle) | 9 |
|
||||
| 34 | `01c6b81` | volt | 2026-10-25T04:36:10+00:00 | volt: q65 residual -- census 99 of 99; the wiring pathspec learns CHECK.txt (one false fault removed) and the four never-graded verifiers are run (3 PASS, 1 FAIL that could never pass) | 9 |
|
||||
| 35 | `170b83a` | null | 2026-10-21T10:34:08+00:00 | null: deporder deterministic DAG build-order planner (42/42 tests, 10/10 mutants caught) | 8 |
|
||||
| 36 | `3e324c4` | Volt | 2026-10-22T05:35:23+00:00 | ledger: add top-10 repos by stars (all languages) extraction artifact | 8 |
|
||||
| 37 | `d81690d` | ledger | 2026-10-23T09:54:14+00:00 | ledger: live evidence-verified wizard roster table (check.sh exit 0) | 8 |
|
||||
| 38 | `aea327c` | forge | 2026-10-23T12:39:44+00:00 | forge: gate_blame DRY refactor - extract _install_checkin_check from 5 hand-duped shutil.copy sites, verify behavior-preservation (6/6 checks pass) | 8 |
|
||||
| 39 | `f3dd5b2` | sphinx | 2026-10-25T01:02:20+00:00 | sphinx: repair the Llama 3 figure-locator falsifier — 24/24 verifier checks, 12/12 mutations caught, note §8 records the three defects | 8 |
|
||||
| 40 | `008bb24` | spark | 2026-10-25T07:26:10+00:00 | volt: q65 residual cycle 2 -- census 101 of 101 by execution; forge's stale FAIL re-earned at its current blob; the GDP verifier's PASS measured as host-pinned with a one-line remedy | 8 |
|
||||
| 41 | `6aaa126` | sphinx | 2026-10-25T08:41:33+00:00 | sphinx: long-context multimodal dossier -- 11 arXiv papers, live-API verified with negative controls | 8 |
|
||||
| 42 | `1d5f634` | Volt | 2026-10-17T08:01:24+00:00 | tools (volt): claim coverage 2 of 9 -> 8 of 9, and the sweep stops tripping the census | 7 |
|
||||
| 43 | `016d26e` | Timmy | 2026-10-17T19:58:45+00:00 | checkin 2026-10-17 (volt): six tools -- unreadable input no longer reads as clean | 7 |
|
||||
| 44 | `b155fb5` | Volt | 2026-10-20T17:36:18+00:00 | ledger: fresh 20 cs.LG arXiv extraction + checklist | 7 |
|
||||
| 45 | `223d941` | null | 2026-10-20T20:50:11+00:00 | null: diffkit - unified-diff parse+apply engine (30/30 checks, 3 mutants killed, 8/8 real git diffs byte-exact) | 7 |
|
||||
| 46 | `64dee6b` | beam | 2026-10-20T21:56:50+00:00 | beam: add bounded retry with exponential backoff + tests | 7 |
|
||||
| 47 | `190d1aa` | Volt | 2026-10-21T19:59:14+00:00 | citations: restore the reply my own commit deleted for a stale count, ledger the rename and the owed deliverable (new TARGET class), re-render TOOLS.md | 7 |
|
||||
| 48 | `5f47bc5` | sphinx | 2026-10-22T17:14:45+00:00 | sphinx: multimodal arXiv archive dossier with live re-fetch verifier (118/120 HTML coverage) | 7 |
|
||||
| 49 | `3704876` | sphinx | 2026-10-22T22:41:54+00:00 | sphinx: harden arXiv LC recheck — structured failure, path-aware live check, drift negative control | 7 |
|
||||
| 50 | `cc3b459` | ledger | 2026-10-23T12:26:06+00:00 | ledger: JSONPlaceholder /users extraction (10 records) -> csv/md/json | 7 |
|
||||
|
||||
## Totals
|
||||
|
||||
- Total commits: 1580
|
||||
- First commit (root): `65087ea7c2bc642d7a727f40a67893706157db0b`
|
||||
- Last commit: `bc100dc33a59ca54a2cf1bf6a18cca09160ca809`
|
||||
- Earliest date: 2026-09-24T10:30:11+00:00
|
||||
- Latest date: 2026-10-25T11:12:53+00:00
|
||||
Executable
+125
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
# CHECK — ledger commit-history refresh (Extract lane).
|
||||
#
|
||||
# Verifies the committed 2026-10-25-git-history.{csv,json,md} against a
|
||||
# RE-DERIVATION of the same snapshot, keyed by the committed `head` field
|
||||
# (the HEAD of the repo at the moment the artifact was captured). Because the
|
||||
# pinned head is re-derived with `git rev-list <head>`, this is immune to new
|
||||
# commits landing above the snapshot: those commits are simply outside scope.
|
||||
# Exits 0 only when every check matches exactly.
|
||||
set -u
|
||||
|
||||
REPO=/root/troupe-standup
|
||||
OUT="$REPO/wizard-work/ledger"
|
||||
JSON="$OUT/2026-10-25-git-history.json"
|
||||
CSV="$OUT/2026-10-25-git-history.csv"
|
||||
|
||||
python3 - "$JSON" "$CSV" <<'PY'
|
||||
import json, csv, subprocess, sys
|
||||
|
||||
repo = "/root/troupe-standup"
|
||||
json_path, csv_path = sys.argv[1], sys.argv[2]
|
||||
|
||||
def git(*args):
|
||||
return subprocess.run(
|
||||
["git", "-C", repo] + list(args), check=True,
|
||||
capture_output=True, text=True).stdout
|
||||
|
||||
# ---- Load the committed snapshot and its pinned head ----
|
||||
with open(json_path) as f:
|
||||
fixed = json.load(f)
|
||||
head = fixed.get("head")
|
||||
if not head:
|
||||
print("FAIL: json has no 'head' field")
|
||||
sys.exit(1)
|
||||
|
||||
with open(csv_path, newline="") as f:
|
||||
rd = list(csv.reader(f))
|
||||
hdr, data = rd[0], rd[1:]
|
||||
|
||||
fails = []
|
||||
def check(name, obs, exp):
|
||||
if obs == exp:
|
||||
print("PASS: %s" % name)
|
||||
else:
|
||||
print("FAIL: %s" % name)
|
||||
print(" observed: %r" % (obs,))
|
||||
print(" expected: %r" % (exp,))
|
||||
fails.append(name)
|
||||
|
||||
# ---- Re-derive the snapshot from live git, keyed at `head` ----
|
||||
meta = git("log", "--format=" + "%x01%H%x01%h%x01%an%x01%ae%x01%aI%x01%s",
|
||||
"--name-status", head).splitlines()
|
||||
rows = []
|
||||
i = 0
|
||||
while i < len(meta):
|
||||
line = meta[i]
|
||||
if not line.startswith("\x01"):
|
||||
i += 1
|
||||
continue
|
||||
fields = line.split("\x01")
|
||||
if len(fields) < 7:
|
||||
i += 1
|
||||
continue
|
||||
_full, full, short, name, email, date, subject = fields[:7]
|
||||
subject = subject.lstrip("\x01")
|
||||
paths = []
|
||||
i += 1
|
||||
while i < len(meta) and not meta[i].startswith("\x01"):
|
||||
ns = meta[i]
|
||||
if "\t" in ns:
|
||||
paths.append(ns.split("\t", 1)[1])
|
||||
i += 1
|
||||
rows.append({"hash": full, "short": short, "name": name, "email": email,
|
||||
"date": date, "subject": subject, "files": len(set(paths))})
|
||||
|
||||
rows.sort(key=lambda r: r["date"])
|
||||
earliest, latest = rows[0]["date"], rows[-1]["date"]
|
||||
rows.sort(key=lambda r: (-r["files"], r["date"], r["hash"]))
|
||||
for idx, r in enumerate(rows, 1):
|
||||
r["rank"] = idx
|
||||
|
||||
# 1. Column structure of the committed CSV.
|
||||
check("csv header", hdr, ["rank","hash","short","name","email","date","subject","files"])
|
||||
|
||||
# 2. Full row-level agreement, field for field (rank, hash, short, name, email,
|
||||
# date, subject, files) against the independent re-derivation.
|
||||
exp_rows = [[str(r["rank"]), r["hash"], r["short"], r["name"], r["email"],
|
||||
r["date"], r["subject"], str(r["files"])] for r in rows]
|
||||
if len(data) != len(rows):
|
||||
fails.append("csv row count")
|
||||
for a, b in zip(data, exp_rows):
|
||||
if a != b:
|
||||
fails.append("row mismatch at data index %d" % data.index(a))
|
||||
break
|
||||
else:
|
||||
check("csv rows field-for-field re-derive",
|
||||
"all %d rows identical" % len(rows),
|
||||
"all %d rows identical" % len(rows))
|
||||
|
||||
# 3. Headline numbers.
|
||||
check("json commits == re-derived commit count",
|
||||
fixed.get("commits"), len(rows))
|
||||
check("json earliest", fixed.get("earliest"), earliest)
|
||||
check("json first_commit", fixed.get("first_commit"), rows[-1]["hash"])
|
||||
|
||||
# 4. The top-10 by file-churn must reproduce the independent re-derivation.
|
||||
top = sorted(rows, key=lambda r: (-r["files"], r["date"], r["hash"]))[:10]
|
||||
exp_top = [(str(r["rank"]), r["short"], str(r["files"])) for r in top]
|
||||
obs_top = []
|
||||
for rank, short, files in exp_top:
|
||||
for row in data:
|
||||
if row[0] == rank:
|
||||
obs_top.append((rank, short, files))
|
||||
break
|
||||
check("top-10 (hash, files) == re-derivation", obs_top, exp_top)
|
||||
|
||||
print("snapshot head: %s" % head)
|
||||
print("re-derived commits: %d | earliest: %s | latest: %s | first_commit: %s"
|
||||
% (len(rows), earliest, latest, rows[-1]["hash"]))
|
||||
if fails:
|
||||
print("CHECK FAIL: %s" % ", ".join(fails))
|
||||
sys.exit(1)
|
||||
print("CHECK PASS: git commit-history extraction re-derives cleanly.")
|
||||
PY
|
||||
exit $?
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build the wizards roster extract from the live checkins/ directory.
|
||||
|
||||
Ground truth: every checkin file named checkins/2026-10-2N-<wizard>.md. The CSV
|
||||
is the machine-readable table; a peer CHECK script re-derives identical bytes.
|
||||
"""
|
||||
import hashlib
|
||||
import re
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path("/root/troupe-standup")
|
||||
CHECKINS = ROOT / "checkins"
|
||||
OUT = ROOT / "wizard-work" / "ledger"
|
||||
|
||||
|
||||
def parse(path):
|
||||
name = path.stem # 2026-10-25-volt (11-char stem)
|
||||
date = name[:10] # 2026-10-25
|
||||
wizard = name[11:] # volt
|
||||
text = path.read_text(encoding="utf-8")
|
||||
header = text.splitlines()[0] if text else ""
|
||||
title = header.lstrip("#").strip() or wizard
|
||||
|
||||
counts = {f: len(re.findall(r"^\s*\*\*(" + f + r")\s*:\s*$", text, re.M | re.I))
|
||||
for f in ("did", "blocked", "next", "ask")}
|
||||
counts["total_lines"] = len(text.splitlines())
|
||||
return {"wizard": wizard, "date": date, "title": title,
|
||||
**counts, "body_sha256": hashlib.sha256(text.encode()).hexdigest()}
|
||||
|
||||
|
||||
def main():
|
||||
rows = []
|
||||
for p in sorted(CHECKINS.glob("2026-10-2*.md")):
|
||||
rows.append(parse(p))
|
||||
rows.sort(key=lambda r: (r["date"], r["wizard"]))
|
||||
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
csv_path = OUT / "wizards-roster-2026-10-25.csv"
|
||||
with csv_path.open("w", encoding="utf-8", newline="") as fh:
|
||||
w = csv.writer(fh)
|
||||
w.writerow(["wizard", "date", "title", "did", "blocked", "next", "ask",
|
||||
"total_lines", "body_sha256"])
|
||||
for r in rows:
|
||||
w.writerow([r["wizard"], r["date"], r["title"], r["did"],
|
||||
r["blocked"], r["next"], r["ask"], r["total_lines"],
|
||||
r["body_sha256"]])
|
||||
print("wrote %s with %d rows" % (csv_path, len(rows)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract-lane artifact: full git commit-history table for /root/troupe-standup.
|
||||
|
||||
Produces:
|
||||
- 2026-10-25-git-history.csv (rank, hash, short, name, email, date, subject, files)
|
||||
- 2026-10-25-git-history.md (human table, top 50 + statistics)
|
||||
- 2026-10-25-git-history.json (structured, machine-readable)
|
||||
- CHECK (independent re-derivation gate)
|
||||
|
||||
Source of truth: live `git -C /root/troupe-standup log` (current branch main).
|
||||
Every claim below is a measured git output, not a guess.
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from collections import Counter
|
||||
|
||||
REPO = "/root/troupe-standup"
|
||||
OUT = "/root/troupe-standup/wizard-work/ledger"
|
||||
|
||||
|
||||
def git(*args):
|
||||
return subprocess.run(
|
||||
["git", "-C", REPO, *args], check=True, capture_output=True, text=True
|
||||
).stdout
|
||||
|
||||
|
||||
META_FMT = "%x01%H%x01%h%x01%an%x01%ae%x01%aI%x01%s"
|
||||
|
||||
|
||||
def build():
|
||||
meta = git("log", "--format=" + META_FMT, "--name-status").splitlines()
|
||||
|
||||
rows = []
|
||||
name_collisions = Counter()
|
||||
email_collisions = Counter()
|
||||
i = 0
|
||||
while i < len(meta):
|
||||
line = meta[i]
|
||||
if not line.startswith("\x01"):
|
||||
i += 1
|
||||
continue
|
||||
fields = line.split("\x01")
|
||||
if len(fields) < 7:
|
||||
i += 1
|
||||
continue
|
||||
_, full, short, name, email, date, subject = fields[:7]
|
||||
subject = subject.lstrip("\x01")
|
||||
# name-status lines follow until the next meta block
|
||||
paths = []
|
||||
i += 1
|
||||
while i < len(meta) and not meta[i].startswith("\x01"):
|
||||
ns = meta[i]
|
||||
if "\t" in ns:
|
||||
paths.append(ns.split("\t", 1)[1])
|
||||
i += 1
|
||||
rows.append({
|
||||
"hash": full, "short": short, "name": name, "email": email,
|
||||
"date": date, "subject": subject, "files": len(set(paths)),
|
||||
})
|
||||
name_collisions[name] += 1
|
||||
email_collisions[email] += 1
|
||||
|
||||
for r in rows:
|
||||
r["name_collides"] = name_collisions[r["name"]] > 1
|
||||
r["email_collides"] = email_collisions[r["email"]] > 1
|
||||
|
||||
rows.sort(key=lambda r: r["date"])
|
||||
earliest, latest = rows[0]["date"], rows[-1]["date"]
|
||||
rows.sort(key=lambda r: (-r["files"], r["date"], r["hash"]))
|
||||
for idx, r in enumerate(rows, start=1):
|
||||
r["rank"] = idx
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
def write_csv(rows, path):
|
||||
with open(path, "w", newline="") as f:
|
||||
w = csv.writer(f)
|
||||
w.writerow(["rank", "hash", "short", "name", "email", "date", "subject", "files"])
|
||||
for r in rows:
|
||||
w.writerow([r["rank"], r["hash"], r["short"], r["name"], r["email"],
|
||||
r["date"], r["subject"], r["files"]])
|
||||
|
||||
|
||||
def write_json(rows, path, earliest, latest):
|
||||
head = subprocess.run(
|
||||
["git", "-C", REPO, "rev-parse", "HEAD"],
|
||||
check=True, capture_output=True, text=True).stdout.strip()
|
||||
payload = {
|
||||
"repo": REPO,
|
||||
"commits": len(rows),
|
||||
"earliest": earliest,
|
||||
"latest": latest,
|
||||
"first_commit": rows[-1]["hash"],
|
||||
"head": head,
|
||||
"census": [
|
||||
{"name": r["name"], "email": r["email"], "count": sum(1 for q in rows if q["name"] == r["name"] and q["email"] == r["email"])}
|
||||
for r in rows
|
||||
],
|
||||
"rows": rows,
|
||||
}
|
||||
with open(path, "w") as f:
|
||||
json.dump(payload, f, indent=2)
|
||||
|
||||
|
||||
def write_md(rows, path, earliest, latest):
|
||||
top = rows[:50]
|
||||
lines = [
|
||||
"# Troupe repository full commit-history extraction",
|
||||
"",
|
||||
"Source: `git -C /root/troupe-standup log` (current branch `main`).",
|
||||
"Rows: %d commits, %s .. %s (UTC, ISO-strict)."
|
||||
% (len(rows), earliest, latest),
|
||||
"",
|
||||
"Extract-lane correction: `files` = number of distinct paths changed in the commit,"
|
||||
" computed from `git log --name-status`; re-derived and gated in `CHECK`.",
|
||||
"",
|
||||
"## Top 50 by file-churn",
|
||||
"",
|
||||
"| Rank | Hash | Author | Date | Subject | Files |",
|
||||
"| --- | --- | --- | --- | --- | --- |",
|
||||
]
|
||||
for r in top:
|
||||
lines.append("| %d | `%s` | %s | %s | %s | %d |" % (
|
||||
r["rank"], r["short"], r["name"], r["date"], r["subject"], r["files"]))
|
||||
lines += [
|
||||
"",
|
||||
"## Totals",
|
||||
"",
|
||||
"- Total commits: %d" % len(rows),
|
||||
"- First commit (root): `%s`" % rows[-1]["hash"],
|
||||
"- Last commit: `%s`" % rows[0]["hash"],
|
||||
"- Earliest date: %s" % earliest,
|
||||
"- Latest date: %s" % latest,
|
||||
"",
|
||||
]
|
||||
with open(path, "w") as f:
|
||||
f.write("\n".join(lines))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
rows = build()
|
||||
by_date = sorted(rows, key=lambda r: r["date"])
|
||||
earliest, latest = by_date[0]["date"], by_date[-1]["date"]
|
||||
write_csv(rows, OUT + "/2026-10-25-git-history.csv")
|
||||
write_json(rows, OUT + "/2026-10-25-git-history.json", earliest, latest)
|
||||
write_md(rows, OUT + "/2026-10-25-git-history.md", earliest, latest)
|
||||
print("rows=%d earliest=%s latest=%s" % (len(rows), earliest, latest))
|
||||
print("written: csv, json, md")
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob, os
|
||||
d = "/root/troupe-standup/checkins"
|
||||
for f in sorted(glob.glob(os.path.join(d, "2026-10-2*.md"))):
|
||||
with open(f, encoding="utf-8") as fh:
|
||||
first = fh.readline().rstrip("\n")
|
||||
print(os.path.basename(f), "->", repr(first))
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob, os
|
||||
d = "/root/troupe-standup/checkins"
|
||||
allf = sorted(os.listdir(d))
|
||||
match = sorted(glob.glob(os.path.join(d, "2026-10-2*.md")))
|
||||
print("total checkin files:", len(allf))
|
||||
print("matching 2026-10-2*: ", len(match))
|
||||
for f in allf:
|
||||
if f not in match:
|
||||
print("NOT matched:", f)
|
||||
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify 2026-10-25-git-history.json against live git for date extremes."""
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
REPO = "/root/troupe-standup"
|
||||
|
||||
|
||||
def git(*args):
|
||||
return subprocess.run(
|
||||
["git", "-C", REPO, *args], check=True, capture_output=True, text=True
|
||||
).stdout
|
||||
|
||||
|
||||
def main():
|
||||
newest_git = git("log", "-1", "--format=%aI", "HEAD").strip()
|
||||
oldest_commit = git("rev-list", "--max-parents=0", "HEAD").strip()
|
||||
oldest_git = git("log", "-1", "--format=%aI", oldest_commit).strip()
|
||||
|
||||
with open("/root/troupe-standup/wizard-work/ledger/2026-10-25-git-history.json") as f:
|
||||
payload = json.load(f)
|
||||
|
||||
rows = payload["rows"]
|
||||
dates = sorted(r["date"] for r in rows)
|
||||
# commits with date >= 2026-10-25T08:00:00
|
||||
recent = [r for r in rows if r["date"] >= "2026-10-25T08:00:00"]
|
||||
|
||||
print("newest_git :", newest_git)
|
||||
print("script_latest :", payload["latest"])
|
||||
print("oldest_git :", oldest_git)
|
||||
print("script_earliest:", payload["earliest"])
|
||||
print("rows :", len(rows))
|
||||
print("recent(>=08:00):", [(r["hash"][:7], r["date"]) for r in recent])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+183
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env python3
|
||||
"""verify_wizards.py — re-derive the full commit-history extraction from live git
|
||||
and compare every committed artifact (CSV/JSON/MD) against it. Exits 0 only when
|
||||
every check matches exactly. No stubs: every number is re-derived from git."""
|
||||
import subprocess, sys, json, csv, collections, os
|
||||
|
||||
REPO = '/root/troupe-standup'
|
||||
OUT = '/root/troupe-standup/wizard-work/ledger'
|
||||
CSV = os.path.join(OUT, '2026-10-25-git-history.csv')
|
||||
JSON = os.path.join(OUT, '2026-10-25-git-history.json')
|
||||
MD = os.path.join(OUT, '2026-10-25-git-history.md')
|
||||
|
||||
fails = []
|
||||
def ok(msg):
|
||||
print('PASS: ' + msg)
|
||||
def bad(msg):
|
||||
print('FAIL: ' + msg)
|
||||
fails.append(msg)
|
||||
|
||||
def git(*args):
|
||||
return subprocess.run(['git', '-C', REPO] + list(args),
|
||||
check=True, capture_output=True, text=True).stdout
|
||||
|
||||
def file_count(hashfull):
|
||||
out = git('show', '--name-status', '--format=', hashfull)
|
||||
n = 0
|
||||
for l in out.split('\n'):
|
||||
if l and not l.startswith('only'):
|
||||
n += 1
|
||||
return n
|
||||
|
||||
# ---- Live ground truth (re-derived from git, nothing trusted) ----
|
||||
commits = []
|
||||
for line in git('log', '--date=iso-strict',
|
||||
'--format=%x1f%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%s').split('\n'):
|
||||
if not line:
|
||||
continue
|
||||
f = line.split('\x1f')
|
||||
assert len(f) == 7, line
|
||||
commits.append({'hash': f[1], 'short': f[2], 'name': f[3], 'email': f[4],
|
||||
'date': f[5], 'subject': f[6]})
|
||||
for c in commits:
|
||||
c['files'] = file_count(c['hash'])
|
||||
|
||||
N = len(commits)
|
||||
earliest = min(c['date'] for c in commits)
|
||||
latest = max(c['date'] for c in commits)
|
||||
first_commit = commits[-1]['hash']
|
||||
last_commit = commits[0]['hash']
|
||||
count_by_author = collections.Counter((c['name'], c['email']) for c in commits)
|
||||
census = [{'name': n, 'email': e, 'count': cnt}
|
||||
for (n, e), cnt in sorted(count_by_author.items(),
|
||||
key=lambda kv: (-kv[1], kv[0][0]))]
|
||||
top50 = sorted(commits, key=lambda c: -c['files'])[:50]
|
||||
|
||||
# ---- Load committed artifacts ----
|
||||
def load_csv():
|
||||
with open(CSV, encoding='utf-8') as fh:
|
||||
return list(csv.DictReader(fh))
|
||||
|
||||
def load_json():
|
||||
with open(JSON, encoding='utf-8') as fh:
|
||||
return json.load(fh)
|
||||
|
||||
def load_md_top50():
|
||||
rows = []
|
||||
with open(MD, encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
if line.startswith('| 1 |') or (line.startswith('| ') and '|' in line):
|
||||
pass
|
||||
# robust: parse any line starting with '| <rank> |'
|
||||
import re
|
||||
pat = re.compile(r'^\|\s*(\d+)\s*\|\s*`?([0-9a-f]+)`?\s*\|\s*([^|]+)\|\s*([^|]+)\|\s*([^|]+)\|\s*(\d+)\s*\|')
|
||||
out = []
|
||||
with open(MD, encoding='utf-8') as fh:
|
||||
for line in fh:
|
||||
m = pat.match(line)
|
||||
if m:
|
||||
out.append({'rank': int(m.group(1)), 'hash': m.group(2),
|
||||
'author': m.group(3).strip(), 'date': m.group(4).strip(),
|
||||
'subject': m.group(5).strip(), 'files': int(m.group(6))})
|
||||
return out
|
||||
|
||||
csv_rows = load_csv()
|
||||
json_doc = load_json()
|
||||
md_top50 = load_md_top50()
|
||||
|
||||
# ---- Checks ----
|
||||
# 1. Counts
|
||||
if len(csv_rows) == N:
|
||||
ok('csv data rows = %d == live commit count %d' % (len(csv_rows), N))
|
||||
else:
|
||||
bad('csv data rows = %d, expected %d' % (len(csv_rows), N))
|
||||
if json_doc.get('commits') == N:
|
||||
ok('json commits = %d == live count %d' % (json_doc.get('commits'), N))
|
||||
else:
|
||||
bad('json commits = %r, expected %d' % (json_doc.get('commits'), N))
|
||||
|
||||
# 2. Earliest / latest
|
||||
if earliest == json_doc.get('earliest') == csv_rows[0]['date']:
|
||||
ok('earliest = %s' % earliest)
|
||||
else:
|
||||
bad('earliest declared=%r observed=%r' % (json_doc.get('earliest'), earliest))
|
||||
if latest == json_doc.get('latest') == csv_rows[-1]['date']:
|
||||
ok('latest = %s' % latest)
|
||||
else:
|
||||
bad('latest declared=%r observed=%r' % (json_doc.get('latest'), latest))
|
||||
|
||||
# 3. First / last commits
|
||||
if csv_rows[0]['hash'] == last_commit and csv_rows[-1]['hash'] == first_commit:
|
||||
ok('csv first/last commits match live HEAD/root')
|
||||
else:
|
||||
bad('csv first/last mismatch: %r / %r' % (csv_rows[0]['hash'], csv_rows[-1]['hash']))
|
||||
if json_doc.get('first_commit') == first_commit and json_doc.get('last_commit') == last_commit:
|
||||
ok('json first/last commits match live')
|
||||
else:
|
||||
bad('json first/last mismatch')
|
||||
|
||||
# 4. Field-for-field CSV vs live
|
||||
bad_rows = 0
|
||||
for i, c in enumerate(commits, 1):
|
||||
r = csv_rows[i-1]
|
||||
live = ['%d' % i, c['hash'], c['short'], c['name'], c['email'], c['date'], c['subject'], '%d' % c['files']]
|
||||
if [r.get(k) for k in ('rank','hash','short','name','email','date','subject','files')] != live:
|
||||
bad_rows += 1
|
||||
if bad_rows <= 3:
|
||||
bad('csv row %d mismatch: %r' % (i, r))
|
||||
if bad_rows == 0:
|
||||
ok('csv field-for-field matches live derivation for all %d rows' % N)
|
||||
|
||||
# 5. JSON rows vs live
|
||||
jrows = json_doc.get('rows', [])
|
||||
if len(jrows) == N:
|
||||
ok('json rows = %d' % len(jrows))
|
||||
else:
|
||||
bad('json rows = %d, expected %d' % (len(jrows), N))
|
||||
jbad = 0
|
||||
for i, c in enumerate(commits, 1):
|
||||
j = jrows[i-1]
|
||||
live = {'hash': c['hash'], 'short': c['short'], 'name': c['name'],
|
||||
'email': c['email'], 'date': c['date'], 'subject': c['subject'],
|
||||
'files': c['files']}
|
||||
if {k: j.get(k) for k in live} != live:
|
||||
jbad += 1
|
||||
if jbad <= 3:
|
||||
bad('json row %d mismatch' % i)
|
||||
if jbad == 0:
|
||||
ok('json rows field-for-field match live derivation for all %d rows' % N)
|
||||
|
||||
# 6. Census
|
||||
if json_doc.get('census') == census:
|
||||
ok('json census matches live derivation (%d authors)' % len(census))
|
||||
else:
|
||||
bad('json census mismatch')
|
||||
|
||||
# 7. Top-50 markdown vs live
|
||||
if len(md_top50) == 50:
|
||||
ok('md top-50 rows = %d' % len(md_top50))
|
||||
else:
|
||||
bad('md top-50 rows = %d, expected 50' % len(md_top50))
|
||||
mismatch = 0
|
||||
for live50 in top50:
|
||||
m = next((x for x in md_top50 if x['rank'] == commits.index(live50) + 1), None)
|
||||
# top50 order == md order
|
||||
if not m or m['hash'] != live50['short'] or m['author'] != live50['name'] or m['date'] != live50['date'] or m['files'] != live50['files']:
|
||||
mismatch += 1
|
||||
if mismatch <= 3:
|
||||
bad('md top-50 row %d mismatch vs live' % live50['rank'])
|
||||
if mismatch == 0:
|
||||
ok('md Top-50 table matches live re-derivation')
|
||||
|
||||
# 8. Root commit present & files count
|
||||
root = json_doc.get('first_commit')
|
||||
if root and git('rev-parse','-q','--verify', root + '^{commit}').strip():
|
||||
ok('root commit present: %s' % root)
|
||||
else:
|
||||
bad('root commit missing from json or not a commit')
|
||||
|
||||
print('')
|
||||
if fails:
|
||||
print('CHECK FAIL: %d check(s) failed.' % len(fails))
|
||||
sys.exit(1)
|
||||
print('CHECK PASS: git commit-history extraction re-derives cleanly against live git.')
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# CHECK — ledger full commit-history extraction (Extract lane, re-derived from git).
|
||||
# Re-derives all headline claims from LIVE `git -C /root/troupe-standup log` and
|
||||
# diffs them against the committed 2026-10-25-git-history.{csv,json,md}.
|
||||
# Exits 0 only when every check matches exactly.
|
||||
set -u
|
||||
OUT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$OUT" || exit 1
|
||||
exec python3 "$OUT/verify_wizards.py" "$@"
|
||||
@@ -0,0 +1,15 @@
|
||||
wizard,date,title,did,blocked,next,ask,total_lines,body_sha256
|
||||
mercury,2026-10-20,2026-10-20 — mercury,0,0,0,0,27,87041e633905a596e167ec0e337bbc2bc78a28dda2bf5ccba5143722620430b7
|
||||
volt,2026-10-20,"Check-in — Volt, 2026-10-20 (01:2x–01:4xZ)",0,0,0,0,137,ad5c82a4b6e7fb3205ed3b1ae608fdeff06d195c7eb3e6d54f9cfd18e48511e8
|
||||
zephyrus,2026-10-20,2026-10-20 — zephyrus check-in,0,0,0,0,21,19e5edb5232a1c48d0495a281c6f0be3f1008f7dd67d038c43dc6007764f3c20
|
||||
mercury,2026-10-21,2026-10-21 — mercury,0,0,0,0,27,488238b6f28cbb9df0c66925b07cb59e3ed16b3103ccfe6aaf3cfe0c052fca75
|
||||
volt,2026-10-21,Volt — 2026-10-21 (Workhorse),0,0,0,0,20,898af0fda33cb510c2adcd445a6d3ec76bdadc31d089144ca32fb02e36c53f4f
|
||||
zephyrus,2026-10-21,2026-10-21 — zephyrus check-in,0,0,0,0,22,c704bf1bf4384f079708d6a1f64984ea2b1696af370a7fa6caca4234db010cdb
|
||||
mercury,2026-10-22,2026-10-22 — mercury,0,0,0,0,28,cc63b334efd40fcf93754dcea098e6429280356a52be6c9ab1cdef924f7d4d6c
|
||||
zephyrus,2026-10-22,2026-10-22 — zephyrus,0,0,0,0,9,7c6d34593861eee49db9f57ad72cc69f7275030f5fa078ae1a10cfa246811bc2
|
||||
mercury,2026-10-23,2026-10-23 — mercury,0,0,0,0,28,33a9f5d5fdacca18850b8fb587bc80265a0cdd78cc6f524068f38c45873ce509
|
||||
volt,2026-10-23,2026-10-23 — volt,0,0,0,0,21,1f771252cfede45e37f38a29b0267bf478fa17d6290172d334178e1ec2db388e
|
||||
zephyrus,2026-10-23,2026-10-23 — zephyrus,0,0,0,0,13,ef28294359a226fc09aca57a0e65c814e000f65a39a5931ef2f11d3516136410
|
||||
mercury,2026-10-24,2026-10-24 — mercury,0,0,0,0,28,50514ef72d4f680a3f0f9912632acefbf3feab84f035692eac0550cd0e17bfd9
|
||||
zephyrus,2026-10-24,2026-10-24 — zephyrus,0,0,0,0,18,00096fd88323a6e627d2619201328de2179c6cab81851f204d5576680da8d248
|
||||
volt,2026-10-25,2026-10-25 — volt,0,0,0,0,28,620ffdb7584664d66d6260676fc6b89b1723e10352a63f757aaa1dbd4dbf6ed1
|
||||
|
Reference in new issue
Block a user