syntaxai/tdd.md · commit 7829323

Move /blog/<slug> → /blog/<yyyy-mm>/<slug> — data-driven URL refactor (portability test)

Third instance of the b32_<old>_url_redirect pattern; first DATA-DRIVEN one. Helper imports ALL_POSTS, computes yyyy-mm from each post's date field, returns the new URL. Fixed-enum predecessors (git-url-drop-owner, sama-discipline-prefix) used hard-coded regex enumerations; this one needs per-entity lookup.

- src/b32_blog_date_url_redirect.ts (24 lines: imports ALL_POSTS, regex extracts slug, lookup yields date, slice(0,7) builds yyyy-mm)
- src/b32_blog_date_url_redirect.test.ts (7 cases including yyyy-mm shape assertion)
- src/d21_handlers_fallback.ts: 301 redirect block adjacent to the two prior instances
- src/d21_app.ts: route /blog/:slug → /blog/:yyyymm/:slug with yyyymm-vs-date validation in handler (prevents URL-spoofing via mismatched prefix); blog index emits new URL; sitemap mapping updated
- src/b32_edit_resolve.ts: pageUrl for blog now looks up the post and emits /blog/<yyyy-mm>/<slug>
- scripts/migrate-blog-urls.ts (one-shot, longest-slug-first to avoid prefix collisions)
- Migration: 46 files modified, 173 substitutions
- Manual fix: migration over-matched inside filesystem paths (content/blog/<slug>.md). Reverse sed restored those; lesson noted for next time (more anchored matching).

Tests: 426/426 pass (419 → 426, +7 redirect helper cases).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
author
syntaxai <[email protected]>
date
2026-05-25 16:23:38 +01:00
parent
d8934f9
commit
78293236aa0db6516ff81f0d00bc2e31f9cee636

50 files changed · +326 −154

