跳至主要内容

文件解析遷移:驗證類

狀態:P2-4 設計已通過審閱(20261019-docs-resolve-p2-4,第 2 輪,受審 revision r2-d42627c241c93b4e,2026-10-19;1 條 major、3 條 minor 均處置);實作已通過第 2 輪審閱(受審 revision r2-1c498ed422a45d74,2026-10-19;3 條 minor 均處置),實際接線與驗證見 §8,尚未下行。 依據:ADR-023 D4、文件解析與索引規格 §1 的 P2-4、設計類遷移;追蹤 FU-142。 本頁定義:/uat-script、/uat(含原生 evidence 工具)、/report、/sim-plan、/impact 取得文件位置的方式。共用契約沿用 /docs-site 的 references/doc-locations.md。

1. 範圍與邊界​

做留在原流程或後續分期
九個既有文件/資料類型加範本;從 UAT 指南、報表規格分類分出一般規劃備註不搬移既有指南、帳本、sidecar、報表規格、run、樣板或附件
五個 skill 的產出與已遷移上游改用 resolve;新頁面後 register不改 UAT 命題、stage/surface、來源分層、真人接受條件或進度狀態機
UAT 原生工具的文件發現接入 registry,新增唯讀 resolve-route 供新建指南共用路由不因工具改版重寫既有指紋、重生指南、重驗真人結果或提高舊指南最低 generator 版號
報表規格與樣式文件的定位;既有 evidence CLI 繼續接收精確路徑動態證據包內部位置、歷史/snapshot/run 識別仍由原生工具負責,不對目錄建立檔案範本
impact 已枚舉的依賴來源改由類型列舉,仍保持唯讀/選擇匯出不把分類為 page 的所有文件自動加入依賴圖,不擴充分析語意
以實際 fleet 與隔離 fixture 驗證範本P2-6 決定 retention、原樣張儲存與證據搬移;P3 才做寫入 hook

新建位置保持現有慣例;registry 有效專案層提供舊佈局時讀回其實際路徑。查無處置依各模式現行流程,不把來源查無當成建立來源的授權。

2. 類型與範本​

下表的路徑皆相對於 {docsRoot}。所有參數還須通過工具現有的 safe_value(禁止空值、.、..、斜線、反斜線、NUL);text 表示 ^.+$,允許既有檔名含空白、中文或點號,不要求下游為本次遷移改名。數字保留前導零,不由工具轉成整數再拼回。

類型templateparamskeyexample
uat-guidedocs/testing/test-plans/{guide}.mdguide 為下述指南 stemguideUS-001-S.UAT-manual-testing-guide
uat-guide-sourcesdocs/testing/test-plans/{guide}.sources.json同上guide同上
uat-resultdocs/testing/uat-results/{result}.jsonresult 為下述帳本 stemresultUS-001-S.UAT
report-specdocs/specs/reports/RPT-{rpt}-{slug}.mdrpt:^[0-9]+$;slug:textrpt001、monthly-summary
report-styledocs/design/report-styles/{style}/{name}.mdstyle、name:textstyle、nameproject-report、rev-1
report-style-datadocs/design/report-styles/{style}/{name}.json同上style、name同上
sim-plandocs/testing/sim-plans/{plan}.mdplan:textplanoffice-load
impact-reportdocs/testing/impact-reports/{date}-{source}.mddate:^[0-9]{4}-[0-9]{2}-[0-9]{2}$;source:textdate、source2026-10-19、test-data-seed
test-data-seeddocs/testing/test-data-seed.md———

各 template 同時是其唯一共用 locate;本期不虛構未發現的舊目錄。專案層的額外 locate 仍沿現有契約。report-spec 的 rpt 是檔名中的原始數字字串,不含 RPT-;registry 不將 1 與 001 視為相同 key。/report 必須先依 §4.2 作數值身分比對,再以既有字串 resolve;新編號補足至少三位,不能直接將使用者的 RPT-1 拆成 rpt=1 判定查無。

2.1 UAT 的物理檔案識別與 surface 選擇​

指南 stem 格式:^US-[0-9]+-([PSI]\.UAT-)?manual-testing-guide(-.+)?$。包含本階段指南、帶模組後綴指南及無 stage 的舊指南。帳本 stem 格式:^US-[0-9]+-[PSI]\.UAT(-.+)?$。

guide/result 是完整檔名 stem,不是以名稱推測 target module 的新規則。無後綴指南仍須讀 target_module;帶後綴也須核對 frontmatter、project.json 與 requested stage。registry 的 key 只防止同一物理識別有兩個位置;同 US/stage/target 的語意重複,仍由 UAT 原生路由拒絕。單看 regex 通過不代表可執行 UAT。

