AI 科技

沒有 Palantir:一頁契約、一支測試、一份核准清單,各做到了 Ontology 的哪一格

2024 年 8 月,Palantir 官方論壇有使用者問能不能用程式碼定義 Ontology,標籤為 Palantirians 的員工帳號答稱正在做、目前還不能用。系列第三篇要拆的是兩年後這句話變成了什麼:一個人、三個公開 repo、沒有平台,語意層與動作層各有哪幾個官方定義的構件,一頁 MODEL.md、一支測試、一份核准清單各自做到了其中哪一格,哪幾格做了也不是同一件事。

2026.09.02 · 作者 dvdmaru · 約 17 分鐘 · 6,369 字

2024 年 8 月,Palantir 官方社群論壇一則討論串裡,有使用者問能不能用 Infrastructure-as-Code 或 API 定義 Ontology 結構,少依賴 GUI。8 月 20 日,論壇群組標籤為 Palantirians 的員工帳號 aparson 回覆:“Currently there is no way for you to use this tooling.”(community.palantir.com 官方社群論壇,Palantirians 標籤帳號 aparson,2024 年 8 月 20 日)同一則回覆接著寫,基礎設施還在開發與測試中;另一則回覆補了一句,這個方向大致上會讓使用者用程式碼定義 ontology,再由 CI/CD 把定義推上 Foundry,變成一個 marketplace product——當時官方自己都說是早期階段。

兩年後,2026 年 9 月查閱時,Palantir 的官方文件已經有一整套叫 SuperRepo 的路徑:object type、link、action 用 TypeScript 宣告,程式碼是 source of truth。用一份文字檔定義 ontology 這條路,Palantir 自己也走通了。這篇用語意、動作、權限、血緣四個觀察面組織全文——這是本文為了跟三個 repo 對照方便自訂的分法,不是 Palantir 官方的分類;Palantir 官方文件的分法是 data、logic、action、security 四項,且官方另外明講 Ontology 不是 semantic layer。這篇接續系列第一篇第二篇。第一篇拆過官方文件裡這四項各自對應什麼;第二篇拆過動作層一個 action 從定義到送出、寫回、留痕的整條路徑。這篇要拆的不是「能不能用文字定義」,是文字定義寫好之後,誰在執行期強制它。

拆法是拿三個作者自己維護的公開 repo 當實錄:作者的 basketball-tools(GitHub dvdmaru/basketball-tools,public)、health-tools(GitHub dvdmaru/health-tools,public)、racing-tools(GitHub dvdmaru/racing-tools,public)。一個人,沒有平台,三個靜態站——語意側用一頁 MODEL.md 加一支測試,血緣側用一份收據 gate,動作側用一份核准清單。三格各自做到了 Palantir 官方文件定義的哪一片,哪些格子沒做,做了也不是同一件事,逐一對照。

本文以五個 Palantir 官方分別定義的基本構件觀察語意側

官方文件的 core-concepts 頁與 Create object type 頁,對語意層的五個概念各給了一句定義:object type 是一個現實世界實體或事件的 schema 定義,property 是物件某個特徵的 schema 定義,link type 是兩個物件類型之間關係的 schema 定義,primary key 是每個實例的唯一識別屬性,backing datasource 是屬性值的來源。這五個構件是官方分別定義的,不是官方宣稱「每個 object type 都必須同時具備」的一個最小集合。

物件與資料表的對應關係,官方用一句類比講清楚:“The definition of an object type in the Ontology is analogous to that of a dataset, while the definition of an object is analogous to that of a row in the dataset.”(Palantir 官方文件,2026 年 9 月查閱,Object types overview 頁)資料表的一列,對應一個物件。primary key 的定義更直白:“The property that acts as a unique identifier for each instance of an object type. Each row in the backing datasource must have a different value for this property.”(Palantir 官方文件,2026 年 9 月查閱,Create object type 頁)語意層怎麼建,官方文件說是把既有資料源 map 成物件、屬性、關聯。

這五個構件之外,Palantir 官方另外走出一條用程式碼定義 ontology 的路:SuperRepo。官方文件寫著:“In a SuperRepo, your object types, links, and actions are declared with Ontology-as-code in the same repository as your functions and frontend. The OSDK is generated locally and regenerated whenever those definitions change.”(Palantir 官方文件,2026 年 9 月查閱,Ontology SDK Overview 頁)SuperRepo 底下的 Ontology-as-code,是把 TypeScript 定義編譯後具現化成平台上的真實實體:“Ontology-as-code provides a pro-code way for you to define your Ontology entities in a SuperRepo. TypeScript definitions of your object types, interfaces, actions, and other entities are compiled and materialized into real entities on your enrollment after your product is deployed. Ontology-as-code acts as the source of truth for your entities, so you should manage all changes from your code definitions.”(Palantir 官方文件,2026 年 9 月查閱,SuperRepo Core concepts 頁)定義一改,OSDK 就重新生成。

