Skip to Content
核心概念複合指令審批終態來源證據

審批終態來源證據

綁定證據,不接受呼叫者宣告

require_approval.output_map 可在既有具名 Review output binding 加上 terminal_fact;省略即保留一般輸出行為。這是原生審批證據,不是客戶端自稱的證明,也不是新增寫入傳輸。

下列規則片段的 placeholder 須替換為既有 Review/template 及欄位身分:

{ "type": "require_approval", "events": ["create"], "template_id": "<native-template-uuid>", "field_map": {}, "output_map": { "process": {"column": "<process-column-key>", "required": true, "terminal_fact": "process_id"}, "plan": {"column": "<plan-column-key>", "required": true, "terminal_fact": "plan_digest"}, "ballots": {"column": "<ballots-column-key>", "terminal_fact": "ballots"} } }

IaC 保留相同 selector,column 使用既有符號欄位 ref。規則與全部載體須通過 plan/apply 驗證;請用 rule line,不要把原生事實塞進 record seed。

terminal_fact載體型別意義
process_id、terminal_statusstring / text綁定的原生流程與 approved 終態
terminal_versionstring / textcanonical 終態 snapshot 的 SHA-256 身分
completed_atstring / text原生 ISO 時戳,保留分鐘以下精度
reviewer_user_ids、ballotsjson真正決策的 assignment 與 ballot 參照
requesteruser原生內部 requester,不是呼叫者
plan_digeststring / text驗證後凍結 plan 的原生 keyed tcm1: commitment
snapshot_versioninteger凍結 envelope 版本,目前為 2
command_id、command_versionstring / text凍結 Command 與原生 definition commitment
review_answer_digeststring / text原生凍結表單 fields/data 的 SHA-256

command_version 不是 Command DSL 版本;terminal_version 是內容身分,不是配置的流水號。plan/definition commitment 與原生 Review readback 相同,不是儲存的 raw plan hash 或 trigger secret。

交易與拒絕契約

只有驗證通過、approved/completed 的原生 Review,能在凍結 v2 Command 放行時提供事實。證據與業務效果透過既有 action core 在同一交易/版本提交,不是第二次高權限 update。至少須留下最後一筆 evidence row;跨多表異動仍遵守既有單一 approval audience 契約。

  • 呼叫者直接寫入(包括 null 或相同值回送)以 approval_provenance_readonly 拒絕。停用規則不會使受保護欄位變得可寫。
  • 受保護時不可移除/重映射 binding,也不可刪除/retype 載體。
  • 缺少凍結 v2 envelope 的 legacy staging 為 approval_provenance_unavailable。
  • required requester 遇到沒有原生內部 requester 的服務/外部流程會拒絕;不可用呼叫者代替。
  • rejected/cancelled 或 failed/stale 放行不產生證據效果。replay 回傳既有收據,不新增證據列或 ballot。

既有 tenant、ACL、action policy、職責分離與委派檢查仍有效。

終態載體與唯一性約束

原生 Command prescan 只可延後 enabled、matching require_approval 規則中 terminal-bound component 的 null/唯一性檢查,不建立暫時 unique claim。非載體 component 仍須驗證,包括載體排在前面時其他 forbidden null。Disabled、nonmatching 或 wrong-event 規則不適用;update 必須有已知 OLD/NEW image。Insert 與 update 的核准比對均使用 stored-formula post image。

保留 ungated pass 或凍結 held pass 前,每個延後的 record 必須有對應 held verdict;否則以 HTTP 409 approval_decision_diverged 回滾該 pass。這不是一般性的唯一性繞過。

核准放行時注入真正終態事實,以一般 unique lock/database claim 檢查完整 tuple,與所有業務 action 使用同一交易。Null 或 duplicate tuple 會回滾載體、業務列、history 與 claim。原生 Review 保持 approved,hold 改為 apply_failed。失敗收據只暴露 unique_tuple_null_forbidden、unique_tuple_conflict、unique_tuple_hash_collision 或 unique_tuple_claim_unavailable,訊息為 Unique constraint cannot be satisfied.;不含 constraint label、column、value、record ID 或 database 細節。Reject/cancel 丟棄 hold,不寫入終態載體。透過原生 Command 路徑的 Agent/MCP/IaC delegation 仍遵守這些檢查;direct REST 仍以 approval_provenance_unavailable 拒絕,不產生 write 或 hold。

