Skip to Content
核心概念規則invariant(SCP)

invariant 規則(SCP)

invariant 是 principal-blind 的資料完整性 floor:不論誰寫、從哪個入口寫,列的 post-image 都必須符合 policy。它特別覆蓋一般使用者寫入、trigger actions、callback,以及核准後 staged change 的實際套用,避免某個 carrier 成為繞過路徑。

只有 policy form

{ "type": "invariant", "name": "完成案件必須有結案日", "policy": { "if": { "column": "狀態", "op": "eq", "value": "完成" }, "then": { "column": "結案日", "op": "is_not_null" } }, "enforcement": "observe" }

invariant 不解析任何房間 scope,因此不接受 channel 的 flat column / require_present form;需要固定 link 集合時,請在 policy leaf 明確提供 IDs。它可用於 chatroom、department、company 三種 scope,也可以與 triggers 共存。每張表最多四條 invariant,全部以 AND 組合,且仍受全表 10 條規則上限約束。

when 不適用;條件必須像上例放在 if node 中。規則判斷 create、update、restore 與 revert 的 post-image;delete 沒有需要驗證的 post-image,因此不由 invariant 否決。既有不合規列仍能被修正,只要修正後的 post-image 合規。

Policy node grammar

Invariant 與 channel 共用同一個 bounded grammar:最深 5 層、最多 24 個 leaf、其中最多 6 個 link leaf。

節點Shape語意
AND{ "and": [node, ...] }全部成立
OR{ "or": [node, ...] }至少一個成立
NOT{ "not": node }反轉結果
IF{ "if": node, "then": node, "else": node? }else 時是 guard:condition false 即通過
Scalar{ "column": name, "op": op, "value": scalar? }本表 stored scalar predicate
Link membership{ "link": name, "op": op, "value": [id]?, "require_present": bool? }固定 ID 集合條件
Link target{ "link": name, "target": node, "quantifier": "any" or "all", "require_present": bool? }一跳檢查 linked record

Scalar operators 是 eqneqgtgteltlteincontainsis_nullis_not_null。Link membership operators 是 subset_ofnone_inis_emptyis_not_emptyeqin

subset_ofeqin 必須明確指定 require_presentin 是 multi-id 集合的 subset sugar,eqvalue 恰好一個 ID。is_empty / is_not_empty 不帶 value。Link target 僅一跳;quantifier: "all" 必須明確指定 require_present,避免空集合的 vacuous truth。若條件 branch 會約束 link,if condition 應由 link_target 的權威資料判斷,不可由 writer-controlled scalar 自我宣告。

以下規則要求每筆庫存都連到至少一個啟用中的產品:

{ "type": "invariant", "name": "產品必須啟用", "policy": { "link": "產品", "target": { "column": "啟用中", "op": "eq", "value": true }, "quantifier": "all", "require_present": true }, "enforcement": "enforce" }

observe 再 enforce

enforcementobserveenforce,預設 observe。Observe 會執行相同評估並回報 preview 診斷,但不拒絕寫入或遮蔽讀取;切到 enforce 前,請先處理 preview 中的 invariant_violations。Enforce 違規會以 403 並帶 machine-readable detail.error: "scp_invariant_violation" 拒絕。

使用 rules.preview 驗證候選 policy,再用 rules.set 發布完整清單。

同表若還有 channel 規則

Invariant 本身不解析任何房間 scope。不過同一張 department table 若也有 enforcing channel 規則,呼叫仍必須通過那道 floor——而 channel floor 是從呼叫者所屬的房間解析出來的,不是從 query parameter。這裡沒有東西可以重試:?acting_chatroom_id 已於 2026-07-29 從所有路由移除,現在只會被靜默忽略。

兩道 floor 的失敗方式不同,請以 detail.error 分支,不要用 HTTP status:

detail.error由誰擋下意義
scp_invariant_violationInvariantPost-image 對任何寫入者都不合法。修正該列
scp_scope_undeclaredChannel你所屬的存活房間,沒有一個在這張表上宣告 scope_values。同一張表的讀取不會報錯,而是回 200 零列或 uniform 404
scp_out_of_scopeChannel你那些房間的合併 scope 沒有涵蓋這一列的 link targets

合併 scope 如何解析、以及為什麼 agent session 的答案可能比 REST 更窄,見 union 契約

整體安全層次與 ACL 的關係見 ACL 的 SCP 總覽

Last updated on