Skip to Content
核心概念Sandbox 寫回

Sandbox 寫回 Custom Table

已發布的 Sandbox task version 可以宣告 Custom Table output contract。符合資格的人類提交該版本時,TeamSync 會在建立 Sandbox run 的同一個 transaction 裡產生一組 run-scoped callback credential,之後把它注入該 run 的 execution manifest。Script 可以用它在一張綁定資料表上新增 records,或新增並更新 records。

這組 credential 不是一般 user session。Public callback 不會在每個 request 重新解析 caller 的 live ACL;token 本身就是在剩餘生命週期內操作整張綁定資料表的 authority。這正是 authoring、submission、confirmation、reveal 與 revocation 必須各自 fail closed 的原因。

精確 output_policy shape

output_policy 屬於 Sandbox task version:

{ "output_policy": { "kind": "custom_table_writeback", "table_id": "22222222-2222-4222-8222-222222222222", "allowed_ops": "create" } }

Contract 是 strict:

欄位Contract
kind必須剛好是 "custom_table_writeback"
table_id同公司、仍存活的 Custom Table UUID;帶 channel 規則的資料表會被拒絕(422 output_policy_channel_table),不論其 enforcement 模式為何,因為 public callback 不帶 acting room,而已 enforce 的 channel 規則會拒絕每一筆寫入;write_policy 為 commands_only 的資料表也會被拒絕(422 output_policy_governed_table),因為 callback 是直接的資料列寫入
allowed_ops"create"(預設)或 "create,update"

未知 key 與其他 operation 字串會被一般的請求驗證拒絕(FastAPI 標準的 422 清單)。Target 會在 draft create/update(422,帶 output_policy_table_not_found——資料表不存在與屬於別家公司給的是同一個答案——或 output_policy_channel_table)、publish 與 run submission(409 output_policy_unsatisfiable)分別檢查,而在 secret reveal 給 execution manifest 前,還會再對它檢查一次 token 的建立者權限。因此不存在、已軟刪除、跨公司或後來加上 channel 規則的 target,會在任何付費工作排入之前就被攔下。

只有 owner-local 的 chatroom/department job 能 mint

Run 只有在它所屬 task 的 home audience 內執行時才會 mint credential:department-owned job 在 owning department 的任何 room,歷史的 chatroom-owned job 則只能在完全相同的 owner room。新的 task 只能建立成 department-owned 或 company-owned,Quick Run 不能帶 output_policy,而帶著 output_policy 發布 company-owned 版本會被以 409 output_policy_owner_scope_unsupported(detail.code)拒絕,所以請使用 department-owned task,並從 owning department 的 room 執行。

從其他任何 room 執行的 run 都是 borrowed,例如其他 department 的 room,包括透過 department/company share 被納入者。Borrowed run 不會 mint token;平台會寫下 ct_writeback.mint_skipped audit,reason 為 borrowed_run_share_generation。Cross-tenant writeback 永遠不允許。Task 的 ownership 與 sharing 請見 Sandbox 模組自己的文件。

Author 與 submitter 都必須覆蓋 token authority

Token 能寫整張表,而且 callback request 沒有 per-request row 或 column ACL context。因此,TeamSync 要求兩個參與把 authority 交給 script 的身分,本來就各自擁有至少同樣寬的權限:

Gate身分與必要權限
PublishTask-version author/publisher 必須是 table manager,或具 insert 權限且沒有 hidden columns;create,update 另外要求不受 filter 限制的 can_edit: "all"。失敗為 403 output_policy_author_denied;root operator 不受此限。
Submit/mint提交的人類接受同一套檢查。失敗為 403 writeback_authority_denied;不會排入一個帶過寬 credential 的付費 run。
Manifest reveal再次針對資料表檢查 token 的建立者權限。

只有以 JWT 互動登入的 user 可以 mint。Sandbox API key、restricted Sandbox key 與 non-user principal 永遠拿不到 writeback authority。已宣告 policy 卻走到 skip path 時不算錯誤:submission 會成功、run 會排入並在沒有 TEAMSYNC_CT_WRITEBACK_* 變數的情況下執行,而且不會告知 submitter。Retry 是同一個 version 上的新 run,所以它會在重試者的 authority 下 mint 一個新 token。

一組 credential、一個 run、有限生命週期

符合資格的 submission 會一起建立 token row 與 run。Execution 取得:

  • TEAMSYNC_CT_WRITEBACK_URL,作為 callback URL:deployment 標準的 API origin(HOST,否則 PUBLIC_HOST,以單純的 http(s) origin 表示),後面接 /public/module/custom_tables/callback/{token_id}。它帶著 token id——credential 的 URL 那一半——所以和 token 一樣以 sealed 方式傳遞;
  • TEAMSYNC_CT_WRITEBACK_TOKEN,作為 token——兩者都走 sealed secret channel,不會放進一般環境變數。

Script 透過 run 一般的對外網路呼叫該 URL。若公司的 runtime egress 已關閉,run 的每一條對外連線都會失敗,callback 也不例外,儘管那些變數仍會被注入。