不用 us 作唯一 key:同一 US 的 P/S/I、多個 server surface、無 stage 的歷史文件可合法並存。也不以空的 module 參數模擬可選後綴(工具禁止空參數)。

2.2 規劃備註與正式文件分開​

目前 uat-guide 以 test-plans/*.md 分類,實際包含方法論提案、scope proposal 等備註。若直接加嚴指南 locate,這些文件會使整個 resolve --list 回 RS-UNPARSED。

採分類拆分:

  • uat-guide.paths 收斂為 docs/testing/test-plans/US-*-manual-testing-guide*.md,priority 5;指南 stem 仍由 §2.1 驗證,畸形指南不轉成備註以逃避檢查。
  • 新增 test-plan-note,涵蓋同目錄其餘 *.md(priority 0,persistent、page、writer open),本期不加 template。README/index 仍由 priority 10 的 section-index 處理。
  • 既有提案保留原位置與網址;不搬檔、不改正文、不把備註送進 check-guide,也不在五個 skill 內新增備註產生器。
  • uat-guide-sources 的來源關係維持指向 uat-guide。若備註旁意外有 .sources.json,列為待核對,不能靜默把它當成合法 UAT sidecar。

報表目錄也有相同情況:fleet 盤點發現四份 layout-review/report-preparation 文件被廣義 report-spec 命中,並非 RPT-{number}-{slug}.md。採同樣分流:report-spec.paths 改為 docs/specs/reports/RPT-*.md、priority 5;新增 report-spec-note 涵蓋同目錄其餘 *.md、priority 0、persistent/page/writer open,不加 template。索引頁仍為 section-index;畸形 RPT-* 仍須回 RS-UNPARSED,不改名成備註隱藏。此調整只改分類,不搬檔、不改既有正文與 URL。

2.3 報表樣式與動態附件​

樣式資料不只 rev-{N}.json;實際存在 inventory、proposal、legacy-tracking 等 metadata,故以 style+name 識別,不替它們捏造 revision。.md 與 .json 是不同類型,可同名並存;style 版次與內容要求仍依報表指南。

report-layout、report-evidence、report-preview、report-restoration、uat-snapshot、uat-equivalence、uat-origin 是動態包/原生歷史樹,本期不加 template。原生工具繼續以 run ID、摘要或既有 manifest 推導包內成員;skill 不自行生成任意附件路徑。寫入前可用 classify 核對預期類型,但不能把分類成功當成指紋、接受、封包閉包或保存期限已通過。

test-result 沒有這五個 skill 的固定產出者,本期不加範本;與 data-model 一併留在 P2-5 完整盤點。不用一個任意檔名範本掩蓋尚未定義的產出契約。

2.4 設計可行性盤點​

以正式 registry 的 P2-3 版本為基礎,僅在審閱證據目錄產生候選(76 → 78 類,新增兩種備註),對九個 workspace 的實際檔案唯讀檢查。九類範本 R12 通過,無無法解析文件、無重複 key;15 項隔離檢查通過。正式 registry 與下游檔案未修改。

workspace主要命中與分類修正
參考實作UAT 指南 68、sidecar 52、帳本 52、seed 1;2 份規劃備註分出
florae-g1UAT 指南 69、sidecar 53、帳本 54、seed 1;6 份規劃備註分出
almanac-g1/ict無 stage 舊指南各 10/3;可定位不代表符合現行 UAT 前置
nbsosRPT 20、樣式正文 18、樣式 JSON 18;4 份報表準備筆記分出,JSON 包含 inventory/proposal/legacy-tracking
crm-v2/tps-g1/tms/tts-v1本次九類尚無文件,仍納入空集合驗證

候選首次檢查揭露報表準備筆記無法解析,才補入 §2.2 分流,未靠改名或略過錯誤取得零缺口。計畫與影響報告目前無 fleet 實例,以隔離的新建/既有路徑檢查補足;其實際 skill 流程仍須在實作時走查。

3. UAT 原生位置橋接​

3.1 調用與失敗契約​

uat/scripts/evidence.py 使用同一份方法論中的 docs-site/scripts/docs.py,以 Python executable 加 argv 呼叫並解析 JSON;script 路徑由工具自身的實際位置定位,不假設 cwd 的 workspace 裡另有一份工具。--workspace 傳目標 workspace;--docs-module 傳已確定的 docs 模組,且須確認其 project.json 登記與既有 docs_root 一致。

只讀目標站台的 registry 投影與專案層;不以 canonical bundle 偷補投影、不下載工具、不以快取或原 Glob 作失敗 fallback。環境/投影缺失、RS-*、解析失敗均轉成可辨識的 UAT error,保留原 code 與文件清單,零證據寫入。測試 fixture 因此須明確帶上 registry 投影。

本期只新增小型調用橋接,registry schema、resolve 與 register 語意不變。原生路徑回傳後仍檢查 workspace 範圍、符號連結與檔案類型。共用契約直接給路徑時的規則照常適用,不因其他 US 的同類型文件無法解析就拒絕已明確給定的操作對象。

操作內快取與效能約束​

一次操作指一個原生命令,或 consumer 在同一 Python 程序內包住整批 US 的唯讀查詢。CLI 建立操作 context;stage_status 等 public API 獨立呼叫時建立 context,已有 context 時沿用。巢狀 evidence_route、不同 stage/surface 及 consumer 的多 US 迴圈共用該 context;退出最外層(含例外)立即釋放,不使用跨操作或跨程序的持久快取。對逐 US 啟動程序的 consumer,只能保證每個程序內的上限,不宣稱其整批工作只啟動一次。

  • 成功的類型完整清單以 (workspace 絕對實體路徑, docs 模組登記 key, common 投影 SHA-256, project 層 SHA-256 或 absent, type) 作 key。同一操作的同一唯讀區段,每個類型至多一次 resolve --list 子程序;US/stage/target 篩選在清單內完成,不因 16–18 次 guide_candidates 重啟 resolver。清單回傳的 duplicates 仍須依原契約核對,不能當成已解決。
  • 單一 key 的 resolve 結果可在同 context 以相同位置識別加命令、類型及完整參數作記憶化;相同查詢只呼叫一次。這只是位置查詢重用,不快取 guide/ledger 驗證、來源指紋或人工接受結論。
  • 每次重用前核對 registry 投影/專案層仍存在且內容雜湊相同;缺失、變更或不可讀立即清除相關項目,再依當前狀態查詢或拒絕。新子程序失敗時直接回錯,不取舊成功結果替代。不同 workspace、docs 模組與 registry 不能共用清單。
  • 任何建立、修改、搬移、刪除指南/sidecar/帳本/來源或 registry 的原生寫入,於寫入前失效該 workspace/docs 的位置快取(失敗亦不恢復舊值),後續查詢屬新的唯讀區段。consumer 若在同程序自行寫檔,也須透過同一 context 的失效入口;無法遵守者應結束 context,下一次操作重新查詢。讀取選定檔案仍核對存在、containment、symlink 及原生內容,不因有快取省略。
  • context 以顯式傳遞或可恢復的 ContextVar 隔離;不可建立跨 workspace 的全域可變路由。/progress 總覽、/next、/work status 在同程序呼叫原生 API 時,由外層包住一個 context;原 public API 的參數仍相容。

§5 以子程序計數作必要效能驗收,另外記錄相同機器、相同 fixture 的耗時比較。清單次數不得隨 stage/surface 或同操作 US 數量成倍增加;尚未實作前不宣稱已有加速。

3.2 已有指南​

  1. 以操作內共用的 uat-guide --list 發現候選,再依工具既有的 US/stage 檔名規則篩選;無 stage 的歷史指南只進歷史查詢,不能成為某個現行 stage 的新結果依據。列出的同 stem 重複位置須拒絕。此列舉沿 resolver 的類型全域 fail-closed,不承諾只受本 US 的錯檔影響;具體停止範圍與修復出口見 §3.4。
  2. evidence_route 繼續核對 inventory、uat_stage、target_module 與 selector。沒有 selector 的多份候選不任取第一份;明示 --guide 時以該檔為對象並核對其 registry 類型與本 US/stage,不先做無關全域列舉。
  3. 既有指南保持原路徑。sidecar 讀指南的 source_fingerprints 指標(保留其既有路徑,不僅因命名不同改寫);帳本由指南後綴推得 result stem,再以 uat-result resolve 取得既有/新路徑。已有 ledger 的 guidePath、targetModule、resultPath 等檢查不變。
  4. 原先以固定 test-plans 根目錄做 containment 的檢查,改為 docs 模組範圍+相符 registry 類型;不能只放寬 containment 而不驗類型。專案層合法 relocate 才可使用,未登記文件不繞過 resolver。
  5. 已解析的 US、SBE、seed 來源依 us resolve、sbe --list --param us=...、test-data-seed resolve 取得;SBE 集合比對不可只看帶 Epic 的篩選結果。current_source_manifest、fragment_manifest、歷史轉換的現行來源發現共同使用橋接;歷史快照中的路徑、Git blob、等價紀錄與 origins 仍按歷史內容還原,不能改成今日的 resolve 結果。

guide_candidates、default_guide_path、source_sidecar_path、result_path 的 public 呼叫面須保持相容,讓 work/progress/next 等 consumer 不必各寫一套路徑。可新增具 workspace/docs context 的內部函式,但不可用全域可變設定污染不同 workspace 或巢狀 evidence_route。

3.3 新建指南:唯讀 resolve-route​

原生命令(介面已依 §8 實作,實作驗證另行送審):

evidence.py resolve-route --cwd {cwd} --us {US-ID} --stage {P.UAT|S.UAT|I.UAT} --target-module {targetModule} [--module-key {moduleKey}]
  • 先核對目標模組與 stage,再找本模組既有指南;一份則回原路徑,多份即拒絕。不同模組的無後綴指南不算本模組的既有指南。
  • 本模組尚無指南時,無後綴路徑若未使用,預設以它作新路徑;被別的模組使用時採 moduleKey 後綴。moduleKey 是本設計新增的原生推導契約,不是現有 inventory 已提供的演算法:依 target 的 workspace-relative 路徑,精確找出 project.json.modules 的唯一登記 key,直接使用完整 key,不取 basename、不轉小寫、不將路徑分隔符替換成連字號。登記 key 須符合 ^[A-Za-z0-9][A-Za-z0-9._-]*$ 並通過 safe_value;含子目錄等不合格式的 key 不自動轉碼。
  • 新增可選 --module-key,只為尚無本模組指南的明確命名決策:給定時強制使用該後綴,即使無後綴路徑空著。它不改 project inventory 的 target 身分,也不能替既有指南改名或 retarget;既有指南若收到此參數即拒絕並提示移除後重試。值須通過同一格式與 safe_value,且不等於其他登記模組可用的預設 key;同 US/stage 的既有指南、sidecar、帳本也須全部檢查占用及 target 一致性,不能借指定參數覆蓋另一 surface。錯誤回傳衝突路徑與 target,供使用者選擇另一個未占用 key 後重跑。
  • 每個新路徑以 resolve 取得;若被其他類型/檔案占用、存在歧義或側錄資料不一致即停止,不覆蓋。指南、sidecar、帳本各自的 exists 都要檢查,避免新指南意外接上孤兒帳本或另一個 surface 的 sidecar。
  • JSON 回傳 targetModule、stage、guidePath、sourceFingerprintPath、resultPath 及各檔 exists,所有路徑均 workspace-relative;writes: 0。新指南的 sidecar 依其 stem 以 uat-guide-sources resolve 取得。既有 sidecar 指標依 §3.2 保留。
  • /uat-script 使用此結果寫指南,再執行原 stamp/check 流程;/uat 的現有選取與寫入仍要求指南已存在,不能藉此命令替人工驗收產生空帳本。

拒絕後的處理亦保持零寫入:

拒絕原因出口
target 不在 inventory、無唯一登記或 stage 錯誤修正呼叫的 target/stage,或先依 inventory 流程處理登記;module-key 不能代替合法 target
預設 key 不適合作檔名、指定 key 衝突使用者選擇符合格式且未占用的 --module-key,重新執行唯讀命令;不自動加流水號
同 target/stage 有多份既有指南列出路徑,先決定保留的正式指南並依既有證據/搬移流程處置重複項,再重跑;本命令不合併或刪除。單次驗收可用既有 --guide 明示對象,但不因此把新建路由當成可用
新指南不存在,sidecar 或帳本已存在列出三個路徑、exists 與可讀的 target/guide 指標;不自動刪除、認領、stamp 或初始化。若為需保留的歷史證據,先依原生修復/歷史流程恢復其指南與關係;若要建立另一份指南,使用未占用的 module-key。確認為廢棄資料後的封存/移除須由使用者另行決定,不由 resolve-route 執行

3.4 舊證據與門檻​

只讀查詢、工具升級或 registry 改版不重寫既有指南、sidecar、帳本或驗收快照,不把 registry 檔加入命題來源。相同來源與位置下,舊 fresh/verified/pending-repair 等結果應相同。不同來源或實際 relocate 仍依原 verifier 判定,不能改 digest 來恢復有效;實際搬檔的等價處置與人工補驗仍沿 ADR-019。

無 stage 舊指南、舊 schema 的限制與歷史匯入不放寬。新工具不得要求因本次純位置接線而重新 stamp 全部指南,或把任意 RS-UNPARSED 報成產品驗收失敗、回退 Sprint。

列舉錯誤的停止範圍是明確的取捨:未明示指南而需要 uat-guide --list 時,另一個 US 的畸形指南也會使該類型列舉回 RS-UNPARSED;使用這個列舉的 stage-status 以及依其判定的 ✅/submit/merge 閘門會停止,批次總覽也須呈現阻擋原因與檔案清單,不可將未計算的 US 報為 clear。這比原本只 glob 本 US 的範圍更廣,係保留共用 resolver 類型完整性契約的預期行為。本期不新增「略過無法解析項目」或 US 範圍掃描介面,也不以快取/Glob 繞過。

修復出口為在錯誤所屬 workspace 執行 docs.py audit,依 DR-UNPARSED-LOCATION 核對錯檔:修正畸形命名,或在有效專案層為真實舊佈局補上 paths/locate,再 audit/resolve 成功後重試原操作。若涉及有效證據的實際搬檔或改引用,依 ADR-019 的等價/補驗流程,不能只改 digest;不能將畸形指南重新分類為備註來隱藏問題。修復前保留原進度及證據,阻擋是文件位置無法確認,不是場景 failed。

明示既有 --guide 的單檔操作仍走 §3.2 的路徑、類型、US/stage/target 與原生關係核對,不先全域列舉;它只能限定這次操作的對象,不能代替要求涵蓋全 surface 的 stage-status/整合閘門。其他必要類型若列舉失敗仍須如實停止。

4. 五個 skill 的改寫​

4.1 uat-script/uat​

  • US/SBE/Persona/API Spec/seed 等已遷移來源改用共用契約;Design Language、模組測試與環境配置仍用其原生來源。
  • 新建與選取採 §3 的原生路由,範例指南從已解析的 UAT 清單中挑相同 stage,而非只找無 module 後綴檔名。唯讀前置不建立空目錄;實際寫入指南時才建立所需父目錄。
  • 指南的來源連結、depends_on 與 source_fingerprints 都由實際路徑算出;schema、來源分層、Coverage 和 stamp 命令責任不變。指南新建後執行 register;只改 sidecar/帳本不執行 register。
  • /uat 不再要求固定的 US/SBE/test-plans 目錄存在作為路徑就緒證據;仍要求對應文件、指南及 Sprint/work 前置就緒。Sprint 尚未遷移,本輪沿原規則。

4.2 report​

  • 所有模式先 report-spec --list,按十進位數值分組 rpt。使用者的 RPT-1、RPT-001 與 RPT-0001 都是數值 1;只接受完整數字 ID,不從主題中的數字猜編號。同組只有一份時,以該檔的原始 rpt 字串(例如 001)resolve 並保留實際路徑及 RPT-ID,後續帳本/包也使用該 ID。同組有多份(包括 RPT-1-* 與 RPT-001-*)即列出歧義並停止,不能因 registry raw key 不同而選一份或再建立。
  • spec 新建模式:數值身分查無後,rpt = str(number).zfill(3),至少三位、超過三位不截斷;例如 RPT-1 新建為 RPT-001、1000 為 RPT-1000。自動取號以清單所有 rpt 的整數最大值加一(空集合從 1 開始),不能字串排序或依數量取號;再以正規化參數 resolve 核對占用,補齊 slug 才建立。其他模式查無只列候選,不建立規格。更新不因補零差異另造同號第二份,不改既有歷史檔名。
  • 樣式正文/JSON 以 report-style、report-style-data 查詢或列舉;版次、預設 profile、來源與引用關係仍依報表指南;不將 metadata 當成可套用的完整樣式。
  • layout/impl/verify/accept/carry-acceptance/status 全部沿用同一 RPT 的實際 spec 路徑。固定帳本及動態 run/bundle 路徑仍由已確認的 RPT ID、現有契約及原生 helper 決定,依 §2.3 分類核對,不把同名 PDF 當同一接受。
  • helper report/scripts/evidence.py 本來接收精確 --spec、--manifest、--bundle、--source 路徑,本期不為它新增另一套文件發現。runs/{runId} 必須在帳本同層的限制、全包指紋、精確 PDF 接受及 carry-acceptance 不變。
  • 新建 RPT/樣式 Markdown 後 register;JSON、HTML 包、PDF 展示依原網站入口與原樣張契約,不誤用 register 替代附件閉包核對。

4.3 sim-plan​

  • plan 名稱先 resolve;未提供時,author 照現行提問,generate 以 --list 的唯一/多份結果選取。查無時 author 可建立,generate 仍提示先 author,不寫出空計畫。
  • Persona、System Context、US/SBE、API Spec 改用已遷移類型;depends_on 及 derived_from 指向實際檔案。外部來源或 server/sim 程式碼不由 docs resolver 接管。
  • 新計畫後 register;產生 locustfile 仍以 targetServer 和 sim_base 為依據,不修改負載模型、SLA、生成物的所有權或手改保留規則。

4.4 impact​

  • 使用者直接給路徑/檔名時仍保留指定對象與 fragment 語意。由類型或編號尋找已遷移來源時才用 resolve;不把檔名搜尋誤改成以 stem 猜 US。
  • 反向索引維持原枚舉範圍:Roadmap、Feature List、Epic、US、SBE,以及原有 api-specs/**/*.md、test-plans/**/*.md 中的 Markdown;BR 未遷移,沿原 parser。已遷移類型以實際清單取得位置,API 草稿原本位於枚舉範圍內,須包含 api-spec-draft --list。原範圍內尚未加範本的備註、目錄頁或其他 Markdown 仍以原範圍 Glob+classify 補入,與已解析清單依路徑去重;不能因分出 test-plan-note 就丟失它已宣告的 depends_on。Domain Model、樣式、帳本不因可列舉就加入此反向索引;原有隱含影響規則另行處理。
  • 從 US/SBE 的 classify 參數取得 Epic;舊佈局缺屬性時依共用契約補問,不能以編號位數猜 Epic。隱含 Domain Model 使用其四候選解析,epic 分檔及 overview 都不存在時只列待補,不製造不存在路徑。
  • 預設只在對話輸出。使用者選擇匯出後才以 impact-report resolve --param date=... --param source=... 取得路徑;source 採已選定來源的檔名 stem(不含目錄、副檔名與 fragment),date 由實際日期取得。同日同 source 已有檔時由現行覆寫決策處理,不自行加時間戳改變命名;不同目錄同名的來源也須呈現碰撞,不以覆寫同意推定可覆蓋另一來源。匯出後 register,--fix-missing 仍不寫原規格。

