Feature #417
進行中ARCH-4-followup-station-mapping-walkable-wiring:walkable 段最近站解析接進班次查詢(SC-16/SM-15)+SM-16 惰性求值
0%
概述
ADR-013 車站映射批第二棒:walkable 段最近站解析接線(SC-16/SM-15)+SM-16 惰性求值¶
背景¶
第一棒(Feature #415)只解了三成因中的第三個(郊區景點超出步行門檻 → 豁免+顯式步行段)。班次查詢本身仍走舊的保守解析:站名精確比對+2km 半徑內多站即回 None。
後果不是「少一點資訊」,而是都會區大眾運輸日排不出行程——台鐵地下化路段(高雄、台南、台北)站距約 1.5–2km,2km 半徑內落有多站屬常態,這些 walkable 節點的 OD 對全部落 miss → Stage C 判該位置不可行 → UnschedulableNode 大量出現。
本批把「自動找最近車站」真正接進查詢流程,成因 2(都會區多站保守放棄)自此消除。
變更內容¶
施工前介面確認(SC-16 (a)~(h)/SM-15,system-architect)¶
- 新增下行型別
ResolvedStationRef(全欄必填、結構上無 unresolved 態 → SM-6 紅線在簽章層成立,不靠 adapter 自律) - SC-6
batch_prefetch_schedules新增 keyword-onlyresolved_stations(None⇒ 舊路徑逐位元零回歸) -
全有全無語義:非
None時全部 OD 對走新路徑、resolve_station_by_hint()一次也不得被呼叫;禁止混合退回的射程自「端」擴為「單次呼叫」(pair 級退回同樣製造輸出上不可辨識的雙重解析) - adapter 零政策三道結構保證(簽章無情境參數/型別無門檻欄/原始碼禁列七個識別字),非靠註解
- 同批更正 SC-15 (o) 一項與「
None⇒ 零回歸」語義互斥的預測:21 個 name-only fixture 不補座標,自動成為舊路徑回歸鎖
工程實作¶
- 政策層
build_resolved_station_refs()(門檻比較單一處)+select_network_from_refs() - D-pre 組裝 per-network
resolved_stations並下傳;adapter 切換分支 - entry 四個步行欄位開始填值且恆取實際被選中網路的 ref(SC-15 (l)-3 一致性由單元層升端到端)
- 兩端步行分鐘相加進
estimated_minutes(ADR-013 決策 4 落地),而at_minute/l1逐字零變動
SM-16 惰性求值(qa 阻擋 2 裁決)¶
候選網路依 (距離和, label) 升冪逐一取時刻表,第一個有直達班次者即回傳。等價性可證:SM-9 的解是「有班次者中距離和最小者」,排序在後者鍵值必更大,結構上不可能改變答案。
否決「(TRA, THSR) 固定順序短路」——那會使 SM-9 結構上永不生效(TRA 幾乎總是先命中),等於靜默廢除一條已落地決策。它短路的是查詢,不是規則。
附帶:ADR-013 決策 7「皆無班次取先查到者」改為「取距離和較小者」,使 adapter 全分支與純函式同解。
治理¶
docs/research/design-memos/ 目錄正式落地(CLAUDE.md 目錄結構+寫入權矩陣;三紅線落 specs README:非規格不得當 specs 引用/進 specs 一律 起步/不得承載研究結論)。
qa 退回兩項阻擋級 → 全數收口 → 終局通過¶
阻擋 1(安全相關):把「未查證」升格為「已查證無班次」¶
新路徑對時刻表查詢失敗採 continue 改試另一網路,而舊路徑同位置是 return None 且原始碼逐字註解「不得改試另一網路偽裝成『查無』」。
場景:共構站(台北/板橋/南港/台中/左營=常態)兩端於 TRA+THSR 皆 walkable,TRA 時刻表查詢失敗(HTTP 錯誤或預算耗盡——後者是明文預期行為),THSR 查證無直達 → 產出 departures == () → Stage C 判 INFEASIBLE_NO_SERVICE → 對使用者是「已查證這天沒有車」的斷言,而 TRA 從未被驗證。negative cache 以 (網路, service_date) 為鍵,單次失敗毒化整批。
修復:失敗旗標 + 無任何候選有服務時 return None(誠實 miss)。
阻擋 2:「零額外配額」錨點的理由是無效推論¶
原文「候選集合恆為子集,故不增加任何上游呼叫」——前半為真,後半忽略了舊路徑 TRA 命中即短路。qa 以呼叫計數探針證實 (THSR, service_date) 時刻表由 0 → 1,多日行程每日 +1。且其交付測試只構造單一候選網路場景,結構上測不到它宣稱保護的情境。
→ architect 裁決改設計(SM-16),舊錨點作廢原文保留供追溯,新增 (d)-1/(d)-2/(d)-3 三列逐字指定必須構造的場景。
qa 的驗證方法¶
不採信綠燈,改以突變測試證明修復承重:
- 突變 A(停用阻擋 1 修復分支)→ 回歸鎖立刻紅燈
- 突變 B(排序鍵反轉)→ 7 條紅燈
- 誠實指出窮舉等價鎖在突變 B 下仍綠(兩側共用排序函式會同步錯)→ 該鎖證的是「兩處同解」而非「排序正確」,不得被敘述成證明選擇正確
- 另抓出一條因新舊 adapter 共用
tmp_path(共用磁碟快取 ⇒ 零 HTTP 呼叫)而完全空轉的配額測試 → 已修
devil 實作復核無阻擋級(逐行核實七項,含「第四次『設計了沒接線』家族風險未重演」——追鏈證實 resolved_stations 確在生產路徑組裝下傳),觀察項 O-1(共用函式漂移陷阱)併修復批處理。
驗收標準¶
-
python -m pytest tests/ -q→ 1426 passed, exit 0(基線 1395,+31);主協調者每輪獨立複跑 - 禁止混合退回:monkeypatch「一被呼叫即 raise」四情境結構斷言;守衛非空轉經反向探針實測
- SM-16 (d)-1:距離和較大的網路時刻表呼叫恰為 0(明文禁止以單一候選網路構造充數)
- SM-16 (d)-2:較小者無班次時兩網路各恰 1 次、最終選較大者
- SM-16 (d)-3:3 距離關係 × 4 服務組合 = 12 例窮舉,adapter 選擇恆等於純函式
-
21 個 name-only 舊路徑測試機械比對零回歸(
old test names absent from new: []) - 6 個既有測試檔改動僅為簽章相容,零斷言弱化
-
qa 全錨點簽核通過,簽核文件落
docs/specs/test-plan-ADR-013-station-mapping-walkable-wiring.md
成熟度與界定(qa 界定七條,摘要)¶
全部維持 。fixture/假 urlopen 驗證,resolved_stations 路徑從未對真實 TDX 執行過;門檻常量仍【低信心】未校準。依低信心來源上限條款與接地上限條款封頂。
-
成因 1(站名比對不命中)是被移除,不是被修好——新路徑不做名稱比對,缺座標端一律必然誠實 miss(含以
Destination.name供 hint 的轉場錨點,由「可能僥倖命中」轉為必然 miss)。這是行為變更,不得描述為零回歸。 成因 2 才是本批真正消除者 -
UNRESOLVED_LOOKUP_FAILED爆炸半徑本批擴大(全空 tuple 的 dict 為 truthy ⇒ 當日全部 OD 對省略) -
estimated_minutes仍不含waiting(缺口由二成分縮為一成分)→ 衍生ARCH-1-3-followup-direct-segment-waiting-minutes - SM-16 後單日每個
(網路, service_date)呼叫數為 1~2 的區間而非常數 1,校準時須以區間處理(上界不變,改變的是期望值) - SM-16 短路合法性前提為紅線:僅因「有無班次」是最高權重、其餘鍵查詢前可全序排定。未來新增需時刻表內容才能算鍵值的判準(班次密度、首末班、票價)即與短路不相容,須同批改回 eager。此條無機械檢查,只能靠三個落點的文字與 code review
- 全數 未跑 live
-
「大眾運輸功能對使用者可用」的宣稱仍不成立(ADR-012 已知弱點 3 射程持續有效);轉乘鏈末腳
walking_to_station_*欄名方向遺留已追認並綁定 ARCH-5 呈現義務(文案須為「下車後步行」),該義務目前無機械檢查,屬對 ARCH-5 批的移交條件
沒有任何資料可供顯示