證據報告
載入時機 – 需要向他人展示結果,但文字難以傳達時,而且證據是實際畫面時。實作或修改了顯示在畫面上的主要功能時,即使沒有要求也應從此處開始製作完成報告。 不適用於無畫面的文件與畫面間流程圖。
目的
使用實際載入並截取的畫面,製作 回答一個問題 的文件。收件者不閱讀程式碼或提交紀錄。他們只知道畫面,因此文件的重量完全來自於畫面是實際運行的結果。與其用十行項目符號說明相同的發現,不如將同一筆記錄在兩個畫面中截取並並列擺放的兩張照片更能快速被理解且不易被反駁。完成大型功能後,若沒有這份報告就只說「已完成」,則收件者自行打開畫面確認的成本會轉嫁到對方身上。
產出物是一份 HTML 檔案。收件者可能用手機開啟,也可能透過瀏覽器列印成 PDF,因此模板需同時適應窄螢幕與 A4 列印。不會另外產生 PDF 或 Markdown 檔案。
這項技能沒有固定的目錄。首先決定 這份文件要回答的一個問題句子,然後根據問題決定比較軸與章節結構。
| 問題 | 比較軸 | 文件做的事 |
|---|---|---|
| 什麼改變了 | 之前的程式碼 <-> 現在的程式碼 | 並列兩個畫面以證明改善 |
| 是否依照規格,還有什麼遺漏 | 規格書、規格 <-> 現在畫面 | 為每個條款附加判定,只留下不符合的項目 |
| 是否符合原則 | 原則、檢查清單 <-> 現在產品 | 將檢查整產品的發現按原因分組,並截取可在畫面上看到的部分作為證據 |
| 條件改變時會有什麼不同 | 狀態 A <-> 狀態 B | 實際切換旗標、日期、權限後截圖 |
| 現在是什麼狀態 | 無軸 | 僅以當前畫面瀏覽整體 |
| 需要決定什麼 | 選項 <-> 選項 | 將每個項目的當前畫面、選項、需要的輸入配對 |
通常會混合兩個以上的軸。 進行規格對照時,可能會出現「規格中沒有但已存在的項目」,這屬於不同軸的項目,需要獨立成一個章節。問題模糊,文件也會模糊。如果無法用一句話寫清楚,就將文件分成兩份。
核心原則
- 畫面是實際運行的結果,而非重現。 憑記憶製作「應該是這樣」的畫面幾乎總是錯誤的。之前的畫面可能含有現在已刪除的元素,或者問題比記憶中的更輕或更重。認為「在這種條件下應該會這樣顯示」也常常錯誤。實際打開旗標後,可能會出現與預期不同的畫面。因此,必須在實際建立要展示的狀態後再截圖。這樣才能在文件中寫下「這是實際運作的結果,而非重現」,而這一句話決定了整份文件的可信度。 -> Step 3
- 在照片旁放置數值。 照片只能說明「看起來是這樣」。將儲存的值與畫面上的值(
data-*屬性、螢幕朗讀文字)並列,就能進一步說明「為什麼看起來是這樣」。 -> Step 3 - 標記在畫面內繪製。 用目測輸入座標幾乎總是會偏移一整列或一整行。如果是瀏覽器畫面,應使用文字或選擇器找到元素,在其位置上繪製邊框與編號並截取。 -> Step 4
- 用於說明的標記不應遮蓋說明的對象。 將高亮標籤直接放置在畫面上,幾乎總是會遮蓋某些東西。標題、輸入框標籤、旁邊欄位的值都可能被遮蓋。圖片上只放編號,說明則移到標題。編號徽章很小,無論放在哪裡損失都較小。 -> Step 4
- 製作的東西必須親眼確認。 工具回傳成功只表示檔案已寫入。邊框是否到了錯誤的元素、徽章是否遮蓋了內容、接縫處是否重複了頁首、提供的連結中圖片是否破損,這些都必須開啟才能知道。 -> Step 5·6
- 區分已截取與未截取的部分。 透過程式碼確認但資料中沒有案例而無法在畫面上看到的項目,應附加「(程式碼依據)」。如果混在一起,連已截取項目的可信度也會受到質疑。 -> Step 1·3
政策
| 政策 | 何時生效 | 內容 |
|---|---|---|
| 資料與設定只能讀取,若要修改需詢問 | Step 3 | 查詢案例的查詢是自由的。若要建立案例而修改開發資料庫,必須在使用者確認後才能進行,並記錄修改的值,之後再還原。在任何情況下都不以營運資料庫為對象 |
| 截圖過程中變更的項目需記錄在文件與報告中 | Step 3 · Step 6 | 如登入 session 建立、外部登入同意、開發資料庫變更等截圖過程中產生的痕跡 |
| 以便於收件者開啟的形式交付 | Step 6 | 本機路徑在收件者的裝置上無法開啟。應發送 report.html 檔案或建立連結,若使用連結則需確認實際可開啟 |
| 向外部發送前需取得確認 | Step 6 | 發送至 Slack、郵件、客戶端時,應先詢問是要以草稿形式還是直接發送 |
前提
| 前提 | 確認 | 若無則 |
|---|---|---|
| 工作會顯示在畫面上 | 變更是否呈現在使用者看到的畫面上 | 僅變更後端或腳本的工作不適用。應以文字報告 |
| 要截取的產品已啟動 | 本機開發伺服器或暫存位址是否有回應 | 啟動方式依該儲存庫的文件。之前的程式碼請參考 axes §時間軸 |
| 有瀏覽器工具 | node scripts/shot.mjs 是否透過 Playwright 運作。其他工具只要能對頁面執行 JS 即可 | Playwright 安裝與使用其他工具截圖的方法請參考 capture §瀏覽器操作 |
| 可以登入 | 是否需要登入才能看到畫面,是否有帳號 | capture §建立登入狀態 |
| Python Pillow | python3 -c "import PIL" | 無法進行拼接與裁切 |
流程
0. 問題與軸 READ <- variants/axes - 根據軸的準備工作不同(程式碼回退、資料變更、文件閱讀、案例搜尋)。只執行所選軸的步驟
1. 項目與判定 (檢查軸則 axes §檢查軸 1~2 產生項目)
2. 結構 READ <- steps/20-document - 將項目分組的標準、判定詞彙、摘要、圖表位置
3. 截取 READ <- steps/30-capture - 可能卡在登入、合成事件、長截圖、讀取畫面值
4. 標記 READ <- steps/30-capture §在畫面內繪製標記 - 用目測座標會偏移整列
5. 圖片確認 (無需開啟文件。確認清單在 Step 5 內)
6. 產出 READ <- steps/60-output - 若破壞模板,窄螢幕與列印會失效;若違反決策區塊規則,複製的內容會不完整
Step 0. 問題與軸
用一句話寫下。如同「向客戶說明本週修正的內容」、「與產品經理確認規格對照後還有什麼遺漏」,必須 包含收件者與目的。目的不同,即使是同一個畫面,強調的重點也會不同。接著從目的表格中選擇軸,並閱讀 axes 中的對應章節。
結束時,應已確定一個問題句子、軸、以及收件者。
Step 1. 項目與判定
不要從截取開始。先將這份文件要處理的項目列出,並為每個項目附加參考代碼與 判定。這個清單將成為文件的骨架,要截取的畫面與要標記的位置也由此決定。
參考代碼應根據不同性質區分前綴,因為收件者的關注點不同。
- 應要求完成的工作:
R-1、R-2... (關心是否完成) - 工作過程中發現並一併修正的:
A-1、A-2... (關心為什麼要動到它) - 規格對照中不符合的:
G-1、G-2... (關心接下來怎麼處理) - 檢查中的發現:依群組編號
1-1、1-2... (關心相同原因的項目)
判定詞彙在整份文件中統一使用同一套(詞彙範例請參考 document §判定詞彙)。判定應計數後放在第一頁。「35 項已實作,3 項需判斷,1 項缺陷」這一行就能代表整份文件。計數的過程中也能發現清單中的空缺處。
工作過程中容易遺漏修正的項目,應使用 git log;若是規格對照,則逐行瀏覽原文以填滿清單。同時標記每個項目是否可以在畫面上看到(資料中是否有案例)。 -> 核心原則 6
結束時,每個項目應已附加程式碼、判定、要截取的畫面或「(程式碼依據)」。
Step 2. 結構
章節不是從目錄中選擇,而是 在分組項目的過程中自然產生。分組標準有以下四種:
- 依畫面 - 當多個項目集中在一個畫面時。改善報告的基本方式
- 依判定 - 當判定結果分歧時。對照報告的基本方式,收件者可以只看「需要決定的事項」
- 依原因 - 當發現很多且分散在多個畫面時。檢查報告的基本方式
- 依項目 - 當每個項目都是獨立的決策時。決策文件的基本方式
無論哪一種,前面都要放 一頁摘要來說明整體,後面的內容越詳細。假設收件者從上往下閱讀,隨時可能停止。章節數量根據要展示的內容決定。不要硬塞內容,也不要建立空的章節。具體的結構規劃方法與實際範例請參考 document。
Step 3. 截取
根據軸的不同,準備工作也不同(請參考 axes)。此處僅列出需共同遵守的事項。
- 需疊加比較的對照組應使用相同的 viewport、相同的捲動位置、相同的範圍截取。 這樣兩張圖片才能以像素為單位對齊,並可使用滑桿與差異模式查看(60-output §疊加查看)
- 比較的畫面之間應使用相同的資料。 資料不同則比較不成立。若要展示同一事實在不同畫面上的不同呈現,應使用同一筆記錄截取所有畫面
- 在截取前應透過查詢確認要展示的功能所需的資料確實存在。 若截取到空白畫面後才發現,則需要重新建立堆疊
- 確認登入狀態後再截取。 實際曾發生在登出狀態下截取需要登入才能看到的元素,然後寫上「不存在」的錯誤。在判定為不存在之前,應先區分是真的不存在,還是因為當前 session 看不到
- 以相同的順序進行操作。 將拍攝清單整合成一個檔案,需要重新拍攝時只要執行該檔案即可
- viewport 應設定得足夠寬裕。 若畫面下方被裁切,則需要重新截取
- 同時讀取儲存的值與畫面中的值。 -> 核心原則 2
- 同時記錄如何到達該畫面。 若要事後回溯路徑與步驟數,必須重新進入。在截取時一併記錄是無成本的(document §畫面的位置與深度)
操作中常見的卡關點請參考 capture。
Step 4. 標記
如果是瀏覽器畫面,在 scripts/shot.mjs 截取的瞬間,會在畫面內繪製邊框與編號(-> capture §在畫面內繪製標記)。長畫面則分段截取後使用 scripts/stitch.py 拼接,側邊欄等非重點部分則使用相同腳本裁切。若非瀏覽器畫面,則使用 grid_overlay.py 讀取座標,再用 annotate.py 繪製。
- 邊框只框住要強調的元素。框太大會模糊焦點
- 顏色應根據判定使用統一的一套。翻閱文件時,僅憑顏色就能理解性質。改善前與問題點使用紅色,改善後使用綠色為基本;對照報告則使用紅色表示不存在、綠色表示存在、需要判斷使用橙色
- 比較的兩個畫面的標記應分別尋找。文字長度不同會導致佈局微幅移動
- 將所有截取與標記彙整在一個檔案中。 這樣修改標記時可以全部重新產生,日後需要重新截取畫面時也只需執行該檔案
Step 5. 圖片確認
使用 Read 工具全部開啟。確認事項:
- 標記結果行中是否有
NOT FOUND - 邊框是否精準框住強調的對象。是否誤抓到相同文字的其他位置(例如不同表格中的相同欄位名稱)
- 編號徽章是否遮蓋了文字或進度條
- 接縫處是否有重複的頁首或目錄
- 裁切的上方是否切到標題的一半。並列的兩張圖片比例是否差異過大
- 寫上「不存在」的項目是否真的在畫面上不存在。 若因為登入狀態或條件而看不到,則應推翻判定
- 標題所說的內容與照片所展示的內容是否一致。是否在該寬度下漏掉了隱藏的欄位,卻寫成「重複三次」
修正錯誤後再次確認。一次就正確的情況很少見。
Step 6. HTML 與交付
- 將
assets/web-report.html複製到報告資料夾中的index.html並填寫內容。骨架與卡片樣式請參考 60-output 骨架。 - 若收件者需要決定事項,則在該依據卡片正下方放置決策區塊。按下底部的
複製按鈕,即可將選定的項目以 Markdown 格式打包,貼入對話中(60-output 取得決策)。 - 開啟三種預覽模式。寬螢幕、390px 寬度、以及
scripts/check_print.sh產出的所有列印頁面(60-output 畫面與列印)。 - 使用
inline-images.py將檔案打包成單一report.html。直接發送檔案或匯出為連結,並以收件者開啟的方式實際確認(60-output 交付)。
不要為每個報告修改模板的 <style>。若將寬度設定為 px 或將表格放在 .tw 之外,會破壞窄螢幕的版面。 -> 核心原則 5
結束時,report.html 在三種預覽模式下均無錯誤,能以收件者開啟的方式開啟,且發送動作等待使用者確認。
常見卡關點
| 現象 | 原因與對策 |
|---|---|
| 開發伺服器立即崩潰 | next dev 會讀取 stdin。加上 < /dev/null 會立即收到 EOF 而正常終止。應使用 `tail -f /dev/null |
| 彈出視窗或下拉選單無法開啟 | Radix 等元件不回應合成事件。應使用自動化工具的實際 click,而非 dispatchEvent |
| 全頁面截圖重複相同畫面或固定頁首重疊 | 工具的全頁面截圖無法正確滾動視窗或內層容器。應使用 shot.mjs 的 full 模式分段截取後拼接 |
| 拼接的照片中目錄重複 | 固定元素殘留。只截取或裁切重點區域 |
| 手機上表格或圖片超出畫面 | 表格未包在 .tw 中,或內聯 style 中使用了 px 寬度。應只使用模板的 class |
| 標記指向錯誤的表格 | 同一個文字在畫面上出現多次。應更改 nth 或使用 exact、選擇器來縮小範圍 |
| 截取到錯誤的分頁 | 其他 session 共享了瀏覽器 daemon。應隔離 session |
| 明明有功能卻寫成不存在 | 在登出狀態或條件不符的情況下截取。判定前應確認登入與條件 |
| 透過連結開啟時缺少幾張圖片 | 簡單伺服器無法處理同時請求。應使用 inline-images.py 打包成單一檔案 |
| 圖片在框架中顯示得很小 | 受到高度限制而縮小。將縱長的圖片改為左右兩欄配置可以放大 |
| 變更過於微小不明顯 | 選錯了比較對象。與其顯示列表畫面中欄位名稱的變更,不如顯示實際編輯該值的編輯畫面 |
| 表格過於密集難以閱讀 | 改為標題在左、內容在右的項目列表。若有群組,則將群組標題放在行的左側一次 |
| 文件越修改越長 | 新增章節後,應移除原本包含該內容的既有敘述 |
通用機制
| 腳本 | 功能 | 產出 |
|---|---|---|
scripts/shot.mjs | 根據拍攝清單使用 Playwright 開啟畫面,繪製標記,並截取。長畫面則分段截取 | 輸出資料夾中的 png、每行一個標記結果 |
scripts/mark.js | 在頁面內使用文字或選擇器尋找元素,繪製邊框與編號。shot.mjs 使用,其他瀏覽器工具可透過 eval 注入 | 每行一個標記結果 |
scripts/stitch.py | 拼接分段截取的片段,並根據名稱座標裁切 | 輸出資料夾中的 png、每行一個大小 |
scripts/inline-images.py | 將 HTML 中的相對路徑圖片與腳本嵌入,打包成單一檔案 | report.html、包含的檔案數與大小 |
assets/decisions.js | 儲存決策區塊,透過畫面底部功能列的複製按鈕將選定項目以 Markdown 格式打包複製 | 固定功能列、localStorage |
assets/compare.js | 在 .pair[data-compare] 上添加並列、滑桿、差異功能列。方式為頁面整體狀態,預設為滑桿。若兩張圖片的像素大小不同,則關閉疊加查看 | 比較功能列、差異比例 |
assets/report-nav.js | 根據 h2·h3 建立左側目錄,並顯示內容量(章節·圖片·決策·閱讀時間)、已讀章節、剩餘決策、目前位置。重新開啟時可接續閱讀 | 左側目錄(窄螢幕時為抽屜)、localStorage |
scripts/serve-tailscale.sh | 在 Tailscale 環境中,將資料夾以 tailnet 內的 HTTPS 位址匯出,並確認回應(選擇性) | URL、PID、停止指令 |
scripts/check_print.sh | 以與瀏覽器列印相同的路徑,將確認用 A4 PDF 輸出至暫存資料夾 | PDF 路徑、頁數、每頁 PNG |
scripts/grid_overlay.py · scripts/annotate.py | 在瀏覽器外的圖片上疊加座標格線,並繪製框線與圖例 | 註解圖片 |
使用方式與注意事項請參考各腳本的檔頭註解。
產出
一個報告資料夾(<日期>-<主題>/):用於編輯的 index.html、圖片 images/(原始圖片位於 images/raw/)、拍攝清單與裁切座標檔案、用於交付的 report.html(包含嵌入圖片的單一檔案)。交付時,應同時說明連結、截取過程中變更的項目、以及無法在畫面上看到的項目。
在技能生態系中的定位
- 瀏覽器工具 - 此技能是關於使用所選工具如何截取並載入文件。若環境中有選擇工具或隔離 session 的規則,則應遵循
- 文件技能 - 無畫面的報告、提案、投影片不屬於此技能,而是通用文件技能的範疇
- 文字修飾 - 若環境中有修飾報告語句與畫面構圖的標準,則應使用。在檢查軸中也可作為原則的來源