rule line
rule 把 table 的規則清單拆成可獨立審查、移動與刪除的 IaC resource。IaC ref 提供穩定 identity;apply 會把各 rule lines 合併進通過既有 rules validator 的完整規則集合。
JSONL Line
{"kind":"rule","table":"orders","ref":"unique_order_no","spec":{"type":"unique","name":"Order number is unique","columns":["order_no"]}}欄位契約
頂層對應 IacRuleLine:
| 欄位 | 必填 | 精確契約 |
|---|---|---|
kind | 是 | 固定 "rule" |
table | 是 | parent table ref |
ref | 是 | table 內的穩定 child ref |
state | 否 | present/absent,預設 present |
renamed_from | 否 | 舊 child ref 或 null |
spec | 條件式 | object;present 必填,只有純 rename 可省略;absent 禁止 |
IacRuleLine.spec 在 IaC Pydantic model 中刻意是 Dict[str, Any],所以本機 parse 不假裝有一個不存在的 typed union。伺服器 apply 會交給既有 TableRulesPayload/shared validator;共同 authored 欄位是必填 type,以及可選 name、when 與 type-specific fields。作者不要提供 server-minted id 或 constraint_id;IaC ref 已負責 identity。
type 的精確集合是 compare、unique、no_overlap、exists、not_exists、transition、check、require、require_approval、channel、invariant、immutable_when。各 type 的必要欄位由 rules validator 決定,例如 unique.columns、compare/check predicates、transition columns、exists/not_exists 的 target/match/where、channel/invariant policy,以及 immutable_when 的 prior_when 與 columns。完整規則 payload 請查閱規則 API。
Ref 與身分規則
Qualified identity 是 {table}.{ref},例如 orders.unique_order_no。同一 table 的 column、rule、trigger、view、public_read refs 與固定的 client_access identity 共用這個空間;任何跨 kind 重名都會被拒絕。
Rule spec 裡位於 column、left、right、start_column、end_column、date_column、sort_by、via 的字串,columns/scope_columns 陣列,以及 filters/data object keys,都被視為同 table 的 column refs。Plan 會 fail closed 地翻成 internal keys;exists/not_exists 的跨表 target/match 語意仍由 server validator 以 live table 關係核對。
由於 differ、executor 與 export 三邊宣告的是同一組 key,immutable_when 的鎖不需要任何特例就能走完整趟:prior_when[].column 由通用的 single-ref walker 接手(column 出現在 spec 任何位置都算 single-ref key,包含巢狀 predicate 清單內),columns 則由 list-ref walker 處理。因此一條鎖能通過 export → plan → apply,並在重新 plan 時是 noop。
Rule spec 也可以帶 $row.{column ref} 樣板 token,export 會寫成 ref,匯入時再翻回內部 key。無法解析的 token 會原樣保留而非 fail closed——詳見可攜身分 token。
SCP link leaf 原樣帶過
在 rule 的 policy 子樹內,SCP 的 link_membership 或 link_target leaf 是以形狀辨識——鍵是否存在,加上各自的允許清單,link_membership ⊆ {link, op, value, require_present}、link_target ⊆ {link, target, quantifier, require_present}——接著由 plan、apply 與 export 原樣複製過去。
要記住的結果是:link_target 的 target 子樹指的是被連結表的欄位,永遠不會對 rule 自身的表解析。過去 ref walker 會依位置比對 target 內裸的 column 鍵,產生誤導性的 unknown column ref '<near table>.<linked column>'——或者當近端表剛好有同名欄位時,靜默把錯誤的 key 寫進儲存的 policy。Leaf 自身的 link 仍會在 apply 時驗證,因此原樣帶過不可能寫入無法解析的東西。
這類 leaf 不會被拒絕。它在 export → plan → apply 之間逐位元組保留,並且是透過 REST 編輯——target.column 無法在 IaC 中撰寫或翻譯。
注意: 這條邊界只適用於
policy鍵之下。在 policy 之外,link只是普通的 JSON 鍵——出現在api_call的 body 或 headers、invoke_command的輸入、json欄位的值——而且欄位本身也可以就叫做link,並成為 viewfilters或 triggerdatamap 的鍵。那些文件會被正常走訪,不會被拒絕。
生命週期與規劃
Present line 可規劃 create、adopt、move、update 或 noop。renamed_from 讓同一 stored rule 換 ref;state: "absent" 規劃從完整 rules 集合移除該 rule。Apply 走 validated PUT path,會保留文件未管理的其他 rules,而不是用單一 line 覆蓋整張表。
Rule semantics 可能建立資料庫 constraint、阻擋既有資料或影響 approval/channel policy。Local parser 與 plan 會先驗證文件內可見 refs、live diff 與集合 cap;free-dict 的 type-specific shared validator 仍在 apply 的持久化路徑執行,因此 apply result 可能再出現 per-line error。
驗證錯誤
Lifecycle、parent 與跨 kind collision:
state=absent lines carry no spec (table lines are the sole adopt-then-delete exception)
state=present lines require a spec (unless a pure rename via renamed_from)
unknown table ref 'orders'
duplicate ref 'orders.unique_order_no' (already declared in this document)若 columns: ["missing"] 無法解析:
unknown column ref 'orders.missing'若合併後的 rule 集合會撐破每表 10 條的上限:
rule cap exceeded (12 > 10); unmanaged rules occupying slots: [names]前兩類 lifecycle detail 目前是工作台的 local-only validator contract;type-specific rules errors 來自 apply 的 downstream shared validator,不屬於工作台 byte-exact 字串。精確本機字串來源:components/iac/parse.ts。
動手試試
在 IaC 工作台宣告 table、order_no column 與範例 unique rule,把 column ref 改成未知值以確認 validate error。修正後對測試 scope plan,再到規則 API核對 type-specific contract。