一頁 MODEL.md 加一支測試,籃球站鎖住的是鍵集合

basketball-tools 的 MODEL.md 列了一份欄位形狀契約;本文只把它當作語意側的局部切片。它訂的驗收判準寫在檔案最後:“驗收判準:正文裡每一個欄位級事實,都要指得出來源欄位。指不出來就是模型知識 → 砍。“(MODEL.md 第 201 行)§1 的表格逐一列出每個賽季快照必有哪些欄位、可有哪些欄位;NBA standings[] 每一列被明訂不能有 divisionMODEL.md 第 28 行)——這條禁令有事故紀錄:MODEL.md 自述曾有寫手在文章裡寫出「太平洋組第 1」,NBA 快照裡本來就沒有 division 這一欄,那個事實來自模型知識,湖人剛好真的是太平洋組戰績最佳,所以碰巧正確,也因此更危險(該起事故本身是 repo 自述,本文未獨立查證)。

守門的是 tests/test_snapshot_schema.py。它把 §1 的表另存成一份 Python 集合,例如 NBA_ROW_FORBIDDEN = {"division"}(第 38 行),三條不變量分別是必有欄位不得消失、出現未登記欄位要紅燈、NBA 列禁 divisiontest_no_division_field_in_nba,第 156 行)。測試檔還帶陽性對照:往副本注入一個假的 division 欄位與一個未登記的頂層欄位,斷言檢查器真的會叫(test_gate_itself_catches_injected_field,第 167 行);另一個陽性對照拿掉一個必有欄位,確認檢查器同樣會叫(test_gate_itself_catches_missing_required,第 182 行);也對空集合防呆——找不到任何快照檔案本身就判失敗,不是悄悄通過(第 138 行)。這支測試在 PR、push 與每日抓資料前各跑一次(.github/workflows/tests.yml 第 28 行;basketball-daily.yml 第 43 至 44 行的 Unit tests 步驟)。

測試檔對 MODEL.md 本身只做一件事:確認檔案存在,並且含「資料契約」「division」「final_four」三個錨字(for anchor in ("資料契約", "division", "final_four"):,第 198 行)。它不解析 §1 的表格,也不比對表格與 Python 集合是否一致。契約因此有兩份副本:MODEL.md 裡的表,與測試檔裡的集合,CI 抓得到「快照 vs 測試集合」的漂移,抓不到「MODEL.md 表格 vs 測試集合」自己不同步——兩份副本仍然靠同一個 PR 人工同步。這一點跟 Palantir 的 SuperRepo 正好相反:TypeScript 定義編譯具現化成平台實體,OSDK 隨定義變更自動重生,MODEL.md 什麼都不會生成。

測試本身也只驗鍵集合——「必有」「可有」「禁止」三個集合的差集運算,不驗值的型別,不宣告 object identity 或 primary key,不驗 link type,不驗 datasource 到 property 的 mapping。這是 Palantir property schema 定義裡很小的一片,不等於一個完整的 object type,也不等於整個語意層。

Palantir 的血緣自動記錄,健康站的收據只回指到已登記的列

Palantir 官方文件把血緣講成自動化的:一個決策是什麼時候做的、依據哪個版本的企業資料、透過哪個應用程式,都會被自動記錄下來,對人類開發者與 AI agent 都能安全存取(why-ontology 頁)。Data Lineage 是另一個工具,讓人看到資料怎麼在整個 Foundry 平台裡流動。Palantir 2024 財年 10-K(2025 年向 SEC 提交)把這件事講成一句對股東的承諾:“Our platforms automatically maintain complete records of both data provenance and all transformations applied to data in the system, allowing users to assess the reliability of the data and facilitate the review and correction of inaccuracies when necessary.”(Palantir 2024 財年 10-K,SEC 官方文件)