Proposal preparation 仍驗證 deferred-record/held-verdict invariant,且不能簽發原生終態來源證據。已合併 #1996 之後,只允許 write keys 與受保護 dependency set 無交集的既有列 update。此集合涵蓋 terminal rule 的 output-map columns、以 column 為來源的 approval field-map inputs、rule when columns、unique/unique_tuple components,以及解析所得的 column dependencies;無法解析或無法取得的 dependency 都 fail closed。Write set 即使把 protected field 設成原值,仍會拒絕。

Prepared/frozen actions 必須有 target ID、正整數 expected version,且所有 protected old/new value 都保持相同。Preparation 與 frozen-access/release 再驗證此邊界。對 protected target 的 insert、upsert、delete、child-collection/cascade write 或 protected-field update 仍以 HTTP 409 approval_provenance_unavailable 拒絕。被拒的 simulation 回滾,不提交 proposal、Review obligation、hold、業務列、history 或 claim。純唯讀 reference 不是 terminal write;一般 authority/context/stale-state 檢查仍適用。此例外不會讓 proposal 成為原生終態事實的簽發者。

受保護載體不授予讀取權

manager-only 或 grant 遮罩的終態載體是 schema/權限相依,不會自動成為呼叫者輸入。mutation Command 的 field_map 為空時,原生 staging 不要求可讀純輸出載體;同時被當作真正輸入的載體仍须通過一般輸入檢查。具名 Review 輸出及呼叫者/表單輸入不享此例外。

完整、未改格式的契約仍凍結,用於放行時 schema/權限重驗。只有列範圍 kernel capability 驗證的精確原生終態值,可在放行時略過寫入端 hidden-column 檢查。遮罩漂移不能放行舊凍結 Command。沒有 write step 的唯讀 reviewer/delegated-ballot plan 保留保守的完整契約讀取 fallback,可能也要求載體可讀。

成功收據可含 approval_provenance(facts、scope/stage、evidence-row ID)。REST、Agent、MCP、execution GET/list、新舊 inbox 收據、events、replay 與 history 重新檢查現行 evidence-row/欄位可見性。不可讀時,回傳 Command 收據只含狀態/遮罩內容,不含來源證據、step value 或 output value。持久 audit receipt 不會被刪除;definition authority 也不會替 invoker 解除遮罩。

收據保留 key 與安全事件 metadata

approval_provenance 只保留給回傳 body 最上層。任何 mapping 或 array 內的巢狀同名 key,即使值為 null,也 fail closed 為只有狀態的收據,manager 也不例外。最上層 null 本身不會遮罩原本可讀的收據。此讀取投影不會改寫 legacy 已儲存 audit body。

自 backend 5.21.0 起,這個名稱在撰寫階段也會被拒絕。outputs map 含有 approval_provenance key 的 Command definition,會被 POST 與 PUT …/commands 拒絕,並在 POST …/commands/validate 中回報:

{ "detail": { "error": "command_output_reserved", "phase": "author", "message": "approval_provenance is reserved for kernel-owned provenance", "path": "outputs.approval_provenance", "retryable": false, "details": {} } }

狀態碼是 422。宣告這個 key 的 IaC command 行會得到 plan 階段的 validate 錯誤,code: "command_output_reserved",所以該 plan 不可 apply,apply 會在任何變更之前回 422。先前已儲存的 definition 仍可讀取與執行,JSON cell 的值也不會被檢查;但回顯進 output 的巢狀 approval_provenance key 仍會讓所有讀取者的收據變成 status-only,請避免在那裡使用這個名稱。已儲存、而且 output 本身就叫 approval_provenance 的 Command 也一樣:它的每一份收據對所有讀取者(包括 manager)都是 status-only 收據,直到你把該 output 改名為止。

Definer-authority Command 的已授權原始 invoker 仍可讀取不含 provenance 的 ct.command.succeeded 事件,只含 IDs、sequence/version metadata 與 keyed payload digest,不含 execution steps、cell values 或 outputs。現行 Command 可見性及不可變的 execution ownership/manager 檢查仍有效;這不是 execution receipt 或 replay 的例外。

帶 provenance 的 definer events 仍要求 manager 及現行 evidence-read 檢查。授予 non-manager 終態欄位讀取權,不會移除此限制。已過濾的 event feed 仍推進 cursor,並標示 stream_complete:false。

來源為 backend #1896、#1906、#1921、#1965、#2055。本頁是來源文件,不建立瀏覽器或真實模型對話品質驗收。

Last updated on