5. 驗證計畫​

項目實作時必要驗證
registry九類 R12;新建/既有/重複 key/非法參數/目錄頁;備註分類不阻擋 UAT 列舉,畸形指南仍 RS-UNPARSED
fleet全部九 workspace 以同一候選 registry 列舉,逐類揭露不可解析與重複 key,不修改下游;報表 metadata 與歷史指南納入
UAT 路由同 US/S.UAT 兩個 server,無後綴綁第一個、第二個採後綴;相同 scenario ID 不共用帳本;無 selector 多候選拒絕;全 surface stage-status/verify-result 不遺漏
效能/context同操作多 stage/surface、重複 18 次 guide_candidates,以及外層包住多 US 的 stage_status:每個唯讀區段的每個類型完整列舉子程序數 ≤ 1;相同參數 resolve ≤ 1。記錄遷移前後相同 fixture 的耗時及子程序次數,不只宣告快取。兩 workspace/docs 模組不得交叉命中;registry 變更/缺失、寫入成功/失敗、巢狀例外後重新查詢;新程序不得沿用舊清單,失敗不得回舊成功
新路由resolve-route 零寫入;project key 原樣使用、巢狀 key 拒絕後明示 module-key 成功、key 占用、既有指南拒絕改 key、錯誤 stage;孤兒 sidecar/帳本拒絕後改用未占用 key,歷史檔案 bytes 不變;project registry relocate
錯檔範圍別的 US 的畸形指南使全域列舉與整合閘門停止,輸出 RS-UNPARSED/檔案清單且不報 failed/clear、不寫證據或回退進度;DR-UNPARSED-LOCATION 修復後重新成功。明示 guide 的單檔操作不受無關指南錯檔阻擋,但不能取代全 surface 閘門
RPT 編號RPT-1 選到既有 RPT-001;舊單份 RPT-1 保留原字串;RPT-1 與 RPT-001 並存時拒絕;查無新建補三位;數值取號跨 009/010、999/1000;其他模式查無零寫入
來源舊佈局 US/SBE/seed;完整 SBE 集合;現行來源走 registry,歷史快照不重解;缺 registry 不 fallback;失敗零 ledger writes
相容性舊指南/sidecar/帳本 bytes 不變;現有 UAT 全套測試、跨模組與來源/歷史/等價回歸;現有 report 全套測試;不製造真人通過
文件五個 skill 的新建、更新、來源查無、直接路徑走查;來源/連結使用實際路徑;唯讀 impact 不寫檔,明示匯出才 register
網站新文件可讀、索引更新;UAT JSON/報表包仍由原附件入口核對;docs-only 建置及標準 preview-only 邊界

