OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      daa02966b6ab
DATE      2026-07-18
SUBJECT   web: oversized commits render a diffstat, not a hundred-megabyte patch
FILES     3 CHANGED
HASH      daa02966b6ab
DATE      2026-07-18
SUBJECT   web: oversized commits render a
          diffstat, not a hundred-megabyte patch
FILES     3 CHANGED
 

diff --git a/ooknet-design/src/lib/git.test.ts b/ooknet-design/src/lib/git.test.ts
index 67ce014..acdda46 100644
--- a/ooknet-design/src/lib/git.test.ts
+++ b/ooknet-design/src/lib/git.test.ts
@@ -1,5 +1,5 @@
 import { describe, expect, it } from "vitest";
-import { branches, excluded, langOf, repoAvailable, repoInfo } from "./git";
+import { branches, excluded, langOf, oversizedNumstat, repoAvailable, repoInfo } 
from "./git";
 import { toGrid } from "./ascii";
 
 describe("toGrid", () => {
@@ -27,6 +27,17 @@ describe("excluded", () => {
   });
 });
 
+describe("oversizedNumstat", () => {
+  it("flags huge patches by lines or file count", () => {
+    expect(oversizedNumstat("3\t1\ta.ts\n10\t2\tb.ts\n")).toBe(false);
+    expect(oversizedNumstat("6000\t0\tbig.json\n")).toBe(true);
+    expect(
+      oversizedNumstat(Array.from({ length: 201 }, (_, i) => `1\t1\tf${i}.json`).
join("\n")),
+    ).toBe(true);
+    expect(oversizedNumstat("-\t-\tbin.png\n")).toBe(false);
+  });
+});
+
 describe("langOf", () => {
   it("maps extensions to frame labels", () => {
     expect(langOf("src/lib/ascii.ts")).toBe("TS");

diff --git a/ooknet-design/src/lib/git.test.
ts b/ooknet-design/src/lib/git.test.ts
index 67ce014..acdda46 100644
--- a/ooknet-design/src/lib/git.test.ts
+++ b/ooknet-design/src/lib/git.test.ts
@@ -1,5 +1,5 @@
 import { describe, expect, it } from "vites
t";
-import { branches, excluded, langOf, repoAv
ailable, repoInfo } from "./git";
+import { branches, excluded, langOf, oversi
zedNumstat, repoAvailable, repoInfo } from "
./git";
 import { toGrid } from "./ascii";
 
 describe("toGrid", () => {
@@ -27,6 +27,17 @@ describe("excluded", () =
> {
   });
 });
 
+describe("oversizedNumstat", () => {
+  it("flags huge patches by lines or file c
ount", () => {
+    expect(oversizedNumstat("3\t1\ta.ts\n10
\t2\tb.ts\n")).toBe(false);
+    expect(oversizedNumstat("6000\t0\tbig.j
son\n")).toBe(true);
+    expect(
+      oversizedNumstat(Array.from({ length:
 201 }, (_, i) => `1\t1\tf${i}.json`).join("
\n")),
+    ).toBe(true);
+    expect(oversizedNumstat("-\t-\tbin.png\
n")).toBe(false);
+  });
+});
+
 describe("langOf", () => {
   it("maps extensions to frame labels", () 
=> {
     expect(langOf("src/lib/ascii.ts")).toBe
("TS");
 

diff --git a/ooknet-design/src/lib/git.ts b/ooknet-design/src/lib/git.ts
index 2fc0879..af62406 100644
--- a/ooknet-design/src/lib/git.ts
+++ b/ooknet-design/src/lib/git.ts
@@ -207,12 +207,38 @@ export interface Commit {
   subject: string;
   body: string;
   files: CommitFile[];
+  /** Set instead of files when the patch is too large to render. */
+  stat?: string;
 }
 
-/** One commit with its patch split per file, github-style. */
+/** True when a numstat says the patch is too big for a page - data
+ *  dumps produce patches in the hundreds of megabytes. */
+export function oversizedNumstat(numstat: string): boolean {
+  const rows = numstat.split("\n").filter(Boolean);
+  let lines = 0;
+  for (const r of rows) {
+    const [a, d] = r.split("\t");
+    lines += (parseInt(a, 10) || 0) + (parseInt(d, 10) || 0);
+  }
+  return rows.length > 200 || lines > 5000;
+}
+
+/** One commit with its patch split per file, github-style. Oversized
+ *  commits carry a diffstat summary instead of patches. */
 export function readCommit(path: string, hash: string): Commit {
   const meta = git(path, ["show", "-s", "--format=%H|%as|%s|%b", hash]).trim();
   const [full, date, subject, ...body] = meta.split("|");
+  const base = {
+    hash: full,
+    date,
+    subject: toGrid(subject),
+    body: toGrid(body.join("|").trim()),
+  };
+  const numstat = git(path, ["show", "--numstat", "--format=", hash]);
+  if (oversizedNumstat(numstat)) {
+    const stat = git(path, ["show", "--stat", "--format=", hash]);
+    return { ...base, files: [], stat: stat.length > MAX_BLOB ? stat.slice(0, MAX
_BLOB) : stat };
+  }
   const patch = git(path, ["show", "--patch", "--format=", hash]);
   const files: CommitFile[] = [];
   for (const chunk of patch.split(/^(?=diff --git )/m)) {
@@ -223,13 +249,7 @@ export function readCommit(path: string, hash: string): Commi
t {
       chunk.length > MAX_BLOB ? chunk.slice(0, MAX_BLOB) + "\n[diff truncated]" :
 chunk;
     files.push({ path: file, diff: trimmed });
   }
-  return {
-    hash: full,
-    date,
-    subject: toGrid(subject),
-    body: toGrid(body.join("|").trim()),
-    files,
-  };
+  return { ...base, files };
 }
 
 /** Frame label for a file: the uppercased extension, same convention

diff --git a/ooknet-design/src/lib/git.ts b/
ooknet-design/src/lib/git.ts
index 2fc0879..af62406 100644
--- a/ooknet-design/src/lib/git.ts
+++ b/ooknet-design/src/lib/git.ts
@@ -207,12 +207,38 @@ export interface Commi
t {
   subject: string;
   body: string;
   files: CommitFile[];
+  /** Set instead of files when the patch i
s too large to render. */
+  stat?: string;
 }
 
-/** One commit with its patch split per fil
e, github-style. */
+/** True when a numstat says the patch is t
oo big for a page - data
+ *  dumps produce patches in the hundreds o
f megabytes. */
+export function oversizedNumstat(numstat: s
tring): boolean {
+  const rows = numstat.split("\n").filter(B
oolean);
+  let lines = 0;
+  for (const r of rows) {
+    const [a, d] = r.split("\t");
+    lines += (parseInt(a, 10) || 0) + (pars
eInt(d, 10) || 0);
+  }
+  return rows.length > 200 || lines > 5000;
+}
+
+/** One commit with its patch split per fil
e, github-style. Oversized
+ *  commits carry a diffstat summary instea
d of patches. */
 export function readCommit(path: string, ha
sh: string): Commit {
   const meta = git(path, ["show", "-s", "--
format=%H|%as|%s|%b", hash]).trim();
   const [full, date, subject, ...body] = me
ta.split("|");
+  const base = {
+    hash: full,
+    date,
+    subject: toGrid(subject),
+    body: toGrid(body.join("|").trim()),
+  };
+  const numstat = git(path, ["show", "--num
stat", "--format=", hash]);
+  if (oversizedNumstat(numstat)) {
+    const stat = git(path, ["show", "--stat
", "--format=", hash]);
+    return { ...base, files: [], stat: stat
.length > MAX_BLOB ? stat.slice(0, MAX_BLOB)
 : stat };
+  }
   const patch = git(path, ["show", "--patch
", "--format=", hash]);
   const files: CommitFile[] = [];
   for (const chunk of patch.split(/^(?=diff
 --git )/m)) {
@@ -223,13 +249,7 @@ export function readCom
mit(path: string, hash: string): Commit {
       chunk.length > MAX_BLOB ? chunk.slice
(0, MAX_BLOB) + "\n[diff truncated]" : chunk
;
     files.push({ path: file, diff: trimmed 
});
   }
-  return {
-    hash: full,
-    date,
-    subject: toGrid(subject),
-    body: toGrid(body.join("|").trim()),
-    files,
-  };
+  return { ...base, files };
 }
 
 /** Frame label for a file: the uppercased 
extension, same convention
 

diff --git a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro b/ooknet-desig
n/src/pages/git/[repo]/commit/[hash].astro
index cf95bad..3c79e93 100644
--- a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro
+++ b/ooknet-design/src/pages/git/[repo]/commit/[hash].astro
@@ -36,7 +36,14 @@ const branch = defaultBranch(repo.path);
     ["FILES", `${commit.files.length} CHANGED`],
   ]} />
   <Pre>{" "}</Pre>
-  {commit.files.map((f) => (
+  {commit.stat ? (
+    <Fragment>
+      <Pre>*** PATCH TOO LARGE - DIFFSTAT ONLY ***</Pre>
+      <Pre>{" "}</Pre>
+      <CodeFrame code={toGrid(commit.stat)} label="DIFFSTAT" />
+      <Pre>{" "}</Pre>
+    </Fragment>
+  ) : commit.files.map((f) => (
     <Fragment>
       <CodeFrame code={toGrid(f.diff)} label={toGrid(f.path)} diff />
       <Pre>{" "}</Pre>

diff --git a/ooknet-design/src/pages/git/[re
po]/commit/[hash].astro b/ooknet-design/src/
pages/git/[repo]/commit/[hash].astro
index cf95bad..3c79e93 100644
--- a/ooknet-design/src/pages/git/[repo]/com
mit/[hash].astro
+++ b/ooknet-design/src/pages/git/[repo]/com
mit/[hash].astro
@@ -36,7 +36,14 @@ const branch = defaultBra
nch(repo.path);
     ["FILES", `${commit.files.length} CHANG
ED`],
   ]} />
   <Pre>{" "}</Pre>
-  {commit.files.map((f) => (
+  {commit.stat ? (
+    <Fragment>
+      <Pre>*** PATCH TOO LARGE - DIFFSTAT O
NLY ***</Pre>
+      <Pre>{" "}</Pre>
+      <CodeFrame code={toGrid(commit.stat)}
 label="DIFFSTAT" />
+      <Pre>{" "}</Pre>
+    </Fragment>
+  ) : commit.files.map((f) => (
     <Fragment>
       <CodeFrame code={toGrid(f.diff)} labe
l={toGrid(f.path)} diff />
       <Pre>{" "}</Pre>
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET