Skip to Content
變更紀錄

變更紀錄

這份手冊對準 teamsync-backend origin/master。

釘選值
Commit172a7f80bdf4dbdffdc018eb08bfa42c62bb485c — v5.21.0 版本提交(tag v5.21.0)
Subjectchore: bump version to 5.21.0
Date2026-10-08 (Asia/Taipei)
租戶 routersrc/routers/private/modules/sandbox/
公開目錄src/routers/public/info/server.py(GET /public/info/sandbox/{regions,profiles})、src/routers/public/sandbox_artifacts.py(GET /public/sandbox/artifacts/{token})
共用 schemasrc/schemas/sandbox.py、src/schemas/enums.py
常數src/components/sandbox/constants.py、src/components/sandbox/storage.py、src/components/sandbox/input_schema.py、src/components/sandbox/secrets.py
Providersrc/components/sandbox/providers/(SANDBOX_PROVIDER 切換;onprem/ 的區域、計價 tier 與佇列上限)、地端 executor src/workers/sandbox_onprem/
Operator root(僅供參考)src/routers/root/sandbox.py
Agent 工具src/components/tools/custom/sandbox/
Triggersrc/crud/custom_table_triggers.py(submit_sandbox_job)
Writebacksrc/crud/sandbox/writeback.py
Command 輸出src/crud/sandbox/command_output.py;公開路由 POST /public/module/custom_tables/callback/command-output/{token_id} 在 src/routers/public/custom_tables_callback/server.py
通知src/crud/sandbox/notifications.py
Runner/建置路徑sandbox/runner/、sandbox/build/(Go runner + Cloud Build compose/scan 路徑)
控制面基礎設施infrastructure/sandbox/gcp/、infrastructure/app/gcp/k8s/base/sandbox-controller-*.yaml

頁面與那棵樹不一致時,以後端為準。重新稽核就從這個 SHA diff 那些路徑。

2026-10-08 — release v5.21.0

**來源與上線:**後端 172a7f80bdf4dbdffdc018eb08bfa42c62bb485c 為 v5.21.0 版本提交(tag v5.21.0,chore: bump version to 5.21.0,2026-10-08 11:07 UTC = Asia/Taipei 19:07)。這是 v5.10.11 之後的第一支釘,所以本則檢視 70862ceae7..172a7f80bd 範圍內 1,848 個 commit 中的 111 個:碰到下方「如何更新這支釘」指令所列路徑的 71 個,加上碰到路徑含 sandbox 的檔案、或訊息提到 Sandbox 的另外 40 個。它們幾乎都屬於其他模組;有五個改變了 Sandbox 契約。下列內容都讀自已發布的樹。本則沒有呼叫任何已部署的 API,所以沒有可引用的 production info.version 讀回結果。日期用 Asia/Taipei。

任務輸出可以執行自訂表格 Command

output_policy 現在是以 kind 區分的聯集型別。除了表格 writeback(custom_table_writeback),部門擁有的任務版本現在可以宣告 { "kind": "custom_table_command", "command_id", "chatroom_id", "input_schema" }。該版本的每一次 run 會透過既有的 TEAMSYNC_CT_WRITEBACK_URL/TEAMSYNC_CT_WRITEBACK_TOKEN 變數收到一把在提交時鑄出的密封、限於單次 run 的憑證(若認領時無法揭露,run 會在沒有這兩個變數的情況下啟動),這兩個變數現在指向公開端點 POST /public/module/custom_tables/callback/command-output/{token_id}。work script 送出 { "inputs": { … } },平台就以 run 的提交者身分,在那一個聊天室裡,執行那一個 Command,每次 run 最多一次:第一份有效輸出勝出,端點會回 404/409 output_run_unavailable、409 output_command_stale、409 output_command_conflict、422 output_schema_violation、403 output_policy_author_denied,或 Commands API 自己的錯誤。

這個 policy 會在草稿建立/更新(422 output_policy_command_not_found、422 output_policy_schema_mismatch、403 output_policy_author_denied)、發布(任何一項 Command 檢查失敗都是 409 output_policy_unsatisfiable;對發布者與已記錄撰寫者的身分、grant 與範圍檢查仍是 403 output_policy_author_denied),以及每一次提交 run 時檢查。和表格 writeback 不同,不合格的 run——borrowed 的房間、政策指定房間以外的房間、API key/受限金鑰/社群 client 的提交者,或撰寫者或提交者沒有該 Command 的 grant——會被拒絕,回 403 output_policy_author_denied,什麼都不會排隊。自訂表格 trigger 現在可以對準這種版本(run 由 trigger 的撰寫者提交,任務的輸入檔是渲染後的 input 物件本身,而不是 source/trigger/record/row 信封)。requires_confirmation 為 false 時,Agent 直接提交,不經確認回合;表格 writeback 的版本仍需要兩回合確認。這些檢查用到的版本撰寫者歸屬是內部的,不會出現在任何回應。

**前端調整:**讓 owner 能撰寫新的種類並顯示撰寫時的錯誤碼;borrower 看到的 output_policy 仍是 null(現在裡面還多了 Command 與聊天室的 id),不要預期有值;把提交時的 403 output_policy_author_denied 當作授權問題,而不是資源不存在。觀察 run 的方式不變,Sandbox 的 run 紀錄不帶 Command 的結果。見任務輸出交給自訂表格 Command、任務受眾、自訂表格 trigger、Agent toolkit、Schema與錯誤。

runner 憑證跟著 timeout_seconds

認領時,runner 用來讀取 manifest、回報進度與完成、以及上傳結果的兩把 runtime 憑證,有效期限現在是已儲存的 run timeout_seconds 加上 120 秒收尾包絡(最多 604800 秒)。在這一版之前,有效期限只有平台預設的 600 秒,之後控制面就拒絕它們,所以更長的 run 無法回報結果,會被 reconcile 判成 platform_failed/provider_terminal_without_callback;這個 release 的地端 E2E(scripts/e2e/custom_tables/sandbox_ttl)在針對舊程式碼的 RED 階段,就是要求一個 timeout_seconds=1800、跑 12 分鐘的 run 以這個結果結束。在託管雲端上,每個 Cloud Run execution 也會以同樣的總長度作為它自己的 timeoutSeconds 覆寫啟動(不超過 168 小時),與重複使用的 Job 範本無關。已儲存的 timeout 缺少或超出範圍,會讓認領 fail closed(僅控制面)。

**前端調整:**無。很長的 timeout_seconds 不必再為了回報結果而壓在 10 分鐘以內。見限制。

runner 會重試它的完成回報

Go runner 的終態 complete 呼叫,現在每次嘗試有 30 秒預算,當控制面回 408、429、500、502、503 或 504,或傳輸失敗(逾時、EOF、連線錯誤;找不到主機不重試)時,最多嘗試三次、每次相隔 500 毫秒。依這項變更自己的標題,重點是:那個呼叫的一次暫時性失敗,不會再讓已完成的 run 被 reconcile 判成 platform_failed,而不是帶著客戶的 exit code 或逾時結束。runner 的變更只有在環境版本由含該變更的 runner release 建置時才會到達它;版本的 runner_release 記錄它用的是哪個 release。

**前端調整:**無。

表格 writeback 與 commands_only 的表