設計階段的候選 registry/fleet 檢查只證明範本可行;現有原生工具回歸只作為相容性基線,不代表新橋接或 resolve-route 已通過。實作須另外提供新介面的命令、實際輸出與失敗斷言。

6. 預計修改範圍與次序​

  1. registry 九類範本與 test-plan-note/report-spec-note,docs-site 測試、共用 doc-locations 類型表、參考實作投影。
  2. UAT evidence 位置橋接與唯讀 resolve-route;fixture 補投影;掃描 current_source_manifest、fragment_manifest、historical conversion 等現行來源入口與 containment,不只改 skill 文字。work/progress/next 經既有 API 消費,新增跨 consumer 回歸,不擴充其語意。
  3. 改寫五個 skill,核對範本、報告與上游引用,更新相關 rule 索引、skill 版號及 Codex adapter 基準。
  4. 完整回歸、fleet 重驗、app-docs 投影及網站核對,實作另開審閱。P2-5 讀取方字樣清理、P2-6 retention 與 P3 hook 依原計畫接續。

7. 設計選擇與審閱條件​

第一輪審閱在 R1-01 裁決四項均採本稿方案;第 3 項以 R1-01 的效能契約、R1-02 的命名與拒絕出口補齊為條件。第 2 輪已確認 §3 與 §5 的條件處置,以及 R1-03 的 RPT 數值正規化、R1-04 的全域停止與修復出口;通過範圍為設計,實作及其效能仍須另行驗證與送審:

  1. UAT registry 以完整 stem 作物理 key,surface 身分由原生工具判定;對照方案為拆成無後綴、帶後綴、legacy 三套類型,會增加九個 guide/sources/result 類型及合併列舉責任。
  2. 將 test-plans 中的一般提案分為 test-plan-note、報表目錄的還原/準備文件分為 report-spec-note,避免嚴格解析擋住真實指南或 RPT;替代方案是為提案逐一搬檔,會改網址且擴大範圍。
  3. 新增 UAT 唯讀 resolve-route 統一新建與既有選取;替代方案是讓 skill 保留一套新檔命名判斷,容易與原生路由分歧。
  4. 動態 run/snapshot/bundle 保持原生識別且本期不遷移位置,報表 helper 維持精確路徑輸入;P2-6 再決定 retention 與儲存衝突。這不代表 ADR-020 與 D2 的待決已解決。

