--- slug: git-url-drop-owner title: Drop redundant :owner segment from /GIT/ URLs date: 2026-05-25 branch: git-url-drop-owner pr_number: 42 merge_sha: 684f257 status: shipped related_posts: [sama-v2-git-url-refactor-plan, sama-v2-git-url-refactor-postmortem] --- 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. Done when: - The four /GIT/ URL kinds work under the new shape: * /GIT/tdd.md/tree/:ref/ → 200, directory listing * /GIT/tdd.md/blob/:ref/ → 200, file viewer HTML * /GIT/tdd.md/raw/:ref/ → 200, text/plain raw * /GIT/tdd.md/commit/ → 200, commit detail - Old URL form is a permanent redirect: * curl -I https://tdd.md/GIT/syntaxai/tdd.md/blob/main/src/b32_sama_v2_verify.ts → HTTP/2 301 → location: /GIT/tdd.md/blob/main/src/b32_sama_v2_verify.ts → cache-control: public, max-age=86400 * Implemented as ONE regex in src/d21_handlers_fallback.ts: /^\/GIT\/syntaxai\/tdd\.md\/(.+)$/ → 301 to /GIT/tdd.md/$1 The regex must sit BEFORE the gitBrowseMatch block at line ~102 so the old URL never reaches the browse handler. - parseRepoBrowsePath in src/d21_handlers_repo_browse.ts keeps its shape (returns {kind, ref, path}) — only its callers drop the owner argument. - isAllowedRepo collapses to isAllowedRepo(repo: string): boolean — owner is implicit, dropped from signature and from the gitBrowseMatch regex (the new regex captures only `:repo` + suffix). - repoBrowseHandler and commitViewHandler drop the `owner` parameter from their signatures. All call sites updated. - The explicit Bun route in src/d21_app.ts:486 changes from "/GIT/:owner/:repo/commit/:sha" → "/GIT/:repo/commit/:sha". - Every link builder emits the new shape: * src/b51_render_repo.ts — 8 call sites (breadcrumbs, parent-dir, raw link, source-view link) * src/b51_render_commit.ts — 2 call sites (commit-parent, raw .diff) * src/b51_render_edit.ts:27 — hard-coded /GIT/syntaxai/tdd.md/commit/... string - All hard-coded "/GIT/syntaxai/tdd.md/" strings in content/ and src/ rewritten to "/GIT/tdd.md/": * content/home.md * content/sama/v2.md * content/blog/sama-v2-rust-project-ripgrep.md * content/blog/sama-v2-workingset-cross-repo-baseline.md * content/blog/sama-v2-metrics-emitter.md * content/blog/sama-v2-go-project-dive.md * content/blog/sama-v2-sitemap-implementation-plan.md * content/blog/sama-v2-git-url-refactor-plan.md (the plan post itself uses old-form examples — those become AFTER-references in postmortem style) * src/d21_handlers_sama.ts:137 (markdown embedded in /sama/v2/verify page body) After: `grep -rn '/GIT/syntaxai/tdd.md/' content/ src/` returns 0 lines. - Test expectations updated in src/b51_render_repo.test.ts and src/b51_render_commit.test.ts to match the new URL strings. - All 379+ tests pass; no test count regression. New helper test (~3 cases) covers the redirect regex: matches a tree/blob/raw/commit URL and produces the expected Location; non-matching URLs (e.g. /GIT/otherorg/repo/...) fall through and don't redirect. - /sama/v2/verify still reports 7/7 ✓ (anti-fudge). - Sitemap unchanged — /GIT/ URLs aren't listed there. - Deployed; live-verify with curl: * /GIT/tdd.md/blob/main/src/b32_sama_v2_verify.ts → 200, body contains "export" * /GIT/tdd.md/tree/main → 200, body contains "src" and "content" * /GIT/tdd.md/raw/main/sama.profile.toml → 200, text/plain * /GIT/syntaxai/tdd.md/blob/main/README.md → 301 with Location /GIT/tdd.md/blob/main/README.md * curl -sL of the old URL lands on the new one and returns the file content * 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). Constraints (anti-fudge): - One regex for the redirect — no per-URL hand-maintained mapping. If the regex grows into "a list" the anti-fudge clause is violated. - Do NOT remove LIVE_REPO_OWNER from src/a31_site_config.ts; it's still the truthful owner constant used by c14_git operations + Forgejo proxy. It just stops appearing in user-facing URLs. - OUT OF SCOPE: the bare git protocol endpoint /syntaxai/tdd.md.git and the two-segment bare-repo view at //. Those go through isGitProtocol + repoMatch — git-client-facing, copy-pasted into clone commands, breakage risk for cosmetics. Touch only the /GIT/ prefix. - No alias mode — both URL forms working forever lets the old one quietly remain canonical. The 301 forces consolidation; the old URL is a redirect, not a working endpoint. - Site language English-only — any new comments or response strings in English. - GitHub flow via flatpak-spawn (branch → PR → merge → push p620 → deploy via flatpak-spawn --host scripts/p620/deploy-tdd-md.sh). - Do NOT change any §4 verifier logic. Load-bearing files to read FIRST: - 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) - src/d21_handlers_fallback.ts (lines 89-117 — bareGitUrl block + gitBrowseMatch regex; the new 301 redirect goes BEFORE gitBrowseMatch) - src/d21_handlers_repo_browse.ts (parseRepoBrowsePath at line 56, isAllowedRepo at line 26, repoBrowseHandler signature at line 69) - src/d21_handlers_commit_view.ts (commitViewHandler signature — drop owner arg) - src/d21_app.ts (line 484-486 — the explicit commit route + import wiring) - src/b51_render_repo.ts (8 link-emit sites — breadcrumbs, parent-dir, raw/source/dir links) - src/b51_render_commit.ts (2 link-emit sites — commit-parent, raw .diff) - src/b51_render_edit.ts (1 hard-coded edit→commit URL at line 27) - src/a31_site_config.ts (LIVE_REPO_OWNER stays exported — confirm callers before touching) - src/b51_render_repo.test.ts + src/b51_render_commit.test.ts (test strings to update mechanically with the link-builder changes)