Skip to Content
核心概念規則require_approval

require_approval 規則

require_approval 把符合條件的寫入從「立即落地」改成「先暫存、送 Review 模組、核准後重播」。它適合高風險資料變更,不是一般 validation error。

Payload

{ "type": "require_approval", "name": "高額訂單需主管核准", "label": "高額訂單變更", "events": ["create", "update", "delete", "restore"], "template_id": "44444444-4444-4444-8444-444444444444", "when": [ { "column": "金額", "op": "gte", "value": 100000 } ] }

events 是 create、update、delete、restore 的非空子集合。template_id 必須是同公司、仍可用且 gates 有效的 Review template。每張表最多一條 require_approval。選填的 exclude_requester 布林值(預設 false,只有為 true 時才儲存)會啟用排除送審者;非布林值是 400 require_approval exclude_requester must be a boolean。

Template 的 reviewer 在存檔當下就被驗證

存規則時會載入該 template,並執行與 Review 模組建立 template 時相同的 gate 驗證,因此「reviewer 根本無法登入」的 gate 會在這裡被擋下,而不是等到之後才發現流程卡在 in_review、票沒有人投得了。Template 在 Review 模組中建立與管理,該模組不在本手冊範圍內。

驗證失敗時 rules.set 回 400,detail 是一個把 Review 模組原訊息包起來的純字串:

review template '44444444-4444-4444-8444-444444444444' has invalid gate groups: review users not found or inactive: ['77777777-7777-4777-8777-777777777777']

冒號之後是實際觸發的那一項檢查 —— review groups not found: [...]、review groups have no active members: [...]、review users not found or inactive: [...],或 gate {i} would assign {n} reviewers, exceeds max 500 —— id 只列出前五個。rules.preview 回完全相同的 400,所以 preview 不會接受存檔會拒絕的東西。Template 不存在、非 live 或屬於其他公司,則是另一則 400 review template '<id>' is not usable. template must exist, be live, and belong to this table's company。

走 IaC rule line 的路徑時,同一段文字不是 HTTP 400:apply 會把它記成該行的 per-resource apply error 寫進 apply report,request 本身仍然成功。

Gate 直接指名一個人({"type": "user", "user_id": "<uuid>"} leaf)的 template 同樣是合法的 require_approval 對象,套用相同的檢查。

409 是 staged success

第一次符合的寫入會建立 staged change,回傳:

{ "detail": { "error": "approval_required", "process_id": "55555555-5555-4555-8555-555555555555", "rule_id": "rule_a1b2c3d4", "rule_label": "高額訂單變更", "staged_change_id": "66666666-6666-4666-8666-666666666666" } }

前端應把它呈現成「已送審」,保存 process_id 與 staged_change_id,不要自動重送。同一目標已有待審變更時會收到 409 approval_pending({"error": "approval_pending", "process_id", "staged_change_id"})。對 create 與 upsert 而言,待審的鍵是比對欄位的值;當某個單一 component 的 unique_tuple 涵蓋該欄位時,鍵會依該 tuple 的正規化——case folding、NFC 與 null 政策——計算,所以 null_policy: "equal" 時兩個空的比對值也會以 approval_pending 碰撞,而 forbidden 時 null 的比對值會被拒絕。

哪些寫入會命中,是依操作分別判斷的。revert 視同 update。有 when 時,update 只要舊列或合併後的新列其中之一符合就會命中;delete 與 restore 以舊列判斷;create 以即將插入、已補上預設值的那一列判斷。在 decimal 欄位上,when 的值必須是純十進位字串("100000"),與所有規則 predicate 相同。

每位 actor 在每張表最多保留 500 筆 pending staged changes;每張表跨所有 actors 最多 50 筆 pending create。任一上限超過時回傳 429:

{ "detail": { "error": "staged_cap_exceeded", "scope": "actor", "limit": 500 } }

另一個 variant 是 {"scope":"table","limit":50}。前端必須依伺服器回傳的 scope 與 limit 呈現訊息;不要只寫死一種佇列上限,也不要假設所有 429 都是 actor cap。

有待審或套用中的變更時,修改或移除 approval rule 會收到 409 {"error": "approval_rule_locked", "pending_count": <n>}。Trigger 也與 approval gate 互斥,避免自動寫入累積無法審核的暫存工作:以這張表為目標的 create_record/update_record action、這張表自身 trigger 上的 delete_record action、以它為目標的 materialize_slots action,以及所引用指令會寫入它的 invoke_command action,不論哪一邊後存,都會回 409 approval_trigger_conflict。

排除送審者

