# 海報投稿盒交接簡報 — poster-desk-lab/1.0.2

[下載完整教學 ZIP](https://yenpo.app/examples/poster-desk-handoff-1.0.2.zip) · SHA-256：`c39d19b210c05f4667cd74db4934459a079408d14c5e7678c24cd087e1df5185`

這是 ZIP 內簡報的閱讀副本。下方原始碼和指令碼路徑均相對於解壓後的 `poster-desk-lab` 目錄；執行命令和複製驗收表需要完整 ZIP。

任務：收集海報標題，供稍後在本機檢視。程式碼、投稿和待核驗承諾均為獨立構造的教學材料，不是真實使用者、事故或某段 AI 輸出。需要 Node.js 22+，不安裝依賴、不聯網、不用憑據。解壓到全新目錄，進入 `poster-desk-lab`；逐條執行下方命令，先驗證包，再按本版本行號讀原始碼。

## 功能事實

| ID  | 承諾與實際觀察                                                                                             | 分類及範圍                                                                                 | 本版本原始碼依據                                                                   |
| --- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| P1  | 「投稿後可以再檢視。」另一個 Node 程序從同一保留目錄讀回相同 ID 和標題。                                   | **implemented / 已實作**：本機檔案、順序程序。不等於崩潰後永續性、遠端資料庫或部署後保留。 | `src/store.mjs` 46–76 行；`src/cli.mjs` 12–17 行                                   |
| P2  | 「回執已經傳送。」返回成功時附有樣例預覽，欄位為 `adapter: fixture`、`delivery: not-attempted`。           | **mock / 模擬**：只有預覽，沒有嘗試傳送；在本包範圍，「已傳送」的承諾不成立。              | `src/cli.mjs` 1–2、15–17 行選擇 `src/receipt.mjs` 3–7 行和 `fixtures/receipt.json` |
| P3  | 「同一投稿重試不重複。」相同 ID、標題按順序再提交，返回 `created: false`，清單仍一條；同 ID 改標題會拒絕。 | **implemented / 已實作**：同目錄、相同內容、順序重試。不承諾併發、寫入中斷或外部通知重試。 | `src/store.mjs` 46–60 行                                                           |
| P4  | 「部署替換後投稿仍保留。」包裡沒有部署環境或資料目錄生命週期資料。保留目錄能讀回，換新目錄則為空。         | **unknown / 未知**：兩個本機結果不能說明部署會保留哪個目錄，不能把 P1 推成 P4。            | `src/store.mjs` 7–9、22–38 行；本快照未提供部署設定                                |

「已實作」只指已示範範圍；「模擬」是已知的替代路徑，不是未經測試的真實服務；「未知」表示缺少判斷所需的環境證據，不等於已知沒有實作。

## 接收與重現

```sh
node --version
node scripts/verify-package.mjs
node scripts/copy-receiver.mjs
node src/cli.mjs init receiver-state
node src/cli.mjs submit receiver-state cloud-poster "Cloud shapes"
node src/cli.mjs list receiver-state
node src/cli.mjs submit receiver-state cloud-poster "Cloud shapes"
node src/cli.mjs list receiver-state
node src/cli.mjs submit receiver-state cloud-poster "Different title"
node src/cli.mjs list receiver-state
node src/cli.mjs init replacement-state
node src/cli.mjs list replacement-state
node src/cli.mjs list receiver-state
node src/cli.mjs init receiver-state
node src/cli.mjs list receiver-state
node --test tests/contract.test.mjs tests/receiver-copy.test.mjs
```

第一次提交的 `accepted`、`created` 為 true；回執仍為 fixture，delivery 為 not-attempted。清單為 `{"cards":[{"id":"cloud-poster","title":"Cloud shapes"}]}`。相同內容重試的 `created` 為 false，清單不變。

改標題那條命令**退出 2**，stderr 為 `{"error":"card-id-conflict"}`，stdout 為空，隨後清單仍保留原標題。新目錄 `replacement-state` 的清單是 `{"cards":[]}`；原目錄仍能讀回卡片。重複初始化原目錄也**退出 2**，報 `{"error":"EEXIST"}`，不會替換它。這兩項是預期拒絕，不要把退出碼改記為透過，也不要用 `&&` 串命令。重複初始化被拒絕後的 list 應再次讀回原卡片。五項測試透過，其中一項實際複製驗收表、填寫包外副本，再確認原包仍能透過校驗。

每條 CLI 命令都是獨立程序，所以檢查的是保留檔案時的程序重啟。新目錄為空只是本機對照，**沒有執行真實部署替換**。命令只會建立兩個新的子目錄；再次重現請重新解壓，不用現有專案或生產資料目錄。

## 接收驗收與待查項

上方複製命令把 `RECEIVER.md` 模板複製到解壓包外的 `../poster-desk-receiver.md`；已有副本會被拒絕，不會覆蓋。按自己的輸出和原始碼閱讀填寫**包外副本**，保留包內原模板不變。驗收記錄不屬於原始包雜湊清單。填寫後，再執行：

```sh
node scripts/verify-package.mjs
```

此時原包仍應透過。驗收條件：P1/P3 在限定範圍成立，P2 保持模擬分類，P4 保持待查。未知項不推翻已經核驗的本機事實，也不能被綠燈測試變成部署承諾。

若要確認真實環境的 P4，須取得準確部署/儲存設定，並以授權的非敏感資料，獨立驗證已知記錄在該環境替換前後的結果。本包不包含這種環境或驗證。併發寫入、斷電、備份恢復和真實通知也未評估。原始碼先儲存卡片再準備回執；回執出錯時，卡片可能已經儲存，不能僅憑錯誤推斷沒有寫入。