自訂表格的表可以帶 write_policy: commands_only(它的紀錄只能透過 Command 變更)。表格 writeback 的 output_policy 不能指向這種表:草稿建立/更新回 422 output_policy_governed_table;發布時,以及提交 run 且真的鑄出憑證時,同樣的狀況是 409 output_policy_unsatisfiable;在該政策開啟之前就鑄出的、限於單次 run 的表格 token,會被 callback 以有型別的 403 governed_context_required 拒絕。

**前端調整:**顯示新的 422;必須寫入這種表的任務,改用 Command 輸出這一種。見任務、分享與啟用與錯誤。

營運面(僅供參考)

在地端部署上,provider 容量更新與 GET /root/sandbox/quota-snapshots/refreshes/{refresh_id} 現在把快照範圍限定在別名 onprem,不再要求 GCP project;託管雲端在 project 缺少或格式不對時,仍回 409 sandbox_gcp_project_unset/sandbox_gcp_project_invalid。營運路由表不變(27 條)。見營運與 Root。

這次稽核找到的更正

下列內容在這個 release 之前就是錯的或不完整,兩種語言都已修正:

  • 錯誤碼頁寫「Authorization 與 X-Api-Key 都沒帶」是 401;實際是 418(Could not validate credentials),認證頁本來就是這樣寫。
  • Agent toolkit 頁說 PATCH /private/chatrooms/setting/jobs/{chatroom_id} 的 OpenAPI 說明只列 wms 與 booking;實際上它列有 sandbox(v5.10.11 時就是如此)。
  • Agent 相關頁面沒有寫明:表格 writeback 的 output_policy 即使 requires_confirmation 是 false 也會強制走提案路徑;現在寫了。

釘選與匯出

README、兩個首頁與執行規劃頁現在寫 v5.21.0 與完整 SHA 172a7f80bdf4…,schema 頁寫 v5.21.0。下方「如何更新這支釘」指令從這個 SHA 開始,並且另外涵蓋 src/routers/public/custom_tables_callback、src/tasks/sandbox_*.py、src/dependencies/sandbox.py 與 src/database/models/sandbox.py。llms.txt、llms-full.txt 與 Markdown twin 由這些頁面重新產生,包括新頁面任務輸出交給自訂表格 Command。

稽核附註——commit 分類