8. 實作接線紀錄​

  • 共用 registry 從 76 增至 78 類;九類加入範本,新增 test-plan-note/report-spec-note。參考實作經 docs-site plan/apply 更新投影與受管基線,不改下游站台。
  • uat/scripts/doc_locations.py 只透過同份方法論的 docs.py 查詢目標投影;每次操作使用可恢復 context,成功清單與相同參數查詢重用,核對 registry 雜湊、檔案邊界及 symlink。已有清單的指南分類可重用其 params;明示單檔且無清單時只 classify 該檔,不先全域列舉。寫入前清除快取,失敗也不恢復。
  • guide_candidates、default_guide_path、source_sidecar_path、result_path 保留 public 參數;來源 US/完整 SBE/seed 改用 resolver。既有 source_fingerprints 指標保留;實體指南與帳本的 stem 由分類參數取得,不從 relocate 後的檔名猜身分。
  • resolve-route 實作 §3.3 的新建/既有路由與 --module-key,回傳 guidePath、sourceFingerprintPath、resultPath、exists(guide/sourceFingerprint/result)及 writes: 0。命名、孤兒資料與歧義錯誤包含處置出口;不改成覆寫或自動認領。
  • 歷史轉換先以 resolver 發現現行來源;歷史 Git 路徑僅以 classify 辨識類型/US,避免共用目錄混入另一個 US;不改原路徑或 blob。重建暫存歷史樹時明示來源檔案集合,按歷史內容與既有等價機制比較,不對歷史快照重跑今日的文件發現。歷史簽名指南的預設查詢範圍保留原有無模組後綴集合,不因新增可列舉類型擴大接受來源。
  • /progress 原生完成閘門以一個 location context 包住同 US 的多階段驗證;/next、/work 既有逐 US CLI 維持每個程序自己的 context,沒有跨程序快取。fixture 明確包含 docs inventory 與投影,不提供測試用 canonical fallback。
  • 五個 skill 與 doc-locations 類型表已改寫;報表按 ID 的選取先作數值比對,直接檔案路徑仍保留指定對象。report helper、動態包及 UAT schema/generator 最低版號均不變。

