凍結提案與操作收據
ct.proposals major 1 將準備確切變更與正式寫入分開。提案會凍結版本 2 write Command 的輸入、實際讀取集合、具體動作與 Review 義務;operation 套用這些已儲存動作,並留下持久收據。準備、核准與正式寫入是三個不同動作。
宣告政策
版本 2 write 定義可選擇加入 proposal_policy:
{"proposal_policy":{"ttl_seconds":900,"template_ids":[]}}ttl_seconds 是 60–604800 的嚴格整數,預設 900;template_ids 最多 16 個不重複的 Review 範本 UUID。版本 1 與 query 定義不能使用此政策。Review 範本增加審批義務;核准不會正式寫入提案。帶有此政策的 Command 若走舊 /execute,會收到 ct.governed_context_required;應改用 prepare 與 operations。
準備、檢視、核准、正式寫入
以下六種路徑都支援聊天室、部門與公司範圍。{scopeWithId} 是 chatroom/{chatroom_id}、department/{department_id} 或 company/{company_id}。Scoped REST 使用 JWT 驗證與原有範圍/Command 權限。
/private/module/custom_tables/{scopeWithId} 後的方法與路徑 | 用途 |
|---|---|
POST /commands/{command_id}/prepare | 凍結確切動作,不正式寫入業務資料 |
GET /proposals/{proposal_id} | 檢視目前獲授權的提案與義務 |
POST /commands/{command_id}/operations | 完成所有檢查後套用儲存提案 |
GET /operations/{operation_id} | 取回持久操作收據 |
POST /commands/{command_id}/selections | 凍結版本 2 query Command 的完整實際讀取集合 |
GET /selections/{selection_id} | 分頁讀取已授權的凍結列/版本參照 |
從 Command 回應取得 command_digest,不要在用戶端自行計算或猜測。Prepare 傳入 contract_version: 1、該 digest、inputs(最多 200 個 key)、1–128 字元的 request_idempotency_key,以及選用的 expected_versions(最多 1000 個 {table_id, record_id, version})與 selection_id。Version 必須是 1–9007199254740991 的嚴格整數。
準備會具體化動作,在 savepoint 中模擬寫入,再回滾模擬;只保留提案與 Review 義務。首次建立回 201,相同 key 與內容的重播回 200。OpenAPI 的預設成功碼是 200,但路由會在建立時設定 201。相同 key 配上不同內容會收到 ct.request_key_reuse。
檢視 proposal_id、proposal_digest、command_digest、read_set_digest、semantic_effect_hash、expected_versions、expires_at、effect_preview 與 approval_assignments。預覽最多 100 個 effect,不能代替完整凍結動作集合。提案狀態為 prepared、pending_approval、approved、rejected、stale;讀取仍須通過目前權限。
正式寫入只傳以下結構,ID 與 digest 應使用伺服器回傳值:
{
"contract_version": 1,
"proposal_id": "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
"expected_proposal_digest": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"request_idempotency_key": "post-order-1001"
}服務不會用新輸入重新建構程式;它重新檢查目前權限、定義、列版本、實際讀取、約束與每個審批義務,才套用儲存動作。定義、讀取集合或資料列改變時,可能需要重新準備;舊預覽不是寫入授權。提案預設存活 900 秒,不能晚於附加 selection 的到期時間;每個 principal 最多 100 個有效提案。
升級備註(backend 5.22.0):提案的資料表 policy snapshot 不再包含資料表 settings 裡的座標索引狀態。升級前為「引用含座標欄位之資料表的 Command」準備的提案,會在升級時失效一次,而且無法復原(沒有索引狀態的資料表,snapshot 不變):此後準備者檢視它、每一次正式寫入(包含重送已完成的正式寫入)、重送它的 request_idempotency_key,以及讀取由它送出的 operation,都會回 409 ct.proposal_stale,審查者檢視它則仍可看到。請以新的 request_idempotency_key 重新準備。之後索引進度不會再讓提案失效。
凍結 selection
建立 selection 需要版本 2 query Command,傳入 command_digest、inputs、maximum_rows(1–10000 的嚴格整數)與 request key。它凍結完整實際讀取集合,不只是顯示結果頁;超量時拒絕,不截短 manifest。首次建立回 201,相同內容重播回 200。存活 900 秒,每個 principal 最多 100 個有效 selection。
回應包含 selection_id、manifest_ref、query/content digest、時間戳記、row_count、列/版本參照與 next_cursor。每頁最多 100 個參照;GET 接受 limit 1–100(預設 100),選用 cursor 為 1–512 字元。不能跨 selection 重用 cursor。範圍、請求者、目前權限、到期與讀取集合是否過期都會重新檢查,不會默默更新過期 selection。
已合併 CT 來源 #2015 從 table source 的整表 logical column-read 證據排除目前呼叫者看不到的欄位,避免 phantom hidden-read 相依;這不授權隱藏運算元,也不免除列版本、真正 consumed-read 或現行權限檢查。
收據與恢復
同步正式寫入成功時回 command_status: "applied"、batch_status: null、receipt 與 external_effects。CtOperationResponse 較廣的狀態 enum 不代表此流程已實作每一種 batch 工作流程。
Operation 提供 operation/proposal ID;收據帶有 receipt_id、committed_at、command/proposal/effect hash、effects digest、有上限的 {effect_ref, kind, resource_id} 清單、truncated 與 output_artifact_id: null。收據截短不代表省略的 effect 沒有發生。Callback 傳遞狀態與資料庫 commit 收據不同;操作已提交不等於外部服務已接收 callback。
以相同 key 重試,或重播同一個已套用提案,會在重新檢查目前權限後回傳原有持久 operation,並設 replayed: true。收到 503 ct.operation_outcome_unknown 時,保留 operation_id 並查詢 operation,不要直接產生新的正式寫入 key。
型別化拒絕使用 CtProblemResponse:detail 是 {type, loc, msg, retry_advice, operation_id} 清單;retry advice 為 do_not_retry、reprepare、query_operation、fix_input 或 retry_same_key。重要代碼包括 ct.definition_stale、ct.proposal_stale、ct.record_version_conflict、ct.selection_stale、ct.request_key_reuse、ct.constraint_violation 與 ct.operation_failed。已合併 CT 來源 #2015 在路由原先描述的 409/422/429/503 problem 回應加入 HTTP 500;權限失敗統一為 Not found,資料表鎖定則保留 423。不要把 schema 列出的每個代碼當成可用功能。
區分過期證據與服務失敗
已合併來源 3085346728403c45e7a4d832223fdcd7d895d43d(#2015)仍對真正的 schema/source-version/link/authority/frozen-manifest 變更與不可用 template 使用適用的 stale 回應。非預期失敗不再冒充過期 proposal 或 authority unavailable:
| 失敗類型 | 回應與 retry advice |
|---|---|
| Command/query timeout、authority lock conflict、effect-identity lock | 409 ct.operation_in_progress;retry_same_key |
| Request key 已綁定不同內容 | 409 ct.request_key_reuse;do_not_retry |
| 無法滿足目前資料表約束 | 422 ct.constraint_violation;fix_input |
| 尚無已提交收據時的非預期內部失敗 | 500 ct.operation_failed;retry_same_key |
Stored-definition validation/dependency 變更仍與非預期重新編譯失敗區分。Server failure log 只記錄根本 exception 類別、source module/line 與 request step,不記錄私密 exception text、inputs 或完整 traceback。提交後的 503 ct.operation_outcome_unknown 仍須查詢收據;500 不代表可以安全改用新 posting key。這些是來源契約,不代表部署或本文件 lane 的行為驗收。
CT Agent 與 MCP
MCP 提供 commands_prepare、commands_invoke、commands_selections_create、proposals_get、operations_get、selections_get。Governed adapter 保留 plan/commit 確認;Review 核准與使用者確認不能互相取代。帶有 proposal_policy 的 Agent 產生工具,即使聊天室關閉確認,也只準備提案,並告知正式寫入需要另一個明確動作,不會核准後自動寫入。
另見 Command 參考、彙總約束 與執行語意。Build capability discovery 宣告 ct.proposals,不授予資料權限,也不證明 staging 已部署。