[object Object]

← back to build-pages

seo: BreadcrumbList JSON-LD on commit detail page + 2 smoke

a8b4a3eb65c5b0a5972f20e5cb3d2524426d7659 · 2026-05-13 14:20:46 -0700 · SteveStudio2

Files touched

Diff

commit a8b4a3eb65c5b0a5972f20e5cb3d2524426d7659
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 14:20:46 2026 -0700

    seo: BreadcrumbList JSON-LD on commit detail page + 2 smoke
---
 server.js     | 10 ++++++++++
 test/smoke.js | 11 +++++++++++
 2 files changed, 21 insertions(+)

diff --git a/server.js b/server.js
index 4ee012e..ee62227 100644
--- a/server.js
+++ b/server.js
@@ -477,7 +477,17 @@ app.get('/p/:slug/c/:hash', async (req, res, next) => {
   if (!p) return res.status(404).send(shell('Not found', '<h1>404</h1>'));
   try {
     const c = await commitDetail(p.repo, req.params.hash);
+    const crumbs = {
+      '@context': 'https://schema.org',
+      '@type':    'BreadcrumbList',
+      itemListElement: [
+        { '@type': 'ListItem', position: 1, name: 'build-pages', item: 'https://projects.agentabrams.com/' },
+        { '@type': 'ListItem', position: 2, name: p.name,        item: `https://projects.agentabrams.com/p/${req.params.slug}` },
+        { '@type': 'ListItem', position: 3, name: c.subject.slice(0, 80), item: `https://projects.agentabrams.com/p/${req.params.slug}/c/${req.params.hash}` },
+      ],
+    };
     res.send(shell(`${c.subject} — ${p.name}`, `
+      <script type="application/ld+json">${JSON.stringify(crumbs)}</script>
       <p class="bp-meta"><a href="/p/${esc(req.params.slug)}">← back to ${esc(p.name)}</a></p>
       <h1>${esc(c.subject)}</h1>
       <p class="bp-meta"><code>${esc(c.hash)}</code> · ${esc(c.dateISO)} · ${esc(c.author)}</p>
diff --git a/test/smoke.js b/test/smoke.js
index 142babe..b0af439 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -107,6 +107,17 @@ function check(name, cond, hint = '') {
   check('butlr ?q=: hydrated',     /value="whisper"/.test(r.body));
   check('butlr: SoftwareSourceCode JSON-LD', /"@type":"SoftwareSourceCode"/.test(r.body));
 
+  // 6d. commit detail page — BreadcrumbList JSON-LD
+  // Probe a commit hash that's known to exist via /api/projects/butlr/commits
+  {
+    const c = await fetch('/api/projects/butlr/commits?limit=1');
+    const m = /"hash":"([a-f0-9]+)"/.exec(c.body);
+    const h = m ? m[1] : 'HEAD';
+    r = await fetch(`/p/butlr/c/${h}`);
+    check('commit: 200',             r.status === 200);
+    check('commit: BreadcrumbList',  /"@type":"BreadcrumbList"/.test(r.body));
+  }
+
   // 6c. perf budget — warm render of /p/butlr (cache warmed by the calls above)
   // should land well under 250ms. Cold is ~80ms, warm ~17ms. The 250ms ceiling
   // is generous and only fails on genuine regression (cache broken, git slow).

← 734d442 seo: SoftwareSourceCode JSON-LD on each project page + 1 smo  ·  back to build-pages  ·  smoke: /healthz <50ms perf budget (regression guard for a no f727cc7 →