8e72c3b810ef81c69ce002c701ca6c4c02a7ee44
diff --git a/src/c21_app.ts b/src/c21_app.ts
index 00a236b64ac5ef3c51569a4ca3febf0077138674..1edd511e9abd582c3fa549c2fc0ef7509939d0a9 100644
--- a/src/c21_app.ts
+++ b/src/c21_app.ts
@@ -6,7 +6,6 @@ import {
renderPage,
renderNotFound,
htmlResponse,
- escape,
} from "./c51_render_layout.ts";
import { renderDocsPage } from "./c51_render_docs_layout.ts";
import {
@@ -14,37 +13,16 @@ import {
projectRegisterMd,
projectDetailMd,
} from "./c51_render_projects.ts";
-import {
- reportsLandingMd,
- execSummaryMd,
- agentDrilldownMd,
- testsOverviewMd,
-} from "./c51_render_reports.ts";
import {
FORGEJO_URL,
adminApiHeaders,
proxyToForgejo,
} from "./c14_forgejo.ts";
-import {
- fetchProjectConfig,
- fetchRepoTree,
- fetchRepoRawFile,
-} from "./c14_github.ts";
-import { verifySama, type SamaReport } from "./c32_sama_verify.ts";
+import { fetchProjectConfig } from "./c14_github.ts";
import { listGames, loadGame } from "./c31_games.ts";
import { ALL_POSTS } from "./c31_blog.ts";
import { ALL_GUIDES } from "./c31_guides.ts";
import { ALL_SAMA } from "./c31_sama.ts";
-import {
- DEMO_REPORTS,
- DEMO_PERIOD,
- DEMO_ORG,
- DEMO_REPOS,
- DEMO_SNAPSHOTS,
- DEMO_STABILITY,
-} from "./c31_reports_demo.ts";
-import { buildLiveReports } from "./c32_real_reports.ts";
-import { buildLiveTestData } from "./c32_real_tests.ts";
import { parseRepoIdentifier } from "./c31_project_config.ts";
import { judge } from "./c32_judge.ts";
import {
@@ -62,58 +40,27 @@ import { renderRepoView } from "./c21_handlers_repo_view.ts";
import { renderAgentsIndex, renderAgentDetail } from "./c21_handlers_agents.ts";
import { renderLeaderboard } from "./c21_handlers_leaderboard.ts";
import { startGithubOauth, handleGithubCallback } from "./c21_handlers_auth.ts";
+import {
+ reportsLandingHandler,
+ reportsDemoHandler,
+ reportsDemoTestsHandler,
+ reportsDemoAgentHandler,
+ reportsLiveHandler,
+ reportsLiveTestsHandler,
+ reportsLiveAgentHandler,
+} from "./c21_handlers_reports.ts";
+import {
+ skillsSamaMdHandler,
+ samaCliResponse,
+ samaSkillHandler,
+ samaVerifyHandler,
+ samaLandingHandler,
+ samaSlugHandler,
+} from "./c21_handlers_sama.ts";
const HOME_MD = "./content/home.md";
const GAME_DIR = "./content/games";
-// ---------------------------------------------------------------------
-// Reports-context builders. The c51 builders take a ReportsContext —
-// these tiny helpers assemble it for the synthetic /reports/demo and
-// the live /reports/live (real data fetched from syntaxai/tdd.md).
-// ---------------------------------------------------------------------
-
-const LIVE_REPO_OWNER = "syntaxai";
-const LIVE_REPO_NAME = "tdd.md";
-const LIVE_FETCH_COUNT = 100;
-
-const DEMO_BANNER_HTML = `
`;
-
-const LIVE_BANNER_HTML = `live data — sourced from
${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} via the public commits API (5-min cache). Agent attribution comes from
Co-Authored-By: footers; commits without one are excluded. Phase coverage measures % of commits tagged
red:/green:/refactor:.
`;
-
-const demoContext = () => ({
- reports: DEMO_REPORTS,
- period: DEMO_PERIOD,
- scopeLabel: `${DEMO_REPOS} repos · ${DEMO_ORG}`,
- bannerHtml: DEMO_BANNER_HTML,
- narrative: {
- changedHeading: "what changed this quarter",
- changedBody:
- "Cursor's score dropped 15 points after agent-mode became default in March; test-deletion incidents climbed from 2% to 14% of refactor commits, concentrated in the `api-gateway` repo. Claude Code's score rose after a phase-tagged commit prefix was added to CLAUDE.md at the end of January. Aider stays steadily high — auto-commit-per-edit prevents most cross-phase cheating on its own.",
- doingHeading: "what we're doing",
- doingBody:
- "- **Cursor in `api-gateway`**: agent-mode disabled for refactor prompts, CONVENTIONS rule \"never delete a test in a refactor commit\" pinned ([details →](/reports/demo/agents/cursor)).\n- **Roll out Claude Code**: copy the CLAUDE.md template that worked in `billing-service` to the other three repos.\n- **Next reading**: 2026-04-30, mid-Q2, to check whether the Cursor fix holds.",
- },
- footerLinks:
- "[per-agent drill-down: Claude Code](/reports/demo/agents/claude-code) · [Cursor](/reports/demo/agents/cursor) · [Aider](/reports/demo/agents/aider) · [tests overview](/reports/demo/tests) · [back to /reports](/reports)",
-});
-
-const liveContext = async () => {
- const live = await buildLiveReports(LIVE_REPO_OWNER, LIVE_REPO_NAME, LIVE_FETCH_COUNT);
- const period = live.earliest && live.latest
- ? `${live.earliest.slice(0, 10)} → ${live.latest.slice(0, 10)}`
- : "no commits fetched";
- const drillLinks = live.reports
- .map((r) => `[${r.name}](/reports/live/agents/${r.slug})`)
- .join(" · ");
- return {
- reports: live.reports,
- period,
- scopeLabel: `${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} · ${live.totalCommits} commits sampled${live.unknownCount > 0 ? ` (${live.unknownCount} unattributed, excluded)` : ""}`,
- bannerHtml: LIVE_BANNER_HTML,
- footerLinks: `${drillLinks ? drillLinks + " · " : ""}[tests overview](/reports/live/tests) · [demo preview](/reports/demo) · [back to /reports](/reports)`,
- };
-};
-
const HOME_DESCRIPTION =
"Test-driven development for agentic coding. Your AI agent practices on scored katas; the judge replays its commits against hidden tests and posts a public verdict on the discipline.";
@@ -479,119 +426,13 @@ ${rows}
return htmlResponse(html);
},
- "/reports": async () => {
- const html = await renderPage({
- title: "Reports — tdd.md",
- description: "Per-agent TDD-discipline reporting over real project repos: trend, failure-mode breakdown, and an exec summary fit for a quarterly readout.",
- bodyMarkdown: reportsLandingMd(),
- ogPath: "https://tdd.md/reports",
- noindex: true,
- });
- return htmlResponse(html);
- },
-
- "/reports/demo": async () => {
- const ctx = demoContext();
- const html = await renderPage({
- title: "TDD-discipline report · Q1 2026 (demo) — tdd.md",
- description: "Mockup of the management-level TDD-discipline report — single page, three agents, with trend and narrative.",
- bodyMarkdown: execSummaryMd(ctx),
- ogPath: "https://tdd.md/reports/demo",
- noindex: true,
- });
- return htmlResponse(html);
- },
-
- "/reports/demo/tests": async () => {
- const html = await renderPage({
- title: "Tests overview (demo) — tdd.md",
- description: "Mockup of the per-test overview: current pass/fail snapshot per repo plus test stability over the quarter.",
- bodyMarkdown: testsOverviewMd({
- period: DEMO_PERIOD,
- bannerHtml: DEMO_BANNER_HTML,
- snapshots: DEMO_SNAPSHOTS,
- stability: DEMO_STABILITY,
- }),
- ogPath: "https://tdd.md/reports/demo/tests",
- noindex: true,
- });
- return htmlResponse(html);
- },
-
- "/reports/demo/agents/:slug": async (req) => {
- const slug = req.params.slug as (typeof DEMO_REPORTS)[number]["slug"];
- const ctx = demoContext();
- const md = agentDrilldownMd(slug, ctx);
- if (!md) {
- const html = await renderNotFound(`/reports/demo/agents/${slug}`);
- return htmlResponse(html, 404);
- }
- const entry = DEMO_REPORTS.find((r) => r.slug === slug)!;
- const html = await renderPage({
- title: `${entry.name} drill-down (demo) — tdd.md`,
- description: `Per-agent drill-down mockup for ${entry.name}: trend, failure-mode breakdown, recent flagged commits with coaching links.`,
- bodyMarkdown: md,
- ogPath: `https://tdd.md/reports/demo/agents/${slug}`,
- noindex: true,
- });
- return htmlResponse(html);
- },
-
- "/reports/live": async () => {
- const ctx = await liveContext();
- const html = await renderPage({
- title: "TDD-discipline report · live — tdd.md",
- description: `Live discipline report built from the real commit history of syntaxai/tdd.md (last ${LIVE_FETCH_COUNT} commits, 5-min cache).`,
- bodyMarkdown: execSummaryMd(ctx),
- ogPath: "https://tdd.md/reports/live",
- noindex: true,
- });
- return htmlResponse(html);
- },
-
- "/reports/live/tests": async () => {
- const data = await buildLiveTestData(LIVE_REPO_OWNER, LIVE_REPO_NAME);
- const ranOn = data.ranAt ? new Date(data.ranAt).toISOString().slice(0, 10) : null;
- const period = data.runsCount === 0
- ? "no runs in bundle"
- : `last run ${ranOn} · ${data.runsCount} run${data.runsCount === 1 ? "" : "s"} cumulative`;
- const unavailableNote = data.runsCount === 0
- ? "No test runs bundled yet. The next deploy will run `bun test --reporter=junit` on the current HEAD and publish the result here. Stability (flaky %, deletion) builds up as more runs land in the bundle — the demo at [/reports/demo/tests](/reports/demo/tests) shows where this is heading."
- : undefined;
- const html = await renderPage({
- title: "Tests overview · live — tdd.md",
- description: `Live test snapshot of ${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} — ${data.runsCount} run${data.runsCount === 1 ? "" : "s"} bundled.`,
- bodyMarkdown: testsOverviewMd({
- period,
- bannerHtml: LIVE_BANNER_HTML,
- snapshots: data.snapshots,
- stability: data.stability,
- unavailableNote,
- placeholderTests: data.placeholderTests,
- }),
- ogPath: "https://tdd.md/reports/live/tests",
- });
- return htmlResponse(html);
- },
-
- "/reports/live/agents/:slug": async (req) => {
- const ctx = await liveContext();
- const slug = req.params.slug as (typeof DEMO_REPORTS)[number]["slug"];
- const md = agentDrilldownMd(slug, ctx);
- if (!md) {
- const html = await renderNotFound(`/reports/live/agents/${slug}`);
- return htmlResponse(html, 404);
- }
- const entry = ctx.reports.find((r) => r.slug === slug)!;
- const html = await renderPage({
- title: `${entry.name} drill-down · live — tdd.md`,
- description: `Live drill-down for ${entry.name} on syntaxai/tdd.md — trend, failure-mode breakdown, recent commits.`,
- bodyMarkdown: md,
- ogPath: `https://tdd.md/reports/live/agents/${slug}`,
- noindex: true,
- });
- return htmlResponse(html);
- },
+ "/reports": reportsLandingHandler,
+ "/reports/demo": reportsDemoHandler,
+ "/reports/demo/tests": reportsDemoTestsHandler,
+ "/reports/demo/agents/:slug": reportsDemoAgentHandler,
+ "/reports/live": reportsLiveHandler,
+ "/reports/live/tests": reportsLiveTestsHandler,
+ "/reports/live/agents/:slug": reportsLiveAgentHandler,
"/guides": async () => {
const rows = ALL_GUIDES
@@ -645,352 +486,16 @@ ${rows}
return htmlResponse(html);
},
- "/skills/sama.md": async () => {
- const md = await Bun.file("./content/sama/skill.md").text();
- return new Response(md, {
- headers: {
- "Content-Type": "text/markdown; charset=utf-8",
- "Cache-Control": "public, max-age=300",
- },
- });
- },
-
- "/tools/sama-cli": new Response(Bun.file("./public/sama-cli"), {
- headers: {
- // text/javascript so browsers preview as code; the shebang at
- // line 1 makes the file directly executable once chmod +x'd.
- "Content-Type": "text/javascript; charset=utf-8",
- "Content-Disposition": 'inline; filename="sama"',
- "Cache-Control": "public, max-age=300",
- },
- }),
-
- "/sama/skill": async () => {
- const raw = await Bun.file("./content/sama/skill.md").text();
- // Strip the YAML frontmatter for the HTML render — the .md raw
- // download keeps it (that's the agent-installable format).
- const stripped = raw.replace(/^---\n[\s\S]*?\n---\n+/, "");
- const installNote = `> **Drop into your agent.** Save the raw markdown to your skills directory:
->
-> \`\`\`bash
-> mkdir -p ~/.claude/skills
-> curl -fsSL https://tdd.md/skills/sama.md -o ~/.claude/skills/sama.md
-> \`\`\`
->
-> The frontmatter at the top of the file (\`name\`, \`description\`) is what your agent's loader keys off — don't edit it. [View raw markdown →](/skills/sama.md)
-`;
- const body = `${installNote}\n\n${stripped}\n\n---\n\n[← /sama](/sama) · [the four disciplines](/sama) · [back to tdd.md](/)\n`;
- const html = await renderDocsPage({
- title: "SAMA skill — drop into your agent — tdd.md",
- description: "An obra/superpowers-style SKILL.md for the SAMA file-naming convention. Save it to ~/.claude/skills/sama.md and your agent will load the layer-prefix discipline on demand.",
- bodyMarkdown: body,
- ogPath: "https://tdd.md/sama/skill",
- active: "sama",
- pathForDocs: "/sama/skill",
- });
- return htmlResponse(html);
- },
-
- "/sama/verify": async (req) => {
- const url = new URL(req.url);
- const repoArg = (url.searchParams.get("repo") ?? "").trim();
- const formMd = `# SAMA verify
-
-> Paste a public GitHub repo. tdd.md will run the four [SAMA disciplines](/sama) against the default branch — *Sorted* (lower never imports higher), *Architecture* (known layer prefixes), *Modeled* (sibling tests, types in c31_*), *Atomic* (~700-line split + placeholder-test detection) — and return a report. No clone, no token; just one tree-listing API call plus raw-content reads. Cached for an hour per repo.
-
-
-
-Try it on this site: [\`syntaxai/tdd.md\`](/sama/verify?repo=syntaxai/tdd.md) · or any public repo of your own.
-
-Limits: anonymous GitHub API quota is 60 requests/hour per IP. Each verify uses one tree-listing call; the rest of the work goes through raw.githubusercontent.com (uncapped). If the verifier returns "rate limit", come back later or use a token-authenticated proxy.
-
-[← /sama](/sama)
-`;
-
- if (!repoArg) {
- const html = await renderDocsPage({
- title: "SAMA verify — tdd.md",
- description: "Paste a public GitHub repo, get the four SAMA disciplines verified mechanically: sorted (lower never imports higher), architecture (known layer prefixes), modeled (sibling tests), atomic (700-line + placeholder-test detection).",
- bodyMarkdown: formMd,
- ogPath: "https://tdd.md/sama/verify",
- active: "sama",
- pathForDocs: "/sama/verify",
- });
- return htmlResponse(html);
- }
-
- const m = /^([^\/\s]+)\/([^\/\s]+)$/.exec(repoArg);
- if (!m) {
- const html = await renderDocsPage({
- title: "SAMA verify · bad input — tdd.md",
- description: "SAMA verify expects an owner/name repo identifier.",
- bodyMarkdown: `# SAMA verify\n\n> Couldn't parse \`${repoArg}\`. Use the form: \`owner/name\`.\n\n[← back](/sama/verify)\n`,
- pathForDocs: "/sama/verify",
- editPathOverride: null,
- ogPath: "https://tdd.md/sama/verify",
- active: "sama",
- noindex: true,
- });
- return htmlResponse(html, 400);
- }
-
- const [, owner, name] = m;
- let report: SamaReport;
- try {
- // Dogfood short-circuit: tdd.md is a private repo, so the GitHub
- // API can't see it. When asked to verify ourselves, read the
- // source from the bundled `./src/` directory inside the container.
- // Same checks, same shape, same code path downstream.
- const isSelf = owner === LIVE_REPO_OWNER && name === LIVE_REPO_NAME;
- if (isSelf) {
- const { readdirSync, readFileSync } = await import("node:fs");
- const srcDir = "./src";
- const tsFiles = readdirSync(srcDir, { withFileTypes: true })
- .filter((e) => e.isFile() && e.name.endsWith(".ts"))
- .map((e) => e.name)
- .sort();
- const contents = new Map();
- for (const f of tsFiles) {
- if (/^c\d{2}_/.test(f)) {
- contents.set(f, readFileSync(`${srcDir}/${f}`, "utf8"));
- }
- }
- report = verifySama({
- repoOwner: owner!,
- repoName: name!,
- defaultBranch: "main",
- srcPaths: tsFiles,
- contents,
- });
- } else {
- const tree = await fetchRepoTree(owner!, name!);
- const srcEntries = tree.entries
- .filter((e) => e.type === "blob" && e.path.startsWith("src/") && e.path.endsWith(".ts"))
- .slice(0, 200);
- const srcPaths = srcEntries.map((e) => e.path.slice("src/".length));
- const samaPaths = srcPaths.filter((p) => /^c\d{2}_/.test(p));
- const contents = new Map();
- const fetches = await Promise.all(
- samaPaths.map(async (p) => [p, await fetchRepoRawFile(owner!, name!, tree.defaultBranch, `src/${p}`)] as const),
- );
- for (const [p, c] of fetches) {
- if (c !== null) contents.set(p, c);
- }
- report = verifySama({
- repoOwner: owner!,
- repoName: name!,
- defaultBranch: tree.defaultBranch,
- srcPaths,
- contents,
- });
- }
- } catch (e) {
- const msg = e instanceof Error ? e.message : String(e);
- const html = await renderDocsPage({
- title: `SAMA verify · ${owner}/${name} · error — tdd.md`,
- description: `SAMA verify could not inspect ${owner}/${name}.`,
- bodyMarkdown: `# SAMA verify · \`${owner}/${name}\`\n\n> Couldn't fetch the repo: ${escape(msg)}\n\nMost common causes: the repo is private, the name is wrong, or you've hit GitHub's anonymous rate limit (60/hour). [← try another repo](/sama/verify)\n`,
- ogPath: `https://tdd.md/sama/verify?repo=${owner}/${name}`,
- active: "sama",
- noindex: true,
- pathForDocs: "/sama/verify",
- editPathOverride: null,
- });
- return htmlResponse(html, 502);
- }
-
- const summary = report.overallPassed
- ? `> ✓ All four checks passed for [\`${report.repoSlug}\`](https://github.com/${report.repoSlug}) on \`${report.defaultBranch}\` (${report.samaFiles} SAMA files / ${report.testFiles} tests / ${report.totalSrcFiles} total in src/).`
- : `> ⚠ ${report.checks.filter((c) => !c.passed).length} of 4 checks failed for [\`${report.repoSlug}\`](https://github.com/${report.repoSlug}) on \`${report.defaultBranch}\`.`;
- const checkBlocks = report.checks
- .map((c) => {
- const status = c.passed ? "✓ pass" : `✗ ${c.violations.length} violation${c.violations.length === 1 ? "" : "s"}`;
- const violationsBlock = c.violations.length === 0
- ? ""
- : `\n\n${c.violations.slice(0, 20).map((v) => `- \`${escape(v.file)}\` — ${escape(v.detail)}`).join("\n")}${c.violations.length > 20 ? `\n- _...and ${c.violations.length - 20} more_` : ""}`;
- const noteBlock = c.note ? `\n\n_${escape(c.note)}_` : "";
- return `### ${c.letter} — ${c.property} · ${status}\n\nExamined ${c.examined} file${c.examined === 1 ? "" : "s"}.${violationsBlock}${noteBlock}`;
- })
- .join("\n\n");
- const reportMd = `# SAMA verify · \`${report.repoSlug}\`
-
-${summary}
-
-${checkBlocks}
-
----
-
-[← verify another repo](/sama/verify) · [the four SAMA disciplines →](/sama) · [SAMA skill for your agent →](/sama/skill)
-`;
- const html = await renderDocsPage({
- title: `SAMA verify · ${report.repoSlug} — tdd.md`,
- description: `SAMA verification for ${report.repoSlug}: ${report.overallPassed ? "all four checks passed" : `${report.checks.filter((c) => !c.passed).length}/4 checks failed`}.`,
- bodyMarkdown: reportMd,
- ogPath: `https://tdd.md/sama/verify?repo=${report.repoSlug}`,
- active: "sama",
- pathForDocs: "/sama/verify",
- editPathOverride: null,
- });
- return htmlResponse(html);
- },
-
- "/sama": async () => {
- const rows = ALL_SAMA
- .map((d) => `| **[${d.letter} — ${d.title}](/sama/${d.slug})** | ${d.rule} |`)
- .join("\n");
- const body = `# SAMA
-
-> **Sorted, Architecture, Modeled, Atomic.** Four properties of a codebase that an AI agent can navigate, change, and verify without drift. The acronym is the rule set; each letter has a one-paragraph definition and a verification you can run.
-
-This is the file-naming and module-organisation convention this site is built on, shared across two other projects in my workspace. It exists to give an AI agent **one obvious place** for every change — and one mechanical check for every layer rule.
-
-## the four disciplines
-
-| letter | discipline | one-line rule |
-|---|---|---|
-${rows}
-
-## reading order
-
-If you're new to this:
-1. Start with **[Sorted](/sama/sorted)** — it has the verification grep that everything else is built around.
-2. Then **[Architecture](/sama/architecture)** — what each layer prefix means.
-3. Then **[Modeled](/sama/modeled)** — where types and tests live.
-4. Then **[Atomic](/sama/atomic)** — the split rule that keeps the rest honest as the codebase grows.
-
-Each page is short, opinionated, and ends with the common mistakes you'll see if the discipline lapses.
-
-## drop into your agent
-
-For agents that load skills from \`~/.claude/skills/\` (Claude Code, obra/superpowers, etc.), grab the SKILL.md version:
-
-\`\`\`bash
-mkdir -p ~/.claude/skills
-curl -fsSL https://tdd.md/skills/sama.md -o ~/.claude/skills/sama.md
-\`\`\`
-
-The skill is the same content as the four pages here, written in obra/superpowers SKILL.md format with frontmatter, an iron-rule statement, and a verification checklist your agent can run before merging. **[Read it formatted →](/sama/skill)** · **[Raw markdown →](/skills/sama.md)**
-
-## verify any public repo
-
-Want to know whether a repo follows SAMA without reading its source? Paste the \`owner/name\` and tdd.md will run all four checks against the default branch — *Sorted* (the import-direction grep), *Architecture* (known layer prefixes), *Modeled* (sibling tests), *Atomic* (700-line + placeholder-test detection). Pass/fail per discipline, with violation lists. **[verify a repo on the web →](/sama/verify)** · or try it on this site: [\`syntaxai/tdd.md\`](/sama/verify?repo=syntaxai/tdd.md).
-
-## the \`sama\` CLI
+ "/skills/sama.md": skillsSamaMdHandler,
+ "/tools/sama-cli": samaCliResponse(),
-The web verifier is good for ad-hoc checks. For CI and pre-commit, install the standalone CLI — same checks, no network needed for local repos:
+ "/sama/skill": samaSkillHandler,
-\`\`\`bash
-mkdir -p ~/.local/bin
-curl -fsSL https://tdd.md/tools/sama-cli -o ~/.local/bin/sama
-chmod +x ~/.local/bin/sama
-sama --help
-\`\`\`
+ "/sama/verify": samaVerifyHandler,
-Two subcommands:
+ "/sama": samaLandingHandler,
-\`\`\`bash
-sama check # verify the current repo's src/
-sama check --json # JSON output for piping into CI tooling
-sama verify-repo owner/name # verify a public GitHub repo (no token)
-\`\`\`
-
-Exit codes: \`0\` on pass, \`1\` if any check fails, \`2\` on error. The CLI is a single Bun bundle (~14 KB). [Bun](https://bun.sh) needs to be on \`PATH\`.
-
-### pre-commit hook
-
-Add to \`.git/hooks/pre-commit\` (or via \`husky\`, \`pre-commit\`, \`lefthook\`):
-
-\`\`\`bash
-#!/usr/bin/env bash
-# Block commits that violate SAMA layer/atomic/modeled rules.
-exec sama check
-\`\`\`
-
-### GitHub Action
-
-\`\`\`yaml
-# .github/workflows/sama.yml
-name: sama
-on: [push, pull_request]
-jobs:
- verify:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: oven-sh/setup-bun@v2
- - run: |
- curl -fsSL https://tdd.md/tools/sama-cli -o sama
- chmod +x sama
- ./sama check
-\`\`\`
-
-If the rule lives in a hook or an action that fails the build, the harness can't talk the agent out of it. That is the whole point of the [corpus post](/blog/agentic-coding-corpus-three-patterns) and the next step from the [from-rules-to-checks](/blog/from-rules-to-checks) wrap-up.
-
-## the case behind it
-
-Two long-form pieces that argue *why* SAMA is shaped this way:
-
-- [**The Claude Code harness postmortem read through TDD + SAMA**](/blog/claude-code-harness-postmortem) — ThePaSch's r/ClaudeAI audit (40+ hidden reminders, 5 gag-order sites, 158 prompt versions in 11 days) read against the iron law and the verification grep. *The harness is loud; the diff doesn't have to be.*
-- [**Three patterns ten threads converge on**](/blog/agentic-coding-corpus-three-patterns) — a six-month corpus of r/ClaudeAI, r/ClaudeCode, r/AgentsOfAI failure-mode threads. Per-pattern mitigation tables map each thread to the SAMA / iron-law rule that catches or prevents it.
-
-If you're reading these for the first time, the order to take them is harness postmortem → corpus → back here.
-
-## why these four together
-
-Each property fixes a different failure mode:
-
-- *Sorted* fails when imports go in any direction → grep proves the rule.
-- *Architecture* fails when responsibilities blur → the prefix is the contract.
-- *Modeled* fails when types and tests scatter → siblings are mandatory.
-- *Atomic* fails when files swell → the ~700-line split keeps atoms small.
-
-Pick one and you'll claw back some clarity. Pick all four and the codebase becomes the kind an agent can be left alone with — there is exactly one right place for any change, and a one-line shell command that proves the layer rule.
-
-The blog post [*Red, tokens, atoms*](/blog/three-constraints-agentic-coding) argues SAMA also compounds with TDD and Claude Code's token-saving discipline; the four properties on this page are the *Atomic* / *Modeled* / *Architecture* / *Sorted* halves of that story.
-
-[← back to tdd.md](/) · [the blog](/blog) · [the guides](/guides)
-`;
- const html = await renderDocsPage({
- title: "SAMA — sorted, architecture, modeled, atomic — tdd.md",
- description: "SAMA is a four-property file-naming and module convention for codebases that AI agents work in: sorted by layer prefix, architecture as a contract, models with siblings, atomic files. One page per discipline.",
- bodyMarkdown: body,
- ogPath: "https://tdd.md/sama",
- active: "sama",
- pathForDocs: "/sama",
- editPathOverride: null,
- });
- return htmlResponse(html);
- },
-
- "/sama/:slug": async (req) => {
- const slug = req.params.slug;
- const entry = ALL_SAMA.find((d) => d.slug === slug);
- if (!entry) {
- const html = await renderNotFound(`/sama/${slug}`);
- return htmlResponse(html, 404);
- }
- const file = Bun.file(`./content/sama/${slug}.md`);
- if (!(await file.exists())) {
- const html = await renderNotFound(`/sama/${slug}`);
- return htmlResponse(html, 404);
- }
- const md = await file.text();
- const html = await renderDocsPage({
- title: `SAMA · ${entry.letter} — ${entry.title} — tdd.md`,
- description: entry.description,
- bodyMarkdown: md,
- ogPath: `https://tdd.md/sama/${slug}`,
- active: "sama",
- pathForDocs: `/sama/${slug}`,
- });
- return htmlResponse(html);
- },
+ "/sama/:slug": samaSlugHandler,
"/games/:kata": async (req) => {
const res = await renderKata(req.params.kata);
diff --git a/src/c21_handlers_reports.ts b/src/c21_handlers_reports.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea3b65998d679daba7a367e064493bd6b2d02519
--- /dev/null
+++ b/src/c21_handlers_reports.ts
@@ -0,0 +1,190 @@
+// c21 — handlers: the /reports cluster. Demo mockup pages plus the
+// live readout assembled from the deploy-time commit + test bundles.
+// Extracted from c21_app.ts per the SAMA Atomic rule.
+
+import {
+ renderPage,
+ renderNotFound,
+ htmlResponse,
+} from "./c51_render_layout.ts";
+import {
+ reportsLandingMd,
+ execSummaryMd,
+ agentDrilldownMd,
+ testsOverviewMd,
+} from "./c51_render_reports.ts";
+import {
+ DEMO_REPORTS,
+ DEMO_PERIOD,
+ DEMO_ORG,
+ DEMO_REPOS,
+ DEMO_SNAPSHOTS,
+ DEMO_STABILITY,
+} from "./c31_reports_demo.ts";
+import { buildLiveReports } from "./c32_real_reports.ts";
+import { buildLiveTestData } from "./c32_real_tests.ts";
+import {
+ LIVE_REPO_OWNER,
+ LIVE_REPO_NAME,
+ LIVE_FETCH_COUNT,
+} from "./c31_site_config.ts";
+
+// -------- shared banners + context builders --------
+
+const DEMO_BANNER_HTML = ``;
+
+const LIVE_BANNER_HTML = `live data — sourced from
${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} via the public commits API (5-min cache). Agent attribution comes from
Co-Authored-By: footers; commits without one are excluded. Phase coverage measures % of commits tagged
red:/green:/refactor:.
`;
+
+const demoContext = () => ({
+ reports: DEMO_REPORTS,
+ period: DEMO_PERIOD,
+ scopeLabel: `${DEMO_REPOS} repos · ${DEMO_ORG}`,
+ bannerHtml: DEMO_BANNER_HTML,
+ narrative: {
+ changedHeading: "what changed this quarter",
+ changedBody:
+ "Cursor's score dropped 15 points after agent-mode became default in March; test-deletion incidents climbed from 2% to 14% of refactor commits, concentrated in the `api-gateway` repo. Claude Code's score rose after a phase-tagged commit prefix was added to CLAUDE.md at the end of January. Aider stays steadily high — auto-commit-per-edit prevents most cross-phase cheating on its own.",
+ doingHeading: "what we're doing",
+ doingBody:
+ "- **Cursor in `api-gateway`**: agent-mode disabled for refactor prompts, CONVENTIONS rule \"never delete a test in a refactor commit\" pinned ([details →](/reports/demo/agents/cursor)).\n- **Roll out Claude Code**: copy the CLAUDE.md template that worked in `billing-service` to the other three repos.\n- **Next reading**: 2026-04-30, mid-Q2, to check whether the Cursor fix holds.",
+ },
+ footerLinks:
+ "[per-agent drill-down: Claude Code](/reports/demo/agents/claude-code) · [Cursor](/reports/demo/agents/cursor) · [Aider](/reports/demo/agents/aider) · [tests overview](/reports/demo/tests) · [back to /reports](/reports)",
+});
+
+const liveContext = async () => {
+ const live = await buildLiveReports(LIVE_REPO_OWNER, LIVE_REPO_NAME, LIVE_FETCH_COUNT);
+ const period = live.earliest && live.latest
+ ? `${live.earliest.slice(0, 10)} → ${live.latest.slice(0, 10)}`
+ : "no commits fetched";
+ const drillLinks = live.reports
+ .map((r) => `[${r.name}](/reports/live/agents/${r.slug})`)
+ .join(" · ");
+ return {
+ reports: live.reports,
+ period,
+ scopeLabel: `${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} · ${live.totalCommits} commits sampled${live.unknownCount > 0 ? ` (${live.unknownCount} unattributed, excluded)` : ""}`,
+ bannerHtml: LIVE_BANNER_HTML,
+ footerLinks: `${drillLinks ? drillLinks + " · " : ""}[tests overview](/reports/live/tests) · [demo preview](/reports/demo) · [back to /reports](/reports)`,
+ };
+};
+
+// -------- /reports landing --------
+
+export const reportsLandingHandler = async (): Promise => {
+ const html = await renderPage({
+ title: "Reports — tdd.md",
+ description: "Per-agent TDD-discipline reporting over real project repos: trend, failure-mode breakdown, and an exec summary fit for a quarterly readout.",
+ bodyMarkdown: reportsLandingMd(),
+ ogPath: "https://tdd.md/reports",
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
+
+// -------- /reports/demo --------
+
+export const reportsDemoHandler = async (): Promise => {
+ const ctx = demoContext();
+ const html = await renderPage({
+ title: "TDD-discipline report · Q1 2026 (demo) — tdd.md",
+ description: "Mockup of the management-level TDD-discipline report — single page, three agents, with trend and narrative.",
+ bodyMarkdown: execSummaryMd(ctx),
+ ogPath: "https://tdd.md/reports/demo",
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
+
+export const reportsDemoTestsHandler = async (): Promise => {
+ const html = await renderPage({
+ title: "Tests overview (demo) — tdd.md",
+ description: "Mockup of the per-test overview: current pass/fail snapshot per repo plus test stability over the quarter.",
+ bodyMarkdown: testsOverviewMd({
+ period: DEMO_PERIOD,
+ bannerHtml: DEMO_BANNER_HTML,
+ snapshots: DEMO_SNAPSHOTS,
+ stability: DEMO_STABILITY,
+ }),
+ ogPath: "https://tdd.md/reports/demo/tests",
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
+
+export const reportsDemoAgentHandler = async (req: { params: { slug: string } }): Promise => {
+ const slug = req.params.slug as (typeof DEMO_REPORTS)[number]["slug"];
+ const ctx = demoContext();
+ const md = agentDrilldownMd(slug, ctx);
+ if (!md) {
+ const html = await renderNotFound(`/reports/demo/agents/${slug}`);
+ return htmlResponse(html, 404);
+ }
+ const entry = DEMO_REPORTS.find((r) => r.slug === slug)!;
+ const html = await renderPage({
+ title: `${entry.name} drill-down (demo) — tdd.md`,
+ description: `Per-agent drill-down mockup for ${entry.name}: trend, failure-mode breakdown, recent flagged commits with coaching links.`,
+ bodyMarkdown: md,
+ ogPath: `https://tdd.md/reports/demo/agents/${slug}`,
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
+
+// -------- /reports/live --------
+
+export const reportsLiveHandler = async (): Promise => {
+ const ctx = await liveContext();
+ const html = await renderPage({
+ title: "TDD-discipline report · live — tdd.md",
+ description: `Live discipline report built from the real commit history of syntaxai/tdd.md (last ${LIVE_FETCH_COUNT} commits, 5-min cache).`,
+ bodyMarkdown: execSummaryMd(ctx),
+ ogPath: "https://tdd.md/reports/live",
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
+
+export const reportsLiveTestsHandler = async (): Promise => {
+ const data = await buildLiveTestData(LIVE_REPO_OWNER, LIVE_REPO_NAME);
+ const ranOn = data.ranAt ? new Date(data.ranAt).toISOString().slice(0, 10) : null;
+ const period = data.runsCount === 0
+ ? "no runs in bundle"
+ : `last run ${ranOn} · ${data.runsCount} run${data.runsCount === 1 ? "" : "s"} cumulative`;
+ const unavailableNote = data.runsCount === 0
+ ? "No test runs bundled yet. The next deploy will run `bun test --reporter=junit` on the current HEAD and publish the result here. Stability (flaky %, deletion) builds up as more runs land in the bundle — the demo at [/reports/demo/tests](/reports/demo/tests) shows where this is heading."
+ : undefined;
+ const html = await renderPage({
+ title: "Tests overview · live — tdd.md",
+ description: `Live test snapshot of ${LIVE_REPO_OWNER}/${LIVE_REPO_NAME} — ${data.runsCount} run${data.runsCount === 1 ? "" : "s"} bundled.`,
+ bodyMarkdown: testsOverviewMd({
+ period,
+ bannerHtml: LIVE_BANNER_HTML,
+ snapshots: data.snapshots,
+ stability: data.stability,
+ unavailableNote,
+ placeholderTests: data.placeholderTests,
+ }),
+ ogPath: "https://tdd.md/reports/live/tests",
+ });
+ return htmlResponse(html);
+};
+
+export const reportsLiveAgentHandler = async (req: { params: { slug: string } }): Promise => {
+ const ctx = await liveContext();
+ const slug = req.params.slug as (typeof DEMO_REPORTS)[number]["slug"];
+ const md = agentDrilldownMd(slug, ctx);
+ if (!md) {
+ const html = await renderNotFound(`/reports/live/agents/${slug}`);
+ return htmlResponse(html, 404);
+ }
+ const entry = ctx.reports.find((r) => r.slug === slug)!;
+ const html = await renderPage({
+ title: `${entry.name} drill-down · live — tdd.md`,
+ description: `Live drill-down for ${entry.name} on syntaxai/tdd.md — trend, failure-mode breakdown, recent commits.`,
+ bodyMarkdown: md,
+ ogPath: `https://tdd.md/reports/live/agents/${slug}`,
+ noindex: true,
+ });
+ return htmlResponse(html);
+};
diff --git a/src/c21_handlers_sama.ts b/src/c21_handlers_sama.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a7af480cf0f4130c57f688eae4b6e9d3e39b1b06
--- /dev/null
+++ b/src/c21_handlers_sama.ts
@@ -0,0 +1,390 @@
+// c21 — handlers: the /sama cluster. All routes that live under
+// /sama/* plus the SKILL raw download and the bundled CLI download.
+// Extracted from c21_app.ts per the SAMA Atomic rule (the dispatcher
+// passed the 700-line split threshold).
+//
+// Each export is a handler function the dispatcher in c21_app.ts
+// references inline so Bun.serve still sees literal route keys for
+// path-parameter type inference.
+
+import {
+ renderNotFound,
+ htmlResponse,
+ escape,
+} from "./c51_render_layout.ts";
+import { renderDocsPage } from "./c51_render_docs_layout.ts";
+import { ALL_SAMA } from "./c31_sama.ts";
+import {
+ fetchRepoTree,
+ fetchRepoRawFile,
+} from "./c14_github.ts";
+import { verifySama, type SamaReport } from "./c32_sama_verify.ts";
+import { LIVE_REPO_OWNER, LIVE_REPO_NAME } from "./c31_site_config.ts";
+
+// -------- /skills/sama.md (raw download) --------
+
+export const skillsSamaMdHandler = async (): Promise => {
+ const md = await Bun.file("./content/sama/skill.md").text();
+ return new Response(md, {
+ headers: {
+ "Content-Type": "text/markdown; charset=utf-8",
+ "Cache-Control": "public, max-age=300",
+ },
+ });
+};
+
+// -------- /sama/skill (HTML viewer of the SKILL.md) --------
+
+export const samaSkillHandler = async (): Promise => {
+ const raw = await Bun.file("./content/sama/skill.md").text();
+ // Strip the YAML frontmatter for the HTML render — the .md raw
+ // download keeps it (that's the agent-installable format).
+ const stripped = raw.replace(/^---\n[\s\S]*?\n---\n+/, "");
+ const installNote = `> **Drop into your agent.** Save the raw markdown to your skills directory:
+>
+> \`\`\`bash
+> mkdir -p ~/.claude/skills
+> curl -fsSL https://tdd.md/skills/sama.md -o ~/.claude/skills/sama.md
+> \`\`\`
+>
+> The frontmatter at the top of the file (\`name\`, \`description\`) is what your agent's loader keys off — don't edit it. [View raw markdown →](/skills/sama.md)
+`;
+ const body = `${installNote}\n\n${stripped}\n\n---\n\n[← /sama](/sama) · [the four disciplines](/sama) · [back to tdd.md](/)\n`;
+ const html = await renderDocsPage({
+ title: "SAMA skill — drop into your agent — tdd.md",
+ description: "An obra/superpowers-style SKILL.md for the SAMA file-naming convention. Save it to ~/.claude/skills/sama.md and your agent will load the layer-prefix discipline on demand.",
+ bodyMarkdown: body,
+ ogPath: "https://tdd.md/sama/skill",
+ active: "sama",
+ pathForDocs: "/sama/skill",
+ });
+ return htmlResponse(html);
+};
+
+// -------- /sama/verify (form + report + dogfood short-circuit) --------
+
+const VERIFY_FORM_MD = `# SAMA verify
+
+> Paste a public GitHub repo. tdd.md will run the four [SAMA disciplines](/sama) against the default branch — *Sorted* (lower never imports higher), *Architecture* (known layer prefixes), *Modeled* (sibling tests, types in c31_*), *Atomic* (~700-line split + placeholder-test detection) — and return a report. No clone, no token; just one tree-listing API call plus raw-content reads. Cached for an hour per repo.
+
+
+
+Try it on this site: [\`syntaxai/tdd.md\`](/sama/verify?repo=syntaxai/tdd.md) · or any public repo of your own.
+
+Limits: anonymous GitHub API quota is 60 requests/hour per IP. Each verify uses one tree-listing call; the rest of the work goes through raw.githubusercontent.com (uncapped). If the verifier returns "rate limit", come back later or use a token-authenticated proxy.
+
+[← /sama](/sama)
+`;
+
+const verifyLocalDogfood = async (owner: string, name: string): Promise => {
+ const { readdirSync, readFileSync } = await import("node:fs");
+ const srcDir = "./src";
+ const tsFiles = readdirSync(srcDir, { withFileTypes: true })
+ .filter((e) => e.isFile() && e.name.endsWith(".ts"))
+ .map((e) => e.name)
+ .sort();
+ const contents = new Map();
+ for (const f of tsFiles) {
+ if (/^c\d{2}_/.test(f)) {
+ contents.set(f, readFileSync(`${srcDir}/${f}`, "utf8"));
+ }
+ }
+ return verifySama({
+ repoOwner: owner,
+ repoName: name,
+ defaultBranch: "main",
+ srcPaths: tsFiles,
+ contents,
+ });
+};
+
+const verifyRemoteRepo = async (owner: string, name: string): Promise => {
+ const tree = await fetchRepoTree(owner, name);
+ const srcEntries = tree.entries
+ .filter((e) => e.type === "blob" && e.path.startsWith("src/") && e.path.endsWith(".ts"))
+ .slice(0, 200);
+ const srcPaths = srcEntries.map((e) => e.path.slice("src/".length));
+ const samaPaths = srcPaths.filter((p) => /^c\d{2}_/.test(p));
+ const contents = new Map();
+ const fetches = await Promise.all(
+ samaPaths.map(async (p) => [p, await fetchRepoRawFile(owner, name, tree.defaultBranch, `src/${p}`)] as const),
+ );
+ for (const [p, c] of fetches) {
+ if (c !== null) contents.set(p, c);
+ }
+ return verifySama({
+ repoOwner: owner,
+ repoName: name,
+ defaultBranch: tree.defaultBranch,
+ srcPaths,
+ contents,
+ });
+};
+
+const renderVerifyReport = async (report: SamaReport): Promise => {
+ const summary = report.overallPassed
+ ? `> ✓ All four checks passed for [\`${report.repoSlug}\`](https://github.com/${report.repoSlug}) on \`${report.defaultBranch}\` (${report.samaFiles} SAMA files / ${report.testFiles} tests / ${report.totalSrcFiles} total in src/).`
+ : `> ⚠ ${report.checks.filter((c) => !c.passed).length} of 4 checks failed for [\`${report.repoSlug}\`](https://github.com/${report.repoSlug}) on \`${report.defaultBranch}\`.`;
+ const checkBlocks = report.checks
+ .map((c) => {
+ const status = c.passed ? "✓ pass" : `✗ ${c.violations.length} violation${c.violations.length === 1 ? "" : "s"}`;
+ const violationsBlock = c.violations.length === 0
+ ? ""
+ : `\n\n${c.violations.slice(0, 20).map((v) => `- \`${escape(v.file)}\` — ${escape(v.detail)}`).join("\n")}${c.violations.length > 20 ? `\n- _...and ${c.violations.length - 20} more_` : ""}`;
+ const noteBlock = c.note ? `\n\n_${escape(c.note)}_` : "";
+ return `### ${c.letter} — ${c.property} · ${status}\n\nExamined ${c.examined} file${c.examined === 1 ? "" : "s"}.${violationsBlock}${noteBlock}`;
+ })
+ .join("\n\n");
+ const reportMd = `# SAMA verify · \`${report.repoSlug}\`
+
+${summary}
+
+${checkBlocks}
+
+---
+
+[← verify another repo](/sama/verify) · [the four SAMA disciplines →](/sama) · [SAMA skill for your agent →](/sama/skill)
+`;
+ return renderDocsPage({
+ title: `SAMA verify · ${report.repoSlug} — tdd.md`,
+ description: `SAMA verification for ${report.repoSlug}: ${report.overallPassed ? "all four checks passed" : `${report.checks.filter((c) => !c.passed).length}/4 checks failed`}.`,
+ bodyMarkdown: reportMd,
+ ogPath: `https://tdd.md/sama/verify?repo=${report.repoSlug}`,
+ active: "sama",
+ pathForDocs: "/sama/verify",
+ editPathOverride: null,
+ });
+};
+
+export const samaVerifyHandler = async (req: { url: string }): Promise => {
+ const url = new URL(req.url);
+ const repoArg = (url.searchParams.get("repo") ?? "").trim();
+
+ if (!repoArg) {
+ const html = await renderDocsPage({
+ title: "SAMA verify — tdd.md",
+ description: "Paste a public GitHub repo, get the four SAMA disciplines verified mechanically: sorted (lower never imports higher), architecture (known layer prefixes), modeled (sibling tests), atomic (700-line + placeholder-test detection).",
+ bodyMarkdown: VERIFY_FORM_MD,
+ ogPath: "https://tdd.md/sama/verify",
+ active: "sama",
+ pathForDocs: "/sama/verify",
+ });
+ return htmlResponse(html);
+ }
+
+ const m = /^([^\/\s]+)\/([^\/\s]+)$/.exec(repoArg);
+ if (!m) {
+ const html = await renderDocsPage({
+ title: "SAMA verify · bad input — tdd.md",
+ description: "SAMA verify expects an owner/name repo identifier.",
+ bodyMarkdown: `# SAMA verify\n\n> Couldn't parse \`${repoArg}\`. Use the form: \`owner/name\`.\n\n[← back](/sama/verify)\n`,
+ pathForDocs: "/sama/verify",
+ editPathOverride: null,
+ ogPath: "https://tdd.md/sama/verify",
+ active: "sama",
+ noindex: true,
+ });
+ return htmlResponse(html, 400);
+ }
+
+ const [, owner, name] = m;
+ let report: SamaReport;
+ try {
+ // Dogfood short-circuit: tdd.md is a private repo, so the GitHub
+ // API can't see it. When asked to verify ourselves, read the
+ // source from the bundled `./src/` directory inside the container.
+ const isSelf = owner === LIVE_REPO_OWNER && name === LIVE_REPO_NAME;
+ report = isSelf ? await verifyLocalDogfood(owner!, name!) : await verifyRemoteRepo(owner!, name!);
+ } catch (e) {
+ const msg = e instanceof Error ? e.message : String(e);
+ const html = await renderDocsPage({
+ title: `SAMA verify · ${owner}/${name} · error — tdd.md`,
+ description: `SAMA verify could not inspect ${owner}/${name}.`,
+ bodyMarkdown: `# SAMA verify · \`${owner}/${name}\`\n\n> Couldn't fetch the repo: ${escape(msg)}\n\nMost common causes: the repo is private, the name is wrong, or you've hit GitHub's anonymous rate limit (60/hour). [← try another repo](/sama/verify)\n`,
+ ogPath: `https://tdd.md/sama/verify?repo=${owner}/${name}`,
+ active: "sama",
+ noindex: true,
+ pathForDocs: "/sama/verify",
+ editPathOverride: null,
+ });
+ return htmlResponse(html, 502);
+ }
+
+ const html = await renderVerifyReport(report);
+ return htmlResponse(html);
+};
+
+// -------- /sama (landing) --------
+
+const SAMA_LANDING_MD = `# SAMA
+
+> **Sorted, Architecture, Modeled, Atomic.** Four properties of a codebase that an AI agent can navigate, change, and verify without drift. The acronym is the rule set; each letter has a one-paragraph definition and a verification you can run.
+
+This is the file-naming and module-organisation convention this site is built on, shared across two other projects in my workspace. It exists to give an AI agent **one obvious place** for every change — and one mechanical check for every layer rule.
+
+## the four disciplines
+
+| letter | discipline | one-line rule |
+|---|---|---|
+%ROWS%
+
+## reading order
+
+If you're new to this:
+1. Start with **[Sorted](/sama/sorted)** — it has the verification grep that everything else is built around.
+2. Then **[Architecture](/sama/architecture)** — what each layer prefix means.
+3. Then **[Modeled](/sama/modeled)** — where types and tests live.
+4. Then **[Atomic](/sama/atomic)** — the split rule that keeps the rest honest as the codebase grows.
+
+Each page is short, opinionated, and ends with the common mistakes you'll see if the discipline lapses.
+
+## drop into your agent
+
+For agents that load skills from \`~/.claude/skills/\` (Claude Code, obra/superpowers, etc.), grab the SKILL.md version:
+
+\`\`\`bash
+mkdir -p ~/.claude/skills
+curl -fsSL https://tdd.md/skills/sama.md -o ~/.claude/skills/sama.md
+\`\`\`
+
+The skill is the same content as the four pages here, written in obra/superpowers SKILL.md format with frontmatter, an iron-rule statement, and a verification checklist your agent can run before merging. **[Read it formatted →](/sama/skill)** · **[Raw markdown →](/skills/sama.md)**
+
+## verify any public repo
+
+Want to know whether a repo follows SAMA without reading its source? Paste the \`owner/name\` and tdd.md will run all four checks against the default branch — *Sorted* (the import-direction grep), *Architecture* (known layer prefixes), *Modeled* (sibling tests), *Atomic* (700-line + placeholder-test detection). Pass/fail per discipline, with violation lists. **[verify a repo on the web →](/sama/verify)** · or try it on this site: [\`syntaxai/tdd.md\`](/sama/verify?repo=syntaxai/tdd.md).
+
+## the \`sama\` CLI
+
+The web verifier is good for ad-hoc checks. For CI and pre-commit, install the standalone CLI — same checks, no network needed for local repos:
+
+\`\`\`bash
+mkdir -p ~/.local/bin
+curl -fsSL https://tdd.md/tools/sama-cli -o ~/.local/bin/sama
+chmod +x ~/.local/bin/sama
+sama --help
+\`\`\`
+
+Two subcommands:
+
+\`\`\`bash
+sama check # verify the current repo's src/
+sama check --json # JSON output for piping into CI tooling
+sama verify-repo owner/name # verify a public GitHub repo (no token)
+\`\`\`
+
+Exit codes: \`0\` on pass, \`1\` if any check fails, \`2\` on error. The CLI is a single Bun bundle (~14 KB). [Bun](https://bun.sh) needs to be on \`PATH\`.
+
+### pre-commit hook
+
+Add to \`.git/hooks/pre-commit\` (or via \`husky\`, \`pre-commit\`, \`lefthook\`):
+
+\`\`\`bash
+#!/usr/bin/env bash
+# Block commits that violate SAMA layer/atomic/modeled rules.
+exec sama check
+\`\`\`
+
+### GitHub Action
+
+\`\`\`yaml
+# .github/workflows/sama.yml
+name: sama
+on: [push, pull_request]
+jobs:
+ verify:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: oven-sh/setup-bun@v2
+ - run: |
+ curl -fsSL https://tdd.md/tools/sama-cli -o sama
+ chmod +x sama
+ ./sama check
+\`\`\`
+
+If the rule lives in a hook or an action that fails the build, the harness can't talk the agent out of it. That is the whole point of the [corpus post](/blog/agentic-coding-corpus-three-patterns) and the next step from the [from-rules-to-checks](/blog/from-rules-to-checks) wrap-up.
+
+## the case behind it
+
+Two long-form pieces that argue *why* SAMA is shaped this way:
+
+- [**The Claude Code harness postmortem read through TDD + SAMA**](/blog/claude-code-harness-postmortem) — ThePaSch's r/ClaudeAI audit (40+ hidden reminders, 5 gag-order sites, 158 prompt versions in 11 days) read against the iron law and the verification grep. *The harness is loud; the diff doesn't have to be.*
+- [**Three patterns ten threads converge on**](/blog/agentic-coding-corpus-three-patterns) — a six-month corpus of r/ClaudeAI, r/ClaudeCode, r/AgentsOfAI failure-mode threads. Per-pattern mitigation tables map each thread to the SAMA / iron-law rule that catches or prevents it.
+
+If you're reading these for the first time, the order to take them is harness postmortem → corpus → back here.
+
+## why these four together
+
+Each property fixes a different failure mode:
+
+- *Sorted* fails when imports go in any direction → grep proves the rule.
+- *Architecture* fails when responsibilities blur → the prefix is the contract.
+- *Modeled* fails when types and tests scatter → siblings are mandatory.
+- *Atomic* fails when files swell → the ~700-line split keeps atoms small.
+
+Pick one and you'll claw back some clarity. Pick all four and the codebase becomes the kind an agent can be left alone with — there is exactly one right place for any change, and a one-line shell command that proves the layer rule.
+
+The blog post [*Red, tokens, atoms*](/blog/three-constraints-agentic-coding) argues SAMA also compounds with TDD and Claude Code's token-saving discipline; the four properties on this page are the *Atomic* / *Modeled* / *Architecture* / *Sorted* halves of that story.
+
+[← back to tdd.md](/) · [the blog](/blog) · [the guides](/guides)
+`;
+
+export const samaLandingHandler = async (): Promise => {
+ const rows = ALL_SAMA
+ .map((d) => `| **[${d.letter} — ${d.title}](/sama/${d.slug})** | ${d.rule} |`)
+ .join("\n");
+ const body = SAMA_LANDING_MD.replace("%ROWS%", rows);
+ const html = await renderDocsPage({
+ title: "SAMA — sorted, architecture, modeled, atomic — tdd.md",
+ description: "SAMA is a four-property file-naming and module convention for codebases that AI agents work in: sorted by layer prefix, architecture as a contract, models with siblings, atomic files. One page per discipline.",
+ bodyMarkdown: body,
+ ogPath: "https://tdd.md/sama",
+ active: "sama",
+ pathForDocs: "/sama",
+ editPathOverride: null,
+ });
+ return htmlResponse(html);
+};
+
+// -------- /sama/:slug (per-discipline content page) --------
+
+export const samaSlugHandler = async (req: { params: { slug: string } }): Promise => {
+ const slug = req.params.slug;
+ const entry = ALL_SAMA.find((d) => d.slug === slug);
+ if (!entry) {
+ const html = await renderNotFound(`/sama/${slug}`);
+ return htmlResponse(html, 404);
+ }
+ const file = Bun.file(`./content/sama/${slug}.md`);
+ if (!(await file.exists())) {
+ const html = await renderNotFound(`/sama/${slug}`);
+ return htmlResponse(html, 404);
+ }
+ const md = await file.text();
+ const html = await renderDocsPage({
+ title: `SAMA · ${entry.letter} — ${entry.title} — tdd.md`,
+ description: entry.description,
+ bodyMarkdown: md,
+ ogPath: `https://tdd.md/sama/${slug}`,
+ active: "sama",
+ pathForDocs: `/sama/${slug}`,
+ });
+ return htmlResponse(html);
+};
+
+// -------- /tools/sama-cli (binary download) --------
+
+export const samaCliResponse = (): Response =>
+ new Response(Bun.file("./public/sama-cli"), {
+ headers: {
+ "Content-Type": "text/javascript; charset=utf-8",
+ "Content-Disposition": 'inline; filename="sama"',
+ "Cache-Control": "public, max-age=300",
+ },
+ });
diff --git a/src/c31_site_config.ts b/src/c31_site_config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5a06b9715a7056eb904844aac3fbbfccf098dc32
--- /dev/null
+++ b/src/c31_site_config.ts
@@ -0,0 +1,10 @@
+// c31 — model: site-wide config constants. Pure data, no I/O.
+// Lives here so handlers across clusters (sama-verify dogfood,
+// reports/live, sitemap, etc.) reference the same values without
+// circular imports between c21_handlers_*.
+
+export const LIVE_REPO_OWNER = "syntaxai";
+export const LIVE_REPO_NAME = "tdd.md";
+// Number of recent commits the live-reports view samples from the
+// in-container git-history bundle.
+export const LIVE_FETCH_COUNT = 100;