以下為 2026-10-19 歷史量測;現況傳輸接線見 §9。當時效能驗收以同操作每類型完整列舉 ≤ 1 為準;當時一次 stage-status 仍有 10–13 次 docs.py 子程序,清單之外是參數不同的單筆 resolve,每次約 0.16 秒。參考實作同機三組交錯量測中位數:US-002 約 0.152 → 2.734 秒(13 次子程序)、US-101 約 0.010 → 1.659 秒(10 次)、US-201 約 0.010 → 1.640 秒(10 次)。耗時為本機觀測值;符合清單次數契約仍有顯著成本,/progress 總覽、/next、/work status 的逐 US 程序也會累積此成本。

後續優化由 FU-144(app-docs/docs/specs/progress/follow-ups.md)承接:比較從已快取 --list 推導既有路徑、僅新建時 resolve,或 docs.py 批次查詢;須保留 context/registry 失效、失敗拒絕、公開介面及歷史證據契約,再量測相同 fixture 的子程序數與耗時。本輪不實作此優化,不將清單重用宣稱為比舊 Glob 更快。完整測試與限制見下方實作審閱結論。

實作審閱結論​

2026-10-19 第 2 輪通過(受審 revision r2-1c498ed422a45d74;審閱者 ada@leandev.io),3 條 minor 均已核對:

  • R1-01:每類型清單次數契約通過;單筆 resolve 子程序成本依本節量測揭露,後續優化由 FU-144 承接。
  • R1-02:以最終程式碼在 .claude/skills/uat/scripts 執行 python3 -m unittest discover -p 'test_*.py',13 個模組、346 項、OK、exit 0(1335.700 秒);其中 test_doc_locations 16 項。完整執行後原生來源 SHA 未變,不拼接中途版次統計。report 原生 helper 未改,既有 34 項回歸通過。
  • R1-03:五個 skill 的通用定位與索引文字改為單行交叉引用,唯一通用定義在 doc-locations.md;修正 sim-plan generate 多餘頓號,adapter 同步驗證通過。

