OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      cf0f1a5d6f13
DATE      2026-07-18
SUBJECT   web: readme falls back to plain text when it defeats the grid, keyvalue
          hard-wraps
FILES     3 CHANGED
HASH      cf0f1a5d6f13
DATE      2026-07-18
SUBJECT   web: readme falls back to plain text
          when it defeats the grid, keyvalue
          hard-wraps
FILES     3 CHANGED
 

diff --git a/ooknet-design/src/components/KeyValue/KeyValue.test.ts b/ooknet-desig
n/src/components/KeyValue/KeyValue.test.ts
index b0f7214..87abedd 100644
--- a/ooknet-design/src/components/KeyValue/KeyValue.test.ts
+++ b/ooknet-design/src/components/KeyValue/KeyValue.test.ts
@@ -3,6 +3,11 @@ import { buildKeyValue } from "./KeyValue";
 import { len } from "../../lib/ascii";
 
 describe("buildKeyValue", () => {
+  it("hard-wraps single tokens wider than the value column", () => {
+    const out = buildKeyValue([["SUBJECT", "feat(hosts:{ooksmedia,ooksdesk,ooknod
e,ookstest})"]], 48);
+    for (const line of out.split("\n")) expect(len(line)).toBeLessThanOrEqual(48)
;
+  });
+
   it("aligns values to the widest key plus gap", () => {
     const out = buildKeyValue([["AUTHOR", "OOKNET"], ["PUBLISHED", "2026-07-16"]]
, 48);
     const lines = out.split("\n");

diff --git a/ooknet-design/src/components/Ke
yValue/KeyValue.test.ts b/ooknet-design/src/
components/KeyValue/KeyValue.test.ts
index b0f7214..87abedd 100644
--- a/ooknet-design/src/components/KeyValue/
KeyValue.test.ts
+++ b/ooknet-design/src/components/KeyValue/
KeyValue.test.ts
@@ -3,6 +3,11 @@ import { buildKeyValue } fr
om "./KeyValue";
 import { len } from "../../lib/ascii";
 
 describe("buildKeyValue", () => {
+  it("hard-wraps single tokens wider than t
he value column", () => {
+    const out = buildKeyValue([["SUBJECT", 
"feat(hosts:{ooksmedia,ooksdesk,ooknode,ooks
test})"]], 48);
+    for (const line of out.split("\n")) exp
ect(len(line)).toBeLessThanOrEqual(48);
+  });
+
   it("aligns values to the widest key plus 
gap", () => {
     const out = buildKeyValue([["AUTHOR", "
OOKNET"], ["PUBLISHED", "2026-07-16"]], 48);
     const lines = out.split("\n");
 

diff --git a/ooknet-design/src/components/KeyValue/KeyValue.ts b/ooknet-design/src
/components/KeyValue/KeyValue.ts
index f6abd4b..2b0d0f4 100644
--- a/ooknet-design/src/components/KeyValue/KeyValue.ts
+++ b/ooknet-design/src/components/KeyValue/KeyValue.ts
@@ -1,6 +1,6 @@
 // Labeled key/value rows with values word-wrapped under their column -
 // the pattern ArticleMeta hand-rolls, as a reusable block.
-import { checkGrid, len, pad, wrap } from "../../lib/ascii";
+import { checkGrid, len, pad, wrapHard } from "../../lib/ascii";
 
 export interface Props {
   entries: [string, string][];
@@ -14,7 +14,7 @@ export function buildKeyValue(entries: [string, string][], width
: number, keyW?:
 
   const lines: string[] = [];
   for (const [key, value] of entries) {
-    wrap(value, valW)
+    wrapHard(value, valW)
       .split("\n")
       .forEach((ln, i) => {
         lines.push(pad(i === 0 ? key : "", kw) + ln);

diff --git a/ooknet-design/src/components/Ke
yValue/KeyValue.ts b/ooknet-design/src/compo
nents/KeyValue/KeyValue.ts
index f6abd4b..2b0d0f4 100644
--- a/ooknet-design/src/components/KeyValue/
KeyValue.ts
+++ b/ooknet-design/src/components/KeyValue/
KeyValue.ts
@@ -1,6 +1,6 @@
 // Labeled key/value rows with values word-
wrapped under their column -
 // the pattern ArticleMeta hand-rolls, as a
 reusable block.
-import { checkGrid, len, pad, wrap } from "
../../lib/ascii";
+import { checkGrid, len, pad, wrapHard } fr
om "../../lib/ascii";
 
 export interface Props {
   entries: [string, string][];
@@ -14,7 +14,7 @@ export function buildKeyVa
lue(entries: [string, string][], width: numb
er, keyW?:
 
   const lines: string[] = [];
   for (const [key, value] of entries) {
-    wrap(value, valW)
+    wrapHard(value, valW)
       .split("\n")
       .forEach((ln, i) => {
         lines.push(pad(i === 0 ? key : "", 
kw) + ln);
 

diff --git a/ooknet-design/src/pages/git/[repo]/index.astro b/ooknet-design/src/pa
ges/git/[repo]/index.astro
index ba0a270..1bd6fad 100644
--- a/ooknet-design/src/pages/git/[repo]/index.astro
+++ b/ooknet-design/src/pages/git/[repo]/index.astro
@@ -6,11 +6,12 @@ import Frame from "../../../components/Frame/Frame.astro";
 import Pre from "../../../components/Pre/Pre.astro";
 import Menu from "../../../components/Menu/Menu.astro";
 import GitListing from "../../../components/GitListing/GitListing.astro";
+import CodeFrame from "../../../components/CodeFrame/CodeFrame.astro";
 import Timeline from "../../../components/Timeline/Timeline.astro";
 import Button from "../../../components/Button/Button.astro";
 import Prose from "../../../components/Prose/Prose.astro";
 import ArticleFooter from "../../../components/ArticleFooter/ArticleFooter.astro"
;
-import { len, row2, ruleD } from "../../../lib/ascii";
+import { len, row2, ruleD, toGrid } from "../../../lib/ascii";
 import { FRAME_W, MOBILE_FRAME_W } from "../../../lib/config";
 import { renderMarkdown } from "../../../lib/markdown";
 import { REPOS } from "../../../git.config";
@@ -29,7 +30,16 @@ const branch = info.branch;
 const entries = dirEntries(repo.path, "", branch);
 const log = repoLog(repo.path, 5, `/git/${repo.slug}/`, branch);
 const readme = readReadme(repo.path, branch);
-const readmeHtml = readme ? renderMarkdown(readme) : null;
+// foreign readmes can defeat the grid (wide tables, exotic markdown);
+// degrade to plain text rather than failing the whole build
+let readmeHtml: string | null = null;
+if (readme) {
+  try {
+    readmeHtml = renderMarkdown(readme);
+  } catch {
+    readmeHtml = null;
+  }
+}
 
 const section = (title: string, right: string) => (w: number) =>
   [row2(title, right, w), ruleD(w)].join("\n");
@@ -85,6 +95,14 @@ const variants: [string, number][] = [
       <Pre>{" "}</Pre>
     </Fragment>
   )}
+  {readme && !readmeHtml && (
+    <Fragment>
+      <Frame build={section("README", "plain - defeats the grid")} />
+      <Pre>{" "}</Pre>
+      <CodeFrame code={toGrid(readme)} label="README.MD" />
+      <Pre>{" "}</Pre>
+    </Fragment>
+  )}
   <Frame build={section("LOG", "most recent first")} />
   <Pre>{" "}</Pre>
   <Timeline entries={log} />

diff --git a/ooknet-design/src/pages/git/[re
po]/index.astro b/ooknet-design/src/pages/gi
t/[repo]/index.astro
index ba0a270..1bd6fad 100644
--- a/ooknet-design/src/pages/git/[repo]/ind
ex.astro
+++ b/ooknet-design/src/pages/git/[repo]/ind
ex.astro
@@ -6,11 +6,12 @@ import Frame from "../../.
./components/Frame/Frame.astro";
 import Pre from "../../../components/Pre/Pr
e.astro";
 import Menu from "../../../components/Menu/
Menu.astro";
 import GitListing from "../../../components
/GitListing/GitListing.astro";
+import CodeFrame from "../../../components/
CodeFrame/CodeFrame.astro";
 import Timeline from "../../../components/T
imeline/Timeline.astro";
 import Button from "../../../components/But
ton/Button.astro";
 import Prose from "../../../components/Pros
e/Prose.astro";
 import ArticleFooter from "../../../compone
nts/ArticleFooter/ArticleFooter.astro";
-import { len, row2, ruleD } from "../../../
lib/ascii";
+import { len, row2, ruleD, toGrid } from ".
./../../lib/ascii";
 import { FRAME_W, MOBILE_FRAME_W } from "..
/../../lib/config";
 import { renderMarkdown } from "../../../li
b/markdown";
 import { REPOS } from "../../../git.config"
;
@@ -29,7 +30,16 @@ const branch = info.branc
h;
 const entries = dirEntries(repo.path, "", b
ranch);
 const log = repoLog(repo.path, 5, `/git/${r
epo.slug}/`, branch);
 const readme = readReadme(repo.path, branch
);
-const readmeHtml = readme ? renderMarkdown(
readme) : null;
+// foreign readmes can defeat the grid (wid
e tables, exotic markdown);
+// degrade to plain text rather than failin
g the whole build
+let readmeHtml: string | null = null;
+if (readme) {
+  try {
+    readmeHtml = renderMarkdown(readme);
+  } catch {
+    readmeHtml = null;
+  }
+}
 
 const section = (title: string, right: stri
ng) => (w: number) =>
   [row2(title, right, w), ruleD(w)].join("\
n");
@@ -85,6 +95,14 @@ const variants: [string, 
number][] = [
       <Pre>{" "}</Pre>
     </Fragment>
   )}
+  {readme && !readmeHtml && (
+    <Fragment>
+      <Frame build={section("README", "plai
n - defeats the grid")} />
+      <Pre>{" "}</Pre>
+      <CodeFrame code={toGrid(readme)} labe
l="README.MD" />
+      <Pre>{" "}</Pre>
+    </Fragment>
+  )}
   <Frame build={section("LOG", "most recent
 first")} />
   <Pre>{" "}</Pre>
   <Timeline entries={log} />
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET