lazyBoy/docs/agent-computer-progress.md

1280 lines
202 KiB
Markdown
Raw Permalink Normal View History

2026-09-10 14:42:17 +00:00
# Agent Computer progress (V3)
2026-09-11 02:47:43 +00:00
> **2026-09-10 第三輪狀態修正:全案仍為 PARTIAL。** 請以 [逐項稽核](agent-computer-audit-2026-09-10.md) 的 O01O48/T01T64 為準。下方前兩輪 `IMPLEMENTED` 包含尚未接進 runtime 的純函式及 fixture不能視為全案已驗收。本輪實際修復與測試見文末。
2026-09-10 14:42:17 +00:00
基準 commit計劃`e6afa324530e19922909d4692c28fb005cc05a7a`
本機開始 HEAD`79952b088b394e36d6c3db3952165f1c3fd59961`
未覆蓋使用者未提交修改(`docs/plan/` 仍未追蹤)。
驗證2026-09-10 複查見文末「複查Bug 修正」):`cargo fmt --check`、`cargo clippy --workspace --all-targets -D warnings`、`cargo test --workspace`(含 sqlx全綠、`make test-agent-computer`、`apps/web npm run build` 全部 exit 0。
sqlx 測試用拋棄式 `pgvector/pgvector:pg16``127.0.0.1:5434``docker run --rm --name lazyboy-test-pg …`),不重建正在服務的 `lazyboy-postgres-1`
真實 OAuth主信箱TigerVNC GUI fixture`BLOCKED_EXTERNAL`。
sample MCP 在真實 Computer 容器 `lb-team-space-*``python3 echo_server.py` JSON-RPC 回 `from-computer`。外掛 UI 已 typecheck無瀏覽器工具未點擊。
---
## PR-00 / PR-01
狀態IMPLEMENTED見前次。截圖交付、semantic/vision、原生 fs/exec 短路徑。
---
## PR-02雙模式身份
狀態IMPLEMENTED資料契約idle沒有強制遷移
- `computers.generation`destroy/recreate `generation + 1`(舊 job 不可裝活)。
- Team 多 bot 同 `computer_id``computer_scope_key(Team, space, bot-a) == bot-b`。Dedicated 互斥 scope。
- **沒有**對 `bots.computer_id` 加 UNIQUE。
- `AdapterContext.computer_generation` / `control_epoch`
- Pause scopes`PauseScope::{Agent,Display,Computer}`;停 A 不 bump B 的 display epoch。
- idle reaper 把 `computer_jobs` running 算進活性。
回滾migration 022 + generation SELECT/UPDATE。
---
## PR-03ledger / 脫敏 / activity
狀態IMPLEMENTEDPostgres 為 mutation 來源;本環境未跑 sqlx 整合測試)
- `dispatch`mutating tool 先 `begin`journal insert 失敗則 `JOURNAL_UNAVAILABLE`,不開做。
-`operationId` + payload hash replay 已存結果;不同 hash → `PAYLOAD_MISMATCH`
- `operationId` 不進入 payload hash。
- `finish``computer_operations` + `operation_outbox``worker_loop` `flush_outbox` 只補尚未出現在 `run_activity``operationId`
- 結果與 outbox payload 經過 `redact_text` / `redact_json`
---
## PR-04jobs / cancel / CAS
狀態IMPLEMENTEDRunner 在 API 行程內container recreate 以 generation 中斷)
- `JobSupervisor``process_group(0)`cancel TERM→KILL process group。
- `exec``action=run|status|cancel`、`background` 回 `jobId`
- `write_file.expectedHash``CONFLICT`,不覆蓋。
- 測試:`/bin/true` 真 exit`sleep 30` 可 cancel。
- API 重啟:`computer_jobs` running/accepted → `interrupted`(不假裝收回 Docker PID
- `LAZYBOY_NATIVE_JOB_CONCURRENCY`(預設 2超額 → `QUOTA_EXCEEDED`
- Artifact`write_file` 成功寫 `computer_artifacts``GET /api/bots/{id}/artifacts` 列表;下載從 Computer `read_file` 串回sha256 不符 → `CONFLICT`
O04 PTY `terminal.*`DEFERRED見文末。跨重啟回收仍在跑的容器 PID標 interrupted不是 resume。
---
## PR-05Tool Manager / MCP
狀態IMPLEMENTEDstdio 不在 API spawnsample 在 Computer無第三方商店
- Manifest空 digest / zip-slip / 空 entrypoint 拒絕。
- 安裝≠Ready`AuthRequired` ≠ 可用)。
- `scripts/sample-mcp/echo_server.py` + `manifest.yaml`(本機範例,不是虛構 npm
- REST`GET/POST /api/bots/{id}/tools`、`POST .../tools/call`、`POST .../revoke`。
- 安裝把 echo 寫進 ComputerDedicated `tools/...`Team `shared/tools/...``python3` 在該容器執行 JSON-RPC。
- Agent 工具 `computer_mcp` 走同一條路徑;未 bind → `NOT_BOUND`
- 外掛頁「Computer 套件」可安裝/呼叫/撤銷 echo市集 MCP 文案不再假裝 stdio 都在 Computer。
- MCP `call_for` 先複製 client 再 await`definitions_for(actor)` 不把別人的工具塞進這次 run。
未做任意第三方套件商店、OAuth broker。`/api/mcp-servers` stdio **不再** `spawn` 子行程,只存 metadata 並指向 Computer Tool Manager。HTTP/SSE 仍為遠端 client。真實 Microsoft/Google OAuth`BLOCKED_EXTERNAL`。
---
## PR-06路由 / verifier / wait
狀態IMPLEMENTED決策層
- `choose_route`:有授權 API 不走 browser`POLICY_DENIED` 不繞路。
- `CompletionLayer`transport ≠ effect ≠ task`wait_counts_as_progress() == false`。
- policy`wait` 不再刷新無進展時鐘;`exec` 可。
- `wait_until` 有 deadline未知 disabled 不空轉。
- system promptGmail/Outlook 有 connector 走 API。
---
## PR-07form / takeover scopes
狀態IMPLEMENTEDform 工具已註冊lease/pause 見 PR-02
- `run_form_macro` 失敗即停、逐步 evidence。
- Display writer lease 原本就有pause scope 見 PR-02。
- Agent 工具 `form_fill`:用最新 snapshot locatorelement id`run_form_macro` 先定位,第一個失敗就停;可選 `submit` click。
---
## PR-08A Gmail fixture
狀態IMPLEMENTED純函式 fixture不碰真信箱
- batchModify 同 delta 分組、1000 cap。
- undo 只撤本 plan 的 delta。
- 真實帳號:`BLOCKED_EXTERNAL`。
---
## PR-08B Outlook
狀態IMPLEMENTEDGraph 語意 fixture非官方 npm
- `$batch` 最多 20子項 429/401 分開。
- categories merge不覆蓋無關分類。
- `Mail.ReadWrite` 不自動允許寄信。
- 真實 Graph OAuth`BLOCKED_EXTERNAL`。
---
## PR-09 TigerVNC 候選
狀態IMPLEMENTEDopt-in預設仍 Xvfb+x11vnc
- `DisplayBackend`slot 0 = `:1` / 5900 / 6080T57
- `lazyboy-screen``LAZYBOY_DISPLAY_BACKEND=tigervnc_xvnc`
- Dockerfile 加入 `tigervnc-standalone-server`,失敗則 script fallback Xvfb。
- Cua/中文/a11y GUI 對照:`BLOCKED_EXTERNAL`**未改 default**。
---
## PR-10 設定 / 文件
狀態IMPLEMENTED
`.env.example``LAZYBOY_EXECUTION_PROFILE`、`LAZYBOY_DISPLAY_BACKEND`、`LAZYBOY_BROWSER_BACKEND`、concurrency、tool install flags。
`migrations/022_agent_computer.sql`
---
## O01O48
| ID | 狀態 |
|---|---|
| O01 | IMPLEMENTED |
| O02 | IMPLEMENTED短 exec長 job 見 O04 |
| O03 | IMPLEMENTED + CAS |
| O04 | PARTIALComputer 內 background exec + cancelPTY `terminal.*` DEFERRED |
| O05 | IMPLEMENTEDform macro + `form_fill` 工具) |
| O06 | IMPLEMENTEDstdio 不在 API spawnHTTP/SSE 遠端echo 在 Computer |
| O07 | DEFERRED未量測 docker exec 開銷) |
| O08 | IMPLEMENTED`boot_for(need_gui=false)` 不 ensure_screen`LAZYBOY_RUNNER_ONLY` 不 boot XFCE |
| O09 | IMPLEMENTEDrouter |
| O10 | IMPLEMENTEDrevoke 從下次 schema 拿掉 computer_mcpstdio 不再進 defs |
| O11 | 保留現況 |
| O12 | IMPLEMENTED |
| O13 | DEFERRED |
| O14 | IMPLEMENTEDPR-01 |
| O15 | 保留現況(既有 profile bind |
| O16 | PARTIALverifier 層 + wait 不算進度) |
| O17 | 實驗opt-in |
| O18 | DEFERRED |
| O19 | 保留現況 |
| O20 | 保留現況 |
| O21 | 保留現況 |
| O22O24 | DEFERRED |
| O25 | IMPLEMENTED保留 |
| O26 | PARTIAL既有 screen/profile lease |
| O27 | IMPLEMENTEDepoch 函式) |
| O28 | PARTIALidle 看 runs/skills/jobs2026-09-10 修正守門原本永遠回 false並在判斷前 reconcile job 狀態) |
| O29 | IMPLEMENTEDpackage/binding 分離;共用 bytes 不共享帳號) |
| O30 | IMPLEMENTED`LAZYBOY_NATIVE_JOB_CONCURRENCY`,預設 2配額滿時先向 Computer reconcile 未 poll 的 job不會永久卡死 |
| O31 | DEFERRED |
| O32 | DEFERREDT59保留 `-ac` 直到 Xauthority 接到 Cua/AT-SPIVNC 仍走認證 proxy |
| O33 | IMPLEMENTEDsample MCP 安裝 REST + UI |
| O34 | IMPLEMENTEDdigestzip-slipunpinned npx 拒絕) |
| O35 | IMPLEMENTEDinstalled ≠ readyAuthRequired 不可用) |
| O36 | PARTIAL熱啟用 bindings無獨立 schema cache 服務) |
| O37 | IMPLEMENTED0.0.2 旁置、job pin 舊版、rollbackremove |
| O38 | BLOCKED_EXTERNAL |
| O39O40 | IMPLEMENTED fixture真實帳號 BLOCKED_EXTERNAL |
| O41 | IMPLEMENTEDdispatch 寫 operations + outboxflush 補送) |
| O42 | IMPLEMENTEDerrorCode/jobId/operationId |
| O43 | IMPLEMENTED列表 + 下載;磁碟 hash 不符 CONFLICT |
| O44 | PARTIALverifier 層) |
| O45 | IMPLEMENTEDCAS + operation id |
| O46 | IMPLEMENTED`GET /api/computer/{id}/health`dbsandboxdisplayjobsoperations |
| O47 | DEFERRED |
| O48 | DEFERRED無固定環境雙模式 P95不寫未測倍數 |
---
## T01T64
| ID | 狀態 | 證據/理由 |
|---|---|---|
| T01 | IMPLEMENTED | `should_deliver_observation_image` |
| T02 | IMPLEMENTED | 換模型takeover 強制交付(同真值表) |
| T03 | IMPLEMENTED | `pixel_actions_need_vision`text-only 無圖 |
| T04 | IMPLEMENTED | `typed_browser_errors` |
| T05 | IMPLEMENTED | Team/Dedicated path + echo 路徑測試 |
| T06 | PARTIAL | generation 拒絕舊 job未覆蓋所有偽造 grant 變體 |
| T07 | 保留現況 | task 無 Docker socket未加新 sentinel fixture |
| T08 | IMPLEMENTED | zip-slip`..` path 拒絕 |
| T09 | IMPLEMENTED | invalid UTF-8 binary payload |
| T10 | PARTIAL | 工具錯誤非空成功;磁碟滿未測 |
| T11 | IMPLEMENTED | `stale_hash` CAS CONFLICT |
| T12 | IMPLEMENTED | Supervisor `/exec` 回完整 `CommandResult`reap 讀 `exit` 檔,`false`/缺檔為 Failed/1 |
| T13 | IMPLEMENTED | Computer-side job_op cancel 走 `computer_cancel_script`TERM→KILL 整個 process group驗證後才標 cancelled2026-09-10 修正 pid 錯誤status 缺欄位當 TRANSPORT不發明 running |
| T14 | DEFERRED | API 重啟標 interrupted不 resume 容器 PID |
| T15 | IMPLEMENTED | generation interrupt |
| T16 | IMPLEMENTED | operation_id hashmismatch2026-09-10 第二輪key 改 per-bot、in-flight 同 id 回 `UNKNOWN_EFFECT`、傳輸失敗不存成 succeededsqlx 測試 `ledger_is_per_bot_and_does_not_rerun_in_flight_work` |
| T17 | IMPLEMENTED | outbox flush 補送且不重複sqlx 測試 `outbox_flush_does_not_duplicate_recorded_operations`2026-09-10 修正 `SELECT 1` 解碼 bug |
| T18 | IMPLEMENTED | `journal_failure` 拒 mutation |
| T19 | IMPLEMENTED | actor-scoped MCPstdio 不在 API 持有 client |
| T20 | PARTIAL | NOT_BOUNDrevoke無真實 token revoke |
| T21 | IMPLEMENTED | `canary_is_stripped`2026-09-10 第二輪ledgersnippet 實際套用 `redact_secret_patterns`(之前傳空 canary 等於沒脫敏) |
| T22 | 保留現況 | 既有 prompt 邊界;無新 injection corpus |
| T23 | PARTIAL | 同 display lease 既有Cua+worker 未雙開 fixture |
| T24 | PARTIAL | pause/takeoverHTTP in-flight barrier 未單獨測 |
| T25 | IMPLEMENTED | wait 不算 milestone |
| T26 | IMPLEMENTED | Gmail batchModify fixture |
| T27 | IMPLEMENTED | fixture 429/partial真實帳號 BLOCKED_EXTERNAL |
| T28 | IMPLEMENTED | undo 只撤本 plan |
| T29 | IMPLEMENTED | 無強制拆 Teammigration 不 UNIQUE computer_id |
| T30 | IMPLEMENTED | `boot_for(need_gui=false)``ensure_screen``maybe_ensure_screen` + FakeSandbox native write/read/exec`start.sh` runner-only 不 boot XFCE |
| T31 | PARTIAL | job 配額;無壓力 bench |
| T32 | DEFERRED | 無郵件分類品質集 |
| T33 | PARTIAL | broker 不進 generic env無任意 exec 讀 socket fixture |
| T34 | IMPLEMENTED | artifact 從 Computer 下載 |
| T35 | PARTIAL | CASoperation replayresume 不重播未全測 |
| T36 | PARTIAL | mutating tools 走 ledgerMCP stdio 不再是旁路 spawn |
| T37 | IMPLEMENTED | `team_computers_share`migration 註解+測試 |
| T38 | IMPLEMENTED | Team `bots/<id>/` 路徑 |
| T39 | IMPLEMENTED | shared/ + CAS |
| T40 | PARTIAL | 多 slot 契約;無雙 writer GUI fixture |
| T41 | PARTIAL | display writer lease 既有 |
| T42 | IMPLEMENTED | pause scope 停 A 不 bump B |
| T43 | PARTIAL | idle 看 jobs整機 pause 未單測 recreate 全集 |
| T44 | 保留現況 | 既有 ensure-screen single-flight |
| T45 | IMPLEMENTED | Dedicated 刪 botTeam Computer 存活 |
| T46 | IMPLEMENTED | echo 安裝/呼叫 `executionLocation=assigned_computer` |
| T47 | IMPLEMENTED | binding per bot套件 per computer |
| T48 | IMPLEMENTED | digestzip-slipunpinned npx |
| T49 | IMPLEMENTED | `plan_version_switch` job pin |
| T50 | IMPLEMENTED | revokeremoverevoke 掉 schema |
| T51 | IMPLEMENTED | Outlook fixture非官方 npm |
| T52 | IMPLEMENTED | Graph 子項 429/401 |
| T53 | PARTIAL | fixture 分頁語意;真實 delta BLOCKED_EXTERNAL |
| T54 | IMPLEMENTED | categories merge 不盲覆蓋 |
| T55 | BLOCKED_EXTERNAL | 無 Cua/中文/a11y GUI |
| T56 | PARTIAL | generation bumpbackend 熱切未做 |
| T57 | IMPLEMENTED | slot 0 = :1/5900/6080 |
| T58 | 保留現況 | 既有 noVNC無新 DPI fixture |
| T59 | DEFERRED | 保留 `-ac`VNC 走認證 proxyXauthority 未接到 Cua |
| T60 | IMPLEMENTED | 同 T30native 路徑不 attach viewerGUI 之後才 `lazyboy-screen ensure` |
| T61 | IMPLEMENTED | 未審查 env tokenunpinned npx 拒絕 |
| T62 | 保留現況 | 同 UID 不宣稱強隔離 |
| T63 | PARTIAL | job 配額renderer OOM 未測 |
| T64 | PARTIAL | 套件路徑可重建;舊 job 不裝活 |
## 2026-09-10 複查Bug 修正
本輪先跑計劃第 16 節的完整 gate再修實際發現的 bug未新增功能。
驗證命令與結果(本機,拋棄式 Postgres `pgvector/pgvector:pg16``127.0.0.1:5434`
- `cargo fmt --all -- --check`:原本有 diff`artifacts.rs`、`computer.rs` 等新檔未格式化)→ 已 `cargo fmt --all`,現在 exit 0。
- `cargo clippy --workspace --all-targets -- -D warnings`exit 0。
- `DATABASE_URL=… cargo test --workspace`**全部通過**api 157 passed / 3 ignoredcontrol 150harness 37contracts 7sandbox 7supervisor 2。前次紀錄的「sqlx 未連」現在已實跑14 個 sqlx 測試dbmemorymonitorrouting::fan_out全綠。
- `make test-agent-computer`exit 0。
- `apps/web``npm run build``tsc --noEmit` + vite通過。
修正:
1. **`lazyboy-api` 測試 binary 結束時 SIGABRT**`ort` `Mutex poisoned``release_env_on_exit` 二次 panic。根因`memory.rs` 用 `catch_unwind` 包住 `TextEmbedding::try_new`,但 `ort` 找不到 `libonnxruntime.so` 時是在持有全域鎖的情況下 `expect` panic鎖被 poison 後程序退出時 `.fini_array` hook 再 panic → abort。正式環境沒設 `ORT_DYLIB_PATH`API 正常關機也會變 exit 134。修法`memory.rs` 新增 `preload_onnx_runtime()`,先走 `ort::init_from(path)`(回 `Result`)預載 dylib失敗即標 `Unavailable` 不再進 fastembed`crates/api/Cargo.toml` 直接依賴同版 `ort ="=2.0.0-rc.13"`lock 無新增 crate。測試 `database_enforces_agent_scope_and_queries_do_not_leak` 改成顯式 `ModelState::Unavailable`,不再靠環境缺 ONNX 來觸發;新增 `a_missing_onnx_runtime_is_an_error_not_a_panic`。反向驗證:`ORT_DYLIB_PATH=/nonexistent cargo test -- --ignored memory_model_recovers_after_cache_failure` 只因無模型 fail**不再 abort**。
2. **Computer 內 background job 的 pid 是錯的T13 process-tree cancel 實際上沒生效)**。`computer_background_launch` 原本是 `mkdir -p … && setsid nohup sh … & echo $!``&` 作用在整個 `a && b` list`$!` 是 bash 子 shell 的 pid不是 `setsid` 後的 session leader。後果`status` 只是碰巧能用(子 shell 會 wait`cancel` 只殺子 shell真正的 `sh`→子程序變孤兒繼續跑,之後 `status` 讀不到 exit 檔還會誤報 `failed`。修法:`mkdir` 獨立一行wrapper 先 `printf %s "$$" > …/pid`launcher 等 pid 檔再輸出(`setsid` 若 fork 也正確)。新增 `computer_cancel_script(pid)``kill -TERM -- -pgid` → 最多 1s 等待 → `kill -KILL -- -pgid` → 再驗證exit 0 才算整棵樹已消失。`supervisor/docker.rs` cancel 改用它,且只有樹確實消失才把 job 標 `cancelled`(否則維持 `running`,不假稱取消)。測試:`computer_cancel_script_kills_the_whole_process_tree`(本機真起 `sh -c 'sleep 300; sleep 300'`,用 `pgrep -g` 驗證子 `sleep` 一起死);另在真實 Team 容器 `lb-team-space-c7bace…` 內手動跑 launchercancelpid=pgid=sid`tree gone`。
3. **supervisor `job_follow_up` 沒檢查 job 屬於哪個容器**:拿到別的 Computer 的 jobId 時會在自己容器對同號 pid 送 `kill`。現在 `job.computer_id != container` 一律回 `unknown job`
4. **`Makefile` `help` 目標壞掉**:新增的 `test-agent-computer` 說明被塞進同一個 `@echo "…` 造成跨行未閉合字串,`make help` 回 `Unterminated quoted string` Error 2。已拆成兩行 `@echo`
5. **idle reaper 的「有工作就不暫停」守門一直是死的HEAD 既有 bug**`computer_has_active_work` 把 `SELECT 1`INT4解成 `(i64,)`sqlx 回 `ColumnDecode mismatched types`,被 `matches!(Ok(Some(_)))` 吞成 false → 只要 `computers.updated_at` 十分鐘沒動,正在跑 run 的 Computer 也會被 suspend。改成 `sqlx::query(...).fetch_optional` 只看有沒有列。sqlx 測試 `idle_reaper_reconciles_unpolled_jobs_with_the_computer` 同時覆蓋 run 與 job 兩種活性。
6. **`flush_outbox` 去重失效T17 宣稱的「不重做」實際沒生效)**:同樣的 `SELECT 1`→`i64` 解碼錯誤讓 `exists` 永遠 None每筆 outbox 都再寫一次 `run_activity`Activity 出現重複 tool 事件。已改為列存在檢查;查詢出錯時保留 outbox 列到下一輪,不猜。新增 sqlx 測試 `outbox_flush_does_not_duplicate_recorded_operations`
7. **背景 job 配額會永久卡死**`computer_jobs.status` 只在 agent 呼叫 `exec status` 時更新;兩個跑完但沒人 poll 的 job 會讓該 Computer 之後永遠 `QUOTA_EXCEEDED`idle reaper 也永遠以為有工作。修法:`tools.rs` 配額看起來滿時先 `refresh_running_jobs`(向 Computer 問最舊 16 筆 running 的真實狀態supervisor 回 `unknown job``interrupted`)再重算;`computer.rs` 的 `pause_idle_computers` 在判斷活性前做同樣的 reconcilesuspended 容器無法問,`stop_parked_computers` 不做)。
未修、已知:
- host 端 `JobSupervisor::start``crates/control/src/jobs.rs`)用 piped stdout 但只在子程序結束後 `read_to_end`;輸出超過 pipe buffer~64 KiB的子程序會永久阻塞。目前正式路徑不用它背景 job 全在 Computer 內,`exec_background_does_not_spawn_on_the_api` 有守門),僅測試使用;若之後要在 API 行程內跑 job 必須先改成邊跑邊 drain。
- supervisor 的 `ComputerJobTable` 在記憶體supervisor 重啟後舊 jobId 回 `unknown job`API 側已把 `computer_jobs` 標 interrupted屬同一限制T14 仍 DEFERRED
回滾:還原 `crates/api/src/memory.rs`、`crates/api/Cargo.toml`ort 直接依賴)、`crates/api/src/tools.rs`refresh_running_jobs、`crates/api/src/computer.rs`、`crates/api/src/operations.rs`、`crates/control/src/jobs.rs`、`crates/supervisor/src/docker.rs`、`Makefile` 本節改動即可;無 migration 變動。
## 2026-09-10 複查(第二輪):三路平行 code review 後的修正
三個獨立 reviewledger/outbox/artifactsjobs/tool-manager/install雙模式/pause/前端)共回報 40 餘項重複、已在上一節修掉的略過。以下每項都有測試或反向驗證。gate`cargo fmt --check`、`clippy -D warnings`、`cargo test --workspace`api 162control 154harness 37、`tsc --noEmit` 全綠。
**LedgerT15T17`operations.rs` 重寫)**
1. **operationId 全域命名空間 → 跨 bot replay拒絕**ledger key 改為 `{bot_id}:{operation_id}`,查詢加 `bot_id` 條件。Bot B 選到 Bot A 用過的 id不會拿到 A 的結果,也不會被 `PAYLOAD_MISMATCH` 擋。
2. **記憶體 `LEDGER` 拆掉**:與 DB 兩份狀態不一致(一邊 accepted 一邊沒列)、無上限增長(連非 mutating tool 都建列。Postgres 是唯一真相;`OperationLedger` 只留 control crate 單元測試用。
3. **`bot_computer_id` 查詢失敗被當「沒有 Computer → Proceed」**:現在 DB 錯誤 = `JOURNAL_UNAVAILABLE`;不需要 Computer 的 mutationrememberschedule`computer_id = NULL` 入帳migration 023 放寬 NOT NULL
4. **同 id 同 payload 的 `accepted` 列直接 Proceed → 崩潰後重試會做第二次**:新增 `Begin::InProgress` → 工具回 `UNKNOWN_EFFECT`,要求先讀回狀態、換新 id 重試。
5. **`finish` 對非 mutating tool 也寫 DBoutbox**:提早 return。`exec status` 改為非 mutating`exec run/cancel` 仍是)。
6. **`"xxx failed: …"` 的傳輸失敗被存成 `succeeded` 並永遠 replay**`outcome_status` 辨識這類文字 → 刪除 accepted 列讓同 id 可重試;不寫入結果。
7. **replay 丟掉 `pause`**`Begin::Replay` 帶回 `pause`
8. **outbox 寫 `run_activity` 失敗仍標 delivered**:新增 `monitor::try_record_pool`,只有成功才標;且只處理 `created_at` 早於 2 秒的列,避免與 `runs.rs` 的直接寫入賽跑而重複。
9. **`redact_text(&text, &[])` 是 no-op**:新增 `redact_secret_patterns`Bearer、`password=``token:`、`sk-``ghp_``AKIA``xox``AIza`、PEM 私鑰、JSON secret keyledger 結果與 activity snippet 都經過它。control crate 新增 `regex` 直接依賴lock 已有)。
10. retention 新增 `operation_outbox`delivered7 天)與 `computer_operations`(非 accepted90 天)。
**JobsT13T14**
11. **runner-only 容器 PID 1 是 `sleep infinity`,不收屍**setsid 後的 wrapper 結束會變 zombie`kill -0` 仍成功 → job 永遠 `running`。修:`HostConfig.init = true`docker-init 收屍);`status` 改先讀 exit 檔、再用 `computer_alive_script`(看 `/proc/*/status` StateZ/X 視為死)。測試 `computer_alive_script_treats_a_zombie_as_dead` 本機造真 zombie 驗證。
12. **launcher 沒吐出 pid 時仍登記 jobpid None→ 永遠 running、不能 cancel**:現在直接回錯誤,不登記幽靈 job。
13. **`exec status/cancel` 不看歸屬與世代**:新增 `job_ownership`:別的 bot 的 job → `UNKNOWN_JOB``generation` 小於目前 Computer 世代或已 `interrupted` → 直接回 interrupted不去問新容器`persist_job` 的 upsert 不再把 `interrupted` 蓋回 `running`
14. **`pin_running_jobs` 把同 Computer 上其他 bot 的 job 也 pin 了**:加 `bot_id` 條件。
**Tool ManagerT18T21**
15. **revoke 後重裝撞 `UNIQUE(package_row_id, bot_id)` → 500**`ON CONFLICT … DO UPDATE SET status='ready' RETURNING id`;切版本走 `switch_binding`(同 tx 內先清掉同 (package_row, bot) 的非 ready 殘留)。
16. **rollback 會把 `revoked` binding 復活**:非 `ready` → 409。
17. **執行前不驗 digest**`verified_run_argv` 在同一條命令內 `sha256sum -c` 通過才 `exec python3`;不符 exit 97 → `PACKAGE_TAMPERED`。測試 `tampered_package_is_refused_before_it_runs` 真改檔驗證。
18. **`validate_manifest` 只檢查非空**:現要求 64 hex`compute-at-install` 佔位會被拒。
19. `InstallBody` 只吃 `package_id`、前端送 `packageId`serde `rename` + `alias` 兩者皆收。
20. `refuse_unpinned_npx``@scope/pkg``@` 當版本 pin修為去掉 scope 前綴再判斷。
**其他**
21. **`form_fill` 靜默截斷**>20 欄或欄位缺 namelocator → `INVALID_ARGUMENT`,不再填半張表回報成功。
22. **`looks_like_css` 誤判 `v1.2 Release``C++ Guide` 這種標題為 CSS**clicktype 先做精確唯一標題比對;找不到才依 locator 形狀決定 `SELECTOR_UNSUPPORTED``TARGET_NOT_FOUND``TARGET_STALE`,並各給對應說明。
23. **`computers.display_backend` 從未寫入**boot 轉 running 時寫入 `DisplayBackend::from_env()`health 不再永遠回欄位預設值。
24. **`delete_bot` 不清 `tool_bindings``computer_jobs``computer_operations``computer_artifacts`**:同 tx 一起刪Team Computer 的配額不再被已刪 bot 佔用)。
25. **`wait``PROGRESS_WHEN_REPEATED`與本文件「wait 不刷新無進展時鐘」相反**:改成 heartbeat 語意 — `wait` 只更新 `last_heartbeat_turn`(不會被當 loop halt但 stale 教練訊息照常觸發;`polling_a_build_or_a_queue_is_not_treated_as_spinning` 同時鎖住兩半契約。
26. **Gmail fixture 沒有真的 undo**:新增 `undo_plan(before, batches)`,只還原本次計畫實際改動的 label原本就有的不拔、原本沒有的不補、人工新加的不動測試做 plan→undo 往返驗證。
27. 前端:`RunActivityEntry.operationId` 補型別;`runs.rs` 從工具回傳 JSON 抽 `jobId` 寫進 activitymonitor 原有的 `entry.jobId` 顯示終於有值;並顯示 `op <短 id>`
**Migration**:新增 `migrations/023_agent_computer_fixes.sql``computer_operations.computer_id` DROP NOT NULL、移除多餘 `computer_operations_id_hash`、outbox pending 部分索引、`computer_operations(bot_id, created_at)` 索引)。不改 022已可能套用過
**review 提到但本輪不動、記錄在此**
- Pause scopes`resume_after_pause``route_operation` 有純函式與測試但沒接進 runs 主迴圈takeover 實際只有 GUI 全暫停,沒有 scope 級細分T22T24 應視為 PARTIAL不是 DONE
- `write_file``bash -lc` 字串插值路徑HEAD 既有);`normalize_workspace_path` 有限制字元,本輪未改成 argv。
- supervisor `ComputerJobTable` 仍在記憶體T14 DEFERRED 不變)。
回滾:還原本節列出的檔案,並 `DELETE FROM _sqlx_migrations WHERE version=23``ALTER TABLE computer_operations ALTER COLUMN computer_id SET NOT NULL`(若已無 NULL 列)。
## 誠實未完成
P0/P1 可在本環境落地的已接上。下面不是「做完」:
1. 真實 Gmail/Outlook OAuth主信箱`BLOCKED_EXTERNAL`。
2. TigerVNC 當預設 + Cua/中文/a11y GUI`BLOCKED_EXTERNAL`;預設仍 Xvfb+x11vnc。
3. Postgres sqlx 整合測試此環境未連。
4. **O04 PTY `terminal.*`DEFERRED** — 非互動走 `exec`+jobs+process-tree cancelTUI 協作仍用 GUI `shell`。不假裝有 PTY。
5. 跨重啟回收容器內仍在跑的 PID標 interrupted不是 resume。
6. 任意第三方套件商店、完整 OAuth broker沒有憑證。
7. O48 無未測速度倍數。
8. 外掛 UI 未在瀏覽器點過(無瀏覽器工具);已 `tsc --noEmit`
雙模式Team/Dedicated 契約不變;**沒有** UNIQUE `bots.computer_id`。stdio MCP **不是** API 子行程。
回滾:還原本輪 crate / migration 022 / lazyboy-screen `-ac` 註解 / sample-mcp / 前端 plugins+i18n。不要 force push。
2026-09-11 02:47:43 +00:00
## 2026-09-10 第三輪:完整計劃核對與實際修復
起始 HEAD `80fe9a8`,工作目錄乾淨;未部署、未操作真實信箱、未刪除既有 Team 資料。
逐項狀態:[O01O48 / T01T64 稽核](agent-computer-audit-2026-09-10.md)。**不是全案完成報告。**
### 實際 diff
1. `crates/control/src/jobs.rs`stdout/stderr 從開始就同時 drain各保留 1 MiB 並標截斷,避免 pipe 塞滿令命令永遠無法退出。拒絕重複 job ID避免覆蓋舊 child handle。`poll` 不再跨 await 暫時拿走 child消除與 cancel/interruption 的競爭窗口。
2. 同檔 `posix_shell_join` 保留空參數;含中文、換行、單引號、`$()`、反引號的真實 shell round-trip 測試。取消拒絕 PID 0/1Computer cancel 排除 zombieSupervisor 對已結束 job 不再發 signal以免 PID 回收後誤殺。
3. `tools.rs`job ownership 在 DB error/missing row 時 fail closed核對目前 bot assignment、Computer generation 與 job owner不再把 unrecorded job 直接轉送。
4. `tools.rs`Computer row lock + `accepted` reservation 同 transaction 執行配額判定,兩 agent/API worker 搶最後一格只有一個成功。DB admission 失敗時不開始命令launch 結果不完整不假報 running`UNKNOWN_EFFECT` 並保留 reservation。
5. `runs.rs`:移除 worker 啟動時把全 DB running/accepted jobs 一律改 interrupted 的 UPDATEAPI 重啟不代表 Computer 程序死亡。Supervisor registry 持久化仍未完成。
6. `computer_files.py`**只在 Computer 執行**read/list/write 以 argv 傳路徑、stdin 傳 bounded base64不把檔名或整份內容拼入 shell/argv。使用 directory descriptor + `O_NOFOLLOW`/`O_NONBLOCK`、regular-file 判斷,拒絕 symlink/FIFO/路徑逃逸與超過 8 MiB 的內容缺目錄不再回空成功。Supervisor file route 允許最多 12 MiB JSON 以容納 base64超過 raw bytes 限制回 HTTP 413。
7. `SandboxProvider::write_file_checked` → Docker transport → Supervisor → helperexpected hash、directory flock、temporary file、fsync、atomic rename 在 Computer 同一程序完成,取代 API 先 read 再 write 的假 CAS。空 expectedHash 表示只可建立unconditional write 需省略 expectedHash。維持原有檔案 executable permission。
8. `path.rs`controlled Team fs 只能指向 own `bots/<id>``shared/`,拒絕其他 bot、相似前綴 bot ID 及 virtual-root 旁路。這不是同 UID arbitrary shell 的 OS 隔離。
9. `supervisor/docker.rs::exec_raw`stdin writer 與 output reader 同時執行,修大量雙向 IO 死鎖job 檔案讀取不再把傳輸/權限錯誤吞成空字串。
10. `operations.rs`:傳輸失敗保留 accepted/unknown 去重紀錄,不能刪 intent 讓相同操作重做。結果與 outbox 同 transaction任何一側失敗回滾dispatch 回 `UNKNOWN_EFFECT`,不宣稱已可靠記錄成功。
11. 同檔:外部 `mcp_*``connection_check` 也需副作用前 journalMCP error 回 typed unknown。**HTTP/SSE MCP client 仍在 API本輪沒有把它搬完。**
12. `tool_install.rs`digest 檢查後直接 compile/execute 同一份 bytes不重新開啟可被替換的 pathnamePython `-I`,拒絕 symlink/non-regular/超限內容。binding 查詢核對當前 Computerboot 後重讀 bot避免初次 provision 用到過時空 assignment。
13. `tests/frontend.test.mjs`:更新一個已過時的描述文字比對,仍驗證 observe boolean/default false 與實際 opt-in 條件;未刪除測試。
14. 新增 `tests/computer-files.test.py`、真實 Rust→Docker opt-in regression、`make bench-agent-computer` 與原生雙模式 benchmark JSON。所有測試容器皆新建、無持久 volume、無公開 ports既有服務不受影響。
### 本輪驗證
- `cargo fmt --all -- --check`:通過。
- `cargo clippy --workspace --all-targets -- -D warnings`:通過。
- `DATABASE_URL=postgres://lazyboy:lazyboy@127.0.0.1:5434/lazyboy cargo test --workspace`374 passed、0 failed、4 ignored包含 disposable sqlx DB 測試。3 個原有外部/模型 fixture ignored新增 Docker fixture 預設 ignored 並於下列命令實際執行。
- `make test-agent-computer`:通過(另含 Python filesystem gate
- `node --test tests/frontend.test.mjs`56 passed。
- `cd apps/web && npm run build`:通過;既有 lottie eval/chunk-size warning非新增編譯錯誤。
- `python3 tests/computer-files.test.py`5 passed含 8 個並行 CAS、1 MiB binary、特殊檔名、symlink/特殊檔案拒絕、大小限制、permission preservation。
- `LAZYBOY_PLAN_TEST_CONTAINER=lazyboy-plan-files-fixture cargo test -p lazyboy-supervisor real_computer_files_cas_and_bidirectional_exec -- --ignored --nocapture`:在新建 `lazyboy/computer:local`、UID 1000、無網路、無 desktop 容器通過;驗證真實 Docker transport、特殊路徑、binary、CAS、1 MiB 雙向 IO、background job 非零退出/完整輸出/取消/terminal job 重複取消。
- `python3 scripts/bench-agent-computer.py`shared 60/60、dedicated 30/30[完整樣本與環境](benchmarks/agent-computer-native.json)。測的是 native helper/read/write/hash/exec非完整 API/model/viewer E2E沒有提速倍數或 GUI 品質宣稱。
### 尚未完成與 checkpoint
核心未完成:受保護且持久的 Computer Runner/PTY/job cursorComputer 本地 durable outboxscope-aware pause/fencing 接線generic MCP loader/常駐 instance/HTTP client 搬遷per-agent/account OAuth brokerGmail/Outlook fake HTTP 與可安裝 adaptertask completion verifier完整 GUI/TigerVNC/viewer benchmark。accepted launch outcome unknown 的 reservation 保守保留,仍需持久 Runner reconcile不能手動猜它沒執行而自動清除重試。取消尚未完成 PID starttime identity 全集。
實際缺程式的項目標 PARTIAL/NOT_STARTED不假借 OAuth 帳號缺失標 BLOCKED_EXTERNAL。真正 Microsoft/Google 帳號、外部模型的 E2E 另列 BLOCKED_EXTERNAL不索取明文密碼不使用主信箱。詳細每個 Oxx/Txx 見稽核表。
回滾:還原上述本輪 diff 與新增 helper/測試/benchmark 檔即可;本輪無 migration。`write_file_checked` 涉及 API、control trait、兩個 sandbox provider 與 Supervisor需一起回滾不能只留半套 transport。
## 範圍追加P0P3 全項完成
使用者明確要求 P0P3 每項完成。先前可選/延期項目全部恢復待辦,包括 transport/DOM 增量、TigerVNC/x0vncserver/XDamage/viewer tuning、Selkies、Xpra、Wayland、shm/OOM、skill 重用與完整 benchmark。互斥 backend 採可選配置,不以一律替換預設理解;每個選項都需實作與驗證,不能只交不採用理由。
## Runner 與中央事件同步 checkpoint2026-09-10後續進度
此節更新前一節尚缺項目,不表示 P0P3 已完成。
- 新增 Computer 內 root 保護的 SQLite job registry、outbox、每工作獨立 worker/socket/output。實際命令降權至 UID/GID 1000、清空繼承環境不繼承控制 token。
- 新增真正 PTY start/interact/resize、精確 binary output cursor、pause/resume/cancel、runtime deadline、4 MiB/stream 上限;完成需等待程序樹與 pipe EOF。重複取消不延後 KILL逾時/超限清理中不提前回報 terminal。
- 修完成時 socket 關閉被覆寫 unknown 的競爭。終態不因 Computer reboot 改為 interrupted管理 reconcile 也需正確 generation。
- API 每 5 秒獨立同步 root outbox不依賴 viewer 或 model turn。migration 024 加入 job run_id 與中央 computer_job_events去重、owner/generation/provider 檢查、job 狀態與 activity 在同一 transactioncommit 後才 ack。API 多 worker 以 job row lock 保持事件順序輸出、argv、程序 metadata 不寫 activity。
- 新增 `make test-runner-jobs`:自動建立無 network、無資料 volume 的 disposable Computer執行 6 項 Python Runner integration 和真實 Rust→Docker transport 測試,結束清除。包括建立新的 DockerHost 後工作仍可取消、本地事件讀取/ack。
- 已通過6 個 Python Runner tests、1 個真實 Rust Docker test、中央事件 SQLx dedup/scoping/order regression。workspace 375 passed、4 ignoredDocker ignored test 另已實跑clippy all targets 通過。最後額外 argv 型別/NUL 驗證與同步 timeout 變更亦已重跑 workspace 375 passed、4 ignored 與 clippy 通過。
仍需完成worker crash/orphan 回收與 PID/starttime 全集、root 輸出/事件 retention現為 64 jobs 硬上限、root scope barrier、broker/grants、通用 MCP/常駐 client/郵件 adapter、完整 files API、task verifier、全部 P2/P3 backend 與 benchmark。此段未部署migration 僅在 disposable SQLx test DB 驗證。
## Runner 回收與輸出保留 checkpoint2026-09-10
- 終態輸出保留 24 小時;達 64 筆保留上限時提前回收最舊、已中央 ack 的終態輸出。未送達事件、執行中工作、unknown 不會被回收。先 commit output_expired tombstone 才刪輸出,重送 start 不重執行output 查詢明確回 OUTPUT_EXPIRED。已 ack outbox 列會清除。
- worker crash 後用受保護 PID/starttime + pidfd 驗證與凍結程序群,回收後標 interrupted不捏造成功或原本 exit code。starttime 不符拒絕發訊號。無 viewer 時也由 events maintenance 偵測/回收。
- worker 本身也記錄 starttime避免 PID 重用誤認存活;啟動 worker 先登記身分,已變 unknown 的 intent 不會稍後重新啟動。
- `make test-runner-jobs`9 個 Python 實測 + 1 個 Rust→Docker 實測通過,新增過期輸出/ack 保護/冪等、64 slots 配額壓力、kill worker/偽造 starttime/自動維護故障注入。workspace 375 passed、4 ignoredclippy all targets 通過。
- 仍未完成:脫離 process groupsetsid的程序隔離/回收、根 journal/tombstone 的長期磁碟配額、scope barrier 與原稽核表其他項。P0P3 全範圍保持未結案。
## Agent takeover barrier checkpoint2026-09-10
- Runner 新增 root SQLite agent barrier先停止新 job admission再停止並確認存活 process group 進入 stopped 狀態。accepted/cancelling/unknown 未處理完不回成功。直接 resume/interact 不能繞過暫停release 僅恢復 scope 暫停的工作,不恢復原本手動暫停的工作。
- API takeover 在授予 user lease 前要求 Runner barrier 成功。migration 025 新增中央 agent_mutation_barriers操作 journal admission 與暫停共用 per-agent advisory transaction lock中央仍有 accepted/unknown 操作就拒絕宣稱接管完成。
- takeover/release 另以 per-agent advisory lock 防止互相交錯release 先釋放 user lease、恢復 Runner再打開中央 admission 與原 run。
- FakeSandbox 也模擬相同 agent job admission/status barrier不靠無條件成功掩蓋測試。
- 驗證10 個 Python Runner 實測 + 1 個 Rust→Docker 實測通過;包含 A 暫停、B 繼續、新工作/直接 resume 拒絕、原本手動暫停保持。SQLx 新增 admission 與 pause race、跨 bot、unknown 保留測試。workspace 376 passed、4 ignoredclippy all targets 通過。
- 未完成display/整機 scope barrier、完整 epoch token 與 stale ref/grant 恢復、外部 HTTP read-back reconciliation、脫離 process group 的 OS 隔離。此段只完成 agent/job 與中央受記錄 mutation admission 的接線,不能視為 O27/T24/T42/T43 全部驗收。
## HTTP MCP client 搬入 Computer checkpoint2026-09-10
- API `McpHub` 只保留授權目錄/config/schema移除 API 內的 rmcp HTTP transport 與 stdio client feature實際探索/呼叫透過 Supervisor→root Runner→Computer 內固定 `lazyboy-controld --mcp-call`。模型呼叫使用當前 bot 的 Computer/generation目錄探索使用該 owner 已運行的 Computer。
- `mcp_*` 需要 Computer readiness但不需要 GUI/viewer。沒有可用 Computer 時連線明確失敗,不回退至 API 主機 HTTP。舊 image 必須更新 controld binary本輪建置了既有 Bookworm controld build stage未替換運行中的 Computer。
- 配置/headers 只從 stdin 傳給 root client錯誤不回傳遠端敏感 body。45 秒 deadline、4 MiB 結果/SSE event 限制、256 MiB process address-space limit、CPU/core dump 限制。`isError` 不記為成功。
- 檢查 rmcp 3.2.0 原始碼發現預設 expired-session 會重送 POST已明確關閉 `reinit_on_expired_session`session expired/response lost 回 unknown不隱式重播 mutation。
- 修正 `npx` pin policy拒絕 latest/next/range/不完整版本與另一參數假冒 pin只採實際執行的 npm package 精確版本,排除 URL/不明 option 形式。這不取代 digest/審核安裝流程。
- 驗證Bookworm release binary 在 disposable、network-none、無 desktop Computer 內跑真實 rmcp SDK + loopback HTTP fixture5 項涵蓋 schema/Unicode call/auth secret canary/isError/session expiry/response lost 單次呼叫/超限結果。另 10 個 Runner tests + 1 個 Rust→Docker test 通過。workspace 376 passed、4 ignored最後 pin policy 2 測試與 clippy all targets 通過frontend 56 passed。
- `make test-runner-jobs` 現在自動透過 image 的 controld build stage 取得相容 binary。可設定 `LAZYBOY_TEST_MCP_IMAGE` 使用已建置的該 stage不直接把開發主機較新 glibc binary 當成 Computer 驗收。
- 仍未完成generic stdio loader/版本 pin instance、常駐 MCP pool、legacy SSE transport、per-agent/account grants/broker、MCP 本地持久 journal/artifact 與全面管理 audit、schema readiness 自動恢復與完整 API E2E。P0P3 保持全範圍未結案。
## 通用 archivestdio MCP checkpoint2026-09-10
- 新增 `/api/bots/{id}/tools/install`,從 Computer 內既有 workspace archive 讀取、驗證 digest、解包與探索 MCP schema。migration 026 保存 manifest先記錄 installing intent完成後才 ready沒有 API 主機下載/解包 task artifact。
- 新增 `computer_mcp` list/discover/call依 actor、bot、當前 Computer、ready binding、manifest version/digest 檢查。SDK 握手及工具呼叫真正使用 Computer 內 stdio child不只對固定 echo script 丟單行 JSON。
- 安裝器拒絕 symlink/hardlink/特殊檔/路徑逃逸、錯 digest、超限展開、未知 manifest 權限/hook 欄位;不可把同版本換成另一 manifest。套件檔案/權限在每次執行前重新驗證。
- 每個 binding 配獨立 UID/GID、私人 HOME/statesetpriv 清除 supplementary groups 並啟用 no-new-privileges。私有套件程式碼另有 root-owned、僅該 binding group 可讀的唯讀副本;共享 immutable code 不混入私人 state。
- 每呼叫結束清理該 UID 的程序,包含 setsid 與 non-dumpable 子程序。使用 `/proc/status` 的真實 effective UID而非會被 dumpable flag 改變的 `/proc` inode owner訊號使用 pidfd 避免 PID 重用。
- Root package revoke 與既有 revoke/remove API 接線;先關 admission不能確認在途 call drain 時回報 pending。版本/hash 與 root binding 不符拒絕執行,避免 legacy rollback 誤用另一版 code。未執行的參數/授權拒絕和真正未知效果分開,避免簡單錯誤污染 unknown ledger。
- 補安裝配額在寫檔前檢查、獨立安裝鎖、同 manifest/binding 遺留 staging 清理與 failed DB commit 後的 hash/permission 驗證恢復。UID 先 durable reserve 再配置檔案 owner不重用失敗安裝的 UID。
- 驗證377 workspace tests passed、4 ignoredSQLx 新增 owner/binding/current-Computer/revoke 可見性測試。10 Runner + 5 HTTP MCP + 4 archive/stdio + 1 Rust Docker = 20 個容器測試通過覆蓋未知欄位、digest、symlink/hardlink、路徑逃逸、展開 quota、版本 pin、撤銷、私有 code/state 與 non-dumpable/setsid 回收。frontend 56 passed、clippy all targets 通過。
- API contract 與目前限制見 [tool-packages.md](tool-packages.md)。仍缺完整 V1 manifest遠端 URL通用 UI、第三方 package fixture、常駐 pool、network/account grants/broker、完整 OS filesystem/network sandbox、state 磁碟 quota/長期 GC、通用重新授權與 rollback、全 API 安裝 E2E。這些仍是 P0P3 未完成範圍,不以本輪 fixture 取代全部驗收。
## 通用套件管理表單 checkpoint2026-09-10
- Tool Manager 新增 Computer workspace archive 路徑與 JSON manifest 安裝表單,顯示安裝回傳 schemas錯誤補中英文文案。切換 bot 重新建立 pane避免舊 bot 的操作結果帶到新 bot。
- 套件清單只顯示當前 Computer 的 bindingsAPI 明確回傳 archive runtime 類型;通用套件不再顯示 echo 呼叫legacy rollback。舊 rollback API 在修改資料前拒絕 archive避免中央版本變更而 root runtime 不匹配。
- revokedinstalling bindings 仍可撤銷或移除,讓 runtime drain 失敗後能重試。操作失敗也刷新中央狀態;清單讀取錯誤不再無聲吞掉。
- 驗證:前端 56 測試與 production build 通過;新增 SQLx 測試涵蓋 runtime kind、revoked readiness、擁有者與 peer bot 隔離、Computer 切換。
- 尚未完成schemas 的持久管理/重新探索、通用工具手動呼叫 UI、完整 V1 安裝精靈、通用重新授權與 rollback此表單不代表 Tool Manager 全部驗收完成。
## 套件探索與手動操作 checkpoint2026-09-10
- Tool Manager 支援已安裝 archive binding 的 schema 重新探索以及指定工具名稱JSON object 參數的手動呼叫。與模型共用 binding 授權與 Computer 內 MCP SDK 路徑,帶入目前 generationComputer 未 running 不派送。
- 手動呼叫經由共用 operations journal、agent barrier 與 outbox要求 UUID operationId重放回傳原結果payload 不符拒絕,未知效果不重新派送。管理操作的 run_id 為 NULLoutbox 不誤寫不存在的 run_activity。
- 分頁 sessionStorage 僅保存最近操作 ID 與 SHA-256 請求雜湊,不保存工具參數。相同請求重用 ID變更輸入或明確建立新操作才使用新 ID。沒有自動 mutation retry。
- SQLx 管理入口回歸涵蓋 ownerpeer bot 拒絕、派送後結果未知、撤銷後原 ID 仍重放而不派送、payload mismatch、schema 探索拒絕 revoked binding以及無 run 的 outbox 完成。這不是第三方 MCP真實 API transport 全套 E2E 的替代。
- 本輪驗證:擴充的 SQLx 管理入口測試通過(含 stopped Computer 留有 provider_ref 的拒絕案例operations 8 項、frontend 56 項、production build 與 API clippy all targets 通過。完整 P0P3 仍未結案。
## 套件重新授權 checkpoint2026-09-10
- migration 027 改為 package/bot 的 live binding partial unique index撤銷移除的 binding 保留歷史,不再因重新安裝而復活舊 ID。
- Archive install 支援明確 `reauthorize: true`UI 有對應選項。先確認全部舊 bindings 的 root runtime 已 drain才 durable reserve 新 binding新的 root 安裝分配不同 UID私人 state。一般重試不會默默授予新權限。
- package advisory lock 加 binding row lock序列化安裝重試與並行撤銷已存在新 installingready intent 時,重試沿用該 ID不重建權限。舊 sample installer 也配合 partial unique index 保留撤銷識別碼。
- Root 對不存在的 binding 撤銷改成冪等成功,適用重新建立的 Computer存在但屬於另一 bot 的 binding 仍拒絕。FakeSandbox 沒有已安裝的套件程序,因此對 absent binding 使用相同語義。
- SQLx 覆蓋未明確重新授權拒絕、新 intent 與舊 revoked row 同時保留、重試不增加第三個 binding。容器 suite 驗證新 UID私人 state、舊 ID 永不復活、其他 bot 不能撤銷。
- 本輪未完成通用 rollback、帳戶 grant/broker、長期 revoked bindingstate GC、全 V1 manifestP0P3 保持未結案。
- 驗證workspace 378 passed、4 ignored其中 Docker transport 另於 disposable gate 執行10 Runner + 5 HTTP MCP + 4 archive/stdio + 1 Rust Docker 全通過fixtures 已清除。frontend 56 passed、production build、workspace clippy all targets 與 diff check 通過。
## Runner 版本切換 checkpoint2026-09-10
- 新增 root `package_switch`:只切換同 package 的已安裝且完整 manifest/hash 相符目標。切換前重驗 cache、entrypoint 與檔案權限,維持原 binding UID私人 state。
- 與 install 共用 binding lock、與執行中 MCP call 共用 UID lock忙碌時回報 PACKAGE_BUSY不殺死已接受呼叫。私有 code 以 stagingrename 換版DB 最終 compare-and-swap 不覆寫並行 revoke。
- `package_switches` 在 binding 版本變更的同一 SQLite transaction 記錄 transition IDpayload hashreceipt。重試回傳既有 receipt不同 payload 拒絕。回滾後再收到舊升級請求,不會重新升級。
- 修正原 install 最終 unconditional ready 寫入:現在檢查 package key 與目前狀態,不能把並行撤銷的 binding 復活。
- 容器測試新增真實 stdio 延遲呼叫private code 升級與回滾、同 UID/state 保留、另一 binding 不受影響、busy、重放與 mismatch、revoked 拒絕。root transition journal 目前上限 1024長期 retention 待補。
- 中央 durable transition intent、API/UI rollback、schema registry 原子更新尚未接線;此 checkpoint 只證明 Runner 切換,不代表全套版本管理完成。
- 驗證10 Runner + 5 HTTP MCP + 5 archive/stdio + 1 Rust Docker共 21 項 disposable Computer 測試通過測試容器已清除diff check 通過。
## 中央版本切換/回滾 checkpoint2026-09-10
- migration 028 新增 durable package_transitions、schemas 與 pending/cancelling 排他性live binding unique index 含 switching/retiring安裝器不會繞過切換中的 reservation。
- `/api/bots/{bot}/tools/{binding}/switch` 與 UI 支援指定已安裝目標版本、沿用 operation ID 恢復 pending。轉換前關閉參與 bindings 的中央 admissionroot package_retire 等現有 call 完成,不中斷它;接著 root switch 與驗證 target schemas。
- 最終 transaction 同時更新 source binding 的 package pointer、ready、目標旧 binding revoked 與 schemas/completed receipt。重放已完成的升級請求不會覆蓋後來的回滾。
- 撤銷/移除任一參與 binding 會關閉全體 admission 並取消 transitionruntime cleanup 未確認前保留 cancelling阻擋新安裝。取消可重試不復活舊 ID。
- 新 transition 使用 agent-barrier advisory lockpaused 拒絕。takeover 的 unresolved-effects 查詢現在包含 pending/cancelling transitions避免切換仍在途卻授予人類 lease。
- SQLx 測试覆蓋 reservation/retry、peer bot 不受影響、generation mismatch rollback、ready/schema atomic completion、舊 receipt 重放、取消與 takeover 邊界。完成 boundary 以已驗證 runtime result 驅動;真實 runtime 由獨立 Docker gate 驗證,仍不是完整 HTTP API→Supervisor→Computer E2E。
- 跨 generation 的 pending transition 目前需明確撤銷清理後重建;完整 account/schema grant registry、常駐 pool、長期 transition/state GC 仍待補。P0P3 全範圍保持未結案。
- 驗證workspace 379 passed、4 ignored最後 takeover 整合後 API 170 passed、3 ignored。21 項 disposable Computer gate 全通過fixtures 已清除frontend 56 passed、production build、workspace clippy all targets 與 diff check 通過。
## 版本切換跨 generation readback2026-09-10
- 新增 root 唯讀 package_transition_status在 install/call 鎖下驗證當前 binding 的實際 package bytes再回傳 request-hash 相符的 receipt 是否存在與當前版本/digest。
- API 遇到同 Computer 新 generation 時先 read back沒有 receipt 必須仍為來源版本,有 receipt 必須仍為目標版本。符合後以目前 Computer generationpending 狀態 CAS 更新,再走原本冪等 retire/switch/discovery/complete 流程。
- 舊 receipt 不代表目前仍在該版本:後來已回滾的 binding 會被拒絕恢復舊升級。無 root binding、bytes/receipt 不符、無法聯絡 Runner 都不更新 generation。
- Docker suite 實測 root readback 未完成/已完成/已被回滾取代三態,跨 identity generation 讀取仍保留原 receipt 驗證。SQLx 驗證讀回失敗不更新 generation判定測試涵蓋有效分支、不同 package、missing 欄位與 receipt/current-version 矛盾。
- 此輪沒有宣稱實際 container restart完整 HTTP API transport E2E 已完成root store 遺失的 recreate 仍需撤銷清理重新安裝state 搬移與持久性驗收仍待補。
- 本輪驗證21 項 disposable Computer gate、2 項 transition/recovery 測試與 API clippy all targets 通過測試容器已清除diff check 通過。
## 實際 Computer restart gate2026-09-10
- `make test-runner-jobs` 現在建立私人套件、切換版本與私人 state執行真正的 `docker restart`,再從新程序/新 identity generation 驗證 root receipt、當前 code/digest、同 UID 與原 state 計數。
- 重啟後驗證 completed 與尚未派送的 transition readback實際回滾再重放舊升級 receipt確認沒有重新升級或重置私人 state。測試只使用 gate 自行建立的容器。
- 驗證:既有 21 項容器測試加 1 個兩階段實際 restart scenario 全部通過fixtures 清除、diff check 通過。這不是 container remove/recreate也不取代完整 HTTP API→Supervisor→Computer E2E。
- 下一個已確認缺口:`DockerHost::provision` 目前只有 home bind mount`/var/lib/lazyboy-runner`、package cache/private exec/state 還在 container writable layer。需要補 root-owned 持久 mount 與既有容器遷移,才能宣稱 recreate 保留 registry套件私人 state目前尚未完成不可把 restart 成功當成 recreate 證據。
## 新 Computer 的 runtime 持久儲存2026-09-10
- provision 新增 DATA_DIR/runtime/{homeKey} 下四個 root-owned bind mountsRunner含 SQLite/outbox/private cache、共享 immutable package cache、private executable copies、私人 tool state。host runtime/key parent 0700不放在 task home 內。
- 目錄建立拒絕 symlink、非 root owner、group/world writable 路徑;再次 provision 保留既有內容。沒有 HOST_DATA_DIR 時使用絕對 bind source修正預設相對 data dir 的 Docker bind path。
- 自動替換既有 Computer 前比對全部 runtime mount 的 source/destination未遷移或指向其他資料位置時拒絕直接 destroy。完整舊容器資料搬移仍待實作此時保留原容器不冒充已遷移。
- gate 使用獨立 temporary bind sources真正 docker rm 後重新建立不同 container ID再驗證 package receipt、code、UID/private state 與 rollback。root Runner source 和資料從 mounts 保留,只有 image binary測試程式重新提供。cleanup 先清除容器,再刪 host fixture 目錄。
- 驗證runtime storage Rust test、21 項既有容器測試restartremove/recreate scenarios 通過Supervisor clippy all targets 與 diff check 通過。此驗證不等於完整 API provisioning transport E2E 或舊容器自動遷移驗收。
## 舊 writable-layer runtime 遷移2026-09-10
- 舊容器替換移除前Supervisor 持 per-home lifecycle file lock停止來源、串流匯出四個 Docker archives、在 root-only staging 解包。全程不在 Supervisor 執行套件shellPythonRust tar loader 保留 owner/mode 與安全的連結語義。
- 驗證拒絕 traversal、重複成員、未宣告父目錄、特殊檔、非 root-owned/writable root每 archive 8 GiB100,000 entries。所有檔案/目錄 fsync保存 prepared/published marker 與內容/metadata fingerprints再分目錄 rename部分發布可重試不覆寫非空目的地。
- 發布後核對完整快照,重試也不僅信任 marker。來源在 snapshot 後重新運行、目標被更改、mount/home source 不一致時拒絕移除來源。遷移中的舊容器不能被另一 wake/provision 繞過 lifecycle lock 重新啟動。
- 修正 create-name-conflict 原本無條件刪除同名容器、destroy 忽略移除失敗。未管理的容器拒絕刪除;公開 destroy 也會先保留 legacy runtime而不是只有 image replacement 才遷移。
- 真實 gate 從沒有 runtime mounts 的舊容器開始,先驗證目的地 sentinel 不被覆寫,完成 migration再注入 partial-publish 狀態與 snapshot tamper確認可恢復拒絕損毀來源仍保留。也實测 wake 阻擋與外來同名容器保留。最後刪除舊容器、建立新的 persistent-mount container驗證 package/UID/state/receipt/rollback。
- 此處驗證的是 Supervisor migration 與真實 Docker archives不取代完整 HTTP API→Supervisor→Computer 操作 E2E亦不宣稱未解決的 job generation reconcile、account broker、viewer完整 P0P3 已完成。
- 驗證workspace 382 passed、5 ignoredSupervisor 2 個 Docker-only 測試在 gate 另跑);既有 21 項容器測試加 restart、legacy migrationpartial publishcollision、remove/recreate 情境通過。最終 workspace clippy all targets、diff check 及 `lazyboy/supervisor:plan-test` distroless image 建置通過。所有 fixture 容器與暫存資料均清除,候選映像未部署。
## Computer generation 與移除失敗處理2026-09-10
- Docker Sandbox 的 DELETE 現在檢查 HTTP statusSupervisor 拒絕遷移移除時不再回報成功。localhost HTTP fixture 覆蓋 204、409、500。
- API restart不健康容器替換只在 destroy 確認後,以同一資料庫交易清除 provider租約、增加 generation、中斷舊 generation 的活動工作。stop 失敗不當成移除證據destroy 失敗或回應逾時保留 provider、generation 與 job 狀態,標記 error 供後續核對。
- 交易鎖住 Computer row 並比對原 providergeneration拒絕過期完成回應provider 遺失且仍有活動工作時拒絕憑空中斷。替換完成後重新讀取 Computer避免 provision 傳入已移除的 provider。
- bootresume 共用 provider 發布交易:新 provider 增加 generation、清除舊租約並中斷舊工作同容器恢復保留 generation。涵蓋遺失 destroy 回應後,下一次 provision 找到新容器的情境。
- SQLx 測試覆蓋失敗保留、成功中斷、terminal新 generation 工作保留、重複過期結果拒絕、無 provider 活動工作拒絕,以及 provider 替換原容器恢復。workspace 384 passed、5 ignoredworkspace clippy all targets 通過。未將此視為完整跨服務故障注入 E2E 或全部 P0P3 驗收完成。
## 閒置回收與工作 admission2026-09-10
- 修正 busy query 失敗時誤認閒置的 fail-open資料庫取得查詢失敗一律禁止回收。accepted/unknown operations 與 pending/cancelling package transitions 也列入活性判斷。
- pause長時間 parked stop 共用交易 helper持 Computer row lock 後重新核對 provider、generation、state 與 idle cutoff再檢查工作。Supervisor lifecycle 回應有 30 秒上限,失敗/逾時不發布假成功狀態;沒有 provider 也不憑空宣稱已停止。
- job admission 使用同一 row lock重新檢查 running 狀態,防止等待回收交易後仍接受工作。這不代表所有 viewer、MCP admission、GUI lease 的 lifecycle race 已完成驗收。
- 新 SQLxlocalhost HTTP fixture 驗證 unknown operation 保活、stop 409 不改狀態、updated_at 改變拒絕舊快照、成功停止、DB query error 保守拒絕admission 測試涵蓋 suspended 拒絕及與 parking row lock 的併發等待。API suite 173 passed、3 ignoredAPI clippy all targets 與 diff check 通過。
## Operation套件換版與閒置回收 admission2026-09-10
- Operation intent 交易現在更新 Computer 活躍時間,取得與 parking 相同的 row lock並與 accepted ledger 一起 commit既有 operation replay 不刷新活躍時間,也不重播效果。沒有 Computer 的操作仍可使用 NULL journal。
- 新 package transition 在 agent barrier 後鎖定 Computer重新檢查 runninggenerationprovider才修改 binding 狀態並寫 pending intent防止讀取 running 後、容器已被暫停仍建立換版。
- SQLx 測試實際持 parking row lock確認 operation admission 等待intent INSERT constraint failure 會回滾活躍時間。換版測試在等待期間把 Computer 改為 suspended確認拒絕且沒有建立 transition恢復 running 後既有換版/取消測試仍通過。
- 驗證API 174 passed、3 ignored新增換版併發測試通過API clippy all targets、diff check 通過。完整 HTTP API→Supervisor→Computer lifecycle 故障注入、viewer 與其他資源活性仍屬未完成範圍。
## API 中斷後的 boot attempt 恢復2026-09-10
- migration 029 新增 boot_attemptboot_started_at 與部分索引,替既有 booting 記錄以 updated_at 補起始時間。API 每次 claim booting 產生獨立 UUID。
- Runner reconciliation loop 回收超過 3 分鐘的 boot attempt正常 provision 120 秒workspace setup 15 秒)。只標記 error 並清除 attempt不清除 provider、不增加 generation、不改 job 結果;後續正常 provision 由 Supervisor 核對實際容器。
- boot success 與 mark_boot_error 都比對 attempt新一次啟動開始後舊成功失敗回應不再能覆蓋它。stopgeneration retirement 清除舊 attemptresume 必須符合無啟動 attempt 的狀態。
- SQLx 測試驗證未逾期不回收、逾期保留 provider/generation/unknown job、新 attempt 拒絕舊結果,以及成功後清除 metadata。API suite 175 passed、3 ignoredAPI clippy all targets 通過。此證據涵蓋資料庫恢復與 fence不冒充 API process kill 的完整 HTTP 故障注入驗收。
## 原生 stat_file2026-09-10
- 新增 agent-facing stat_file schemadispatch沿用 Team bot workspaceshared 路徑授權;列入 native sandbox routingtext-only 模型可用且不需要 GUI。SandboxProvider 提供明確 unsupported fallbackDocker provider 接 Supervisor `/computers/{id}/files/stat`
- metadata 在 Computer 內的 descriptor-relative helper 讀取;不讀取內容、不追蹤最終 symlink父目錄仍 O_NOFOLLOW。輸出 path、file/dir/symlink/special、size、modemodifiedNs 使用字串避免 JavaScript 浮點數失真;不回傳 symlink 的外部目標。
- Python fixture 覆蓋 1 TiB sparse file、FIFO 不阻塞、symlink、父目錄 symlink 越界、traversal、缺檔與 root directory6 項檔案測試通過。Rust 真實 Docker file gate 加入 stat kindsizetimestamp 檢查。
- workspace 387 passed、5 ignoredworkspace clippy all targets 通過。此項不取代尚缺的 patch/move/search、讀取分頁串流也不宣稱完整 API HTTP 檔案操作 E2E 已完成。
- 最終 Docker gate 通過:既有 RunnerHTTP MCPpackage fixtures、實際 restart、legacy migration部分發布恢復名稱衝突保留、remove/recreate以及含 stat 的真實檔案 CAS雙向 execfixture 容器清除完成,未部署候選映像。
## 原生 patch_file2026-09-10
- 新增 patch_file schemanative routingagent workspace dispatch透過 SandboxProvider 與 Supervisor `/computers/{id}/files/patch` 在 Computer 內修改API 不下載原檔執行 read-modify-write。操作接入既有中央 operation ledgerbarriertransport 失聯或非確定回應標為 UNKNOWN_EFFECT不自動重播。
- 支援 offsetdeleteBytescontentBase64 的 byte splice必填小寫 SHA-256 expectedHash。只修改既有 regular file要求合法範圍原檔及結果限制 8 MiB保留 mode。同 directory flock 內比對 hash、組成結果、temporary file fsyncatomic replacedirectory fsync最後讀回比對 hash回傳 sizesha256verified。
- helper 拒絕未知 request fields、負數bool offsets、越界、缺檔、symlink8 項原生檔案測試通過,包含二進位 patch、權限保留、失敗原檔不變、8 個並行 patch 僅一成功。真實 Docker file gate 已加入 patchstale-hash conflict 檢查。
- 尚未實作 move/search、byte cursor大型串流以及檔案變更的 Computer 本地 durable journal中央 ledger 不冒充本地 journal 驗收。
- 最終驗證workspace 387 passed、5 ignored8 項檔案 fixture、含 patch 的真實 Docker gateRunnerMCPrestartmigrationremove-recreatenative files與 workspace clippy all targets 通過。fixture 容器清除,未部署。
## 原生 move_file2026-09-10
- 新增 move_file schemanative routingoperation ledger dispatch來源與 destination 各自經 Team bot workspaceshared 路徑授權。透過 SandboxProvider 與 Supervisor `/computers/{id}/files/move` 執行API 不搬運檔案 bytes。
- 必填 source expectedHash 與 expectedDestinationHash空字串表示目的地必須不存在。Computer helper 以 descriptor-relative O_NOFOLLOW 開啟兩端目錄,依 device/inode 固定順序取得 flock重複目錄只鎖一次檢查 regular file/hash 後移動。目的地不存在使用 Linux renameat2 NOREPLACE已存在且 hash 相符才 atomic replace之後同步兩個目錄並讀回目的地 hash確認來源消失。
- 保留 inodemodebytes拒絕同一檔案hardlink alias、symlink、越界與未知欄位。此版來源及既有目的地核對上限 8 MiB父目錄須存在跨 filesystem 不使用非原子 copy fallback。原生 searchbyte paging大型串流與本地 file journal 仍待完成。
- 10 項 Python file fixture 通過,包含雙端 conflict 原檔保留、權限、反向跨目錄無死鎖、同一目的地僅一成功Docker native gate 增加真實移動來源消失bytes 驗證及移回。
- 最終驗證workspace 387 passed、5 ignored10 項原生 file fixture、含 move 的真實 Docker gate、workspace clippy all targets 通過。fixture 容器均清除,未部署。
## 原生 search_files2026-09-10
- 新增 search_files schemanative routingworkspace dispatch透過 SandboxProvider 與 Supervisor `/computers/{id}/files/search` 在 Computer 執行 UTF-8 literal search。API 不下載整棵檔案樹,無 shell、regex 或 GUI 依賴。
- descriptor-relative DFS、O_NOFOLLOW、不追蹤 symlink最多 32 層4096 entries16 MiB 讀取;單檔上限 1 MiB、最多 100 matches、序列化 match 總量 512 KiB。NUL無效 UTF-8、特殊檔、過大、讀取時改變、過長路徑與無權限檔案均計入 skippedtruncatedlimitReasoncomplete 明示搜尋覆蓋範圍,不能將部分結果當作完整無命中。
- 每個 match 提供 path、byteOffset、previewOffset、可讀 preview 與 byte-safe previewBase64純 UTF-8 query 最多 256 bytesmaxResults 預設 20。根路徑缺檔回報失敗。
- 13 項檔案 fixture 通過,包括 Unicode byte offsets、regex 符號當字面值、binary/symlink/FIFO/oversize 略過、entry/byte/result/output limits以及特殊長檔名的 JSON 大小限制。Docker native gate 新增真實容器內搜尋與 Unicode offset 驗證。
- workspace 387 passed、5 ignoredworkspace clippy all targets 與最終 Supervisor clippy 通過;完整大型檔案 byte paging串流、Computer 本地 file journal 及全 API HTTP E2E 尚未完成。
- 最終 Docker gate 通過RunnerHTTP MCPpackagesrestartlegacy migrationremove-recreate含 search 的 native file gate。fixture 容器清除完成,未部署。
## byte rangecontinuation 讀取2026-09-10
- 新增 read_file_bytestext 與 binary page 分開offsetBytesmaxBytesexpectedVersion最大 64 KiB回傳 base64、nextOffset、EOF、總 size、chunkSha256。chunk hash 明確不冒充全檔 hashAPI 不先載入整份大檔。
- Computer 使用 O_NOFOLLOWregular-file 檢查及 pread。version v1 由 device/inode/size/mtime/ctime 建立offset>0 必須帶版本讀前讀後核對拒絕檔案被替換或修改後拼接不同版本。offset=size 可取得空 EOFoffset>size、零長度超量非法版本回報錯誤。
- Supervisor `/computers/{id}/files/read-range` 與 Docker Sandbox 保留 FILE_NOT_FOUND、PERMISSION_DENIED、INVALID_ARGUMENT、CONFLICT、SIZE_LIMIT 等錯誤類別read-only transport 失敗不偽裝空內容成功。
- 15 項原生檔案 fixture 通過包含二進位分頁重組、EOF、同 bytes 被重新替換時舊版本拒絕、1 TiB sparse file 尾端定位。真實 Docker native gate 增加 first pagetailEOFbytes 驗證,整個 RunnerMCPrestartmigrationremove-recreate gate 通過。
- workspace 387 passed、5 ignoredworkspace clippy all targets 通過。大型 upload/download/attachment 全串流、directory pagination、Computer 本地 file journal 及完整 API HTTP E2E 仍未完成。
- 額外 localhost HTTP regression 驗證 400403404409413500 保留正確工具錯誤碼;測試與最終 Sandbox clippy 通過。fixture 容器均已清除,未部署。
## 舊 list_files 容量與錯誤修正2026-09-10
- 移除無上限 os.listdirsort改用 scandir最多 4096 entries 與 512 KiB 序列化內容,收齊且確認目錄 mtime/ctime 未變後才輸出與排序。超限/衝突不輸出部分成功清單。
- symlink、FIFO特殊檔不再誤標成 regular file。Supervisor 以 413409 保留 DIRECTORY_LIMITCONFLICTDocker Sandbox 與 agent-facing list_files 傳遞 typed error一般 list failure 也不再使用成功 text outcome。
- 18 項原生檔案 fixture、Sandbox 10 項測試(含 localhost HTTP limit/conflict regression、workspace clippy all targets、diff check 通過。本輪沒有重新聲稱完整 DockerAPI E2E有界拒絕不取代尚未完成的 directory continuation。
## Directory continuation2026-09-10
- 既有 list_files 加入 limit1200cursor透過新的 SandboxProviderSupervisor `/computers/{id}/files/list-page` 取得有界頁面;未指定分頁時保留既有 bounded/sorted list 行為。
- Computer helper 使用經本機 Linux dirent64 header 核對的 64-bit Linux readdir64telldirseekdir cookie。每頁重新開啟 descriptor-relative 目錄並接續 cookie不重掃前面頁面返回 filesystem order、nextCursor、eof 與 version。最多 200 entries512 KiB entry JSON長檔名達輸出上限也提供 continuation。
- 版本綁定路徑、device/inode、目錄 mtime/ctime讀前讀後核對目錄 membership 改變、跨路徑 cursor、非法 token 會拒絕。此版本核對目錄項目,不宣稱各檔案內容的跨頁 snapshot。cursor 是讀取位置資料不充當授權憑證workspace grant 仍逐次核對。
- 21 項原生檔案 fixture 通過4301 entries 全量分頁無重複漏項、cursor replay、目錄變動跨路徑拒絕、空目錄、長檔名輸出限制接續。真實 Docker native gate 驗證跨 helper 程序 continuation 與修改後 conflictRunnerMCPrestartmigrationremove-recreate gate 通過fixture 容器清除。
- Workspace 首輪發現既有 zombie fixture 偶發前提失敗shell 可能在 exec 前先回收子程序。改用明確 fork確認 /proc zombie 後才通知測試,最後透過 stdin 關閉要求 parent waitpid 清理;移除固定 200 ms 等待與不確定 shell 行為。
- Directory continuation 不取代大型 upload/download/attachment 全串流與 Computer 本地 file journal完整 API HTTP E2E 與其餘 P0P3 仍未完成。
- 最終重跑workspace 389 passed、5 ignored21 項 file fixtures、真實 Docker gate、workspace clippy all targets、diff check 通過。未部署候選映像或修改正式 Team 資料。
## 唯讀檔案 typed errors 與假成功修正2026-09-10
- 修正 legacy read_filestat_file 在 transport 失敗與路徑驗證失敗時仍回成功 text outcome新增共用 native_file_failure保留 FILE_NOT_FOUNDPERMISSION_DENIEDINVALID_ARGUMENTSIZE_LIMITDIRECTORY_LIMITCONFLICT 等分類。listsearch 也沿用這些分類。
- Computer helper 對 read/stat/list/search/read-range/list-page 分類已知唯讀錯誤,保留現有 conflict/directory-limit 標記。Supervisor 唯讀 endpoints 共用 status mapperDocker Sandbox 的 read/stat/list 保留 HTTP error 類別,停止讀取無用途的錯誤 bodyfile_operation 路徑拒絕帶 INVALID_ARGUMENT。
- 未把此分類直接套用到可能已產生副作用的 write/patch/move避免將回應遺失readback 失敗誤判成確定未執行。
- 23 項 helper fixture 通過包含缺檔、oversize、非法路徑與實際降權程序讀取 permission-denied失敗無 bytes 輸出。localhost HTTP fixture 覆蓋 read/stat/list/range 各 400/403/404/409/413/500API outcome regression 確認 error_code 非空。
- 最終 workspace 390 passed、5 ignored23 項 file fixtures、workspace clippy all targets、diff check 通過。本輪未重跑整個 Docker gate不冒充完整 API HTTP E2Emutation 磁碟滿/本地 journal全串流與其餘 P0P3 仍有必做項。
## 寫入回應未知與 fsync 失敗邊界2026-09-10
- Docker write_file_checked 對 request response loss一般 server failure 明示 UNKNOWN_EFFECT409 保持 CONFLICT400413 保留確定的 INVALID_ARGUMENTSIZE_LIMIT。API write_file 不再將這些不確定情況寫成普通 FILE_WRITE_FAILED而由既有 operation ledger 保留 unknown禁止自動重播。
- 新 helper 故障注入測試在 temporary-file fsync 與 rename 後 directory fsync 分別注入 ENOSPC前者原檔保持不變後者新內容已可见但 helper 失敗;兩者都清除 temporary。這證明 transport failure 不能推論未寫入;測試是 fsync fault injection不冒充真實磁碟填滿測試。
- localhost HTTP fixture 覆蓋 204、400、409、413、500 及直接關閉連線確認失聯500 保留 UNKNOWN_EFFECT。
- 驗證24 項 file fixtures、API 176 passed3 ignored、Sandbox 11 passed、workspace clippy all targets 與 diff check 通過。本輪未重新宣稱完整 Docker gateComputer 本地 file journal未知結果 readback recovery全串流與其餘 P0P3 仍待完成。
## Computer root file journal backend2026-09-10
- 新增 runner_files.py隨 trusted Runner bootstrap 提供固定 computer_files helper source。root SQLite file_operations 以 computer/bot/generation/operation ID 隔離,先 FULL/WAL commit accepted intent 才以 UID/GID 1000、清空 supplementary groups環境與資源限制執行 write/patch/move。
- ledger 保存 action/path/precondition/desired-or-replacement hashes、payload digest 與有界 receipt不保存 task contents。相同 IDpayload 只回放結果payload mismatch 拒絕acceptedunknown 不重播。file_status 僅讀取同 scope 歷史結果。全域 1024 歷史紀錄上限,額滿拒絕新效果但保留回放;長期 retention公平 quota 仍待補。
- file_mutate 與 root agent barrier admission 同 SQLite transaction 序列化pause acknowledgement 會等待檔案 accepted/unknown 清空,無法確認時 BARRIER_INCOMPLETE不假接管。root helper 本身不取代 API workspace assignment/grant 檢查。
- write 現在也在 fsync/rename 後讀回 hash與 patch/move 一樣提供 verified receipt。RPC stdin 上限調成有界 16 MiB容納既有 8 MiB file write payload這不是大型檔案 streaming 實作。
- 六項真實容器 root journal 測試receipt重送不覆蓋後續修改、wrong bot/generation 隔離與 UID/metadata 防讀、patch/move/conflict、未完成 intent 不重播且阻擋 pause、journal admission readonly failure 不啟動 child、quota 拒絕新操作但保留 replay以及 SQLite receipt commit 注入失敗後保留 unknown人類後續修改。部分情境合併在同一測試。
- 歷史 root receipt 在實際 restart、legacy runtime migration、remove/recreate 後仍可按原 scope 查得。這是持久資料驗證,不冒充新 generation 的 API recovery/readback。
- 驗證workspace 391 passed、5 ignored24 項 file helper tests、6 項 root file journal tests、Runner/MCP/package/restart/migration/recreate/native file Docker gate、workspace clippy all targets、diff check 通過。fixture 容器均清除。
- **仍未完成**:正式 API write/patch/move 路徑尚未切換到 root journalfile outbox、中央 receipt reconcile、unknown readback recovery跨 generation 驗證尚待接線。此 backend 不列為全案或完整 file journal E2E 完成。
## Agent file journal HTTP 接線與 operation ID 並行修正2026-09-10
- Agent `write_file``patch_file``move_file` 經 Sandbox SDK → Supervisor `/files/mutate` → Computer root file journal要求 bot 與正 generation未知 transportreceipt 結果保留 UNKNOWN_EFFECT。未支援此能力的 provider 明確拒絕,不退回未記錄的寫入。
- API central intent 仍先於 HTTP 持久提交root operation ID 使用本次原始 ID 的 SHA-256保留 root identity scope。write receipt 額外核對 pathsizeSHA-256符合才登錄 artifact。
- 修正共用 `last_operation_id` 的競爭file mutation 與 artifact 使用 dispatch 區域變數一路傳遞不受另一個工具修改共用顯示欄位影響。SQLx 測試以 admission advisory lock 建立交錯,驗證正確 root ID、HTTP 發送前 accepted、重送不再 HTTP以及 artifact 對應 ID。
- 真實 Docker gate 已包含 SDK → 同一 Supervisor HTTP handler/middleware → root Runnerreceipt replay 不覆蓋後續人類修改、payload mismatch、CAS conflict、root pause 拒絕新操作;完整 RunnerfileMCPpackagerestartmigrationrecreate gate 通過fixture 清除。
- API→mock Supervisor contract 與上述真實 transport gate 是兩段證據,尚不列為完整 API HTTP→Computer E2E。其他 legacy 寫入upload 路徑、file outbox中央 reconcileunknown readback跨 generation recovery、全串流及其餘 P0P3 仍必須完成。
- 最終驗證API 177 passed3 ignored、workspace Clippy all targets`-D warnings`、format 與 diff check 通過Docker gate 含新增真實 file HTTP 測試通過。
## Computer file outbox2026-09-10
- 新增 root SQLite `file_outbox`accepted event 與 intent 同交易result event 與 receipt 同交易;只存 operation reference、identity、狀態與 helper receipt不存任務檔案內容。
- Runner `file_events` 支援未確認事件重送,每批至多 100 筆256 KiB event JSON`ack_file_events` 按完整 computer/bot/generation scope 刪除已確認事件,重複 ack 可接受,其他 bot/generation 無法讀取或刪除。確認事件不刪除 operation receipt因此不能使舊操作重新執行。
- 新增兩項真實 Computer 測試涵蓋 redelivery、scope isolation、ack 去重、receipt replay以及 outbox INSERT 故障intent transaction rollback 不啟動修改receipt transaction rollback 在修改已發生後保留 unknownaccepted event。
- **仍待完成**API 持久保存中央 operation→root operationprovidergeneration mapping、中央 file event dedupackreceipt reconcile、unknown readback recovery。現有 job event loop 尚不消費 file outbox。升級前既有 file receipt 沒有可反推的原始 operation ID不能虛構 backfill event需利用中央 dispatch mapping 與 scoped `file_status` 補查。
- 驗證:完整 Docker gate 通過Runner 10、root file 8、HTTP MCP 5、package 5、實際 restartlegacy migrationremove-recreatenative filefile HTTP兩次 lifecycle verification 均確認未 ack file outbox 與 receipt 保留。fixture 已清除diff check 通過。
## 中央 file dispatch identity mapping2026-09-10
- Migration 030 新增 `computer_file_dispatches`:以中央 operation FK 保存 Computerbotproviderrunner identitygenerationroot operation ID、request hash 及檔案 reference內容 hashsize。write/patch 的 base64 內容不進 DB。
- Agent file mutation 在 HTTP 前先提交 mapping。交易鎖定 Computer 與 bot重查 running、provider/generation、目前 binding、owner/space 與 accepted central intentadapter actor 必須一致。HTTP 使用與 mapping 完全相同的 ComputerRefAdapterContext snapshot。
- Mapping DB error過期 generation 拒絕 mutation不送 HTTP。既有相同 key 僅允許同 payload 與同 provider/generation mapping不覆蓋舊 incarnation 的 recovery 證據。
- SQLx API integration fixture 在 HTTP handler 內查驗 mapping 已持久提交、hash/size/path 對應且不含內容;追加 stale generation 與 DB INSERT trigger fault兩者均驗證 transport request count 不增加。
- 中央 file event 消費、dedup/ack、receipt reconcile 與 unknown readback 尚未接線;此 mapping 是恢復所需持久資訊,不能單獨宣稱斷線恢復完整完成。
- 驗證API 177 passed3 ignored最終 actor guard 後定向 integration test 再通過workspace Clippy all targets 與最終 API Clippy`-D warnings`、format、diff check 通過。本輪未重跑 Docker gate未宣稱完整 API→Computer recovery E2E。
## 中央 file event 同步與 receipt reconcile2026-09-10
- Migration 031 新增 scoped `computer_file_events` 去重表;背景 Runner loop 依持久 dispatch mapping 輪詢 `file_events`,中央 transaction commit 後才送 `ack_file_events`,不重送檔案 mutation。
- 每筆事件核對 Computer/provider/generation/bot/root operation identity鎖定 lifecycle 與 operation。驗證 receipt pathverifiedhash 格式8 MiB size boundwrite 核對預期內容 hash/sizemove 核對目的地及來源 hashpatch 接受可信任 helper 的核驗 receipt。
- Event、accepted/unknown→receipt 狀態及通知 outbox 同 transaction已知 terminal 結果不被 unknown/舊事件倒退。同 event key 不同內容拒絕,舊 generation錯誤 bot 不 ack。
- 修正活動紀錄去重recovery 通知攜帶獨立 eventKey不能被同 operation 先前的 unknown 訊息吞掉;同 recovery 通知重送仍去重。
- SQLx 測試涵蓋並行重送、亂序terminal 不倒退、錯誤 scope、錯誤 hash/verified、通知 journal 故障整筆回滾;真實 SDK→mock HTTP fixture 確認 ack 前中央結果與事件已持久存在ack HTTP 503 後重送不增事件/通知且不 dispatch mutation。
- 驗證API 181 passed3 ignored最終 recovery Activity 定向測試、workspace Clippy all targets-D warnings、formatdiff check 通過。
- **仍待完成**API→真實 Supervisor→Computer 的整條失聯 E2E、原本 receipt 未提交的 unknown readback、跨 generation 授權恢復、recovery artifact metadata 補登、poll/retention 公平配額與完整 idle outbox 活性。此次證據不涵蓋這些缺項,其餘 P0P3 繼續必做。
## 真實 API dispatcher→Supervisor→Computer file recovery gate2026-09-10
- 新增 opt-in SQLx integration啟動編譯後 Supervisor binary 的實際 router/middleware使用現有隔離 Computer、一次性 PostgreSQL 測試 DB、loopback fault proxy呼叫正式 API `dispatch``sync_events`
- write、patch、move 均先在真實 Computer 完成proxy 讀到 succeeded 後丟棄回應,讓 API 留下 UNKNOWN_EFFECT。直接讀取實際檔案確認效果再寫入模擬後續人類修改中央收到 durable outbox 後恢復成功,同 operation 重送不再發送 mutation HTTP後續檔案內容保留。
- 確認 3 個操作共 6 個事件提交中央並從 root outbox ack 清除。fixture Supervisor 由 guard 在成功或 panic 後 kill/wait臨時 DATA_DIR 清除;只接受 `lazyboy-plan-runner-test-` 容器,不觸碰正式 runtime。
- `make test-runner-jobs` 納入此 gate 並要求明確設定 disposable PostgreSQL `DATABASE_URL`;新增前置檢查與使用說明,缺少 DB 設定時在建立容器前停止。
- 驗證:完整 Docker gate 通過,含 Runner 10root file 8HTTP MCP 5package 5restartmigrationrecreatenative filefile HTTP以及新增三種檔案 mutation 的真實跨程序恢復測試workspace Clippy all targets、formatdiff check 通過,測試容器及測試 Supervisor 已清除。
- 此處入口是正式 API dispatcher非公開 HTTP API/model runroot receipt 未提交的 unknown readback、API/Supervisor/Computer 同時 crash 矩陣、跨 generation recovery、artifact 補登與其餘 P0P3 仍未完成。
## File receipt artifact 補登與 direct/recovery race2026-09-10
- 移除原本只處理 write、忽略 DB error 的 artifact 寫入writepatchmove 的正常回應先驗證可信 receipt再以已持久 dispatch 的 provider/generation/operation scope 登錄 metadata。失敗回 UNKNOWN_EFFECT由 durable outbox 恢復。
- 背景 receipt reconcile 在事件/結果/通知同一 transaction 補登 artifact。operation row lock 序列化正常回應與 recovery新 artifact ID 由完整中央 operation key 的 SHA-256 決定,既有相符 random ID 保留,內容不符拒絕,不忽略錯誤。
- 修正 recovery 先完成時,稍後正常成功回應被判成 unknown僅在同 operation 已有可信 file event、中央 terminal status 與本次結果一致時接受既有提交,不建立第二筆通知。
- SQLx 新增 artifact INSERT 故障後不完成事件/不 ack、通知故障連 artifact 一起 rollback、正常回應與背景 recovery 並行只登錄一筆,及較晚 direct success 沿用已持久結果/通知。
- 真實 dispatcher→Supervisor→Computer 失聯 gate 擴充writepatchmove 恢復後核對 artifact path原操作 hashsize每個 operation 僅一筆;後续人類修改不取代歷史 receipt metadata重送不重新修改檔案。
- artifact immutable snapshotretention全串流、unknown readback、跨 generation 恢復與其餘 P0P3 仍待完成。
- 驗證API 183 passed4 ignored完整 Docker gate含新增 artifact 回復驗證通過workspace Clippy all targets-D warnings、formatdiff check 通過;測試容器清除。最後 direct/recovery completion 修正由完整 API suite 驗證。
## File event 錯誤隔離2026-09-10
- 修正單一 bot 的 eventack error 直接中止整台 Computer 同步:保留錯誤回報與重試需求,仍繼續處理後面的 bot。
- 同一批資料逐事件處理identityreceipt 驗證失敗的事件不提交、不 ack其他有效事件仍持久提交並送確認。批次仍回傳失敗不能把未處理事件冒充已交付。
- 擴充 HTTP fixture在有效 acceptedsucceeded 前插入錯 bot 事件,確認只 ack 正確的兩個 ID再讓 ack 回 HTTP 503確認後面的健康 bot 仍被輪詢,下一次重送不重複中央紀錄。
- 驗證file_operations 6 項 SQLx 測試與 API Clippy all targets-D warnings通過。本輪不冒充完整 Docker gate大量 scope 的輪詢排序timeout 公平性、100 筆壞事件占滿 batch 時的 quarantine、全系統資源配額仍未完成。
## 持久 file poll 排程與 timeout 進度2026-09-10
- Migration 032 新增每 computer/provider/generation/bot 的 poll scope、輪詢時間與租約。dispatch INSERT trigger 同交易建立 scope並 backfill 既有 dispatch不因新操作把同 bot 的順序重設到最前面。
- SQL `FOR UPDATE SKIP LOCKED` 原子取得最久未輪詢 scopeIO 前更新 last_polled。每次同步最多 4 個不同 scope、每個 timeout 2 秒;慢 bot 不會反覆占滿整輪。30 秒租約讓多個 API worker 協調API 中斷後可重新取得;舊 token 不能釋放後來的新租約。
- 每累積 16 個中央已提交事件就送 ack批次結束確認餘數後段 timeout 不必讓前段永遠無法確認。壞事件仍不 ack中央未知結果仍不重播 mutation。
- 新增 SQLx並行 claims 不重複、先前已輪詢 scope 排到其餘 peer 後面、expired lease takeoverstale releasewrong generation真實 SDK HTTP 慢 bot timeout 後健康 peer 繼續,以及 ack 前中央僅完成該 prefix 的分段順序測試。
- 驗證API 185 passed4 ignored、完整 Docker gate 含真實 file recovery 通過;最後分段確認變更後 9 項 file_operations 測試、workspace Clippy all targets-D warnings、formatdiff check 通過。Docker fixture 清除。
- 此輪完成檔案回執輪詢的持久順序與有界等待;過期 scope retention、滿頁壞事件 quarantine、全系統工作CPURAMdisk 公平配額,以及其他 P0P3 仍未完成。
## Root unknown file readback 證據2026-09-10
- `file_status` 新增嚴格 boolean `readback`;只能按既有 identityoperation ID 讀取受保護 metadata 指向的檔案,不能自行提供任意路徑。僅 unknown 操作執行 readback已有 terminal receipt 仍直接回放。
- 新增 UID 1000 fingerprint helperdescriptor-relative/no-follow、regular file、8 MiB 限制、directory shared lock、讀取前後 inode/size/mtime/ctime 及路徑綁定核對,只回傳 hash/size不回傳 task bytes。不可讀symlink超量變為 unavailable不誤認目標已符合。
- Root `file_observations` 每 operation 保留最近一次 metadata-only 觀察write 核對 desiredHashmove 提供來源缺失/目的地 hash 的分開 snapshot。始終 `execution_proven=false`,操作保持 unknown不能把目前相同內容當作原操作的執行證據。patch 缺少完整目標 hashdesired_state_matches 保留 null。
- 真實 root receipt UPDATE trigger fault 後驗證 readback match、不同 bot/generation 拒絕、root 持久觀察、後續人類修改 mismatch、重送仍不改寫檔案。helper 新增 binary/特殊路徑、內容不外洩、symlink 拒絕、1 GiB sparse file 有界拒絕測試。
- 驗證25 項 helper tests、完整 Docker gate含 root file 8 項與 dispatcher 真實恢復、workspace Clippy all targets、diff check 通過fixture 清除。
- **仍待完成**API 對此觀察的查詢恢復決策、patch pre-effect 完整目標 fingerprint、unknown→已核驗目標狀態的明確語義、跨 generation 恢復。此輪是 readback 證據 backend不能列為完整 unknown recovery其餘 P0P3 保持必做。
## 授權 file receipt/readback API2026-09-10
- 新增 `POST /api/bots/{id}/file-operation`body `{ "operationId": "原操作 ID", "readback": true }`;沿用既有登入/路由授權,拒絕未知欄位與空 ID。readback 省略時只取 durable receipt。
- 從中央 dispatch mapping 取得 root operation ID核对 bot user/space、目前 Computer binding/provider/generation/running無匹配回 404不發出 Runner request。查詢使用該 bot/generation 的 `file_status`,不派發 mutation。
- helper 回來後重查 lifecyclebindingowner查詢中已更換 Computer/generation 回 409。25 秒 deadline狀態/code 與 64 KiB 回應限制;原始 stderr 不回傳。
- 回傳 root status 與 evidence不寫中央 operation status不把 desired_state_matches 自動當成 execution_proven。此 API 是只讀核驗入口,尚未接 Tool schemaUI 或明確的恢復決策。
- 驗證SQLxSDK HTTP 測試涵蓋同 owner 查詢、不同 user 無 HTTP、執行中 generation 變更拒絕、舊 generation 事前拒絕、中央 unknown 保留API Clippy all targets-D warnings、formatdiff check 通過。本輪不冒充完整 HTTP登入→Computer E2E。
## Agent file_operation_status 工具2026-09-10
- 新增 `file_operation_status` schemadispatch參數 `targetOperationId`、可選 boolean `readback`;目標 operation ID 與這次查詢 ID 分開,不重新 reserve mutation intent。
- API handler 與 agent 共用 file_status lookup 的 owner/binding/provider/generation 核對與 timeout。列入 native sandbox readiness不需要 GUIvisionrun 指引引導 unknown file result 先查 receipt不自動重做。
- writepatchmove 的失敗回覆新增結構化 operationId/errorCode/message使 agent 能取得實際原操作 ID 執行 readback保留既有 typed error code。
- 擴充 SQLx HTTP fixture以正式工具 dispatch 查詢既有 unknown 操作,確認保留 unknown、execution_proven=false、中央 operation 筆數不增加native routing唯讀判定與 unknown 回覆原 ID 另有測試。
- UI 顯示、明確恢復決策與 unknown→verified 狀態語義、patch 完整目標 fingerprint、跨 generation 恢復及其餘 P0P3 尚未完成。
- 驗證:完整 API 187 passed4 ignored最終 operation ID 回覆定向測試、workspace Clippy all targets 與最終 API Clippy-D warnings、formatdiff check 通過。本輪未重跑真實 Docker gate。
## 活動紀錄 File Evidence UI2026-09-10
- run activity payload 補上經 owner 查詢取得的 botId使既有歷史 tool entry 也能定位目前授權 bot。writepatchmove 活動列有 operationId 時顯示「核對檔案結果」。
- 按鈕只呼叫既有 `POST /api/bots/{botId}/file-operation` 並帶 readback=true不送 mutationretry分別呈現歷史已核驗 receipt、目前符合不同、證據不足、操作不可用generation 變更/查詢失敗。繁中與英文文案均不把 desired_state_matches 當成原操作已成功。
- 顯示 receipt 或觀察的檔案路徑React 文字渲染處理特殊字元。請求期間禁用按鈕,關閉面板 abort 並忽略遲到回應;鍵盤 Enter/Space 不被外層 RunProbe 攔截Escape 仍可關閉。
- 前端測試新增狀態文案真值表與按鈕 API取消late response鍵盤事件驗證。58 項 frontend tests、TypeScript、Vite production build 通過API Clippy all targets 在停用 incremental cache 後通過(初次檢查遇到 rustc incremental ICE並已修正 RunRow 所需 bot_id 欄位。diff check 通過。
- 尚未做瀏覽器視覺/登入→真實 Computer 點擊 E2E明確恢復決策、unknown→verified 語義、patch 完整目標 fingerprint、跨 generation 恢復與其餘 P0P3 仍待完成。
## Patch pre-effect 完整目標 fingerprint2026-09-10
- Computer helper 新增內部 `patch-plan`,沿用相同 byte rangebase64SHA-256 CAS8 MiB 驗證,僅計算完整 patched bytes 的 hash/size不建立暫存檔或修改原檔。
- Root 先提交 accepted intent再執行只讀 plan驗證 plan 的 path/precondition/hash/size將 desiredHash/desiredSize 持久寫入受保護 metadata提交成功才啟動真正 patch。metadata commit failure 不發生 file mutation。
- 真正 patch 再次驗證原檔 hashplan 與 mutation 間的 concurrent edit 回 CONFLICT不換用新 base。final receipt 額外核對 durable desiredHash/desiredSize結果不符保留 unknown。
- 新 patch 的 unknown readback 現在可核對完整目標 hash舊 intent 沒有完整 fingerprint 時仍回證據不足。desired_state_matches 仍不等於 execution_proven不自動清除 unknown。
- helper 測試驗證 plan 唯讀、完整 binary 結果 hash/size、計算後人類修改被 CAS 拒絕;真實 root 測試注入 plan metadata commit fault 與 final receipt commit fault驗證不提前修改、完整 readback、後續人類修改與禁止自動 replay。
- 驗證26 項 helper、9 項 root file、完整 Docker gateRunner/MCP/packages/lifecycle/native file/真實 API dispatcher recovery及 workspace Clippy all targetsCARGO_INCREMENTAL=0-D warnings、diff check 通過fixture 清除。
- 明確恢復決策仍需 child quiescence執行來源等證據不可只靠當前 hash 清除未知效果;跨 generation recovery、完整隔離資源配額與其他 P0P3 尚待完成。
## File child handoff 與 quiescence 證據2026-09-10
- 每個新 file intent 保存 controller PID/start/boot 與 handoff_requiredroot 用 Popen 啟動可信 mutation helper先持久提交 child identity才傳送交接與 payload。plan-only helper 不修改檔案。
- Helper 在開啟父目錄/建立路徑/修改 bytes 前,要求完整 handoff、payload byte length 與 SHA-256missing/partial/extra payload 全部拒絕。root 中斷傳輸時不能把截斷但仍合法的 base64 當成完整檔案。
- child identity commit failure 會 kill/wait 尚未獲准的 helper不發生檔案 mutationtimeout例外清理同樣回收 owned child。已接受但結果未知的操作仍禁止 replay。
- Unknown readback 新增 helper_quiescent相同 boot 下 PID/start 相符且存活回 false已退出zombie原 PID 已被其他 start 重用回 true沒有舊 handoff 證據、無法讀取程序資料、boot/namespace 不同回 null。不同 namespace 不足以證明舊容器已停止。
- 真實測試新增 child identity commit fault 不建立任何目錄;實際 kill controller、child 等待目錄鎖仍判存活,釋放鎖後完成但 receipt 遺失readback 判 child 已停止且仍保持 unknown。另新增 handoff 缺失payload 截斷extra bytes 拒絕測試。
- 驗證27 項 helper tests、11 項 root file tests、完整 Docker gate 含 lifecycle真實 dispatcher recovery 通過;最後 boot 證據收緊另有 2 項 file-process-proof tests已接 gate、workspace Clippy all targets 與 diff check 通過。fixture 清除。
- 此處只證明可信 file mutation helper 是否仍可繼續寫入,不宣稱全 task process tree 隔離;明確的 unknown 恢復決策、跨 generation 舊容器退役證據、全系統配額及其他 P0P3 尚未完成。
## Readback metadatalifecycle 競態修復2026-09-10
- 覆查發現status 先 SELECT controller-only metadatacontroller 隨後提交 child identity 並退出時,舊 snapshot 可能錯把仍存活的 child 判為 quiescent。現在確認 controller 已退出後,再讀一次受保護 metadata 並核對 child此後 controller 已不能再提交新的交接。證據仍維持 unknown不重送 mutation。
- 新增 SQLite 回歸測試,在 status 已讀取 metadata 後、程序身分觀察時提交 child identity重現這個順序驗證回覆及持久 observation 都是 helper_quiescent=false即使當前檔案 hash 已符合目標。
- API readback 的第二次 lifecycle 檢查補上 running state查詢途中 Computer 停止時回 409後續查詢回 404 且不再呼叫 Runner。既有 ownergeneration 檢查與 unknown 保存測試仍通過。
- 驗證3 項 process-proof tests、完整 Docker gate10 Runner、11 root file、5 HTTP MCP、5 package以及 restartmigrationremove-recreatenative filesSupervisor HTTP實際 API dispatcher 遺失回應恢复通過API owner/lifecycle/generation 定向 SQLx 測試、workspace Clippy all targetsCARGO_INCREMENTAL=0-D warnings與 diff check 通過。自建測試容器已清除。
- 對應 O03O41O45、T17T24 的恢復證據正確性;兩模式共用相同 root helper 與 API 驗證路徑。本輪未變更 schema尚未部署回退此修復會重新引入已重現的錯誤判定。
- 下一步仍須完成明確 unknown 恢復決策、跨 generation 退役證據與 outbox 全頁異常事件的公平補送P0P3 全案尚未完成,不把此回歸測試當成完整驗收。
## File outbox 有界掃描與公平續送2026-09-10
- 修正整頁 retained failure 永遠遮住後續有效 receipt 的問題。新增 migration 033為每個 Computer/provider/generation/bot poll scope 持久保存 scan_afterscan_through每輪固定上限完成後回頭重試舊事件不因持续追加而永久跳過失敗資料。
- Root file_events 支援嚴格整數 cursor仍以完整 identity 查詢;每次最多 100 筆256 KiB。從 SQLite 只讀取每筆最多 128 KiB1 的 bytes損壞 JSON、非文字、過大、NUL 尾碼及無效 payload 回 file.invalid 參照不刪原始列也不回傳損壞內容。Unicode escaping 擴大後仍受單筆上限約束。
- API 驗證 cursor、嚴格遞增 event ID 與固定 snapshot 上限;在每筆處理前持久 checkpointlease token期限不符即拒絕。不能只在整頁前推 cursor否則單頁第一筆慢 transaction 仍會餓死後面的事件。
- 只有中央 eventreceiptartifactnotification transaction 成功提交的 ID 才 ackcursor 不是 ack。timeout、取消、ack 遺失或拒絕處理的事件保留並於下一輪 snapshot 重訪。旧 Runner 的空 stdout 仍走既有補送行為,完整分頁能力需新版兩端。
- 新增 root SQLite 測試100 筆損壞資料後的有效 receipt 仍可讀取;途中新增事件等下一輪;失敗列留存、跨 bot 拒絕、cursor 型別範圍拒絕、blob深層陣列大資料NUL 不阻塞。
- 新增 API SQLxHTTP 測試:整頁 poison 後有效結果完成且僅 ack 已提交 ID第一筆資料庫 pg_sleep 超時transaction 回滾但下一筆下輪仍成功cursor 越界/跳號/逆序與 snapshot 變更拒絕。既有失去 ack、中央回滾、artifact 去重、peer 公平測試維持通過。
- 驗證file operations 12 項定向測試、完整 API 191 passed4 ignored、最終 root scan 測試及完整真實 Docker gateRunner、file、MCP、package、lifecycle、HTTP、API dispatcher receipt recovery通過workspace Clippy all targetsCARGO_INCREMENTAL=0、-D warnings與 diff check 通過,自建容器已清除。最後另補 lease 過期 worker 不得修改 replacement cursor 的定向回歸。
- 對應 O03O30O41O45、T17T18T31。TeamDedicated 沿用相同按 bot scope 的掃描,不修改兩模式共享策略。未部署;回退需保留 root outboxreceipt 及 migration 033 的游標欄位,舊 API 可忽略欄位,不能刪失敗事件來假裝恢復。
- 下一步:明確 unknown 恢復決策、跨 generation 舊 runtime 退役證據、outboxscope 長期保留與全系統公平資源配額。其餘 P0P3 尚未全部完成。
- 最終補充lease replacement 定向測試已通過。gate 後覆查再加入 JSON transport canaryNaN無窮值超過 i64 的整數/孤立 surrogate避免 Python 接受但 Rust 拒絕整批 JSONroot scan 測試已覆蓋並通過這些案例,保留異常事件參照,不回傳原始內容。此最後解析收緊由直接 SQLite 回歸測試驗證,未再重跑完整 Docker gate。
## 同 generation 檔案 unknown 明確恢復2026-09-10
- `file_status` 新增顯式 resolve=true必須同時 readback=true同樣使用原 operationbotComputergeneration 的受保護 mapping。只有 helper 已停止、controller 已停止、目前檔案後置條件符合時才完成恢復;缺舊 handoff、不同 boot、程序仍存活、hash 不符、讀取或 fsync 失敗都維持 unknown不重播 mutation。
- 恢復會重新讀取並 fsync 檔案與父目錄move 改以 fingerprint-pair 同時持有兩端目錄 SH locks讀取 target 後再核對 source。這是 cooperating file writers 下的後置條件核驗,不冒充任意 shell 的強隔離或原 rename 的因果證明。
- Root 以單一 SQLite transaction 更新 receiptoperation 及 outbox重複或並行恢復先檢查既有 terminal receipt不新增重複完成事件。恢復紀錄使用 verificationBasis=postcondition、executionProven=false並保存 helper/controller quiescencesucceeded 在此表示明確恢復的後置條件已核验,不能推論原操作曾成功執行或 exactly-once。
- API ownercurrent bindinggenerationrunning fence 同樣適用 resolve。`file_operation_status` 工具 schemadispatcher 已接旗標;中央 outbox reconcile 驗證上述 proof 欄位並在公開結果保留 verificationBasisexecutionProven沿用 artifactnotification 同交易提交。中央狀態透過既有背景補送收斂,不把 root 回覆當成中央 transaction 已完成。
- UI 在 unknown、目前符合且兩個程序均停止時提供「重新核驗並完成恢復」點擊仍重新做後端核驗使用獨立文案標明後置條件恢復與歷史執行未證實。繁中英文、請求旗標與 controller 存活時不顯示按鈕均有回歸驗證。
- 真實 root 測試涵蓋 writepatchmove 的 original receipt commit fault、hash 被人修改時保持 unknown、resolve receipt transaction failure 不發成功事件、重複恢復不重送事件、後續 replay 不覆寫人工修改。Host process-proof 測試額外驗證 child/controller 任一存活均不能完成恢復helper 測試驗證兩目錄鎖及 fsync fault 無成功輸出、不改 bytes。
- 實際 API dispatcher→Supervisor→Computer gate 新增原 root receipt 提交失敗,再透過 status/readback/resolve 工具恢復、中央 outbox 登錄 artifact、原操作 replay 保留 proof basis 且不改人工內容;這仍不是登入/模型/瀏覽器 UI 的全程 E2E。
- 驗證29 helper tests、3 process-proof tests、12 root file tests、58 frontend tests、TypeScript/Vite production build、完整 API 192 passed4 ignored、完整 Docker gate含新增實際恢復、workspace Clippy all targetsCARGO_INCREMENTAL=0、-D warnings及 diff check 通過;自建容器已清除。最後新增 fsync fault 測試另行通過,沒有變更 gate 後的產品程式。
- 對應 O03O41O43O45、T17T18T24T35。兩模式保留同樣依 bot scope 處理;本輪不新增 schema、不部署。回退須保留已建立的 postcondition receiptoutbox中央紀錄及其語義不能抹除恢復歷史或退回會遺失 proof basis 的版本。
- 下一步仍有跨 generation 的舊 runtime 退役證據、舊 intent 恢復、其他檔案寫入路徑 journal、immutable artifact 與串流、完整隔離scope barrier資源配額、Tool ManagerOAuthmail adapters以及尚缺的 P2/P3 backend 與基準測試。全案保持未完成。
## 退役證據與 artifact 核驗來源持久化2026-09-10
- 新增 migration 034computer_generation_retirements 保存 Computergenerationprovider_refhome_key唯一 proof_idprovider_destroy_ack 及時間。只有 destroy 成功回覆且 generation/provider CAS 仍相符時,才與 generation 退役、jobs interruption 同交易寫入;不根據 changed providerchanged namespace單純 generation 增加回填證據。
- SQLx 故障驗證涵蓋 destroy 失敗不留證據proof INSERT 失敗不退休 generation/jobsproof 已寫入後 job UPDATE 失敗會回滾 proof、generation 與 jobstale ackproviderless active jobs 拒絕;一般 provider 切換不憑空建立第二筆 ack。這是中央持久證據基礎尚未拿來自動解除跨 generation unknown。
- Artifact 新增 verification_basis明確區分 execution_receipt、postcondition 與 legacy_unspecified既有資料保留未知來源不因 migration 推測歷史執行。可信 receipt 與舊 path/hash/size 完全相符才補登來源;已有來源不允許被不同 receipt 改標。
- Catalog API 傳回 verificationBasis新增 owner scope 與三種來源的實際 handlerPostgreSQL 測試。中央 receipt parser 同時拒絕帶 recovery proof markers 卻缺 verificationBasis 的資料,避免默認成原執行 receipt。
- Artifact 回歸測試驗證舊 ID 保留、可信 postcondition 來源補登,以及來源衝突時不提交 event實際 API dispatcherSupervisorComputer recovery gate 驗證一般 write/patch/move artifact 為 execution_receiptroot receipt 遺失後明確恢復的 artifact 為 postcondition。
- 驗證:完整 API 193 passed4 ignored最後 parserartifact 14 項定向測試、catalog handler 測試及擴充的 retirement 交易回滾測試通過;完整 Docker gate 含實際恢復artifact 來源驗證、workspace Clippy all targetsCARGO_INCREMENTAL=0-D warnings、diff check 通過。後補 retirement 測試未改產品程式;自建容器已清除。
- 對應 O28O41O43O45、T15T17T18。兩模式共用相同持久證據與 scope未部署。回退需保留 migration 034 的退役歷史及 artifact 核驗來源,不可把 legacy/postcondition 統一改標成 execution_receipt。
- 下一步:安全地將退役 acknowledgement 與舊 root journalhome_key目前授權綁定接通跨 generation readback明確恢復不能只因中央多一筆 proof 或容器名稱改變就跳過程序停止證明。其餘未完成 P0P3 保持原範圍,並非已完成跨 generation 驗收。
## Artifact 授權 fence 與 Computer 內 verified read2026-09-10
- 修正下載只查 artifact 擁有者、卻不查 bot 目前綁定的缺口。讀取前要求同 owner/space、current Computer binding、running/providerTeam 路徑需精確落在 own workspacesharedDedicated 保留 rooted relative path非法 path/hash/size 不開始 transport。
- 讀取完成後重查 artifact 仍存在且 path/hash/size 未換、owner/binding/provider/generation/state/scope/home_key 仍相符改綁、停機、generation 變更、產物撤銷或 storage scope 變更皆不回傳 bytes。請求攜帶 bot/generation context25 秒 deadline後端錯誤以固定訊息回覆不把任意 backend text 洩出。
- 下載標頭改為 UTF-8 percent-encoded filename*安全處理中文、引號、分號、CR/LF加入 private/no-store 與 nosniff。內容型別維持 octet-stream。
- 新增 SandboxProvider::read_file_verified、Supervisor /read-verified 與 Computer helper read-verified。helper 在 Computer 持目錄 SH lock讀取有界 binary bytes比對 expected SHA-256size 後才輸出不符合、特殊檔案、symlink 或無效條件不輸出內容。API artifact handler 不再計算檔案內容 hash。
- SDK 核對 verified/path/hash/size/base64 及解碼長度,拒絕缺 receipt、錯 path/hash、截斷、UTF-8 fallback、過大回覆transport 分 chunk 收集,依 expected_size有界 metadata 限制 JSON 大小。這仍是最多 8 MiB 的有界 buffer 下載,不是完整大型檔案串流。未知 provider 不用 API-side hashing分開 stat/read 作假 fallback。
- PostgreSQL實際 HTTP fixture 覆蓋 Team/Dedicated binary 下載、owner 拒絕、14 種傳輸途中 lifecycle/ref/receipt/response 異常、跨 bot/path traversal 拒絕、size 不符與 header escaping最初測試中的私人模式 fixture 名稱已修正為實際 enum dedicated。
- helper 新增 1 MiB binary verified read、hash/size/type 拒絕、symlink、空檔與後續人工修改不洩 bytes實際 API SDK→Supervisor→Computer gate 增加正常與修改後 CONFLICT、最終 1 MiB binary verified roundtrip。
- 驗證30 helper tests、3 artifact 定向測試(含最終 14-case guards、完整 API 196 passed4 ignored、完整真實 Docker gate 含 1 MiB verified transport、workspace Clippy all targetsCARGO_INCREMENTAL=0-D warnings及 diff check 通過。最終 SDK guard 更新已做定向 HTTP 回歸與最終 Docker gate不冒充登入瀏覽器下載的全程 E2E。
- 對應 O03O43O45、T06T09T10T21T34T64。未部署API/Supervisor 需一起更新才能使用 verified read舊 provider 維持拒絕而非降級繞過核驗。本輪無新 schema不修改現有 artifact bytes自建容器已清除。
- 下一步仍有 immutable artifact 快照保留策略、upload/download/attachments 真正串流、其他 task file processing 路徑,以及跨 generation 恢復的完整可信證據鏈;其餘 P0P3 不縮減、不標成已完成。
## Computer 內不可變 file artifact 快照2026-09-10
- 新的 journaled write/patch/move可信 UID 1000 helper 在 mutationreadback 核驗及目錄鎖內保留結果 bytes僅透過 child→root 私有 pipe 帶 snapshotContentBase64。root 比對 hash 後將 bytes 寫入 /var/lib/lazyboy-runner/artifacts移除 payload 欄位才發布 receiptoutbox中央 ledgercatalog 不存 task contents。
- 快照以 SHA-256 命名、root-owned 0600目錄 0700用 private temp、fsync、no-clobber link 與目录/父目錄 fsync 發布。受保護 lock 序列化儲存與容量檢查;相同 hash 重用前核對 bytes/ownership/hash 並再次 fsync避免前次 sync 失敗後 dedup 誤報成功。
- 原操作結果未知而明確做 postcondition recovery 時,先再次由 Computer read-verified 讀取符合 hash/size 的 bytes保存快照後才提交 recovered receipt。快照寫入容量失敗不能發布成功原工作檔案可能已變更此時保留 unknown清出容量後仍須明確恢復。
- 每個 store 暫以 256 MiB4096 entries 有界orphan/pending files 也計入。這是容量上限,不是完整 retention自動 GC舊 receipts 缺 snapshotRef 不捏造已保存 bytes繼續顯示 legacy artifact 行為。
- 新 file_artifact 管理操作必須以同 bot 的原 Computer identity/generation/operation 找到 succeeded receipt且 artifactRef/hash/size 相符才能讀取 root blob知道 hash 不構成授權。固定 helper 重新核對 blob不接受檔案系統路徑。已成功的歷史快照可在目前較新 generation 中讀取,但不因此解除任何舊 unknown mutation。
- migration 035 保存 snapshot_ref正常receipt recovery 同交易登錄,保留驗證來源與 legacy ID。Catalog 明示 immutableAPI 用 durable dispatch mapping 取得 origin走專用 Supervisor /artifact 與有界 SDK verified response。缺 origin 或壞快照拒絕,不退回已修改工作檔案;既有 owner/binding/lifecycle fence 及 snapshot_ref 重查持續生效。
- Root 測試覆蓋普通及 recovered snapshot、原檔後續人工修改、錯 bot 拒絕、歷史 generation read、UID 1000 直接讀取拒絕、receipt/outbox 不含 base64 payload容量滿維持 unknown移除 fixture padding 後明確恢復。獨立受保護 store 測試覆蓋 inode dedup、tamper/symlink 拒絕、fsync 故障後再次拒絕及成功重試。
- 實際 lifecycle gate 新增 restartlegacy migrationremove-recreate 後讀回 snapshot bytes實際 API dispatcher→Supervisor→Computer 驗證 write/patch/move 在人類修改後仍讀回當時產物,錯 bot 無法讀取。API handlerHTTP fixture 驗證跨 generation immutable download 只取 durable originmissing mapping 不走 workspace fallback。
- 驗證197 API passed4 ignored、13 root file tests、2 protected artifact tests、原有 30 helper tests、完整 Docker gate含 snapshot lifecycle/recovery、workspace Clippy all targetsCARGO_INCREMENTAL=0-D warnings與 diff check 通過。最後 download row 改具名 struct 修正 lintartifact read 失敗時固定錯誤文字,避免部分 stdout bytes 被放進 control-plane error。自建容器已清除沒有部署。
- 對應 O03O41O43O45、T09T17T18T21T34T64。兩模式仍以同 bot receipt 授權root-private storage 跟隨既有 runner 持久掛載。回退必須保留 snapshots、snapshot_ref、原 receipts 與 provenance不能將已有 immutable reference 降級為 live path 或刪掉 blob 假裝回滾。
- 尚缺:完整 per-agent quota/retention/GC、全工具輸出 artifact、真正大型檔案附件串流、跨 generation unknown 恢復可信證據鏈,以及仍列在 audit 的其餘 P0P3。沒有將全案或 O43 全列宣告完成。
## 快照發布程序死亡後的暫存檔回收2026-09-10
- 修正 root 快照 publisher 被強制終止後,遺留 `.pending-<32 lowercase hex>` 永久占用容量的問題。新 publisher 先取得同一 artifact-store.lock再做有界 inventory此時前一 publisher 已釋放核心鎖,才可移除符合精確暫存命名且 root-owned/private/regular 的檔案。
- 不刪除已發布 SHA-256 名稱或其他未知名稱發布後、unlink 暫存檔之前死亡的 hardlink 只移除 pending link保存原 published inode。symlink不安全 ownership 或 mode 拒絕處理。清理後 fsync 目錄,失敗不發布成功;重試仍須完成正常 snapshot durability。
- 6 項 protected artifact tests 通過,新增實際子程序在 file fsynclink 後被 kill、發布 inode 保留、活 publisher 持鎖時清理等待、256 MiB orphan quota 回收、不認得的 pending-like 檔案仍保留並計入 quota以及 cleanup fsync 失敗/重試。
- 完整真實 Docker gate 通過:含 13 root file tests、RunnerHTTP MCPpackage 原有測試、restartmigrationremove-recreate、native file transport、Supervisor HTTP 與實際 API recovery。gate 執行時包含前 5 項 protected artifact tests其後新增的第 6 項 fsync fault test 已獨立通過產品程式未再變更。Supervisor all-targets ClippyCARGO_INCREMENTAL=0、-D warnings通過。
- 對應 O43T18T64只回收不能被活 publisher 擁有的未完成發布暫存檔,不是已發布 artifact 的 retention/GC。沒有新增 schema部署回退不得刪除 published blobs。全工具 artifact、per-agent quota、published retention、串流與其餘 P0P3 仍需完成。
## File journal 准入容量與歷史 receipt 保留2026-09-10
- 修正所有 file_operations包含成功失敗終態累積 1024 筆後永久拒絕新操作的限制。仍保留每筆 request digestreceiptunknown intent不靠刪除歷史 IDs 釋出名額,避免過期重送變成第二次 mutation。
- 新准入在原 BEGIN IMMEDIATE 中執行acceptedunknown 合計最多 1024 個未完成名額status index 支援查詢;另按 SQLite page_countfreelist_count 乘 page_size要求 128 MiB 使用頁面預算內尚有 64 KiB 准入餘裕。已完成紀錄不占未完成名額,仍占真實 metadata 空間。
- 既有操作的 digestreceipt replay 檢查先於准入限制file_statusreceipt completion明確 recovery 不走新 intent 准入。SQLite 空頁可再用,因此刪除已允許回收的其他資料後不必 VACUUM 才能恢復准入。此預算計入同一 Runner DB 的其他表,不冒充 per-agent 公平 quota、WAL 上限或整機硬磁碟配額;持續增長到容量上限仍須 retention管理政策未丟棄 anti-replay 證據。
- 3 項新 SQLite 測試通過acceptedunknown 名額及終態釋放、不刪 receipts實際 128 MiB zeroblob 壓力拒絕新 intentoutbox原 replay/status 保留,釋放後重用 freelist兩連線競爭最後一個名額僅一方成功。
- 真實 root file gate 改為先以 1024 accepted fixtures 驗證拒絕,再保留同 1024 rows 改成終態,驗證新 file mutation 成功;人類改檔後重播原 receipt 不再覆寫。完整 Docker gate 通過,含 13 root file tests、6 protected artifact tests、RunnerHTTP MCPpackages、restartmigrationremove-recreate、Supervisor HTTP、實際 API dispatcher recovery。gate 包含前 2 項 SQLite tests最後追加並行名額測試另行通過產品程式未再變更。
- Supervisor all-targets ClippyCARGO_INCREMENTAL=0、-D warnings通過。HTTP MCP fixture 曾在 client 關閉 GET 後記錄 BrokenPipeError已檢查來自 fixture 的空 405 reply5 項 MCP assertions 及整體 gate 均通過,不記為產品失敗或額外修正。
- 對應 O03O41T18未部署沒有中央 migration。root SQLite 新 index 為相容變更;回退要保留既有 receipt舊版仍會恢復 lifetime count 限制。其餘 P0P3、完整 journalartifact retention、公平配額與串流仍未完成。
## 每個 bot 的 file journal 未完成額度2026-09-10
- 在既有全機 1024 個 unresolved 名額與 SQLite 使用頁面准入預算之外,加入每 bot 256 個 acceptedunknown 上限,滿額回 FILE_AGENT_QUOTA。以 journal identity 中的 stable bot_id 累計,跨 providergeneration 共用額度,不能藉重建重置未知操作負債。
- 計數與 intent INSERT 共用原 BEGIN IMMEDIATE查詢最多處理全機准入上限內的 identity groups。既有 receipt replay 仍先於新准入檢查;終態紀錄保留但釋放未完成名額,沒有刪除或重執行 unknown。
- 新真實 root file 測試建立跨兩個 origin identities 的 256 筆 acceptedunknown驗證原 identity 與新 provider/generation 都拒絕且沒有改檔;舊 receipt 仍可重播,另一個 bot 寫入成功;一筆轉終態後原 bot 恢復准入。
- SQLite 並行最後名額測試擴充為全機與每 bot 兩組兩個真實連線競爭只允許一方提交。3 項容量測試、14 項 root file tests、6 項 protected artifacts、完整 Docker gateRunnerMCPpackagesrestartmigrationremove-recreatenative transportSupervisor HTTP實際 API recovery及 Supervisor all-targets Clippy 通過;自建容器已清除。
- 對應 O30O41T18T63Team 與 Dedicated 共用同一每 bot 限制。這只防止單一 bot 耗盡全機 unresolved slots不保證多個滿額 bot 同時存在時仍有全機容量,也不是 CPU/RAM/磁碟公平排程或所有工具的 request quota。
- 未部署、沒有新 schema。回退需保留所有原 receiptsunknown其餘 P0P3 的完整公平隊列、retentionstreaming、跨 generation 恢復與其他缺項仍待完成。
## File statusreadback 的儲存與授權 fence2026-09-10
- 檢查跨 generation 恢復入口時發現 file_status 只核對 bot owner 與 provider/generation未確認 Computer owner/space 相符,也未在讀取後重查 storage scope/home_key。現已在查詢前要求 Computer 與 bot 同 owner/space並使用實際 home_key 建立 ComputerRef。
- 傳輸後除原 runningbindinggeneration fence 外,再核對 Computer owner/space、scope/home_key/kind以及同 operation 的 durable dispatch provider/generation/runner identity/runner operation。原 mapping 被刪除或替換、儲存位置或授權改變時回 CONFLICT不回傳過時證據。
- SQLx實際 HTTP fixture 新增 7 種途中異動Computer owner、space、模式、home_key、root operation ID、Runner ID、刪除 dispatch全部拒絕另驗證事前 Computer owner/space mismatch 不呼叫 transport。原 status、工具 resolve、generation/stop race 與不新增 mutation intent 的測試保留。
- 驗證:完整 API 197 passed4 ignored、擴充 file_status 測試、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings、完整真實 Docker gate14 root file tests、容量snapshotlifecycle、實際 dispatcher recovery與 diff check 通過;自建容器已清除。沒有部署或 schema 變更。
- 對應 O41O45T17。這是目前 generation 的恢復入口授權補強,不宣告跨 generation unknown 恢復已完成。後者仍需把中央 provider_destroy_ack、原 home_key/root identity 與目前授權經可信管理通道綁定;不能接受一般 request 內自稱退役的欄位作停止證明。
- 其餘 P0P3 全案範圍維持;仍缺完整 retention/streaming、跨 generation 恢復、其他路徑 journal、公平排程及 audit 所列驗收。
## 重建後的唯讀 file receipt 歷史查詢2026-09-10
- 新 Computer root file_history只接受 operation_idorigin_computer_idorigin_generation以目前 authenticated bot_id 組成舊 identity要求 origin generation 不超過目前 generation查原完整 identityoperation hash。其他 bot、未來 generation、夾帶 readbackresolvebot override 均拒絕。
- 歷史成功/失敗 receipt 有界讀取並回傳acceptedunknown 明示 execution_proven=false、observation_performed=false、desired_state_matches=null、retirement_proof_required。不呼叫 helper、不讀目前工作檔、不修改 receiptobservationoutbox沒有以新 PID namespace 代替停止證明。
- API file-operation lookup 現在允許同一 current Computer binding 下較早 generationprovider 的 durable dispatch。用目前 provider/generation 送到新 Computer 的 file_historybody 只帶原 Runner identity外層回覆新增 historicaloriginGeneration。跨 generation resolve 在 transport 前回 CONFLICT普通查詢仍可取得已知 receipt 或明確未知狀態。原 owner/space/storage/kinddispatch mapping 傳輸後 fence 保留。
- 更新 file_operation_status 的模型工具描述,說明歷史 unknown 不會被 readback 或 resolve。歷史查詢不會把舊 outbox 自動 ack也尚未將歷史 receipt 回填中央 operation/artifact該同步流程與 unknown retirement-proof recovery 仍需完成。
- 新 root test 驗證原檔被人類修改後取得歷史 receipt、錯 bot未來 generation額外欄位拒絕以及未知操作查詢完全不改檔receiptobservationoutbox。實際 restartlegacy migrationremove-recreate gate 新增以較新 identity 的 file_history 取得原 receipt。
- API HTTPPostgreSQL 測試覆蓋 replacement provider、current generation header 與 original identity body、historical/原 generation metadata、unknown 未觀察、resolve 拒絕及途中 home_key 變更拒絕。先前 current-generation 的授權與 mapping 異動測試持續通過。
- 驗證197 API passed4 ignored、15 root file tests、6 protected artifacts、3 capacity tests、完整真實 Docker gate含既有實際 API recovery及 workspace all-targets Clippy 通過。最後 replacement-provider HTTP fixture 與工具描述已納入完整 API suiteroot 程式在 gate 後未再修改。自建容器清除、未部署。
- 對應 O03O41O45T17T64Team/Dedicated 均以相同 current bot 授權讀歷史。回退要保留原 root receipts舊 Runner 無 file_history 時拒絕,不降級成任意重做。沒有宣告跨 generation unknown 恢復或全部 P0P3 已完成。
## 查詢歷史終態 receipt 時回填中央狀態2026-09-10
- API 歷史 receipt 查詢現在於傳輸後開交易,重新驗證並鎖住目前 Computerbot原 dispatch核驗結果後才回覆。只處理 root 已保存的 succeededfailed歷史 unknown 保持未知,不做新檔案效果或停止推論。
- migration 036 的 computer_file_history_receipts 保存原 dispatch provider/generation/Runner/operation 與核驗後 outcome。這是歷史 receipt 觀察紀錄,不是本地 outbox 事件;不編造 local_id不 ack 未讀取的舊事件。相同 proof 重播去重proof 改變或與既有終態矛盾時拒絕。
- 重用既有 action/path/hash/size/provenance parser 與 artifact registration原 operation acceptedunknown 可更新為 receipt 終態artifact、history proof、operation result、Activity outbox 在同一交易提交。保留 execution_receiptpostcondition 區別及 immutable snapshot reference失敗不把 root 事實刪掉或重跑操作。
- SQLx fault test 在最後 Activity INSERT 注入故障,證明前面已寫入的 artifacthistoryoperation 全數回滾;恢復後兩次回填只各留一筆 artifacthistoryActivity。本地 computer_file_events 維持零新增unknown 及矛盾 failed receipt 拒絕。
- API HTTP fixture 以 replacement provider 歷史成功回覆驗證中央 unknown→succeeded、artifact 登錄及重複查詢去重;所有原 owner/storage/origin fence 測試持續通過。
- 真實 API→Supervisor→Computer gate 新增:保留 root postcondition receipt、模擬中央 completion/artifact 遺失、將 fixture generation 更新後做兩次歷史查詢;中央恢復 succeeded重建 artifact 保持 postcondition 與原 snapshot referenceActivity 一筆、local event 數不變、人類後續修改仍原封不動。generation 更新只用來測歷史查詢,沒有冒充舊程序退役證據。
- 驗證:完整 API 198 passed4 ignored、完整 Docker gate15 root files、snapshotquotalifecycle 及上述歷史回填、workspace all-targets Clippy 與最後新增 E2E 的 API all-targets Clippy 通過;自建容器清除,未部署。
- 對應 O41O43O45T17T64。migration 036 的 proof/outcome 為持久 metadata回退須保留中央先部署 migration 才能使用新回填。尚缺不依賴查詢的歷史 outbox 背景續送ack以及 unknown 跨 generation 的可信退役與明確恢復;其餘 P0P3 缺项不縮減。
## 歷史 receipt 與事件送達的終態一致性2026-09-10
- 補強兩條恢復途徑原本各自去重、未交叉核對的邊界。歷史回填先核對已送達的最新終態 payloadevent persistence 在處理 succeededfailed 時核對既有 history proof 的 originstatusoutcome。任一不一致先拒絕不寫入 artifact新 event不能形成可 ack 的中央入帳紀錄。
- acceptedunknown 的晚到事件仍可保留與 ack不因已有歷史終態而刪除歷史觀察操作本身不退回 unknown。相符終態事件可正常送達且不重複產生歷史回填已發布的 Activity。原有固定範圍游標單筆錯誤隔離可繼續處理後續事件矛盾 root 事件不被直接丟棄。
- 新增兩項 SQLx 測試history succeeded → acceptedunknownmatching succeeded 送達後只有一筆 Activity矛盾 failed 未入帳;已送達 failed 後即使中央 operation result 被 fixture 模擬遺失,也不能接受矛盾 historical succeeded沒有新 history/artifact。
- 驗證:完整 API 200 passed4 ignored、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings、完整真實 Docker gate 含原 postcondition 歷史回填snapshot15 root file testslifecycle及 diff check 通過。自建容器清除;沒有新 migration 或部署。
- 對應 O41O45T17。此檢查保留已驗證的終態證據不將衝突當成普通成功重播不等於歷史 outbox 背景掃描已接通。下一步仍須將舊 scope 的分頁續送與中央提交後 ack 綁定目前授權,並完成跨 generation unknown 停止證明;全部 P0P3 範圍維持。
## Computer 歷史 outbox 的分頁與 ack 入口2026-09-10
- 新 root file_history_eventsack_file_history_events嚴格接受 origin_computer_idorigin_generationcursor 三欄origin bot_id 固定取自目前 authenticated identity未來 generation 或額外 botresolve 欄位拒絕。唯讀掃描不形成程序停止或成功證明。
- 轉接既有 file_events 有界 fixed-snapshot scan 與 identityevent IDs 精確刪除,保留原事件 IDpayload不改寫成目前 generation既有 100 rows256 KiB batch128 KiB event、異常 placeholder原始壞資料保留、游標驗證與 ack 上限繼續適用。
- 新 SQLite 測試驗證 100 筆壞事件後可讀到有效歷史事件ack 含其他 bot目前 generation IDs 時只刪相符 origin 範圍;錯 bot 為空集合未來boolean generation、額外欄位及非法 ack cursor 拒絕。
- 真實 root test 驗證較新 identity 的 scan 與原 outbox 完全相同、錯 bot ack 不刪資料、正確 ack 只刪指定前綴lifecycle fixture 新增 restartlegacy migrationremove-recreate 後由較新 identity 讀取原未 ack events內容與 IDs 不變。
- 驗證2 outbox tests、15 root file tests、完整 Docker gatesnapshot/quota/jobs/MCP/packages/lifecycle實際 API 歷史 receipt 回填、Supervisor all-targets ClippyCARGO_INCREMENTAL=0、-D warnings及 diff check 通過。自建容器已清除,未部署,沒有新 schema。
- 對應 O41T17T64。這一輪是 Computer 端入口,中央背景 poll scopes 尚未改為選取舊 origin也尚未透過此入口做提交後 ack未宣告歷史背景續送已完成。回退保留原 outbox舊版不支援新動作時不可改用目前 identity ack 代替。其餘 P0P3 與跨 generation unknown 恢復範圍維持。
## 背景 file poll 選取前的 bot 授權檢查2026-09-10
- 檢查歷史 scope 接線時發現 claim_poll_scope 未連接目前 bot assignment已解除綁定或 owner/space 不相符的 retained scope 仍可能先被選中並發起讀取,再由中央 persist 拒絕。現於 claim SQL 要求 bot 仍綁同 Computer 且 user_idspace_id 相符。
- 無權 scope 保留原 metadata不取得 lease、不更新 last_polled、不因暫時改綁而丟掉 outbox 掃描位置;合法重新綁回後可重新選取。這是選取時的授權快照,不冒充整段傳輸的 lifecycle barrier提交時的 binding/generation 檢查仍保留。
- 新 SQLx 測試覆蓋 detached、foreign owner、foreign space 不被選取,原合法 bot 正常取得 lease檢查三個拒絕 scope 的 lease/last_polled 未動重新綁回後恢復選取。既有公平輪替、lease expiry fencing 與 HTTP poll 測試仍通過。
- 驗證:完整 API 201 passed4 ignored、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings與 diff check 通過。此輪僅改中央選取 SQL沒有修改 Runner、schema 或部署;未重跑沒有變更的容器程序測試。
- 對應 O30O41T17。中央選取目前仍限現有 generation歷史 poll origin 接線與提交後 ack 仍需完成沒有把入口完成當成背景續送完成。P0P3 原始範圍維持。
## 中央歷史 file outbox 背景續送2026-09-10
- claim_poll_scope 現在選取目前 Computer 下不晚於目前 generation 的合法 bot scopes不再排除旧 provider/generation。保留 current provider/generation/running、bot assignment/owner/space 檢查及既有 lease/token/visited-bot 輪替。migration 037 加入跨 generation last_polled 排序索引。
- 每次 claim 後取出原 scope provider/generation/cursor歷史 scope 必須從 durable dispatch 唯一解析原 Runner identity缺失歧義拒絕。請求以目前 Computer provider/generation/context 送達file_history_events body 帶原 identity 與固定快照 cursor。
- persist_event 分開處理目前授權/儲存快照與原事件 identity鎖目前 Computer/bot 並核對 captured owner/space/home_key/scope、running/provider/generation再以原 dispatchroot identity 驗證 payload、登錄原 local_idgeneration。已有 historical proof 的一致性檢查仍生效accepted/unknown 不被當作程序停止或成功。
- 只有 PostgreSQL 提交成功的 IDs 進入 ack list。歷史 scope 使用 ack_file_history_eventsbody 帶原 identity目前 scope 沿用原 ack。讀取前與 ack 前另重查目前授權/儲存快照,變更時不發起該 transport。原 4 次嘗試/每 scope 2 秒、逐筆 checkpoint、16 ID 前綴 ack、poison 保留與 lease fencing 持續適用。
- 新 HTTP/PostgreSQL 測試驗證 replacement provider目前 generation header、原 identity cursor、壞事件後仍提交有效事件、第一次 ack 失敗後重送去重、ack 發出時 operation/artifact 已提交、Activity 僅一筆home_key 改變後 scan 與 ack 都拒絕。
- 實際 API→Supervisor→Computer gate 新增未 ack 的 journaled write保留 root 原事件並模擬中央 completion/artifact 遺失fixture generation 前進後由 sync_events 自動恢復 succeeded 與 execution_receipt artifact以原 generation 保存兩個事件,最後 root 歷史 outbox 為空。不依賴 file-operation 查詢,不重做檔案寫入。
- 驗證:最終完整 API 202 passed4 ignored、完整 Docker gate15 root files、root history scan/acklifecycle實際背景恢復、workspace Clippy 通過;最後補充 index 與 stale-ack assertion 已納入完整 API/gate。自建容器清除、沒有部署。
- 對應 O30O41T17T64。scope/lease 仍是每 scope 且每個 worker 每輪排除已拜訪 bot未宣告跨 replicas 的 per-bot 資源隔離或大量歷史空 scopes 的延遲 target 已驗收。舊未知效果的可信停止證明、明確恢復、retention 與其餘 P0P3 維持待辦。
- 回退需保留舊 poll scopescursorroot outbox 與 event 原 generation新 index 可保留。舊 API 恢復僅輪詢目前 generation不可刪除尚未 ack 的歷史事件當作回退清理。
## 多 worker 跨 generation 的 bot poll lease 互斥2026-09-10
- 修正歷史 scope 接入後,同一 bot 的不同 generation 可以被不同 worker 同時取得有效 lease 的缺口。claim 改用短交易鎖住 stable bot row 與候選 scope候選查詢排除該 bot 已有的有效 lease取得鎖後再用新 READ COMMITTED snapshot 重查,才發布 lease。
- 明確 SET TRANSACTION ISOLATION LEVEL READ COMMITTED避免部署環境改預設 isolation 使第二次檢查仍看舊 snapshot。busy botscope 使用 SKIP LOCKED競爭重試最多 4 次,保留其他 bot 的選取機會,整個網路輪詢不持有 bot DB row lock。
- 新 SQLx 並行測試建立同 bot 兩個 generation兩個 worker 同時競爭只一個成功;另一個 bot 正常取得 lease。原 lease 過期後可換 generation claim過期 token 不能 checkpoint遲到 release 不會清掉 replacement lease。
- 原逾時續送測試揭露新的合理排程差異SQL future drop 不代表 PostgreSQL 已完成回滾bot row 仍鎖住時新 claim 會跳過。測試改以限時取得該 row lock 等待實際回滾完成,再核驗 cursor 續送和只有後續事件提交;初次新增 fixture 的 lock_timeout 單位已修正為 PostgreSQL 支援的 5s沒有放寬 outcome/assertions。
- 最終完整 API 203 passed4 ignoredAPI all-targets ClippyCARGO_INCREMENTAL=0、-D warnings與 diff check 通過。此輪未改 Runnerschema部署驗證集中於真實 PostgreSQL 並行、lease 與既有 HTTP 續送回歸。
- 對應 O30O41T17T63。這是使用新版 claim 的 worker 間有效 lease 互斥;不宣告舊版 replica 混跑或已過期但仍在外部執行的請求已被物理取消,也不是 CPU/RAM 隔離。全部 worker 升級後才可依賴新 per-bot claim 語意rollback 不刪 scopecursor。歷史空 scope 延遲retention、跨 generation unknown 恢復及其餘 P0P3 仍待完成。
## 已讀空歷史 scope 的輪詢延後2026-09-10
- migration 038 新增 next_poll_after預設立即可選取。只有歷史 scope 回覆經驗證的空 batch完成游標 (0,0) 時,才在再次核對目前授權後,使用尚有效的 lease token 延後 60 秒再查;不刪 poll scope、outbox、receipt 或原始 identity。
- claim SQL 過濾未到期的歷史 scope目前 provider/generation 明確豁免延後時間,因此即使殘留未來時間也立即可選取。非空/壞事件與缺少有效 cursor 的回覆不當作已讀空,不藉 backoff 丟失事件。
- SQLx 測試驗證歷史空 scope 讓出輪詢機會、目前 scope 即使 future timestamp 仍可選取、歷史延後到期後重返輪替,以及釋放後的 stale lease 不能修改 delay兩個 scope 均完整保留。到期測試透過 fixture 設定 DB 時間欄位,不等待固定 sleep。
- 真實 API→Supervisor→Computer gate 在完成歷史背景恢復與 ack 後,再次讀取真正空 outbox確認 delay 持久化、cursor (0,0),立即重跑 sync 不更新該 scope last_polled。原 15 root file tests歷史 artifact 回填lifecycle 持續通過。
- 驗證:最終完整 API 204 passed4 ignored、完整 Docker gate、API all-targets Clippy 及 diff check 通過。自建容器已清除,未部署。最後 current-scope 豁免已納入最終 API suite 與 gate。
- 對應 O30O41T17T63。這降低已知空歷史 scope 的重複輪詢,不宣告大量從未掃描 scopes 的初始延遲或完整全機公平排程 target 已驗收。延後期間若舊 scope 又產生事件,仍會於到期重查;未因 generation 改變推論程序已停止。
- 回退可保留新欄位,舊 API 會恢復較頻繁輪詢而不是刪掉資料。跨 generation unknown 恢復的可信退役證據鏈、完整 retention/streaming 與其餘 P0P3 仍需完成。
## 背景事件的執行後端種類 fence2026-09-10
- 背景 file poll 的 require_poll_scope 與 event commit 原先核對 owner/space、home_key/scope、provider/generation漏掉 captured Computer kind。現加入 kind 比對涵蓋讀取前、ack 前以及同交易提交事件artifact 的檢查;與 file-status 查詢的後端 fence 對齊。
- 新 SQLx 測試保持 provider/generation 不變、只變更 kind驗證舊 snapshot 的 poll 驗證及 receipt commit 拒絕artifacteventActivity 都沒有新增operation 保留 unknown恢復原 kind 後正常核驗及提交。
- 驗證:完整 API 205 passed4 ignored、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings與 diff check 通過。此輪僅中央 SQL fence 與 PostgreSQL 測試,未改 Runner、schema 或部署,未重跑不變的容器流程。
- 對應 O41O45T17。提交拒絕保留原 root 事件供後續處理,不把 metadata 設定變更解讀成已完成其他 provider 的操作。完整輪詢延遲驗收、跨 generation unknown 退役證據鏈與其餘 P0P3 缺項仍維持原範圍。
## 跨 generation 退役證據的驗證與私有管理通道2026-09-10
- 新 root file_retirement_proof 驗證 HMAC-SHA256 envelopepayload 最多 4096 bytes拒絕重複 JSON 欄位、額外 claims、未來過期時間、超過 60 秒期限、boolean 整數混用、錯目前 identity/home_key、跨 bot origin、非較早 generation、非 provider_destroy_ack 種類與非法 references。錯誤統一為 INVALID_FILE_RETIREMENT_PROOF不含任意簽章資料或 key。
- Supervisor 使用獨立 lazyboy-file-retirement-v1 用途標記,從 master實際 container homeKey label 衍生 256-bit key與公開給 Computer 服務的 control token 分離,其他 home 的 key 也不同。只有 file_retirement_validate 動作才把 key/home 加入 fixed root request 的私有頂層欄位,以 Docker exec stdin 傳遞;不放在 argvtask env 或使用者提供的 nested input 中。
- Root 驗證探針回傳 proof_validproof_idorigin_generation先取出私有 key/home不發布 key不開始 task helper、不清除 unknown也不發布恢復 receipt。驗證簽章不等於此階段已核實 provider 實際被 destroy中央 acknowledgement 查證與安全發證尚待 API 接線。
- 3 項 Python 協定測試涵蓋有效證據、錯 key/home/current context、MAC 篡改、簽章有效但 claims 非法、重複欄位、無界/壞 envelope。Rust credential 測試驗證用途及 home 分離registered gate 執行這些 proof tests。
- 真實 Supervisor HTTP→Computer fixture 以測試 authority 簽章,驗證 Rust 簽章Python verifier 互通、private key 不在回覆、偽造 signature 與跨 bot 拒絕、原人類修改檔案不動。該 fixture 明示只驗證 envelope不把仍存活的測試容器偽稱為已退役。
- 驗證3 proof tests、Rust credential test、完整 Docker gate含擴充的 Supervisor HTTP 證據驗證、15 root files、lifecycle、實際 API 歷史背景恢復)與 Supervisor all-targets Clippy 通過diff check 通過,自建容器清除,未部署。
- 對應 O41O45T17。尚未提供可自行接受任意 retirement claims 的恢復入口;下一步必須由 API 依目前授權核對中央 provider_destroy_ack原 dispatchhome_key再透過此通道把證據送入明確 postcondition recovery。全部 P0P3 剩餘範圍維持,不能將簽章驗證探針當成跨 generation unknown 已完成。
## 簽章退役證據的 root 明確恢復與中央來源核對2026-09-10
- Root 新增 file_retirement_recover僅在嚴格驗證簽章、目前 identity/home、原 identity、期限及 provider_destroy_ack claims 後,使用已退役的證據進行原操作後置條件核驗。不同 boot 的 PID 不被視為停止證明;簽章證據也不繞過內容 fingerprint、fsync、paired move 或 immutable snapshot 核驗。
- 恢復 receipt 保留 postcondition、executionProven=false新增 retirementProofIdquiescenceBasis。已驗證 claims不含 keysignature與 receiptoutbox 同 SQLite transaction 保存於 file_retirement_receipts重送返回既有 receipt不覆蓋後來的人工作業。Supervisor 私有 key 注入擴充至恢復動作。
- 新真實 root 測試以 fixture authority 及舊 boot metadata 模擬跨 generation普通查詢維持 unknown壞 MAC 拒絕,有效證據遇到人類內容衝突仍 unknown內容符合才恢復且不重寫檔案後續重送保留人類修改。這不是實際 API destroy acknowledgement 的端到端驗收。
- 第 4 項 proof 測試使用真實 SQLite transaction、模擬已完成的檔案核驗邊界注入 audit INSERT 失敗,確認 receiptoutboxaudit 全部回滾,移除故障後只提交一次。
- 中央 parser 嚴格核對 proof ID 格式及 postconditionprovider_destroy_ack 來源。record_artifact 另要求該 ID 匹配中央退役 acknowledgement 的原 dispatch provider/generation 與目前 home缺失或錯 home/provider/generation/proof 拒絕,同交易保留 unknown。新增 SQLx 測試覆蓋拒絕及成功。
- 驗證:最終完整 API 206 passed4 ignored完整 Docker gate 通過16 root files、Supervisor HTTP、lifecycle、實際 API 歷史背景恢復fixture 容器清除4 項 proof tests 通過。Gate 後新增的中央 acknowledgement guard 已由最終 API suite 覆蓋,第 4 項 SQLite proof test 另行通過。未部署。
- 對應 O41O45T17。API 歷史 resolve 仍拒絕:必須補齊目前 path grant、中央查證、受信任 issuer、專用 transport 與實際 destroy/recreate 恢復端到端測試,才可對使用者開放。此輪不能宣告跨 generation unknown 已完整完成;其餘 P0P3 範圍維持。
## 中央退役查證與專用簽章恢復通道2026-09-10
- 新 FileRetirementRequest 與 SandboxProvider::recover_retired_file 管理介面,拒絕額外欄位、錯/空 identity、非較早 generation 與空 home不支援的 provider 預設 fail closed。Docker SDK 核對目前 context/home使用專用 files/recover-retired endpoint回覆串流上限 128 KiB、stdout 64 KiB 並嚴格核對 status/code。
- Supervisor 入口要求 master token、bot 與 generationbody 上限 16 KiB再次核對實際 container homeKey label。只有管理端生成用途分離的 HMAC 與 60 秒 claimsenvelope 直接送入 root不返回給 API工具task不接受呼叫者提供的 signature。原 generic exec 仍不能自行簽章。
- API 歷史 resolve 不再一律拒絕。先用原 captured identity 鎖住目前 Computer/bot/dispatch查證原 computer/provider/generation 與目前 home 匹配的 provider_destroy_ackFOR SHARE 保持 acknowledgement 穩定;在鎖內讀原 metadata依目前 bot workspace scope 檢查來源與 move 目的地全部路徑,再呼叫管理通道。以 2 秒 lock_timeout 限制取得鎖等待、25 秒 transport timeout 限制外部等待,鎖保留至中央 reconciliation commit。普通歷史查詢仍不讀取 live path。
- 新 SQLxHTTP 測試覆蓋缺 acknowledgement、錯 provider/generation/home、空未正規化跨 bot舊 dedicated 路徑、move 目的地越權,這些案例都不發起 transport有效請求在 external call 期間實際嘗試修改四種 DB records全部因 row locks 拒絕。unknown、錯 status/code、過大回覆不產生 artifact有效 receipt 保留 postconditionexecutionProven=falseproof ID 並去重。這是 DB metadata 互斥驗證,不宣稱任意外部 Docker 操作受到 PostgreSQL 鎖控制。
- Supervisor HTTP fixture 覆蓋 SDK 專用入口、home mismatch、錯 tokenbotgeneration、額外 signature 拒絕,以及已知 receipt 重送。擴充 fixture 注入真實 SQLite result UPDATE 故障helper 實際寫入後由專用 issuer 恢復 unknown再核對人類後續修改不被重送覆蓋。此 fixture 使用測試 authority並未真的 destroy 舊 guest。
- 最終驗證:完整 API 207 passed4 ignoredControl 157 passed、Sandbox 11 passed完整 Docker gate 通過4 proof tests、16 root files、擴充 Supervisor HTTP unknown 恢復、lifecycle、實際 API 歷史背景恢復workspace all-targets ClippyCARGO_INCREMENTAL=0、-D warnings及 diff check 通過。自建 fixture 容器已清除。
- 對應 O41O45T17。仍需實際 lifecycle destroy 產生中央 acknowledgement再 recreate 並經 API 恢復 unknown 的完整一體化 gate也需 UI 歷史恢復可用性提示/入口與恢復回覆遺失故障驗收。全 P0P3 原範圍保持,沒有將各層 fixture 拼成已完成端到端的宣告。未部署。
## 實際 provider 退役與重建後恢復 gate2026-09-10
- 擴充既有 API→Supervisor→Computer 整合 gate建立獨立的一次性 Dedicated guest使用 network=none、CPU/RAM/PID 上限、持久 home 與四個 runtime mounts。所有目錄位於本次 Supervisor fixture 的暫存目錄,退出時先移除 guest 再清除資料。既有 Team fixture 不變。
- 真實 root SQLite result UPDATE 故障讓 write helper 寫入成功而 receipt 缺失;移除故障後呼叫原 production replace_computer_generation僅將 Rust 可見性改為 pub(crate) 供同 crate gate 使用),經 Supervisor stop/destroy 取得 acknowledgement。測試核對舊 Docker ID 已不存在、中央 retirement 原 provider/home/generation 正確、generation 前進且 provider 清空;沒有在 fixture 人工 INSERT retirement。
- 以相同持久 mounts 建立不同 Docker ID再用 fixture 發布新 provider/running這一步不宣告完整公開 boot/readiness 流程已驗收。核對原檔案 bytes 與 root journal 跨容器保存,普通歷史查詢仍不讀取 live path。
- 經 API tool dispatcher 明確 resolve人類內容衝突保持 unknown 且不改檔fixture 恢復預期 bytes 後,恢復須回傳中央實際 proof ID、postcondition、executionProven=falsemtime 不變。後續人類編輯及重送不得重寫immutable artifact 仍返回核驗 bytes背景歷史 outbox 必須以原 generation 保存兩個事件並只產生一份 artifact。
- 初次執行在新增 fixture 的 file_events 初始化缺少 JSON 游標時失敗,尚未進入退役流程;已補上必要的 {},保留所有 outcome/assertions 重跑。最終完整 Docker gate 通過16 root files、Supervisor HTTP、既有 Team 歷史恢復及新增 Dedicated 實際退役恢復API 整合測試 18.89 秒workspace all-targets Clippy 與補充 API all-targets Clippy 通過diff check 通過。所有本次 fixture 容器已清除,未部署。
- 對應 O41O45T15T17T64本輪不改產品恢復語意擴大真實故障lifecycle 證據範圍。回退可撤除該 fixture不刪 persisted journal退役 acknowledgement 或改復原來源。歷史恢復 UI、恢復回覆遺失、公開 boot/readiness 一體化及其餘 P0P3 尚待完成。
## 歷史 unknown 的明確恢復 UI2026-09-10
- API file-operation 回覆新增 retirementRecoveryAvailable。只有歷史 unknown 在目前 owner/binding/storage/dispatch locks 內,經相同 retirement_authorization helper 核對中央 provider_destroy_ack、原 identity、目前 home、所有受影響路徑後才為 true。普通查詢仍使用 file_history、不讀 live path、不簽發 envelope也不返回管理 keyproof claims。
- 真正 resolve 每次重新查證,不接受 UI 提示作為授權。抽出共用 helper 後缺失不匹配非法路徑回傳不可用DB 錯誤仍失敗,不偽造可用性。終態及同 generation 不給歷史恢復提示。
- Run Monitor 對歷史 unknown 僅在中央 boolean 提示為 true 時顯示既有「重新核驗並完成恢復」按鈕;新增中英文提示,說明舊 Computer 已退役且可嘗試核驗。渲染不呼叫 API必須點擊才送 readback=trueresolve=true當前 generation 原有 helper/controller/desired state 條件保留。內容衝突訊息優先,不把可嘗試恢復顯示成已成功。
- SQLx/HTTP 回歸擴充 hint缺 acknowledgement、錯 home/provider/generation、未正規化與跨 botmove 目的地越權皆 false合法 hint 不進行檔案觀察;顯示後更改 acknowledgement homeresolve 拒絕且沒有發起恢復 transport。前端新增 strict boolean終態歷史與當前分流測試實際元件事件測試確認不自動執行且點擊送對原 operation。
- 驗證:前端 59 tests 通過、TypeScript/Vite production build 通過(既有 bundle size warning、完整 API 207 passed4 ignored、workspace all-targets Clippy 與 diff check 通過。完整 Docker gate 通過,包括 16 root files、Supervisor HTTP、既有 Team 歷史恢復與 Dedicated 實際退役/重建後 availability assertionAPI 整合段 18.73 秒。本次 fixture 容器均已清除。
- 對應 O41O45T17T64。未宣告瀏覽器視覺公開登入後端到端已測目前 UI 證據為元件事件/狀態測試及 production build。Team 現有同 generation 恢復維持Dedicated 真實退役 fixture 持續驗收。回退可忽略新增提示欄位、隱藏歷史按鈕,不刪既有 receiptacknowledgement。恢復回覆遺失、公開 boot/readiness 一體化及其餘 P0P3 仍待完成,未部署。
## 退役恢復 receipt 回覆遺失驗證2026-09-10
- 擴充實際 Dedicated destroy中央 acknowledgement重建 fixture在 API→Supervisor 的專用 recover-retired transport 插入一次性故障代理。代理完整讀到真實 root succeeded receipt 才回 502不建立 receipt、不修改 task bytes也不改寫退役 claims。
- API 必須回報 FILE_STATUS_UNAVAILABLE原操作維持 unknown中央 artifact 與 historical proof 均為零;代理核對只收到一次請求,禁止傳輸層悄悄重做。真實檔案 mtime 在 root 恢復期間維持不變。
- 回覆遺失後先讓人類修改檔案,再經正常 API 明確恢復請求取回原 receipt。回傳 evidence 必須與代理先前讀到的實際 receipt 完全相同,保留原中央 proof IDpostconditionexecutionProven=false人類 bytes 與 mtime 不變。既有再次重送、immutable artifact 讀取與歷史 outbox 入帳檢查持續執行。
- API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings與 diff check 通過;完整 Docker gate 通過,新增實際退役/回覆遺失整合段 19.14 秒,原 root filesSupervisor HTTPTeam 背景恢復皆通過。自建 fixture 容器已清除。這項變更只修改測試 fixture沒有改產品協定恢復程式不重跑不變的前端建置。
- 對應 O41O45T17T64。本案例覆蓋「root 已提交HTTP 回覆被換成 502」不宣告所有 socket reset逾時中央程序崩潰時序均已驗收。公開 boot/readiness 一體化、完整故障矩陣及其餘 P0P3 仍保持原範圍,未部署。
## boot 健康探測不明時保留原 Computer2026-09-10
- 核對公開 boot 路徑時發現 guest_has_screens 把 ContainerProbe::Unknown 壓成 falseboot_for 接著會執行 stop/destroy/replacement暫時 HTTP 失敗因此可能銷毀仍可用的 Computer。移除該 boolean wrapperboot 明確拒絕 Unknown 並保留原 provider/generation/state。
- probe 對固定 test -x 的 exit 0 視為 Alive、exit 1 視為 Missing其他非零碼如 timeout 124終止 137錯誤 2改為 Unknown。原明確容器缺失錯誤仍走 Missing沒有以未知狀態推導退役 acknowledgement。
- 新 SQLxHTTP regression 覆蓋 TeamDedicated、need_gui true/false 與 HTTP 5031241372檢查原 provider/generation/running 與 unknown job 保持、沒有 stop/destroy/provision 請求、沒有新增 retirement恢復健康 code 0 後 runner-only boot 可重用原 provider。
- 最終完整 API 208 passed4 ignored、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings及 diff check 通過。上述 Docker 回覆遺失 gate 在此 boot 修正前已通過;此修正不改該 gate 使用的明確 replace 路徑,新增公開 boot 分支以真實 PostgreSQLHTTP regression 驗證。公開實際容器 boot/readiness 與全 P0P3 仍待完成,未部署。
## 退役後透過正式 boot_for 重建2026-09-10
- Dedicated 退役恢復 gate 移除 fixture 的 Docker recreateSQL provider publication改呼叫 production boot_for(need_gui=false),經 Sandbox→Supervisor provision、映像 entrypointready marker 與中央 boot_attempt CAS 發布 running。核對新 provider ID、generation 仍為退役後的 2、boot attempt 清除;再次 boot 重用相同 provider/generation沒有多寫退役紀錄。
- 原先故障 guest 仍由 fixture 建立;銷毀、退役紀錄、重新 provision、就緒檢查、中央發布、未知效果恢復與回覆遺失重送均走實際程式。測試 Supervisor 固定 512 MiB2 CPUs256 PIDs、關閉 sudo 並清除 shared screen network 環境;正式 provision 會建立自己管理的 networkfixture cleanup 新增只移除本次 guest 與其 network。
- 此版本完整 Docker gate 已通過,整合段 22.96 秒API all-targets Clippy 通過。另新增全新 Team home 的正式 cold bootnative write 測試,不預先建立或修正 home ownership。確認該新增 assertion 不在首次執行 binary 內,因此已重新編譯並重跑整合 gateTeam cold boot 曾揭露 ownership 缺陷,修正及最終結果見下節。
- 對應 O08O41O45T15T17T64。這是公開 boot 函式到真實 runner-only 容器的整合;不等於瀏覽器登入 HTTP routeGUI、browser、desktop、viewer 各層 readiness 均已驗收。全部 P0P3 其餘範圍維持,未部署。
## 修正未設定 HOST_DATA_DIR 的全新 home ownership2026-09-10
- 新 Team cold boot gate 揭露真實啟動失敗API/Supervisor 由 root 在本機執行,未設定 HOST_DATA_DIR 時API 建立的 home 保留 root ownership映像以 UID 1000 啟動,建立 .browser-profiles 時因權限拒絕而 exit 1Supervisor provision 回 500。故障由實際 guest stderr 與 Supervisor startup log 確認,不是以 fixture 手動 chown 掩蓋。
- DockerHost::provision 在驗證 managed home canonical path 後,對所有 Unix 部署統一將 home 根目錄設為 1000:1000不再只在 HOST_DATA_DIR 模式執行。僅改根目錄擁有者,不遞迴改寫 taskbrowsertool 既有內容權限chown 失敗仍在建立容器前拒絕。
- Team cold boot fixture 不預建 homeruntime、不修 ownership實際呼叫 boot_for核對新 home uid/gid=1000、Team bot 的 journaled write 與 native read 成功。Dedicated 正式 re-provision、warm boot reuse、退役恢復及回覆遺失仍在同 gate 內執行。
- 診斷階段保留了 provision 失敗的 Supervisorguest logs並清除本次 guest/network不動既有部署。workspace all-targets Clippy、diff check 及修正後完整 Docker gate 均通過,整合段 26.18 秒;包含全新 Team cold boot1000:1000 ownershipnative write-read以及 Dedicated 正式 re-provisionwarm reuse退役恢復與回覆遺失。本次 guestnetwork 全部清除。
- 對應 O03O08O41T15T17。這是 root 啟動的本機部署及新 home 的缺陷修正;不宣告 GUIviewerbrowser 獨立 readiness 與登入後完整產品流程已完成。P0P3 其餘範圍保持。
## health 證據、授權與探測期限2026-09-10
- 發現 component_health 把設定中的 display backend 一律當 ok=true且 jobs count SQL 失敗時回退成 0這兩者都可能產生沒有依據的健康回報。display 改回 ok=nullstate=unknownnot probed設定值另放 configuredBackend未運行的 sandbox 標 inactiveok=null。整體 ok 只有全部元件明確 true 才為 true。這不影響原生工具 admission。
- jobs count 與 display backend DB 讀取失敗明確拒絕回覆不以零工作環境預設冒充當前資料operations 可用性改用 EXISTS避免為探測而計算全表總數。
- health 開始前核對 Computer owner/space 與 actor探測後在 transaction 核對並鎖定目前 bot assignment、owner/space、provider/generation/state、home/scope/kind/display backend。跨範圍請求不發起 transport期間變更拒絕舊結果。
- probe_computer_container 的 HTTP future 原先無總期限,現在在原 guest 5 秒 command timeout 外加入 6 秒 transport deadline。逾時是 Unknown沿用 boot 保留原 provider 的處理;不推斷程序已停止或寫入退役紀錄。
- 新 SQLxHTTP health regression 覆蓋未知 display、foreign owner/space、探測中 home/generation/binding/backend 變更、jobs 表不可用及 inactive sandbox。boot regression 加入實際永不回覆的 HTTP handler驗證有界返回 Unknown、provider/generation/running 保持、無 stop/destroy/provision。最終完整 API 209 passed4 ignored、API all-targets ClippyCARGO_INCREMENTAL=0、-D warnings及 diff check 通過。此輪未改 RunnerSupervisorUI使用真實 PostgreSQL 與 HTTP 故障測試,未重跑不變的容器與前端流程。
- 對應 O08O41O45T15T17。此次修正的是誠實回報、存取範圍與等待界線不把 unknown 當成完整 layered readiness下一步仍需實際 browserdesktopviewer scoped probes 與其復原流程。全部 P0P3 範圍維持,未部署。
## Computer-local 唯讀 runtime probes 與 Runner 程式傳送修正2026-09-11
- 新 runtime_health root 管理動作先核對 identityslot經受保護 Runner SQLite 初始化後,以 UID/GID 1000、乾淨 env、256 MiBFDCPU 限制執行固定 Python probe總期限 8 秒、成功 stdout 上限 4096 bytes。逾時spawn 錯誤正規化為 RUNTIME_HEALTH_UNAVAILABLE避免 TimeoutExpired 把 helper argv/source 放入錯誤。
- 未指派 slot 時 desktop/browser/viewer 均為 null不探測預設 :1slot 僅接受整數 07拒絕 boolean額外欄位。已指定 slot 時各項獨立desktop 核對 xdpyinfo 與 WM supporting window/namebrowser 核對對應 loopback DevTools discovery、協定與本地 websocket URLviewer 核對 vnc.html 及真正 WebSocket upgradeacceptbinary RFB greeting不只看 HTTP port。每次 HTTPX11 等待與資料量皆有界,不啟動任何服務、不輸出 browser 內容。
- 6 個 Python tests 覆蓋 discovery 壞資料foreign URL大小限制redirectviewer 假 upgradeaccept遮罩或過大 frame錯 RFB分段 greetingX11 沒 WM、無 slot 不探測及元件獨立性root timeout/spawn error 不洩漏 helper canary。正向 browser/desktop/viewer 此階段使用協定subprocess fixtures不宣告真實 ChromiumXFCEviewer session 已測。
- 新真實 root 容器測試確認 UID 1000 runner、有 slot 但未啟動 GUI 的結果、非法 body 拒絕,以及 jobsfile journaloutbox 筆數不變Supervisor HTTP fixture 另經 SDK 呼叫 runtime_health。API health endpoint 尚未接入這些結果,必須先接目前 screen assignment/profile 與前後 fence該 endpoint 仍保持未探測,不提前顯示新後端成功。
- 第一輪容器 gate 揭露既有 Runner bootstrap 把整份 Python source 放在單一 argv增加 probe 後跨過目前 Linux 的長度上限native file transport 出現 argument list too long。已改固定小型 bootstrapstdin 長度 frame程式最多 1 MiB以 unbuffered os.read 精確消耗 source保留剩餘 request bytes 給 exec程式以 root-private temp filefsyncrenamedirectory fsync 發布request管理 key 不存入該程式檔。
- 3 個真實 pipe/exec tests 驗證超過 128 KiB 的 UTF-8 程式、4093-byte 分段傳送、request 原 bytes 保留、request canary 不進程式檔、非法/截斷 frame 不替換旧程式,以及不受保護目錄拒絕。這些 tests 與 runtime probes 均註冊到 Docker gate。
- 6 probe tests、3 bootstrap tests、workspace all-targets Clippy 與 diff check 通過;修正後完整 Docker gate 通過17 root files、Supervisor HTTP runtime_health簽章恢復、既有 lifecycle 及 Team/Dedicated 正式啟動與退役恢復API 整合段 24.98 秒。本次 fixture 容器與 networks 已清除。對應 O08O41O45T17T64。仍需 API scoped 接線、真實 GUI/browser/viewer 正向及故障復原驗收P0P3 其餘範圍維持;未部署。
## health API 接入分項 runtime 證據2026-09-11
- control 增加嚴格 RuntimeReadinessObservation成功 code/status、4096-byte stdout、空 stderr、version 1、必要 nullable 欄位、型別、未知重複欄位、runner UID 證據及精確 slot 均檢查。無 slot 時 GUI 必須全 null有 slot 時每項必須明確 booleanfalse 不會拖成 Runner 不可用。傳輸錯誤正規化15 秒總期限,不回傳任意來源錯誤內容。
- component_health 只讀取目前 bot 自己的 ScreenRow先檢查 slot/display/view_port 對應,不以預設 slot 0 借用其他 bot 畫面;實際呼叫 Computer-local runtime_health回報 display/browser/viewer 獨立證據及 nativeReady。沒有畫面或探測失敗仍保留 null/unknownnativeReady 僅代表 Runner 探測成功,不代替原生工具的 quota權限 admission。
- 沿用 Computer owner/storage/provider/generation/assignment 前後檢查,並核對 screen identity、slot、display/view_port、profile mode/path、execution fence。探測中從無畫面變成有畫面、刪除、換 profile 或 fence 變更皆拒絕舊結果。這是 assignment 一致性,尚不表示已證明 Chromium 實際 process 的 profile 身分。
- 4 個 control readiness tests 與 SQLx真實 HTTP regression 通過,涵蓋 malformed evidence、外部 scope、Computer 變更、screen 新增刪除profile/fence 變更、分項成功失敗及 inactiveDB 失敗。真實 Team cold boot fixture 另加入 component_health→Supervisor→root Runner 驗證,不配置 screen要求 nativeReady=true、GUI null 且查詢後仍無 ScreenRow。完整 API 209 passed4 ignored、完整 Docker gate 通過,真實 API 整合段 26.06 秒本次容器network 已清除。其後檢查 SDK 發現 generic exec 會先完整讀入 response已對 runtime_health 加入 16 KiB 串流上限,非成功狀態不讀任意錯誤 body真實 chunked HTTP regression 證明超限及 503 在沒有 EOF 時仍立即拒絕且不洩漏 canary。此追加修正後 API health 回歸、SDK chunked test 與三個受影響 crates all-targets Clippy-D warnings均通過修正了測試未使用 socket read byte count 的 Clippy 問題diff check 通過。完整 Docker gate 執行於追加 SDK 串流限制之前,該限制另由上述真實 HTTP 測試覆蓋。
- 對應 O08O41T17。真實 ChromiumXFCEwebsockify 正向與故障復原及 P0P3 其他項目仍未完成;未部署。
## 真實 GUI readiness 與服務重啟驗證2026-09-11
- 新增 `make test-runtime-gui`scripts/test-runtime-gui.py在獨立隨機命名 Computer image 容器中執行 tests/runtime-probe-gui.test.pynetwork none、UID/GID 1000、1 GiB memory2 CPU512 pidsread-only fixture mounts、240 秒 host timeoutfinally 清除自己的容器。
- 使用真實 Xvfb :8、XFWM、持續 session D-Bus、Chromium about:blank9229、x11vnc5907與 websockify6087。驗證 cold 全 false、全部服務 true以及依序終止重啟 browser、websockify、RFB server、WM 的 8 個狀態;每個狀態保留 Runner true未受影響元件仍 trueNone slot 不借用存在的畫面。10 個狀態全部通過;最終版每次 probe 以獨立 Python -I 程序、正式 clean env、256 MiB AS20 秒 CPU64 FD無 core、8 秒 timeout4096-byte stdout 限制執行,重跑仍全數通過。
- 首次真實驗證找到產品 bugprobe GET /vnc.html但 image 僅安裝 index.htmlvnc_lite.htmlSupervisor 的正式 viewer URL 也是 vnc_lite.html正常 viewer 因而一直 false。已修正到 /vnc_lite.html協定 fixture 對其他未知路徑回 404避免寬鬆假 server 掩蓋同類問題6 probe tests 通過。
- 第二輪 WM 重啟 fixture 失敗原因為終止該 process group 一併終止其自動啟動的 session bus並非探測結果不實改獨立持續 D-Bus 後全部通過,保留失敗證據與分類。此次正向驗證涵蓋 WMCDP discovery實際 WebSocket-RFB greeting不涵蓋全部 XFCE services、Chromium page 操作profile process 身分、公開 viewer 登入/瀏覽器渲染、產品 ensure_screen 自動修復或整個 Computer 故障復原。
- 包含 root Runner source embedding 的完整 Docker gate 通過API 真實整合段 26.52 秒6 protocol tests、最終受限 probe 的真實 GUI 10 個狀態、Python compile 與 diff check 通過。測試容器networks 已清除。O08 等相關項仍 PARTIALP0P3 其餘範圍維持,未部署。
## 正式 ensure_screen 的桌面服務修復2026-09-11
- 找到 lazyboy-screen 兩個會略過修復的判斷ensure_slot 的 X serverVNCweb port 快速路徑直接回成功start_desktop 只看 panel PIDWMxfdesktop 死亡不處理。移除無鎖快速成功路徑,所有 ensure 在既有 per-slot flock 內走相同檢查start_desktop 分別核對 WMdesktoppanel僅補啟動缺失者且有界確認程序存活後才成功。
- alive_pidfile 僅接受正整數 PID排除 /proc state ZX桌面服務另比对實際 comm避免 zombie 的 kill -0 成功被當成正常服务。這不是完整 PID start-timedisplay identity 防偽,仍不宣告任意同 UID 程序隔離。
- 部分服務重啟重用既存 per-screen D-Bus address明確 address 存在才做有界 ping無 address 時直接建立新 bus避免 dbus-send 的隱式 autolaunch 導致沒有可傳給桌面程序的 addressPID。AT-SPI launcherregistry 僅在原 PID 不存活時補啟動。D-Bus 本身中斷且所有桌面 PID 尚存活的完整復原仍待驗證/補強。
- 新 make test-screen-recovery 使用同一 networkless disposable Computer harnessread-only mount 當前正式 lazyboy-screen。真實執行 ensure 7驗證 warm ensure 的 WMdesktoppanelCuaXvfbD-Bus 全部 PID 不變;分別終止 WM、panel、desktop 後,兩個並行 ensure 均成功,只更換故障服務 PID、其餘 PID 与 bus address 不變,實際 runtime probe desktop/viewer 恢復 true、未開 browser 保持 false。三種故障均通過fixture 容器清除。
- bash syntax、diff check、9 個 control screen tests、59 個前端 regression 通過。此次修改 image 腳本並以現行 image 加掛工作樹腳本驗證,尚未重建/部署 production image原完整 Runner gate 未重跑,因未修改其 root PythonRust 傳輸。O08T17 仍保持 PARTIAL尚需全 XD-BusCuabrowser 的正式自動復原、其他 display slot 並行及公開 GUI 完整流程。P0P3 原範圍不縮減。
## 兩畫面正式修復與 Cua 截圖驗收2026-09-11
- 擴充 test-screen-recovery使用正式 lazyboy-screen 同時 cold ensure slots 67displays :7:8各自固定獨立 browser profile、DevTools ports 92289229。此驗收 fixture memory 提升到 2 GiBprobe-only fixture 仍 1 GiB保留 network none2 CPU512 pids256 MiB shm240 秒總期限;不呼叫外部帳號或部署環境。
- 對 slot 7 依序終止 WM、panel、desktop、Cua、Xvfb、D-Bus、Chromium每次發出兩個並行 ensure要求故障 PID 更換、desktop/browser/viewer 全部 true。小範圍故障要求其餘 PID 不變XD-Bus 允許必要相依服務重啟D-Bus 故障要求新 address。七種故障全部通過。
- 每次復原都實際執行 cua-driver call start_session 與 get_desktop_state先刪除舊圖再確認新 PNG 產生;並非只核對 socket 或進程存在。每次亦核對 slot 6 的全部 PIDD-Bus address 不變且三項真實 probe 仍 true。Chromium 的 process title 正規化後精確比對各 profile path 與 DevTools port初版測試誤以為 Chromium 保留 NUL-separated argv已依實際 process-title 格式修正,未把該 assertion 當成產品跨 profile bug。
- 最終真實兩畫面七種故障Cua screenshotpeer unchanged 全數通過(/tmp/lazyboy-screen-two-displays-final.logPython compilebash syntaxdiff check 通過,測試容器清除。本輪主要補實測,不重跑未改動的 Rust前端。
- 這補上 O08T17 的正式腳本服務與兩畫面復原證據;仍非 API owner/screen leasecontrol epoch 全鏈路故障驗收,不包含公開瀏覽器登入 viewer 操作、AT-SPI 語意操作在 D-Bus 斷線後的完整恢復、全八畫面資源公平性或所有 display backend。各完整項目仍 PARTIALP0P3 範圍維持。
## API screen startup 授權與回覆驗證2026-09-11
- ensure_bot_screen 開始時在 transaction 鎖定目前 Computerbot核對 actor owner/space、bot assignment、provider/generation/running、home/scope/kind/profile mode/execution fence配置與 per-task profile 更新亦在該 transaction 執行,不再先對任意 captured Computer 建立 ScreenRow。Computer row lock 亦序列化 slot 配置;移除不再使用的非交易 list_screen_slots helper。
- capabilities 失敗不再默認 multi_screen=true5 秒期限screen adapter context 補 captured generation所有 busy retries 共用 90 秒期限。Provider 回傳 slot/display/view port 必須符合 captured row啟動後再核對並鎖定 Computer/bot 與 screen identitymappingprofileexecution fence變動時拒絕舊結果。
- SDK 原先缺 slot/display/viewPort 時使用 request slot:16080並將過大 integer cast 截斷;改 serde required typed fields、alias view_port、精確 layout 比對,拒絕 ok=falseduplicate fieldoverflow缺欄位。成功及失敗 body 均限 16 KiB 串流讀取,僅保留 busy starting 可重試分類,不回傳任意 guest error body。新增 serde workspace dependency。
- 新 SQLx真實 HTTP regression 通過foreign actor 不送 RPC、不建 screen正常配置成功RPC 中 generation/home/bot assignment/profile/screen fence/computer fence 變動、screen 刪除及錯誤 slot 回覆皆拒絕。SDK decoder regression 通過。完整 API 210 passed4 ignored、完整 sandbox SDK 13 tests、affected all-targets Clippy-D warnings通過diff check 通過。
- 本次是中央授權與結果 fence不等於 guest 端已阻止所有在途過期副作用restore_computer_screens 的其他 bot 恢復路徑仍需套用同樣核對control epoch/lease 的全鏈路與自動修復授權仍未全部完成。P0P3 原範圍维持,未部署。
## 其他 bot 畫面恢復的授權與指派核對2026-09-11
- 抽出 validate_screen_assignmentensure_bot_screen 與 restore_one_screen 共用 Computer/bot owner、provider/generation/storage/profile mode/execution fence以及 ScreenRow identityslot/display/portprofileexecution fence 核對;另在 RPC 前拒絕不合法 slot/mapping。
- restore_computer_screens 不再把 get_bot 的 None 當空名稱繼續啟動。每個恢復先驗證目前授權與指派,送出 captured generation 及原 ScreenRow profile核對 adapter 回覆後再次驗證;其他 bot 的恢復共用 90 秒期限錯誤明確記錄並繼續適用的其餘項目timeout 結束本批。
- 擴充 SQLx真實 HTTP regression正常 per-task 恢復沿用 original-task profileforeign actor解除 bot 指派在 RPC 前拒絕,呼叫數不變;恢復中八種 generation/home/binding/profile/fence/delete/wrong-slot 情境均拒絕舊結果。focused regression、最終完整 API 210 passed4 ignored、API all-targets Clippy-D warnings及 diff check 通過。
- 此次補上中央恢復路徑,仍不宣告 guest 已阻止所有在途 stale epoch 副作用;真正 guest 層 lease/epoch admissionbarrier 與完整公開 GUI 流程仍待完成。未改 Supervisorimage未部署P0P3 原範圍維持。
## GUI context 傳遞鏈與結構檢查2026-09-11
- 查出 AdapterContext 雖有 screen_idscreen_lease_idcontrol_epochSDK 原先未傳送API adapter_context_for 亦未設定 epoch。現以 captured ScreenRow execution_fence 傳送 control_epochSDK 保留 screen ID、lease、run、generationAPI SQLx HTTP regression 實際核對 screen ID 與 epoch header 等於配置資料。這個 epoch 尚非 X restart/service epoch。
- Supervisor screens route 在 master token 驗證後核對必要 context單一 header、合法 bot/screen reference、正 generation、有界非負 epoch、slot/display layout 以及 body/profile 一致;拒絕 missingduplicateoverflowidentity mismatchoptional lease/run 若存在也須有效格式。兩個 Supervisor tests 包含 SDK→真實 HTTP→同一 validator 的成功與拒絕情境。
- SDK 的 header builder 改回傳 Result所有呼叫傳遞錯誤原先 space/bot/token 解析可能 panic、display/profile 解析失敗被略過,現在無法編碼的身份均以 INVALID_ADAPTER_CONTEXT 拒絕,不洩漏原值,不以移除 header 降級到預設畫面。14 SDK tests 通過,包含 epoch/lease 保留及非法 lease/display/profile。
- 最終完整 API 210 passed4 ignored、14 SDK tests、2 Supervisor context tests、affected all-targets Clippy-D warnings及 diff check 通過。這是身份傳遞與結構檢查,**不是**目前 epoch/lease 授權或持久化 stale request admissionSupervisor code 亦明註必須由 Runner 對 durable state 核對。guest 層阻擋與 pause acknowledgment/barrier 等仍未完成P0P3 原範圍維持;未部署。
## Runner GUI durable fence 基礎2026-09-11尚未接入 GUI 執行)
- 新 runner_gui_fences.py 提供 root-only SQLite/WAL/FULL 狀態,保留 provider/generation 與各 slot 的 screen/bot/epoch/lease/expiry/pausedroot-private directory/file/no-follow/hardlink 檢查。generation 只能前進,相同 generation 不可換 provider相同 epoch 不可換 owner/screen/lease/paused舊 epoch 拒絕重播不縮短既有期限。admit 本身不建立或推進任何授權。
- generation publication 使用全域 exclusive flock一般 display admission 共享 generation lock 並独占本 slot lock其他畫面仍能 admitpublish。所有 lock waits 有界scope 更新必須等該 scope 執行 guard 退出generation 更新等待全體;等待後再檢查發布授權是否已到期。執行時不持有 SQLite transaction。
- 不能把 kernel lock 在 process crash 後自動釋放當成 quiescenceadmit 先 durable INSERT active intent再交給 executorexecutor 必須明確 confirm_quiescent 才刪除。例外、程序被 kill、未明確確認或完成 DELETE 失敗均留下 unresolved拒絕同 scope 新 admissionepoch 與 generation publication。其他 slot 可繼續。active 狀態最多 8 slots不依逾時自動清除。
- 11 個 root fixture tests 通過missing/forward/stale identity、DB reopen 後 generationowner 高水位、pause/resume、expiry與重播、真實跨程序鎖與 peer 並行、process kill、exception、正常返回未確認、SQLite generation rollbackintent insertcompletion delete fault、等待期間 expiry、UID 1000 真實子程序拒絕、root directory/file/symlink 與 malformed claims。已加入 make test-gui-fences 及既有 Runner gate 的 host checksPython compilediff check 通過fixture temp state 自動清除。未重跑未改動的 RustDocker/GUI 整合。
- **此模組尚未由 Runner bundleGUI 路由呼叫,不宣告部署中的 stale GUI 已被阻擋。** 下一步需:中央 display epoch 跨 ScreenRow 刪除/重新指派仍單調(目前 execution_fence 重建可能回 0不能直接當永久 slot epoch只由已驗證 management publication 更新狀態,普通 GUI 請求不可自升 epochexecutor 持續保有 guard、遵守 expiry deadline 並驗證 quiescencecrash unresolved 須由可信 processprovider retirement proof 恢復不能直接刪除API pause/takeover 等待 root barrier acknowledgement 才授予控制。
- 對應 O27T41T56 與 scoped fencing 契約。這是可測的持久化基礎與接線前必須滿足的條件GUI 全鏈路、agent/Computer 分層整合及 P0P3 其餘要求維持未完成,未部署。
## 中央 display epoch 跨指派單調性2026-09-11
- migration 039 新增每 Computer/slot 的 computer_display_epochs 高水位及 ScreenRow.display_epoch BIGINT刪除 ScreenRow 留下 counter 並推進 tombstone重新插入換 owner 不可從 0 重用。配置透過 counter row 的 ON CONFLICT UPDATE 鎖序列化,避免先取 sequence 後等待舊交易造成較舊 epoch 晚提交。Computer 父項刪除仍可 cascade不把被刪除父項重新插入 counter。
- trigger 在 profile、identity/mapping、control holder/lease、execution run/fence、lease 縮短/清除及顯式 bump 時配置新 epoch純 updated_at、no-op、相同 lease 延長不撤銷目前 epoch。外部傳入的 display_epoch 不直接採用;跨 slot 移動推進舊/新 counter使用固定 counter 順序。
- API adapter context 改送 display_epochScreenRow 讀取、啟動restore 的前後核對及 health snapshot 一併接入。SQLx HTTP regression 增加只更新 display_epoch 的第九種在途變更,舊結果拒絕。
- 兩個新增 SQLx tests 通過:真實舊 schema 資料 backfill包含 execution_fence=2147483647升為 2147483648rollback/delete/recreate/move/expiry renewal/shortening/manual reset 與 parent cascade透過 pg_stat_activity 確認 replacement INSERT 正在等 slot lock另一 slot 可更新,刪除提交後 replacement epoch 大於 tombstone。
- 最終完整 API 212 passed4 ignored、API all-targets Clippy-D warnings及 diff check 通過。僅操作 SQLx disposable DB未對部署資料套 migration未部署。
- 高水位是配置器,不是已送达 Runner 的 barrier receipt必須先提交中央 epoch/reservation 才能向 Runner 發布;無法把回滾交易中取到的 epoch 對外發布。Runner 管理發布、GUI executor guard/expiry/quiescence、未明效果恢復及中央 pause acknowledgement 仍待接線。P0P3 完整範圍維持。
## Root GUI 簽章發布接收與 profile 綁定2026-09-11
- runner_gui_fences 已嵌入正式 root Runner bundle新增 gui_fence_publish handler。Supervisor 只在此操作透過 root stdin 私有欄位傳入依實際 home label 派生、與 file retirementcontrold token 分離的 HMAC key一般 exec 輸入不能自行簽章。Root 驗證精確 schema、重複 JSON 欄位、audience/home/provider/bot/generation、60 秒發布授權、最長 5 分鐘 scope lease鎖等待後再驗證授權期限成功才回傳不含 key簽章的 receipt。
- claim 與 durable screen/active intent 加入 profile。相同邏輯 profile 跨 slot 的 active effect 互斥;不同 profileslot 仍可並行,穩定 generation 的 scope publication 不誤取全域 exclusive lock。舊 schema 缺 profile 的 active intent 保守阻擋,不自動清除;舊 screen 需要較新 epoch 才能重新綁定。profile 目前為嚴格邏輯路徑,尚非 filesystem inodesymlink alias 身份證明。
- 14 個 host fence tests 通過,涵蓋原真實 process killSQLite faults新增 profile 排他平行、legacy migration、簽章時間identityschema 拒絕。真實 SDK→Supervisor HTTP→root Runner 驗收用 fixture-only signer驗證有效 publication、竄改 MAC 明確 INVALID_GUI_PUBLICATION、合法簽章舊 epoch 明確 STALE_GUI_EPOCH且回覆不含管理 key。測試曾誤把 SDK transport error 當 CommandResult已依實際契約修正並要求精確拒絕原因。
- 最終完整 Runner gate 通過(/tmp/lazyboy-gui-publication-gate-verified.logAPI 真實恢復整合 25.54 秒Supervisor all-targets Clippy -D warnings 通過(停用 incremental、Python compilediff check 通過。成功 gate 自有容器network 已清除,未部署。
- 目前完成的是受簽章保護的接收端;正式管理 issuerAPI durable publication intent、GUI executor admission guarddeadlinequiescence、boot/service epoch 與可信 unresolved recovery 尚未接入。generation 與 scope 分兩次 commit失敗可留下較新 generation不能把未取得完整 receipt 當成功;中央 pause/takeover 仍必須等待 root barrier acknowledgement。O27 保持 PARTIALP0P3 全部原定範圍維持。
## 正式 GUI 管理簽發與回執核對2026-09-11
- 新 GuiFenceClaimGuiPublicationRequestGuiPublicationReceipt 契約及 SandboxProvider.publish_gui_fence 專用方法,未支援 provider 明確拒絕,不透過一般 execute 模擬簽發。請求核對合法 identity、slot、profile、5 分鐘 lease 上限,以及完整 AdapterContexthome 綁定;呼叫者仍必須先提交並授權中央 epoch。
- 新 master-authenticated POST /computers/{id}/gui/publish16 KiB body 限制;逐一核對 bot/screen/generation/epoch/slot/profile/lease/display header拒絕重複或不一致。Supervisor 再核對實際 container home label由管理端派生專用 key、產生 60 秒 HMAC publication經既有私有 root 通道送出;不接受 caller envelope 或 key。
- Supervisor 與 SDK 均核對 strict typed receipt、完整 claimpaused有效 expiry不將其他 scope 或舊 epoch 回覆當成功SDK 15 秒總期限,回覆串流上限 16 KiB。任何未取得有效 receipt 的呼叫不能視為已交接;特別是 timeout 可能發生在 durable publication 之後,中央必須保留 intent、重試原 epoch不假定回滾。
- 159 個 control tests、15 個 SDK tests 與 affected all-targets Clippy -D warnings 通過。新增 SDK 真實 HTTP fixture 驗證有效 receipt以及 wrong epoch/profile/paused、expired、published=false、未知欄位與不結束的過大 chunked response 拒絕,錯誤不洩漏 response canary。
- 真實 disposable Computer 的 SDK→正式 Supervisor signer→root receiver 驗證發布、重送相同 receipt、較新 epoch pause以及 SDK context mismatch、HTTP missing auth/context、錯誤 home 和舊 epoch 拒絕;原 fixture-only signer 的有效/竄改/舊 epoch 接收測試保留。管理 HTTP 段通過4.14 秒)。
- 尚未接中央 API durable publication intent背景 retrypause acknowledgement也尚未由 GUI executor 持有 root admission guard不能宣告部署中的 stale GUI effect 已全面阻擋。boot/service epoch、unresolved recovery 與 P0P3 其餘完整要求維持未完成,未部署。
- 最終完整 Runner gate 通過(/tmp/lazyboy-gui-issuer-gate.logAPI 真實恢復整合 26.34 秒);本輪 fixture containersnetworks 已確認清除,最終 diff check 通過。
## Agent 暫停狀態與 display epoch 同交易更新2026-09-11
- 檢查中央 GUI publication 前置條件時發現agent_mutation_barriers 的 paused 改變原先只推進 agent epoch不更新 ScreenRow.display_epoch。Root GUI publication 將 paused 綁定同一 display epoch因此先後發布不同 paused 值會形成衝突;只修簽发/重試不能解決。
- migration 040 新增 agent barrier 的 INSERTUPDATEDELETE trigger只有實際 false↔true 變化才透過既有 039 counter allocator 推進該 bot 的全部 display epochs與中央 barrier 寫入同一交易。初始 false、重複 truefalse 不推進;刪除 paused barrier 及 bot_id 移動亦正確失效舊/新 bot scope。其他 bot 的獨立 display 不受影響。升級時既有 paused bot 的 display epoch 也會推進。
- 新 SQLx regression 覆蓋正式 set_agent_barrier helper、直接 SQL、重複狀態、交易內新值交易外未提交值不可見、rollback 保留原 epoch、pause/resume/delete、barrier bot 移動、counter 與 screen 一致,以及真實 populated pre-040 schema migration backfill 僅推進已 paused peer。
- 最終完整 API 213 passed4 ignored/tmp/lazyboy-agent-display-barrier-api.log27.39 秒API all-targets Clippy -D warnings、diff check 通過。只操作 SQLx disposable databases未對部署資料套 migration未改 root GUI 程式或重新執行 Docker gate。
- 這是中央 epoch 原子性修復,仍不是 root 已確認停止交接的證據API durable publication intentretryacknowledgement 與 GUI executor guard 尚待接入。P0P3 全部原定範圍與 O27 PARTIAL 維持,未部署。
## 中央 GUI 發布意圖與啟動畫面接線2026-09-11
- migration 041 新增 gui_publications保存不可由 transport error 刪除的精確 request、pendingacknowledged、receipt 與確認時間。啟動畫面及其他 bot 的畫面恢復均呼叫新 publish_screen在鎖定目前 owner/bot/Computer/ScreenRow identity 與 display epoch 後保存意圖commit 後才送專用 provider publication網路期間不持有 DB transaction。
- 發布 claim 使用 captured generation/display epoch/profile/execution runpaused 由目前 agent barrier 或 human holder 決定;一般期限 120 秒,執行中 run 另受 execution lease 上限限制。重試重用相同 claim/home/paused 且仍有 30 秒期限的既有精確意圖,不因回覆遺失建立另一個同義請求;過期歷史 pending 不自動刪除,每 Computer/bot 最多 1024 個 unresolved。acknowledged 歷史 retention 與 expired pending 的可信收斂仍待完成。
- provider 回覆後重新鎖定並核對目前指派,等待 DB lock 後再次檢查 expiry只有完整 typed receipt 匹配且 intent UPDATE 恰好一列,才同交易保存 acknowledged。途中 pause 的 migration 040 epoch 變更使舊回覆拒絕;未收到有效回執或 DB 寫入失敗仍保留 pending。
- SQLx真實 HTTP fixture 驗證foreign actor 不發布handler 收到請求時 DB intent 已提交502 後重用同一 id/request發布途中中央 pause 不被 DB/network lock 阻塞,舊 acknowledgement 拒絕receipt UPDATE trigger 故障回滾保留 intent重試成功。既有 startuprestore 授權與九種在途指派變更測試仍通過。FakeSandbox 新增明確 transport-only publication fixture不把它當 root lockingcrash 證據。
- 最終完整 API 214 passed4 ignored/tmp/lazyboy-gui-central-api-tests.log28.45 秒、15 SDK tests、affected all-targets Clippy -D warnings 及 diff check 通過。僅 SQLx disposable DB未套用部署 migration。
- 此次是 startuprestore 的前置發布與 request-driven retry背景 retry、中央 pause/takeover 等待 root acknowledgement、GUI executor guarddeadlinequiescence、boot/service epoch 及完整人類輸入管制尚待接線。P0P3 全部原定範圍與 O27 PARTIAL 維持,未部署。
- 真實跨程序完整 Runner gate 亦通過(/tmp/lazyboy-gui-central-gate.logAPI 整合 26.62 秒):由正式 boot_for(false) 重建的 Dedicated Computer中央保存意圖後經正式 signer 到 root 成功發布proxy 僅丟棄第一次已成功回覆;中央先維持 pending第二次以同一 intent id精確 request 取得有效 receipt 並 acknowledged實際 publication RPC 共兩次。此測試不啟動 GUI effect也不代替 GUI executor admission 驗收。自有 fixture containersnetworks 已確認清除。
## GUI publication 背景重試與原始 actor 綁定2026-09-11
- API startup 新增 retry_loop每輪至多取四個 due scopes每 Computer/bot 一個候選SKIP LOCKED 避免被別的交易持有的 intent 卡住retry_after 30 秒 claim/backoff 在 migration 042 持久化query 5 秒/單筆 delivery 20 秒provider 15 秒上限,最多四筆並行,輪間 2 秒。這是 delivery 排程,不延長原 GUI lease不自動建立新 publication。
- foreground 與 background 共用 deliver發送前與回覆後核對目前 Computer/bot/ScreenRow assignment發送前另核對原 claim/context、paused、run lease 上限及精確已提交 intent。背景僅處理原 request 未過期者,過期與未明歷史保留 pending不把 expiry 當作 quiescence。
- migration 042 另保存原 owner_user_idowner_space_id。發送與 ack 都核對此 proof防止把舊 intent 以後來的新 owner 身分重送。舊 schema 的 intent 缺 actor proof 時保持 NULL、不由目前 owner 推定補值background 排除;新的 explicit startup 可保存目前合法 actor 的新 intent。
- SQLx HTTP regression 改由背景批次完成 lost response 與 DB ack fault 後的原 request 重試;驗證舊 epoch 不發 RPC、過期缺 actor proof錯誤 owner 不重送且 pending 不刪。新增六 bot 的 bounded batch 測試:另一交易持有 intent lock 時,其他四 scope 先成功,其餘 scope 繼續;解鎖後才完成原 scope。這是批次與鎖行為證據不代表任意大量歷史 backlog 的公平性已驗收。
- 完整 API 215 passed4 ignored/tmp/lazyboy-gui-retry-api.log30.87 秒、API all-targets Clippy -D warningsdiff check 通過。真實完整 Runner gate 通過(/tmp/lazyboy-gui-retry-gate.logAPI 整合 26.32 秒root 成功 publication 回覆被 proxy 丟棄後,由 retry_batch 讀取同一 durable intent、透過正式 signer 重送並取得 ack未重新呼叫 startup 產生 authority。重用未改動的已建 controld fixture image測試自有 containersnetworks 已確認清除,未部署。
- 後續仍需改善大量同 scope 舊 pending 的 current-intent 優先序與掃描成本(目前依 due/created 排序,不能把小型六 bot 測試當作大 backlog 無飢餓證明);過期/缺 proof pending 的可信收斂與 acknowledged retention 尚缺。中央 pause/takeover 等待 root acknowledgement、GUI executor guarddeadlinequiescence、boot/service epoch 與完整人類輸入管制仍待接線。P0P3 原定完整範圍維持O27 仍 PARTIAL。
## GUI retry 排除過時 backlog 與 Computer 授權快照2026-09-11
- 修正背景候選只按 due/created 排序的缺口:同 scope 大量尚未到期但已過時 epoch原先可能逐筆占用批次令目前有效 intent 等到過期。候選現在先 join 目前 Computer/bot/screen核對 owner/space、running、home、完整 claim、paused 及 execution lease 上限;過時記錄不取得 retry claim也不刪除。真正送 RPC 前/後仍保留交易內授權重查,不以候選快照替代 fence。
- 同時補上原 request 尚未保存的 Computer 授權狀態migration 043 新增 computer_authority JSONBscope/kind/browser_profile_mode/execution_fence。reserve、重用、發送、ack 与背景候選均核對原快照,避免 Computer fence 或 profile mode 已變更後,背景 worker 以新 ComputerRow 重送舊授權。歷史缺快照保持 NULL不推定 backfill須新的 explicit request。新增 current claimexpiry partial indexes將具原始授權的 pending 查詢與歷史資料區分。
- SQLx 六 bot fixture 加入 900 筆較早、仍未到期的舊 epoch 與 100 筆過期 intent持有有效 intent 的外部 transaction lock 時,其餘四 scope 於 3 秒測試期限內完成,下一個有效 scope 繼續,解鎖後完成原 scope全部 1000 筆 obsolete pending 原 retry_after 未變且仍保留。這驗證指定 backlog 下不占用候選,尚非任意量級/全 provider 公平性保證。
- HTTP fixture 另驗證缺 Computer snapshot、Computer execution_fence 變更、browser_profile_mode 變更均不發 RPC原 ownerexpiredlost replyack DB faultconcurrent pause 與 exact request retry tests 保留。
- 完整 API 215 passed4 ignored/tmp/lazyboy-gui-backlog-api.log30.75 秒、API all-targets Clippy -D warningsdiff check 通過。完整真實 Runner gate 亦通過(/tmp/lazyboy-gui-backlog-gate.logAPI 整合 25.82 秒),包含原 root 成功 publication lost reply 後的 background acknowledgement中途 UI 誤按中斷未重啟仍在執行的 gate確認原 handle terminal 後收集結果。自有 fixture containersnetworks 已確認清除。未套用部署 migration未部署。
- 大規模全域吞吐公平性量測、pending 可信收斂與歷史 retention 仍需完成;下一步仍是 GUI executor admission guarddeadlinequiescence 與 pause/takeover acknowledgement全 service epoch人類輸入任意 shell 隔離亦未完成。P0P3 全部範圍維持O27 仍 PARTIAL。
## GUI transport target 綁定修復2026-09-11
- 接 GUI executor guard 前查出 routing 缺口Supervisor act 允許 body display/profile 覆蓋 header targetbrowserrecording 在 body-only target 情況又可能由 header/default target 決定另一畫面。新增共用 checked_gui_targetbody/header 同時存在必須相同slot/display 必須符合既有八畫面 layout明確 empty非法 display/slot/profile control characters 拒絕,不默默降到 primary。無 target 的既有 primary fallback 保留,這不是授權成功證明。
- Supervisor 及 controld 的 act/browser/recording start/stop/collect 均先呼叫 strict header wrapper拒絕重複 display/profile/slot header包含相同重複值再使用一致 targetcontrold 不再在這些路徑以 header precedence 隱藏 body 衝突。profile 在此僅檢查 transport 結構與一致性,合法 filesystem scope實際 inode 身分仍由後續 admission 契約處理。
- 160 control tests、15 SDK tests、兩個服務的 header regression 與 affected all-targets Clippy -D warnings 通過Python compilediff check 通過。
- 新 disposable tests/gui-targets.test.py 啟動本轮重新編譯的實際 controld對五個 GUI 路由測 display/profile mismatch、重複 display/profile 及 slot mismatch共 25 cases 全部得到 route 層的精確 400 Bad Request結束後回收該 fixture daemon。新增至完整 Runner gateSupervisor HTTP fixture 同時增加五個路由拒絕 conflict 的驗收。
- 此次沒有將普通 HTTP 成功當作 quiescence也尚未接 root GUI executor guard。現行 Computer start 會以 lazyboy UID 啟動 controld任意同 UID shell服務身分与可信 completion 邊界仍需補強executor 在 timeout/斷線時不得自動 confirm_quiescentpause/takeover 必須等可信 root barrier ack。P0P3 所有原定範圍維持,未部署。
- 最終完整 Runner gate 通過(/tmp/lazyboy-gui-target-gate.logSupervisor HTTP 4.11 秒、API 真實恢復整合 26.92 秒),包含實際 controld 25 種拒絕案例及 Supervisor 五路由 conflict 拒絕。自有 fixture containersnetworks 已確認清除。
## Cua 未明呼叫不再自動重開 session 放行2026-09-11
- 查出 CuaClient 在 mutation timeout 後,下一次 mutation 會 remove suspect marker 並嘗試 start_session即使 driver 拒絕或其他錯誤,也可能丟失 marker。新 sessionHTTP 可回覆都不能證明舊 driver input 已停止,因此移除此自動修復放行。
- 新 CuaClient 本地 MutationGuard 共用八個 per-display mutex單次 admission 等待上限 5 秒;進入執行後如果 timeout、outer future 被取消或不明 transport/driver outcomeDrop 在釋放 lock 前保存 unresolved marker。新 mutationstart_session 對同 display 返回 EffectUnknown其他 display 繼續。只取消尚未取得 guard 的等待者、不曾啟動的缺失 driver以及正常完成的已知結果不留下 false unresolved。
- Read path 若遇到 session ended、需要 start_session也必須取得同樣 mutation guard不能以 read 名義清掉未明 writer。一般讀取沒有新增 writer lock。delivery-mode escalation 限制為已知 semantic refusalbusytimeout、DriverUnhealthy、Internal、EffectUnknown 等不再因 recommended delivery 而重送。controld 將 EffectUnknown 回傳 409。
- 164 個 control tests、2 個 controld tests 與 affected all-targets Clippy -D warningsdiff check 通過(/tmp/lazyboy-cua-unresolved-verified-tests.log。新增測試包含共享 client 的真實 task abort、等待者取消、peer display、不存在 driver、未知 outcome 不 escalation另以隔離暫存 fake CLI 啟动真實子程序,等待其讀完 request 後取消,確認 CLI PID 已消失仍不允許 start_sessionpeer 的兩次正常 call 都成功。此 fixture 只測真實程序transport cancellation不是實際 GUI input 完成證明。測試 script 的第一版 Rust 引號錯誤已修正,最終重新編譯/測試與 Clippy 通過。
- 完整 Runner gate 通過(/tmp/lazyboy-cua-unresolved-gate.logAPI 真實恢復整合 26.70 秒),重新建置 controld fixture原實際 GUI target 25 casesSupervisor HTTPnative/MCP/retirement 與 publication retry gate 保留。測試自有 containersnetworks 已確認清除,未部署。
- **這是目前 controller instance 內的防護,不是 root durable GUI executor guard。** marker 仍在記憶體,跨 controller instanceprocess restart 不保留,也未提供可信退休 proof 的清除流程;跨 profile 排他、整個 multi-call GUI operation guard、同 UID shelldaemon authenticity、server-side human input、pause/takeover barrier 仍需完成。不可把 CLI 已退出/一般 HTTP 成功當成遠端 GUI effect quiescence。P0P3 原範圍維持O27 PARTIAL。
## GUI 觀察與健康路由的 target 驗證2026-09-11
- 延續 O26O27O46 檢查,修正 controld observecontroller health 仍使用寬鬆 display fallback 的缺口,以及 Supervisor observe 未使用同一 strict target validator 的差異。三個路徑現在拒絕明確空值、非法或遠端 display、重複 target headers 與 slot/display 衝突,使用已驗證的 display/profile 建立 context未指定 target 時保留既有 primary 行為。TeamDedicated 共用相同檢查,不改 assignment 或資料。
- 擴充 disposable controld HTTP fixture兩個觀察健康路由各增加 7 種拒絕案例,合計由 25 增為 39Supervisor 真實 HTTP fixture 增加 observe 空/非法/遠端 display 與重複 header 拒絕。這些案例驗證路由在 backend 前返回 400不等於實際 GUI effect 或 admission/quiescence 驗收。
- 兩個服務共 3 個 headererror regression tests、affected all-targets Clippy -D warnings、Python compile 與 diff check 已通過。完整 Runner gate 以重新建置的 controld 通過(/tmp/lazyboy-gui-read-target-gate.log39 種實際 controld HTTP 案例、Supervisor HTTP 4.07 秒、API 真實恢復整合 26.26 秒;原 native/files/MCP/publication retry 驗證保留。自有 fixture containersnetworks 已確認清除。
- 回滾可還原這三個讀取路由的 target 選取及新增 fixture未部署。root durable executor、可信完成退休 proof、pause/takeover acknowledgement 與全部尚缺 P0P3 項目持續保留,下一步檢查 cursor configuration 的 timeout 是否被忽略而繼續 mutation。
## Cua 游標設定未明即停與使用量暫停交接2026-09-11
- 修正 configure_cursor_motion 的 500 ms timeout不可解析回覆driver timeout 原先被忽略且寫入 cache隨後繼續 click 的問題。現在返回 Result未知結果向外傳遞既有 MutationGuard 保存 unresolved不送後续 input、不 cache 未明設定。session restart 後的設定同樣傳遞錯誤。已知 semantic refusalbusy 的 optional setting 保留相容 cache 行為。
- 真實 fake CLI fixture 驗證 timeout、malformed、structured timeout 三種失敗只收到 set_agent_cursor_motion下一次 click 得 EffectUnknownunsupported 設定可正常連續兩次 click 且只設定一次。這是本地 transport 證據,不是遠端 GUI quiescence也不改變 root durable executor 尚未接線的狀態。
- 最終 165 control tests2 controld tests 通過(/tmp/lazyboy-cua-motion-tests-final.logClippy 最初報 collapsible-if已改成同語意 let-chain最終 affected all-targets -D warnings 通過(/tmp/lazyboy-cua-motion-clippy-final.log。容器 gate 使用該純語法整理前的同語意 runtime snapshothost 最終測試Clippy 覆蓋整理後 source。
- 使用者表示剩約 10% 使用量,要求列已做/未做並收尾等待。已新增 [暫停交接文件](agent-computer-handoff-2026-09-11.md),逐項保留 O01O48 状態、完整待辦與操作交接;不再開新功能。已啟動的完整 Runner gate 完成後補記,工作樹保留未提交,未部署。
- 收尾完整 Runner gate 已通過(/tmp/lazyboy-cua-motion-gate.logSupervisor HTTP 4.19 秒、API 整合 26.82 秒);本次 fixture containersnetworks 已確認清除,所有測試 handle 結束。最終 diff check 通過,依使用者要求暫停等待恢復,不啟動下一個實作。