health-tools 做的不是 Palantir 這項完整 provenance 承諾的窄版,而是範圍與方向都不同的「已登記判準列引用收據」。MODEL.md 訂了規則:“頁面上的每個數字都必須回指到某一列,該列的 quote 必須 grep 得回該來源的快照”(MODEL.md 第 19 行)。「正常」或「偏高」這類判讀,定位是對明細列篩選出來的結果,不是一個獨立儲存的欄位(MODEL.md 第 21 行);來源依授權情況分三桶,其中一桶只能引用不能轉載全文,快照只留在本機、排除在版控之外,版控裡只保留 sha256 雜湊值(MODEL.md 第 42 行)。

守門的 scripts/check-receipts.pydata/criteria/*.json 每一列做四件事:doc_id 必須存在於 manifest、引句非空、快照存在時引句要 grep 得回、快照不存在時印 SKIP(scripts/check-receipts.py 第 5 至 16 行)。比對規則只吃掉字串裡的空白,全形半形、大小寫、≧與≥ 這些差異刻意不處理,理由是這些差異正是回查原文的指紋(第 69 行);比對不中就是 FAIL,不准塞進例外清單,也不准反過來改 quote 遷就快照(第 18、23 行)。快照不在磁碟時的行為是這句話:“快照檔不存在時印 SKIP,不是 PASS。SKIP 代表「還沒驗過」,退出碼仍為 0”(第 15 至 16 行)——退出碼仍是 0,不擋 CI。

正文出現手寫表格會直接讓 build 失敗,因為判準表是由 data/ 生成的,md 裡再寫一份就是雙源:“正文含手寫表格。指標頁的判準表由 data/criteria/ 生成,md 不得再寫一份(雙源=資料改了頁面不會叫)。“(scripts/gen-indicator.py 第 342 至 343 行)生成器要跑兩次 SHA-256、兩次結果必須全同,這一步是 CI 的 shell 步驟,不是 repo 內獨立的一支程式(.github/workflows/tests.yml 第 31、41 行)。一筆判準的引句,範例是 hba1c 那一列:“A1C ≥6.5% (≥48 mmol/mol).”(data/criteria/hba1c.json 第 14 行)

這是「值到出處」的建置期血緣,不是 Palantir 講的「決策到資料版本再到應用」的執行期 decision lineage。收據 gate 只證明已登記判準列的引用可查,不反向盤點頁面上是不是每個數字都有一列撐著;缺快照的列 SKIP、不擋 CI。history 檔的變更事件靠一個 status 枚舉機器強制不渲染未證實的列——“未證實的列不得渲染”(data/criteria/history-schema.json 第 106 行)——但誰在什麼時候把一列從「已證實(需補充)」判成「已證實」,沒有結構化的 actor 或 timestamp 欄位。

Palantir 的動作層綁住五個能力面向,賽車站的核准清單只守 sha256 命中一關

Palantir 官方文件把一個 action 定義成一筆交易(action types overview 頁)。組成一個 action type 的,是五個能力面向:送出資格(submission criteria)、參數驗證、Ontology edits 或 writeback、可選的 side effects,以及配置後才會有的 action log。配置 action log 後,它預設記錄 Action/Action type 識別、版本、時間戳、送出者與被改物件主鍵;audit log 是另一套機制,其 export dataset 可選的保留政策上限為 730 天,不能把兩者混成同一種 log。五個面向不是每個 action type 都必須同時具備的集合,但 Palantir 把它們綁進同一個定義、同一次送出,第二篇已經拆過這五樣各自的機制。

racing-tools 在動作層做的是發布前的一道准入 gate。config/approved.json 的自我定位寫在檔案開頭:“default-deny 發布核准清單。只有 article_sha256 完全命中的文章才會進輸出。“(config/approved.json 第 2 行)清單為空時,build 會把已上線文章一併下架,這是 default-deny 的正確行為,不是 bug。一筆核准存七個欄位:slug、article_sha256、facts_sha256、check_report_sha256、approved_by、approved_at、note——但 build-articles.py 只比對 article_sha256,facts_sha256 與 check_report_sha256 只是留存產稿與對帳證據,不是准入條件。

sha256 不符時,build-articles.py 印一句警告就跳過該篇:approval invalidated (article_sha256 mismatch)scripts/build-articles.py 第 772 行),腳本本身不回傳 build failure。但這只是第一層:PR 與週更管線先跑單元測試,tests/test_site_facts.py 裡的 ApprovedArticlesAreStillApproved 會把同一個 mismatch 判成測試失敗,測試檔的註解寫得很直接:“所以把它變成機械擋線:sha 對不上就讓測試紅,PR 合不進去。“(tests/test_site_facts.py 第 176 行)合不進去,週更也就不會進入後續部署(.github/workflows/racing-weekly.yml 第 95、102 行)。

approved.json 的註解寫著核准者不得與產稿者相同,但這句話只存在註解裡,發布 gate 沒有讀、也沒有比對 approved_by——build-articles.py 從頭到尾只取 article_sha256 這一個欄位(scripts/build-articles.py 第 765 至 775 行)。清單本身有一支腳本會寫入,approve-season-intro.py,射程只限賽季導言的 migration(scripts/approve-season-intro.py 第 3 行);本輪對 approved.json 的相關命中沒有找到其他寫入腳本,其他文章的核准,依 note 欄與查無結果推斷,是人工改 JSON 加合併 PR 完成的。

勘誤是第三個獨立的檔,data/errata.json,欄位有 slug、at、was、now、what、credit,人工維護,由 build 讀入渲染成 /errata/ 頁。核准的 note 欄承載了一次重新核准的敘事:文章勘誤後 sha256 從 7d23f22f… 換成 2c629835…config/approved.json 第 21 行)。核准、發布、勘誤三段分開在三個地方,靠 slug 與 sha256 的命名慣例對齊,沒有共用型別定義把它們綁成一個 action:racing-tools 沒有 Ontology object 或 link edits,沒有送出者權限或身分的機械檢查,也沒有每次通過或拒絕自動生成的 action log;approved.json 與 errata.json 都是人工維護的狀態與敘事檔,不是 action log。

權限層,三個 repo 在限定範圍內都搜不到存取控制實作

Palantir 的權限層有自己的機制。物件安全政策獨立於底層資料源另外設定:“Object security policies allow you to configure view permissions on an object instance by configuring security policies on the object type, independently of the permissions on the backing data source.”(Palantir 官方文件,2026 年 9 月查閱,Object security policies 頁)屬性層的權限用同一套機制,只套用到部分屬性;Roles 是 Ontology 的中央權限模型。透過 Ontology MCP 代表終端使用者執行的第三方 client,可使用 OAuth authorization code grant:使用者明確同意請求的範圍,access token 限定在該使用者於 Foundry 的權限內;同頁另列供非互動、service-to-service client 使用的 client credentials grant,這也不是 AIP agent 權限模型的統一敘述。官方原句:“Each user explicitly consents to the requested scopes, and the resulting access token is scoped to that user’s permissions in Foundry.”(Palantir 官方文件,2026 年 9 月查閱,Ontology MCP Authentication and authorization 頁)官方 2026 年 1 月 22 日一篇 blog 另外講過,一個 agent 實際持有的權限是三個因素共同決定的函數:設定並擁有它的使用者、agent 自己的服務帳號與 OSDK 權限範圍、以及當下代表哪個使用者在執行;同年 4 月 28 日另一篇 blog 說,所有 agent 活動受管理人類使用的同一套安全政策管控。

三個 repo 都做過同一件事:在限定範圍內搜尋 permissionroleaclauth。basketball-tools 在 .py.json.md.yml 檔(排除 .gitnode_modules、worktrees)搜尋,命中只有 workflow 的 permissions:Permissions-Policy 標頭、authorauthored 這類子字串,roleacl 零命中。health-tools 用同樣的範圍搜尋,命中只有 workflow 的 permissions:、文件標題裡的 role、HTML 的 role="img"author。racing-tools 在 scripts/tests/.github/ 內搜尋,除了 HTML 的 role="img" 兩處,一樣沒有找到存取控制實作。三個都是限定範圍內的負向結果,不能寫成整個 repo 都沒有,更不能寫成自建做不到權限。

三個 repo 沒做,不等於權限這一格只有 Palantir 做得出來。開源授權引擎 Cerbos 把條件式規則做進 resource policy:“A resource policy contains all rules governing access to a single resource kind. Rules are evaluated per action and can reference roles, derived roles, and conditions.”(Cerbos 官方文件,2026 年 9 月查閱)稽核也做進去了,audit log 記錄存取紀錄與引擎決策的脈絡。差別不是做不做得到,是這三個 repo 沒有接這類外接引擎,而 Palantir 的權限政策直接綁在 ontology 的定義上。

四個觀察面對照表

下表把本文自訂的四個觀察面,跟 Palantir 官方機制、本文三個 repo 做到的切片並排。

觀察面Palantir 官方機制名(英文原詞)官方一句(改寫)本文 repo 做到的切片(檔+行)沒做到或不是同一件事的地方
語意定義object type/property/link type/primary key/backing datasource五個構件各有官方 schema 定義;官方以 dataset 類比 object type、以 dataset row 類比 object,本文 repo 的快照列並不是 Palantir Ontology objectbasketball-tools:MODEL.md 的欄位契約表加測試檔另存的 Python 鍵集合(MODEL.md:28tests/test_snapshot_schema.py:30-40只驗鍵集合,不驗值型別、object identity 或 primary key、link type、datasource-to-property mapping;MODEL.md 本身不生成任何東西,兩份副本靠同一個 PR 人工同步(tests/test_snapshot_schema.py:193-199
動作action type(submission criteria/validation/side effect/writeback/action log)一次送出是一筆交易;本文檢視五個能力面向,其中 side effects 為可選,action log 在配置後才有,不宣稱每個 action type 都同時具備五項racing-tools:config/approved.json 的發布前准入 gate,article_sha256 命中才進輸出(scripts/build-articles.py:769-775沒有 Ontology edits、沒有送出者權限的機械檢查、沒有每次提交自動生成的 action log;approved.json 與 errata.json 都是人工維護檔(config/approved.json:2
權限object/property security policy、Roles、Ontology MCP token scope物件視圖權限可獨立於底層資料源另外設定三個 repo 在限定範圍搜尋未找到開源授權引擎(如 Cerbos)把規則與稽核做進政策檔,這樣的做法存在;差別是外接引擎,不是綁在 ontology 定義上
可追溯性(血緣)Data Lineage、decision lineage 自動記錄(audit logs 為另一套機制)決策的時間、資料版本、應用程式自動被記錄並可安全存取health-tools:scripts/check-receipts.pydata/criteria/*.json 的已登記列檢查 doc_id 與 quote;快照在磁碟時引句須命中,缺快照則 SKIP(scripts/check-receipts.py:5-16不是決策到資料版本再到應用的執行期血緣,只是值到出處的建置期血緣;history 的 status 誰判、何時判沒有結構化欄位(data/criteria/history-schema.json:106

dbt、Cube、LookML 與三個開源專案各自定義的是什麼

同一個「ontology」或「semantic layer」的字,被好幾家公司用在不同地方。dbt 的 Semantic Layer 官方定義句是:“define metrics on top of existing models”(dbt 官方文件,2026 年 9 月查閱)——只描述 metrics 的定義與查詢,這一頁沒有描述寫回,不代表 dbt 整個產品做不到。Cube 官方文件寫:“In Cube, cubes are used to organize tables and connections between tables.”(Cube 官方文件,2026 年 9 月查閱)——組織表與表之間的連接,同樣沒有描述寫回。Looker 的 LookML “describe dimensions, aggregates, calculations, and data relationships”(Looker 官方文件,2026 年 9 月查閱);Databricks 的 metric views 把 measure 定義與分組、篩選欄位分開:“separating measure definitions from the fields”(Databricks 官方文件,2026 年 9 月查閱)。dbt 另外有 model contracts,管的是一個 model 全部欄位的形狀,不管誰能看哪一欄。

一份廠商比較頁 Timbr 對照 Palantir 時自承:“Timbr does not provide a native equivalent to Palantir Actions.”(Timbr 廠商比較頁,自稱 2026 年 7 月驗證)

自建 ontology 不是新鮮事。GitHub 上的 operational-ontology 專案,每一次呼叫不論通過或拒絕都建一筆 action 實例寫進稽核 log:“Every call, applied or refused, creates one action instance and records it in the audit log.”(github.com/gura105/operational-ontology,GitHub 個人專案)foundry-ontology-open 鏡像 Foundry 的四種型別,Object Types、Link Types、Action Types、Functions;openfoundry 自稱是一個功能完整的本地 Foundry 模擬器。這幾個都是個人專案,只能說明存在前例,不代表成熟或被普遍採用。

Palantir 自己的 10-K 在 Competition 一節寫過,潛在客戶的內部軟體開發是公司主要的競爭對手,組織常常先自己建再回頭買現成的,自建時通常靠一堆客製解法、外部顧問、IT 服務公司、套裝與開源軟體拼湊——這是給股東看的風險揭露,不是行銷語言。

三個 repo 的守門形狀表

契約檔守門程式在哪跑(CI 步驟)寫入者留痕方式程式擋不住只靠人工的規則
basketball-toolsMODEL.md §1tests/test_snapshot_schema.py.github/workflows/tests.yml(第 28 行)加 basketball-daily.yml(第 43 至 44 行)3 支 fetch 腳本;NBA 與台籃走 snapshot_guard.guarded_write,HBL 檔另有直接 write_textconfig/season-facts.jsonverified 自由文字欄,人工填寫驗收判準(指不出來源欄位就砍)是人工審核規則,程式沒有檢查
health-toolsMODEL.md §1scripts/check-receipts.py.github/workflows/tests.yml(第 31、41、50 行)scripts/fetch-health-source.py 寫 manifest.json;repo 內沒有找到寫 data/criteria/*.json 的腳本manifest 每筆帶 sha256fetched_at;history 列的 status 枚舉,未證實不渲染history 的 status 由誰判、何時判,沒有結構化欄位,只有人工紀錄
racing-toolsconfig/approved.jsonscripts/build-articles.py 的 sha256 比對加 tests/test_site_facts.pyApprovedArticlesAreStillApproved.github/workflows/racing-weekly.yml(第 95、102 行)approve-season-intro.py,射程僅限賽季導言;其他文章依 note 欄推斷為人工改 JSON 加合併 PRdata/errata.json 第三個檔,加上 approved.json note 欄的自由文字敘事核准者不得與產稿者相同只是註解,build-articles.py 沒有讀、也沒有比對 approved_by

什麼情況值得做輕量版守門機制

三個 repo 做到的,是把 Palantir 官方文件拆出來的幾個構件,各自用一份文件加一支程式或一份清單,做出一小片可驗證的守門。值不值得做,取決於幾個條件:有沒有多個流程共用同一批實體、要不要做會寫回的動作、權限或合規是不是硬需求、要不要能回答「這個數字哪裡來的」、資料是不是散在多個系統。這幾個條件成立得越多,把這幾格交給同一套執行期強制的價值就越高。只有單向唯讀、schema 自己說了算的靜態站,做到本文這三格——欄位形狀契約、引用收據、發布准入 gate——已經夠用。

回到開頭那則論壇提問。「能不能用程式碼定義 ontology」這件事,兩邊現在都有答案:Palantir 走 SuperRepo 與 Ontology-as-code,自建走 MODEL.md、判準 JSON、核准清單。差別不在定義之後有沒有文字檔,在定義寫好之後,由誰、在什麼時候把它強制。本文找到的開源與自建前例,足以證明各個機制可分別實作;它們不能證明把這些機制整合、長期維護與一致強制不是技術問題。本文三個 repo 與 Palantir 的可驗證差別,是前者把機制分散在文件、測試、JSON 與 CI,後者由同一平台承接 Ontology 實體、Actions、權限政策與血緣能力;是否都屬同一份定義,本文不主張。

本系列下一篇:同名異物——dbt、Cube、LookML、知識圖譜與 Palantir 各自叫 ontology 或 semantic layer 的是什麼。

常見問題

Q:一頁 MODEL.md 算不算 Palantir 的 object type 定義? 這是類比,不是等價。在 SuperRepo 的 Ontology-as-code 路徑中,TypeScript object type 定義會在產品部署後編譯、具現化成平台實體,OSDK 隨定義變更重生;MODEL.md 什麼都不會生成,測試檔另外存一份 Python 鍵集合,對 MODEL.md 只驗檔案存在與三個錨字,兩份副本靠同一個 PR 人工同步。

Q:沒有 Palantir,寫回動作的驗證與稽核能自己做嗎? racing-tools 的核准清單做到了 default-deny,只有 article_sha256 完全命中的文章才會進輸出。但核准者不得與產稿者相同只存在註解裡,發布 gate 沒有讀、也沒有比對 approved_by;勘誤是另一個獨立的檔,人工維護。

Q:自建的血緣跟 Palantir 的 decision lineage 差在哪? health-tools 的收據 gate 做的是值到出處:對快照在磁碟的已登記判準列,引句必須 grep 命中;缺快照的列會 SKIP 且不擋 CI。Palantir 講的 decision lineage 是決策到資料版本再到應用,記錄的是一個決策發生的時間、依據哪個版本的資料、透過哪個應用程式,兩者不是同一層次的東西。

Q:什麼情況值得做輕量版的守門機制? 多個流程共用同一批實體、需要會寫回的動作、權限或合規是硬需求、需要回答數字的出處、資料散在多個系統,這幾個條件成立得越多,把機制整合進同一套執行期強制的價值越高;只有單向唯讀、自己控制 schema 的靜態站,做到欄位契約、引用收據、發布准入 gate 這三格就夠。