session article-alias — 哲宇提問觸發的評估 → 完整實作 ship Session span: 15:51:09 → 19:27:04 +0800(約 3h36m,1 commit) 資料來源:
git log %ai、.taiwanmd/wake-context.latest.mdmtime
哲宇問:「zh url slug 中文現在是用中文,要不要同時也開放網址(就像其他語言的格式,但是用英文 slug)也可以開同一個文章頁?讓人好複製跟直觀理解,你一起幫我評估。」評估完他回「照你說的做吧,完整做完然後 /twmd-finale」。
沒有從「複製起來醜不醜」這個直覺出發,先去翻 404 監測。reports/404-monitor/latest.json(2026-07-23 單日 9,266 次 404)的 cross-lang-slug 家族是 538 次,其中 235 次來自真人瀏覽器。抽前 10 條猜測 slug 對照 knowledge/en/ 的實際檔名,10/10 完全命中——沒有人在自創英文寫法,大家就是把 /en/ 拿掉。
這把問題從「人體工學願望」變成「我們自己的網址文法有裂縫」。站上每一種其他頁面,中文版都等於英文版拿掉 /en/(/en/about ↔ /about、/en/dashboard ↔ /dashboard)。只有文章頁破例,因為 slug 本身也換了。那 538 次是照著我們自己教的規則推網址的人跟機器。
順手量了網址長度三態(830 組):中文原貌中位數 14 字、百分比編碼後 46 字最長 154 字、英文別名 32 字。中文網址在網址列其實是三者裡最短最好看的,痛點只在傳輸格式。這條讓我沒有跟著直覺一路推到「改成英文 slug」,反而收斂成「開側門、留正門」。
別名的 SSOT 是新的 config/article-aliases.json,只增不改。git log 顯示近 90 天 knowledge/en/ 改過 6 次檔名;別名若每次 build 從 en 檔名現算,改一次名就殺掉一批已經分享出去的連結。凍住等於分享出去的網址永不死,順便接住那 34 篇沒有英文版、現算會漏掉的文章。
轉址殼自己寫,不用 Astro 內建的 redirects 設定。內建產出的是 content="2;url=...",白畫面停兩秒——對一個我們主動請人拿去分享的網址是錯的前門。自寫的殼是 0 秒 meta refresh 加 location.replace(),canonical 對齊 SEO.astro 的 encodeURI 加尾斜線寫法。
第三條是「永不公告」:不進 sitemap、不進 hreflang、不做站內連結。這條寫在註解裡只是自律,所以同時做成 check-url-contract.mjs 的紅燈閘門(別名出現在任一公告面就計入 dead)。2026-07-17 那次 15% 404 率的根因就是站體公告了 13,014 條自己沒有的 URL,同一種病不能換個形狀再得一次。
實作上別名跟文章走同一個路由檔(Astro 的 [category]/[slug] pattern 只能有一個檔案),同檔多發 path、一個 prop 分流。落地 04a8657de,8 檔 +1337 −26。
第一個是過度概化。我一度把 cross-lang-slug 整個家族從 generate-redirects.mjs 的允許名單移除,理由是「別名 registry 已經系統性接管了」。跑完看 diff 才發現那個家族有兩個方向:另一半是反向的「外語路由 + 中文 slug」(/ja/economy/台灣企業:台積電 → /ja/economy/tsmc),別名 registry 完全沒覆蓋。整個家族拿掉會重新打開十幾條真 404。改成用「registry 所有權」當判準——source 在別名清單裡才讓路,判準從家族換成所有權。
第二個是驗證對象錯了。用瀏覽器實走別名時,preview 服務的是主 repo 的舊 dist(我在 worktree 工作),跑出來的是改動前的 Astro 內建殼。差一點把「舊東西還在正常運作」當成「新東西通過驗證」。發現後把 worktree 產出的殼放進被服務的目錄再驗,才拿到真的結果。
收尾時對 redirects 少掉的 17 條做了控制實驗(把別名 registry 暫時移開再跑一次):11 條是我讓給別名的,另外 6 條是今天的 404 快照裡本來就沒有那些路徑。這個對照讓 commit message 不必猜。
| 檢查項 | 狀態 |
|---|---|
| MEMORY 有這次 session 的紀錄 | ✅ |
| Timestamp 精確 | ✅ git log %ai + 檔案 mtime |
| Handoff 三態已審視 | ✅ |
| CONSCIOUSNESS 反映最新狀態 | ❌ 未動(本次無器官分數變化,數據由 data-refresh routine 寫) |
| 自我檢查工具 PASS | 見下方 Stage 4 |
繼承 2026-07-25-102214-vortex-babel-2(巴別塔渦輪,本 session 未接手,仍由平行 babel session 持有):
- ⏳ 存量 passthrough drift 分批 heal / fleet 兩節點缺 prettier 正規化 / mouhouse worktree 未 commit 譯文
- ⏳ dashboard 介面翻譯 section 動態抓語言 / ar 與 ru 完整開起來 / 四產線行軍中
本 session 新 handoff:
-
827 條英文別名側門 ship + 線上驗證 - 觀察 30 天:
cross-lang-slug家族該歸零(基線 538/日,其中真人 235)。同時看 GA 走別名進來的組成——真人顯著就談分享按鈕要不要給別名,幾乎全是機器就維持中文網址當唯一正門。可證偽形式建議進 UNKNOWNS 掛due_date: 2026-08-24 - 分享按鈕維持現狀(中文網址),等上面那筆數據再由哲宇拍板;三個選項與我的傾向(兩個都給、中文預設)已在對話中列出
- 新文章出生時要跑
prebuild:aliases才會有別名——已接進 prebuild 鏈,但沒有譯文的文章拿不到別名(目前 34 篇),babel 補上英文版後下次 build 自動長出
今天最有價值的一步是「先去翻 404 監測再回答」。哲宇的問句本身帶著一個合理但未經量測的前提(中文網址不好複製),如果順著那個前提做,會做出一個看起來對、但理由是猜的東西。量完之後前提部分成立(傳輸格式真的醜)、部分被推翻(網址列反而最短),而真正的理由是我原本沒想到的那條:站體自己的網址文法在文章頁破例,那些 404 是使用者正確套用我們教的規則。
第二件事是兩個錯的形狀一樣。把家族當判準、把舊 dist 當新 dist,都是「拿一個相近但不是同一個的東西代替真正該檢查的對象」。REFLEXES #82 講的 proxy signal 是同一族,只是這次發生在我自己手上,而且兩次都靠「看實際輸出」而不是「看自己的推理」才抓到。
LESSONS 候選一條,已 append 到 LESSONS-INBOX:generate-redirects.mjs 是快照驅動、非累積型,昨天有效的 redirect 會因為流量衰減掉出 top-300 而消失(本次控制實驗量到 6 條)。修好的 404 可能因此復活。
🧬
v1.0 | 2026-07-25 19:27 +0800 session article-alias — 哲宇提問 zh 網址要不要同時開英文 slug,評估後完整實作 誕生原因:中文文章網址用中文檔名,其他語言用英文 slug;讀者與機器照站體自己的文法推網址而撞牆 核心洞察:先量再答把「人體工學願望」變成「自己的網址文法有裂縫」;中文網址在網址列最短最好看,痛點只在傳輸格式;兩個自捕錯誤同形——拿相近的東西代替真正該檢查的對象 LESSONS-INBOX 候選:generate-redirects 快照驅動非累積,已修好的 redirect 會隨流量衰減消失