參考實作與框架 docs-only 建置通過;完整含 server 同步的 build 仍因兩個 server Javadoc 編譯缺少符號失敗,由既有 FU-143 承接。此通過不代表產品 UAT、報表 PDF 接受或下游已升級;沒有重寫既有證據或製造真人通過。P2-5、P2-6 與 P3 繼續依原分期處理,P2 全部通過後才統一 publish;ADR-023 維持 Proposed。

9. FU-144:canonical 唯讀位置 API(實作與八站下行完成)​

已結案方案 C 只調整位置傳輸;docs-site 1.11.0/uat 6.19.0 的實作已通過審閱,並於 2026-10-24 完成八站下行(來源 12b080031)。 受支援介面與載入生命週期的權威定義為 .claude/skills/docs-site/references/doc-locations.md §11。 CLI/API 共用引擎與錯誤封裝;UAT 的 public 參數、清單快取、registry 失效、寫前 invalidate、 直接指南及歷史 workspace 身分不變。工具 bytes/集合變動時拒絕舊 handle,缺件須同步完整方法論。

執行前先擷取原件、核對雜湊及靜態 API 能力標記/入口,缺少標記的舊 CLI 在執行前拒絕;只編譯已核對的 bytes。載入使用操作限定的私有 package;不插入 consumer sys.path、不覆寫 docs/resolve/exchange/retention 裸名,consumer 先載入及 API 先載入兩種順序均須成立。退出/例外只清理自己擁有的私有模組, 不清空 sys.modules;一般標準函式庫 import cache 可保留。API 只接受 resolve/classify,拒絕寫入動詞, 不捕獲全域 I/O、不寫 bytecode。這是傳輸改變,不省略原件證明或改判 UAT。

效益門檻、現況量測與本輪驗證落在參考實作維運文件 app-docs/docs/operations/docs-resolve-performance-plan.md;歷史 §8 的舊量測保留,不能當作現況。 正式驗證須計入首次載入,逐 US 比較完整 stage-status 輸出與定位回應;既有指南、sidecar、帳本、 快照、原件及人工接受 bytes 不變。完整回歸、Codex 同步與實作人審通過後才提交/發布。 驗證、實作審閱及八站下行均完成後,FU-144 已於 2026-10-24 結清;逐站提交與核對結果見上述維運文件。非定位成本本輪不處理、不另開待辦,不因此減少歷史證明要求。