Skip to Content

IaC 錯誤目錄

IaC 錯誤先按階段處理:parse 決定每個實體行能否成為合法、符合 kind schema 的 object;validate 再跨行解析 refs 與語意關係。修正前一階段後才處理下一階段,能避免被連鎖錯誤誤導。

錯誤形狀與階段

除了下方另述的同步 parse abort,伺服器的 per-line 錯誤 envelope 是 {line, kind, ref, phase, code, detail}

  • line 是原始 JSONL 的 1-based 實體行號,包含空白行—— 0 是合法值,代表「與任何文件行無關」。
  • phaseparsevalidatediffapply 其中之一。
  • code 是選填的穩定 enum,共有 iac_plan_staleretryable_lock_conflict 兩個值;不屬於這兩種分類的舊有 diagnostics 不設值。

工作台顯示的是該 envelope 中的 {line, phase, kind, detail}。完整回應形狀請以 plan 參考為準。

Phase 決定一個錯誤造成多大破壞。Request-time parse abort 什麼都不執行,並回 flat-detail 400validate 錯誤同樣不執行,但以 422 回傳 per-line list——除非更早的 supplied-plan_hash mismatch 已先產生 409 plan_stale。Parse、validation 與 hash 檢查都在 asynchronous dispatch 前執行,所以這些 request-time failure 都不會產生 ticket。diff 階段錯誤不會阻擋 applyability:同步 apply 回傳 200,只略過該行,再繼續處理其他可執行的行。apply 階段錯誤同樣位於成功 apply result 的 per-line 錯誤中;失敗的行會回滾自己的 transaction,然後繼續執行。大型文件通過 preflight 並拿到 202 後,worker 會強制重新 parse 與 plan 已暫存的 bytes;只有這個 worker-side recheck 的失敗才會變成下方所述的 terminal parse_errorvalidate_error ticket。

以下 code block 的 detail 是 byte-exact 形式。{name} 代表錯誤當下插入的實值,不是回應裡會保留的大括號。已驗證的本機字串來源是 components/iac/parse.ts:117-295,298-444,494-784,1101-1284

Parse 階段

文件與 JSON

document exceeds {max_bytes} bytes document is not valid UTF-8 excessively nested JSON structure (max depth 128) invalid JSON: {detail} header must be the first line and unique record cap exceeded for table '{table}' ({max_records}) line cap exceeded ({max_lines}, record lines exempt) table cap exceeded ({max_tables})

這個順序就是實際檢查順序,而且看得出來。byte 上限與 UTF-8 解碼屬於文件層級,在進入逐行迴圈前只跑一次;其餘全部逐行執行,而巢狀深度守衛是第一個逐行檢查——排在 json.loads 之前、line kind schema 驗證之前、header 規則之前,也在三個 cap 之前。因此一行同時「過深」且「JSON 壞掉」時,回報的是 excessively nested JSON structure (max depth 128),不會是 invalid JSON: {detail};一行同時過深且會撞上 record cap exceededline cap exceededtable cap exceededheader must be the first line and unique 時,回報的也是巢狀中止,不是那些 cap。