預設情況下,送出受審批管控之寫入的人,也可以是它的審核者之一。設定 exclude_requester: true——或是 Review template 本身帶有 exclude_requester 旗標(在 Review 模組中設定,本手冊不涵蓋),或對 Command 而言它的 definition 帶有這個旗標——送審者就不能核准自己的變更。有效旗標是這些來源的邏輯 OR,並在送出當下隨 Review process 一起快照,所以之後編輯規則或 template,只會影響之後才送出的 process。

  • 誰是送審者。 不論傳輸方式,寫入背後已驗證的人類:使用者(JWT、OAuth 或 MCP、API key、內部 agent、callback token 的建立者)除非是服務帳號,否則就是他自己的送審者;Agent 平台 client 會解析為它所委派的存活人類;其他一律沒有人類歸屬。
  • 送出時。 在評估 gate 之前,送審者會從每個 gate 的每一個審核者葉節點(直接指定或群組)中被移除。若某個必要 gate 因此沒有任何合格的核准者,寫入會以 409 {"error": "no_eligible_approver", "message": "Excluding the requester leaves a required review gate with no eligible approver", "gate_order": <n>} 被拒絕,且不暫存任何東西——絕不會自動核准,也不會留在 pending。若送出的主體沒有已驗證的人類身分(服務帳號、不支援的 client),寫入會以 409 {"error": "requester_unattributable", …} 被拒絕:排除送審者是 fail closed,而不是排除不了任何人。
  • 核准時。 Review 模組會拒絕送審者的任何一票(核准或否決),回 403 requester_cannot_approve。
  • Release 時。 引擎在套用之前會再檢查一次:若快照中的送審者投過核准票,staged change 會被丟棄(Command 計畫以 requester_cannot_approve 為原因被丟棄),而且不會寫入任何東西。

其他拒絕與上限

情況回應
寫入通過入口檢查之後才開始 schema 遷移,且規則有符合423 {"detail":{"error":"table_locked","message":"table is undergoing a schema migration; retry shortly"}}——是物件 detail,不同於入口檢查的字串 423 Table is currently locked for operation: <op>。不會暫存任何東西;遷移結束後再重試
符合的規則所指向的 Review 範本不存在、已被軟刪除或屬於其他公司單筆寫入(紀錄、callback、agent 工具)、同步的 POST …/records/bulk 與 command 都回 409 {"detail":{"error":"approval_template_unusable","rule_id","rule_label","template_id"}}。不會暫存任何東西;請修正規則的 template_id,不要重試
這張表(或列為成員的表)還有 pending 或 applying 的 staged change 時新增、修改或刪除欄位423 {"detail":{"error":"approval_holds_pending","pending_count":<n>}}。請先讓這些變更結案或捨棄。超過 10 000 筆紀錄的資料表刪除欄位時會以背景遷移執行,所以請求會被接受,這個阻擋改以刪除失敗的形式出現
受審核的佇列式批次新增、更新或刪除超過 1000 個 actionTicket 以 failed 結束,帶 error: {"error":"gated_batch_too_large","limit":1000} 與 error_message gated batch exceeds the approval row limit (1000); split it or narrow the rule;不會暫存任何東西。規則的 events 涵蓋批次的操作時就會檢查,時間早於 when 的判斷。同步的批次路由每批最多 100 個 action,所以永遠不會碰到這個上限

核准之後,變更以領取(claim)的方式套用:每次領取都計一次嘗試,被領取超過五次的變更會以 max apply attempts exceeded 結束為 apply_failed,並通知申請人。停在 applying 且 600 秒沒有心跳的變更,會被下一次派送重新領取,所以當掉的套用最多可能停在 applying 約十分鐘。核准的 revert 會依資料表目前的 schema 重播:目標版本已經不相容時——欄位已移除、缺少必填欄位、型別不符,或值被目前的欄位規則拒絕(例如已停用的 select 選項)——變更會以 apply_failed 結束,而不會寫入。

審核者看不到暫存寫入的全部內容。column_acl 讀取權限不是 all 的欄位,以及不在任何授權 visible_columns 允許清單內的欄位,都會對每一位審核者(包括管理者)從 Review 內容的 diff 中省略——沒有 key,也沒有名稱——但暫存的寫入本身仍會寫入它們,所以 diff 裡少了某個欄位不代表「沒有變更」。在這種資料表上儲存 require_approval 規則時,warnings 會帶一則警告:require_approval rule '<label>': this table restricts column visibility via column_acl or grant visible_columns — those columns are omitted from the reviewer-facing approval content for every reviewer. Review 內容另有 65 536 bytes 的上限:超過時會加上 "truncated": true,並依 review_manifest、actions、tables、diff 的順序清空體積較大的 key,直到符合上限為止;暫存的寫入本身仍然完整。

完整流程——template 前置條件、writer 收到的 409、reviewer decision 與 release/discard——見核准流程指南。端點資料見 rules.set、stagedChanges.list 與 stagedChanges.discard。

Last updated on