系列說明 >> 本系列大部分 PR 來自私人或公司專案,部分程式碼、環境設定與實作細節不便公開。
我只能保證文中提到的 PR 與問題皆為真實案例,但會經過必要的匿名化與內容調整。
本系列主要分享問題如何被發現、背後的思考方式,以及解法如何形成,不會深入討論完整實作與部署細節,敬請見諒。
Base Repo: paulshaclaw
Change Ref: PR #51-feat(stage2): add atomizer linker pipeline
Issue: D23 已經能把 Claude/Codex/Copilot 的 Session 與原始 Payload 收進 Archive,但一段 Transcript 往往同時混著需求、錯路、Command Output、暫時猜測與最後結論。全部保存下來,只解決「沒有丟掉」,沒有解決下一隻 Agent 該讀哪一段。
Root Cause: Captured Session 缺少穩定的 Knowledge Unit、來源鏈與處理狀態。若只做摘要,容易丟掉 Provenance;若每次重新拆分,又可能因 Crash、Reimport 或重跑產生重複與漂移。
Solution: 建立 Deterministic Atomizer/Linker:先把 Session 拆成候選 Fragment,再 Promotion 成帶 Session/Project/Source Provenance 的 Atomic Slice;Processing Ledger 記錄處理狀態,Relations Ledger 保存 Slice/Entity 關聯,Two-pass Pipeline 支援 Dry-run、Crash Resume 與 Reimport。
Evidence: Memory Tests 269 OK、Stage 2 Integration Check 為 [stage2] ok、Repo Tests 368 OK。Final Review 另抓到 Path Traversal Finding,修正後補 Regression 並通過 focused re-review。這些證據支持 Transcript 已能被決定性拆分、追蹤與恢復;它不代表每一則 Slice 都正確,也不代表 Agent 已經能在需要時找到它。
上一篇,Importer 終於把 Session、原始 Payload 與 Provenance 留了下來。
至少學費收據沒有再跟著 Session 一起消失。
但真的打開一份 Captured Session,問題很快就從「沒有資料」變成另一種:
需求怎麼改的
試過哪些 Command
哪條路後來被推翻
中間貼了多少 Log
最後真正留下哪個判斷
全部都在。
也正因為全部都在,下一隻 Agent 如果想知道:
「上次遇到雙 Authority,最後到底靠哪個 Boundary 收掉?」
它還是得先讀完整段 Transcript,再自己把真正有用的部分找出來。
老Go看著 Archive。
「你把二十二天的收據裝訂成冊了。」
「教材呢?」
嗯……還沒寫。
所以 Capture 之後,下一個問題不是怎麼存更多。
是怎麼把一段混在一起的 Session,拆成下一次真的有機會被取用的工程知識。
PR #51 建立的 Atomic Slice,可以先把它理解成一則單一工程知識。
例如一段 Session 裡可能同時留下:
相對路徑不能假設 Caller CWD
Service 啟動不等於常駐 Process 還活著
同一份 State 只能有一個 Writer
它們可以各自成為 Slice。
但 Slice 不是把幾句話 Copy 到另一個 Markdown 就算完成。
至少還要保留:
小re問得很直接:
「你要的是一句看起來很對的話,還是一句能回去查原文的話?」
如果來源鏈被拆掉,Atomic Knowledge 很快就會變成一堆沒有責任人的格言。
所以每一則 Slice 都帶著 Frontmatter、穩定身分與 Provenance。
它由 Atomizer/Promoter 產生,後續交給 Linker、MOC、Search 與 Recall 使用;保存的是單一工程判斷及其來源鏈。
它不是整段 Transcript。
也不是一段不知道誰寫的摘要。
這條 Pipeline 採 Two-pass。
先 Split,再 Promote/Link:
Captured Session
↓
拆成候選 Fragments
↓
Promotion 成 Atomic Slices
↓
建立來源與 Relation
先後分開有一個很實際的理由。
如果處理到一半 Process 掛掉,系統要知道:
Session 還沒拆
已拆、尚未 Promote
已 Promote、Relation 尚未完成
整段已完成
這些狀態記在 Processing Ledger,也就是 Session 從 Capture、Split 到 Promote 的持久事件帳本。
Slice 與 Entity 之間的關聯則進 Relations Ledger:一份 Append-only 的關聯帳本,不直接靠每次重掃全文猜回來。
小bu看了一眼:
「那失敗就全部重跑,也不是不行。」
可以。
前提是你不介意一段長 Session 每次都重新拆、重新命名、重新產生 Relation,然後再花時間確認這一輪跟上一輪是不是同一批東西。
Ledger 在這裡不是為了把架構寫得比較完整。
它是讓 Crash Resume 與 Reimport 有明確起點,不必每次從零開始假裝第一次見面。
整條 Branch 做 Final Review 時,抓到一個 Path Traversal Finding。
這個 Finding 很符合本系列的習慣。
大家正在討論怎麼把知識拆得更漂亮,Reviewer 先問:
「Project、Session 或輸入欄位如果帶了
../,最後會寫去哪裡?」
Atomizer 會根據 Project/Session/Slice Identity 組路徑。
只要其中一段能被當成任意路徑,所謂 Knowledge Root 就可能只是建議位置。
結果不只是寫錯資料夾。
還可能覆蓋不屬於 Memory Pipeline 的檔案。
這個 Finding 修正後補了 Regression,再做 focused re-review 才放行。
小re沒有因為「內容只是 Markdown」就把它降級。
「能被持久化的 Artifact,就要先把寫入邊界說清楚。」
前面 D3 是 UART 字串不能冒充 Completion Boundary。
今天則是 Project 名稱不能冒充安全路徑。
換了資料格式,物理世界還是在收帳。
PR #51 最後留下:
269 memory tests OK
stage2 integration: ok
368 repo tests OK
它能支持的主張是:
它不能支持:
每一則 Slice 都值得永久保存,或下一隻 Agent 已經找得到正確那一則。
因為 Archive 從一大本帳,變成了很多張可引用的小卡。
數量一多,另一個問題馬上冒出來。
老Go翻了幾頁 Knowledge 目錄。
「以前是一個地方找不到。」
「現在是很多地方都可能找得到。」
下一篇,記憶切成幾百片後,我們只是把「找不到」升級成「更多地方找不到」嗎?
Have a nice day.