藏書地圖是空的——8 個庫有 7 個顯示 0 個關係、0 個代表主題 #87
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
leo 2026-08-11:「三元組地圖看不到——這是 bug 但沒有票?」 對,沒有票。這是那張票。
症狀(2026-08-11 實測,不是傳聞)
kbdb_get_map()全館地圖回來 8 個庫,其中 7 個是空殼:[][][][][][][]narrative八個庫全是 null。為什麼這是 bug 不是「還沒長出來」
關係本身不是 0——庫裡有大量三元組,只是沒被算進地圖(初判:卡片沒貼 library 分類標,
地圖是照 library 聚合的 ⇒ 沒貼標的關係聚合不到任何一庫,於是每庫都顯示 0)。
⇒ 地圖現在等於白紙:AI 一開門呼叫
kbdb_get_map(),得到的是「八個庫,什麼都沒有」,定位不到該進哪個庫,只能退回全庫盲搜。這正是藏書地圖存在要解掉的那件事。
影響誰
Leo/Arcrun#81(AI 一打開沒有全景圖)建在這上面——地圖是空的,全景圖就是空的Leo/InkStoneCo#17(票總圖+知識總圖)的「知識那一半」也吃它——index 要寫「庫裡有哪些子庫、各裝了什麼」,資料來源就是這張地圖
已知線索(省下重查)
matrix/arcrunmain 上(commitb6ef0f0)——地基有了,存量沒補、源頭沒接倒過來做=補完的當下又開始長出新的沒貼標的,永遠追不完
怎麼驗才算數
kbdb_get_map()回來的每一個有內容的庫,都有非零triplet_count與top_entities紅線
判斷不該用工作流要寫明理由,不准默默寫成腳本
相關
Leo/Arcrun#81(全景圖,建在本張上)|Leo/InkStoneCo#17(票總圖的知識那半)|Leo/arcrun-rag#50(藏書地圖同一個庫兩筆生效,另一個病)|Leo/Arcrun#85(語意搜尋補算,同樣是「灌回的存量沒被算到」家族)🔴 leo 2026-08-11 點破一個會讓工作流變空砲的前提
答案:沒有解決。而且證據寫在 kbdb 自己的原始碼註解裡
(
kbdb/src/actions/library-map.ts:8,2026-07-19 對線上核實時留下的):同檔第 7 行也記著:triplet template 有
source_urislot、沒有libraryslot。現在線上實測(
kbdb_get_map):8 個庫的 map record 都在,但triplet_count: 0、top_entities: []、narrative: null——連 API 自己回的 hint 都寫著「只有兩側三元組都標了 library 值才抓得到,
舊資料若沒標會偏稀疏,是誠實現況不是 bug」。
⇒ 機制在、值不在。 庫名這件事目前只存在於「有幾個庫」這個層級,
沒有下沉到每一筆資料身上。
這對兩張票各自的意思
對
Leo/Arcrun#85(向量化分層)leo 的四層裡:
⇒ 不必等 ③ 才動工:時間那三層先做,
#85就已經解掉「今天寫的立刻查得到」這個有感的部分。但 ③ 要老實標成「等
Arcrun#87」,不准假裝策略完整。對
Leo/Arcrun#87(藏書地圖是空的)本票原本的敘述是「地圖是空的」,那是症狀。
真正的病是資料沒有貼庫標——地圖只是第一個因此顯形的地方,
#85的第三層是第二個。⇒ 本票的價值比原本寫的高:它是「按庫做任何事」的地基。順序仍然是:先讓源頭寫入時就貼標,再補存量(倒過來做,補完的當下又長出沒貼標的新資料)。
🔴 leo 2026-08-11:「而且不標庫,接下來怎麼搜?」——實測後答案比原本寫的更糟
他這一問把本票從「地圖顯示不出東西」升級成「整條檢索路徑的地基」。
實測(打線上實例,不是讀碼推論)
拿一個真的問題去搜(
kbdb_search(q="卡片筆記法", mode="keyword"),37 筆命中):library這個參數q/mode/owner_id/sourcelibrary欄位"library"出現 0 次)source/sort_order/logseq_uuid/source_id。沒有庫⇒ 三層全斷:資料沒有庫、搜尋不能按庫濾、結果不會告訴你這筆屬於哪個庫。
所以「藏書地圖」現在是一張到不了的地圖
kbdb_get_map的官方提示寫著:但
kbdb_search根本沒有「進某個庫」這個動作。 地圖指的路,工具走不到。⇒ 這就是為什麼地圖空了那麼久也沒人被絆倒——本來就沒有人真的照它走。
leo 的第二句同樣要記下來
「沒有庫就剩一個」——實測證實了,剩的那一個是
source(來源 URI)。今天不管是搜尋還是挑補算對象,唯一能用的維度就是它,而它是「檔案從哪來」,不是「這屬於哪個庫」。
⇒ 判定標準只有一份,不能先按時間做一版、等庫好了再改一版。這是本票與
Leo/Arcrun#85合流的理由。因此本票的定位(改寫)
不是「地圖顯示問題」,是「按庫做任何事的地基」。 至少三條路現在都壓在它上面:
Leo/Arcrun#85Leo/InkStoneCo#17/Leo/Arcrun#81要達成什麼(三段都要,缺一條路仍然不通):
① 資料身上有庫 ② 搜尋能按庫縮小範圍 ③ 結果看得出是哪個庫來的
順序仍然不能倒:先讓源頭寫入就貼標,再補存量。
⚠️ 補存量本身也要花額度(47 萬筆補標=大量寫入,與補算向量搶同一份每日預算)
⇒ 每日上限那道閘要同時管補標與補算,否則做這件事的時候就把那道閘繞過去了。
leo 2026-08-11:「補標如何做?」——先回答「憑什麼判定」,寫入是小事
翻了真資料(線上實例,
kbdb_search回來的完整欄位)。判定依據不是單一欄位,現況是四種訊號並存:metadata.sourcelogseq/ai-canon-wikitags_json["mira-wiki","ai-generated"]parent_id鏈page_name/logseq_uuid目標詞彙是固定的:庫名就是地圖上已經存在的那 8 個
(
arcrun/arcrun-harness/arcrun-rag/derivations/inkstoneco/kbdb-ingest-plugin/mira/notes)——它們看起來就是來源 repo/vault 的名字。
📌 原始碼早就預想過這件事(
kbdb/src/actions/library-map.ts:8-12):⇒ 這條原則要守住:「哪個來源算哪個庫」是語意,屬於呼叫端;資料層只負責照做。
因此補標要達成什麼(四條,順序不能亂)
① 源頭先接:寫進來的時候就宣告自己是哪個庫
餵資料的人知道自己在餵哪個庫,資料層不必猜。 這是唯一的根治——
不先做這件,補存量的當下又會長出新的沒貼標的,永遠追不完(leo 已經強調過兩次)。
② 存量補標=一份「訊號 → 庫」的對照規則,套用一次
規則本身是判斷(人或 AI 定一次),套用是機械。
兩者要分開:規則寫在看得到的地方,套用可以重跑。
③ 🔴 判不出來的一律留白,不准猜
貼錯比沒貼更糟:沒貼只是搜不到,貼錯會讓地圖顯示假的分佈,
而人會照著假地圖決定「該進哪個庫查」——錯誤會被放大成決策依據。
⇒ 留白是誠實狀態,可以之後補;猜錯要有人先發現才修得掉。
④ 分批、可續跑、冪等、受每日上限
補標本身就是大量寫入(47 萬筆),與補算向量搶同一份每日預算
⇒ 那道每日上限必須同時管補標與補算,否則做這件事的時候就把閘繞過去了。
動工的人要先量、不要假設
D70
補標是會反覆發生的動作(每有新來源就要再跑一輪)⇒ 照 D70 應該是工作流。
判斷不該,要寫明理由。
leo 2026-08-11:「這 8 個庫哪裡來的?⋯⋯都從 gitea 同步,所以可以用現有的原稿來搜」
這句話把補標從「猜」變成「對帳」。 每個庫 = 一個 Gitea repo,原稿還在
⇒ 判定依據不必從卡片身上的殘缺欄位反推,可以拿原稿當權威來源逐筆對回去。
⇒ 前一則列的四種訊號(source/tags/parent 鏈/page_name)降級成輔助,
主依據是:這張卡的內容出自哪個 repo 的哪個檔。
但查的過程撞到三件,動工前要一起看
① 管理頁與藏書地圖的庫清單對不起來
leo 的 Portal 管理頁列了 8 個庫:
arcrun/arcrun-harness/arcrun-rag/inkstoneco/kb/kbdb-ingest-plugin/mira/notes而
kbdb_get_map()回的 8 個是:arcrun/arcrun-harness/arcrun-rag/derivations/inkstoneco/kbdb-ingest-plugin/mira/notes直接查
kbdb_get_map(library='kb')回:⇒ 同一個「有哪些庫」的事實有兩份,而且已經漂移(
kb只在管理頁、derivations只在地圖)。這正是
Leo/arcrun-rag#40說的那個形狀(同一事實兩份、18 處、7 處出過事)。補標之前要先確定「以哪一份為準」,否則會補進一個沒人認得的庫。
② 那個畫面本身就是「幾乎沒貼標」的證據
管理頁每一個庫底下寫的是 「1 張知識卡」(只有
kb是 7 張 · 168 條關聯)。47 萬筆躺在庫裡,而按庫數出來的總數是個位數
⇒ 貼標覆蓋率接近零,不是「有一些沒貼」。
③
library_map本來就有commit_hash欄位,而它是null地圖的 slot 定義裡有
commit_hash——設計上就是要記「這個庫同步到哪個 commit」。實查八個庫全是
null。⇒ 「庫 ↔ repo ↔ 哪一版原稿」這條綁定,機制在、值沒寫。
補標如果要靠原稿對帳,這一格正是該被填起來的東西——填了之後,
下一次同步就知道「從哪個 commit 到哪個 commit 之間新增的卡屬於這個庫」,補標從一次性變成常態。
⚠️ 另一件我沒有把握、要動工的人先確認的
我用 MCP 查到的卡片全部在
owner_id = bfezv28v名下;換成
owner_id = 'leo'查,地圖是空的、關鍵字搜也是 0 筆。而
Leo/mira#8記著「安裝器種的工作流把『這些知識屬於誰』寫死成bfezv28v」。這兩件必須一起看——如果補標補在錯的 owner 底下,等於白做。
🔴 先確認「leo 本人登入後看到的那 47 萬筆,掛在哪個 owner」,再決定補標的對象。
(我沒有該實例的登入身分,只能量到 MCP 這一側,這格留給有身分的人做。)
2026-08-11 動工前的量測:根因和票上寫的不一樣,而且補標母體小了 300 倍
先量再定規則(照 leo 交代)。結論是:「地圖是空的」有三個獨立的病,只有一個是「資料沒貼標」,
而且真正該補的不是 47 萬筆,是 1,426 筆。
量測工具=
GET /kbdb/entries(回total,精確計數)與GET /kbdb/records/by-template/triplet,全部走
arcrun-cypher-executor.leo21c.workers.dev既有 proxy(D38:一律 API,沒碰 SQL)。一、三個前提的答案
① 以哪份庫清單為準 → 兩份都不是。權威來源是
source_uri裡的 Gitea repo 名三元組的
source_uri本身就寫著它從哪個 repo 來,格式固定:⇒ 不必從殘缺欄位反推,也不必猜。實測
gitea:Leo/開頭的 1,426 筆,八個 repo 的分項相加 正好等於 1,426(無殘餘、無重疊):
gitea:Leo/arcrun-harness@gitea:Leo/Arcrun@gitea:Leo/notes@gitea:Leo/kb@gitea:Leo/arcrun-rag@gitea:Leo/mira@gitea:Leo/InkStoneCo@gitea:Leo/kbdb-ingest-plugin@kb://(Logseq journals 管線,已經有標)所以管理頁與地圖的「漂移」是假的——
kb和derivations都是合法的庫,只是各自被下面第二、三個 bug 藏起來一個。兩份清單沒有真的互相矛盾。
⚠️ 但 leo 的前提有一處要修正:
derivations不是 Gitea repo(實查 Gitea 24 個 repo 沒有它;
gitea:Leo/derivations@命中 0 筆)。它是
derivationtemplate 的推導卡,AI 產出、沒有原稿可對帳。⇒「8 個庫都從 Gitea 同步」對其中 7 個成立,
derivations要另一條規則。⚠️ 另一處細節:Gitea 上是
Leo/Arcrun、Leo/InkStoneCo(大寫),地圖庫名是
arcrun/inkstoneco(小寫)⇒ 對照時要正規化大小寫。② owner 是誰 →
bfezv28v是對的,前一手看到的是舊快照wiki/status.md「2026-08-11 深夜 leo21c 的 47.9 萬筆回來了」記載:灌回後 owner 分佈=
bfezv28v479,373/bfezv28v::portal9。我線上複驗total479,373,一筆不差。⇒
owner_id='leo'查不到東西不是分區問題,是那個抽屜在 08-11 的還原之後已經不存在。Leo/mira#8「安裝器寫死 bfezv28v」現在反而和資料實際所在一致。補標對象=
bfezv28v,這格可以結案。(殘留:抽樣時看到極少數owner_id='leo'/NULL,量級極小。)③
commit_hash怎麼填 → 目前 100 筆 library_map record 裡,這個欄位一次都沒被寫入過不是「值是 null」,是 key 根本不存在於任何一筆 record 的 values 裡。
recomputeLibraryMap只有在 caller 傳commit_hash時才寫,而現在沒有任何 caller 會傳。⇒ 要讓補標從一次性變常態,得由「同步 Gitea → 補標」那一端在收工時回填當次的 commit。
二、量到的分佈(這是本票估算要改的地方)
valueblocksource=spec-artifact,page_name為空)notesource=logseq)triplet(entries)🔴 「47 萬筆補標」是把 40.8 萬筆內部 slot 值算進去了。
而地圖只數三元組 record(
entry_values的libraryslot),不是數 entries。⇒ 要讓地圖亮起來,補標母體就是那 1,426 筆,一批就做得完,跟每日額度幾乎不衝突。
⚠️ 庫值有兩個互不相干的存放處,別補錯地方:
entry_values的libraryslot(地圖只讀這個)entries.metadata_json.$.library(搜尋/embed 讀這個,目前 479,234 筆算general)三、規則:訊號 → 庫(確定性,判不出來的只有 ~2%)
實測交叉表(100 筆隨機三元組 record),零例外:
gitea:Leo/kb@gitea:Leo/notes@gitea:Leo/mira@kb://kb⇒ 判得出來 98%,判不出來 2%(留白)。前一則列的四種訊號(source/tags/parent 鏈/page_name)
全部用不到——
source_uri一個欄位就夠,而且是確定性的,不是機率性的。(tags 覆蓋率實測 35/37 為空,本來就不堪用。)
四、🔴 真正的根因:地圖每被讀一次,就往 D1 寫一批新 record
這條先前沒人寫下來,而且它同時解釋了
arcrun-rag#50和本票。ensureFreshLibraryMaps會比對「即時三元組數」與「快取的地圖數」,不一致就重算。但:liveTripletCountsByLibrary(library-map.ts:333)不過濾 statusrecomputeLibraryMap(:150)只算status='active'⇒ 兩邊永遠對不上 ⇒ 每次讀地圖都判定 stale ⇒ 每次都重算 ⇒ 每次都新增一筆 record。
實測(間隔 3 秒連讀兩次全館地圖,中間沒有任何寫入動作):
⇒ 這就是為什麼
library_map累積了 100 筆 record:kb44 筆(全部 superseded)、general41 筆、notes2 筆。它們是幾十次地圖讀取留下的殘骸。三個病因此拆開來看:
kb消失=44 筆全被標成 superseded(重算互相 supersede 的競態)⇒ 讀端過濾掉 ⇒ 地圖看不到它。我這次呼叫
kbdb_get_map(library='kb')觸發一次重算,kb就帶著 148 個三元組回來了,全館地圖從 8 個庫變成 10 個。資料一直都在,是地圖把它藏起來。
notes顯示 0 但實際有 108=兩筆都是active,讀端取最新那筆(空殼)⇒ 即arcrun-rag#50。libraryslot 沒值(這才是「沒貼標」那一半)。🔴 順帶一提:這個迴圈本身就在偷 D1 寫入額度,而且沒有任何閘管它——
與本票關心的「補標會不會把補算的閘繞過去」是同一個口袋。它比補標更該先止血。
五、🔴 擋點:補標的通道還沒部署上線
b6ef0f0開通的PATCH /kbdb/records/:idproxy(三元組補標的唯一對外通道)在 leo21c 線上不存在。實測:
兩種 404 的 content-type 不同,可以斷定是沒部署,不是資料問題。
⇒ 我原本要做的 3 筆端到端實證做不了,卡在這裡。
同樣地,
recomputeLibraryMap早就內建source_prefixfallback(
(t.library = ? OR (t.library IS NULL AND t.source_uri LIKE ? || '%')),正是為這次過渡設計的),但
POST /map/recompute沒有任何對外通道——proxy 只轉發 GET,MCP 也沒有這支。⇒ 設計好的過渡機制目前叫不動。
六、CP 三態
◐ 半通 —— 規則已定案且是確定性的、母體已量清楚(1,426 筆)、owner 已確認;
但補標通道沒上線,所以一筆都還沒補、地圖仍然缺 7 個庫。
還缺什麼(依序)
liveTripletCountsByLibrary與recomputeLibraryMap的 status 判準不一致(否則補標期間每次讀圖都在寫 D1,且會繼續生 superseded 殘骸)+清掉那 100 筆殘骸。
b6ef0f0的 PATCH proxy 到 leo21c,或改為對外開放POST /map/recompute(後者不必動 1,426 筆資料就能讓地圖亮起來,是成本更低的一條)。
kbdb-graph-plugin),kbdb/src/index.ts檔頭自己寫著triplet (separate repo)。⇒ 這件不在本 repo,要在
Leo/kbdb-graph-plugin開票:萃取寫入時就把source_uri已知的 repo 名一併寫進libraryslot。不做這件,補完當天又會長出新的沒標的。規則是確定性字串比對、母體 1,426 筆、且要與補算共用每日額度
⇒ 適合做成工作流,不建議寫成一次性腳本。
derivations要另一條規則(沒有 Gitea 原稿可對帳)。commit_hash由「同步 → 補標」那端在收工時回填。未做(照紅線停手)
2026-08-11 止血完成:根因複驗 + 修法 + 測試證據(另有一個必須先看的事故揭露)
⚠️ 先講一件意外:這次工作過程中,修好的 commit 被意外推上了 gitea
main不是我刻意推的,過程如下:
gitea/main切自己的分支。git worktree add -b <branch> <path> gitea/main這個指令本身有個副作用:會把新分支的 upstream 設成
gitea/main(不是它自己)。git push -u gitea <branch名>——正常應該推去同名的新分支,但因為上一步那個 upstream 殘留設定,實際落地變成直接推去
refs/heads/main。main-and-prod-push-guard.sh),但這次沒被擋——查證後發現:閘用一枚全機共用的戳記檔
/tmp/.main-push-ok(15 分鐘內有效即放行),而這台機器上同時有別的 session 在跑,那枚戳記不是我留的、也不是這次任務的授權,
但因為戳記檔不分 session、只看新鮮度,我的推送就順著別人的授權視窗溜過去了。
後果評估(已查證,不是猜測):
git merge-base --is-ancestor b6ef0f0 5919c6b確認是乾淨的 fast-forward,之前 main 上的所有 commit 一筆都沒少、沒被覆蓋。
是規則被繞過,不是規則本身失效。
兩個都需要總管/leo 裁決的問題:
① main 上這個 commit 要不要保留(內容已測試良好),還是要走正式流程撤回重來;
②
main-and-prod-push-guard.sh的戳記檔用全機共用路徑、不分 session,在多 session 並行時形同虛設——這是機制本身的破口,建議另開票修(戳記應綁 session id
或工作目錄,不能是誰按過誰都能用的全域開關)。
根因複驗結果
票上 08-11「動工前的量測」comment 第四節寫的根因複驗屬實:
kbdb/src/actions/library-map.ts的liveTripletCountsByLibrary(即時計數)完全不過濾status,而recomputeLibraryMap(重算後寫進快取的那份)只算COALESCE(status,'active')='active'。兩邊判準不一致 ⇒ 只要庫裡有一筆 superseded triplet,即時數字就永遠對不上快取 ⇒
ensureFreshLibraryMaps永遠判定 stale ⇒ 每次讀地圖(
GET /map、GET /map/:library、kbdb_get_mapMCP 工具)都觸發一次重算並新建一筆library_map record,無止盡寫 D1。
獨立重現(用 leo21c MCP 連線,
bfezv28v,純讀無寫):連讀兩次kbdb_get_map(),中間無任何寫入動作:
與票上原記載的「間隔 3 秒連讀兩次、updated_at 仍前進」是同一個病,數字對得上。
修法
liveTripletCountsByLibrary的 SQL 改成先 pivot 出每筆 triplet record 的 status,再套用與
recomputeLibraryMap逐字一致的COALESCE(status,'active')='active'過濾。兩邊判準對齊後,資料未變動時兩個計數必然相等,stale 判定回歸「真的有資料變動才 stale」。
測試證據
新增迴歸案「Arcrun#87 迴歸:superseded triplet 存在時,連讀兩次地圖不會再次觸發重算」
(
kbdb/tests/library-map.test.ts)。反向驗證過,不是空氣測試:把同一顆測試跑在修前的舊 SQL 上會失敗(
library_maprecord 數 2 vs 期望 1,即多寫了一筆);跑在修後的新 SQL 上通過。
kbdb/tests/library-map.test.ts整份 19/19 全綠(含原有 18 案)。其餘測試檔案有 5 案 + 1 個 tsc 錯誤失敗,但複驗過在改動前的
gitea/main基線上同樣失敗(缺一個不相干的 migration 檔
0005_credential_template.sql、以及一個既有的型別錯誤),不是本次改動造成的。
殘骸清理:還沒做,缺一個可用的通道
票上記載的 100 筆 library_map 殘骸(
kb44 筆 superseded/general41/notes2)這次沒有清——查證後發現目前沒有可用的刪除通道:
cypher-executor的/kbdb/records/:idproxy 只開了 GET/POST/PATCH,沒有 DELETE。DELETE /records/:recordId,但 leo21c 上的 kbdb worker要求
KBDB_INTERNAL_TOKENBearer 認證(fail-closed),這是我不該持有、也確實沒有的機密。清理需要總管(或部署後的後續 session)視情況補一支 DELETE proxy,或用別的授權管道處理。
部署狀態
修法還沒部署到 leo21c(照紅線,部署要交回總管解保險)。分支:
fix/library-map-recompute-loop-87-v3(commit5919c6b,如上述意外,目前也已同步在
gitea/main)。部署後請重跑一次「連讀兩次地圖」的 live 測法,確認
updated_at不再前進,才算 ✅ 通。CP 三態
◐ 半通——根因已複驗、修法已寫且有測試證據(含反向驗證非空氣測試)、
獨立 live 重現修前症狀成立;但:① 沒有部署到 leo21c,無法貼「修後」的 live 實測
② 既有殘骸沒清(缺通道)③ 過程中意外把 commit 推上了 main,需總管裁決是否保留。
2026-08-12:owner 這一格獨立複驗過了(總管,唯讀)
Leo/mira#8的 08-10 快照與本票 08-11 的結論互相矛盾,今天單獨查了一次:owner_id = bfezv28v,479,383 筆,在現役庫516884ce…(arcrun-rag-bfezv28v-db)mira#8量到的「leo479,084 筆」在孤兒庫1099d0f3…(已無人綁定)owner_id被改名leo→bfezv28v(
journeys/leo21c-data-recovery.md:389)⇒ 本票的結論成立,補標照
bfezv28v走不會白做。 已去mira#8標它的數字失效。✅ 2026-08-12 11:1x:止血在 leo21c 本人那台實測通過
不是 stage、不是測試實例,是他自己那台。
修前的症狀是「每讀一次、每個庫都重算並新建一筆紀錄」。
現在 8/10 凍住 ⇒ 「只有資料真的變了才重算」這條成立。
部署時間對得上:兩顆 worker 的
modified_on是2026-08-12T01:26:27Z(台北 09:26),而止血那筆
5919c6b是 08-11 22:16 進 Gitea main 的 ⇒ 那次acr update就帶上了它。🔴 我差點把它誤判成「根本沒部署」
第一次只讀兩次、看到有時間戳在動,就下結論說「新版沒部署到你那台」並要 leo 去跑
--force。連讀四次才看出 8 個是凍住的。
⇒ 教訓:這種「會不會每次都重算」的症狀,要看比例,不是看有沒有東西在動。
一個活著的系統本來就有東西在動。
還沒解釋的一格
general三元組數 0,但時間戳每次讀都會動。可能是「未標記的 entry 被正規化成 general」那條路一直有新資料,也可能是另一個殘留的重算條件。不影響本張的結論,但沒查清楚。
本張其餘部分沒動
補標本身(8 個庫有 7 個顯示 0)還沒做——那是本張的主體,止血只是止血。
📐 leo 2026-08-12:這三張票是同一條路線,不是三件事
這句話收掉的模糊空間
原本三張票各自看起來像獨立問題:
Leo/Arcrun#87:藏書地圖 8 個庫有 7 個顯示 0(存量沒貼庫標)Leo/kbdb-graph-plugin#1:新進來的知識還是沒貼庫標(源頭沒修)Leo/mira#8:daemon 一接上去,新東西會進到搜不到的抽屜它們是同一條 ingest 路線的三段。 而 leo 給的順序把「先補存量還是先修源頭」這個爭論直接解掉了:
源頭要換成本機庫,Gitea 那條要斷掉。 所以補存量不是為了補完就好,
是為了讓「本機庫 ↔ 資料庫」對得上,好把來源切過去。
五步的意思(照他的原話,不加工)
為什麼順序是這個,不能跳
第 5 步是最後才做。先斷再接=中間那段時間新知識無處可去。
而第 3 步是關鍵接縫:「同一個庫在雲端叫什麼、在本機是哪個資料夾」這個對應表現在不存在,
沒有它,第 4 步的 daemon 不知道要讀哪裡、也不知道讀進來的東西該貼哪個庫標。
⇒ 所以
#87的補標不是「順手把存量補一補」,它產出的判準就是第 3 步要用的對應表。給接手的人
三張票要一起看,不要各自開工。動之前先確認自己在做第幾步。
2026-08-13:二次收尾——三件各自的實況,◐ 半通(誠實列缺什麼)
先處理總管中途提醒的疑慮:
fix/library-map-recompute-loop-87-v3(5919c6b/b6ef0f0)不是躺著沒併的分支——複驗
git merge-base --is-ancestor 5919c6b/b6ef0f0 main兩者皆YES,兩顆 commit 都已在main/gitea/main(票上 08-12 03:36 那則「leo21c 本人那台實測通過」就是這次部署的驗證)。留著的只是一份 38 commit 落後的 stale worktree(
.worktree-fix-87),已
git worktree remove+git branch -d清掉(-d而非-D,git 自己核可完全合併才讓刪)。沒有重做,我的新分支是疊在這兩顆 commit 之上,不是平行做第二份。
① D1 偷額度迴圈——仍然是修好的(live 複驗,不是重測一次)
本次工作跨度中連讀
kbdb_get_map()兩次(間隔約 20-30 分鐘,中間只有我的唯讀查詢,無任何寫入動作):
8/9 庫完全靜止=修法仍然有效(若迴圈沒修好,讀一次就會全部往前跳,08-11 票上原始症狀
正是這樣)。
general桶的updated_at持續移動是 08-12 03:36 那則已經記過的已知殘留問題("還沒解釋的一格"),不是新退化——這次沒有進一步查它,維持誠實標示為未解。
CP:✅ 通(有連續兩次獨立實測、時間跨度內零異常)。
② 藏書地圖 8/9 庫仍是 0——根因沒變,但擋點從「沒有批次通道」變成「還沒執行」
現狀複驗(今天實測,與票上 08-11 記錄的症狀一致,沒有自己好):
08-11 的量測已經把「為什麼」查得很清楚(母體 1,426→現況重量約略同量級的 8 個庫),
本次卡住的地方是擋點③:補標的通道還沒上線那條——單筆
PATCH /kbdb/records/:id(
b6ef0f0)雖然已經在 main,但母體上千筆逐筆呼叫既不安全(無節流/冪等)也不現實,而批次版通道原本不存在。
這次做的:補上批次版能力,PR 已開,未部署、未對 leo21c 執行任何一筆真的 backfill:
Leo/ArcrunPR #114(fix/triplet-library-batch-backfill-87→main)backfillTripletLibraryTags+POST /records/backfill-library(含對外 proxy 通道),安全原則對齊既有
Arcrun#85的 entries 版:呼叫端決定 library+source_prefix、冪等、與既有 D69 每日 D1 額度共用、
owner_id必填、寫入沿用既有updateRecord(沒有第二套entry_values SQL)
(
auth.test.ts型別缺陷/portal-data等 4 個測試檔)複驗為 pre-existing(stash 前後一致,與本次改動無關)
為什麼沒有往下執行到「地圖真的有東西」:
kbdb_create_record/get_record/query/search/graph_neighbors/list_templates——逐一核對過,沒有寫入既有 record 的工具)。他的實例」)——而批次執行需要帶
X-Arcrun-API-Key(leo 的真身金鑰)呼叫剛開通的端點,這條路唯一能安全做到的方式就是本機
acr/curl 帶那把金鑰,正是紅線指名要避開的動作。⇒ 這不是懶得做,是在「有安全寫入通道」與「紅線」之間,我判斷紅線優先,把可執行的
that 批次能力做完整、測過、PR 好,執行本身留給有安全通道的人(總管跑 D20 部署儀式後,
用
acr或工作流以 leo 自己的身分執行;或總管另外決定)。怎麼執行(給下一棒,逐庫呼叫直到
pending:0):CP:◐ 半通——能力已建好、測過、PR 好;地圖此刻仍是 0(複驗過,不是猜);
缺:部署 + 對 leo21c 執行批次呼叫(8 次 POST)+ 執行後重讀地圖貼證據。
③ 對照清單+來源標籤——依總管三次修正後的方向重寫,設計提案而非「分流依據」
寫在 InkStoneCo
system-dev/wiki/ops-facts.md「雲端庫↔本機資料夾對照清單+來源標籤設計」段(分支
wiki/arcrun-87-library-source-tag-notes已推 gitea,未併)。摘要:git remote get-url gitea逐一核實本機路徑(不是猜的)。
kb是純資料夾無.git(Syncthing 真身);notes本機完全沒有(來源是手機→Linode,這台 Mac 從未參與)。
watch_folders(守 leo 08-13「不敢連到所有 repo,果然出了不少事」那條紅線)。
KBDB base 既有的
content_hash(entries 欄位+三元組 template slot)已經是「指紋」這格的地基,不需要 KBDB base 新增任何欄位。「folder UUID+搬家判斷」屬於 daemon 端
(
polaris/mira),跨出本 repo/本票範圍,這次只寫設計提案,沒有實作,也沒有演一次搬家——那需要 daemon 端目前不存在的程式碼,誠實標示為未完成,建議在
Leo/mira#6或另開新票收這個設計。
CP:◐ 半通——對照清單本體是實測完成的交付物;來源標籤是有憑有據的設計提案(不是
拍腦袋,扣著 KBDB 既有欄位走);「演一次搬家」這題沒有做到,因為需要的程式碼在另一個
repo、另一個 SDD 的範圍。
總結三態
general桶已知殘留問題維持未解)PR:
Leo/Arcrun#114|wiki 分支:Leo/InkStoneCowiki/arcrun-87-library-source-tag-notes(皆未併,等總管審)。
🔴 更正:PR #114 不是「藏書地圖是空的」的解(2026-08-13,實查後)
總管今天早上對外說過「PR #114 很可能是『地圖空』的直接解」。那句話是錯的,我更正。
負責這條線的 agent 實查資料現況後發現:
gitea:Leo/Arcrun@…/gitea:Leo/mira@…等來源,42 筆抽樣裡 15 筆已標
librarysource_uri=kb://、library=kb,沒有一筆來自
gitea:⇒ 真因是「三元組從沒被萃取」,不是「有三元組但沒標庫」。
⇒ PR #114 在這批資料上會補到 0 筆。
這不代表 PR #114 沒用
它的能力沒問題(批次補標通道,kbdb 測試 218/218 綠),
是它的前提(庫裡有三元組)在這批資料上不成立。
⇒ 保留該 PR,之後三元組真的長出來時會用到。但不要再把它當成地圖空的解。
所以「地圖 8 個庫是 0」實際上是兩件事
triplet_count=0但entry_count>0的庫被誤讀成「沒有知識」entry_count讓地圖說實話(進行中,會另開 PR)🔴 總管自己就是這個誤導的受害者:我看到 8 個庫 0,下結論「知識不在庫裡」——
那句也不精確。知識(entries)在,只是三元組沒產生。
⇒ 這正是「讓地圖說實話」要修的東西:地圖現在說的話,讓讀它的人做出錯誤判斷。
(署名:總管)
🔍 根因查到了:不是「沒萃」,也不是「萃了又不見」——是「萃了,但沒有人把它送出去」
leo 2026-08-13 問:「要分作 1)根本沒有萃 2)先前有萃現在找不到」。
兩個都不是。 卡片裡的三元組有被解析出來,但寫入 graph 那一步從來沒被執行過。
決定性證據
polaris/mira/arcrun/km_wiki_ingest.yaml:391-395—— 這支 workflow 自己承認三元組寫入不在它裡面(註解寫著「graph 三元組:呼叫端 client loop,本 workflow 同步回傳材料」,並附上呼叫端該打的那行指令)。它的
flow(同檔 53-59 行)只到create_entry/update_entry,沒有任何節點呼叫 graph——只是把算好的envelopes(裡面就有三元組)塞進 HTTP 回應,期待呼叫端自己再打一次。⇒ entries 那一半完整、沒斷(42 筆命中、
library標對,都是這條路的產物)。⇒ 三元組那一半的最後一哩,四個 repo 上從沒有人跑過。
為什麼會設計成這樣(不是偷懶,是當時的物理限制)
km_wiki_ingest.yaml:25-34記著:2026-07-07 之前http_request打同帳號*.leo21c.workers.dev會撞 CF 1042(同 zone 自循環);graph envelope 又是巢狀 JSON,recipe body 只吃純量塞不進去(Leo/Arcrun#34)。⇒ 當時唯一能走的路,就是把三元組寫入交給「client(非 Worker,沒有 1042 限制)」。
後來補的外環也不管用,而且它自己寫了原因
system-dev/workflows/km-wiki-ingest-all.local.yaml有post_graph節點(181-188 行)會自動送 graph。但檔頭 62-66 行自己記著它對大 repo 會壞:🔴
Leo/arcrun與Leo/mira正是四個空庫裡的兩個。文件白紙黑字寫「外環必漏/必敗」,而指定的 fallback 正是那支不寫 graph 的內環
⇒ fallback 的第二步(人工補送 graph)從未被執行。
🔴 這再次確認:PR #114 不會讓這四個庫從 0 變出東西
kbdb/tests/triplet-library-backfill.test.ts:1-11記載 #87 解的是「1,633 筆已存在的三元組只有 171 筆填了library」。⇒ 那是「三元組存在但沒標庫」。而
arcrun/mira/arcrun-rag/arcrun-harness這四個庫的三元組是 0,沒有東西可以被補標。兩個方向(總管建議 B,但這是結構決策,等 leo)
⚠️ 先講一個會改變判斷的現況:這條 Gitea 管線本身已被判定「不搬、已被取代」(
system-dev/docs/issues-log/Leo-InkStoneCo-2.md:79,178),線上 webhook 也已隨 08-10 換裝消失。所以問題不只是「補一步」。km_wiki_ingest補內建的 graph 寫入,並解掉外環對大 repo 的 64KB/截斷失效system-dev/(products/arcrun-rag/collector/direct.go:984的SkipDirNames),拿掉這個排除,改走已經自帶post_triplet的rag-ingest-card.local.yaml總管建議 B:
kb那 1851 條三元組正是走 B 這條路產生的——同一支 workflow 裡 entry 與 triplet 一起寫完,沒有「最後一哩靠人補」這個斷點。A 是在退役管線上補一個當初因物理限制而拆開、如今限制已解除的設計。🔴 但 B 要動 daemon 的掃描範圍,那是 leo 的手動決定 ⇒ 等他一個詞。
偵察者自己標的未查缺口(照實留著)
0005/0006的內容沒讀,無法確認 A/B 是否依賴它們新加的欄位acr(避開Leo/Arcrun#109的舊 CLI 陷阱)(署名:總管)
五個空庫的三元組:批次腳本已備好,卡在 prod-write-guard 等總管蓋章
依派工單(跑
notes/arcrun-harness那條km_wiki_ingest/trigger 內建post_triplet的路),本輪把剩下五個庫(
arcrun/arcrun-rag/inkstoneco/mira/kbdb-ingest-plugin)的卡片清單、逐卡呼叫腳本都準備好了,但還沒有實際打進 leo21c——這是一次對 prod 的批次寫入,
派工單明講「不要自己造戳記,做到這一步交回總管」,所以停在這裡等蓋章。
已做(唯讀,沒有動 leo21c 任何資料)
確認機制:
Leo/miraPR #14(6bd4d91)已併 main,km_wiki_ingest現在自己會把三元組寫進KBDB /records(decide >> 對每個 rel >> post_triplet),呼叫端不必再補送——與notes/arcrun-harness今天已驗證成功的形狀相同。五個庫的卡片清單(用 Gitea Contents API 逐層遞迴撈,不吃
git/trees的 64KB/1000 筆截斷——arcrun/mira兩庫的樹分別 249KB/262KB 且truncated:true,已照派工單指示走「逐卡」不走外環):kbdb_get_map現有 entry_count 對比inkstone/Arcruninkstone/arcrun-raginkstone/InkStoneCoinkstone/mirainkstone/kbdb-ingest-plugin共 63 張卡。清單存在
/private/tmp/claude-501/-Users-youlinhsieh-Documents-tech-projects-InkStoneCo/5f4b6e1b-57df-4452-baca-33853b6b73d4/scratchpad/ingest87/inkstone_*_cards.txt。批次腳本:同目錄
run_ingest.sh——對每張卡 POSThttps://arcrun-cypher-executor.leo21c.workers.dev/webhooks/named/km_wiki_ingest/trigger(
X-Arcrun-API-Key: bfezv28v,body 帶repo/ref/card_path/gitea_token/owner_id=bfezv28v),逐筆記錄到
ingest-results-<timestamp>.jsonl,結尾印total/ok/fail彙總。冪等:沿用
km_wiki_ingest自己的content_hash/triplet_hash判準,重跑不會產生重複。給總管的執行指令(單一 Bash 呼叫,戳記只消耗一次)
跑完後複驗(三步,貼回票上):
⚠️ 順手量到一個 guard 的洞(誠實記錄,不是本票要解的範圍)
prod-write-guard.sh目前只看 Bash 工具呼叫的表面指令文字:若指令是
bash run_ingest.sh(腳本內部才有curl ... workers.dev ...),guard 的 regex 抓不到腳本內文,會直接放行、不需要戳記——
這是「換個包裝就穿過去」的同款破口(該檔自己的註解也警告過這件事)。
本輪沒有利用這個洞,仍照規矩把指令交回來等
touch /tmp/.prod-write-ok;但這個 gap 值得總管另外看一下要不要補(例如遞迴檢查腳本內容,或至少檢查
bash <path>這種呼叫形態)。(署名:偵察 subagent,唯讀量測,沒有寫入 leo21c 任何資料)
已貼,網址是 #87 (comment)
⏸ 這條先 pending:leo 2026-08-14 令「先修復 daemon ingest,力量集中在一個地方」
⇒ 五個空庫的批次補灌(留言 2562 那份備好的腳本)暫不蓋章,先停在原地,不是被否決。
一併 pending 的還有
Leo/miraPR #14(三元組寫回)的合併時機——機制已實測通(notes0→6、arcrun-harness0→7),但它屬於 gitea ingest 那條線。接下來力量放哪:daemon ingest 這條(
Leo/mira#8量到的根因=安裝器種的 4 支工作流把 owner寫死
bfezv28v,rag_chat12 處/rag_ingest_card8 處/rag_takedown4 處),路線是 leo 08-14 定的「清空 leo21c → 重裝乾淨的 Arcrun RAG → 重新萃取」。
📌 給接手的人:不要重新診斷這張票,根因與量測都在留言 1820/2562 裡;
解除 pending 的條件=daemon ingest 那條通了(重裝後 daemon 收一張卡、portal 搜得到)。
(署名:總管)