Secret 只以 hash 保存,之後的 read API 不會再回傳明文。Token 一開始會先蓋上一個 backstop 存活期(至少 48 小時,或 run 的 work timeout 加 finalization envelope,若後者更長),Manifest reveal 時,validity window 再縮到 claim 時間加 run work timeout 再加 finalization envelope(120 秒);重複 reveal 只會維持或縮短這個 window,絕不延長,過期的 token 會得到 callback 統一的 404。在 submission 階段,signing key 不存在或無法使用(503 sandbox_writeback_key_unavailable)或 target 已不可用(409 output_policy_unsatisfiable),會在任何付費工作之前就拒絕該次 submission;在 reveal 階段,key 不存在或無法使用會扣住 credential,建立者的權限已不足以涵蓋 token 時也一樣,run 則在沒有它的情況下執行。Target 本身在 reveal 時不會重新檢查:在 run 排隊期間被丟到垃圾桶、或才被加上 channel 規則的資料表,仍會被注入 writeback 變數,而 script 的 callback 寫入會改為被拒絕(已 enforce 的 channel 規則回 403,已在垃圾桶的資料表回 400)。

Run 進入 terminal transition 時 token 會被撤銷,包含取消與 offboarding cleanup paths。只有 token 仍 live 且 reveal gates 仍通過時,重建 manifest 才會得到相同 run-bound values。

這個 token 同時也是資料表 callback-token 清單中的一筆一般資料列。資料表 moderator 會在 callbackTokens.list 看到它顯示為 sandbox-run:{run_id},並帶有它的 allowed_ops、valid_until、revoked,以及設為提交者的 created_by;moderator 也可以隨時用 callbackTokens.revoke 結束該 run 的 writeback:從那一刻起 callback 回統一的 404,而 run 本身繼續執行。

Callback 仍會套用 Custom Table schema、rules、links 與 allowed-operation checks;但它不會重新解析被標記使用者的 row/column ACL,created_by 只是 attribution,不是 authentication。它同樣不在 agent 工具箱那道受 command 治理的寫入轉導之內:那道閘門位於 agent 的資料列寫入工具裡,所以帶有 settings.agent_writes_via_commands_only 的資料表,仍然接受這組 credential 的寫入。不要把那個設定當成「強迫 Sandbox script 改走 command」的手段:要做到這件事請用 write_policy: commands_only,它會在 callback 拒絕這組 credential(一般 token 檢查之後、任何 receipt 之前回 403 governed_context_required),也會拒絕儲存以該資料表為目標的寫回設定。在切換之前鑄造的 token,會在 callback 被拒絕。兩個 environment values 都必須視為 secret:外洩等於在到期或撤銷前,取得對整張綁定資料表執行宣告 operations 的能力。Callback 以統一的 not-found 回應避免 token probe 成為 existence oracle。用 run token 做的寫入會被標成機器產出(建立時是 created_by_ai、更新時是 changed_by_ai),created_by 仍是促成這次寫入的使用者,所以歷史紀錄分得出 script 寫入與人工編輯。和所有 callback 一樣,update 的 data 接受顯示名稱或內部 key,遇到未知的欄位 key 會回 400,而 create 則會丟掉未知 key。Callback request 協定見外部回呼。

Agent submission 一律需要稍後另一輪確認

帶 output_policy 的 agent-facing Sandbox version,即使一般 requires_confirmation 為 false,也屬於 confirmation-grade:agent lane 上的 sandbox_submit_job 工具(不是 trigger action submit_sandbox_job)第一次呼叫只會準備 proposal(一份 proposal_receipt,有效 30 分鐘),必須由一則不同、時間上嚴格較晚的人類訊息確認後,TeamSync 才會建立 run,以防 prompt injection 把使用者的資料表 authority 花在一組送進 task-author script 的 credential 上;只有 confirmation receipt 與所有 live submission gates 都通過後才會 mint token。這與 agent 工具箱的兩輪確認是同一個原則。Agent 永遠看不到具體的 writeback 拒絕原因;外部 client 的 submission 不會被拒絕,而是在沒有 credential 的情況下執行。

Trigger 永遠不能提交帶 policy 的版本

submit_sandbox_job 沒有人類 confirmation turn,因此任何帶 output_policy 的 task version 都會被拒絕,即使 requires_confirmation 為 false。Validator 會在 trigger 設定階段拒絕,worker 也會在 fire time 重複檢查,以防 pinned version 在 trigger 儲存後發生變化。

設定時錯誤為:

submit_sandbox_job cannot use a task version that declares a custom-table writeback output_policy

Fire-time denial 為:

submit_sandbox_job denied: task version declares a custom-table writeback credential; trigger submissions cannot mint one

不能以清掉 requires_confirmation 繞過;output_policy 本身就會啟動 fence。請改用人類 JWT submission;若走 agent lane,完成明確的第二輪確認。Trigger action 其餘 contract 見 submit_sandbox_job。

整合 checklist

  1. 目標必須是同公司、live、沒有 channel 規則的 Custom Table。
  2. 只選 create 或 create,update;update authority 要求不受 filter 限制的 edit-all 權限。
  3. Publish 前確認 author 具完整 token-covering authority。
  4. Callback URL 與 token 只在 run 內讀取、不要記錄,run 終止後立刻停止使用。

Task 的 authoring、sharing 與 run route 見 Sandbox 模組自己的文件。

Last updated on