sama-v2-second-url-refactor-postmortem.md
raw
· source
8 minutes 8 seconds — the cost-flattening hypothesis is confirmed
The git-url-refactor postmortem closed with a single falsifiable claim:
"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."
The second URL refactor happened today. It landed in 8 minutes and 8 seconds.
T+00:00:00 git checkout -b sama-discipline-prefix (first commit)
T+00:00:30 goals/sama-discipline-prefix.md written (dogfooded /goal)
T+00:01:45 b32_sama_discipline_url_redirect.ts + test (copy of git template)
T+00:02:30 d21_handlers_fallback.ts redirect block (paste alongside existing)
T+00:02:50 d21_app.ts Bun route + sitemap handler (one edit each)
T+00:04:00 sed pass over 13 content + src files (one regex)
T+00:04:20 one sed over-rewrite caught + fixed (test failed, 30s to revert)
T+00:05:10 419/419 tests green (+12 new helper cases)
T+00:06:30 commit, push, gh pr create, gh pr merge (the GitHub-flow)
T+00:07:30 deploy script ran (rebuild + restart container)
T+00:08:08 /healthz answered, live-verify passed (all 4 new URLs 200, all 4 old URLs 301)
7.4× faster than predicted. Cost-flattening confirmed at a much more dramatic rate than the original hypothesis dared.

What the prediction got right
The original postmortem named three things the pattern would carry through:
- A 5-line Layer-1 helper with one regex
- A sibling test covering all match-cases + non-match-cases
- A Layer-3 wrapper that emits the 301
All three landed identically in PR #53. The helper is 13 lines in both PRs (same code modulo identifier renaming). The Layer-3 wrapper is the same 11 lines in both fallback handlers, literally copy-pasted from the rewriteOldGitUrl block to the new rewriteOldSamaDisciplineUrl block. The sibling test grew from 9 cases to 12 — slightly more because the new pattern has more non-match neighbours (/sama/v2, /sama/skill, the new-form URLs) that needed explicit null-return tests.
What the prediction missed — pattern risk
One surprise: the sed pass over-rewrote.
The pattern s|/sama/(sorted|architecture|modeled|atomic)|/sama/discipline/\1|g matched inside filesystem paths like content/sama/sorted.md — turning them into the nonsensical content/sama/discipline/sorted.md (the directory content/sama/discipline/ doesn't exist; the file is at content/sama/sorted.md).
This bug surfaced via a test — b32_edit_resolve.test.ts failed when its expected filePath: "content/sama/sorted.md" got rewritten to content/sama/discipline/sorted.md. The pattern caught it in seconds, and reverting was one Edit. But it's a genuine new failure mode the first refactor didn't have, because git-url-drop-owner's regex was /GIT/syntaxai/tdd.md/ — three segments long, far less likely to collide with filesystem paths.
Pattern risk added to the recipe: when generating a sed for a URL refactor, prefer anchoring (href="...", [link](...)) or use a more restrictive character class. The 30-second revert was cheap this time because a test caught it. In a refactor with no covering test, the over-rewrite would have landed silently.
The /goal that follows the third URL refactor should include this lesson explicitly as an anti-fudge clause.
What lands when this pattern keeps repeating
PR #42 took an evening. PR #53 took 8 minutes. Two datapoints isn't a trend, but it's not nothing: the cost is dropping faster than linear.
The mechanism is mundane. The first time:
- You design the helper shape (
SitemapUrl-like type,rewrite*function name,null-vs-string return for non-match) - You design the test shape (match-all-kinds, non-match-cases, edge cases like empty input)
- You design the Layer-3 wrapper shape (Response with 301, Location header, Cache-Control)
- You discover the gotchas (regex order in the fallback, sed scope, Containerfile gotcha, breadcrumb cross-references)
The second time, all of that is done. You import the template, change the slug, paste. The first refactor's 19 files become the second refactor's 17 files because the helper + test are now reuseable structure, not new design.
The third refactor — whichever one we pick — should land in similar time unless the cost-flattening hits a floor at the irreducible-minimum of "type the new slugs + sed". My guess: 5–10 minutes for any future URL move, dominated by deploy time (~50s per deploy) and gh-CLI roundtrips.
What about /blog/<slug> → /blog/<yyyy-mm>/<slug>?
This was the third candidate in the postmortem. It's much bigger — ~27 blog posts × N cross-links each = probably 100+ references. The helper pattern would still work, but the sed-pass scope explodes, and the new URL needs to be computed from data (the post's date field), not from a fixed enum.
Prediction for that one: not 8 minutes. Probably 20–30 minutes, because:
- Helper signature changes (must accept date AND slug, lookup the date from ALL_POSTS by slug)
- Sed pass over content/*.md is sketchier (more risk of over-rewrite)
- Sitemap handler needs the new URL shape, but the redirect needs the old-shape regex AND a way to know each post's date
The cost-flattening claim holds for refactors of the same shape. When the input expands (fixed enum → data-driven), the helper has to grow. That's a falsifiable distinction worth testing next.
The empirical chain ratchets
/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, both PRs link back to their plan posts.
Anyone reading /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.
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.
What's next on the empirical chain
The natural next step is the third datapoint. Two falsifiable subclaims to test:
- A same-shape refactor stays small. Pick another fixed-enum URL move (e.g.
/sama/v2/example-crud→/sama/v2/examples/crudand/sama/v2/example-wordpress→/sama/v2/examples/wordpress). Prediction: ≤ 8 minutes, possibly faster since 2 slugs vs 4. - A data-shaped refactor stays under 30 minutes. Pick
/blog/<slug>→/blog/<yyyy-mm>/<slug>. Prediction: ≤ 30 min, with most of the time in the sed-pass design (not the helper or wrapper).
If subclaim 1 lands under 8 minutes, cost-flattening hits its floor. If subclaim 2 lands over 30 minutes, the pattern's portability is bounded — fixed-enum cheap, data-driven expensive — and that boundary becomes the new empirical knowledge.
Either outcome is the next blog post. The chain ratchets.