Spaces:
Running
Running
Overlay measured Python source lines on progress chart
Browse filesCount source lines from Git history on a separate right axis, leaving the unavailable initial seed unestimated.
Co-authored-by: Codex <noreply@openai.com>
- README.md +9 -1
- build_progress.py +68 -0
- site/index.html +1 -1
- site/progress.js +11 -1
README.md
CHANGED
|
@@ -33,7 +33,7 @@ Keep local logs and temporary files in `scratch/`, which is ignored by Git.
|
|
| 33 |
Generate the chart snapshot from the leaderboard's v3 cache before starting the app:
|
| 34 |
|
| 35 |
```sh
|
| 36 |
-
python build_progress.py /path/to/swarmchat-leaderboard-v3.json
|
| 37 |
```
|
| 38 |
|
| 39 |
The generated data stays in `scratch/progress.json` and is never committed. Supply
|
|
@@ -43,3 +43,11 @@ It uses the leaderboard's length-penalised percentage metric and latest successf
|
|
| 43 |
1,000-prompt run per revision, with all three SmolLM baselines. The contiguous outage
|
| 44 |
plateau from November 7, 2026, 12:12:47 through 13:15:11 UTC (commit times) is omitted;
|
| 45 |
other score fluctuations and the original revision positions are preserved.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
Generate the chart snapshot from the leaderboard's v3 cache before starting the app:
|
| 34 |
|
| 35 |
```sh
|
| 36 |
+
python build_progress.py /path/to/swarmchat-leaderboard-v3.json --source-repo scratch/v8-history.git
|
| 37 |
```
|
| 38 |
|
| 39 |
The generated data stays in `scratch/progress.json` and is never committed. Supply
|
|
|
|
| 43 |
1,000-prompt run per revision, with all three SmolLM baselines. The contiguous outage
|
| 44 |
plateau from November 7, 2026, 12:12:47 through 13:15:11 UTC (commit times) is omitted;
|
| 45 |
other score fluctuations and the original revision positions are preserved.
|
| 46 |
+
|
| 47 |
+
The right axis overlays physical lines in `bot/**/*.py` at each retained evaluated
|
| 48 |
+
commit, including blank lines and comments but excluding tests. Counts come from
|
| 49 |
+
the source repository's first-parent Git diffs, including deletions and merges.
|
| 50 |
+
Fetch the source history into `scratch/v8-history.git` before building the snapshot;
|
| 51 |
+
unavailable commits get a null code-size value, rather than an estimate. The first
|
| 52 |
+
evaluated seed (`541b8def5107`) predates the current main history and is no longer
|
| 53 |
+
available from the Hub; its win-rate point remains, but its code-size point is absent.
|
build_progress.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
| 3 |
import argparse
|
| 4 |
import json
|
| 5 |
import math
|
|
|
|
| 6 |
from pathlib import Path
|
| 7 |
|
| 8 |
# The abrupt outage plateau, bounded by the last/first affected commit timestamps.
|
|
@@ -12,6 +13,57 @@ OUTAGE_END = "20261107T131511Z"
|
|
| 12 |
MODEL = "HuggingFaceSwarms/SwarmChat-v8"
|
| 13 |
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
def build_progress(cache):
|
| 16 |
latest = {}
|
| 17 |
for path, summary in cache["summaries"].items():
|
|
@@ -51,8 +103,24 @@ def build_progress(cache):
|
|
| 51 |
if __name__ == "__main__":
|
| 52 |
parser = argparse.ArgumentParser(description=__doc__)
|
| 53 |
parser.add_argument("cache", type=Path)
|
|
|
|
|
|
|
| 54 |
args = parser.parse_args()
|
| 55 |
result = build_progress(json.loads(args.cache.read_text()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
output = Path(__file__).parent / "scratch" / "progress.json"
|
| 57 |
output.parent.mkdir(exist_ok=True)
|
| 58 |
output.write_text(json.dumps(result, separators=(",", ":")) + "\n")
|
|
|
|
| 3 |
import argparse
|
| 4 |
import json
|
| 5 |
import math
|
| 6 |
+
import subprocess
|
| 7 |
from pathlib import Path
|
| 8 |
|
| 9 |
# The abrupt outage plateau, bounded by the last/first affected commit timestamps.
|
|
|
|
| 13 |
MODEL = "HuggingFaceSwarms/SwarmChat-v8"
|
| 14 |
|
| 15 |
|
| 16 |
+
def count_source_tree(repository, commit):
|
| 17 |
+
"""Count a source tree directly for evaluated commits outside the main history."""
|
| 18 |
+
tree = subprocess.check_output(
|
| 19 |
+
["git", "-C", str(repository), "ls-tree", "-r", commit, "--", "bot"], text=True)
|
| 20 |
+
objects = [line.split()[2] for line in tree.splitlines() if line.endswith(".py")]
|
| 21 |
+
total = 0
|
| 22 |
+
with subprocess.Popen(["git", "-C", str(repository), "cat-file", "--batch"],
|
| 23 |
+
stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
|
| 24 |
+
for oid in objects:
|
| 25 |
+
process.stdin.write((oid + "\n").encode())
|
| 26 |
+
process.stdin.flush()
|
| 27 |
+
size = int(process.stdout.readline().split()[2])
|
| 28 |
+
blob = process.stdout.read(size)
|
| 29 |
+
process.stdout.read(1)
|
| 30 |
+
total += blob.count(b"\n") + bool(blob and not blob.endswith(b"\n"))
|
| 31 |
+
process.stdin.close()
|
| 32 |
+
if process.wait() != 0:
|
| 33 |
+
raise RuntimeError(f"Could not read source tree for {commit}")
|
| 34 |
+
return total
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def source_line_counts(repository):
|
| 38 |
+
"""Physical lines in bot/**/*.py, including blanks/comments, excluding tests.
|
| 39 |
+
|
| 40 |
+
Accumulate first-parent diffs, including deletions and merge changes. Disabling
|
| 41 |
+
rename detection makes moves across the bot/ boundary count correctly.
|
| 42 |
+
"""
|
| 43 |
+
command = ["git", "-C", str(repository), "log", "--first-parent", "--reverse",
|
| 44 |
+
"--format=commit:%H", "--numstat", "--no-renames",
|
| 45 |
+
"--diff-merges=first-parent", "HEAD"]
|
| 46 |
+
counts, commit, total = {}, None, 0
|
| 47 |
+
with subprocess.Popen(command, stdout=subprocess.PIPE, text=True) as process:
|
| 48 |
+
for line in process.stdout:
|
| 49 |
+
line = line.rstrip("\n")
|
| 50 |
+
if line.startswith("commit:"):
|
| 51 |
+
if commit is not None:
|
| 52 |
+
counts[commit[:12]] = total
|
| 53 |
+
commit = line.removeprefix("commit:")
|
| 54 |
+
elif "\t" in line:
|
| 55 |
+
added, removed, path = line.split("\t", 2)
|
| 56 |
+
if path.startswith("bot/") and path.endswith(".py"):
|
| 57 |
+
if added == "-" or removed == "-":
|
| 58 |
+
raise ValueError(f"Cannot count binary Python file: {path}")
|
| 59 |
+
total += int(added) - int(removed)
|
| 60 |
+
if process.wait() != 0:
|
| 61 |
+
raise RuntimeError("Could not read source history")
|
| 62 |
+
if commit is not None:
|
| 63 |
+
counts[commit[:12]] = total
|
| 64 |
+
return counts
|
| 65 |
+
|
| 66 |
+
|
| 67 |
def build_progress(cache):
|
| 68 |
latest = {}
|
| 69 |
for path, summary in cache["summaries"].items():
|
|
|
|
| 103 |
if __name__ == "__main__":
|
| 104 |
parser = argparse.ArgumentParser(description=__doc__)
|
| 105 |
parser.add_argument("cache", type=Path)
|
| 106 |
+
parser.add_argument("--source-repo", type=Path, required=True,
|
| 107 |
+
help="Git repository containing the evaluated source history")
|
| 108 |
args = parser.parse_args()
|
| 109 |
result = build_progress(json.loads(args.cache.read_text()))
|
| 110 |
+
counts = source_line_counts(args.source_repo)
|
| 111 |
+
missing = []
|
| 112 |
+
for point in result["points"]:
|
| 113 |
+
if point["commit"] not in counts:
|
| 114 |
+
exists = subprocess.run(
|
| 115 |
+
["git", "-C", str(args.source_repo), "cat-file", "-e", point["commit"]],
|
| 116 |
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
|
| 117 |
+
counts[point["commit"]] = count_source_tree(args.source_repo, point["commit"]) if exists else None
|
| 118 |
+
if counts[point["commit"]] is None:
|
| 119 |
+
missing.append(point["commit"])
|
| 120 |
+
point["lines_of_code"] = counts[point["commit"]]
|
| 121 |
+
result["missing_source_commits"] = missing
|
| 122 |
+
if missing:
|
| 123 |
+
print(f"No source available for {len(missing)} commits; leaving code-size gaps: {', '.join(missing)}")
|
| 124 |
output = Path(__file__).parent / "scratch" / "progress.json"
|
| 125 |
output.parent.mkdir(exist_ok=True)
|
| 126 |
output.write_text(json.dumps(result, separators=(",", ":")) + "\n")
|
site/index.html
CHANGED
|
@@ -84,7 +84,7 @@
|
|
| 84 |
<p class="foot">PyBot at commit <a id="commit" target="_blank" rel="noopener"></a>. Click a file to open it on the Hub.</p>
|
| 85 |
<section class="progress" aria-labelledby="progress-title">
|
| 86 |
<h2 id="progress-title">Learning to converse, one revision at a time</h2>
|
| 87 |
-
<div id="progress-chart" role="img" aria-label="
|
| 88 |
<p class="foot" id="progress-status" aria-live="polite">Loading evaluation history…</p>
|
| 89 |
</section>
|
| 90 |
</main>
|
|
|
|
| 84 |
<p class="foot">PyBot at commit <a id="commit" target="_blank" rel="noopener"></a>. Click a file to open it on the Hub.</p>
|
| 85 |
<section class="progress" aria-labelledby="progress-title">
|
| 86 |
<h2 id="progress-title">Learning to converse, one revision at a time</h2>
|
| 87 |
+
<div id="progress-chart" role="img" aria-label="PyBot win rate in orange on the left axis and Python lines of code in blue on the right axis, over evaluated revisions, with three SmolLM baselines"></div>
|
| 88 |
<p class="foot" id="progress-status" aria-live="polite">Loading evaluation history…</p>
|
| 89 |
</section>
|
| 90 |
</main>
|
site/progress.js
CHANGED
|
@@ -12,6 +12,12 @@ async function drawProgress() {
|
|
| 12 |
customdata: points.map(p => p.commit),
|
| 13 |
line: {color: "#eb6834", width: 2},
|
| 14 |
hovertemplate: "PyBot · revision %{x:,}<br>Win rate: %{y:.2f}%<br>Commit %{customdata}<extra></extra>"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
}, ...data.baselines.map((baseline, index) => ({
|
| 16 |
type: "scatter", mode: "lines",
|
| 17 |
name: baseline.name,
|
|
@@ -21,13 +27,17 @@ async function drawProgress() {
|
|
| 21 |
hovertemplate: `${baseline.name}<br>Win rate: %{y:.2f}%<extra></extra>`
|
| 22 |
}))];
|
| 23 |
await Plotly.newPlot("progress-chart", traces, {
|
| 24 |
-
margin: {l: 60, r:
|
| 25 |
paper_bgcolor: "#ffffff", plot_bgcolor: "#ffffff",
|
| 26 |
font: {family: "'Letter Gothic', monospace", size: 12, color: "#000000"},
|
| 27 |
xaxis: {title: {text: "Evaluated revisions", standoff: 12},
|
| 28 |
range: extent, gridcolor: "#eeeeee", zeroline: false, automargin: true},
|
| 29 |
yaxis: {title: {text: "Win rate (%)", standoff: 10}, rangemode: "tozero",
|
|
|
|
| 30 |
gridcolor: "#eeeeee", zerolinecolor: "#dddddd", automargin: true},
|
|
|
|
|
|
|
|
|
|
| 31 |
showlegend: false,
|
| 32 |
annotations: data.baselines.map(baseline => ({
|
| 33 |
text: baseline.name, x: 1, xref: "paper", y: baseline.score, yref: "y",
|
|
|
|
| 12 |
customdata: points.map(p => p.commit),
|
| 13 |
line: {color: "#eb6834", width: 2},
|
| 14 |
hovertemplate: "PyBot · revision %{x:,}<br>Win rate: %{y:.2f}%<br>Commit %{customdata}<extra></extra>"
|
| 15 |
+
}, {
|
| 16 |
+
type: "scatter", mode: "lines", name: "Lines of code", yaxis: "y2",
|
| 17 |
+
x: points.map(p => p.revision), y: points.map(p => p.lines_of_code),
|
| 18 |
+
customdata: points.map(p => p.commit),
|
| 19 |
+
line: {color: "#287a9b", width: 2},
|
| 20 |
+
hovertemplate: "Revision %{x:,}<br>Lines of code: %{y:,}<br>Python source in bot/ (including blanks and comments)<br>Commit %{customdata}<extra></extra>"
|
| 21 |
}, ...data.baselines.map((baseline, index) => ({
|
| 22 |
type: "scatter", mode: "lines",
|
| 23 |
name: baseline.name,
|
|
|
|
| 27 |
hovertemplate: `${baseline.name}<br>Win rate: %{y:.2f}%<extra></extra>`
|
| 28 |
}))];
|
| 29 |
await Plotly.newPlot("progress-chart", traces, {
|
| 30 |
+
margin: {l: 60, r: 72, t: 30, b: 60},
|
| 31 |
paper_bgcolor: "#ffffff", plot_bgcolor: "#ffffff",
|
| 32 |
font: {family: "'Letter Gothic', monospace", size: 12, color: "#000000"},
|
| 33 |
xaxis: {title: {text: "Evaluated revisions", standoff: 12},
|
| 34 |
range: extent, gridcolor: "#eeeeee", zeroline: false, automargin: true},
|
| 35 |
yaxis: {title: {text: "Win rate (%)", standoff: 10}, rangemode: "tozero",
|
| 36 |
+
color: "#eb6834",
|
| 37 |
gridcolor: "#eeeeee", zerolinecolor: "#dddddd", automargin: true},
|
| 38 |
+
yaxis2: {title: {text: "Lines of code", standoff: 10}, overlaying: "y", side: "right",
|
| 39 |
+
rangemode: "tozero", color: "#287a9b", tickformat: "~s",
|
| 40 |
+
showgrid: false, zeroline: false, automargin: true},
|
| 41 |
showlegend: false,
|
| 42 |
annotations: data.baselines.map(baseline => ({
|
| 43 |
text: baseline.name, x: 1, xref: "paper", y: baseline.score, yref: "y",
|