深度上限固定為 128,不是 CUSTOM_TABLE_IAC_MAX_* 那組環境變數之一,各部署無法調高。它計算的是整個實體行上的 [{,包含 line envelope:record line 最外層的 { 是 depth 1、其 data object 是 depth 2,所以 record payload 實際可用約 125 層。字串字面值內的括號不計入,反斜線跳脫也會被正確處理。比較是嚴格大於——量到 128 通過,129 中止——而且每一行各自判定,因此 500 行淺文件完全不受影響。這個預算刻意留有餘裕:最深的合法 payload 是 command definition,它自己的 JSON 深度上限是 64。

在這個守衛存在之前,唯一的巢狀保護是 json.loads 外層的 RecursionError catch,而現代 CPython 根本不會觸發它。於是一顆 nesting bomb 會乾淨地 parse 完、通過 schema 驗證,並一路進入 diff 與 plan——被 deep copy、重新序列化、重建成 Pydantic model——之後才可能碰到較窄的限制,而且只在 json 欄位上(MAX_JSON_CELL_DEPTH 32)。

同一類輸入在工作台回報的是不同字串:它的遞迴 parser 會爆棧,輸出 invalid JSON: excessively nested JSON structure——有前綴、沒有深度,而且來自 RangeError 而非量測出來的上限。只有伺服器端的字串帶 (max depth 128)。工作台也會重現 JSON decoder 的 detail,例如 invalid JSON: Expecting property name enclosed in double quotes。伺服器另負責 byte/UTF-8 與部署上限;本機驗證不取代 server limits。

這一族已經沒有「feature flag 關閉」的分支。CUSTOM_TABLE_IAC_V14 已刪除,因此 plan、apply、state 與 export 無條件可用,上面那些上限就是 parse 階段唯一會產生的 400。另外有兩個 request body 的 400 位於端點層:

Provide the JSONL document as a 'file' multipart part or as the raw request body Empty document: provide the JSONL as a 'file' multipart part or as the raw request body

Request-time parse 中止的格式是 line {n}: {detail},而且——與本頁其他所有錯誤不同——它是以扁平的 400 detail 字串送出,不是 {line, kind, ref, phase, code, detail} envelope:parse 是全有全無,沒有 per-line 清單可以承載。文件層級的中止使用 line 0。這個回應發生在 dispatch 前,絕不會產生 async ticket。若文件已經拿到 202,之後在 worker 強制重新 parse 已暫存 bytes 時才失敗,poll wrapper 會改帶 body.status: "failed"body.error.code: "parse_error",以及 body.error.message: "line {n}: {detail}"。Worker-side replan 若已不 applyable,則使用 body.error.code: "validate_error" 並附上 per-line errors。這些是防御性 worker recheck,不是 caller 原始 malformed 或 invalid request 的另一種回應。

Export 在自己的輸出會撐破行數上限時另有一個 400

export would produce {n} non-record lines, exceeding CUSTOM_TABLE_IAC_MAX_LINES ({max}); narrow the export with table_ids= or set include_records=false

這個上限現在也把 insight_selectionpublic_readcommand 行算進去。

Pydantic 欄位契約

缺少必填欄位、literal/enum 不符、型別錯誤、pattern/長度違規與未知欄位,會用後端 parser 的 JSON-serialized Pydantic issue list 呈現。工作台最多保留前三個 issues。缺少 header version 的精確 detail 是:

[{"type": "missing", "loc": ["header", "version"], "msg": "Field required", "url": "https://errors.pydantic.dev/2.12/v/missing"}]

record.on_drift: "merge"client_access.spec.passphrase_enabled: "maybe" 的精確例子:

[{"type": "literal_error", "loc": ["record", "on_drift"], "msg": "Input should be 'skip' or 'update'", "ctx": {"expected": "'skip' or 'update'"}, "url": "https://errors.pydantic.dev/2.12/v/literal_error"}]
[{"type": "bool_parsing", "loc": ["client_access", "spec", "passphrase_enabled"], "msg": "Input should be a valid boolean, unable to interpret input", "url": "https://errors.pydantic.dev/2.12/v/bool_parsing"}]

Validate 階段

Ref、順序與碰撞

duplicate table ref '{ref}' duplicate ref '{table}.{ref}' (already declared in this document) unknown table ref '{table}' unknown table ref '{table}' (target) unknown table ref '{table}' (source) unknown column ref '{table}.{ref}' unknown column ref '{table}.{ref}' (link_field) unknown column ref '{table}.{ref}' (target_column) unknown column ref '{table}.{ref}' (match) unknown column ref '{table}.{ref}' (filter) unknown column ref '{table}.{ref}' (expression)

columnruletriggerviewpublic_read 在同一 table 共用 qualified-ref 空間,因此跨 kind 重名也會命中 duplicate refcommand ref 以自己的完整 qualified 字串碰撞,重複的 insight selection 則有專屬訊息:

duplicate ref 'command:{ref}' (already declared in this document) duplicate insight_selection line for chatroom '{uuid}'

工作台的 ref 驗證來源是 components/iac/parse.ts

Grant

unresolved visible_columns ref '{token}': unknown column ref '{table}.{token}' unresolved read_filter ref '{token}': unknown column ref '{table}.{token}' unresolved edit_filter ref '{token}': unknown column ref '{table}.{token}' can_read "filtered" requires a read_filter read_filter is only valid when can_read is "filtered" can_edit "filtered" requires an edit_filter edit_filter is only valid when can_edit is "filtered" row policy {path} must be one of {"and": [nodes]}, {"or": [nodes]}, {"not": node}, a {"column", "op", "value"} predicate or a {"link", "quantifier", "target"} link_target leaf row policy {path} "{and|or}" must be a non-empty list of nodes row policy {path} "not" takes exactly one node, not a list row policy {path}: {kind} node has unknown key(s): {keys} row policy {path}: link_membership leaves are not supported in row policies — use link_target with a target {"column": "id", "op": "in", "value": [...]} row policy {path}: quantifier must be "any" or "all" row policy {path}: require_present must be stated explicitly (true/false) on quantifier "all" — all([]) is vacuously true row policy {path}: require_present does not apply to quantifier "any" (already false when there are no linked records) row policy {path}: "link" must name a link column (internal col_<hex> key) row policy {path}: a link leaf may not appear inside a link_target's target (row policies are 1-hop) row policy {path} nests deeper than the max 5 levels row policy exceeds max 24 leaves ({n}) row policy exceeds max 6 link leaves ({n})

row policy … 開頭的字串與伺服器的 row-policy 文法驗證器(custom_table_row_policy.py)逐條對應;{path} 是節點位置,例如 or[1].not,根節點時為空。public_read.read_filter 回報相同字串,並加上 read_filter: 前綴。

精確來源:components/iac/parse.ts

身分 Token

所有接受可攜身分 token 的介面共用的語法錯誤。括號裡的 {hint} 是該通道自己的文法:cell 通道——record cell、trigger when 值、invoke_command 輸入、link 自然鍵,以及 table.spec.moderators——的內容是 expected '$user:<username>', '$smc:<platform>:<platform_user_id>', '$room:<chatroom name>' or '$room:<department name>/<chatroom name>'grant 通道——grant.principal.idinsight_selection.chatroom——會在 username 那一項之後插入 '$dept:<department name>',而 empty department name 也只會出現在那裡。

malformed principal token '{token}': empty username|empty chatroom name|needs platform AND platform_user_id ({hint}) malformed principal token '{token}': empty department name (expected '$user:<username>', '$dept:<department name>', '$smc:<platform>:<platform_user_id>', '$room:<chatroom name>' or '$room:<department name>/<chatroom name>') unrecognized principal token '{token}' ({hint}) principal token '{token}' does not match the column's type: a {kind} column expects {prefixes} or a raw id unknown principal kind '{kind}' for token '{token}'

{prefixes} 是該 kind 自己的前綴集合,以 or 串接:user 欄位是 $user:<...>social_client$smc:<...>principal$user:<...> or $smc:<...> or $room:<...>,grant 則是每種型別一個前綴。這道閘門在任何查詢之前執行,所以 token 帶的名稱不必存在;而因為 $dept: 只用於 grant,任何 cell 裡的 $dept: 得到的正是這一則錯誤。

解析錯誤:

principal token '{token}': no user with username '{name}' in this company principal token '{token}': user '{name}' is deleted principal token '{token}': no department named '{name}' in this company principal token '{token}': department '{name}' is deleted principal token '{token}': no live chatroom named '{name}' in this company principal token '{token}': ambiguous — {n} live chatrooms are named '{name}' ({ids}); qualify it as '$room:<department name>/{name}' principal token '{token}': no live chatroom named '{room}' in department '{dept}' in this company principal token '{token}': ambiguous — {n} live chatrooms match ({ids}) principal token '{token}': no social client with platform user id '{id}' on platform '{p}' in this company principal token '{token}': ambiguous — {n} social clients match, in chatrooms {ids} cannot resolve this scope's company for principal token resolution trigger when column '{col}': {token error} invoke_command input '{name}': {token error}

Token 無法解析的行會以 {prefix}unresolved-{8 個十六進位字元} 形式的佔位 ref 回報,因為 IacPlanAction.ref 有 pattern 限制且不接受 $。它是錯誤標籤,不是資源身分。

Computed 欄位

only name/description can be updated on {link|rollup|lookup|formula} columns (got: {sorted fields}); to change computed config delete and recreate the column (state: absent + new line) pick.order_column requires link_field (picked lookup) to resolve its owning table

第一則是 diff 階段錯誤。它出現在 plan action 上,apply 時整份文件回傳 200 且只略過那一行,而不是文件層級的 422

在 rule 的 policy 子樹內,SCP 的 link_membershiplink_target leaf 會以形狀辨識,並由 plan、apply 與 export 原樣帶過。link_targettarget 子樹指的是被連結表的欄位,永不對 rule 自身的表解析。

這裡沒有對應的錯誤。中途某個版本曾以 unresolved ref '<link>': SCP link leaves (link_membership/link_target) are not yet translatable through IaC — author or edit this rule's policy over REST 拒絕這類 leaf;那則訊息從未成為最終行為,也不應被寫進文件。這條規則的範圍也很窄:在 policy 鍵之外,link 只是普通的 JSON 鍵,欄位也可以就叫做 link

table settings audience

settings.default_permissions.audience "company" is only valid on department-scoped tables settings.default_permissions.audience must be "scope" or "company", got '{value}'

兩者對任何非 state: "absent" 且帶 spectable line 觸發。它們屬於 validate 階段,會擋掉 applyability,apply 回 422 且什麼都不執行。Apply 端會對live 資料表自身的 scope 重跑同一道檢查,因此直接呼叫或使用已 stale、不再與 live state 相符的 plan 都繞不過去;在那裡同一則訊息會變成該行在 200 內的 apply 錯誤。詳見 table line kind

insight_selection

insight_selection is only valid for department-scope documents insight_selection requires a non-empty system (header.system) duplicate insight_selection line for chatroom '{uuid}'

public_read

public_read v1 supports secretless tokens only; declare secretless: true (a Bearer-secreted token cannot be minted through IaC — use the REST mint lane) view ref '{view}' is not a managed view in this document (declare a `view` line for it, or manage it via a prior apply — no view adoption in v1) bound view ref '{view}' is deleted in this document (state: absent) — revoke this token line (state: absent) first, or keep the view bound view ref '{view}' has no live view row (deleted out of band) — re-declare the view (state: present) or revoke this token (state: absent) read_filter predicate must be an object with a 'column' key (got {type}) read_filter predicate is missing a 'column' ref unresolved read_filter ref '{token}': {detail} unresolved visible_columns ref '{token}': {detail}

其中兩則在 apply 端另有寫法。受管理 view 的錯誤會加前綴,並把「for it」寫成「BEFORE this line」:

public_read '{table}.{ref}': view ref '{view}' is not a managed view in this document (declare a `view` line BEFORE this line, or manage it via a prior apply — no view adoption in v1) public_read v1 supports secretless tokens only; declare secretless: true (mint a Bearer-secreted token via REST)

把 grant filter 複製進 token spec 會在 mint 時失敗,因為公開 token 沒有操作主體:

read_filter may not reference $me / $me.department on a public token (no principal exists); $today and $now are allowed

command

unknown table ref '{tref}' command adoption requires the live command to match the declared spec; export the live command or use a distinct name ambiguous adoption: {n} live commands named '{name}' redacted callback values require an existing managed command; replace them before recreating it redacted callback values require an existing managed command; replace them before creating in a fresh scope

ambiguous adoptiondiff 階段錯誤,與既有的 table 版本 ambiguous adoption: {n} live tables named '{name}' 同類——apply 回傳 200 且只略過該行。其餘四則會阻擋 applyability。

Record

table '{table}' has no resolvable key column for record matching key column '{key}' is a {boolean|json} column and cannot be a natural key ({reason}) unknown column ref '{token}' in record.data

Key 欄位的訊息涵蓋三種不可作為 key 的型別。{reason}boolean 時是 a two-value domain cannot uniquely match records,在 jsoninterval 時是 {type} values have no canonical bind representation and cannot uniquely match records。Principal(principalusersocial_client)欄位可以當自然鍵。

精確來源:components/iac/parse.ts。伺服器 plan 看見 live records 後還可能回傳:

record data missing required key column value ('{internal_key}') duplicate key value {value_repr}: {count} record lines in this document declare the same new key ambiguous key value {value_repr}: {count} live records match

Apply 階段

以下錯誤出現在 200 apply 回應的 per-line 錯誤中。失敗的行會回滾自己的 transaction,apply 再繼續處理其他可執行的行。

moderators not found (or deleted): ['{id}'] moderators outside this table's company: ['{id}'] cannot resolve this table's company for moderator validation settings.default_permissions.audience "company" is only valid on department-scoped tables settings.default_permissions.audience must be "scope" or "company", got '{value}' command '{ref}': table no longer resolves live command '{ref}' has pending staged executions command '{ref}': tag not found in this scope command '{ref}': tables outside tag: {ids} command '{ref}': document system tag is required a command named '{name}' already exists in this scope command '{ref}' is referenced by table triggers (command_referenced_by_trigger): table '{name}' ({id}) trigger '{name}' ({id}) command changed after planning; run plan again trigger changed after planning; run plan again Concurrent write conflict (lock); please retry the request. insight_selection '{insight.uuid}': chatroom does not exist or is deleted insight_selection '{insight.uuid}': chatroom belongs to a different company insight_selection: chatroom token '{token}' now resolves to a different chatroom than it did at plan time; run plan again principal column '{internal key}': {token error} view '{table}.{ref}': invalid configuration ({n} field error(s))

principal column '{internal key}': {token error} 是上方身分 token 錯誤在 apply 端的對應形式。只有當該 record 行的 principal 欄位是同一份文件較早處宣告時才會走到它——plan 會帶著 warning 延後該行,executor 再重跑一次替換,因此失敗是以 200 內的 applied: false 出現,而不是 422。見 record line kind

Link cell 的解析失敗——包含 principal 自然鍵目標的 link 清單裡的身分 token——回報的 refrecord:{line},不帶純量 record 錯誤所使用的 {table}. 前綴。

command changed after planning; run plan againtrigger changed after planning; run plan again 會帶 code: "iac_plan_stale"。若 apply exception 被分類為 MySQL 12051213,則會帶 code: "retryable_lock_conflict",detail 是淨化後的 Concurrent write conflict (lock); please retry the request.;回應絕不洩漏原始資料庫文字、SQL 或參數。其他 diagnostics 的 code 不設值。

command '{ref}': table no longer resolves live 刻意統一措辭:它不區分「不存在」與「不屬於你」。view 那一行在 spec.config 帶了 CustomTableViewConfig 沒宣告的 key 時觸發——config 在 parse 階段是自由 dict,工作台攔不到,這個檢查在 apply 時 fail-closed 執行(見 view line kind)。

有兩則 apply 錯誤帶 line: 0,因為它們無法歸屬到任何文件行——兩者都以 kind: "table" 與 header 的 system 作為 ref:

tag sync failed: {exception} orphan prune failed: {exception}

Orphan-prune maintenance branch 也使用同一個 lock classifier。若其 exception 是 MySQL 12051213,line-0 detail 會是 orphan prune failed: Concurrent write conflict (lock); please retry the request.,且 coderetryable_lock_conflict。這同樣要求重新 plan;不可因此重播舊 apply body。

Apply 也拒絕回吐原始例外文字,因為它可能夾帶明文密語或未經淨化的 integrity error:

invalid configuration ({n} field error(s)) ← view 行會帶前綴:view '{table}.{ref}': … client_access configuration is invalid ({ExcType}) command configuration is invalid ({ExcType})

看到這幾則時,真正的原因在伺服器日誌,不在回應裡。

文件層級的狀態碼

狀態碼Detail時機
200IacApplyResponse同步 apply 已完成。仍須檢查 per-line resultserrors;HTTP success 不代表每一行都成功
202ticket_idIacApplyTicketResponseParse、validation、plan 與 hash 檢查通過後,record-line 數量超過同步上限;接著輪詢 public task route
400Flat detail 字串JSONL 格式錯誤、UTF-8 無效,或撞到 document/line/table/record cap。完全沒有執行,也不會建立 ticket
404Chatroom not foundDepartment not foundCompany not foundRoute 無法解析指定 scope;此外 chatroom apply 有一般的 per-mutation root re-lock,command mutation 另有涵蓋三種 scope 的 command-root lock,但 department/company 並沒有套用到所有 line kind 的一般 mid-apply fence
409{"code": "plan_stale", "message": "…", "plan_hash": "…"}Apply 帶的 plan_hash 與重算的 plan 不符。完全沒有執行
422重算 plan 的 validate-phase 錯誤清單Apply 的文件帶有任何 validate 階段錯誤。完全沒有執行

目前僅本機攔截的 Validator 訊息

工作台會先攔下這幾類源自 Pydantic field 與 model validator 的 detail;它們會在 parse phase 回報(phase: "parse")。伺服器 parser 尚未把它們穩定序列化為同樣的 422 detail,可能落成 500。因此「byte-exact」對這幾類是目前工作台的本機契約,不是已承諾的 server response:

settings.{owned_key} is server-owned and cannot be set via IaC 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) state=present lines require a spec principal.audience is required when principal.type=='chatroom' principal.audience is only valid when principal.type=='chatroom' grant spec 'can_insert' must be a boolean (true/false) or null, not {python_type} grant spec '{field}' must be one of ['all', 'filtered', 'none', 'own'] or null, got {value_repr} rpm may not be null — omit the field to keep the mint default (60) allow_query may not be null — omit the field to keep the default (false)

owned_key 的實例是 column_mappingiacgrant spec 那一類的 fieldcan_readcan_edit。present-requires-spec 這道 guard 有兩種寫法:commandpublic_read 沒有 renamed_from,因此它們的訊息不帶純改名的括號補述。最後兩則是 public_read 的 spec validator,在那裡「省略」與「填 null」是真的不同。精確來源與 local-only 註記:components/iac/parse.ts

Authored 介面上沒有任何地方會靜默忽略未知欄位,但攔截的時機分兩種。頂層拼錯的 key,或具型別 spec(IacTableSpecIacCommandSpecIacPublicReadSpecIacClientAccessSpecIacGrantPrincipal)內的未知 key,在 parse 階段被拒絕。view 的 spec.config 是唯一的自由 dict:它的 key 改在 apply 階段驗證,只讓那一行失敗(view '{table}.{ref}': invalid configuration …),文件其餘部分照常進行。

本機與伺服器驗證

IaC 工作台是無 I/O 的早期回饋:它認得全部十二種 line kind,包含 commandinsight_selectionpublic_read,並驗證 Pydantic 欄位、ref graph、grant policy、public-read token policy 與 record key。它不能讀取 IaC state 或 live scope,因此下列判斷一定要 server plan:

  • ref 是否已 claim 一個仍存在的 resource,或能否唯一 adopt;
  • display/internal column mapping 與跨表 live IDs 是否可解析;
  • live drift、依賴、授權範圍與 resource-specific server constraints;free-dict CRUD model 的最後一層檢查可能直到 apply phase 才執行;
  • record natural key 是否重複或在 live table 中不唯一;
  • 文件大小、table/line/record 部署上限。

有幾類規則在結構上就超出本機能力,一定要伺服器 plan:

  • 與 scope 相關的檢查。 解析器沒有 scope 脈絡,因此 insight_selection is only valid for department-scope documentssettings.default_permissions.audience "company" is only valid on department-scoped tables 永遠不會在本機觸發。它能證明 header.system 那一道,而且確實有做。
  • 身分 token 解析。 本機只檢查到 pattern;$dept:Front Desk 是否存在、是否已刪除、是否有歧義,都是以公司為錨點的伺服器工作。這也表示 duplicate insight_selection line 中「解析後才碰撞」的形式只有伺服器抓得到——本機只有字面完全相同才會碰撞。
  • 受管理 view 的綁定。 public_readview 可能由先前 apply 管理,解析器看不到,因此它不嘗試「這個 view 是否受管理」的檢查。它會執行純文件內的 CASCADE 防護:當被綁定的 view 在同一份文件中宣告為 absent 時。
  • Command definition。 只有 definition.steps[].table 會對文件內的資料表 ref 檢查。運算式預算、步驟形狀與參照解析屬於伺服器 compiler。
  • Public-read mint policy。 SCP channel 規則、強制隱藏欄位的允許清單、跨表 computed 語法與 row-policy token 的合法性,都在每次 apply 重新執行,本機從不重現。

工作台成功只代表可以進入 server plan,不代表可以直接 apply。Plan 成功也不代表可忽略 apply results;apply 是 per-line best-effort,必須檢查每一行的 applied/error。

修正順序

  1. 先修正 JSON 與唯一 header,讓所有 lines 能 parse。
  2. 再修正每個 kind 的 required/optional fields 與型別。
  3. 依文件順序修正 table refs、qualified-ref 碰撞與欄位 refs。
  4. 修正 filtered grant、row policy 與 record natural key。
  5. 重新執行本機驗證,再送 server plan;對 live-only error 以 plan evidence 修正。
  6. 只有在 plan 完全可解釋並通過審查後才 apply。

動手試試

把一份 JSONL 貼進 IaC 工作台,依序製造一個 JSON parse error、一個跨 kind ref collision 與一個缺少 read_filter 的 filtered grant。確認 phase/line/detail 後逐一修正,再對測試 scope 執行唯讀 plan。

Last updated on