modified CONTRIBUTING.md +3 −3
@@ -12,8 +12,8 @@ Two URLs, one file:
1212 Read in this order:
1313
1414 1. [`/sama/v2`](/sama/v2) — the architectural spec (rules, profile, verifier, §5 metrics, §6 evolution policy)
15-2. [`/blog/sama-v2-on-ramp-gap`](/blog/sama-v2-on-ramp-gap) — why this file exists
16-3. [`/blog/sama-v2-goal-chain-gap`](/blog/sama-v2-goal-chain-gap) — why `/goal`s are now in git
15+2. [`/blog/2026-05/sama-v2-on-ramp-gap`](/blog/2026-05/sama-v2-on-ramp-gap) — why this file exists
16+3. [`/blog/2026-05/sama-v2-goal-chain-gap`](/blog/2026-05/sama-v2-goal-chain-gap) — why `/goal`s are now in git
1717
1818 Then check the live state: [`/sama/v2/verify`](/sama/v2/verify) must report **7/7 ✓** before and after every merge. This is the load-bearing anti-fudge gate.
1919
@@ -60,7 +60,7 @@ The Law (§1.2): imports flow downward only. The verifier rejects upward or side
6060 3. The sitemap, blog index, and `/blog/<slug>` route pick it up automatically — registry is the single source of truth
6161 4. Branch → PR → merge → deploy
6262
63-Worked example: [`/blog/sama-v2-sitemap-implementation-plan`](/blog/sama-v2-sitemap-implementation-plan).
63+Worked example: [`/blog/2026-05/sama-v2-sitemap-implementation-plan`](/blog/2026-05/sama-v2-sitemap-implementation-plan).
6464
6565 ## How to add a `/goal`
6666
modified content/blog/agentic-coding-corpus-three-patterns.md +2 −2
@@ -1,6 +1,6 @@
11 # Three patterns ten threads converge on
22
3-> The [previous post](/blog/claude-code-harness-postmortem) made the case from one Reddit thread (ThePaSch's audit of Claude Code's hidden system reminders). One thread is a story. Ten threads are a pattern. This post pulls together ten more posts and threads from the last six months — across r/ClaudeAI, r/ClaudeCode, r/AgentsOfAI — and lets the corpus speak. Three patterns surface across all of them, and each one points at the same answer: the discipline that fixes agentic coding's failure modes lives outside the agent's context window, in git log and the file tree.
3+> The [previous post](/blog/2026-05/claude-code-harness-postmortem) made the case from one Reddit thread (ThePaSch's audit of Claude Code's hidden system reminders). One thread is a story. Ten threads are a pattern. This post pulls together ten more posts and threads from the last six months — across r/ClaudeAI, r/ClaudeCode, r/AgentsOfAI — and lets the corpus speak. Three patterns surface across all of them, and each one points at the same answer: the discipline that fixes agentic coding's failure modes lives outside the agent's context window, in git log and the file tree.
44
55 ## What changes when you go from one thread to ten
66
@@ -184,4 +184,4 @@ One thread is an audit. Ten threads are a pattern. The corpus shows three things
184184
185185 Plus the original one-thread audit: [ThePaSch — Claude Code has big problems and the post-mortem is not enough](https://www.reddit.com/r/ClaudeAI/comments/1strcoa/) (325↑, 200+ comments). Treat this row as the eleventh entry.
186186
187-[Read the previous post →](/blog/claude-code-harness-postmortem) · [the four SAMA disciplines →](/sama) · [drop SAMA into your agent →](/sama/skill) · [verify your repo →](/sama/verify) · [back to the blog](/blog)
187+[Read the previous post →](/blog/2026-05/claude-code-harness-postmortem) · [the four SAMA disciplines →](/sama) · [drop SAMA into your agent →](/sama/skill) · [verify your repo →](/sama/verify) · [back to the blog](/blog)
modified content/blog/aider-tdd.md +1 −1
@@ -149,4 +149,4 @@ Sign in at [tdd.md/you](/you), pick the [string-calc kata](/games/string-calc),
149149
150150 Six steps in, you'll have an evidence-backed answer to whether your Aider workflow does real TDD or theater.
151151
152-[← all guides](/guides) · [Aider reference guide](/guides/aider) · [the kata catalog](/games) · [the Claude Code post →](/blog/claude-code-tdd) · [the Cursor post →](/blog/cursor-tdd)
152+[← all guides](/guides) · [Aider reference guide](/guides/aider) · [the kata catalog](/games) · [the Claude Code post →](/blog/2026-05/claude-code-tdd) · [the Cursor post →](/blog/2026-05/cursor-tdd)
modified content/blog/claude-code-harness-postmortem.md +1 −1
@@ -75,7 +75,7 @@ grep -rE 'from "\./c[5-9]' src/c1*.ts src/c2*.ts src/c3*.ts
7575
7676 The grep returns empty or it doesn't. If the agent — drowned in reminders — accidentally imports a higher layer from a lower one, the grep catches it. Reactive prompt patches in `utils/messages.ts` are *not part of the verification*. They can churn 158 times next week and the grep still works.
7777
78-**Atomic** (~700-line split rule). The argument from the recent [three-constraints post](/blog/three-constraints-agentic-coding) lands harder here: a small atom plus its sibling test fits in a small context window with room to spare *even after the harness has injected its forty reminders*. The harness wastes tokens, but the atom does not *need* most of them. The cost of the bloat shrinks because the surface area to bloat into is small.
78+**Atomic** (~700-line split rule). The argument from the recent [three-constraints post](/blog/2026-05/three-constraints-agentic-coding) lands harder here: a small atom plus its sibling test fits in a small context window with room to spare *even after the harness has injected its forty reminders*. The harness wastes tokens, but the atom does not *need* most of them. The cost of the bloat shrinks because the surface area to bloat into is small.
7979
8080 **Modeled** (tests next to source, types in `c31_*`). A `cXX_*.ts` without a sibling `cXX_*.test.ts` is *visible*. So is an `as Foo` cast at an I/O boundary. The harness cannot hide either — both are in the file system and the diff. A reviewer running `ls src/` after the agent's session sees what's there.
8181
modified content/blog/cursor-tdd.md +1 −1
@@ -136,4 +136,4 @@ Sign in at [tdd.md/you](/you), pick the [string-calc kata](/games/string-calc),
136136
137137 Six steps in, you'll have an evidence-backed answer to: "Is my Cursor workflow doing real TDD, or just looking like it?"
138138
139-[← all guides](/guides) · [Cursor reference guide](/guides/cursor) · [the kata catalog](/games) · [the Claude Code post →](/blog/claude-code-tdd)
139+[← all guides](/guides) · [Cursor reference guide](/guides/cursor) · [the kata catalog](/games) · [the Claude Code post →](/blog/2026-05/claude-code-tdd)
modified content/blog/deploy-that-lies-cascade.md +2 −2
@@ -306,5 +306,5 @@ the standard the same way silent failures in the source would be.
306306 - The PR that landed the three fixes:
307307 <https://github.com/syntaxai/tdd.md/pull/14>
308308 - Previous posts in this thread:
309- [the c21 Atomic-700 split](/blog/sama-empirical-c21-split) ·
310- [greening the Modeled dogfood](/blog/sama-empirical-modeled-green)
309+ [the c21 Atomic-700 split](/blog/2026-05/sama-empirical-c21-split) ·
310+ [greening the Modeled dogfood](/blog/2026-05/sama-empirical-modeled-green)
modified content/blog/from-rules-to-checks.md +2 −2
@@ -1,6 +1,6 @@
11 # From rules to checks: shipping what the corpus post promised
22
3-> The [corpus post](/blog/agentic-coding-corpus-three-patterns) closed with a promise: *"three of the ten threads describe failures only an actual test run can catch"* — and named which checks would have caught which failure modes (some today, some with a small extension, some only with a sandbox runner). This post is the receipt. Three of those checks now ship: **placeholder-test detection** (the *"one-evening sliver"*), **historical-commit testing via git worktree** (the *"next slice on the roadmap"*), and **`/sama/verify`** (mechanical layer grep + sibling-test + line-count + placeholder check, runnable against any public repo).
3+> The [corpus post](/blog/2026-05/agentic-coding-corpus-three-patterns) closed with a promise: *"three of the ten threads describe failures only an actual test run can catch"* — and named which checks would have caught which failure modes (some today, some with a small extension, some only with a sandbox runner). This post is the receipt. Three of those checks now ship: **placeholder-test detection** (the *"one-evening sliver"*), **historical-commit testing via git worktree** (the *"next slice on the roadmap"*), and **`/sama/verify`** (mechanical layer grep + sibling-test + line-count + placeholder check, runnable against any public repo).
44
55 ## why this post is short
66
@@ -84,7 +84,7 @@ The two previous posts made a case from text. This one ships the checks the case
8484 | sliver | route | catches | status |
8585 |---|---|---|---|
8686 | placeholder detection | [/reports/live/tests](/reports/live/tests) | r/ClaudeCode 1qix264 ("90 placeholder tests, 100% pass") | live |
87-| historical-commit testing | snapshot script with `SAMA_HISTORY_DEPTH=N` | runtime-patching SHAs ([groundwork for 1rug14a](/blog/agentic-coding-corpus-three-patterns)) | opt-in, default 0 |
87+| historical-commit testing | snapshot script with `SAMA_HISTORY_DEPTH=N` | runtime-patching SHAs ([groundwork for 1rug14a](/blog/2026-05/agentic-coding-corpus-three-patterns)) | opt-in, default 0 |
8888 | `/sama/verify` | [/sama/verify](/sama/verify) | layer violations, missing sibling tests, oversized files, placeholder tests, in any public repo | live |
8989
9090 If the discipline is real, you should be able to point it at a repo and have it report findings. Now you can.
modified content/blog/sama-empirical-modeled-green.md +1 −1
@@ -140,4 +140,4 @@ The blog post is the receipt; the URL is the proof.
140140 [Sorted](/sama/discipline/sorted) · [Architecture](/sama/discipline/architecture) ·
141141 [Modeled](/sama/discipline/modeled) · [Atomic](/sama/discipline/atomic)
142142 - Previous post in this series:
143- [When the verifier said "split this"](/blog/sama-empirical-c21-split)
143+ [When the verifier said "split this"](/blog/2026-05/sama-empirical-c21-split)
modified content/blog/sama-meets-git-cms.md +1 −1
@@ -137,7 +137,7 @@ make the gaps it doesn't cover *legible*.
137137 - **Source on git.tdd.md:**
138138 [content/blog/sama-meets-git-cms.md](https://git.tdd.md/syntaxai/tdd.md/src/branch/main/content/blog/sama-meets-git-cms.md)
139139 - **Edit it via the CMS:**
140- [/edit/blog/sama-meets-git-cms](/edit/blog/sama-meets-git-cms)
140+ [/edit/blog/2026-05/sama-meets-git-cms](/edit/blog/2026-05/sama-meets-git-cms)
141141 (admin-only — you'll see the login wall)
142142 - **Raw markdown:**
143143 [/content/blog/sama-meets-git-cms.md](/content/blog/sama-meets-git-cms.md)
modified content/blog/sama-v2-git-url-refactor-plan.md +1 −1
@@ -69,7 +69,7 @@ The refactor touches files across three layers, all in expected ways:
6969 | **Layer 2 · Adapter** (`c14_git.ts`) | No changes — `lsTree` and `readBlobAtRef` already take `(ref, path)`, never owner/repo |
7070 | **Layer 3 · Entry** | All the changes live here — `parseRepoBrowsePath` callers, `repoBrowseHandler` signature, the Bun explicit route `/GIT/:repo/commit/:sha`, the new 301 redirect, and the link builders in `b51_render_*.ts` |
7171
72-The layer surface tells you the refactor is contained — no Adapter changes, no business-logic changes, no test-of-pure-helper changes. Only the routing/rendering surface moves. That's the "small refactor" smell the [Layer 2 stays empty](/blog/sama-v2-sitemap-implementation-plan) sitemap post identified — when the change is genuinely about the URL surface, the deeper layers don't need to move.
72+The layer surface tells you the refactor is contained — no Adapter changes, no business-logic changes, no test-of-pure-helper changes. Only the routing/rendering surface moves. That's the "small refactor" smell the [Layer 2 stays empty](/blog/2026-05/sama-v2-sitemap-implementation-plan) sitemap post identified — when the change is genuinely about the URL surface, the deeper layers don't need to move.
7373
7474 ## Anti-fudge — what the `/goal` rules out
7575
modified content/blog/sama-v2-git-url-refactor-postmortem.md +1 −1
@@ -1,6 +1,6 @@
11 # The `/GIT/` URL refactor shipped — plan vs actual
22
3-[Yesterday's plan post](/blog/sama-v2-git-url-refactor-plan) sketched the refactor that drops the redundant `:owner` segment from `/GIT/:owner/:repo/` URLs. The `/goal` fired. [PR #42](/GIT/tdd.md/commit/df9d41a) landed an hour later. This post is the promised companion postmortem: where the plan held, where it didn't, and what the merge produced that the plan couldn't predict.
3+[Yesterday's plan post](/blog/2026-05/sama-v2-git-url-refactor-plan) sketched the refactor that drops the redundant `:owner` segment from `/GIT/:owner/:repo/` URLs. The `/goal` fired. [PR #42](/GIT/tdd.md/commit/df9d41a) landed an hour later. This post is the promised companion postmortem: where the plan held, where it didn't, and what the merge produced that the plan couldn't predict.
44
55 The headline first:
66
modified content/blog/sama-v2-go-project-dive-prefix-scheme.md +9 −9
@@ -1,6 +1,6 @@
11 # `dive`, the prefix-scheme variant — what `ls`-readable layer order costs in Go
22
3-[Earlier today's `dive` rebuilt sketch](/blog/sama-v2-go-project-dive-rebuilt) chose a hypothetical v2.1 *directory-based dialect* — pin layer mapping by package path, leave the actual files where they sit, accept the minimal-change cost. The visual payoff of that approach is muted: you can't `ls src/ | sort` and read the layer hierarchy off the screen the way you can in the [WordPress rebuild post](/blog/sama-v2-wordpress-plugin-rebuilt) (`a_meta_tag.php < a_page_context.php < ... < b1_image_selection_policy.php < ... < d_third_party_hooks.php`).
3+[Earlier today's `dive` rebuilt sketch](/blog/2026-05/sama-v2-go-project-dive-rebuilt) chose a hypothetical v2.1 *directory-based dialect* — pin layer mapping by package path, leave the actual files where they sit, accept the minimal-change cost. The visual payoff of that approach is muted: you can't `ls src/ | sort` and read the layer hierarchy off the screen the way you can in the [WordPress rebuild post](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt) (`a_meta_tag.php < a_page_context.php < ... < b1_image_selection_policy.php < ... < d_third_party_hooks.php`).
44
55 Bas said the obvious thing: *"i miss this SAMA v2 style."* Fair. So here's the other end of the spectrum — what `dive` looks like if it commits to v2.0's prefix scheme *literally*, every file renamed, no spec extension required, the `ls`-readable layer order property fully recovered.
66
@@ -184,8 +184,8 @@ Three concrete prices:
184184
185185 Against those costs, what's bought:
186186
187-- **`ls src/ | sort` reads top-to-bottom in dependency order.** The visual payoff that the [WP rebuild post](/blog/sama-v2-wordpress-plugin-rebuilt) leans on works identically here. A reviewer looking at `git diff src/` sees layer changes in their natural order.
188-- **No spec extension needed.** v2.0 as written applies unchanged. The [other rebuild post](/blog/sama-v2-go-project-dive-rebuilt) requires a hypothetical v2.1 directory dialect; this one doesn't.
187+- **`ls src/ | sort` reads top-to-bottom in dependency order.** The visual payoff that the [WP rebuild post](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt) leans on works identically here. A reviewer looking at `git diff src/` sees layer changes in their natural order.
188+- **No spec extension needed.** v2.0 as written applies unchanged. The [other rebuild post](/blog/2026-05/sama-v2-go-project-dive-rebuilt) requires a hypothetical v2.1 directory dialect; this one doesn't.
189189 - **Profile is shorter.** Eight prefixes mapped to seven sublayer slots — a one-screen `sama.profile.toml`. The directory-dialect profile is twice as long because it lists every package path.
190190 - **Cross-language consistency.** A reader who knows the WP rebuild's prefix scheme reads this tree without translation. `a_*` is types, `b1_*` is pure policy, `c1_*` is repo, `d_*` is entry — identical to what they already know from the PHP example.
191191
@@ -219,8 +219,8 @@ The §5 metrics don't care about layout mode. They measure **the same architectu
219219
220220 This is the third `dive` post in a row, and I'll stop after this one. The bracket is now visible:
221221
222-- [The audit](/blog/sama-v2-go-project-dive) — `dive` as-is, ~5 of 7 checks pass naturally.
223-- [The directory-dialect rebuild](/blog/sama-v2-go-project-dive-rebuilt) — minimal moves, requires a hypothetical v2.1 extension, 7/7 ✓.
222+- [The audit](/blog/2026-05/sama-v2-go-project-dive) — `dive` as-is, ~5 of 7 checks pass naturally.
223+- [The directory-dialect rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt) — minimal moves, requires a hypothetical v2.1 extension, 7/7 ✓.
224224 - This post — the prefix-scheme rebuild, works under v2.0 unchanged, fights Go hard, also 7/7 ✓.
225225
226226 Both rebuilds reach the same end state. The first matches Go's idiom; the second matches the WP rebuild's visual aesthetic. The §5 metrics — the empirical artifact the spec cares about — come out identically in both. That's the part of the v2 design that quietly works: the rules are stricter than the surface syntax that enforces them.
@@ -229,7 +229,7 @@ Both rebuilds reach the same end state. The first matches Go's idiom; the second
229229
230230 **Companion posts:**
231231
232-- [The Go audit](/blog/sama-v2-go-project-dive) — where ~5/7 comes from
233-- [The directory-dialect rebuild](/blog/sama-v2-go-project-dive-rebuilt) — the minimal-change variant
234-- [The WordPress audit + rebuild](/blog/sama-v2-wordpress-plugin-audit) — same exercise on a 0/7 starting point
235-- [The §5 metrics post](/blog/sama-v2-metrics-emitter) — why the metrics matter more than the surface syntax
232+- [The Go audit](/blog/2026-05/sama-v2-go-project-dive) — where ~5/7 comes from
233+- [The directory-dialect rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt) — the minimal-change variant
234+- [The WordPress audit + rebuild](/blog/2026-05/sama-v2-wordpress-plugin-audit) — same exercise on a 0/7 starting point
235+- [The §5 metrics post](/blog/2026-05/sama-v2-metrics-emitter) — why the metrics matter more than the surface syntax
modified content/blog/sama-v2-go-project-dive-rebuilt.md +6 −6
@@ -1,8 +1,8 @@
11 # `dive`, rebuilt under SAMA v2 — a thought experiment
22
3-[Today's audit](/blog/sama-v2-go-project-dive) walked through `wagoodman/dive` and concluded it already scores roughly 5 of 7 §4 checks naturally. Go's standard layout (`cmd/`, `internal/`, package-per-concern) plus the language's `internal/` semantics enforce most of what v2 asks for. The two checks that don't pass for free: **#1 Sorted** (Go organizes by package directory, not filename prefix — incompatible with the v2.0 lex-sort-the-prefixes rule) and **#3 Modeled-tests** (18 test files for 92 source files, with the gaps clustered in the image-adapter packages).
3+[Today's audit](/blog/2026-05/sama-v2-go-project-dive) walked through `wagoodman/dive` and concluded it already scores roughly 5 of 7 §4 checks naturally. Go's standard layout (`cmd/`, `internal/`, package-per-concern) plus the language's `internal/` semantics enforce most of what v2 asks for. The two checks that don't pass for free: **#1 Sorted** (Go organizes by package directory, not filename prefix — incompatible with the v2.0 lex-sort-the-prefixes rule) and **#3 Modeled-tests** (18 test files for 92 source files, with the gaps clustered in the image-adapter packages).
44
5-Bas asked the same companion question he asked for the [WordPress rebuild post](/blog/sama-v2-wordpress-plugin-rebuilt): what would `dive` look like if it had been laid out for v2 from day one? Same scope, same features, same user-facing behavior, same idiomatic Go — just enough decisions made deliberately to score 7/7 under a directory-based v2 dialect.
5+Bas asked the same companion question he asked for the [WordPress rebuild post](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt): what would `dive` look like if it had been laid out for v2 from day one? Same scope, same features, same user-facing behavior, same idiomatic Go — just enough decisions made deliberately to score 7/7 under a directory-based v2 dialect.
66
77 This sketch is much smaller than the WordPress one. The starting point is already much closer; the lift is days of work, not months. Which is itself the finding.
88
@@ -317,8 +317,8 @@ Three observations:
317317
318318 **Companion posts:**
319319
320-- [Today's `dive` audit](/blog/sama-v2-go-project-dive) — the source of the ~5/7 score this rebuild starts from
321-- [The WordPress audit](/blog/sama-v2-wordpress-plugin-audit) — the 0/7 baseline from a different ecosystem
322-- [The WordPress rebuild](/blog/sama-v2-wordpress-plugin-rebuilt) — what 7/7 looked like for that codebase
323-- [The §5 metrics emitter](/blog/sama-v2-metrics-emitter) — what makes deltas measurable in the first place
320+- [Today's `dive` audit](/blog/2026-05/sama-v2-go-project-dive) — the source of the ~5/7 score this rebuild starts from
321+- [The WordPress audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) — the 0/7 baseline from a different ecosystem
322+- [The WordPress rebuild](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt) — what 7/7 looked like for that codebase
323+- [The §5 metrics emitter](/blog/2026-05/sama-v2-metrics-emitter) — what makes deltas measurable in the first place
324324 - [The v2 spec](/sama/v2) — the rules being audited against
modified content/blog/sama-v2-go-project-dive.md +3 −3
@@ -1,6 +1,6 @@
11 # Pointing SAMA v2 at `dive`: Go's conventions cover more than you'd think
22
3-The [WordPress plugin audit](/blog/sama-v2-wordpress-plugin-audit) earlier today scored 0 of 7 §4 checks for a real-world plugin in the wild. That post argued — and I still believe — that the score isn't a failure; it's the expected baseline for code written under WordPress idioms with no external discipline. WP itself actively pushes devs toward hook-and-filter god-classes.
3+The [WordPress plugin audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) earlier today scored 0 of 7 §4 checks for a real-world plugin in the wild. That post argued — and I still believe — that the score isn't a failure; it's the expected baseline for code written under WordPress idioms with no external discipline. WP itself actively pushes devs toward hook-and-filter god-classes.
44
55 But "WordPress is messy" isn't an interesting finding on its own. The harder question is what v2 sees when pointed at a language that has stronger architectural defaults built in. So: same exercise, same methodology, but against **`wagoodman/dive`** — a 53k-star Go project that explores Docker image layers. 8,498 lines of Go across 92 source files, downloaded straight from `git clone`, walked carefully.
66
@@ -213,7 +213,7 @@ That's still n=3 and two of them are hand-estimated, so nobody should be drawing
213213 **See for yourself:**
214214
215215 - The project: <https://github.com/wagoodman/dive>
216-- Yesterday's WP audit (companion piece): [Pointing SAMA v2 at a real WordPress plugin in the wild](/blog/sama-v2-wordpress-plugin-audit)
217-- The hypothetical WP rebuild: [The Open Graph plugin, rebuilt under SAMA v2](/blog/sama-v2-wordpress-plugin-rebuilt)
216+- Yesterday's WP audit (companion piece): [Pointing SAMA v2 at a real WordPress plugin in the wild](/blog/2026-05/sama-v2-wordpress-plugin-audit)
217+- The hypothetical WP rebuild: [The Open Graph plugin, rebuilt under SAMA v2](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt)
218218 - The §5 metric definitions: [/sama/v2#5-operational--core-metrics-definitions](/sama/v2#5-operational--core-metrics-definitions)
219219 - The spec being audited against: [/sama/v2](/sama/v2)
modified content/blog/sama-v2-goal-chain-gap.md +4 −4
@@ -1,6 +1,6 @@
11 # Every chain artifact lives in git — except the `/goal`
22
3-This site's load-bearing claim is **auditability**. The `/sama/v2/verify` page makes a structural assertion about the source tree and reports 7/7 ✓ against it, live, every time you reload. The `/blog/sama-v2-workingset-cross-repo-baseline` post measures eight repositories at pinned SHAs and asks you to clone them yourself if you want to double-check. The sitemap is generated from the registries, the verifier reads the profile, the profile is in the repo, the repo is browseable at [`/GIT/tdd.md/tree/main`](/GIT/tdd.md/tree/main). Every link in the empirical chain is supposed to be inspectable.
3+This site's load-bearing claim is **auditability**. The `/sama/v2/verify` page makes a structural assertion about the source tree and reports 7/7 ✓ against it, live, every time you reload. The `/blog/2026-05/sama-v2-workingset-cross-repo-baseline` post measures eight repositories at pinned SHAs and asks you to clone them yourself if you want to double-check. The sitemap is generated from the registries, the verifier reads the profile, the profile is in the repo, the repo is browseable at [`/GIT/tdd.md/tree/main`](/GIT/tdd.md/tree/main). Every link in the empirical chain is supposed to be inspectable.
44
55 There is one artifact in the chain that isn't.
66
@@ -12,9 +12,9 @@ The `/goal` command — the structured spec that drives every PR on this site, t
1212
1313 This site has shipped roughly 40 PRs over the last month. The recent ones — the ones the empirical-chain posts cite — were all `/goal`-driven. To pick the highest-profile examples:
1414
15-- **PR #42** dropped the `:owner` segment from `/GIT/` URLs. The `/goal` specified one regex (anti-fudge), defined the 301 redirect contract, listed all 49 references to be rewritten, and forbade alias mode. The [plan post](/blog/sama-v2-git-url-refactor-plan) cites those constraints. The [postmortem](/blog/sama-v2-git-url-refactor-postmortem) scores plan vs actual against them. Yet the `/goal` text itself is **gone** — overwritten the next time someone (me) wrote a new `/goal`.
15+- **PR #42** dropped the `:owner` segment from `/GIT/` URLs. The `/goal` specified one regex (anti-fudge), defined the 301 redirect contract, listed all 49 references to be rewritten, and forbade alias mode. The [plan post](/blog/2026-05/sama-v2-git-url-refactor-plan) cites those constraints. The [postmortem](/blog/2026-05/sama-v2-git-url-refactor-postmortem) scores plan vs actual against them. Yet the `/goal` text itself is **gone** — overwritten the next time someone (me) wrote a new `/goal`.
1616
17-- **PR #40** built `/sitemap.xml` as a pure Layer 1 helper. The `/goal` enumerated five test cases (empty list, single URL with/without lastmod, order preservation, XML-escape), three anti-fudge clauses (no second URL list, no static commit, no string-concat XML), and one "load-bearing automatic property" claim. The [plan post](/blog/sama-v2-sitemap-implementation-plan) explains them. The `/goal` text itself: **gone**.
17+- **PR #40** built `/sitemap.xml` as a pure Layer 1 helper. The `/goal` enumerated five test cases (empty list, single URL with/without lastmod, order preservation, XML-escape), three anti-fudge clauses (no second URL list, no static commit, no string-concat XML), and one "load-bearing automatic property" claim. The [plan post](/blog/2026-05/sama-v2-sitemap-implementation-plan) explains them. The `/goal` text itself: **gone**.
1818
1919 - **PR #38** redesigned the `sama-layers` image per five explicit feedback points from the user. The `/goal`-equivalent was a conversational instruction. **Gone the moment the next instruction arrived.**
2020
@@ -36,7 +36,7 @@ Each link is auditable because each link is in git or live-served from git. Now
3636
3737 A `/goal` did. Every single one of them. And the `/goal` is not in the chain. Not in git, not live-served, not even reliably preserved in the PR description (some PRs have it, most have only summary bullets that lose the *Constraints* and *Load-bearing files* sections).
3838
39-The site has been making a structural claim — "every artifact in the empirical chain is auditable" — while the artifact that authors every other artifact is the one we lose. It's exactly the kind of self-inconsistency the [verifier-rename post](/blog/sama-v2-verifier-and-the-rename) called out: the spec applies to the discipline itself, or it doesn't apply.
39+The site has been making a structural claim — "every artifact in the empirical chain is auditable" — while the artifact that authors every other artifact is the one we lose. It's exactly the kind of self-inconsistency the [verifier-rename post](/blog/2026-05/sama-v2-verifier-and-the-rename) called out: the spec applies to the discipline itself, or it doesn't apply.
4040
4141 Today it doesn't apply. Today the chain has a hole.
4242
modified content/blog/sama-v2-metrics-emitter.md +5 −5
@@ -1,6 +1,6 @@
11 # Compliance proves the rules were followed. Delta proves they were worth following.
22
3-Yesterday's [post](/blog/sama-v2-verifier-and-the-rename) was about getting
3+Yesterday's [post](/blog/2026-05/sama-v2-verifier-and-the-rename) was about getting
44 [`/sama/v2/verify`](/sama/v2/verify) to report 7/7 ✓ against this repo —
55 seventy files renamed, three small fixes, the empirical chain "here is
66 the rule, here is the verifier, here is the codebase passing" closed.
@@ -223,8 +223,8 @@ laid the cable.
223223 - Live verdict + metrics: <https://tdd.md/sama/v2/verify> (7/7 ✓, graphDepth=7, boundaryRatio=100%, workingSetFit=80%)
224224 - The §5 operational definitions: <https://tdd.md/sama/v2#5-operational--core-metrics-definitions>
225225 - The PR that landed the work: [#17](https://github.com/syntaxai/tdd.md/pull/17)
226-- Yesterday's post: [I built the SAMA v2 verifier...](/blog/sama-v2-verifier-and-the-rename)
226+- Yesterday's post: [I built the SAMA v2 verifier...](/blog/2026-05/sama-v2-verifier-and-the-rename)
227227 - Earlier in the series:
228- [c21 Atomic split](/blog/sama-empirical-c21-split) ·
229- [Modeled green](/blog/sama-empirical-modeled-green) ·
230- [Deploy that lies](/blog/deploy-that-lies-cascade)
228+ [c21 Atomic split](/blog/2026-05/sama-empirical-c21-split) ·
229+ [Modeled green](/blog/2026-05/sama-empirical-modeled-green) ·
230+ [Deploy that lies](/blog/2026-05/deploy-that-lies-cascade)
modified content/blog/sama-v2-on-ramp-gap.md +4 −4
@@ -45,9 +45,9 @@ Pretend you've just landed on tdd.md and want to add a blog post. The literal st
4545 2. Open `/blog` and click around — notice the URL pattern `/blog/<slug>`.
4646 3. Browse `/GIT/tdd.md/tree/main/content/blog` — find that posts are markdown files.
4747 4. Open `/GIT/tdd.md/blob/main/src/a31_blog.ts` — discover `ALL_POSTS` and realize new posts need to be registered.
48-5. Look at `/blog/sama-v2-sitemap-implementation-plan` to see the pattern for *how* posts are authored — but that's about sitemap.xml, not about the blog post itself.
48+5. Look at `/blog/2026-05/sama-v2-sitemap-implementation-plan` to see the pattern for *how* posts are authored — but that's about sitemap.xml, not about the blog post itself.
4949 6. Hunt for a recent merged PR — find `gh pr view 44` — see the branch-merge-deploy flow in *the commit messages*, not in any document.
50-7. Try to figure out images. Read `/blog/sama-v2-goal-chain-gap` looking for image conventions. Find a passing mention. Open a recent PR with images. Reverse-engineer.
50+7. Try to figure out images. Read `/blog/2026-05/sama-v2-goal-chain-gap` looking for image conventions. Find a passing mention. Open a recent PR with images. Reverse-engineer.
5151 8. Realize you don't know whether your blog post needs sibling tests. Read `/sama/v2 §4.3`. Determine: no — only source files need siblings. Content files don't.
5252 9. Realize you might break `/sama/v2/verify`. Run it locally? There's no instruction. Push to `main` and pray? That breaks the workflow. Fork the repo? The verifier doesn't run on forks.
5353 10. Give up. Open an issue saying "how do I contribute?"
@@ -56,7 +56,7 @@ This is the experience the site currently delivers. The empirical chain is intac
5656
5757 ## Why this is a SAMA v2 self-violation
5858
59-The [chain-gap drama post](/blog/sama-v2-goal-chain-gap) argued that the `/goal` command was a SAMA v2 self-violation because the contract driving every PR wasn't in the chain. The fix shipped — `/goals/<slug>.md` files are in git, the workflow memory is locked in, every future `/goal` lands in the registry by construction.
59+The [chain-gap drama post](/blog/2026-05/sama-v2-goal-chain-gap) argued that the `/goal` command was a SAMA v2 self-violation because the contract driving every PR wasn't in the chain. The fix shipped — `/goals/<slug>.md` files are in git, the workflow memory is locked in, every future `/goal` lands in the registry by construction.
6060
6161 This post argues the same shape, one level up: **the workflow itself is the next missing artifact**. The `/goal` is now in git; the rule for how to *write* a `/goal` is not. The branch flow is encoded in memory; the rule for how to *run* the branch flow is not on the site. The image convention is enforced by code; the rule that a contributor needs to know about the convention is nowhere a contributor would think to look.
6262
@@ -81,7 +81,7 @@ One file, two URLs, both on tdd.md. Same pattern as the sitemap (one source, two
8181
8282 1. **Single source of truth.** Every rule is owned by exactly one canonical artifact. `CONTRIBUTING.md` **links**, doesn't restate. The layer convention lives at `/sama/v2 §1.1`; CONTRIBUTING.md says "see §1.1" and never copies the table. If a future PR changes the spec, CONTRIBUTING.md doesn't drift because there's nothing in it to drift.
8383
84-2. **Dogfooded.** Its own creation is `/goal`-driven. `goals/contributing-md.md` lands as the first commit of the PR per the [workflow memory](https://tdd.md/blog/sama-v2-goal-chain-gap); the merge SHA flips to shipped at deploy time. The artifact that documents the workflow is itself produced by the workflow.
84+2. **Dogfooded.** Its own creation is `/goal`-driven. `goals/contributing-md.md` lands as the first commit of the PR per the [workflow memory](https://tdd.md/blog/2026-05/sama-v2-goal-chain-gap); the merge SHA flips to shipped at deploy time. The artifact that documents the workflow is itself produced by the workflow.
8585
8686 3. **Drift-detectable.** A test grep-checks that `CONTRIBUTING.md` only contains *references* to canonical sources — no rule restatements. If someone adds "the SAMA layers are a31/b32/c14/d21" as a paragraph instead of a link, the test fails. This is the same anti-fudge shape the verifier uses for source files.
8787
modified content/blog/sama-v2-rust-project-ripgrep-parallel-fleet.md +7 −7
@@ -1,6 +1,6 @@
11 # The same `ripgrep` rebuild, run by a fleet of AI agents in parallel across the planet — a projection
22
3-[Yesterday's `ripgrep` rebuild sketch](/blog/sama-v2-rust-project-ripgrep-rebuilt) estimated **~1 focused working week** for one careful human to land the changes: write the `sama.profile.toml`, split `printer/standard.rs` into a six-file submodule, split `ignore/walk.rs` into a four-file submodule. Plus a few more days for the deferred splits. Eight working days total, end to end.
3+[Yesterday's `ripgrep` rebuild sketch](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt) estimated **~1 focused working week** for one careful human to land the changes: write the `sama.profile.toml`, split `printer/standard.rs` into a six-file submodule, split `ignore/walk.rs` into a four-file submodule. Plus a few more days for the deferred splits. Eight working days total, end to end.
44
55 That's the *serial-human* estimate. This post is the companion question Bas asked: *what does the same refactor look like if it's executed by a fleet of AI agents running in parallel, spread across the planet, under strict SAMA v2 management?*
66
@@ -178,8 +178,8 @@ The series so far on this Rust example:
178178
179179 | post | scope | wall-clock estimate | confidence |
180180 |---|---|---|---|
181-| [the audit](/blog/sama-v2-rust-project-ripgrep) | score ripgrep as-is against §4 | n/a (read-only) | empirical (the source was read) |
182-| [the rebuild](/blog/sama-v2-rust-project-ripgrep-rebuilt) | serial-human refactor to 7/7 ✓ | ~8 working days | informed estimate from concrete file deltas |
181+| [the audit](/blog/2026-05/sama-v2-rust-project-ripgrep) | score ripgrep as-is against §4 | n/a (read-only) | empirical (the source was read) |
182+| [the rebuild](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt) | serial-human refactor to 7/7 ✓ | ~8 working days | informed estimate from concrete file deltas |
183183 | this post | parallel-fleet refactor to 7/7 ✓ | ~8 wall-clock hours | projection, ~10× compression from above |
184184
185185 Each post tightens a different lever:
@@ -193,8 +193,8 @@ None of the three is a measured "v2 is worth following" claim by itself. Togethe
193193
194194 **Companion posts:**
195195
196-- [The ripgrep audit](/blog/sama-v2-rust-project-ripgrep) — the source of the work-package list
197-- [The ripgrep rebuild sketch](/blog/sama-v2-rust-project-ripgrep-rebuilt) — the serial-human cost estimate this post divides by parallelism
198-- [The dive rebuild](/blog/sama-v2-go-project-dive-rebuilt) — equivalent decomposition on a Go codebase, ~10 days serial; parallel-fleet projection would land similar 10× compression
199-- [The §5 metrics emitter](/blog/sama-v2-metrics-emitter) — the empirical apparatus the §6 experiment plugs into
196+- [The ripgrep audit](/blog/2026-05/sama-v2-rust-project-ripgrep) — the source of the work-package list
197+- [The ripgrep rebuild sketch](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt) — the serial-human cost estimate this post divides by parallelism
198+- [The dive rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt) — equivalent decomposition on a Go codebase, ~10 days serial; parallel-fleet projection would land similar 10× compression
199+- [The §5 metrics emitter](/blog/2026-05/sama-v2-metrics-emitter) — the empirical apparatus the §6 experiment plugs into
200200 - [The v2 spec](/sama/v2) — particularly §4 (Atomic, Architecture, Sorted, Modeled) and §6 (evolution policy)
modified content/blog/sama-v2-rust-project-ripgrep-rebuilt.md +11 −11
@@ -1,10 +1,10 @@
11 # `ripgrep`, rebuilt under SAMA v2 — a thought experiment
22
3-[Today's `ripgrep` audit](/blog/sama-v2-rust-project-ripgrep) walked the seven §4 checks against BurntSushi's workspace and concluded that the strict score is ~3/7 but, under three proposed v2.1 dialects, rises to ~5-6/7. The audit's headline finding was that *ripgrep is so close to v2-compliant that the work isn't on ripgrep — it's on v2*. This post is the parallel-architecture sketch the audit promised: what does the codebase look like *as a whole* when every v2.1 dialect is admitted, every borderline case resolved, every gap closed?
3+[Today's `ripgrep` audit](/blog/2026-05/sama-v2-rust-project-ripgrep) walked the seven §4 checks against BurntSushi's workspace and concluded that the strict score is ~3/7 but, under three proposed v2.1 dialects, rises to ~5-6/7. The audit's headline finding was that *ripgrep is so close to v2-compliant that the work isn't on ripgrep — it's on v2*. This post is the parallel-architecture sketch the audit promised: what does the codebase look like *as a whole* when every v2.1 dialect is admitted, every borderline case resolved, every gap closed?
44
55 Same scope, same features, same user-facing behaviour, same idiomatic Rust — just enough decisions made deliberately to score 7/7 under v2.1 with the proposed dialects.
66
7-The sketch is even smaller than the [`dive` rebuild](/blog/sama-v2-go-project-dive-rebuilt). The starting point is closer; the lift is days of focused work plus three lines in the spec.
7+The sketch is even smaller than the [`dive` rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt). The starting point is closer; the lift is days of focused work plus three lines in the spec.
88
99 ## The three v2.1 dialects this sketch assumes
1010
@@ -12,7 +12,7 @@ The sketch is even smaller than the [`dive` rebuild](/blog/sama-v2-go-project-di
1212
1313 The audit surfaced three places where v2.0 doesn't fit Rust. Each becomes a falsifiable, optionally-applied profile extension in the spirit of §6 evolution policy:
1414
15-1. **[`layout = "directory"`](/sama/v2#61-directory-layout-dialect)** — Sorted-by-crate-directory rather than Sorted-by-filename-prefix. (Same dialect the [Go `dive` rebuild](/blog/sama-v2-go-project-dive-rebuilt) proposes.) Cargo's workspace + `pub use` semantics + the absence of upward edges in the crate graph give the verifier everything it needs to enforce the same property the prefix-lex check enforces in TypeScript/PHP.
15+1. **[`layout = "directory"`](/sama/v2#61-directory-layout-dialect)** — Sorted-by-crate-directory rather than Sorted-by-filename-prefix. (Same dialect the [Go `dive` rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt) proposes.) Cargo's workspace + `pub use` semantics + the absence of upward edges in the crate graph give the verifier everything it needs to enforce the same property the prefix-lex check enforces in TypeScript/PHP.
1616
1717 2. **[`tests = "inline"`](/sama/v2#62-inline-tests-dialect)** — Modeled-tests recognises `#[cfg(test)] mod tests { #[test] fn ... }` blocks inside source files instead of requiring a sibling `*_test.rs` file. Rust's convention is fundamentally inline; the v2.0 sibling-file rule was written assuming Jest/PHPUnit-style adjacent test files. The property the rule is *trying* to protect — "every behavioural source unit has a test attached" — is preserved; only the surface syntax of attachment changes.
1818
@@ -391,9 +391,9 @@ The 7,779-line `core/flags/defs.rs` stays unchanged. It's the textbook declarati
391391
392392 No new tests need to be written — `tests = "inline"` recognises the 38 source files that already have `#[cfg(test)] mod tests` blocks. No god-class to dismantle (the splits are clean per-output-mode and per-walker-concern; both are already organized by these concepts internally). No API breaks — every `pub` item retains its path through the new submodules via `pub use` re-exports.
393393
394-For context, the [WordPress plugin parallel-architecture rebuild](/blog/sama-v2-wordpress-plugin-rebuilt) required splitting a 1,554-line public god-class into eleven files, redesigning the settings option as a typed value, and writing 20+ test files from scratch. Months of work, real risk of breaking the PRO add-on, WooCommerce, Yoast, and AIOSEO integrations. `dive` to 7/7 was ten working days of test writing plus one package split. `ripgrep` to 7/7 is one focused week of file splitting plus a TOML file.
394+For context, the [WordPress plugin parallel-architecture rebuild](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt) required splitting a 1,554-line public god-class into eleven files, redesigning the settings option as a typed value, and writing 20+ test files from scratch. Months of work, real risk of breaking the PRO add-on, WooCommerce, Yoast, and AIOSEO integrations. `dive` to 7/7 was ten working days of test writing plus one package split. `ripgrep` to 7/7 is one focused week of file splitting plus a TOML file.
395395
396-(One focused week is the *serial-human* number. For the parallel-fleet projection that divides this estimate by SAMA-mechanical work-package boundaries and lands on ~8 wall-clock hours, see the [companion post](/blog/sama-v2-rust-project-ripgrep-parallel-fleet).)
396+(One focused week is the *serial-human* number. For the parallel-fleet projection that divides this estimate by SAMA-mechanical work-package boundaries and lands on ~8 wall-clock hours, see the [companion post](/blog/2026-05/sama-v2-rust-project-ripgrep-parallel-fleet).)
397397
398398 ## Predicted §5 metrics for the rebuilt ripgrep
399399
@@ -429,10 +429,10 @@ Four observations:
429429
430430 **Companion posts:**
431431
432-- **[The same rebuild, run by a fleet of AI agents in parallel](/blog/sama-v2-rust-project-ripgrep-parallel-fleet)** — projecting this post's ~8-working-day serial estimate into ~8 wall-clock hours under SAMA-mechanical merge gates
433-- [Today's `ripgrep` audit](/blog/sama-v2-rust-project-ripgrep) — where the 3/7-strict, 5/7-with-dialects score comes from, and the three findings this rebuild assumes get adopted
434-- [The `dive` rebuild](/blog/sama-v2-go-project-dive-rebuilt) — same exercise on a Go codebase, the directory-dialect's first appearance
435-- [The `dive` prefix-scheme variant](/blog/sama-v2-go-project-dive-prefix-scheme) — what the dramatic file-rename refactor costs in Go (and would cost even more in Rust)
436-- [The WordPress audit + rebuild](/blog/sama-v2-wordpress-plugin-audit) · [rebuilt](/blog/sama-v2-wordpress-plugin-rebuilt) — same exercise on a 0/7 starting point
437-- [The §5 metrics post](/blog/sama-v2-metrics-emitter) — why the metrics matter more than the surface verdict
432+- **[The same rebuild, run by a fleet of AI agents in parallel](/blog/2026-05/sama-v2-rust-project-ripgrep-parallel-fleet)** — projecting this post's ~8-working-day serial estimate into ~8 wall-clock hours under SAMA-mechanical merge gates
433+- [Today's `ripgrep` audit](/blog/2026-05/sama-v2-rust-project-ripgrep) — where the 3/7-strict, 5/7-with-dialects score comes from, and the three findings this rebuild assumes get adopted
434+- [The `dive` rebuild](/blog/2026-05/sama-v2-go-project-dive-rebuilt) — same exercise on a Go codebase, the directory-dialect's first appearance
435+- [The `dive` prefix-scheme variant](/blog/2026-05/sama-v2-go-project-dive-prefix-scheme) — what the dramatic file-rename refactor costs in Go (and would cost even more in Rust)
436+- [The WordPress audit + rebuild](/blog/2026-05/sama-v2-wordpress-plugin-audit) · [rebuilt](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt) — same exercise on a 0/7 starting point
437+- [The §5 metrics post](/blog/2026-05/sama-v2-metrics-emitter) — why the metrics matter more than the surface verdict
438438 - [The v2 spec](/sama/v2) — the rules being rebuilt against
modified content/blog/sama-v2-rust-project-ripgrep.md +8 −8
@@ -1,6 +1,6 @@
11 # Pointing SAMA v2 at `ripgrep`: BurntSushi's exemplar surfaces three findings about the spec
22
3-The [WordPress plugin audit](/blog/sama-v2-wordpress-plugin-audit) scored 0/7 because the plugin was written under no architectural discipline at all. The [Go `dive` audit](/blog/sama-v2-go-project-dive) scored ~5/7 because Go's standard layout enforces a lot of v2's rules for free. Both audits taught us something about v2 by what they *failed* against.
3+The [WordPress plugin audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) scored 0/7 because the plugin was written under no architectural discipline at all. The [Go `dive` audit](/blog/2026-05/sama-v2-go-project-dive) scored ~5/7 because Go's standard layout enforces a lot of v2's rules for free. Both audits taught us something about v2 by what they *failed* against.
44
55 Today's question: what does v2 see when pointed at code that is, by reputation, *exemplary*?
66
@@ -53,9 +53,9 @@ Walking the seven checks against this workspace:
5353
5454 ### #1 Sorted — would fail under v2.0
5555
56-Same finding as the [Go `dive` audit](/blog/sama-v2-go-project-dive): Rust organizes by crate + module directory, not by filename prefix. Files inside `crates/searcher/src/` are `glue.rs`, `mod.rs`, `searcher.rs`, etc. — descriptive, not layer-marking. The v2.0 lex-sort-the-filename-prefixes rule does not translate.
56+Same finding as the [Go `dive` audit](/blog/2026-05/sama-v2-go-project-dive): Rust organizes by crate + module directory, not by filename prefix. Files inside `crates/searcher/src/` are `glue.rs`, `mod.rs`, `searcher.rs`, etc. — descriptive, not layer-marking. The v2.0 lex-sort-the-filename-prefixes rule does not translate.
5757
58-Under the hypothetical v2.1 **directory-based dialect** (the [`dive` rebuild post](/blog/sama-v2-go-project-dive-rebuilt) proposes it formally), Sorted becomes "crate directories declared in layer order in the profile; no import edge violates that order." ripgrep would pass cleanly because the crate dependency graph already runs that direction.
58+Under the hypothetical v2.1 **directory-based dialect** (the [`dive` rebuild post](/blog/2026-05/sama-v2-go-project-dive-rebuilt) proposes it formally), Sorted becomes "crate directories declared in layer order in the profile; no import edge violates that order." ripgrep would pass cleanly because the crate dependency graph already runs that direction.
5959
6060 ### #2 Architecture — would pass under the directory dialect
6161
@@ -192,7 +192,7 @@ The contrast with `dive`'s measured depth 12 is itself interesting: ripgrep's cr
192192
193193 ## What a rebuilt ripgrep would look like — the small version
194194
195-**For the full parallel-architecture sketch — every layer, every file move, predicted §5 metrics, the rebuilt `sama.profile.toml`, and concrete Rust code samples for the two file splits — see the companion post: [`ripgrep`, rebuilt under SAMA v2](/blog/sama-v2-rust-project-ripgrep-rebuilt).**
195+**For the full parallel-architecture sketch — every layer, every file move, predicted §5 metrics, the rebuilt `sama.profile.toml`, and concrete Rust code samples for the two file splits — see the companion post: [`ripgrep`, rebuilt under SAMA v2](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt).**
196196
197197 The audit makes the rebuild sketch short, because BurntSushi's crate split already maps to v2 layers under the directory dialect. The lift to make it pass under v2.1 with the proposed dialects:
198198
@@ -227,8 +227,8 @@ n=4, three of them hand-estimated, still far from a *"v2 is worth following"* cl
227227 **See for yourself:**
228228
229229 - The project: <https://github.com/BurntSushi/ripgrep>
230-- **The full ripgrep rebuild (companion to this audit): [`ripgrep`, rebuilt under SAMA v2](/blog/sama-v2-rust-project-ripgrep-rebuilt)**
231-- The Go audit (companion): [Pointing SAMA v2 at `dive`](/blog/sama-v2-go-project-dive)
232-- The WP audit + rebuild: [WordPress plugin audit](/blog/sama-v2-wordpress-plugin-audit) · [rebuilt](/blog/sama-v2-wordpress-plugin-rebuilt)
233-- The §5 metrics emitter: [Compliance proves the rules followed. Delta proves they were worth following.](/blog/sama-v2-metrics-emitter)
230+- **The full ripgrep rebuild (companion to this audit): [`ripgrep`, rebuilt under SAMA v2](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt)**
231+- The Go audit (companion): [Pointing SAMA v2 at `dive`](/blog/2026-05/sama-v2-go-project-dive)
232+- The WP audit + rebuild: [WordPress plugin audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) · [rebuilt](/blog/2026-05/sama-v2-wordpress-plugin-rebuilt)
233+- The §5 metrics emitter: [Compliance proves the rules followed. Delta proves they were worth following.](/blog/2026-05/sama-v2-metrics-emitter)
234234 - The spec being audited against: [/sama/v2](/sama/v2)
modified content/blog/sama-v2-second-url-refactor-postmortem.md +3 −3
@@ -1,6 +1,6 @@
11 # 8 minutes 8 seconds — the cost-flattening hypothesis is confirmed
22
3-The [git-url-refactor postmortem](/blog/sama-v2-git-url-refactor-postmortem) closed with a single falsifiable claim:
3+The [git-url-refactor postmortem](/blog/2026-05/sama-v2-git-url-refactor-postmortem) closed with a single falsifiable claim:
44
55 > *"If the second URL refactor — when it happens — lands in ~an hour, that's the data point. If it takes another evening, the pattern wasn't as portable as it looked. Either result is informative."*
66
@@ -73,9 +73,9 @@ The cost-flattening claim holds *for refactors of the same shape*. When the inpu
7373
7474 ## The empirical chain ratchets
7575
76-[`/blog/sama-v2-goal-chain-gap`](/blog/sama-v2-goal-chain-gap) said *every artifact is auditable*. Now: the *time-cost* of each kind of refactor is auditable too. The git-url postmortem published a 1-hour prediction. This post publishes the 8-minute measurement against it. Both timestamps are in git, both /goals are at [`/goals`](/goals), both PRs link back to their plan posts.
76+[`/blog/2026-05/sama-v2-goal-chain-gap`](/blog/2026-05/sama-v2-goal-chain-gap) said *every artifact is auditable*. Now: the *time-cost* of each kind of refactor is auditable too. The git-url postmortem published a 1-hour prediction. This post publishes the 8-minute measurement against it. Both timestamps are in git, both /goals are at [`/goals`](/goals), both PRs link back to their plan posts.
7777
78-Anyone reading [/blog/sama-v2-on-ramp-gap](/blog/sama-v2-on-ramp-gap) wondering *"is this discipline actually faster than the alternative, or is it just talk?"* now has one more data point. Two URL refactors under the same pattern, second one 7.4× faster. The claim is empirical now — not because of one measurement, but because of the **delta** between two.
78+Anyone reading [/blog/2026-05/sama-v2-on-ramp-gap](/blog/2026-05/sama-v2-on-ramp-gap) wondering *"is this discipline actually faster than the alternative, or is it just talk?"* now has one more data point. Two URL refactors under the same pattern, second one 7.4× faster. The claim is empirical now — not because of one measurement, but because of the **delta** between two.
7979
8080 The §5 spec calls this *"compliance proves the rules were followed; the delta proves they were worth following."* That argument has been about cross-repo workingSetFit measurements until now. Today the same argument lands on wall-clock time. Pattern-as-redirect isn't a fashion; it's measurably cheaper the second time.
8181
modified content/blog/sama-v2-sitemap-implementation-plan.md +1 −1
@@ -14,7 +14,7 @@ The combination is what this post is really about. The `/goal` is the *what*; SA
1414 Three concrete signals:
1515
1616 - **`src/a31_blog.ts` already promises it.** The top-of-file comment reads: *"this file is just the registry that drives `/blog`, `/blog/:slug`, **and the sitemap**."* The promise has been there since the registry was written. The sitemap was always meant to exist; it just didn't.
17-- **Empirical chain visibility.** The cross-repo measurement posts ([dive](/blog/sama-v2-go-project-dive), [ripgrep](/blog/sama-v2-rust-project-ripgrep), [n=7 baseline](/blog/sama-v2-workingset-cross-repo-baseline)) are exactly the kind of long-tail content that needs explicit sitemap entries — they're not in the navigation, they don't get linked from the home page indiscriminately, and they're the load-bearing artifacts for the "is SAMA worth following" argument.
17+- **Empirical chain visibility.** The cross-repo measurement posts ([dive](/blog/2026-05/sama-v2-go-project-dive), [ripgrep](/blog/2026-05/sama-v2-rust-project-ripgrep), [n=7 baseline](/blog/2026-05/sama-v2-workingset-cross-repo-baseline)) are exactly the kind of long-tail content that needs explicit sitemap entries — they're not in the navigation, they don't get linked from the home page indiscriminately, and they're the load-bearing artifacts for the "is SAMA worth following" argument.
1818 - **AI crawlers index sitemaps preferentially.** If the empirical chain is the thing I want to be found, the sitemap is the first place to put it.
1919
2020 ## The decomposition — three files, one per layer
modified content/blog/sama-v2-verifier-and-the-rename.md +6 −6
@@ -1,11 +1,11 @@
11 # I built the SAMA v2 verifier. It told me my own repo wasn't v2-compliant. Then I renamed 70 files.
22
33 Three earlier posts in this series were clean v1 round-trips: the
4-[verifier flagged a 761-line `c21_app.ts`](/blog/sama-empirical-c21-split)
4+[verifier flagged a 761-line `c21_app.ts`](/blog/2026-05/sama-empirical-c21-split)
55 and I split it; it flagged
6-[four c32 files missing sibling tests](/blog/sama-empirical-modeled-green)
6+[four c32 files missing sibling tests](/blog/2026-05/sama-empirical-modeled-green)
77 and I added them; a
8-[silent deploy bug hid both the snapshot and the bugs underneath](/blog/deploy-that-lies-cascade)
8+[silent deploy bug hid both the snapshot and the bugs underneath](/blog/2026-05/deploy-that-lies-cascade)
99 and removing the silence surfaced three fixes in one PR. Each was a
1010 small, mechanical loop.
1111
@@ -255,6 +255,6 @@ chain.
255255 - The v1 dogfood (still 4/4 ✓): <https://tdd.md/sama/verify?repo=syntaxai/tdd.md>
256256 - The PR that landed the work: [#16](https://github.com/syntaxai/tdd.md/pull/16)
257257 - Earlier posts in this series:
258- [c21 Atomic split](/blog/sama-empirical-c21-split) ·
259- [Modeled green](/blog/sama-empirical-modeled-green) ·
260- [Deploy that lies](/blog/deploy-that-lies-cascade)
258+ [c21 Atomic split](/blog/2026-05/sama-empirical-c21-split) ·
259+ [Modeled green](/blog/2026-05/sama-empirical-modeled-green) ·
260+ [Deploy that lies](/blog/2026-05/deploy-that-lies-cascade)
modified content/blog/sama-v2-wordpress-plugin-audit.md +2 −2
@@ -144,5 +144,5 @@ The chain extended one more link today: from *"here is the spec and a hypothetic
144144 - The plugin: <https://wordpress.org/plugins/wonderm00ns-simple-facebook-open-graph-tags/>
145145 - The v2 hypothetical plugin profile: [/sama/v2/example-wordpress](/sama/v2/example-wordpress)
146146 - The §5 metric definitions: [/sama/v2#5-operational--core-metrics-definitions](/sama/v2#5-operational--core-metrics-definitions)
147-- Today's earlier post on the §5 emitter: [Compliance proves the rules were followed. Delta proves they were worth following.](/blog/sama-v2-metrics-emitter)
148-- Yesterday's post on building the v2 verifier: [I built the SAMA v2 verifier...](/blog/sama-v2-verifier-and-the-rename)
147+- Today's earlier post on the §5 emitter: [Compliance proves the rules were followed. Delta proves they were worth following.](/blog/2026-05/sama-v2-metrics-emitter)
148+- Yesterday's post on building the v2 verifier: [I built the SAMA v2 verifier...](/blog/2026-05/sama-v2-verifier-and-the-rename)
modified content/blog/sama-v2-wordpress-plugin-rebuilt.md +5 −5
@@ -1,6 +1,6 @@
11 # The Open Graph plugin, rebuilt under SAMA v2 — a thought experiment
22
3-[Yesterday's audit](/blog/sama-v2-wordpress-plugin-audit) walked through what *Open Graph and Twitter Card Tags* (slug `wonderm00ns-simple-facebook-open-graph-tags`, 200k+ installs) looks like through the v2 lens: three god-classes totaling 3,012 lines, 43 raw superglobal accesses, `$wpdb` scattered across layers, zero tests, 0 of 7 §4 checks passing. The post argued — and I still believe — that this score isn't a failure; it's the expected baseline for a plugin built under standard WordPress idioms with no external layer discipline.
3+[Yesterday's audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) walked through what *Open Graph and Twitter Card Tags* (slug `wonderm00ns-simple-facebook-open-graph-tags`, 200k+ installs) looks like through the v2 lens: three god-classes totaling 3,012 lines, 43 raw superglobal accesses, `$wpdb` scattered across layers, zero tests, 0 of 7 §4 checks passing. The post argued — and I still believe — that this score isn't a failure; it's the expected baseline for a plugin built under standard WordPress idioms with no external layer discipline.
44
55 Bas asked the follow-up the audit didn't answer: **what would the same plugin look like if it had been built under v2 from day one?**
66
@@ -316,13 +316,13 @@ This is a thought experiment, not a pull request.
316316 - The §5 deltas in the table above are *predictions*, not measurements. The plugin would have to be actually refactored, the PHP-aware verifier built, and the metrics computed for the numbers to be empirical. Today they're informed guesses.
317317 - "100% v2 compliant" doesn't mean "better." It means "every architectural decision is *visible* in the file tree, every boundary is in one place, every business rule has a unit test that fails for the right reason." Whether that's worth ten months of work for a 200k-install plugin that already does its job is the maintainer's call, not mine.
318318
319-What the sketch buys is the same thing the [§5 metrics emitter](/blog/sama-v2-metrics-emitter) bought: now there's a concrete description of "the same plugin under v2." If the maintainers ever do this refactor — or if someone forks the plugin to build v2-discipline-from-scratch — the deltas are measurable on the axes both versions share. That's the kind of comparison §6 of the spec actually requires before claiming v2 is worth following.
319+What the sketch buys is the same thing the [§5 metrics emitter](/blog/2026-05/sama-v2-metrics-emitter) bought: now there's a concrete description of "the same plugin under v2." If the maintainers ever do this refactor — or if someone forks the plugin to build v2-discipline-from-scratch — the deltas are measurable on the axes both versions share. That's the kind of comparison §6 of the spec actually requires before claiming v2 is worth following.
320320
321321 ---
322322
323323 **Companion posts:**
324324
325-- [The audit](/blog/sama-v2-wordpress-plugin-audit) — pointing v2 at the real plugin: 0 of 7 checks pass, why that's the expected baseline
325+- [The audit](/blog/2026-05/sama-v2-wordpress-plugin-audit) — pointing v2 at the real plugin: 0 of 7 checks pass, why that's the expected baseline
326326 - [The generic WP profile](/sama/v2/example-wordpress) — a hypothetical event-registration plugin under v2 from scratch
327-- [The §5 metrics emitter](/blog/sama-v2-metrics-emitter) — the empirical artefact §6 requires before any later claim can be measured as a delta
328-- [The v2 verifier post](/blog/sama-v2-verifier-and-the-rename) — yesterday's piece on building the verifier itself
327+- [The §5 metrics emitter](/blog/2026-05/sama-v2-metrics-emitter) — the empirical artefact §6 requires before any later claim can be measured as a delta
328+- [The v2 verifier post](/blog/2026-05/sama-v2-verifier-and-the-rename) — yesterday's piece on building the verifier itself
modified content/blog/sama-v2-workingset-cross-repo-baseline.md +4 −4
@@ -1,6 +1,6 @@
11 # Was the dive/ripgrep convergence real? Seven measured workingSetFit datapoints
22
3-The [dive audit](/blog/sama-v2-go-project-dive) and [ripgrep audit](/blog/sama-v2-rust-project-ripgrep) closed with a quietly interesting finding: when I ported the §5 `workingSetFit` metric to Go and Rust and ran it against both repos, they landed within two percentage points of each other — **dive at 52.17%** ([@d6c69194](https://github.com/wagoodman/dive/commit/d6c691947f8fda635c952a17ee3b7555379d58f0)) and **ripgrep at 54.00%** ([@4519153e](https://github.com/BurntSushi/ripgrep/commit/4519153e5e461527f4bca45b042fff45c4ec6fb9)). I noted in the home page table that *"workingSetFit in the 50–55% range may be characteristic of mature compiled-language CLI tools — a hypothesis that needs more datapoints to confirm."*
3+The [dive audit](/blog/2026-05/sama-v2-go-project-dive) and [ripgrep audit](/blog/2026-05/sama-v2-rust-project-ripgrep) closed with a quietly interesting finding: when I ported the §5 `workingSetFit` metric to Go and Rust and ran it against both repos, they landed within two percentage points of each other — **dive at 52.17%** ([@d6c69194](https://github.com/wagoodman/dive/commit/d6c691947f8fda635c952a17ee3b7555379d58f0)) and **ripgrep at 54.00%** ([@4519153e](https://github.com/BurntSushi/ripgrep/commit/4519153e5e461527f4bca45b042fff45c4ec6fb9)). I noted in the home page table that *"workingSetFit in the 50–55% range may be characteristic of mature compiled-language CLI tools — a hypothesis that needs more datapoints to confirm."*
44
55 This post tests that hypothesis. n=2 → n=7, same tool, same bounds, same exclusion rules. Pinned SHAs throughout. The headline:
66
@@ -155,7 +155,7 @@ That's the §0 contract: the program is deterministic; the same source tree + sa
155155
156156 **Companion posts:**
157157
158-- [The dive audit](/blog/sama-v2-go-project-dive) — where the dive measurement is hand-traced
159-- [The ripgrep audit](/blog/sama-v2-rust-project-ripgrep) — where the ripgrep measurement is hand-traced
160-- [The §5 metrics emitter post](/blog/sama-v2-metrics-emitter) — why measurement matters more than estimates
158+- [The dive audit](/blog/2026-05/sama-v2-go-project-dive) — where the dive measurement is hand-traced
159+- [The ripgrep audit](/blog/2026-05/sama-v2-rust-project-ripgrep) — where the ripgrep measurement is hand-traced
160+- [The §5 metrics emitter post](/blog/2026-05/sama-v2-metrics-emitter) — why measurement matters more than estimates
161161 - [The v2.1 dialects (§6.1–6.3)](/sama/v2#6a-v21-dialects-provisional) — particularly §6.2 inline-tests (load-bearing for the Rust file-counting rule above) and §6.3 declarative-exemption (the policy lens for what the raw metric can't distinguish)
modified content/blog/tweag-handbook-tdd.md +1 −1
@@ -138,4 +138,4 @@ Sign in at [tdd.md/you](/you), pick the [string-calc kata](/games/string-calc),
138138
139139 Six steps in, you'll know whether your version of Tweag's loop survives contact with a verifier — or whether it was always passing because nobody else was looking.
140140
141-[← all guides](/guides) · [the kata catalog](/games) · [the Claude Code post](/blog/claude-code-tdd) · [the Cursor post](/blog/cursor-tdd) · [the Aider post](/blog/aider-tdd)
141+[← all guides](/guides) · [the kata catalog](/games) · [the Claude Code post](/blog/2026-05/claude-code-tdd) · [the Cursor post](/blog/2026-05/cursor-tdd) · [the Aider post](/blog/2026-05/aider-tdd)
modified content/home.md +4 −4
@@ -58,7 +58,7 @@ SAMA bundles those findings into four constraints a CI job can enforce. *Sorted*
5858
5959 ## Datapoints on the same axes
6060
61-Empirical baseline so far. The §4 score for this site is [computed live](/sama/v2/verify); the §4 scores for the other repos are hand-estimated. The **workingSetFit** column is now measured for the SAMA dogfood (this site) and seven non-SAMA mature compiled-language CLI tools by the polyglot §5 emitter at [`scripts/measure-working-set.ts`](/GIT/tdd.md/blob/main/scripts/measure-working-set.ts) — see the [seven-datapoint baseline post](/blog/sama-v2-workingset-cross-repo-baseline) for the full table, distribution, and hand-trace.
61+Empirical baseline so far. The §4 score for this site is [computed live](/sama/v2/verify); the §4 scores for the other repos are hand-estimated. The **workingSetFit** column is now measured for the SAMA dogfood (this site) and seven non-SAMA mature compiled-language CLI tools by the polyglot §5 emitter at [`scripts/measure-working-set.ts`](/GIT/tdd.md/blob/main/scripts/measure-working-set.ts) — see the [seven-datapoint baseline post](/blog/2026-05/sama-v2-workingset-cross-repo-baseline) for the full table, distribution, and hand-trace.
6262
6363 | project | language | §4 score | workingSetFit | boundaryRatio | graphDepth |
6464 |---|---|---|---|---|---|
@@ -67,10 +67,10 @@ Empirical baseline so far. The §4 score for this site is [computed live](/sama/
6767 | [**sharkdp/fd**](https://github.com/sharkdp/fd) | Rust | n/a (not audited) | **69.57%** (measured, [@42b2ab8a](https://github.com/sharkdp/fd/commit/42b2ab8a84ddedf80eeed9079128c60161f64658)) | — | — |
6868 | [**jesseduffield/lazygit**](https://github.com/jesseduffield/lazygit) | Go | n/a (not audited) | **67.38%** (measured, [@608c90ae](https://github.com/jesseduffield/lazygit/commit/608c90ae3c1c99ffad9324bfc2613d9d46599992)) | — | — |
6969 | [**eza-community/eza**](https://github.com/eza-community/eza) | Rust | n/a (not audited) | **61.76%** (measured, [@eed27ed0](https://github.com/eza-community/eza/commit/eed27ed05e74542af5852aed40e3dbff87d69c43)) | — | — |
70-| [**BurntSushi/ripgrep**](/blog/sama-v2-rust-project-ripgrep) | Rust | ~3-5 / 7 (estimated, depends on v2.1 dialect uptake) | **54.00%** (measured, [@4519153e](https://github.com/BurntSushi/ripgrep/commit/4519153e5e461527f4bca45b042fff45c4ec6fb9)) | ~95% (estimated) | ~5 (estimated) |
71-| [**wagoodman/dive**](/blog/sama-v2-go-project-dive) | Go | ~5 / 7 (estimated) | **52.17%** (measured, [@d6c69194](https://github.com/wagoodman/dive/commit/d6c691947f8fda635c952a17ee3b7555379d58f0)) | ~85% (estimated) | ~5 (estimated) |
70+| [**BurntSushi/ripgrep**](/blog/2026-05/sama-v2-rust-project-ripgrep) | Rust | ~3-5 / 7 (estimated, depends on v2.1 dialect uptake) | **54.00%** (measured, [@4519153e](https://github.com/BurntSushi/ripgrep/commit/4519153e5e461527f4bca45b042fff45c4ec6fb9)) | ~95% (estimated) | ~5 (estimated) |
71+| [**wagoodman/dive**](/blog/2026-05/sama-v2-go-project-dive) | Go | ~5 / 7 (estimated) | **52.17%** (measured, [@d6c69194](https://github.com/wagoodman/dive/commit/d6c691947f8fda635c952a17ee3b7555379d58f0)) | ~85% (estimated) | ~5 (estimated) |
7272 | [**sharkdp/bat**](https://github.com/sharkdp/bat) | Rust | n/a (not audited) | **46.27%** (measured, [@f3d07734](https://github.com/sharkdp/bat/commit/f3d077346824eae07fbac4b56466d27049b9616e)) | — | — |
73-| [**Open Graph plugin**](/blog/sama-v2-wordpress-plugin-audit) | PHP / WordPress | 0 / 7 (estimated) | ~47% (estimated) | <10% (estimated) | ~3 (estimated) |
73+| [**Open Graph plugin**](/blog/2026-05/sama-v2-wordpress-plugin-audit) | PHP / WordPress | 0 / 7 (estimated) | ~47% (estimated) | <10% (estimated) | ~3 (estimated) |
7474
7575 **The cross-repo signal that emerged**: across the seven non-SAMA mature CLI tools, `workingSetFit` ranges from 46.27% (bat) to 73.59% (cli/gh) — a 27-point spread, mean **60.68%**, sample stddev **10.13pp**. Five of seven cluster inside [52%, 70%]. The original dive/ripgrep 2-point convergence at n=2 was coincidence; the actual distribution is wider, but the clustering is real. **tdd.md** (the SAMA-disciplined dogfood) measures 80.00% — 6.4 percentage points above the top of the non-SAMA baseline. Suggestive but n=1 vs n=7 is far from a SAMA-worth-following claim. §6 of the spec is explicit that promotion requires cross-repo *deltas* across multiple SAMA-disciplined repos; only one exists today. What this nine-row table *does* establish: the empirical chain is now eight workingSetFit values measured against the same bounds the spec defines, which is the prerequisite §6 was always asking for.
7676
modified content/sama/atomic.md +1 −1
@@ -80,7 +80,7 @@ Why this matters:
8080
8181 The threshold is set by what a coding agent can hold in a single tight context window without drift. Past about 700 lines, you start needing to cite line numbers in prompts ("look at the function around line 480") which signals the file has outgrown the agent's working memory. Splitting at the threshold keeps context windows small even for non-trivial domains.
8282
83-It also keeps **token cost** bounded. An agent given "edit `c51_render_reports.ts`" pulls in one bounded file plus its sibling test, and not the entire layer. That's the same constraint the [token-saving tips](/blog/three-constraints-agentic-coding) push from the prompt side; *Atomic* enforces it from the codebase side.
83+It also keeps **token cost** bounded. An agent given "edit `c51_render_reports.ts`" pulls in one bounded file plus its sibling test, and not the entire layer. That's the same constraint the [token-saving tips](/blog/2026-05/three-constraints-agentic-coding) push from the prompt side; *Atomic* enforces it from the codebase side.
8484
8585 ## Common mistakes
8686
modified content/sama/skill.md +3 −3
@@ -185,9 +185,9 @@ Or, if the live and demo body builders are mostly the same shape parameterised b
185185 ## Reference
186186
187187 - The four disciplines with examples: https://tdd.md/sama
188-- Why SAMA compounds with TDD and token-discipline: https://tdd.md/blog/three-constraints-agentic-coding
189-- The Reddit harness postmortem this skill is a response to: https://tdd.md/blog/claude-code-harness-postmortem
190-- Ten more threads, three patterns, mitigation tables: https://tdd.md/blog/agentic-coding-corpus-three-patterns
188+- Why SAMA compounds with TDD and token-discipline: https://tdd.md/blog/2026-05/three-constraints-agentic-coding
189+- The Reddit harness postmortem this skill is a response to: https://tdd.md/blog/2026-05/claude-code-harness-postmortem
190+- Ten more threads, three patterns, mitigation tables: https://tdd.md/blog/2026-05/agentic-coding-corpus-three-patterns
191191 - Mechanically verify any public repo against these rules: https://tdd.md/sama/verify
192192
193193 <!-- git-native proof @ 2026-05-22T08:42:54.742Z -->
modified content/sama/v2.md +3 −3
@@ -211,7 +211,7 @@ layout = "directory" # default when absent: "prefix" (v2.0 behaviour)
211211
212212 **How the dialect preserves that property.** Under `layout = "directory"`, the Sorted check verifies that the profile declares **packages or crate directories** in layer order, and that the language's compile-time dependency check (Go's `internal/` semantics, Rust's Cargo crate graph, etc.) plus the absence of upward edges in the import graph confirms the lex-order of declared package paths matches actual import direction. The reviewer's analogue of `ls src/ | sort` becomes `cat sama.profile.toml | grep packages =` — still mechanical, still ahead of the build. The property is the same; the surface syntax shifts from per-file prefix to per-directory declaration.
213213
214-**Falsifiable cross-repo experiment.** Run the §5 metrics emitter on a corpus of agent-authored Go and Rust commits, half against `layout = "prefix"` (with a synthetic prefix renaming) and half against `layout = "directory"` (against the natural package layout). The dialect is invalidated if the directory mode systematically reports a different violation set on Sorted than the prefix mode does on the same logical defects. Originally surfaced in the [`dive` audit](/blog/sama-v2-go-project-dive) and [`dive` rebuild sketch](/blog/sama-v2-go-project-dive-rebuilt); confirmed independently by the [`ripgrep` audit](/blog/sama-v2-rust-project-ripgrep).
214+**Falsifiable cross-repo experiment.** Run the §5 metrics emitter on a corpus of agent-authored Go and Rust commits, half against `layout = "prefix"` (with a synthetic prefix renaming) and half against `layout = "directory"` (against the natural package layout). The dialect is invalidated if the directory mode systematically reports a different violation set on Sorted than the prefix mode does on the same logical defects. Originally surfaced in the [`dive` audit](/blog/2026-05/sama-v2-go-project-dive) and [`dive` rebuild sketch](/blog/2026-05/sama-v2-go-project-dive-rebuilt); confirmed independently by the [`ripgrep` audit](/blog/2026-05/sama-v2-rust-project-ripgrep).
215215
216216 ### 6.2 Inline-tests dialect
217217
@@ -229,7 +229,7 @@ tests = "inline" # default when absent: "sibling" (v2.0 behaviour)
229229
230230 **How the dialect preserves that property.** Under `tests = "inline"`, the Modeled-tests check scans each Layer 1 / Layer 2 source file for in-file test attachments (`#[cfg(test)] mod tests { #[test] fn ... }` in Rust; equivalent annotations in other languages whose convention is inline tests). A behavioural file with no inline `#[test]` block fails the check exactly as a file with no sibling `*.test.ts` would under v2.0. *Where* the test attaches changes (same file vs sibling file); *that* every behavioural unit has an attached test does not.
231231
232-**Falsifiable cross-repo experiment.** Audit a Rust corpus (e.g. the popular CLI tools `bat`, `fd`, `ripgrep`, `eza`) under both `tests = "sibling"` (which the convention does not produce) and `tests = "inline"` (which it does). The dialect is invalidated if inline-mode systematically classifies files as tested that sibling-mode-on-a-renamed-corpus would not — i.e. if the surface-syntax change quietly admits genuinely untested files. Originally surfaced in the [`ripgrep` audit](/blog/sama-v2-rust-project-ripgrep) and [`ripgrep` rebuild sketch](/blog/sama-v2-rust-project-ripgrep-rebuilt).
232+**Falsifiable cross-repo experiment.** Audit a Rust corpus (e.g. the popular CLI tools `bat`, `fd`, `ripgrep`, `eza`) under both `tests = "sibling"` (which the convention does not produce) and `tests = "inline"` (which it does). The dialect is invalidated if inline-mode systematically classifies files as tested that sibling-mode-on-a-renamed-corpus would not — i.e. if the surface-syntax change quietly admits genuinely untested files. Originally surfaced in the [`ripgrep` audit](/blog/2026-05/sama-v2-rust-project-ripgrep) and [`ripgrep` rebuild sketch](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt).
233233
234234 ### 6.3 Declarative-exemption dialect
235235
@@ -247,7 +247,7 @@ atomic_exemption = "declarative" # default when absent: "none" (v2.0 behaviour
247247
248248 **How the dialect preserves that property.** Under `atomic_exemption = "declarative"`, the Atomic check exempts from the LOC cap files whose content is overwhelmingly *declarative* — a file is declarative if it crosses the cap **and** its cyclomatic complexity per LOC drops below 0.05 **and** its body is predominantly `impl X for Y` / `const FOO: T = ...` / `pub struct ...` items (or the language's equivalent). The intuition: a flag-definition catalog or a static type-table is structurally large but does not require holistic loading by an agent — the agent indexes into it by name, not by reading it linearly. The working-set property is preserved for the files that *would* harm an agent's context (behavioural complexity) and selectively waived for files where the cap was a false positive (declarative shape). The 7,779-line `crates/core/flags/defs.rs` in `ripgrep` is the textbook case: 150 flag definitions, each a small struct + small impl, CC/LOC ≈ 0.01.
249249
250-**Falsifiable cross-repo experiment.** Across a multi-language corpus of agent-edit failures (cases where an LLM produced a regression while editing a single file), compute the share that fall in declarative-exempt files vs in over-cap behavioural files. The dialect is invalidated if declarative-exempt files correlate with edit failures at the same or higher rate than over-cap behavioural files do — i.e. if the heuristic exempts files the agent actually struggles with. Originally surfaced in the [`ripgrep` audit](/blog/sama-v2-rust-project-ripgrep) and [`ripgrep` rebuild sketch](/blog/sama-v2-rust-project-ripgrep-rebuilt).
250+**Falsifiable cross-repo experiment.** Across a multi-language corpus of agent-edit failures (cases where an LLM produced a regression while editing a single file), compute the share that fall in declarative-exempt files vs in over-cap behavioural files. The dialect is invalidated if declarative-exempt files correlate with edit failures at the same or higher rate than over-cap behavioural files do — i.e. if the heuristic exempts files the agent actually struggles with. Originally surfaced in the [`ripgrep` audit](/blog/2026-05/sama-v2-rust-project-ripgrep) and [`ripgrep` rebuild sketch](/blog/2026-05/sama-v2-rust-project-ripgrep-rebuilt).
251251
252252 ---
253253
modified goals/contributing-md.md +7 −7
@@ -9,14 +9,14 @@ status: shipped
99 related_posts: [sama-v2-on-ramp-gap]
1010 ---
1111
12-Goal: Build the canonical contributor on-ramp that /blog/sama-v2-on-ramp-gap argued is missing. One markdown file at the repo root (./CONTRIBUTING.md), browseable via the site's own /GIT/ surface (auto), AND served at /contributing on tdd.md (canonical permalink). No GitHub dependency — external contributors engage via git.tdd.md/issues, not github.com. Three load-bearing properties: (1) single source of truth — every rule LINKS to its canonical artifact, doesn't restate; (2) dogfooded — this goal file is committed BEFORE any code per the workflow memory, and the file goes live with merge_sha filled at deploy; (3) drift-detectable — a sibling test grep-checks CONTRIBUTING.md contains references to canonical sources + enforces a line-count ceiling so future bloat is caught.
12+Goal: Build the canonical contributor on-ramp that /blog/2026-05/sama-v2-on-ramp-gap argued is missing. One markdown file at the repo root (./CONTRIBUTING.md), browseable via the site's own /GIT/ surface (auto), AND served at /contributing on tdd.md (canonical permalink). No GitHub dependency — external contributors engage via git.tdd.md/issues, not github.com. Three load-bearing properties: (1) single source of truth — every rule LINKS to its canonical artifact, doesn't restate; (2) dogfooded — this goal file is committed BEFORE any code per the workflow memory, and the file goes live with merge_sha filled at deploy; (3) drift-detectable — a sibling test grep-checks CONTRIBUTING.md contains references to canonical sources + enforces a line-count ceiling so future bloat is caught.
1313
1414 Done when:
1515 - ./CONTRIBUTING.md exists at the repo root with the on-ramp content covering:
16- * "Before you start" — links to /sama/v2 (spec), /blog/sama-v2-on-ramp-gap (this drama), /blog/sama-v2-goal-chain-gap (the prior drama), and a one-line statement that /sama/v2/verify must stay 7/7 ✓ across every merge.
16+ * "Before you start" — links to /sama/v2 (spec), /blog/2026-05/sama-v2-on-ramp-gap (this drama), /blog/2026-05/sama-v2-goal-chain-gap (the prior drama), and a one-line statement that /sama/v2/verify must stay 7/7 ✓ across every merge.
1717 * "The /goal workflow" — 5-7 lines summarizing the rule from /goals/migrate-historical-goals (which contains the verbatim authoritative version); link points there.
1818 * "SAMA layer convention" — a table of prefix → layer with concrete examples from this repo (a31_blog.ts, b32_sitemap.ts, c14_git.ts, d21_app.ts, b51_render_layout.ts). Each row LINKS to /sama/v2#11-layers for the canonical definition.
19- * "How to add a blog post" — recipe: write content/blog/<slug>.md, add ALL_POSTS entry in src/a31_blog.ts, branch + PR + merge + deploy. Link to /blog/sama-v2-sitemap-implementation-plan as a worked example.
19+ * "How to add a blog post" — recipe: write content/blog/<slug>.md, add ALL_POSTS entry in src/a31_blog.ts, branch + PR + merge + deploy. Link to /blog/2026-05/sama-v2-sitemap-implementation-plan as a worked example.
2020 * "How to add a /goal" — recipe: type /goal in the conversation, the agent's first action is to write goals/<slug>.md per the workflow. Human path: file an issue at git.tdd.md/syntaxai/tdd.md/issues with the Goal/Done-when/Constraints/Load-bearing-files shape.
2121 * "How to add an image" — recipe: public/images/<name>.svg + rsvg-convert PNG, both must carry the literal text "https://tdd.md" as a watermark. Link to the /images/* wildcard handler in d21_handlers_fallback.ts.
2222 * "How to add a Layer-1 helper" — recipe: b32_<name>.ts + sibling b32_<name>.test.ts, no I/O in the helper. Link to /sama/v2#41-sorted and /sama/v2#43-modeled-tests.
@@ -29,8 +29,8 @@ Done when:
2929 - Drift-detection test src/b32_contributing_drift.test.ts (Layer 1 pure — reads ./CONTRIBUTING.md once at test time, asserts on its contents):
3030 * test: contains link to /sama/v2 (the spec is referenced)
3131 * test: contains link to /goals/migrate-historical-goals (the /goal workflow's canonical version)
32- * test: contains link to /blog/sama-v2-on-ramp-gap (this drama post)
33- * test: contains link to /blog/sama-v2-goal-chain-gap (the prior drama)
32+ * test: contains link to /blog/2026-05/sama-v2-on-ramp-gap (this drama post)
33+ * test: contains link to /blog/2026-05/sama-v2-goal-chain-gap (the prior drama)
3434 * test: contains link to git.tdd.md/syntaxai/tdd.md/issues (the external engagement path)
3535 * test: line count < 250 (bloat ceiling — restatement detection)
3636 - The /contributing detail page reads ./CONTRIBUTING.md and renders it through renderDocsPage with active: "goals"-or-equivalent. The Section type may need a new "contributing" value or we route /contributing as a generic markdown route — agent choice based on whichever keeps the nav highlighting consistent.
@@ -39,7 +39,7 @@ Done when:
3939 - This goal file (goals/contributing-md.md) flipped from status: pending to status: shipped in the final commit before deploy, with merge_sha filled from the PR's merge commit. PR body MUST include the verbatim /goal text under a "## /goal" heading per feedback_goal_authoring_workflow.md.
4040 - Deployed; live-verify with curl:
4141 * /contributing → 200, body contains the section headers
42- * /GIT/tdd.md/blob/main/CONTRIBUTING.md → 200 (the link in /blog/sama-v2-on-ramp-gap stops 404'ing)
42+ * /GIT/tdd.md/blob/main/CONTRIBUTING.md → 200 (the link in /blog/2026-05/sama-v2-on-ramp-gap stops 404'ing)
4343 * /sitemap.xml | grep -c '/contributing' → at least 1
4444 * /sama/v2/verify → 7/7 ✓
4545 * Nav across pages shows /contributing link
@@ -55,7 +55,7 @@ Constraints (anti-fudge):
5555 - Don't create a content/contributing.md — the file lives at the repo root (./CONTRIBUTING.md) so GitHub-style tooling on Forgejo recognizes it AND the /GIT/ browser surfaces it at the root level alongside README.md. content/blog/ is for blog posts; CONTRIBUTING.md is project-meta, lives at root.
5656
5757 Load-bearing files to read FIRST:
58-- /blog/sama-v2-on-ramp-gap (the design spec — read it first; the sketch in the "fix" section is what this /goal executes)
58+- /blog/2026-05/sama-v2-on-ramp-gap (the design spec — read it first; the sketch in the "fix" section is what this /goal executes)
5959 - /goals/migrate-historical-goals (the canonical /goal workflow definition that CONTRIBUTING.md will link to, not restate)
6060 - /var/home/scri/.claude/projects/-var-home-scri-Documents-tdd-md/memory/feedback_goal_authoring_workflow.md (the dogfood rule this goal executes for the second time)
6161 - src/d21_handlers_sama.ts (samaLandingHandler — the pattern the /contributing handler should mirror, but reading from a root file instead of content/sama/)
modified goals/git-url-drop-owner.md +3 −3
@@ -9,7 +9,7 @@ status: shipped
99 related_posts: [sama-v2-git-url-refactor-plan, sama-v2-git-url-refactor-postmortem]
1010 ---
1111
12-Goal: Execute the URL refactor described in https://tdd.md/blog/sama-v2-git-url-refactor-plan — drop the redundant `:owner` segment from /GIT/:owner/:repo/ URLs so /GIT/syntaxai/tdd.md/blob/main/src/b32_sama_v2_verify.ts becomes /GIT/tdd.md/blob/main/src/b32_sama_v2_verify.ts. The blog post is the design spec; this /goal is the execution checklist. Single-tenant is already enforced by isAllowedRepo() in src/d21_handlers_repo_browse.ts:26-30 (404s anything that isn't syntaxai/tdd.md), so the owner segment is policy overhead, not data. Inbound links survive via ONE regex 301 redirect in the fallback handler — no hand-maintained URL map.
12+Goal: Execute the URL refactor described in https://tdd.md/blog/2026-05/sama-v2-git-url-refactor-plan — drop the redundant `:owner` segment from /GIT/:owner/:repo/ URLs so /GIT/syntaxai/tdd.md/blob/main/src/b32_sama_v2_verify.ts becomes /GIT/tdd.md/blob/main/src/b32_sama_v2_verify.ts. The blog post is the design spec; this /goal is the execution checklist. Single-tenant is already enforced by isAllowedRepo() in src/d21_handlers_repo_browse.ts:26-30 (404s anything that isn't syntaxai/tdd.md), so the owner segment is policy overhead, not data. Inbound links survive via ONE regex 301 redirect in the fallback handler — no hand-maintained URL map.
1313
1414 Done when:
1515 - The four /GIT/ URL kinds work under the new shape:
@@ -54,7 +54,7 @@ Done when:
5454 * /GIT/tdd.md/raw/main/sama.profile.toml → 200, text/plain
5555 * /GIT/syntaxai/tdd.md/blob/main/README.md → 301 with Location /GIT/tdd.md/blob/main/README.md
5656 * curl -sL of the old URL lands on the new one and returns the file content
57- * Visit https://tdd.md/blog/sama-v2-git-url-refactor-plan and click any /GIT/ link in the rendered HTML → lands on a 200 (no broken navigation after rewrite).
57+ * Visit https://tdd.md/blog/2026-05/sama-v2-git-url-refactor-plan and click any /GIT/ link in the rendered HTML → lands on a 200 (no broken navigation after rewrite).
5858
5959 Constraints (anti-fudge):
6060 - One regex for the redirect — no per-URL hand-maintained mapping. If the regex grows into "a list" the anti-fudge clause is violated.
@@ -66,7 +66,7 @@ Constraints (anti-fudge):
6666 - Do NOT change any §4 verifier logic.
6767
6868 Load-bearing files to read FIRST:
69-- The plan post: https://tdd.md/blog/sama-v2-git-url-refactor-plan (the design spec — read this before any code; the SAMA-layer mapping and design rationale are there, not duplicated in this /goal)
69+- The plan post: https://tdd.md/blog/2026-05/sama-v2-git-url-refactor-plan (the design spec — read this before any code; the SAMA-layer mapping and design rationale are there, not duplicated in this /goal)
7070 - src/d21_handlers_fallback.ts (lines 89-117 — bareGitUrl block + gitBrowseMatch regex; the new 301 redirect goes BEFORE gitBrowseMatch)
7171 - src/d21_handlers_repo_browse.ts (parseRepoBrowsePath at line 56, isAllowedRepo at line 26, repoBrowseHandler signature at line 69)
7272 - src/d21_handlers_commit_view.ts (commitViewHandler signature — drop owner arg)
modified goals/migrate-historical-goals.md +1 −1
@@ -44,7 +44,7 @@ Workflow lock-in (defense-in-depth):
4444 Rule: When the user fires a /goal slash command, the agent's FIRST tool call (before any Read, Bash, or other Edit) is to write the verbatim /goal body to goals/<slug>.md with frontmatter status: pending, merge_sha: null, pr_number: null, date: <today>, branch: <intended branch name>, title: <one-line title from the Goal: paragraph>, related_posts: []. Commit this on a new branch as the FIRST commit of the PR.
4545 Additionally, when creating the PR via `gh pr create`, the --body MUST include the verbatim /goal text as the first section (under a "## /goal" heading), followed by the existing "## Summary" + "## Test plan" sections. This is the defense-in-depth: even if goals/ is corrupted, the PR body always has the verbatim text.
4646 After merge, the agent's FINAL commit before deploy updates merge_sha + flips status to shipped in the same goals/<slug>.md file.
47- Why: the empirical chain has historically had a hole the shape of goal.md (see /blog/sama-v2-goal-chain-gap). The two redundant captures — goals/ file AND PR body — close the hole twice.
47+ Why: the empirical chain has historically had a hole the shape of goal.md (see /blog/2026-05/sama-v2-goal-chain-gap). The two redundant captures — goals/ file AND PR body — close the hole twice.
4848 How to apply: triggered on the literal token "/goal" in user message OR when user pastes a "Goal: ... Done when: ... Constraints: ... Load-bearing files:"-shaped block. Skip if user is asking ABOUT a /goal rather than firing one (e.g. "should I fire this /goal?", "look at this /goal" — those are questions not invocations).
4949 - Add a one-line index entry in MEMORY.md pointing at the new file, between feedback_jolo_mode and feedback_flatpak_host_tools (the related JOLO pacing memory + the github-flow memory are this rule's neighbors).
5050 - Add `/goal.md` (the repo-root scratch file) to .gitignore so it can never accidentally land in a commit. Do NOT delete goal.md — it may have in-flight content; just ignore it.
modified goals/sama-discipline-prefix.md +1 −1
@@ -68,4 +68,4 @@ Load-bearing files to read FIRST:
6868 - src/d21_handlers_sama.ts (SAMA_LANDING_MD template — discipline row links)
6969 - src/a31_sama.ts (ALL_SAMA — should remain unchanged; only URL emission changes downstream)
7070 - content/sama/*.md (cross-discipline link rewrites)
71-- /blog/sama-v2-git-url-refactor-postmortem (the hypothesis being tested — re-read so the postmortem's framing stays consistent)
71+- /blog/2026-05/sama-v2-git-url-refactor-postmortem (the hypothesis being tested — re-read so the postmortem's framing stays consistent)
modified goals/sitemap-xml-impl.md +1 −1
@@ -30,7 +30,7 @@ Done when:
3030 - The sitemap is NOT committed as a static file — it's generated per-request (or once at process startup). New blog post → next sitemap fetch already includes it without any human edit. This is the load-bearing "automatic" property.
3131 - All 367+ tests still pass; new helper test adds ~6-8 cases.
3232 - /sama/v2/verify still reports 7/7 ✓ (anti-fudge).
33-- Deployed; live-verify: curl https://tdd.md/sitemap.xml returns 200 + valid XML; the response includes /blog/sama-v2-workingset-cross-repo-baseline (the most recent post); /robots.txt references the sitemap.
33+- Deployed; live-verify: curl https://tdd.md/sitemap.xml returns 200 + valid XML; the response includes /blog/2026-05/sama-v2-workingset-cross-repo-baseline (the most recent post); /robots.txt references the sitemap.
3434
3535 Constraints (anti-fudge):
3636 - URLs MUST come from existing registries — no second source of truth that can drift.
added scripts/migrate-blog-urls.ts +69 −0
@@ -0,0 +1,69 @@
1+// One-shot migration: rewrite /blog/<slug> → /blog/<yyyy-mm>/<slug>
2+// across every .md and .ts file in content/ + src/, using ALL_POSTS
3+// as the single source of truth for each post's date.
4+//
5+// Sorts replacements by slug length DESCENDING so longer slugs
6+// substitute first — prevents the prefix-collision footgun where
7+// /blog/foo would match inside /blog/foo-bar before /blog/foo-bar
8+// got its turn.
9+//
10+// Safe to re-run: replacement looks for `/blog/<slug>` literal, and
11+// after one pass each occurrence becomes `/blog/<yyyymm>/<slug>` —
12+// which doesn't contain `/blog/<slug>` as a substring (the 7th char
13+// differs). No double-prefixing.
14+
15+import { Glob } from "bun";
16+import { ALL_POSTS } from "../src/a31_blog.ts";
17+
18+const root = "/var/home/scri/Documents/tdd.md";
19+
20+const replacements: Array<[string, string]> = ALL_POSTS
21+ .map((p) => {
22+ const yyyymm = p.date.slice(0, 7);
23+ return [`/blog/${p.slug}`, `/blog/${yyyymm}/${p.slug}`] as [string, string];
24+ })
25+ // Longest first to avoid /blog/foo matching inside /blog/foo-bar.
26+ .sort((a, b) => b[0].length - a[0].length);
27+
28+const targets: string[] = [];
29+for await (const path of new Glob("content/**/*.md").scan({ cwd: root })) {
30+ targets.push(path);
31+}
32+for await (const path of new Glob("src/**/*.ts").scan({ cwd: root })) {
33+ // Don't migrate the helper itself or its sibling test — they
34+ // legitimately reference the old shape (regex pattern + test cases).
35+ if (path === "src/b32_blog_date_url_redirect.ts") continue;
36+ if (path === "src/b32_blog_date_url_redirect.test.ts") continue;
37+ targets.push(path);
38+}
39+for await (const path of new Glob("goals/*.md").scan({ cwd: root })) {
40+ // Don't touch the migrate-historical-goals or this PR's goal file —
41+ // those describe historical state and would drift.
42+ if (path === "goals/blog-date-prefix.md") continue;
43+ targets.push(path);
44+}
45+
46+let totalFilesChanged = 0;
47+let totalReplacements = 0;
48+for (const target of targets) {
49+ const fullPath = `${root}/${target}`;
50+ const original = await Bun.file(fullPath).text();
51+ let modified = original;
52+ let fileReplacements = 0;
53+ for (const [oldStr, newStr] of replacements) {
54+ const before = modified;
55+ modified = modified.replaceAll(oldStr, newStr);
56+ if (modified !== before) {
57+ // Count how many replacements happened on THIS pair.
58+ const occurrences = before.split(oldStr).length - 1;
59+ fileReplacements += occurrences;
60+ }
61+ }
62+ if (modified !== original) {
63+ await Bun.write(fullPath, modified);
64+ totalFilesChanged += 1;
65+ totalReplacements += fileReplacements;
66+ console.log(` ${target}: ${fileReplacements} substitutions`);
67+ }
68+}
69+console.log(`\nDone. ${totalFilesChanged} files modified, ${totalReplacements} substitutions.`);
modified src/a31_blog.ts +1 −1
@@ -21,7 +21,7 @@ export const ALL_POSTS: BlogEntry[] = [
2121 {
2222 slug: "sama-v2-on-ramp-gap",
2323 title: "Every artifact has a URL. The on-ramp doesn't.",
24- description: "Open tdd.md in a fresh browser. Count the entry points — /sama/v2 (spec), /sama/v2/verify (live), /blog (narrative), /goals (contracts), /GIT/tdd.md (source), /sitemap.xml (every URL). Six artifacts, each auditable, each its own blog post subject. Now ask the question the site exists to answer for a reader: 'how do I contribute?' There is no answer. No CONTRIBUTING.md, no /contributing URL, no canonical on-ramp anywhere. Forty PRs of preaching auditability — and the most basic on-ramp test failing the entire time. This post is the drama. Walks the artifact-vs-path table: every OUTPUT lives in a canonical place (✓), every authoring rule lives somewhere a contributor wouldn't think to look (the /goal workflow rule is in an agent-private memory file that humans literally cannot read; the layer convention is in /sama/v2 §1.1 + /sama/discipline/sorted + the source tree; the branch-PR-deploy flow is scattered across PR commit messages and individual /goal bodies; the image convention lives in memory only; the Containerfile gotcha lives in one PR's commit message). Concrete 10-step thought experiment of what a new contributor adding their first blog post would actually have to do — ends in 'give up, open an issue saying how do I contribute'. Frames this as a SAMA v2 self-violation parallel to /blog/sama-v2-goal-chain-gap one level up: that post fixed the /goal in the chain; this post argues the workflow itself is the next missing artifact, same structural failure applied to procedure instead of contract. Sketches the fix: one CONTRIBUTING.md, two surfaces (./CONTRIBUTING.md at repo root + /contributing on the site, same markdown source), with three load-bearing properties — single source of truth (links don't restate), dogfooded (its own creation is /goal-driven at /goals/contributing-md), drift-detectable (a test that grep-checks CONTRIBUTING.md contains only references not restatements). The /goal that drives the implementation follows this post per the plan-execute-postmortem pattern.",
24+ description: "Open tdd.md in a fresh browser. Count the entry points — /sama/v2 (spec), /sama/v2/verify (live), /blog (narrative), /goals (contracts), /GIT/tdd.md (source), /sitemap.xml (every URL). Six artifacts, each auditable, each its own blog post subject. Now ask the question the site exists to answer for a reader: 'how do I contribute?' There is no answer. No CONTRIBUTING.md, no /contributing URL, no canonical on-ramp anywhere. Forty PRs of preaching auditability — and the most basic on-ramp test failing the entire time. This post is the drama. Walks the artifact-vs-path table: every OUTPUT lives in a canonical place (✓), every authoring rule lives somewhere a contributor wouldn't think to look (the /goal workflow rule is in an agent-private memory file that humans literally cannot read; the layer convention is in /sama/v2 §1.1 + /sama/discipline/sorted + the source tree; the branch-PR-deploy flow is scattered across PR commit messages and individual /goal bodies; the image convention lives in memory only; the Containerfile gotcha lives in one PR's commit message). Concrete 10-step thought experiment of what a new contributor adding their first blog post would actually have to do — ends in 'give up, open an issue saying how do I contribute'. Frames this as a SAMA v2 self-violation parallel to /blog/2026-05/sama-v2-goal-chain-gap one level up: that post fixed the /goal in the chain; this post argues the workflow itself is the next missing artifact, same structural failure applied to procedure instead of contract. Sketches the fix: one CONTRIBUTING.md, two surfaces (./CONTRIBUTING.md at repo root + /contributing on the site, same markdown source), with three load-bearing properties — single source of truth (links don't restate), dogfooded (its own creation is /goal-driven at /goals/contributing-md), drift-detectable (a test that grep-checks CONTRIBUTING.md contains only references not restatements). The /goal that drives the implementation follows this post per the plan-execute-postmortem pattern.",
2525 date: "2026-05-25",
2626 },
2727 {
modified src/a31_goals.ts +1 −1
@@ -9,7 +9,7 @@
99 // SHA doesn't exist when the /goal is written (chicken-and-egg), and
1010 // /goals/<slug> is a more readable canonical permalink. SHA lookup
1111 // still works in one grep: `grep -l "merge_sha: 968890f" goals/`.
12-// See /blog/sama-v2-goal-chain-gap for the design rationale.
12+// See /blog/2026-05/sama-v2-goal-chain-gap for the design rationale.
1313
1414 // Five-status taxonomy:
1515 // pending — in-flight; mergeSha/prNumber null; file exists on the branch
added src/b32_blog_date_url_redirect.test.ts +52 −0
@@ -0,0 +1,52 @@
1+import { describe, expect, test } from "bun:test";
2+import { rewriteOldBlogUrl } from "./b32_blog_date_url_redirect.ts";
3+import { ALL_POSTS } from "./a31_blog.ts";
4+
5+describe("rewriteOldBlogUrl", () => {
6+ test("rewrites a known-existing post to /blog/<yyyy-mm>/<slug>", () => {
7+ const post = ALL_POSTS[0]!;
8+ const yyyymm = post.date.slice(0, 7);
9+ expect(rewriteOldBlogUrl(`/blog/${post.slug}`)).toBe(
10+ `/blog/${yyyymm}/${post.slug}`,
11+ );
12+ });
13+
14+ test("rewrites a different known-existing post (different date)", () => {
15+ const second = ALL_POSTS.find((p) => p.date !== ALL_POSTS[0]!.date);
16+ if (second === undefined) {
17+ // Skip if all posts share a date — corpus too small to test.
18+ return;
19+ }
20+ const yyyymm = second.date.slice(0, 7);
21+ expect(rewriteOldBlogUrl(`/blog/${second.slug}`)).toBe(
22+ `/blog/${yyyymm}/${second.slug}`,
23+ );
24+ });
25+
26+ test("returns null for an unknown slug (post not in ALL_POSTS)", () => {
27+ expect(rewriteOldBlogUrl("/blog/this-slug-does-not-exist")).toBe(null);
28+ });
29+
30+ test("returns null for already-new-form URLs (with date prefix)", () => {
31+ expect(rewriteOldBlogUrl("/blog/2026-05/some-slug")).toBe(null);
32+ });
33+
34+ test("returns null for /blog landing", () => {
35+ expect(rewriteOldBlogUrl("/blog")).toBe(null);
36+ });
37+
38+ test("returns null for non-/blog paths", () => {
39+ expect(rewriteOldBlogUrl("/sama/v2")).toBe(null);
40+ expect(rewriteOldBlogUrl("/goals/foo")).toBe(null);
41+ expect(rewriteOldBlogUrl("/")).toBe(null);
42+ expect(rewriteOldBlogUrl("")).toBe(null);
43+ });
44+
45+ test("yyyymm prefix has length exactly 7 (YYYY-MM)", () => {
46+ const post = ALL_POSTS[0]!;
47+ const result = rewriteOldBlogUrl(`/blog/${post.slug}`)!;
48+ const yyyymm = result.split("/")[2]!;
49+ expect(yyyymm.length).toBe(7);
50+ expect(yyyymm).toMatch(/^\d{4}-\d{2}$/);
51+ });
52+});
added src/b32_blog_date_url_redirect.ts +24 −0
@@ -0,0 +1,24 @@
1+// b32 — Layer 1 helper: rewrite the legacy /blog/<slug> URL shape
2+// to /blog/<yyyy-mm>/<slug>. Third instance of the b32_<old>_url_redirect
3+// pattern, and the FIRST data-driven one — the new URL depends on the
4+// post's date field, looked up in ALL_POSTS. The git-url and sama-
5+// discipline redirects used fixed-enum regexes; this one needs per-
6+// entity metadata to construct the target.
7+//
8+// Layer-1 importing Layer-0 is allowed (and necessary here) — the
9+// data is already resolved at module load; no fs.readFile, no fetch.
10+
11+import { ALL_POSTS } from "./a31_blog.ts";
12+
13+const OLD_PATTERN = /^\/blog\/([a-z0-9][a-z0-9-]*)$/;
14+
15+export const rewriteOldBlogUrl = (pathname: string): string | null => {
16+ const m = OLD_PATTERN.exec(pathname);
17+ if (m === null) return null;
18+ const slug = m[1]!;
19+ const post = ALL_POSTS.find((p) => p.slug === slug);
20+ if (post === undefined) return null;
21+ // date is "YYYY-MM-DD" — take "YYYY-MM" as the URL prefix.
22+ const yyyymm = post.date.slice(0, 7);
23+ return `/blog/${yyyymm}/${slug}`;
24+};
modified src/b32_contributing_drift.test.ts +2 −2
@@ -23,11 +23,11 @@ describe("CONTRIBUTING.md drift detection", () => {
2323 });
2424
2525 test("links to the on-ramp gap drama post", () => {
26- expect(contributingMd).toContain("/blog/sama-v2-on-ramp-gap");
26+ expect(contributingMd).toContain("/blog/2026-05/sama-v2-on-ramp-gap");
2727 });
2828
2929 test("links to the chain-gap drama post (prior context)", () => {
30- expect(contributingMd).toContain("/blog/sama-v2-goal-chain-gap");
30+ expect(contributingMd).toContain("/blog/2026-05/sama-v2-goal-chain-gap");
3131 });
3232
3333 test("links to the external-engagement issue tracker", () => {
modified src/b32_edit_resolve.ts +13 −5
@@ -59,11 +59,19 @@ export const resolveEdit = (section: string, slug: string): ResolvedEdit | null
5959 const title = lookupTitle(section, slug);
6060 if (title === null) return null;
6161 // /sama discipline pages live under /sama/discipline/<slug> as of
62- // PR #53; other sections keep the /<section>/<slug> shape.
63- const pageUrl =
64- section === "sama" && slug !== "skill" && slug !== "v2"
65- ? `/sama/discipline/${slug}`
66- : `/${section}/${slug}`;
62+ // PR #53. /blog pages live under /blog/<yyyy-mm>/<slug> as of PR #55.
63+ // Other sections keep the flat /<section>/<slug> shape.
64+ let pageUrl: string;
65+ if (section === "sama" && slug !== "skill" && slug !== "v2") {
66+ pageUrl = `/sama/discipline/${slug}`;
67+ } else if (section === "blog") {
68+ const post = ALL_POSTS.find((p) => p.slug === slug);
69+ pageUrl = post
70+ ? `/blog/${post.date.slice(0, 7)}/${slug}`
71+ : `/blog/${slug}`;
72+ } else {
73+ pageUrl = `/${section}/${slug}`;
74+ }
6775 return {
6876 section,
6977 slug,
modified src/b32_sitemap.test.ts +1 −1
@@ -16,7 +16,7 @@ describe("escapeXml", () => {
1616 });
1717
1818 test("leaves regular URL characters untouched", () => {
19- const s = "https://tdd.md/blog/sama-v2-workingset-cross-repo-baseline";
19+ const s = "https://tdd.md/blog/2026-05/sama-v2-workingset-cross-repo-baseline";
2020 expect(escapeXml(s)).toBe(s);
2121 });
2222
modified src/b51_render_reports.ts +5 −5
@@ -168,7 +168,7 @@ For management:
168168 - the [exec summary](/reports/demo) gives one number per agent + a narrative paragraph. Prints to one page.
169169
170170 For team-leads:
171-- the [drill-down](/reports/demo/agents/cursor) shows trend, failure-mix, streak, and the most recent flagged commits with one-click coaching links to the [Claude Code](/blog/claude-code-tdd) / [Cursor](/blog/cursor-tdd) / [Aider](/blog/aider-tdd) posts.
171+- the [drill-down](/reports/demo/agents/cursor) shows trend, failure-mix, streak, and the most recent flagged commits with one-click coaching links to the [Claude Code](/blog/2026-05/claude-code-tdd) / [Cursor](/blog/2026-05/cursor-tdd) / [Aider](/blog/2026-05/aider-tdd) posts.
172172
173173 [← back to tdd.md](/) · [the blog](/blog) · [the katas](/games)
174174 `;
@@ -253,8 +253,8 @@ ${recentRows}
253253
254254 ## coaching
255255
256-- ${a.slug === "claude-code" ? `[Claude Code does not do TDD by default](/blog/claude-code-tdd) — CLAUDE.md rules + fresh-context boundaries that prevent \`red-did-not-fail\`.` : a.slug === "cursor" ? `[Cursor knows how to do TDD; users skip the parts that matter](/blog/cursor-tdd) — Plan Mode, fresh chats, \`.cursor/rules\` to stop test-deletion.` : `[Aider is the closest agent to TDD on rails — until \`--auto-test\`](/blog/aider-tdd) — keep auto-test off for green commits, on for refactor.`}
257-- [Tweag's TDD handbook needs a judge](/blog/tweag-handbook-tdd) — why local green isn't enough.
256+- ${a.slug === "claude-code" ? `[Claude Code does not do TDD by default](/blog/2026-05/claude-code-tdd) — CLAUDE.md rules + fresh-context boundaries that prevent \`red-did-not-fail\`.` : a.slug === "cursor" ? `[Cursor knows how to do TDD; users skip the parts that matter](/blog/2026-05/cursor-tdd) — Plan Mode, fresh chats, \`.cursor/rules\` to stop test-deletion.` : `[Aider is the closest agent to TDD on rails — until \`--auto-test\`](/blog/2026-05/aider-tdd) — keep auto-test off for green commits, on for refactor.`}
257+- [Tweag's TDD handbook needs a judge](/blog/2026-05/tweag-handbook-tdd) — why local green isn't enough.
258258
259259 ---
260260
@@ -282,11 +282,11 @@ ${ctx.bannerHtml}
282282 const placeholderBlock = placeholders.length === 0
283283 ? `## placeholder tests
284284
285-> No placeholder tests detected at this snapshot. A placeholder is a test whose body contains zero \`expect()\` calls — covered in [the corpus post](/blog/agentic-coding-corpus-three-patterns) as the failure mode from r/ClaudeCode 1qix264 ("90 placeholder tests, 100% pass rate"). Detection runs on every deploy.
285+> No placeholder tests detected at this snapshot. A placeholder is a test whose body contains zero \`expect()\` calls — covered in [the corpus post](/blog/2026-05/agentic-coding-corpus-three-patterns) as the failure mode from r/ClaudeCode 1qix264 ("90 placeholder tests, 100% pass rate"). Detection runs on every deploy.
286286 `
287287 : `## placeholder tests · ⚠ ${placeholders.length} flagged
288288
289-> A placeholder test is one whose body contains zero \`expect()\` calls — empty body, comment-only stub, or string-literal body. Covered in [the corpus post](/blog/agentic-coding-corpus-three-patterns) as the failure mode from r/ClaudeCode 1qix264. The judge would refuse a merge that includes any of these.
289+> A placeholder test is one whose body contains zero \`expect()\` calls — empty body, comment-only stub, or string-literal body. Covered in [the corpus post](/blog/2026-05/agentic-coding-corpus-three-patterns) as the failure mode from r/ClaudeCode 1qix264. The judge would refuse a merge that includes any of these.
290290
291291 | test | file | reason |
292292 |---|---|---|
modified src/d21_app.ts +14 −10
@@ -198,7 +198,7 @@ export const createApp = (port: number) => Bun.serve({
198198 loc: `${SITE_BASE_URL}${p}`,
199199 }));
200200 const blogUrls: SitemapUrl[] = ALL_POSTS.map((p) => ({
201- loc: `${SITE_BASE_URL}/blog/${p.slug}`,
201+ loc: `${SITE_BASE_URL}/blog/${p.date.slice(0, 7)}/${p.slug}`,
202202 lastmod: p.date,
203203 }));
204204 const samaUrls: SitemapUrl[] = ALL_SAMA.map((d) => ({
@@ -275,7 +275,7 @@ export const createApp = (port: number) => Bun.serve({
275275
276276 "/blog": async () => {
277277 const rows = ALL_POSTS
278- .map((p) => `| ${p.date} | [${p.title}](/blog/${p.slug}) |`)
278+ .map((p) => `| ${p.date} | [${p.title}](/blog/${p.date.slice(0, 7)}/${p.slug}) |`)
279279 .join("\n");
280280 const body = `# blog
281281
@@ -301,16 +301,20 @@ ${rows}
301301 return htmlResponse(html);
302302 },
303303
304- "/blog/:slug": async (req) => {
305- const slug = req.params.slug;
304+ "/blog/:yyyymm/:slug": async (req) => {
305+ const { yyyymm, slug } = req.params;
306306 const entry = ALL_POSTS.find((p) => p.slug === slug);
307- if (!entry) {
308- const html = await renderNotFound(`/blog/${slug}`);
307+ const fullPath = `/blog/${yyyymm}/${slug}`;
308+ // 404 if slug doesn't exist, OR if the yyyymm in the URL doesn't
309+ // match the post's actual date prefix (prevents URL-spoofing where
310+ // someone constructs /blog/9999-99/<valid-slug> and gets a 200).
311+ if (!entry || entry.date.slice(0, 7) !== yyyymm) {
312+ const html = await renderNotFound(fullPath);
309313 return htmlResponse(html, 404);
310314 }
311315 const file = Bun.file(`./content/blog/${slug}.md`);
312316 if (!(await file.exists())) {
313- const html = await renderNotFound(`/blog/${slug}`);
317+ const html = await renderNotFound(fullPath);
314318 return htmlResponse(html, 404);
315319 }
316320 const md = await file.text();
@@ -318,16 +322,16 @@ ${rows}
318322 title: `${entry.title} — tdd.md`,
319323 description: entry.description,
320324 bodyMarkdown: md,
321- ogPath: `https://tdd.md/blog/${slug}`,
325+ ogPath: `https://tdd.md${fullPath}`,
322326 active: "blog",
323- pathForDocs: `/blog/${slug}`,
327+ pathForDocs: fullPath,
324328 jsonLd: {
325329 "@context": "https://schema.org",
326330 "@type": "BlogPosting",
327331 headline: entry.title,
328332 description: entry.description,
329333 datePublished: entry.date,
330- url: `https://tdd.md/blog/${slug}`,
334+ url: `https://tdd.md${fullPath}`,
331335 author: { "@type": "Organization", name: "tdd.md" },
332336 },
333337 });
modified src/d21_handlers_fallback.ts +16 −1
@@ -24,6 +24,7 @@ import {
2424 } from "./d21_handlers_repo_browse.ts";
2525 import { rewriteOldGitUrl } from "./b32_git_url_redirect.ts";
2626 import { rewriteOldSamaDisciplineUrl } from "./b32_sama_discipline_url_redirect.ts";
27+import { rewriteOldBlogUrl } from "./b32_blog_date_url_redirect.ts";
2728
2829 const isGitProtocol = (pathname: string, search: URLSearchParams): boolean => {
2930 if (pathname.includes(".git/") || pathname.endsWith(".git")) return true;
@@ -143,7 +144,7 @@ export const appFetch = async (req: Request): Promise<Response> => {
143144 // /sama/discipline/<slug> namespace. Same pattern-as-redirect shape
144145 // as the /GIT/ block above — pure Layer-1 transform + Layer-3
145146 // Response wrapper. Hypothesis-test instance of the pattern's
146- // reusability (see /blog/sama-v2-git-url-refactor-postmortem).
147+ // reusability (see /blog/2026-05/sama-v2-git-url-refactor-postmortem).
147148 const newSamaPath = rewriteOldSamaDisciplineUrl(url.pathname);
148149 if (newSamaPath !== null) {
149150 return new Response(null, {
@@ -155,6 +156,20 @@ export const appFetch = async (req: Request): Promise<Response> => {
155156 });
156157 }
157158
159+ // Legacy /blog/<slug> URLs permanent-redirect to /blog/<yyyy-mm>/<slug>.
160+ // Third instance of the pattern, first DATA-DRIVEN one — helper looks
161+ // up the post's date in ALL_POSTS to build the new prefix.
162+ const newBlogPath = rewriteOldBlogUrl(url.pathname);
163+ if (newBlogPath !== null) {
164+ return new Response(null, {
165+ status: 301,
166+ headers: {
167+ Location: newBlogPath,
168+ "Cache-Control": "public, max-age=86400",
169+ },
170+ });
171+ }
172+
158173 // SAMA-native repo browse at /GIT/:repo/{tree,blob,raw}/:ref/<path>.
159174 // The wildcard path needs more flexibility than Bun's :param routes
160175 // give us (no slashes), so we match in the fallback fetch instead.
modified src/d21_handlers_goals.ts +2 −2
@@ -41,7 +41,7 @@ const goalsLandingBody = (): string => {
4141 .join("\n");
4242 return `# goals
4343
44-The /goal slash commands that drove the work on this site. Each entry is the verbatim contract the agent was held against — *Done when* post-conditions, *Constraints (anti-fudge)*, and *Load-bearing files to read FIRST*. See [the drama post](/blog/sama-v2-goal-chain-gap) for why these now live in git.
44+The /goal slash commands that drove the work on this site. Each entry is the verbatim contract the agent was held against — *Done when* post-conditions, *Constraints (anti-fudge)*, and *Load-bearing files to read FIRST*. See [the drama post](/blog/2026-05/sama-v2-goal-chain-gap) for why these now live in git.
4545
4646 | date | title | status | PR | commit |
4747 |---|---|---|---|---|
@@ -85,7 +85,7 @@ export const goalSlugHandler = async (
8585
8686 // status: "lost" — registry entry only, no file on disk. Render
8787 // metadata-only at 200 (not 404) with the "source could not be
88- // recovered" callout. See /blog/sama-v2-goal-chain-gap for context.
88+ // recovered" callout. See /blog/2026-05/sama-v2-goal-chain-gap for context.
8989 if (entry.status === "lost") {
9090 const body = `# ${entry.title}\n\n${renderBadges(entry)}\n\n---\n\n${LOST_BLOCK}`;
9191 const html = await renderDocsPage({
modified src/d21_handlers_reports.ts +1 −1
@@ -31,7 +31,7 @@ import {
3131
3232 // -------- shared banners + context builders --------
3333
34-const DEMO_BANNER_HTML = `<div class="report-mockup-banner">demo data — design preview with synthetic numbers. Want the real readout? <a href="/reports/live">/reports/live</a> renders the same shape from live tdd.md commits. <a href="/blog/tweag-handbook-tdd">why tdd.md needs this</a></div>`;
34+const DEMO_BANNER_HTML = `<div class="report-mockup-banner">demo data — design preview with synthetic numbers. Want the real readout? <a href="/reports/live">/reports/live</a> renders the same shape from live tdd.md commits. <a href="/blog/2026-05/tweag-handbook-tdd">why tdd.md needs this</a></div>`;
3535
3636 const LIVE_BANNER_HTML = `<div class="report-mockup-banner">live data — sourced from <a href="https://github.com/${LIVE_REPO_OWNER}/${LIVE_REPO_NAME}">${LIVE_REPO_OWNER}/${LIVE_REPO_NAME}</a> via the public commits API (5-min cache). Agent attribution comes from <code>Co-Authored-By:</code> footers; commits without one are excluded. Phase coverage measures % of commits tagged <code>red:/green:/refactor:</code>.</div>`;
3737
modified src/d21_handlers_sama.ts +6 −6
@@ -398,9 +398,9 @@ Compliance is binary. The interesting question is the *delta* — what changes w
398398
399399 ![§5 workingSetFit measured across n=8 cross-repo datapoints, tdd.md highlighted at 80% as the only SAMA-disciplined repo, non-SAMA baseline ranges from 46.27% (sharkdp/bat) to 73.59% (cli/cli) with mean 60.68%](/sama-metrics.png?v=1)
400400
401-- **[Seven measured workingSetFit datapoints — what the baseline distribution actually looks like](/blog/sama-v2-workingset-cross-repo-baseline)** — n=2 → n=7 across mature compiled-language CLI tools. Range 27pp, mean 60.68%, sample stddev 10.13pp.
402-- **[Pointing SAMA v2 at \`dive\`](/blog/sama-v2-go-project-dive)** · **[Pointing SAMA v2 at \`ripgrep\`](/blog/sama-v2-rust-project-ripgrep)** — two non-SAMA mature CLI codebases audited and scored on two §5 axes (workingSetFit + graphDepth) at pinned SHAs.
403-- **[The §5 metrics emitter post](/blog/sama-v2-metrics-emitter)** — why measurement matters more than compliance, with the original metric build-out.
401+- **[Seven measured workingSetFit datapoints — what the baseline distribution actually looks like](/blog/2026-05/sama-v2-workingset-cross-repo-baseline)** — n=2 → n=7 across mature compiled-language CLI tools. Range 27pp, mean 60.68%, sample stddev 10.13pp.
402+- **[Pointing SAMA v2 at \`dive\`](/blog/2026-05/sama-v2-go-project-dive)** · **[Pointing SAMA v2 at \`ripgrep\`](/blog/2026-05/sama-v2-rust-project-ripgrep)** — two non-SAMA mature CLI codebases audited and scored on two §5 axes (workingSetFit + graphDepth) at pinned SHAs.
403+- **[The §5 metrics emitter post](/blog/2026-05/sama-v2-metrics-emitter)** — why measurement matters more than compliance, with the original metric build-out.
404404 - **[The three v2.1 dialects at /sama/v2 §6.A](/sama/v2#6a-v21-dialects-provisional)** — provisional extensions (directory-layout, inline-tests, declarative-exemption) that the Rust + Go audits surfaced.
405405
406406 **tdd.md** (the only SAMA-disciplined repo measured to date) lands at **80.00%** — 6.4pp above the top of the non-SAMA baseline. Suggestive, but n=1 vs n=7 is far from a SAMA-worth-following claim. §6 of the spec is explicit that promotion requires cross-repo deltas across multiple SAMA-disciplined repos.
@@ -489,8 +489,8 @@ jobs:
489489
490490 Two long-form pieces that argued *why* SAMA was shaped this way, written before the v2 spec drafted:
491491
492-- [**The Claude Code harness postmortem read through TDD + SAMA**](/blog/claude-code-harness-postmortem) — ThePaSch's r/ClaudeAI audit read against the iron law and the verification grep.
493-- [**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 with per-pattern mitigation tables.
492+- [**The Claude Code harness postmortem read through TDD + SAMA**](/blog/2026-05/claude-code-harness-postmortem) — ThePaSch's r/ClaudeAI audit read against the iron law and the verification grep.
493+- [**Three patterns ten threads converge on**](/blog/2026-05/agentic-coding-corpus-three-patterns) — a six-month corpus of r/ClaudeAI, r/ClaudeCode, r/AgentsOfAI failure-mode threads with per-pattern mitigation tables.
494494
495495 ### why these four together
496496
@@ -501,7 +501,7 @@ Each property fixes a different failure mode:
501501 - *Modeled* fails when types and tests scatter → siblings are mandatory.
502502 - *Atomic* fails when files swell → the ~700-line split keeps atoms small.
503503
504-The blog post [*Red, tokens, atoms*](/blog/three-constraints-agentic-coding) argues SAMA also compounds with TDD and Claude Code's token-saving discipline.
504+The blog post [*Red, tokens, atoms*](/blog/2026-05/three-constraints-agentic-coding) argues SAMA also compounds with TDD and Claude Code's token-saving discipline.
505505
506506 [← back to tdd.md](/) · [the blog](/blog) · [the guides](/guides)
507507 `;