搜尋方式:(A) 對下方「如何更新這支釘」指令的路徑做 git log 70862ceae7..172a7f80bd(71 個 commit:60 個非 merge、11 個 merge);(B) 碰到任何路徑含 sandbox 的檔案的非 merge commit;(C) commit 訊息提到 Sandbox 的 commit。聯集共 111 個 commit(99 個非 merge、12 個 merge),每個都恰好分類一次:

  • 有文件記載/串接端看得到的契約變更(上面各節涵蓋;5 個 commit):7c41cbc501(Command 輸出,#1853)、739894a878(憑證壽命,#1826)、433e22bd00(完成回報重試,#1819)、3fa893b56d(commands_only,#1788)、4b11540fa6(所選 provider 的容量更新,#1804)。
  • 沒有額外契約變更的 merge commit(12 個):c7e3d41426、aba63cb121、e65d71e298、a81511bb15、9a4d7b0660、028db39d42、a3c9665e10、8e80f29a49、ba3290fcb7、d65e9e5b26、62b4075d81、d77bcfa6e4。
  • 開發環境、基礎設施、CI 與打包——對已發布產品沒有影響(9 個):03d3f5d4df、3cb548cb43、9057cc086d(Sandbox 開發環境啟用、啟動期間維持關閉、在共用 project 內隔離;production 資源名稱不變)、69598743e9(較早把 Sandbox 從開發部署移除)、feba983f1e、4d7415d467(agent-workspace IaC)、1bea1ef4ec(CI workflow)、45242b8711(雜湊鎖定的 Python lock)、552609edbf(release 與已部署映像的佈局契約)。
  • 內部變更,沒有契約變更(1 個):37b79e2222(行程回收現在會等待有追蹤的行程內工作,包括 run 排入佇列後喚醒 controller 的執行緒;3 秒 sweep 仍是備援)。
  • 地端安裝套件、營運腳本、教學與 compose add-on(26 個):e19594605b、4c11ddea98、3d05af8193、690d574faa、415bd335d1、10a72f6c1f、11b49fd897、695e7bf761、200512a125、150a8fc8be、46e9051e6c、d4a6be835b、caa80868dd、16e82ca37f、840b0c7220、fd991177fb、d72b880df9、67c513e294、4891aab5e2、e62c9907eb、73e377d58c、bbabc707ac、22ca3e74d0、aafb03c9be、368713044a、ebb3e0c988。它們改的是引導式安裝程式、它的診斷、add-on 位址處理與打包,不是租戶 API,手冊記載的任何變數也沒有改變意義;手冊把安裝套件交給後端的 docs/deployment/on-prem/。
  • 測試工具與 Agent 工具選擇(3 個):1d89736847(針對既有 Sandbox scope 拒絕行為的測試)、badb87d738(自訂表格驗收 runner)、9ec0fbae42(智慧工具選擇器;五個 Sandbox 工具仍被釘住)。
  • 其他模組——共用被稽核的路徑、只在訊息裡順帶提到 Sandbox、或碰到檔名含 sandbox 的檔案;都沒有改變 Sandbox 行為(55 個):7df284baa0、7a0a2b8a0d、dbdaeb4243、a21ba222ef、6bad38fbe9、737955fb69、6bf9760687、c9392060d1、c15a12f9b0、eaf7c84d76、cc5d2db9c8、1a607e52b8、bfb9ced050、cfb7457a4f、430d9aa23c、a510143539、9750eac491、74a6a2b13a、c48f763467、457140d0de、0f8985db78、2f548ae2a7、d48281f258、4ac973afae、2b78575d80、f0e17d4259、e5770ead73、ce26227b87、c6c21d4194、8ecc1f9a54、63636600ae、49103a6c5d、82042fed21、3b380b1a63、68f5beffc2、455fa388c6、e932ccdc0a、ae5229549e、9f7f93b7fd、2b0c952fef、1bc159f300、8cb89701ef、1eb1d3e517、68bc44c431、48577334a5、9587d94e93、8c0435fd3f、0e89a8032d、64843e7b66、19c720aad2、168e3d0da0、0de6458c1e、ba8ca8b3cd、c6d02fa6fa、78d30b5ff6。備註:新增的 OAuth access token(只在 /mcp/* 有效)與 Command service key(只在兩條 Command 路由有效)在 Sandbox 路由上都會被拒;7df284baa0 讓自訂表格的請求處理離開事件迴圈(command-output 路由變成在 threadpool 執行的一般 handler,契約相同);455fa388c6 移除 AI 呼叫上的價格閘門,並保留 Sandbox 雲端建置的價格閘門;4ac973afae 修正表格 callback 的 update data 說明(僅文件)。

2026-09-19 — production v5.10.11

來源與上線:後端 70862ceae7869470c14f4ed7cc7dfc3609e299f4 為 v5.10.11 版本提交(origin/master HEAD,tag v5.10.11)。Production release  由 「Release & Deploy to GCP (production)」run 35428530132  部署,該 run 於 2026-09-19 成功結束;production 讀回 GET https://api.cluster.scfg.io/openapi.json 的 info.version 為 5.10.11。本則稽核 9b8b95e59..70862ceae 之間、碰到下方「如何更新這支釘」指令所列路徑的每一個 commit(共 202 個:190 個非 merge commit 加 12 個 merge commit)。這段範圍大多是新的地端 provider(SANDBOX_PROVIDER=onprem);除非另外註明,託管雲端部署的行為不變。

Run 佇列:位置、預估時間與 429 背壓

SandboxRunDetailResponse 在 queue_position 旁新增可為 null 的 eta_seconds,所有回傳 run 的路由都有(提交、列表、明細、取消、重試、Quick Run)。託管雲端上 queue_position 意義不變(在公司 queued run 中從 1 起算),eta_seconds 一律為 null。地端部署兩者都來自 executor 佇列:位置也涵蓋 executor 尚未接手的 starting,預估時間為 ceil(位置 ÷ 整個 fleet 的 run slot 數) × 同一 profile 最近 20 筆已完成 run 的平均耗時,沒有歷史時為 null。OpenAPI 現在把 POST .../runs、POST .../runs/{run_id}/retry 與 POST .../quick-run 的 429 宣告為 SandboxQueuedRunLimitErrorResponse 或 SandboxQueueFullErrorResponse;queue_full(僅地端:整個 executor fleet 的佇列已滿)帶 limit、retry_after_seconds 與 60 秒的 Retry-After header。

前端調整:eta_seconds 非 null 才顯示,絕不自行推算;依兩個 429 元件重新產生 client。遇到 queue_full 先等 Retry-After;遇到 sandbox_queued_run_limit 則退避到等待中的 run 變少再送。見執行與結果、Schema、錯誤與限制。

Quick Run 的 input 終於送達工作

在這一版之前,Quick Run 從未暫存 input:工作讀到的是空的 /workspace/input.json,GET .../content 也回 has_input=false。Quick Run 現在跟手動提交一樣暫存 input,$TEAMSYNC_INPUTS_FILE 就是送出的 JSON。因此 Quick Run 也可能回 422 input_not_stageable/503 input_staging_unavailable(在 manager 檢查與冪等重放之後、建立任何任務或 run 之前)。

**前端調整:**拿掉針對 Quick Run 空 input 的權宜做法,兩個暫存錯誤比照手動提交處理。見 Quick Run 與錯誤。

依 provider 過濾的區域目錄與 onprem

SandboxRegionCode 新增 onprem,公開區域的 tier 範圍放寬為 1..3(3 = 固定/專屬容量,以名目會計費率計價)。GET /public/info/sandbox/regions 回傳部署所用 provider 的目錄:託管雲端永遠不列 onprem;地端部署只列 onprem。selectable_regions 是租戶 settings 使用的 active operator 列集合;正確 bootstrap 的地端部署只有 onprem,但 operator 額外建立的 tier 1/2 列可能出現在其中,而公開目錄與 build gate 仍依 provider 過濾。POST .../versions/{vid}/builds 若 build_region 不在該部署公開的目錄內,回 422 build_region_unavailable(地端在已有 active 區域列、但指定的不在其中時也回這個)。省略 build_region 時,地端預設 onprem,雲端仍是 asia-east1。

**前端調整:**區域選項維持由目錄驅動,接受 tier=3,建立建置的請求不要寫死 asia-east1。無 body 的 retry-build 端點在此釘選仍由後端固定使用 asia-east1。見環境與建置、端點、列舉與執行規劃。

地端部署

自架主機用 Docker executor 取代 Cloud Run,執行同一套租戶 API。串接端看得到的差異:只有一個 onprem 區域並以 tier 3 名目費率計價;有每公司與整個 fleet 的佇列上限(queue_full);submit/start 狀態的 next_action 用語改為不指名供應商(「the local runtime」;容量狀態則是「the on-prem sandbox」);沿用雲端 runner 的 error_code/failure_stage 詞彙,逾時 exit_code=124、取消 130;映像的其他 ENV 不再滲進工作 shell;執行期對外網路另需主機設 SANDBOX_ONPREM_EGRESS=internet;工作要回呼主機自己的 API,需要 operator 開放 API origin 並提供信任憑證庫。Agent 提交遇到任一種 429 時,工具錯誤為 provider_unavailable。

**前端調整:**依目錄與 GET /settings 建構介面,不要預設雲端行為;next_action 原文呈現。見雲端與地端部署、營運與 Agent 工具。

Runner:巢狀行程命名空間與計量修正

這一段 runner 說的是託管雲端;地端使用 Docker worker 的直接 shell 路徑。託管雲端開啟執行期對外網路的 run(預設)上,此釘的 runner 原始碼會嘗試讓工作 shell 成為巢狀 user+PID 命名空間的 PID 1;主機允許私有 /proc 設定時才會擁有自己的 /proc,若主機不允許命名空間則保留直接 shell fallback。關閉對外網路的 run 維持直接啟動 shell。短命的孤兒行程(例如 BusyBox wget https://… 分出的 ssl_client)在巢狀設定啟用時不再讓整個 run 被 SIGKILL 成 exit_code=137。命名空間內,主機允許 id 對應時 id -u 為 0,否則是溢位 uid 65534 且沒有任何 capability;/workspace 與 $TEAMSYNC_OUTPUT_FILE 仍可寫入。Runner 在 /workspace/.teamsync/ 下保留自己的紀錄。另一項修正:工作已 exit 0 的 run,不會再因網路介面拆除的時間差被結算成 platform_failed/metering_failed/stage metering_wait/exit_code=130。Runner 的變更要等環境版本由包含它的 runner release 建置後才生效;版本的 runner_release 記錄是哪一版。

**前端調整:**不需要調整;有背景行程時不要對 exit_code=137 做特例。見執行期須知與本機重現。

失敗提示與保留

secret_env_name_collision 的 failure_hint 改為說明真正的規則(某個一般環境變數與已綁定的 secret slot 同名),secret_env_value_collision 也有了自己的提示(某個一般環境變數的值與已綁定的 secret 值相同)。歸檔回收在仍有未歸檔的 curated 版本釘住同一 digest 時,保留租戶建置的 execution 套件。見執行與結果與保留。

營運面(僅供參考)

GET /root/sandbox/queue 以同一形狀在每種部署列出等待中的工作與 executor 容量。註冊 tier 3 區域只接受地端部署上的 onprem。營運路由表現在列出全部 27 條 root 路由,包括先前漏列的 GET/PUT /companies/{company_id}/policy。見營運。

釘選與匯出

README、兩個首頁、執行規劃頁與 Schema 頁改標 v5.10.11 與 70862ceae。下方「如何更新這支釘」指令改從這個 SHA 起算,並加入營運與控制面 router、地端 executor 與 controller、sandbox/onprem/、整個 infrastructure/sandbox/,以及這些頁面引用的其他後端路徑。llms.txt、llms-full.txt 與 Markdown twins 由這些頁面重新產生。

稽核附註——commit 分類

範圍內每個 commit 都已分類。先列出 29 個契約變更 commit;其餘 commit 沒有改變任何文件化或串接端可見的契約:

  • 文件化/串接端可見的契約變更(由上方各節涵蓋;共 29 個): 3edebc843、3dd307ba0、fa423ad8c、03b3eca5f、1d806d00b、a08bd498e、ee8a6de1b、aecbe16d6、fe074dfe0、6d42c0d3a、0e8a4b584、c9b5894fe、4687c6553、f916c29fe、a3f50f512、ec39191f0、3205659d2、c6c55f12f、ee54b9584、dfd96f0ca、5c69c5917、d5edcffc5、d384d06a5、dd005d9fe、33eebf13d、e157b4093、e882217cc、eee7aff4b、a78a0c47a。
  • Merge commit,除了合併進來的 commit 外沒有額外文件化契約變更: bf5968970、6f7718d4b、54c2c1012、d331534b1、e773750a4、f93f24597、679147a5f、d9aac6f71、d615306d9、a70e4fe8f、37f3fd1f3、ae8783293。
  • 地端 provider 內部(work lease、排程器、sweeper、executor、建置關卡、registry、dind 打包;僅供營運參考):6491285ef、bcee513d9、90c7cb8f1、acd18b7c1、542defb74、f232d0852、ec3d10407、50f1373f8、b7e54b141、b9909ad18、ec9dedd7a、2b31cd051、810484db2、d12a69949、761092f43、bd8d951a2、56e695fad、6c435f033、5741e685d、bf9f8ce37、d0d872302、3e8f8d4fc、c8387f7bf、f3e3388ae、9a62fb64b、fb75f449a、9f9a299f4、cf8cd1ff0、51f334f33、af83f77df、302fd9542、c2cc9ec74、c2d75c8a3、7867f3971、8047773ee、0119b6a50、fa6a3dcfd、beb9996a4、14ba3ab85、b8f16252a、aa0e1f609、5faa8bf52、410b1f53b、1fe95018c、24ab14393、76b048f28、6e2f05e2b、87fb335e3、8a2c6f337、30c27f6d3、a78b86674、bf42d7e23、d7ed040ae、5ffa0eaa4、50c52d071、c3a495845、e3ed8437f、8197701e2、3000ac16e、e7f7d9f45、fbdd515b1、ff9a4ca3d、28b6b3312、2a7da3852、8daf2a81a、9c688487f、08c3fcf77、6c40e71d5、3b5780264、cece7e91b、da366aaca、73c3455e7、3917dc89b、7c0bd4de6、abbeb5bad、e140b4c42、dc05cd786、bbe709b1a、93951d7f1、fa4c6b5f5、c53f60d98、8fa0aec70、28e9fdd5e。
  • 共用重構、效能與測試(雲端回應逐位元不變):ecfeeca63、8cb94350e、f58826b93、f8795d46f、04d436164、c5cbb1011、275c43f31、d78342af0、106469961、543ad2b73、d926fd9f1、37b70caf3、e8a0f7327、0ea91eaf5、b0602e136、b14239834、bb043e755、544737775、dac6cd145、44f0b9d4a、c51dc3406。
  • Runner subreaper 嘗試,已在同一範圍內被巢狀命名空間取代:5d1acdf93、9847dc302。
  • 共用稽核路徑的其他模組(src/schemas/enums.py 的非 sandbox 列舉、infrastructure/sandbox/gcp/**/agent-workspace、src/routers/private/modules/server.py 的私有模組掛載):bbe49538b、ebf8c6d6e、c9c805528、d911258d8、cbae44462、6501074b0、b86990f66、3320fcacd、89677a14c、1206ffea9、68d62b320、f30db1557、50ff40109、79722e274、9819680b3、22a4e375f、8f3fd1757、ff1fdfa7b、3e238babc、037b51362、e1a955a22、a9d6127b6、71dc5749c、643bb249a、55998aecc、3cccd926a、7877bb6fd、c7c5f9fc2、90ad65f5d、e7b251ecc、27f9fe4be、49658aa62、92934f0c9、4aa4aea74、bfab0b7dc、e2f7d67d2、ae2254aa6、3e6e6e0e6、293488605、8df1ababe、b5ab0d2db、3916a119e、d38cca5a9、145c7f438、7ba15c58e、3a79fb629、4e4ecec5e、2649934fe、a9ecda8fb、2f7f9a7b6、c2a9d7dbe、f3f70735e、b8c8fe2b8、1b295eb93、a396ac72f。

2026-09-10 — production v5.10.0

**來源與上線:**後端 9b8b95e598a7b1f606c030d8dd0f27f26c748c83 為 v5.10.0 版本提交,執行程式碼與已驗收的 9393591ae 相同。Production release  與部署讀回 已完成;本頁日期採 Asia/Taipei。以下描述目前契約,舊紀錄保留當時的上線範圍。

環境 owner 與釘選受眾

環境編輯不再只限公司管理員。POST /environments 接受 owner_scope=company|department 與 owner_id;預設 scope 是 company,因此部門管理員必須明確選自己的部門。PATCH、context 上傳、版本/build 操作與 archive 都依環境 owner scope 授權,兩種 owner 共用公司的 active-environment 上限。

**前端調整:**保留 owner_kind 以及獨立的 owner_scope/owner_id,依目前授權顯示控制。部門環境可給同部門任務或公司擁有任務釘選,不可給其他部門任務或 Quick Run;Quick Run 需要公司擁有或 curated 環境。見環境建立及權限矩陣。

能力提示與 source 可見性

GET /me 提供當前管理能力與可建立的 owner scopes。manageable_chatroom_scope=company 配合空房間 id 陣列,表示所有現有/未來房間。Owner 目錄(GET /tasks、detail、versions)依 live audience grant 顯示;同公司身分不等於能看全部任務。

**前端調整:**顯示 source 編輯功能前先讀必填的 source_visible。False 表示原始內容被隱藏,owner view 也須看 content_state 才能區分已清除的內容。Room menu 即使由 owner 呼叫仍使用 borrower view。見能力與管理查詢。

跨房間歷史與管理清單

GET /runs 提供依可見範圍篩選的跨聊天室歷史,支援可重複的 room/task/status、submitted_by_me、queued-time 界線、total 與 keyset 分頁。Task/room binding、task secret、task approval、consumer secret 清單提供管理既有物件所需的 metadata;consumer 外層回應也有 consumer_name。

**前端調整:**原樣傳回 /runs cursor,使用其授權範圍內的 total。管理清單上限 2000 列並回 truncated,能力 id 清單上限 5000;binding 歷史預設 active,需要 retired/all 時明確傳入。task_visible=false 時隱藏不可用的任務身分資訊;secret/approval 清單仍縮限到可管理的 consumer scope,不回 secret 值。見管理查詢。

分享、重疊 grant 與 Enable 同意

部門任務可直接分享到同公司任一存活房間,舊的「先分享整個部門」步驟已不需要。Grant 依 room、department、company 順序解析;剩餘等價授權可保留 binding,不會悄悄接受不同的憑證來源政策。既有 run 仍固定在當時的 grant/generation。

**前端調整:**Share 與 Enable 仍是兩個操作。Enable、明確建立 binding、accept-version,可替操作者有管理權且已解析的 borrower-secret scope 記錄精確版本同意。缺少 slot 或他人管理的 scope,仍須設定/核准;GET、發布、分享、一般 run 不會核准。接受版本保留已接受的政策。見任務受眾與Secret 同意(後端 #1260/#1262)。

忠實重試與可判讀的失敗狀態

POST .../runs/{run_id}/retry 在省略 body/input 或 input 為 null 時,逐位元重放保留的來源 input;非 null input 可在相同版本 pin 上以新 run 身分執行新參數。保留的 input 不存在、已退役、不可讀或 digest 不符時回 409 retry_input_unavailable,不再改用空 payload。

**前端調整:**新的重試意圖使用新的 Idempotency-Key;保留期限阻止重放時,請傳明確 input。呈現有型別的等待/失敗欄位與保留的 provider 拒絕來源,除了 work exit code,也分別檢查儲存內容與實際下載。受限 key 在允許房間呼叫 retry 回 405;管理/Quick Run 則可能更早在 auth 回 403。見執行/重試及錯誤。

Secret 驗證與作者 metadata

Create/rotate 解密後最少 4 個 UTF-8 bytes,不足時回 422 detail[].type=sandbox_value_too_short。明確核准會檢查已發布版本、相符 digest、risk_accepted=true 與非空、正規化、合法的 slot 名稱;claim 仍要求精確 borrower 子集。

**前端調整:**驗證位元組數而非字數,將過短值與信封/解密錯誤分開處理。新的 slot declarations 採具名物件,保留可選 metadata;讀取側仍支援歷史宣告。請更新產生的型別,不要把宣告攤平成失去欄位的任意 map。見Secret及Schema。

執行區域與費用規劃

公司 settings 提供 live selectable_regions、可為 null 的有型別 pricing,以及唯讀 operator egress 政策;region-readiness map 保留 live codes。費率含已加價的 profile 單價、最低計費/finalization 時間與網路預留界線。

**前端調整:**從目前需授權的 settings 取得區域,分別保留已儲存選擇,依文件的預估上限公式計算且不要再加價。提交時仍會重新檢查費率/政策/預算;runtime placement 不代表資料落地保證。見執行規劃。

手冊與 Agent 匯出

英文與繁體中文教學、endpoint/schema 表、首頁 pin、權限矩陣一起同步;更正了目前章節裡 retry 遺失 input、menu cursor 永遠為 null、結果上傳初始化限制、環境只限公司管理員等舊描述。llms.txt、llms-full.txt 與各語言 Markdown twins 由相同頁面重新產生。驗證包含 typecheck、靜態匯出與全部內部連結;來源/production 讀回及歷史 live E2E 證據仍各自註明範圍。

2026-09-05(四)— runner release 核准 + 歸檔版本回收(後端 #1162、SBW-08)

  • Runner release 核准(後端 #1162):task-bundle 的 runner 允許清單從環境變數搬進 operator 表,每次請求即時讀取。GET/POST /root/sandbox/runner-releases、DELETE /root/sandbox/runner-releases/{sha};版本回應新增 runner_release_approved + runner_release_next_action;補上 409 task_bundle_runner_unsupported。stage image 發佈會自動核准自己的 commit,新的 runner release 不再讓新建環境卡住。
  • 歸檔版本回收(SBW-08):歸檔環境版本後幾分鐘內即回收其各區 Cloud Run Job、quarantine/execution 映像套件、attestation 與建置報告;孤兒 Job/套件也一併清掃。歸檔是終態。
  • 建置線:提早離開共用 release Build 的 attempt(取消、逾時、步驟失敗)不再卡在 cleanup_pending。

2026-09-04(三)— 環境建置約快 2 倍(後端 #1154)

  • 六個驗證 gate(static scan ∥ smoke → sign → attest → promote → final verify)現在是同一個 Cloud Build 的步驟,跑在 E2_HIGHCPU_8,接在 customer build 之後。輕量映像約 5–6 分鐘就 ready(原約 12),重的約 7 分鐘(原約 19)。進度欄位不變;build_expected_seconds 約 360。

2026-09-04(二)— 任務管理 + 產出物檔案(後端 #1151,runner #1152)

  • PATCH /tasks/{id}(name/description/agent_enabled)與 POST /tasks/{id}/archive(整個任務歸檔:版本歸檔、binding 撤銷、排隊中的 run 取消、分享紀錄保留)。
  • GET /environments/{id}/context-uploads:唯讀列出已完成的建置 context 上傳,附 used_by_version_ids。
  • 任務可以產出檔案:放在 $TEAMSYNC_ARTIFACTS_DIR(/workspace/artifacts)底下的東西會變成該次執行的產出物 bundle——GET .../artifacts 逐檔列出,POST .../artifacts/{artifact_id}/public-link 逐檔分享。整包拒收規則寫在 runtime 契約的 artifacts。
  • context-uploads 列表補正(#1156):已被版本吃掉的上傳也會列出,並以 used_by_version_ids 連回版本。

2026-09-04 — 前端追蹤項(後端 #1149)

  • GET /chatrooms/{id}/runs(游標 (queued_at, id),最新在前)、GET .../menu(依 task_id)、GET .../runs/{rid}/artifacts(依 relative_path)都收 page_token;三條的 next_page_token 現在是真的游標。
  • POST /bindings/{id}/accept-version 重新計算 update_available,不再寫死 false。
  • SandboxTaskVersionResponse 新增 environment_id/environment_name。
  • SandboxBuildAttemptResponse 新增 retryable_until(版本在 retryable_failed 期間的 7 天重試視窗)。
  • build_ready/build_failed/build_cancelled 有通知 producer(環境 owner-scope + 公司管理者,繁中文案),並新增 curated_environment_published 事件(通知有釘該環境的公司)。
  • 逐檔產出物公開連結:POST/DELETE .../artifacts/{artifact_id}/public-link;GET /public/sandbox/artifacts/{token} 串流該檔案驗過 digest 的位元組區間。
  • 手冊自我矛盾修正(執行期網路、script-uploads)——見下方 09-03 條目。

2026-09-01 — FE 疑問修正 + 全站 docs↔implementation 稽核 vs 上一支釘 7011b318d

前端 2026-08-31 的沙盒疑問清單觸發了這一輪:先修 OpenAPI 契約(後端 PR #1100,待合——SandboxRuntimeContract 新增 working_directory/network 欄位、work_command 欄位描述的 python3 work.py 壞例子改成 python3 /workspace/work.sh),再對全站 21 頁跑一輪 docs↔implementation 稽核:133 個經對抗驗證確認的修正全數套用(64 遺漏、50 矛盾、17 過時、2 雙語分歧)。影響最大的幾個:

  • 認證:缺 credential 是 418(Could not validate credentials),不是 401;受限金鑰打 /tasks 路徑是認證層 403,不是 404。
  • runtime 契約:補 working_directory(cwd 名義上 /workspace 但不保證——一律絕對路徑)與 network(執行期無對外網路;建置期 RUN 可連公網)。
  • 建置:source_digest 單獨送不會比對已完成物件(錯誤晚到建置期才爆);Dockerfile 必須是封存根層的一般檔案;任何 # syntax= 行都拒(不只遠端);解壓上限 5 GiB/100k entries;retry-build 不吃 body、不沿用 region/profile;503 build_admission_fenced;complete 未被版本採用會佔住 staging slot。
  • 執行:run retry 不重放 input(新 run 拿到空 {},input_digest 卻對齊原 run——要重放請重新 POST /runs);產出物下載回的是 5 分鐘 capability token。

新頁:本機重現與除錯——用本機 docker harness 重現執行契約(固定檔名、同一個 sh session、兩個環境變數)、Node node_modules 陷阱、與真沙盒的差異表。

2026-08-31 — job contract、共享 secret slot 政策、永久公開連結、傳輸加密 vs 上一支釘 e94b54c3d

Master 自上一支釘之後上了五波租戶面功能,加一波大型建置路徑穩定性修正(PR #1033–#1087,總共 41 個 sandbox 範圍的 PR——完整清單見下方)。e94b54c3 手冊裡以下句子現在是錯的:

  • 建置 context 裡的 Dockerfile 必須 FROM alpine:3.20/busybox:1.36/debian:bookworm-slim 之一;scratch 在 compose 會被拒。
  • Base 映像裡的 CVE(例如 Alpine:3.20)仍可能讓掃描失敗,error_code=vulnerability_reject。
  • 沒有辦法宣告 work script 怎麼被呼叫、預期什麼 JSON input 形狀,也無法在提交 run 之前先驗證那個形狀。
  • 分享 grant 除了讓借用方自己提供值之外,沒有任何 secret 管理機制。
  • run 的 log/output 永遠只能透過已驗證租戶走 5 分鐘的產出物下載 capability 取得。
  • POST /secrets / POST /secrets/rotate 接受明文 value。

正確替代:任務、發布與綁定(job contract)、Secret 與授權(slot 政策 + 傳輸加密)、內容、Digest 與下載(公開連結)、建立環境並建置(base 映像與 CVE 立場)、任務受眾(分享受眾 fail-fast)。

Job contract(PR #1065)

  • #1065 — work_command(自由格式的驅動指令,materialise 進 /workspace/driver.sh,在 startup.sh 之後被 source;留空 → . /workspace/work.sh,跟舊行為位元組相同)、input_schema(JSON Schema draft 2020-12;提交的 input 違反它就是 422 input_schema_violation,在 dispatch 之前擋下;input_example 在這次草稿建立/更新呼叫時必須通過它,否則 422 job_contract_invalid——發布永遠不會重新驗證)、一個 runtime_contract 區塊(固定呼叫方式 + TEAMSYNC_INPUTS_FILE/TEAMSYNC_OUTPUT_FILE 環境變數名稱),出現在房間選單(SandboxMenuItemResponse——不論呼叫者是誰都是遮蔽過的預設值)、版本詳情回應(owner 看得到真正的 work_command)與 input-preview 回應上,一條 multipart 的 POST .../versions/{vid}/script-file 上傳路由(owner-manager、只限草稿),以及一個 POST .../versions/{vid}/input-preview 試跑端點(精確位元組 + digest + schema 判定,不會 dispatch 任何東西——公司裡任何非受限成員都能對草稿或已發布版本呼叫,不是 owner-manager 專屬)。work_command 對 borrower 禁止(遮蔽成預設值,就連選單上 owner 自己看到的也是遮蔽值);input_schema borrower 看得到。Agent 工具選單項目帶 input_schema 與 secret_slots,但不帶 runtime_contract。

Dispatch 出包鏈(PR #1066–#1072)

  • #1066 — sandbox_cloud_run_quota_leases.weight 從 INT 加寬成 BIGINT。記憶體維度的 admission 權重是位元組數(標準 profile 的 2 GiB 租約會溢位有號 INT);自 ~08-26 起每個 dispatch 都卡在 starting。
  • #1067 — 給 sandbox_job_executor 自訂 IAM role 加上 run.jobs.runWithOverrides——跟 run.jobs.run 是不同的權限,每個帶 env override 的 dispatch 都需要它;之前每個 live dispatch 都 403 provider_forbidden。
  • #1068 — 執行中 job 的網路對外連線現在無條件停用。 Cloud Run Sandboxes launcher 的 --allow-egress 要建立 veth pair,需要 root;runner 依設計拒絕以 root 執行。目前沒有逐任務的 opt-in。
  • #1069 — REST 手動提交現在會在建立 run 之前,把 input JSON staging 進 owned-object store。之前從來沒做過——每個 REST 提交的 run,work script 都會默默看到空 input。
  • #1070 — 修掉 #1069 造成的自我 deadlock:staging 現在發生在拿公司 policy row lock 之前,不是在 lock 底下。
  • #1071 — 手動 run 的 input staging 拒絕現在會記錄完整例外鏈,並在 422 回應裡點名根本原因。
  • #1072 — 手動 run 的 input staging 現在用 scoped idempotency key 的確定性 uuid5 當 subject,而不是原始(無界限)的 key——後者曾經溢位 SandboxOwnedObject.subject_id(String(36))。

永久公開連結 + 共享 secret 管理(PR #1074–#1081)

  • #1074 — 永久公開結果連結:POST/DELETE .../chatrooms/{id}/runs/{run_id}/{log|output}/public-link 為一次 run 的 log 或 output 鑄造/撤銷一個沒有 TTL、不需驗證的 GET /public/sandbox/artifacts/{token} 下載連結。
  • #1075 — 修掉一個 NameError(_reject_restricted 定義錯了模組)——之前在 staging 上每次 mint/revoke 呼叫都會 500。
  • #1076 — 共享 secret slot 政策:分享 grant 可以設定 secret_slot_policies({slot_name: "borrower"|"owner"|"owner_overridable"}),只能在建立時設,要改就重新分享。
  • #1077 — Secret 傳輸加密:POST /secrets 與 POST /secrets/rotate 現在只接受混合 AES-256-GCM + RSA-OAEP-SHA256 的 encrypted_value 信封({encrypted_key, iv, ciphertext},都是 base64,金鑰來自 GET /public/info/model_key/public_key)。明文 value 一律拒絕——四種可分辨的 422 錯誤代碼(sandbox_plaintext_value_rejected/sandbox_encrypted_value_required/sandbox_transit_keypair_missing/sandbox_encrypted_value_undecryptable)。
  • #1078 — 修正了 GET /public/info/model_key/public_key 的描述,之前還宣稱明文「可以當備援接受」。
  • #1079 — 把部門擁有的任務直接分享給受眾之外的聊天室,現在在分享建立時就 fail-fast 409 share_target_not_in_audience,不會是一個悄悄永遠用不到的 grant。
  • #1080 — Provider secret 路徑現在按任務分段(加上 .../tasks/{task_id})——兩個不同任務共用同一個 consumer scope 與 slot 名稱,不再會撞上同一條未分段路徑。
  • #1081 — Manifest 揭露現在會重新檢查 owner 出借 pin 的 grant 存活狀態。一筆 grant 若在認領與之後的 manifest 讀取之間被撤銷,現在會被拒絕(控制面 409 share_grant_revoked),而不是仍然解析出那個過期的 pin。

建置路徑穩定性(PR #1033–#1055)

一條 20 個 PR 的鏈,全部是在 2026-08-21 到 2026-08-25 之間於 live 環境發現的,重新打通了租戶自訂建置的快樂路徑,並縮短了 rollout/診斷時間。兩個對租戶可見的結果已在上方點名(base 映像允許清單移除、CVE 閘門移除);其餘都是維運/CI 穩定性修正。

  • #1033 — 打通自訂建置:Dockerfile base 允許清單自 08-21 起卡住每次建置(例如 node:20-alpine 被拒),且沒寫回任何原因——只有一個乾巴巴的 wrapper_fault。
  • #1035 — Compose 接受 Node 系映像;每個 base 映像都會帶的一個無害 /etc/mtab symlink,之前被誤判成保留路徑逃逸。每個 builder 拒絕現在都會點名自己。
  • #1037 — Stage 映像發布從四個手動步驟改成一個 CI job,背後有一個真的 admission 圍欄(之前的「圍欄」只是一個沒有強制力的貼上字串)。
  • #1038 — 依對抗性 review 加固了那個 CI 圍欄:每次長等待前都重新取得 re-entrant hold(之前的 TTL 可能在 rollout 途中過期、悄悄開了圍欄),並修正 rollback 的 annotation 處理。
  • #1040 / #1041 — Compose 直接接受任何公開 base 映像(node、golang、python-slim、debian、ubuntu、busybox、nginx 全部 live 驗證過);CI admission 圍欄現在以 Job 執行。
  • #1042 — CVE 掃描結果重新歸類為只是參考——HARD_FAILURE_SEVERITIES 現在是空的,OPA policy 也沒有嚴重度規則了,所以沒有 CVE 能擋建置。live 掃描階段現在一律把拒絕回報成 policy_reject;vulnerability_reject 仍留在封閉的 receipt 集合與 terminal-class 對照表裡(程式碼沒刪),但 live 路徑已經到不了那裡。SBOM/漏洞報告仍會產生並附掛。
  • #1043 — 把 stage rollout 從約 22 分鐘砍到約 6 分鐘:一旦資料庫已經證明沒有進行中工作,就跳過一個 600 秒的 pod-grace 等待。
  • #1044 — 一個沒留下 receipt 就死掉的 stage,現在會印出 stage_error gate=<gate> code=<code>,而不是靜靜地 exit 2。
  • #1045 — 修好 attest 閘門:Container Analysis v1 不接受 client 提供的 occurrence id;這個閘門自從上線就一直失敗。
  • #1046 — Rollout 現在會強制刪除已排空的 controller pod,而不是用一個縮短過的等待去跟 deployment 自己的 600 秒 termination grace 賽跑。
  • #1047 — 修掉一個洩漏的 context 上傳 staging slot(complete_upload 從沒釋放過它)——之前卡住每個租戶發布 E2E,撞 staging_slot_exhausted。
  • #1048 — Settled-lease 的 staging 上限檢查改寫成 correlated EXISTS(之前是 O(公司終身上傳數量) 的 IN 清單)。
  • #1049 — Smoke 閘門不再要求 bin/sh(usrmerge 系發行版如 Debian/Ubuntu/Fedora 只有 usr/bin/sh);區域 Job 建立現在指向 promote 實際寫入的東西。
  • #1050 — 一個重試中的 regional_readback 閘門現在會記下真正的原因(例如 provider_forbidden),而不是用一個只點名計時器的代碼結案。
  • #1051 — 一個因期限觸發的取消,現在會保留閘門已經記下的原因,而不是拿一個乾巴巴的取消標記蓋掉它。
  • #1052 — Buildkit scratch 目錄的收尾,不再因為 Python TemporaryDirectory 清理時的 EPERM 而讓一個原本已完成的建置失敗。
  • #1053 — Promote 的 receipt 現在回報真正的搬移位元組計數,不只是邏輯/manifest 大小。
  • #1054 — 把 EPERM 收尾修正做得更持久(純 mkdtemp + best-effort rmtree);跨套件的 blob 複製現在會重新雜湊並登記到目標套件下,而不是相信一個僅限套件範圍的存在性檢查。
  • #1055 — 給 sandbox-job-provisioner 加上 sandbox-execution 的 Artifact Registry 讀取權——Cloud Run 建立時的映像可讀性檢查之前對每個租戶版本都失敗封閉。

控制面穩定性(PR #1082–#1087)

  • #1082 — 每個控制面拒絕(claim/bootstrap/progress/manifest/……)現在都會記錄 stage、subject、拒絕代碼與狀態——之前只有裸的 HTTP 狀態碼會進 access log。
  • #1083 — 把 sandbox-controller pod 釘住不讓 GKE Autopilot autoscaler 驅逐(cluster-autoscaler.kubernetes.io/safe-to-evict: "false")——整併曾經每 5–7 分鐘就殺掉這個單副本 controller,悄悄讓已 staging 的 dispatch 卡死。
  • #1085 — Sandbox-controller 的 KEDA scaler 從 gcp-pubsub 換成 gcp-stackdriver——pubsub scaler 已棄用,且它固定的回看視窗對這個低流量的訂閱回傳空值。
  • #1086 — 一個背景 reaper 現在會救回卡在 starting/provider_submit_staged 的 run(controller 在 dispatch 途中掛掉時,重新驅動同一條恰好一次的送出路徑)。取消一個尚未認領/正在競速的 run,現在會可靠地立刻釋放它的排隊與並行 lease,而不是偶爾洩漏。
  • #1087 — Capacity-keepalive 刷新現在會在快照過期前約 60 秒觸發,而不是剛好卡在過期門檻上。Dispatch 拒絕與 sweeper 執行緒當機現在都會被記錄,不再靜默;controller 自己的 log 現在真的會送到 stdout(之前打到一個沒設定的 root logger 就消失了)。

仍不是前端面

  • /sandbox-control/*、/root/sandbox/* 請求本體。
  • Cloud Build tags、stage 映像 digest、CI admission 圍欄內部、GKE Deployment/ScaledObject YAML、KEDA trigger 設定。
  • 原始 R2 key/presigned URL/secret 值/writeback HMAC key/provider secret 路徑。

2026-08-23 — 實作建置路徑 vs 上一支釘 d99b4cad6

#975 之後 master 上了租戶 compose/scan 實作路徑與可持久化的建置取消(到 #1023)。租戶路由清單與列舉沒變。#975 手冊裡以下句子現在是錯的:

  • 取消仍在排隊的建置 attempt 當下就結算。
  • Writeback 把 TEAMSYNC_CT_WRITEBACK_URL 注入 ordinary env(只有 token 走密封通道)。
  • 任意公開 FROM 映像都能 compose。(scratch 不在允許清單;alpine:3.20 掃描常失敗。)(已於 2026-08-25 被取代——見上方 2026-08-31 的條目。)
  • 模組能用之前,公司必須先打開 SANDBOX_ENABLED。

正確替代:建立環境並建置、五分鐘跑一次。

實作路徑補上的(#1012–#1025 時期,釘在 #1023)

  • 租戶自訂建置是真的 Cloud Build compose + scan。Dockerfile FROM 必須是 alpine:3.20、busybox:1.36、debian:bookworm-slim(ECR public library 標籤)。其他 base 會 compose 失敗。掃描仍可能 customer_failed,error_code=vulnerability_reject/policy_reject。(已於 2026-08-25 被取代——見上方 2026-08-31 的條目。)
  • POST .../builds/{id}/cancel 一律圍欄 stage capability 並寫入可持久化的 provider-cancel intent。輪詢到 terminal_class=cancelled。排隊中取消不是同一請求內結算。
  • Writeback 的 URL 與 token 都走密封 secret 通道。兩者都不能進 ordinary_env(TEAMSYNC_ 是保留前綴)。
  • SANDBOX_ENABLED 預設 true。false 才是 kill switch(503 sandbox_disabled),不是啟用單。
  • 快路徑:釘 live system_curated 目錄 SCFG Standard(每個公開區域都是 state=ready)。除非你需要自訂映像,否則跳過租戶上傳/建置。
  • 未完成的 context 上傳會漏 staging lease。撞上 20 個 live slot 會 429 staging_slot_exhausted,連 scan report 寫入也會卡住。Abort 未完成 session;不要對 init 空轉重試。

仍不是前端面

  • Cloud Build tags、stage 映像 digest、/sandbox-control/*、/root/sandbox/* 請求本體。

2026-08-19 — PR #975 + #964 vs 上一支釘 076c1278

上一支手冊釘是 #956 的 merge。之後 master 進了自訂表格 writeback(#964)以及部門任務/上傳/歷史面(#975)。

不要再留舊故事。 以下句子現在是錯的:

  • 目錄任務可以用 owner_scope=chatroom 建立。
  • 建立版本必填 source_digest;前端永遠不上傳位元組。
  • 分享就會把任務放進 Agent 選單。
  • output_policy 是不透明 JSON/只有聊天室擁有才能 writeback。
  • Staging 20/20GiB/每分鐘 5 次只在控制面。
  • 租戶面除了 queued-run 沒有 429(上傳 429 存在)。
  • task.agent_enabled 是 Agent 開關。

正確替代:任務受眾。

#975 補上的

  • 建立只有 department/company;POST /tasks 送 chatroom 是 422。隱藏 Quick Run 父任務仍在。
  • 分享對象:整間公司(含未來部門)、任一部門、擁有部門或已有 grant 的部門裡的房間。
  • 房間 GET/POST .../granted-jobs.../enable|disable。選單 + Agent = 已授予 且 已啟用,每個呼叫者同一份清單。手動 REST 仍走 can_execute_manually(share + 成員資格;不要求啟用)。
  • Context 上傳:init → PUT X-Sandbox-Upload-Capability → complete → owned_object_id。單一部分、1 GiB、15 分鐘 capability。
  • GET /public/info/sandbox/regions 與 /profiles。xlarge 租戶不可選。
  • Company manager GET /tasks/{id}/runs + /numOfData(offset/limit)。
  • 擁有部門的 writeback 即使房間是透過 share 進來,只要在擁有部門裡就會鑄憑證。公司擁有的任務不能發布 output_policy。

#964 補上的(以 #975 之後的狀態為準)

  • 有型別的 SandboxOutputPolicy。執行期把 TEAMSYNC_CT_WRITEBACK_URL/TEAMSYNC_CT_WRITEBACK_TOKEN 注入密封 secret 通道(不在 REST,也不在 ordinary_env)。
  • 只有 JWT 使用者;API key/受限金鑰/社交客戶端不鑄。
  • Trigger 路徑拒絕 output_policy 版本。Agent 仍走確認。
  • 403 output_policy_author_denied/writeback_authority_denied;409 output_policy_owner_scope_unsupported/output_policy_unsatisfiable;503 sandbox_writeback_key_unavailable。

仍不是前端面

  • /sandbox-control/*、/root/sandbox/* 請求本體。
  • 原始 R2 key/presigned URL/secret 值/writeback HMAC key。

2026-08-19 — 更早一次相對 2026-08-13 的缺口補齊

2026-08-13 的手冊已有租戶路由清單。那次補了 schemas、agent 工具、通知、自訂表格 trigger、下載 TTL、取消來源,並修了若干內部矛盾。那些頁還在;這支釘改寫被 #975 證偽的頁。

如何更新這支釘

git -C ../teamsync-backend fetch origin master git -C ../teamsync-backend log -1 --format='%H %s %ci' origin/master git -C ../teamsync-backend diff 172a7f80bdf4dbdffdc018eb08bfa42c62bb485c..origin/master -- \ src/routers/private/modules/sandbox \ src/routers/private/modules/server.py \ src/routers/public/info/server.py \ src/routers/public/sandbox_artifacts.py \ src/routers/public/custom_tables_callback \ src/routers/root/sandbox.py \ src/routers/sandbox_control \ src/schemas/sandbox.py src/schemas/enums.py \ src/components/sandbox \ src/components/tools/custom/sandbox \ src/crud/sandbox \ src/crud/custom_table_triggers.py \ src/database/models/sandbox.py src/dependencies/sandbox.py \ 'src/tasks/sandbox_*.py' \ src/workers/sandbox_onprem src/workers/sandbox_controller.py \ sandbox/runner sandbox/build sandbox/onprem sandbox/e2e-js \ docs/runbooks/sandbox-operations.md \ infrastructure/sandbox \ infrastructure/app/gcp/k8s/base/sandbox-controller-deployment.yaml \ infrastructure/app/gcp/k8s/base/sandbox-controller-scaledobject.yaml

要分類的 commit 清單用 git log --oneline <pin>..origin/master -- <同一組路徑>,再加上碰到路徑含 sandbox 的任何檔案的非 merge commit(例如 scripts/sandbox/ 底下的地端安裝套件與 docker-compose.sandbox.yaml),以及訊息提到 Sandbox 的 commit(git log -i --grep=sandbox)。src/schemas/enums.py、src/crud/custom_table_triggers.py 與 infrastructure/sandbox/gcp/ 也放了其他模組(自訂表格、Edge Workers、agent workspace);這些 commit 請歸類為本模組以外,不要略過不記。

2026-09-03 —— 對 master 0203b987 的實機驗證

由 staging 實機執行(GCP log + 9 次執行的 JS 套件)補上的事實:

  • 任務包:POST /tasks/{id}/bundle-uploads(zip / tar / tar.gz,≤20 MiB),解壓到 /workspace;runner 保留的根目錄檔名 → 422 bundle_path_forbidden。
  • runtime 契約修正:runtime_egress_enabled 開啟時有對外網路(pip / npm / go get 在工作階段可用);只有 /workspace 與 /tmp 可寫。PATH 極簡;python -m venv 會失敗——已被 #1145 取代:work shell 沿用映像的 PATH(沒設時採慣用預設),官方 python:* 映像上 venv 可用。
  • SandboxRunDetailResponse 的失敗來源:error_code、error_detail、exit_code(精確,含 launcher 壓縮過的結束碼)、failure_stage、failure_source、計量位元組。
  • 每分鐘 5 次上傳額度下提交 → 422 input_not_stageable;新版本第一次執行 1–5 分鐘——已被 #1140/#1145/#1146 取代:run input 不再計入額度(連續提交全部 queued),第一次執行約 10–35 秒到 running。環境建置仍約 11–19 分鐘(七個循序驗證階段)。
  • 已知限制:runner 上傳結果可能在該額度下被略過(completed + has_output=false)——#1140 已修(結果上傳不計入額度),#1145 再補強(輸出遺失時以 platform_failed/result_upload_failed 結束,不會是 completed)。
  • 參考實作:teamsync-backend 的 sandbox/e2e-js/。
Last updated on