遞歸閉包積木組合語言:折疊、展開、引用與再封裝
Recursive Closure Block Composition Language: Collapse, Expansion, Reference, and Re-encapsulation
系列名稱: 遞歸自適應積木組合語言(Recursive Adaptive Block Composition Language, RABCL)
系列編號: EML-RABCL-2026-04
作者: Neo.K(許筌崴)with Aletheia(GPT)
機構: EveMissLab/一言諾科技有限公司
版本: v0.1 基礎理論稿
日期: 2026 年 7 月 30 日
文件定位: 積木語言閉包、結構嵌套、定義/實例分離、引用語義、折疊/展開、版本與再封裝
摘要
前述 RABCL 文件已建立三個基礎:第一,工作流可以在受約束條件下升格為新的高階積木;第二,封裝前必須經過局部靜止、快照、分析、驗證與原子提交;第三,積木不能被簡化成無狀態純函數,而應被描述為具有邊界、端口、契約、狀態、副作用、權限與證據輸出的可契約呼叫單元。
然而,若要使這些積木真正構成一種語言,仍需回答更基本的問題:封裝後的大積木如何再次進入畫布?同一積木在不同位置出現時,是複製、引用還是實例化?展開後修改內部結構,會不會同步改變所有使用者?積木可以包含積木,但能否包含自身?多層封裝如何避免無限展開?版本更新後,既有工作流應追蹤最新版本、固定舊版本,還是建立相容性分支?
本文提出 RABCL 的受約束遞歸閉包模型。令合法積木定義集合為 ,合法組合關係為 ,則閉包條件不是無條件的:
這種閉包同時要求型別、契約、效果、權限、版本與治理條件成立。積木的外觀可以被折疊為單一節點,但其權威結構仍保存為可尋址的定義圖;折疊與展開只是同一權威對象的不同投影。本文進一步區分四個核心對象:積木定義、積木版本、積木實例與積木引用。其中定義描述「它是什麼」,版本描述「哪一個不可變修訂」,實例描述「在本次工作流中具有何種狀態」,引用則描述「此處如何找到並約束該定義或版本」。
本文也區分三種不同的遞歸:結構遞歸、執行遞歸與演化遞歸。結構遞歸允許積木包含其他積木;執行遞歸涉及積木在運行時直接或間接呼叫自己;演化遞歸則是 AEREC 對積木實現進行多代生成、驗證與選擇。三者必須分別受控,不能因「積木可嵌套」便推論所有執行遞歸都安全,也不能因版本持續演化便宣稱形成無限計算。
本文最終建立折疊、展開、引用、實例化、內聯、分叉、升版與再封裝八個基本操作,以及回環一致性、邊界保存、無隱藏捕獲、版本可重現、引用可解析與權威單一性六項核心不變量。由此,工作流不再只是被動保存的圖,而能形成一個持續增長、可引用、可驗證、可回滾且可再次組合的局部語言。
關鍵詞: 遞歸閉包、積木語言、工作流、折疊、展開、引用、實例、內容定址、版本、再封裝、RABCL
0. 問題定位
RABCL 的第四個核心問題不是「畫布能不能把幾個節點框起來」,而是:
一個已封裝積木如何成為下一層組合的合法語言基元,同時保留可展開、可修改、可追溯與可回滾的能力?
若缺少明確語義,產品容易落入下列混亂:
- 折疊只是 UI 隱藏,展開後卻找不到原始結構;
- 拖入兩個同名積木,修改其中一個卻意外改動另一個;
- 工作流保存了「最新版本」的模糊指標,日後無法重現;
- 內部節點被直接複製,導致相同實現散落多份並逐漸漂移;
- 積木包含積木後,除錯器每次都遞歸展開全部層級;
- 自我引用與結構嵌套被混為一談,形成不可停止的執行;
- AI 為了最佳化而修改共用定義,卻未取得所有使用者同意;
- 視覺圖、執行圖、版本圖與來源圖各自維護,逐漸形成多份真相。
因此,本篇不只定義一種畫布操作,而是建立 RABCL 的語言物件模型。
1. 從「大方塊」到語言基元
1.1 大方塊不是像素區域
一個真正的高階積木不能以畫布座標或矩形框作為本體。畫布上的方塊只是投影:
積木本體應是權威結構中的可尋址物件:
其中:
- :身分與命名資訊;
- :外部契約;
- :端口、狀態、效果與權限邊界;
- :權威中介表示;
- :依賴與內部成員;
- :版本與相容性;
- :治理與存取政策;
- :來源、歷史與證據。
方塊可以改變顏色、位置、縮放或是否展開,但這些視覺操作不應自動改變 的語義。
1.2 語言基元的最低資格
一個物件要成為 RABCL 的語言基元,至少應滿足:
也就是它必須:
- 可命名;
- 可穩定尋址;
- 有明確契約;
- 能被 Runtime 呼叫;
- 能與其他積木合法組合;
- 能在需要時檢查其內部與來源。
只具備「可拖曳」或「可重用」仍不足以成為完整語言基元。
2. 四個不可混淆的核心對象
2.1 積木定義
積木定義描述一個相對穩定的語義身分:
例如:
eml.media/GenerateValidatedAsset
它回答的是「這是什麼能力」,而不是「目前哪一版實現」或「此次呼叫的狀態」。
2.2 積木版本
版本是某個積木定義的一次不可變修訂:
版本應固定:
- 契約;
- 權威結構;
- 依賴鎖定;
- 驗證證據;
- 建構與執行需求;
- 內容指紋。
一旦發布,版本內容不得就地覆寫。任何語義或實現改動都形成新版本或候選分支。
2.3 積木實例
實例是積木版本在某張工作流中的具體出現:
其中:
- :該實例的配置;
- :該實例的局部狀態;
- :該實例在工作流中的局部連線。
同一版本可以有多個實例:
兩個實例共享定義與版本,但不必共享運行狀態。
2.4 積木引用
引用不是積木本身,而是找到積木的規則:
常見引用可分為:
- 精確版本引用:固定到 ;
- 內容引用:固定到某一內容雜湊;
- 相容範圍引用:接受一組契約相容版本;
- 符號引用:例如
stable、approved、latest-tested; - 本地分支引用:指向工作區內尚未發布的候選版本。
引用解析後才得到可執行版本:
其中 是時間 的註冊表與政策狀態。
3. 定義圖與實例圖的分離
3.1 為何需要兩張圖
RABCL 至少需要區分:
以及:
其中:
- :積木定義與版本之間的依賴圖;
- :某次工作流中的積木實例與資料/控制連線圖。
若不區分兩者,使用者刪除畫布實例可能誤刪全域定義;修改定義則可能被誤解成只調整單一節點。
3.2 定義圖的基本要求
定義圖應保存:
- 積木版本依賴哪些版本;
- 依賴是內嵌、動態載入還是能力需求;
- 契約與版本約束;
- 來源與驗證鏈;
- 是否存在循環依賴。
在最小 MVP 中,定義依賴圖應優先限制為有向無環圖:
這不是宣稱所有合法軟體架構都必須無環,而是為了讓初版的建構、版本解析、快取、展開與垃圾回收保持可控。
3.3 實例圖可以具有執行循環
工作流本身可能含有:
- 重試;
- 迴圈;
- 回饋;
- 狀態機轉移;
- 事件等待;
- 遞歸呼叫。
因此 不必是 DAG。但循環必須具有明確的控制語義:
換言之,結構上出現回邊不等於錯誤,但不能只靠一條視覺連線隱含無限循環。
4. 折疊與展開
4.1 折疊不是刪除
折疊操作為:
其中:
- :權威結構;
- :原操作狀態;
- :單一積木投影;
- :保存折疊資訊後的操作狀態。
折疊只改變視圖與操作粒度,不應刪除內部結構,也不應將所有內部節點序列化成無法再解析的黑盒字串。
4.2 展開是受控投影
展開操作為:
其中:
- :展開深度;
- :展開模式。
模式至少包括:
- 唯讀展開:檢查內部但不可修改;
- 實例展開:查看該實例的配置與狀態;
- 候選分支展開:建立可編輯草稿;
- 除錯展開:顯示 Trace、狀態與效果;
- 來源展開:查看版本、依賴與證據。
因此,展開不等於取得共用定義的直接寫入權。
4.3 往返一致性
若沒有修改,積木經展開與重新折疊後應保持語義一致:
其中 表示相對於外部契約 的一致,而不要求畫布座標、折疊狀態或註解完全相同。
4.4 有損與無損展開
某些積木可能只有:
- 外部契約;
- 已編譯工件;
- 來源摘要;
- 不完整或受保護的內部表示。
因此應標示:
只有 full 積木能保證完整往返;partial 可展開到允許的抽象層;opaque 則只能顯示契約與證據,不能假裝可還原全部內部。
5. 引用、複製與實例化
5.1 拖入畫布預設應是實例化
當使用者將既有積木拖入畫布時,預設操作應是:
而不是複製整份積木定義。
這可避免每次使用都產生一份逐漸漂移的內部副本。
5.2 複製實例
複製實例表示:
並滿足:
配置可以選擇複製,運行狀態通常不應默認複製,尤其是:
- 憑證;
- 鎖;
- 長期任務游標;
- 交易狀態;
- 外部資源所有權。
5.3 分叉定義
若使用者希望改造積木內部並保留獨立演化路徑,應執行:
新定義保留來源:
但具有新的命名空間、治理權與版本序列。
5.4 內聯
內聯操作將引用的積木版本展開並嵌入當前候選圖:
內聯後,該結構不再自動追蹤原積木更新。這適合:
- 需要深度修改;
- 要消除 Runtime 呼叫邊界;
- 要產生獨立、可離線部署的工件;
- 需要將依賴固定進封裝內。
但內聯會提高重複、漂移與安全修補遺漏風險,因此必須保存來源指紋。
5.5 引用優先、複製例外
RABCL 的預設原則應是:
中文可表述為:預設引用,明確分叉;預設實例化,不默認複製定義。
6. 三種遞歸必須分離
6.1 結構遞歸
結構遞歸表示積木可以包含積木:
這是 RABCL 最基本的高階組合能力。
只要每層封裝都有有限權威表示,結構深度雖可增長,任何具體版本仍是有限物件:
6.2 執行遞歸
執行遞歸表示積木在 Runtime 直接或間接呼叫自身:
或:
這與結構嵌套不同。執行遞歸必須具備:
- 終止條件;
- 深度或資源預算;
- 重入政策;
- 狀態隔離;
- 取消與逾時;
- Trace 關聯。
最低安全要求可表示為:
6.3 演化遞歸
演化遞歸表示 AEREC 對積木實現進行多代變換:
它不是積木在同一次執行中呼叫自身,而是版本或候選實現的跨代生成。
演化遞歸需要:
- 契約錨定;
- 每代證據;
- 選擇函數;
- 負知識;
- 停止準則;
- 回滾路徑。
6.4 三者的正交表示
可以定義積木的遞歸向量:
其中:
- :結構遞歸深度;
- :執行遞歸特性;
- :演化代數或演化深度。
一個積木可以具有深層結構嵌套,卻完全沒有執行遞歸;也可以結構很簡單,卻在 Runtime 中執行遞歸演算法。這三者不能再以單一「遞歸」標籤混合描述。
7. 受約束遞歸閉包
7.1 閉包算子
令合法積木集合為 ,封裝算子為:
其中:
- :連線與工作流結構;
- :契約、權限、版本與治理條件;
- :封裝失敗或拒絕。
只有當:
全部成立,才有:
7.2 相對閉包
閉包永遠相對於某個環境與政策:
同一組積木可能在開發環境可合法組合,在生產環境卻因權限、資料區域或模型政策而不可部署。
因此:
RABCL 的閉包不是宇宙性的代數閉包,而是工程與治理條件下的可組合閉包。
7.3 封裝不保證純化
將多個有副作用積木封裝成大積木,不會自動消除副作用:
只有已被封裝內部完全吸收、不再外顯的效果,才可從外部契約中隱藏。網路存取、檔案寫入、付費 API、資料庫交易與人工審批仍須顯式保留。
8. 八個基本語言操作
RABCL v0.1 的語言操作可先固定為八個:
8.1 collapse
將展開工作流投影為單一積木節點,不改變權威語義。
8.2 expand
按深度、權限與模式查看積木內部。
8.3 reference
建立對積木定義或版本的受約束引用。
8.4 instantiate
在工作流中建立具有局部配置與狀態的積木實例。
8.5 inline
將引用版本內嵌至候選結構,切斷自動升版關係。
8.6 fork
從既有版本建立新的獨立積木定義與演化線。
8.7 revise
對同一積木定義建立新版本,不覆寫舊版本。
8.8 repack
將已修改或重新組合的候選圖,經 EQB、契約推斷與驗證後,再次提交為積木版本。
可以用簡化語法表示:
block eml.media/GenerateValidatedAsset@1.0.0 {
import image.source@1
import model.generate@2
import quality.validate@1
export generateValidatedAsset
compose {
source -> generate -> validate
validate.reject -> generate.retry
validate.accept -> output
}
}
這段語法的重點不在具體字面格式,而是明示:
- 使用的是哪些積木與版本;
- 哪些能力被導入;
- 哪些接口被導出;
- 內部如何連線;
- 哪些內部能力被封裝後不再外露。
9. 身分、版本與內容定址
9.1 四層識別
RABCL 不應只使用一個 id 欄位承擔所有語義。至少需要:
其中:
- :積木定義身分;
- :語義版本身分;
- :不可變內容指紋;
- :工作流實例身分。
9.2 內容指紋
可定義:
其中:
- :密碼雜湊;
- :規範化權威表示;
- :契約;
- :鎖定依賴;
- :會影響工件的建構條件。
相同內容應得到相同內容識別;內容一旦改變,指紋必須改變。
9.3 符號引用與不可變內容分離
stable、approved、latest-tested 等符號引用可以移動,但其所指向的內容版本不可變:
工作流發布時,應將符號引用解析並鎖定:
如此才能兼顧易用的名稱與可重現的執行。
9.4 依賴閉包指紋
積木的可重現性不只取決於自身內容,也取決於完整依賴閉包:
這允許系統判斷兩個表面相同的積木是否實際依賴不同模型、工具或 Runtime。
10. 版本相容性不是只看版本號
10.1 契約指紋
對外契約可產生規範化指紋:
版本更新時,系統比較:
- 輸入是否擴張或收縮;
- 輸出是否改型;
- 新增或刪除哪些效果;
- 權限是否升級;
- 錯誤集合是否改變;
- 狀態遷移是否相容;
- 資源上限是否改變。
10.2 相容關係
可定義:
表示 可在所有依賴 契約的合法位置安全替換 。
這比「主版本號沒變,所以應該相容」更精確。
10.3 自動升版條件
只有在:
成立時,系統才可建議或自動進行版本替換。
若新增網路、檔案、付費服務或更高資料權限,即使輸入輸出型別未變,也不應視為無害的小版本更新。
11. 再封裝的正式程序
11.1 再封裝不是保存按鈕
當積木被展開並修改後,不能直接覆寫原版本。正確程序為:
11.2 變更分類
再封裝前應判定:
其中:
- :契約變更;
- :效果變更;
- :權限變更;
- :狀態模型變更;
- :依賴變更;
- :內部實現變更。
若只有 且外部契約與效果不變,可形成實現修訂或 AEREC 候選。若 、 或 發生不相容改動,則必須形成新語義版本,甚至新積木定義。
11.3 再封裝輸出
一次成功再封裝至少產生:
- 新版本清單;
- 新權威結構;
- 契約與效果差異;
- 鎖定依賴;
- 測試與驗證報告;
- 遷移建議;
- 回滾目標;
- 內容與閉包指紋。
12. 六項核心不變量
12.1 往返不變量
無修改的展開與折疊應保持契約語義:
12.2 邊界保存不變量
折疊後所有外部可觀測的輸入、輸出、狀態、效果、錯誤與權限必須仍可由積木邊界表達:
12.3 無隱藏捕獲不變量
封裝不得偷偷捕獲畫布外變數、未宣告工具、環境祕密或全域狀態:
12.4 版本可重現不變量
精確版本與內容指紋應解析到同一不可變結構:
12.5 引用可解析不變量
所有可發布工作流中的引用都必須能在部署前解析,或被明確標示為由 Runtime/Host 提供的能力:
12.6 權威單一性不變量
畫布、文字 DSL、狀態機視圖、執行計畫與除錯視圖只能是投影:
不能各自成為獨立真相來源。
13. AI 在遞歸組合語言中的角色
13.1 AI 可以提出的操作
AI 可協助:
- 辨識可封裝子圖;
- 建議積木名稱與命名空間;
- 推斷端口與契約;
- 判斷引用或內聯較合適;
- 偵測重複積木與可共用定義;
- 生成折疊後摘要;
- 比較版本與契約差異;
- 建議分叉、升版或保持鎖定;
- 推斷最佳展開深度;
- 發現循環依賴與隱藏捕獲;
- 生成再封裝候選。
13.2 AI 不應單獨決定的操作
AI 不應在無政策與驗證條件下:
- 修改共用積木的已發布版本;
- 將符號引用自動升級到權限更高版本;
- 把引用悄悄改成內聯;
- 複製機密狀態到新實例;
- 將不可逆副作用隱藏進封裝;
- 自動解除依賴鎖定;
- 將執行循環誤判為結構嵌套;
- 無限制展開或遞歸執行。
13.3 提案與提交分離
AI 生成的操作先形成提案:
只有在驗證與政策通過後:
這延續 RABCL 前三篇的基本原則:AI 可以提出結構,但不能跳過權威提交與治理邊界。
14. 與現有元件與內容定址思想的關係
WebAssembly Component Model 已展示一個重要工程事實:具有機器可讀 import/export 介面的元件,可以被組合為新的元件;組合後,已被滿足的依賴可成為內部實現細節,而未滿足的依賴繼續暴露為新元件的 import。其元件也可以嵌套其他元件,並透過介面檢查判定組合是否成立。RABCL 接受這種「介面驅動組合後仍為同類元件」的方向,但把範圍擴大到視覺工作流、狀態、效果、權限、來源、AI 推斷與可逆展開。
Git 的物件與引用機制則說明了不可變內容與可移動名稱可以分離:內容物件由內容定址,符號引用則提供人類可讀、可更新的入口。IPFS 的 Merkle DAG 也展示內容識別與圖形關係可以共同形成可驗證的物件結構。RABCL 不需要複製 Git 或 IPFS 的全部架構,但可借用兩個原則:
- 已發布積木版本應具有不可變內容指紋;
stable、approved等可移動名稱只能是引用,不能把其當成可重現版本本身。
因此,RABCL 的積木可以同時具有語義名稱、版本名稱、內容指紋與工作流實例識別,而不再把所有身分壓縮到一個可變 ID。
15. 常見失敗模式
15.1 展開即修改共用定義
使用者只是為了查看內部而展開,卻因拖動節點直接改變所有引用者。解法是唯讀展開與候選分支分離。
15.2 拖入即複製
每次使用積木都複製全部內部內容,造成修補與升版無法同步。解法是預設實例化與引用,只有明確內聯或分叉才複製結構。
15.3 latest 污染可重現性
工作流只保存 latest,數週後重跑得到不同結果。解法是編輯期可使用符號引用,提交與部署時必須解析為精確版本與內容指紋。
15.4 版本號相容假象
僅依賴主次版本號,忽略新增權限、副作用或資料外流。解法是加入契約、效果與權限差異檢查。
15.5 結構遞歸誤當執行遞歸
積木包含自己的舊版本或同族元件,不代表 Runtime 必須無限自我呼叫。解法是分離定義依賴圖與實例執行圖。
15.6 無限制全展開
除錯器展開所有子積木與依賴,造成認知與計算爆炸。解法是深度限制、按需載入與摘要視圖。
15.7 隱藏能力捕獲
封裝後積木表面只有一個輸入輸出,內部卻偷偷使用網路、檔案、祕密或付費模型。解法是自由依賴掃描與能力 import 顯式化。
15.8 自我引用版本環
新版本依賴符號 stable,而 stable 又更新指向新版本自身,形成解析循環。解法是發布時鎖定不可變版本,禁止內容閉包中的未解析自指符號。
16. MVP 前置資料結構
本篇仍不開始實作,但可以先鎖定最小資料物件:
block_definition:
id: eml.media/GenerateValidatedAsset
title: Generate Validated Asset
namespace: eml.media
block_version:
version: 1.0.0
content_hash: sha256:...
contract_hash: sha256:...
closure_hash: sha256:...
authority_ir: cair://objects/...
expandability: full
imports:
- ref: eml.media/ImageSource@1.1.0
content_hash: sha256:...
mode: reference
- ref: eml.model/GenerateImage@2.0.3
content_hash: sha256:...
mode: reference
exports:
- interface: generate-validated-asset
instances:
state_policy: isolated
config_schema: schema://...
recursion:
structural_depth: 2
runtime_recursion: guarded
max_call_depth: 8
provenance:
parent_version: null
source_workflow: workflow://...
validation_certificate: cert://...
MVP 的初始限制可以是:
- 定義依賴圖必須為 DAG;
- 不支援直接自我依賴;
- 執行循環必須使用顯式迴圈或狀態機節點;
- 發布版本不可變;
- 拖入預設建立實例;
- 編輯共用積木必須建立候選分支;
- 部署時鎖定精確版本與內容指紋;
- 展開深度預設為一層;
- 只有
full積木支援完整往返編輯; opaque積木僅顯示契約、來源與證書。
17. 主要命題
命題一:同類組合命題
合法積木在組合條件成立時,封裝結果仍是合法積木,而不是另一種不可再組合的特殊物件。
命題二:定義/實例分離命題
積木定義與工作流實例必須具有不同身分、版本與狀態生命週期。
命題三:折疊非刪除命題
折疊只改變投影與操作粒度,不得破壞權威內部結構與來源鏈。
命題四:展開非寫入命題
查看積木內部不等於取得修改已發布共用定義的權限。
命題五:引用優先命題
積木重用應預設透過引用與實例化完成;複製定義、內聯與分叉必須是明確操作。
命題六:不可變版本命題
已發布積木版本與其內容指紋不得就地覆寫,任何改動都形成新候選或新版本。
命題七:遞歸分離命題
結構遞歸、執行遞歸與演化遞歸是三種不同機制,必須分別建模與治理。
命題八:相對閉包命題
RABCL 的閉包只在型別、契約、效果、權限、版本、環境與治理條件下成立。
命題九:再封裝事務命題
展開後的修改不能直接覆寫權威版本,必須重新經過靜止、差異分析、驗證與原子提交。
命題十:局部語言增長命題
每次成功封裝都可為命名空間增加新的語言基元,但新基元必須納入引用、版本、來源與相容性治理。
18. 理論邊界
本文不主張:
- 所有工作流都能形成合法積木;
- 所有積木都可完整展開為原始碼;
- 結構嵌套可無限免費展開;
- 內容雜湊本身能證明語義正確;
- 版本號可以取代契約與效果驗證;
- 自我引用天然安全;
- 遞歸封裝突破圖靈可計算性;
- 局部語言增長等同模型獲得自主主權;
- AI 可以在無審核下修改共用積木與生產依賴;
- 初版 MVP 應支援任意循環依賴與跨組織自動升版。
本文只主張:
19. 結論
RABCL 所謂的「積木組合語言」不能只停留在視覺上把幾個節點框成一個大方塊。真正的語言化要求:大方塊必須成為可命名、可尋址、可契約、可版本化、可實例化、可展開、可引用、可再次封裝的一級計算物件。
其基本循環為:
而其雙向操作為:
其遞歸性則不是無條件的「任何東西都能包任何東西」,而是:
一旦這些概念成立,工作流工具就不再只是固定節點庫的使用介面。人類與 AI 可以在實際工作中,把已完成、已驗證的計算結構提升為新的語言基元,再用這些新基元構造更高階工作流。語言因此不再只由平台開發者預先寫死,而能在可治理、可追溯與可回滾的前提下,隨使用過程逐步增長。
下一篇將處理這些積木如何同時存在於格子語言操作表面、CAIR 權威結構、MSSP 描述索引與 RDR 執行派發之中,並避免四個層次各自維護一份互相漂移的系統真相。
參考資料
- Bytecode Alliance, WebAssembly Component Model — Components. https://component-model.bytecodealliance.org/design/components.html
- Bytecode Alliance, WebAssembly Component Model — Composing Components. https://component-model.bytecodealliance.org/composing-and-distributing/composing.html
- Bytecode Alliance, WebAssembly Component Model — Interfaces. https://component-model.bytecodealliance.org/design/interfaces.html
- Bytecode Alliance, WebAssembly Component Model — Worlds. https://component-model.bytecodealliance.org/design/worlds.html
- Git Project, Pro Git — Git Objects. https://git-scm.com/book/en/v2/Git-Internals-Git-Objects
- Git Project, Pro Git — Git References. https://git-scm.com/book/en/v2/Git-Internals-Git-References
- IPFS Docs, Merkle Directed Acyclic Graphs. https://docs.ipfs.tech/concepts/merkle-dag/
- IPFS Docs, Content Identifiers. https://docs.ipfs.tech/concepts/content-addressing/