uncle6me-web
8e9bd09072
fix(engine): 回應太大就說「回應太大」——不再冒充「請求失敗」(Arcrun#92)
...
真因:零件(main.go)給 host function 的接收緩衝區是固定大小(http_request 64KB、
claude_api 1MB)。回應超過這個大小時,wasi-shim 的 writeOut 照寫不誤:
new Uint8Array(buf, outPtr, data.length).set(data)
data 比零件的 outBuf 大 → 覆寫零件堆積體,零件接著 outBuf[:outLen] 切片 panic;
或 writeOut 撞 memory 邊界丟例外 → 回 1 → 零件印一句 "HTTP request failed"。
使用者照那句去查連線/URL/防火牆,方向全錯。
修法(容量握手,不改 host function 簽名、向後相容):
- 零件呼叫前把 outBuf 長度預先寫進 *outLenPtr(宣告容量)
- host 在寫回前讀這個值當上限;塞不下就**不寫**(不再覆寫零件記憶體),回新的
HOST_TOO_LARGE=3
- http_request host fn 收到 3 → 改寫一段講真話的 error envelope(實際大小+上限+
「不是連線失敗」+分頁/篩選的具體做法+機器可讀 code/actual_bytes/limit_bytes),
沿用既有 parsed["error"] 判定鏈原樣送到使用者面前
- 舊零件沒宣告容量(讀到 0)→ 維持舊行為。不可硬套 64KB 預設:各零件緩衝區大小不同,
硬套會把原本正常的大回應誤判成「太大」,那只是換一種說謊
同一條路徑上另一個「訊息與真因脫節」一併修:component-loader 的 makeHttpRunner
`try res.json() catch res.text()`,在零件回非 JSON 時 body 已被消費 → 丟
"Body has already been used",與真因無關(同檔 readBodyOnce 的註解早就寫明這個坑)。
改成只讀一次。
驗證狀態(誠實標示,mindset §7):
- 通:5 顆零件 tinygo build 全過,wasm 已重編進 .component-builds/
(claude_api 依 .gitignore 慣例不入庫,由部署端重編)
- 未跑:runtime 驗證。本 session 的權限層擋掉 node/vitest/wasmtime,
before/after 實測輸出待人跑 scripts/repro-oversize-response.mjs
- 未做:.worker-builds/ 重編(需 node scripts/build-worker-artifacts.mjs),
否則修法不會進 self-hosted 安裝路徑(Arcrun#93 同款陷阱)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-12 16:49:22 +08:00
uncle6me-web
a24f2912eb
chore(builds): 重編執行檔——把 wait 的修法真的放進引擎成品(Arcrun#93 的閘抓到的)
...
#101 併進 main 後,.worker-builds/arcrun-cypher-executor 還記著 a5e4caf,
比源碼 HEAD 少了 f1370e2(wait 搬回引擎那筆)。
⇒ 這正是 #93 那道閘存在的理由:**沒有它,這次出貨會送出一個
「引擎裡沒有 wait 修法」的成品**——leo 更新完照樣燒 CPU,而出貨線全綠。
閘寫出來的隔天就抓到一次,抓到的還是我。
arcrun-cypher-executor source a5e4caf → f1370e22 sha256=8411ed59b7ad
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-12 15:30:26 +08:00
Leo
1791ffa497
Merge pull request ' #101 等待搬回引擎——WASI 沙箱裡沒有「不花 CPU 地等」這種東西' ( #103 ) from fix/wait-not-in-wasm-101 into main
2026-08-12 07:26:00 +00:00
Leo
296fb01247
Merge pull request 'portal 安裝完成清單拿掉「去 Google 申請 AI 金鑰」那一項(arcrun-rag#81)' ( #102 ) from fix/portal-onboarding-drop-gemini-key-81 into main
2026-08-12 07:24:47 +00:00
uncle6me-web
f1370e2275
fix(engine): 等待搬回引擎——WASI 沙箱裡沒有「不花 CPU 地等」這種東西(Arcrun#101)
...
leo 在 youlin stage 實測(只有 input >> wait 兩個節點):
ms=3000 → 38.9s 後 503(1102) / ms=20000 → 34.0s / ms=30000 → 34.9s / 寫死 3000 → 34.8s
四個值同一種死法、與 ms 無關 ⇒ 病不是「等待很貴」,是「等待從來沒成功過」。
修法:wait 移進 BUILTIN_COMPONENTS,由引擎 await 一個 timer。
只花 wall-clock、不記 CPU ⇒ 等 30 秒與等 3 秒同價(皆 ≈0)。
I/O 契約沿用 component.contract.yaml,既有 workflow 的 wait 節點定義不必改。
🔴 誠實標明:原本註解斷言「Workers 時鐘在同步執行期間凍結,所以自旋永不結束」。
寫測試去證,反而被打臉——workerd 裡自旋 2553 圈後 Date.now() 就前進了。
那條假斷言已刪除(不是改鬆),完整機制降級為推測。修法不依賴它:
純 WASI 沙箱本來就沒有睡覺這個手段,會等的只有宿主。
實測:
npx vitest run tests/wait-builtin.test.ts → 12 passed (12)
npx vitest run(全套) → 386 passed / 14 failed
(14 = 動工前的既有紅燈數,未新增)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-12 15:15:08 +08:00
uncle6me-web
d58a6e152d
fix(portal): 安裝完成清單拿掉「去 Google 申請 AI 金鑰」那一項(arcrun-rag#81)
...
leo 2026-08-12:「已經改用 workers AI,刪掉。」
那一項長在**安裝完成清單裡而且是勾選項** ⇒ 使用者會以為不做這步就沒裝完,
而它要人離開流程、去第三方網站申請帳號、把金鑰貼進表單
——**這是整條安裝路徑上最重的一個動作,而它現在是白做的**。
連帶:步數不再寫死「還差 2 步」,改成由剩下的項目算出來
(少一項卻還寫 2,是另一種說謊)。
2026-08-12 14:44:38 +08:00
uncle6me-web
793a94ecb5
chore(worker-builds): 重編——#100 的修法要進執行檔才會送到用戶那台
...
cypher-executor source 525faaf → a5e4caf(sha 49d59597 → d1765930)。
今天第三次在同一件事上被提醒:改完源碼沒重編,出貨與安裝送出去的還是舊的。
2026-08-12 13:36:39 +08:00
uncle6me-web
cbeddf7535
merge: 讀不到就說讀不到——總圖不再把「讀不到」畫成「你沒有」(Arcrun#100)
...
總管審過並自己跑了驗證:
cypher-executor 374 pass(原 357,+17 條),14 個失敗與 main 基準線完全相同
反向驗證:拿掉帶認證那一行 ⇒ 14 → 17 failed;還原 ⇒ 回到 14
它挖到兩件我沒交辦、而且比原題更嚴重的:
· /triplets/stats 的 total 是**分頁長度不是總數**(預設 limit=100)
⇒ 只修 401 的話畫面會從「0」變成「100」——一樣是假的
· 數 entries 原本不帶 owner 過濾 ⇒ **會混到別的租戶**(實測 459,137 vs leo 的 458,732)
2026-08-12 13:36:17 +08:00
uncle6me-web
d7c6bd0680
merge: 更新不再照名字找資源——已部署 worker 綁著什麼就是什麼(Arcrun#97)
...
總管審過並自己跑了驗證(那條線被權限閘擋住,沒能執行):
新測試 20 條全過(含四種「說不準就停手」情境)|CLI 全套 38 pass / 0 fail
反向驗證:把「照名字 ensure」原語加回去 ⇒ 紅線測試當場變紅(0 pass / 1 fail)
重編 dist:舊的 ensureKvNamespace/ensureD1Database 在產物裡 0 個
它做的比交辦的多:加了兩條紅線測試(cf-api 不得再提供「找不到同名就順手建一顆」的原語、
只有 resource-resolver 能決定要不要建),以及一條我沒想到的——
**部署出去的 toml 不得殘留官方帳號的資源 id**(自架寫進官方庫=跨租戶外洩)。
誠實標記:驗證是本機模擬(假 CF API),**沒有在真機上跑過**。
2026-08-12 13:36:17 +08:00
uncle6me-web
a5e4caf5cb
fix(portal): 讀不到就說讀不到——總圖不再把「讀不到」畫成「你沒有」(Arcrun#100)
...
leo 2026-08-12 打開總圖看到:「0 個實體 · 0 條關聯/知識庫還沒有任何關聯——
上傳文件後 AI 會自動織網」。**而他庫裡有 1854 條三元組。**
那句話會叫他去做一件不需要做的事。
三個獨立的洞疊起來才變成那句謊:
① console-dashboard.ts 打 kbdb-graph-plugin 沒帶認證(同段落打 kbdb 的兩支都有帶)
② 那顆 worker 不在更新的部署清單裡 ⇒ token 一換它就落單
③ **畫面把 null 畫成 0**——後端已經誠實回 null 了,是前端把它變成謊話
為什麼一直沒被發現:graph plugin 原本身上沒有 token ⇒ 門開著 ⇒ 沒帶也進得去。
2026-08-12 輪替後它有了 token,門關上,401 才浮出來。
📍 repo:matrix/arcrun(cypher-executor/src/routes/、console-ui/public/)
📍 票:Leo/Arcrun#100
2026-08-12 13:33:53 +08:00
uncle6me-web
45a546a686
fix(cli): 更新不再照名字找資源——已部署 worker 綁著什麼就是什麼(Arcrun#97)
...
病根:更新會「確保」它需要的資源存在,而它是**照名字找**的。
使用者的資源是安裝器建的(`arcrun-rag-<x>-kv-webhooks`),更新找的是 `WEBHOOKS`
⇒ 找不到 ⇒ 新建一顆空的並綁上去。
2026-08-12 實撞(leo21c):一次例行更新後
KV 9 顆 → 18 顆、D1 1 顆 → 2 顆,worker 全綁到新建的空的
⇒ 工作流一支都看不到、portal 登出、總圖空的、80 把 recipe 解不出來
leo 原話:「leo21c 是掛掉的」。資料沒掉,但從他的角度就是東西全不見了。
修法方向:**已經部署上去的 worker 綁著什麼,那就是事實**——
名字是使用者那側的事,不是更新指令可以決定的。
📍 repo:matrix/arcrun(cli/)|📍 票:Leo/Arcrun#97
2026-08-12 13:30:17 +08:00
uncle6me-web
e69d6bbc03
chore(worker-builds): 重編——kbdb 的跳脫修法要進執行檔才算數(Arcrun#94)
...
今天已經在這件事上被咬過一次(8e10f1d):源碼改了、執行檔沒重編,
出貨會全綠地送出舊的。這次併完就重編,不留同一個坑。
kbdb source 525faaf → c497ec4(sha256 7bc66656 → ffb8d434)。
其餘四顆源碼沒動、位元組也沒動。
2026-08-12 12:22:10 +08:00
uncle6me-web
b302c03ea8
merge: 搜尋框打的 % 和 _ 是字,不是萬用字元(Arcrun#94)
...
總管逐筆審過兩筆,並自己跑了測試(那條線被權限閘擋住沒能執行):
前後對照 查 100% 改前撈回「共有 100 個待辦項目」→ 改後只回真的含 100% 的
查 owner_id 改前連 ownerXid 也中 → 改後只回字面命中
單打 % 或 _ 改前整個庫都回來 → 改後只回字面命中
反向驗證 拿掉跳脫 → 8 failed(紅的正是病徵本身)
拿掉 ESCAPE → 5 failed(含既有 search-long-query 兩條)
既有測試 18 檔 197 pass → 19 檔 213 pass
它連帶處理了一個我沒想到的:跳脫會讓 pattern 變長,所以長度上限改用「跳脫後」的
長度算——否則打 48 個 % 會產生 98 bytes 的 pattern,退回 08-03 修掉的那個 HTTP 500。
誠實標記:只在本機真 SQLite 上驗過,沒對任何線上實例跑過。
同款漏洞另有兩處未動(library-map.ts:169、library-backfill.ts:75-76,吃維運端前綴參數)。
2026-08-12 12:21:48 +08:00
uncle6me-web
c497ec418e
test(kbdb): 用真 SQLite 釘住 #94 的前後對照與跳脫邊界
...
只驗 SQL 形狀不算數——「% 被當成萬用字元」這件事,只有真的跑一次 LIKE 才看得見。
用 node:sqlite(與 library-map/embed-backfill 同款治具)跑真 SQL,每組驗收同時跑
「舊寫法」與「現行寫法」,讓前後對照直接長在測試裡。
守五件事:
① 前後對照 —— 100% / owner_id / 單打符號,改前撈回不相干的、改後只回字面命中
② 跳脫邊界 —— `\` 不跳脫會漏掉真正的 `C:\`,也會讓 `_` 的跳脫失效、萬用字元漏回來
③ ESCAPE 齊全 —— 沒有任何 `content LIKE ?` 是裸的(漏一個就等於那條路沒修)
④ 不退化 —— 不含 % _ \ 的查詢 pattern 逐字不變,最熱路徑仍是單一 LIKE
⑤ byte 預算 —— 滿是 % 的長查詢仍在 D1 的 50 bytes 上限內(承 2026-08-03 的 500 修復)
反向驗證(把修法拿掉,兩半分別驗,兩半都是承重的):
拿掉跳脫 → 8 failed / 204 passed,紅的正是病徵本身
拿掉 ESCAPE → 5 failed / 207 passed(含既有 search-long-query 2 條)
復原後 → 19 檔 213 pass(基線 18 檔 197 pass)
2026-08-12 11:59:36 +08:00
uncle6me-web
6985bf4850
fix(kbdb): 搜尋框打的 % 和 _ 是字,不是萬用字元(Arcrun#94)
...
使用者在搜尋框打 `%` 或 `_`,搜出來一堆跟他打的字無關的東西。
病根:pattern 一直是 `'%' + 使用者輸入 + '%'` 直接內插,而 SQLite 的 LIKE 有
兩個萬用字元(`%` 任意長度、`_` 任意一字)且**沒有預設跳脫字元**——不寫
ESCAPE 就沒有任何辦法表示「字面上的 %」。所以他打的符號被當成 pattern 語法:
`100%` → `%100%%` → 「100」後面接什麼都算 ⇒ 撈回一堆不相干的
`owner_id` → `%owner_id%` → `_` 匹配任一字元 ⇒ ownerXid 也中
單打 `%`/`_` → `%%%`/`%_%` → 整個庫都回來
舊病,不是 08-10 斷詞(#84)引進的:pattern 從來就是這樣拼的。之前關鍵字搜尋
幾乎恆為 0 命中,這個洞被那個洞蓋住;斷詞讓搜尋真的會回東西之後才浮出來。
斷詞那段一個字都沒動。
修法:pattern 產生點全部收斂到兩支 helper——
· escapeLikeLiteral():跳脫 `%` `_` `\` 三個字元
· CONTENT_LIKE 常數:每個 `content LIKE ?` 一律帶 `ESCAPE '\'`
為什麼跳脫字元本身(`\`)也要處理:宣告 ESCAPE 之後 `\` 就變成 pattern 裡有
意義的字元,而且它會把後面那個字吃掉、且不報錯——打 `C:\` 會變成去找 `C:%`
(真正的 `C:\` 反而漏掉);只跳脫 %/_ 而漏掉 `\`,打 `C:\_temp` 時 `\\` 先被
讀成字面 `\`、後面的 `_` 變回萬用字元 ⇒ 撈到 `C:\Xtemp`。三個是一組的。
`[` `]` `?` `*` 不需要跳脫(那是 GLOB/別的方言,LIKE 不吃),多跳只會白白吃掉
pattern 的 byte 預算。
連帶:跳脫會變長(`%`→`\%`),所以 50 bytes 上限改用「跳脫後」的長度算
(likeBytes),否則打 48 個 `%` 會產生 98 bytes 的 pattern ⇒ 退回 2026-08-03
修掉的那個 HTTP 500。不含這三個字元的查詢 likeBytes ≡ utf8Len ⇒ 既有查詢逐字不變。
search-long-query.test.ts 兩條「逐字比對謂詞字串」的斷言跟著新字串更新——改的是
比對用的常數、不是放寬檢查(仍逐字相等比對),pattern 本身一個字都沒變。
沒有引進第三種搜尋機制,沒有動資料層(三表不變),沒有動斷詞。
2026-08-12 11:59:36 +08:00
uncle6me-web
8e10f1d83e
chore(worker-builds): 重編官方成品——kbdb/cypher-executor 的修法之前只在源碼裡
...
為什麼要有這一筆:`.worker-builds/` 是**出貨與安裝真正拿去部署的執行檔**,
而它記的 source_commit 在剛併完 #85/#88 之後對不上源碼:
arcrun-cypher-executor 成品記的 797e7f7 源碼已經是 525faaf ⚠️
arcrun-kbdb 成品記的 a7e23ba 源碼已經是 3eb8b31 ⚠️
⇒ 這時候去出貨或 `init`,送出去的是**舊的執行檔**,測試全綠也沒用
(wiki/mistakes.md「修的東西在執行檔裡,改完源碼+測試綠 ≠ 送到用戶手上」)。
🔴 build-bundles.mjs 的「落後閘」抓不到這個:它比的是「.worker-builds 這個目錄有沒有
落後 main 的 commit」,不是「成品記的 source_commit 有沒有落後那顆 worker 的源碼」。
這次是人工比對才發現的。修這道閘另開票。
重編後:cypher-executor source=525faaf、kbdb source=3eb8b31,兩顆的新程式碼都在產物裡
(kbdb 找得到 embed_backfill_usage/backfillEntryLibraryTags,cypher 找得到 builtin 那條路)。
誠實標記:另外三顆(code/http_request/mcp)源碼沒動,位元組卻變了——是 esbuild
版本漂移換了它產生的 helper(`__esm` 多了一段 try/catch)。這正是 #77 記的
「build 不可跨機器重現」那個結構性斷點的實例。
2026-08-12 09:50:50 +08:00
uncle6me-web
3eb8b31f2b
merge: 補算向量的節奏、額度、世代核對+標庫共用同一顆閘(Arcrun#85/D68/D69)
...
總管逐筆審過 1d6dde4/674e1b4/37e13fc:全部落在 kbdb/,沒有新表(額度用量寄生在
既有 entries 表單一列,D38)、沒有動實例。標庫與時間分層共用一套 SelectionCriteria
與同一顆每日 D1 額度計數器——兩者若各記各的,其中一個會把另一個的閘繞過去。
實測:kbdb 全套 196 pass / 0 fail(含反向驗證:拿掉 cap 那個 case 會變紅)。
紅線仍在:這只是併進 main,還沒部署到任何實例。
2026-08-12 09:40:30 +08:00
uncle6me-web
8cee9c9f76
merge: /cypher/search 不再誤報執行期原生零件 not_found(Arcrun#88)
...
總管逐筆審過 525faaf:改動只在 cypher-executor 的 search-nodes.ts(查 registry 前先比對
執行期白名單)與 component-loader.ts(把既有三份白名單的聯集匯出),沒有新清單、
沒有掃目錄灌死碼。實測基準線:本分支 357 pass / 14 fail,main 350 pass / 14 fail
——同樣的 14 個既有失敗(portal-data 等 5 檔),新增的 7 個全綠。
2026-08-12 09:40:18 +08:00
uncle6me-web
7e3ca4c1a1
Revert "WIP(kbdb): 語意搜尋零命中的排查—— ⚠️ 被總管中途叫停,未完成驗證"
...
This reverts commit af3edff856 .
2026-08-11 23:18:38 +08:00
uncle6me-web
af3edff856
WIP(kbdb): 語意搜尋零命中的排查—— ⚠️ 被總管中途叫停,未完成驗證
...
leo 2026-08-11 判斷「如果是 Vectorize 沒完成就不用查了」,總管據此停線。
真因已經寫在 repo 自己的註解裡(kbdb/wrangler.toml:43-51,Arcrun#11):
metadata index 只收「建立後 upsert」的向量,既有向量須 reindex,
否則帶 owner_id filter 一律 0 命中——與實測每一格吻合
(805 筆在、關鍵字搜得到、語意 0、拿自己查自己也 0 ⇒ 不是分數門檻)。
⚠️ 這批改動是排查途中的產物,**沒有走完驗證**,不要當成可用的修法。
保留只是不讓它憑空消失(總管中斷造成,不是它做壞)。
接手的人請先讀 Arcrun#85 上的結論再決定要不要用。
真正的補救是 reindex,而 reindex 要燒 AI 額度
⇒ 卡在 Arcrun#85 的每日額度閘上線之後才能做。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 23:05:20 +08:00
uncle6me-web
c5d696556e
保管:#89/#90/#91 卡在人類閘前的產物,從 session 暫存目錄搶進版控
...
三樣都做完並實測過,但落地的最後一步是終端機裡等人親手打字的互動閘。
它們原本只存在於某個 session 的 scratchpad——那種目錄一關就沒了。
· recipes/gitea_put_file.yaml 出貨線 7 站等它
· recipes/cf_worker_deploy_simple.yaml ⚠️ 只適用無 bindings 的簡單情形(見 #90)
· hash-component/ sha256/sha1/md5,已與系統原生指令逐位元核對
(.wasm 是 1.3MB 編譯產物,不進版控,README 附重編指令)
README 寫了落地指令與各自的注意事項。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 22:38:55 +08:00
uncle6me-web
5919c6b90f
fix(kbdb): 藏書地圖讀端每次都觸發重算寫 D1(Arcrun#87 止血)
...
liveTripletCountsByLibrary 沒有過濾 status,recomputeLibraryMap 只算
COALESCE(status,'active')='active'——兩邊判準不一致,只要庫裡有一筆
superseded triplet 就永遠判定 stale,導致每次讀地圖(GET /map、GET /map/:library、
kbdb_get_map MCP 工具)都觸發重算並新建一筆 library_map record,無止盡寫 D1,
且加劇既有的非原子 supersede 競態(kb 44 筆全 superseded、notes 兩筆同時 active
即 arcrun-rag#50 的共同根因之一)。
修法:liveTripletCountsByLibrary 的 SQL 改成 pivot 出 status 再套用與
recomputeLibraryMap 逐字一致的過濾,兩邊判準對齊。
新增迴歸測試釘住此 bug(反向驗證:跑在修前的 SQL 上會失敗,非空氣測試);
獨立用 leo21c MCP 連線連讀兩次 kbdb_get_map() 重現修前症狀
(general 庫 updated_at 從 1786457080 前進到 1786457114,中間無寫入)。
kbdb/tests/library-map.test.ts 19/19 全綠。既有殘骸(100 筆 library_map record)
未清——目前沒有可用的 DELETE 通道,待部署後另行處理。
kbdb-sql-ok:liveTripletCountsByLibrary 的 .prepare 呼叫是牆內本體
(kbdb/src/actions/),本次 checkout 開在巢狀 worktree
matrix/arcrun/.worktree-fix-87/(避免打斷另一 session 佔用中的
matrix/arcrun 主 checkout),kbdb-api-wall-guard.sh 的字面路徑比對
*matrix/arcrun/kbdb/src/* 吃不到中間多出的 worktree 目錄層,非真的繞牆。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 22:16:30 +08:00
uncle6me-web
525faaf5d0
fix(cypher-executor): /cypher/search 不再誤報執行期原生零件 not_found(Arcrun#88)
...
病因:/cypher/search 只查 component registry(SUBMISSIONS_KV,經 submitComponent/
index-only 才有記錄);而 component-loader.ts 能直接解析、從不查 registry 的一整類
零件(trigger_workflow/BUILTIN_COMPONENTS/LOGIC_BINDING_MAP/WASM_HTTP_RUNNER_IDS,
如 if_control/http_request/switch)從未被 submit 過。leo21c 實例實測:
GET /components/catalog 回 404「零件 catalog 不存在」,search 因此對這些零件誠實地
回「兩庫都查過沒有」——但它們其實跑得動(leo 08-11 探測工作流已證)。
修法:從 component-loader.ts 匯出 RUNTIME_NATIVE_COMPONENT_IDS(既有三份執行期
解析白名單的聯集,非新清單),search-nodes.ts 在查 registry 之前先比對,
不受 registry 是否可達/是否已 backfill 影響。真正不存在的零件仍誠實回
not_found/unknown,not_found 的分型建議與相似候選機制不變。
刻意不做:不掃描 registry/components/* 目錄當清單來源——那含已標記待刪的死碼
(km_writer/kbdb_upsert_block),07-30 曾把這類死碼誤灌進 registry;也不投資
SUBMISSIONS_KV 的 backfill 腳本——decisions-summary.md D29 已定調 SUBMISSIONS_KV
併入「KV 退休戰」,不宜再加投資。
測試:cypher-executor/tests/search-nodes-runtime-native.test.ts 7 case 全綠,
複現 registry unreachable/registry 可達但目錄空(leo21c 實例的真實症狀)兩種情境。
全 suite 迴歸:357 pass(較修前 350 pass 多 7 個新測試),既有 14 個失敗與修前
數量、內容完全相同(pre-existing,與本次改動無關)。
2026-08-11 21:51:21 +08:00
uncle6me-web
37e13fc9bf
merge: 併入 main 最新(b6ef0f0 三元組 library 補標 proxy+測試)保持分支不落後
2026-08-11 18:46:03 +08:00
uncle6me-web
674e1b4fa2
fix(kbdb): D69 節流世代核對+標庫共用 D1 額度,補「挑哪一批」的統一 SelectionCriteria(Arcrun#85)
...
leo 逐行複核 fix/embed-backfill-d68 後點出的破口+二次裁決(票上全文見 Leo/Arcrun#85):
一、向量化優先序(今天寫的立刻/本週在跑的先跑/有查詢紀錄的庫優先/半年前慢慢跑)表達
不出來——策略要能從外面(工作流)指定,不能焊死在資料層。新增 embed.ts 的
`SelectionCriteria`(owner_id/source/library/since/until),backfillEmbeddings 與
reconcileEmbedGeneration 共用同一套形狀;「按庫」那一層現在有資料可用即可運作(見下)。
二、世代核對(reconcileEmbedGeneration)不打 AI 但逐筆寫 D1,47 萬筆候選 ≈ 4.7 倍 D1
100,000 rows/日免費額度,先前零保護。新增 actions/maintenance-quota.ts(單一 entries
列/日的共用計數器,精神同 execution-log.ts/embed.ts 既有慣例,不新增表)。
三、leo 二度裁決:「標庫」與「時間分層」其實是一件事,判定標準要從第一天同時容納兩者,
不能先做一半再回頭改。新增 actions/library-backfill.ts 的 backfillEntryLibraryTags——
呼叫端(ingest/daemon/Arcrun#87)決定要貼哪個庫、用 page_names(Gitea 原稿卡名精準
點名,leo 定案的正解)或 source_prefix/page_name_prefix 過渡 fallback 篩選候選,base
只負責安全、節流地寫入。owner_id 刻意必填(leo 點出「補錯 owner 等於白做」——實查卡片
掛在 owner_id=bfezv28v,換成 'leo' 查卻是空的)。
D69:reconcile 與標庫 backfill 共用同一顆「今天還剩多少 D1 寫入額度」計數器(不共用的話
其中一個會把另一個的閘繞過去);新增 POST /entries/backfill-library + GET .../status,
擴充 POST /embed/backfill 與 /embed/reconcile 吃 library/since/until 參數。
測試:92 → 39 個新增/擴充案例覆蓋 since/until/library 篩選、reconcile 額度真的擋
(含「拿掉 cap 會變紅」反向驗證)、標庫 backfill 冪等/owner_id 必填/page_names 精準比對、
以及兩個操作共用同一顆額度計數器的跨模組驗證(雙向:先 reconcile 耗盡再標庫、反之亦然)。
kbdb 全套 192 個測試綠燈,tsc --noEmit 除既有 auth.test.ts 舊缺陷外無新增錯誤。
紅線:未併 main、未部署、未動任何實例的 is_embedded 旗標(只在本地 SQLite 測試治具跑過)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 18:39:55 +08:00
uncle6me-web
b6ef0f07dc
fix(kbdb): 開通 PATCH /kbdb/records/:id proxy + 補三元組 library 補標測試
...
leo 2026-08-11:貼 wiki 卡「這裏就有 3 個三元組,如果三元組是 0 一定是有錯」——
三元組沒有不見(新式 1,633 筆/舊式 636 筆都還在),問題是地圖看不到:新式三元組
只有 171 筆填了 library slot,其餘因寫入時 template 還沒有該 slot 而被靜默丟棄
(record-crud.ts createRecord 只替「已宣告」的 slot 建值,不是替 caller 傳的
values 建值——順序錯了值就消失,不報錯)。
本次改動:
- cypher-executor/src/routes/kbdb-proxy.ts:補 PATCH /kbdb/records/:recordId。
基本盤(kbdb/src/routes/records.ts)早有這個端點(mira-dissolve T2.1 的
updateRecord),但這條 proxy 之前只轉發 GET/POST /kbdb/records,外部(工作流/
CLI/補標腳本)打不到——能力在,通道沒開,補標三元組只能繞去改表(違 D38)。
純轉發、無業務邏輯,比照既有 PATCH /kbdb/entries/:id 慣例。
- kbdb/tests/triplet-library-backfill.test.ts:真 node:sqlite 驗三件事——
①源頭順序(ensure-slot 必須在 write 之前,事後補救不了已寫的那筆,重現+
驗證正解)②存量補標(地圖輸出前後對照)③不會重複做(同批跑兩次,第二次
touch 0 筆)。順手記錄一個相關但不在本次範圍的小落差:liveTripletCountsByLibrary
的 'general' fallback 桶與 recomputeLibraryMap 的精確比對語意沒對齊。
- cypher-executor/tests/kbdb-records-patch-proxy.test.ts:新端點的租戶閘/
參數驗證/轉發/404 透傳。
全數綠燈:kbdb 181/181、cypher-executor 新增 8 案全過(既有 14 案失敗為
pre-existing,已用 git stash 比對確認與本次改動無關)。
kbdb-graph-plugin(實際的三元組寫入端 createTriplet/ingestEnvelope)需要同款
修正(library 補進 TRIPLET_SLOTS + 從 source_uri 推導),但該 repo 現行
0 份 active SDD,其 sdd-guard 明確要求人決定要不要開啟——本次不越界代為決定,
留在報告中交回。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 16:48:31 +08:00
uncle6me-web
1d6dde4a01
fix(kbdb/embed): D68 補算向量照新到舊排序+每日額度上限+修復舊世代 is_embedded 誤判
...
leo 2026-08-11 拍板(D68,system-dev/wiki/decisions-summary.md):補算向量要照時間
由新到舊、且每天有額度上限,不能一次把 Workers AI 每日免費 10,000 neurons 燒光
(與萃取共用同一份額度,見 ops-facts.md)。對應 Leo/Arcrun#85 列出的三個缺口:
① 補算是由舊到新(ORDER BY created_at ASC)② 沒有每日額度上限 ③ 沒有任何自動觸發。
改動:
- backfillEmbeddings:ORDER BY created_at DESC(新到舊),並在打 AI 前依
env.EMBED_BACKFILL_DAILY_LIMIT(未設用推導出的預設值 1800,算式見 embed.ts 註解)
截斷候選、額度用完即停手不再打 AI。額度用量存在 entries 表單一列
(entry_type='embed_backfill_usage',UTC 日期切),不新增表(D38)。
- embedOnWrite / backfillEmbeddings 成功嵌入後在既有 content_hash 欄位蓋上
現行模型名(世代戳記),修復 leo21c 資料還原案:從備份整批灌回的列帶著對已退役
768 維索引的 is_embedded=1,現行 1024 維索引永遠不會補到它們。
- 新增 reconcileEmbedGeneration + POST /embed/reconcile:對 is_embedded=1 但
content_hash 非現行世代的候選,問 Vectorize.getByIds 是否真的在現行 index——
在→只補 content_hash 不打 AI;不在→重置 is_embedded=0 交回正常 backfill 佇列。
- 新增 kbdb/tests/embed-backfill.test.ts(改走真 SQLite,比舊版手刻假 DB 更硬):
14 個測試涵蓋新到舊排序、額度真的擋(含「拿掉 cap 會變紅」的反向驗證)、
世代核對端到端(reconcile → 重置 → backfill 真的補回來)、既有行為不迴歸。
現況誠實回報:目前沒有任何東西會自動觸發補算(無 cron/scheduled handler)——
唯一的「自動」路徑是 entries.ts 的語意搜尋回 0 命中時 fire-and-forget 觸發一次
(既有行為,本次未改動),仍需人或 CC 主動呼叫 /embed/backfill 或掛排程。
紅線:未動 leo 正式實例 leo21c;未動資料層形狀(三表不變,仍走既有 content_hash
bookkeeping 欄);未 push main,本 commit 在獨立分支 fix/embed-backfill-d68。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 16:42:54 +08:00
uncle6me-web
507620e313
merge: Arcrun 統一編譯零件,成品放固定位置 .worker-builds/(Arcrun#80)
...
總管 2026-08-11 審過後併入:
- 照本 repo 既有慣例(.component-builds 底下的 wasm 本來就 commit 進來),不新造第二套
- 每顆成品自帶 source_commit + content_sha256 ⇒ 答得出「我是哪個版本編出來的」到單顆層級
- 重現性已驗:兩個不同路徑深度的獨立 clone 分別裝依賴分別編譯,
5 顆的 content_sha256 與 wasm sha256 逐位元相同(manifest 只差 generated_at)
⇒ 這正是 arcrun-rag#39 的驗收條件,也是 #72 那個死結的解
待觀察(不擋本次):每次編譯會 commit 數萬行成品進原始碼 repo,長期會脹。
2026-08-11 13:54:19 +08:00
Leo
1e94f8451e
Arcrun#80: commit tier2 worker 官方編譯成品到固定位置 .worker-builds/
...
從本 repo 的 cypher-executor / kbdb / .component-builds/http_request /
registry/components/code / mcp 五個原始碼目錄,用 scripts/build-worker-artifacts.mjs
編出 5 顆成品,commit 進 repo(與既有 .component-builds/*/component.wasm 同一套
「固定位置、任何人直接拿」慣例)。
每顆 manifest 條目自帶 source_commit(該原始碼目錄最後改動的 commit)與
content_sha256,答得出「我是哪個版本的原始碼編出來的」到單顆層級。
重現性已驗證(見 commit 說明外的驗證記錄):同一個 commit 在兩個獨立 clone
(不同磁碟路徑深度,刻意模擬雲端 vs 地端的目錄結構差異)分別裝依賴、分別編譯,
5 顆的 content_sha256 與 wasm module sha256 逐位元相同,manifest.json 唯一差異
是 generated_at 時間戳。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 13:45:33 +08:00
Leo
dcb6ad693b
fix(build-worker-artifacts): dirty 判斷排除自己的輸出目錄
...
.worker-builds/ 是本腳本的輸出,在成品寫出、commit 之前永遠是 untracked——
拿它判斷「原始碼乾不乾淨」是自己把自己判成髒的假陽性。git status pathspec
排除 .worker-builds 後才是「原始碼有沒有未 commit 變更」的真實訊號。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 13:45:33 +08:00
Leo
3b0238bb28
Arcrun#80: 新增 tier2 worker 官方編譯腳本(成品固定位置的地基)
...
背景:安裝器(arcrun-rag)過去自己對 Arcrun 原始碼跑 esbuild,導致同一份原始碼在
不同機器編出不同位元組(見 arcrun-rag changelog 1.4.33 段、arcrun-rag#72):
① esbuild 把入口路徑寫進產物內部註解,該路徑預設相依於執行時 cwd
② 各 worker 目錄用不同套件管理器裝 node_modules,夾帶不同版本間接依賴
本腳本解法:
- absWorkingDir 固定為「本腳本自己算出的 repo 根目錄」,entry 一律用相對路徑餵給
esbuild——不管 clone 放在磁碟哪個絕對路徑,esbuild 內部產生的相對路徑字串相同
- 不自己跑 install,強制要求呼叫者先用該目錄既有 lockfile 裝好依賴(pnpm frozen /
npm ci),避免「install 方式不同 → 依賴版本不同 → 位元組不同」
- 每顆 worker 的 manifest entry 自帶 source_commit(該目錄最後改動的 commit),
答到單顆層級,不是整包一個 source 欄位
涵蓋 5 顆 tier2 worker(與 arcrun-rag bundle-components.mjs CORE_COMPONENTS 對齊):
cypher-executor / kbdb / http_request / code / mcp。
scripts/ 自帶 package.json + pnpm-lock.yaml 鎖 esbuild 版本(0.24.0)——
工具版本本身也是重現性的輸入之一。
驗證:本地跑通 5/5 build;byte-identical 重現性驗證見後續 commit(兩個獨立 clone
比對 sha256)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-11 13:45:33 +08:00
uncle6me-web
788295ed71
merge: 忘記密碼的錯誤訊息改白話+健康檢查回報寄信有沒有接上(arcrun-rag#38/#69/#25)
...
總管 2026-08-11 審過後併入:
- 拿掉行話「實例」;拿掉「請管理員直接幫你改密碼」(單人使用者就是管理員=死路,#25 同病)
- 改成給一條他自己走得完的路:重新跑一次安裝/更新
- /health 增回報 mail_relay_configured,讓安裝器判斷得出這台要不要重推
2026-08-11 13:24:34 +08:00
uncle6me-web
797e7f751c
fix(portal): 忘記密碼斷點——安裝器從沒注入 PORTAL_MAIL_RELAY_BASE(arcrun-rag#38/#69/#25)
...
leo 被鎖在自己的系統外面:1.4.35 已出 prod,「忘記密碼」畫面在線上,但按下去回
503「這台實例還沒有設定寄信服務」。根因在 products/arcrun-rag 的安裝器——
`grep -rn PORTAL_MAIL_RELAY installer/` 是零命中,即使 landing 那半(郵差)
D62 已經寫好。這個 repo 這邊改兩件配合修:
- /health 多回 `mail_relay_configured`(布林,不洩漏網址)——安裝器判斷「要不要
重推」只比 bundle_version,但這個 var 是這次才第一次被注入,跟版本號無關;
純比版本號的話,已經在最新版的實例(如 leo 那台)永遠不會因為「按更新」而
重推,這個 var 永遠補不進去。安裝器那邊會讀這個欄位決定要不要強制重推。
- portal.ts 的 503 訊息改白話(不提「實例」)+給一條使用者自己走得完的路
(重新執行安裝/更新),不再說「請管理員幫你改密碼」——單人使用者的管理員
就是他自己,那是死路(同源病灶:arcrun-rag#25)。
安裝器那半的修法(PORTAL_MAIL_RELAY_BASE 注入+stale 判斷)在
products/arcrun-rag 同批修(installer/oauth-prototype/worker.js)。
測試:cypher-executor `npx vitest run tests/portal-auth.test.ts tests/health.test.ts`
37/37 綠(35+2,既有測試無回歸;本次未新增測試——改動是訊息文案與健康檢查欄位,
行為已由既有測試覆蓋的路徑保護)。
2026-08-11 12:59:57 +08:00
uncle6me-web
d1c44a5878
merge: 忘記密碼與改密碼合成同一個機制(D62,arcrun-rag#69/#25)
...
總管 2026-08-11 逐筆審過後併入:
- 三筆:8d49d88 機制/9a29eb5 瀏覽器實測抓到的兩個前端缺陷/c76e10d 回歸測試
- #66 的修正 417d69c 在本分支血緣裡,併入不會弄丟已出貨的行為
- 試併零衝突;併入後 cypher-executor 測試 360 項、通過 346
(14 個失敗與 main 併入前完全相同,是既有紅燈,非本次造成)
- 併入後多出的 8 項全數通過=D62 的回歸測試
⚠️ 併入 main ≠ 出貨。要送到用戶手上仍需走出貨管線並由 leo 解保險。
2026-08-11 11:14:13 +08:00
uncle6me-web
a7e23badf2
WIP(kbdb): 關鍵字搜尋改成斷詞—— ⚠️ 未完成驗證,agent 被中途停止
...
【為什麼要這個】leo 2026-08-10:「沒有 MCP 你就是瞎的」。
總管實測(有對照組)證明搜尋對 AI 結構上不可用:
kbdb_search("Gemini 逃生口") → 0 筆 ← 兩個詞從不相鄰
kbdb_search("Gemini") → 864 行 ← 知識明明在
kbdb_search("local arcrun") → 5 筆 ← 這兩字在內容裡剛好相鄰
⇒ 現況是拿整個查詢字串去 LIKE,不拆詞。而 AI 問的永遠是問句 ⇒ 永遠回 0。
【這筆做了什麼】CJK/英數分段切詞、CJK 與 ASCII 停用詞、
單詞份量上限(避免長詞獨大)、相對分數截斷;附 search-tokenize.test.ts。
🔴 【誠實聲明】**這筆沒有驗完就被停了**(leo 要求全體停工專心 MCP 進安裝清單)。
未做:前後對照的實際輸出、回歸(原本查得到的不能變查不到)、相關性不崩壞。
**接手的人不要當成已驗證的東西**,先跑那三項再說。
分支保留於 gitea,隨時可接回去。相關:Leo/mira#4 總管留言。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
(cherry picked from commit 763de199b5 )
2026-08-11 10:02:09 +08:00
Leo
eebb691426
merge: 傳播空窗期不再銷毀 session(arcrun-rag#66)
...
leo 2026-08-10 本人被這個鎖在 stage 外面,並靠修好後的重設流程走回來——
這是「收的人自己驗到」,不是我們自己測過。
病:認證的家是 Workers Secret,改它會產生 worker 新版本,既有 isolate 讀到舊 env。
舊碼在那個空窗裡讀不到 record 就直接 SESSIONS_KV.delete()
⇒ 帶著完全有效的 token,登入狀態被當場銷毀,secret 鋪開也回不來。
#55 補的加速器重試只加在登入路徑,session 驗證這道門沒有。
實測空窗約 45 秒(不是 #55 記的 ≥15 秒):
改完密碼後舊密碼一路到 t+44.1s 仍登得進去,t+47.1s 才開始 401。
三段修法:
1. 先問加速器再判定(與登入路徑同一支 hydrateFromAccelerator)
2. 永不因「讀不到」刪 session——刪是 best-effort 清潔工,清掉的卻是使用者唯一的憑據
3. 仍讀不到且在空窗 → 503 auth_store_propagating,不是 401
(前端看到 401 就清 localStorage,後端不刪也沒用)
前端 boot() 收斂成「只有 401 才算被登出」。
驗證:stage 改密碼後同一 token 打 90 秒 → 200x30 / 401x0;瀏覽器實跑仍在站內;
tests/portal-auth.test.ts 27/27 綠。
2026-08-10 14:19:04 +00:00
Claude
c76e10d314
test(portal): 補 #66 與 D62 的回歸測試(8 條,35/35 綠)
...
#66(三條,斷言的是「session 有沒有被刪掉」而不只是狀態碼)
- 傳播空窗(加速器 key 還在)+讀不到 record → 503 auth_store_propagating,**KV 那筆還在**
- 非空窗+讀不到 record → 401 擋下,**KV 那筆仍然還在**(刪是清潔工,清掉的卻是唯一憑據)
- session 內容本身壞掉 → 401 且**該刪**(那是確定的事實,不是暫時讀不到)
⇒ 前兩條在舊碼上必紅:舊碼在這兩個情況都會 SESSIONS_KV.delete()
D62(五條)
- 帶 reset_token 呼叫 /portal/password/change:**不必登入、不必現有密碼**;
且「先刪再回」=同一條連結第二次必定 400 reset_token_invalid,KV 裡也真的沒了
- 先「看一眼」票(GET /portal/password/reset)不會消耗它
- 亂猜 / 格式不對的 token → 400
- 沒 reset_token 又沒登入 → 401(修改密碼那一格仍要身分)
- 沒設代寄服務 → /portal/password/forgot 誠實 503 mail_relay_not_configured(不假裝寄出去了)
擺放順序有註解說明:#66 那組會故意把 per-isolate overlay 灌成空的(模擬空窗),
而 overlay 是模組級全域變數不隨 test 重置,故必須排在檔案最後。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss
2026-08-10 13:55:53 +00:00
Claude
9a29eb5af6
fix(portal): 瀏覽器實測抓到的兩個前端缺陷——連結被路由吃掉、.hide 從來沒有在藏東西
...
兩個都是「HTTP 200 看不出來、真的開瀏覽器才會現形」的(規則五點五③)。
① `#/reset?token=…` 被路由正規化吃掉
route() 的第一行是「raw 不在 VIEWS 就換成 HOME」,而 reset 不是站內的 view
⇒ 使用者點信裡的連結,網址被改寫成 `#/search`、修改密碼畫面根本沒出現,
**而且 token 一起被丟掉**——連結一次有效,等於這條連結就這樣廢了。
改:route() 開頭先看有沒有 reset token,有就走 showReset 並 return。
(boot() 那條只顧得到「整頁重新載入」;hash 變動這條路以前沒人守。)
② `.hide` 一直只有三條有 scope 的規則(#tabbar .tab / #sidenav .nav / .modebtn)
沒有通用的 `.hide { display:none }` ⇒ 任何其他元素掛上 class="hide" **完全沒被藏起來**,
看起來有藏、其實沒藏。實測畫面:登入頁還沒按「忘記密碼」就已經露出 email 欄與「寄出連結」;
連結模式下「現有密碼」那一格也照樣顯示(D62 的「差別只有一格」當場破功)。
補通用規則,帶 !important 以蓋過 inline display(#forgot-box 有)。
既有三種用法意圖一致(都是要藏),行為不變。
stage 瀏覽器實測(youlin,playwright):忘記密碼 → 取連結 → 點進去 →
不輸入現有密碼設新密碼 → 自動回登入頁 → 用新密碼登入成功 → 進站 →
設定頁同一份表單(現有密碼那一格回來)改密碼 → **沒有被踢出去、可以繼續操作**。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss
2026-08-10 13:51:41 +00:00
Claude
8d49d883c0
feat(portal): 改密碼與忘記密碼合成同一個機制,用連結不用一次性密碼(D62)
...
leo 2026-08-10 拍板:「這兩個機制其實是一個機制,可以簡化。」
修改密碼:輸入**現有的** → 輸入新的 → 覆蓋
忘記密碼:收到**「修改密碼」連結** → **不輸入現有密碼(忽略)** → 輸入新的 → 覆蓋
⇒ 同一個畫面、同一條寫入路徑,差別只有「現有密碼」那一格。
後端(cypher-executor/src/routes/portal.ts)
- POST /portal/password/change =**那一支**。帶 reset_token 就走連結那一格(忽略 current),
沒帶就要登入 + 正確的 current。兩條路在 writeNewPassword 之後完全相同。
/portal/me/password 保留成**別名轉呼同一支**(不留第二份實作,兩份必然漂移)。
- POST /portal/password/forgot(公開)/GET /portal/password/reset(看票,不消耗)
- 連結的安全性(承 D50,不可退讓):**一次有效**(用掉即刪,先刪再回)、
**會過期**(KV TTL 30 分鐘)、**與註冊辨識碼不同源**(現場 crypto 亂數,
只活在本實例 SESSIONS_KV,與 landing SIGNUPS 那組安裝辨識碼毫無關係)。
KV 存的是 token 的 sha256,不是 token 本身。
- 🔴 不做一次性密碼(leo:「不要發一次性密碼太麻煩」)。
- 🔴 已否決不准寫回來的三條(D50):console 密碼救援/重裝重設密碼/直接用固定辨識碼。
中央代寄(arcrun-rag landing 那半在該 repo)
leo 給的職責切法:實例產生連結、管一次性/過期;arcrun.dev 只是郵差。
必須這樣切的硬理由:用戶自己的實例**沒有 send_email binding**,根本寄不了信。
🔴 總管紅線:**絕不把整條 URL 交給郵差**——寄件網域帶 DKIM,肯收「任意 URL+任意 email」
就是一台開放的釣魚中繼,燒的是整個網域信譽、不可逆。
故只交出本實例 origin + 一張回呼票,並新增 POST /portal/password/relay-verify:
郵差**回頭打這個 origin** 問「這張票是你發的嗎」,冒用別人網域會被那台實例自己否認
⇒ 主機屬於呼叫方這件事由郵差親自確認,不是相信宣稱。
信裡的連結落點 GET /portal/password/reset-link(主機刻意=被確認過的那個 origin)。
前端(console-ui/public/portal/index.html)
- 登入頁「忘記密碼」入口,**在 portal 不在 console**(leo:「是對 portal 不是對 console,
這樣 youlin 雖然忘記,我還是可以去 portal 忘記密碼。」)
- 拆掉登入頁原有的「用管理主控台密碼救援自己」連結與「忘記密碼請聯絡管理員」
——兩條都是 D50 已否決的做法(console 與 portal 是同一組帳密的兩個鑰匙孔)。
- #v-reset 殼**沒有自己的密碼欄位**:真正的表單是設定頁那唯一一份 #pw-form,
進入連結模式時被原封不動搬過去,只切換「現有密碼」那一格顯不顯示。
同一個表單元素、同一支送出函式 —— D62「同一個畫面」的字面落地。
驗證:tsc 與 baseline 同為 23 個既有錯誤(零新增);27/27 既有測試綠;前端 JS node --check 過。
stage 實測見交付回報。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss
2026-08-10 13:23:44 +00:00
Claude
417d69ceb3
fix(portal): 傳播空窗期不再銷毀 session——讀不到 ≠ 這個人不存在(arcrun-rag#66)
...
leo 2026-08-10 在 youlin stage 改完密碼被登出,之後怎麼登都回不去。
病灶是「這一瞬間讀不到」被當成「這個人不存在」,而且做的是**不可逆**的動作。
認證的家是 CF Workers Secret,改它會產生 worker 新版本,既有 isolate 讀到的
還是舊 env(#55 實測 ≥15 秒)。舊的 requirePortalUser 在那個空窗裡直接把
session 從 KV 刪掉——不是擋下讓你重試,是當場銷毀,等 secret 鋪開也回不來。
#55 補的「讀不到就再問一次加速器」只加在登入路徑(findAndVerifyUser),這道門沒有。
三處修法(缺一不可):
1. requirePortalUser 先問一次加速器再判定(與登入路徑同一招、同一支函式)
2. **永不因「讀不到」刪 session**;仍讀不到且正在傳播空窗 → 回 503
`auth_store_propagating` 而不是 401(讀得到 record 的「已停用」照舊刪,那是確定的事實)
3. 前端 boot() 從「任何非 2xx 都 dropSession」收斂成**只有 401 才算被登出**
——後端不刪、前端卻自己丟掉 localStorage 的 token,症狀一模一樣
順帶修掉同一族的一個資料遺失路徑:mutateAuthStore 舊版拿「可能是舊版 env」當底稿做
read-modify-write,而 writeAuthStore 會重切分片並刪掉多出來的舊分片 ⇒ 底稿若是
「某帳號被建立之前」的版本,那個帳號會在這次寫入中被抹掉且無法還原(secret 是唯一真相源)。
改成先問加速器、再把 env 版與 overlay 版取聯集當底稿;刪除仍有效(fn() 在聯集之後才跑)。
驗證:tsc 與 baseline 同為 23 個既有錯誤(零新增);tests/portal-auth.test.ts 27/27 綠。
stage 實測見交付回報。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01R8vF2zS2XpaZjzkC75Fjss
2026-08-10 13:22:34 +00:00
Leo
035e8b255b
chore(mcp): stage build 標記對齊實際部署的 commit
...
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 09:51:36 +00:00
Leo
1c630ecfd4
docs(mcp): /health 註解誠實界定——404 只代表比本版舊,不等於舊世代
...
實測:leo21c 與 geek6688 的 /health 都回 404,但 geek6688 是新世代(email+password)。
原註解會讓下一個人拿 404 去判世代而誤判。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 09:51:36 +00:00
Leo
a99d3e5a3e
chore(mcp): 補 stage 部署設定(youlin)——升級 arcrun-mcp 終於有測試場
...
arcrun-mcp 不在安裝器出貨的那批裡,所以「升級某台的 arcrun-mcp」一直沒有地方先驗,
要驗只能拿 leo21c(唯一一份 47.9 萬筆知識的真身)冒險。本檔把 stage 補上。
順帶把「手動直推 arcrun-mcp 到自架帳號」的兩個坑從人的記性搬進檔案:
① 拿掉 mcp.arcrun.dev route(zone 在 uncle6,自架帳號沒有)
② OAUTH_KV 填真 id(出貨 toml 是佔位符,直推不填 → /authorize 503)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 09:51:36 +00:00
Leo
894408181f
feat(mcp): GET /health — 一條 curl 看出這台是新舊世代 MCP
...
判斷一台實例的 arcrun-mcp 是哪一代認證,原本只能打 /authorize 剖 HTML 有幾個欄位
(ops-facts 2026-08-10 的土法)。改成誠實版本面:200+auth=portal-login =新世代;
404 =舊世代(同意頁還要那把沒人拿得到的 MCP_OWNER_SECRET ⇒ 等於接不上)。
順帶 build 標記(MCP_BUILD var)讓「這台跑的是哪一版」看得到。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 09:51:36 +00:00
uncle6me-web
d022ca067b
merge: kbdb DELETE 誠實回報向量刪除結果(arcrun-rag#46)
...
總管複核:改法與同檔 /entries/deprecate-by-library 一致(同步 await 再回應),
不動 schema、不加表(守 D38),附 84 行測試。
舊版 fire-and-forget 會把向量刪除失敗靜默吞掉——呼叫端看到「刪除成功」
但語意搜尋還留著殘影,這正是 #46 回報的症狀。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 15:50:36 +08:00
uncle6me-web
6715402bcc
fix(kbdb): DELETE /entries/:id 向量刪除改同步+誠實回報(arcrun-rag#46)
...
舊版把向量刪除包成 fire-and-forget(waitUntil(...).catch(()=>{}))——失敗被靜默
吞掉,呼叫端(rag_takedown_direct workflow/未來的 portal 刪除 UI)永遠不知道
向量沒清乾淨。與同檔 /entries/deprecate-by-library(同步 await + 回報
vectors_deleted)的做法不一致,補齊同款誠實回報:回應加 vector_deleted
(true/false/null),D1 本體刪除不因向量失敗而被擋下。
補上這支端點原本零覆蓋的測試(entries-delete.test.ts,3 案:模組未開/
向量刪除成功/向量刪除失敗)。
隨附 live e2e 驗證(youlin stage,4 筆測試知識,含批次 3 筆):刪除後
keyword/semantic 混合檢索與 rag_chat AI 問答皆不再讀到已刪內容,控制組
(未刪的既有知識)不受影響——確認端到端「刪除即在所有查詢路徑消失」成立,
細節見 Leo/arcrun-rag#46 留言。
2026-08-10 15:41:01 +08:00
uncle6me-web
c4cee35adb
feat(auth): 認證與資料分離——搬動知識資料時登入不再跟著壞掉(D61 / arcrun-rag#55)
...
leo 2026-08-10 下令:「登入認證資料要分離⋯⋯就算只有我一個人存在單獨的 json 檔也好,
它不能被改資料庫的連結導致無法登入。」「昨天不能登入 portal,今天不能登入 mcp,
這根本就是一個問題。」
病:portal 帳號住 KBDB(owner_id = {CONSOLE_TENANT}::portal),console 管理員帳密住
SESSIONS_KV。兩者都靠 binding 指過去,重裝/遷移一定會被重新指一次 ⇒ 保險箱的鑰匙
放在保險箱裡。2026-08-09 leo 資料一個位元組都沒動,卻被鎖在門外。
修:認證搬到 CF Workers per-script Secrets(掛在 script 上,與 bindings 兩套資源,
重部不會洗掉;journeys/gemini-key-lost-on-reinstall.md 與 installer worker.js:1148 皆有實證)。
- 新增 lib/portal-auth-store.ts:自足的 JSON,讀取零網路呼叫,>4.6KB 自動溢位分片
- portal.ts 的帳號讀寫全部改走它;KBDB 只留為舊實例的回退讀路徑,登入成功順手搬過去
- console-auth.ts 的第二份認證資料同樣搬離 KV
- 不牴觸 D38:KBDB 三張核心表不增不減,本案是把東西搬出去
- 沿用 credentials.ts 既有的 putWorkerSecret/deleteWorkerSecret,不另造第二套寫入路徑(D36)
明顯失敗(把 #10「寧可明顯失敗,不要靜默錯置」套到門鎖上):
- 「這台實例讀不到任何登入資料」回 503 + code=auth_store_empty,且**不計入 5 次鎖定**
(08-09 leo 就是被系統自己的誤判鎖了 15 分鐘)
- /console/setup 遇既有帳號改說「你剛才輸入的密碼沒有被採用」,不再只說「已設定過」
- /health 與 /console/auth-status 吐 auth_store 狀態(住哪、寫不寫得進去)
stage 實測撞到並修掉的坑:改 secret 會產生 worker 新版本,既有 isolate 讀到的還是舊 env
⇒ 「建好帳號立刻登入」有 15 秒以上 401,還被算進鎖定。加一層短 TTL 的 KV 加速器
(非真相源,只在 secret 查不到/密碼對不上時問一次),換 KV 不影響不變量。
驗收:stage(youlin)把知識資料庫換成另一顆空的 + 換租戶代號 + SESSIONS_KV 換成空的,
三樣一起換之後 portal / MCP /authorize / console 三條登入路徑仍全綠(複跑 3 次)。
對照組(舊版程式碼同樣換庫):登入回「email 或密碼錯誤」,5 次後鎖 15 分鐘。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 14:13:37 +08:00
uncle6me-web
ae81d22775
fix(harness): 世代閘的 ON_TRUE 判準過時,反過來擋下正確教材
...
引擎自 2026-08-01 起已支援條件邊(cypher-executor/src/graph-executor.ts
case 'ON_TRUE'/'ON_FALSE'/'ON_BRANCH',VALID_EDGE_TYPES 亦已列入;31 個
cypher-executor 測試全過)。registry/skills/write_intent_workflow.md(單一
真相源)也已在同日更正為教 ON_TRUE/ON_FALSE/ON_BRANCH 是合法邊。
但 cli/scripts/check-harness-generation.mjs 的世代閘還停在舊世代判準:
只要 SKILL.md 出現正面示範的 ON_TRUE 就擋——這道閘本身才是落後的一方,
把已經寫對的教材當錯誤攔下,害乾淨 `npm run build` 必敗。
同源的過時內容還藏在三個手動維護的 harness 原始檔(非腳本產物):
CLAUDE.block.md/commands/arcrun.md/hooks/arcrun-guard.sh 都寫著
「引擎沒有條件邊」「沒有 ON_TRUE/ON_FALSE/ON_FAILURE」,一併更正。
真正不存在的邊是 ON_FAILURE(VALID_EDGE_TYPES 只有 ON_FAIL),把 mustNot
判準從 ON_TRUE 換成 ON_FAILURE,並新增 must 規則要求 ON_TRUE 必須出現,
防止教材日後又被改回「條件邊不存在」的舊世代說法。
skills/arcrun-mindset/SKILL.md 是由 registry 於建置期重建的產物
(build-harness-skill.mjs),本次改動只跑 `npm run build:harness`
重建、不手改。
驗證:故意把 SKILL.md 的 ON_FAILURE 改成正面示範,確認閘仍會擋下
(exit 1),還原後 `npm run build` 連跑兩次皆全綠且冪等(SKILL.md
md5 不變)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-10 11:03:43 +08:00
uncle6me-web
9740794050
docs(3-specs): 立案 Arcrun App ↔ Portal 掛載協定 v0 提案(Leo/Arcrun#82)
...
設計全文住在票上,本檔只留指針+影響分析,等 leo confirm。
病根實查:Portal「有哪些頁」在單檔 HTML 裡寫了四遍,出貨時整包內嵌成
單檔 worker,安裝器只會整顆換掉、無任何掛載點概念 ⇒ 加一個能力=改核心。
未 confirm 前不開新 SDD、不動功能程式碼(現行 active=workflow-discovery)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 22:02:08 +08:00
uncle6me-web
453dec60b1
fix(scripts): template 來源改指活帳號,404 不再靜默寫入垃圾內容
...
scripts/install.sh 與 scripts/update.sh 的更新來源指向已被 GitHub suspend 的
uncle6me-web 帳號,實測全部 404 ⇒ 自動更新靜默失效。改成與 system-dev-template
本體、以及本 repo 現行世代 system-dev/scripts/ 一致的正解:預設公開 GitHub
youlinhsieh/system-dev-template,可用 TEMPLATE_SOURCE 環境變數覆寫,不改檔。
同時補上 looks_like_error_page 判斷(沿用 template repo 已修好的寫法):curl
對 404 常回傳非空的錯誤頁內容,只判斷「非空」會把它當成正常檔案寫入且不報錯。
現在錯誤頁會被偵測、檔案不寫入、FAILED 清單於結尾列出、腳本以非零狀態碼結束。
實測:
- 修正後來源多個路徑回真實 HTTP 200(CLAUDE.md/VERSION/self-update 兩支腳本)。
- 刻意把 TEMPLATE_SOURCE 指回死帳號重跑兩支腳本:全部項目進 FAILED 清單、
無任何檔案被錯誤頁污染、exit code 1。
- 兩支腳本 bash -n 語法檢查通過。
已知缺口(不在本次範圍,留待另決):template repo 內部檔案佈局已從
.claude/wiki/、docs/ 搬到 system-dev/ 前綴,這兩支舊世代腳本仍用舊路徑,
其中一部分檔案(wiki 範本、docs/README、SDD 範本等)在新帳號上仍 404——
現在會清楚回報失敗而不是靜默吞掉,但尚未逐一改點新路徑。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com >
2026-08-09 20:54:01 +08:00
uncle6me-web
bfc98fe41a
官網與 npm 上的 GitHub 連結指向已停用帳號,全是 404(arcrun-rag#41)
...
延續同一次盤查(判準:素不相識的人點進來會不會被帶到到不了的地方)。
這批比 README 更顯眼——是 arcrun.dev 官網上那顆「GitHub」鈕,以及 npm 套件頁的
Repository 欄。逐一 curl 實測全部 404:
- landing(官網三個檔五處):github.com/richblack/arcrun → 404(帳號已 suspend)
→ github.com/youlinhsieh/Arcrun(200)
其中 integrations 頁還指 richblack/arcrun/blob/main/CONTRIBUTING.md =雙重死
(帳號沒了,而且這個 repo 從來就只有 CONTRIBUTING-components.md)
→ youlinhsieh/Arcrun/blob/main/CONTRIBUTING-components.md(實測 200)
- cli/package.json 的 repository.url:github.com/uncle6me-web/Arcrun.git → 404
(同樣是 suspend 掉的舊帳號)→ youlinhsieh/Arcrun。這欄會直接顯示在
npmjs.com/package/arcrun 的 Repository 連結上,裝了 CLI 的人就是從那裡點過來。
只換字串,沒有邏輯變動;package.json 已驗證仍是合法 JSON。
⚠️ 同一批掃出但**本次未動**(behavior-affecting,另案處理):
scripts/install.sh:29 與 scripts/update.sh:26 的 template 來源仍指
raw.githubusercontent.com/uncle6me-web/… =實測 404 ⇒ 自動更新靜默失效。
這正是 agent-memory 記過「uncle6me-web 曾害 template update.sh 自動更新靜默
死亡」的同一顆雷,修在 template repo 卻沒修到 Arcrun 這份 copy。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 20:28:05 +08:00
uncle6me-web
be9b92eb28
README:四個對外連結修掉,別再把點進來的人帶到死地方(arcrun-rag#41)
...
leo 08-09:「整個 github 的 readme 都是過時的,如果用戶真的連過來會被誤導」。
逐一 curl 實測,不靠假設:
- Arcrun RAG 連結指 git.uncle6.me/Leo/arcrun-rag = **實測 404**(那顆是 private;
同主機的 Leo/Arcrun 反而匿名 200 ⇒ 判準是逐一實測,不是「Gitea 一律 private」)
→ 改指公開鏡像 github.com/youlinhsieh/arcrun-rag(200)
- 致謝的 @richblack → github.com/richblack **實測 404**(帳號已 suspend),
改 @youlinhsieh(200)
- 結尾 [CONTRIBUTING.md] → 檔案不存在,線上實測 raw 404;
repo 裡真正有的是 CONTRIBUTING-components.md(線上 200)
- 「給 AI 操盤手:開始前讀 .claude/rules/06-mindset.md」→ `.claude` 整個在公開
排除清單裡,公開 repo 根本沒這個檔 ⇒ 對外=指了個不存在的路。改指 llms.txt
(公開、線上 200,第 23-26 行就是那套世界觀),並說明裝 harness 後才會有 Skill。
另把 08-08 留的內部說明 HTML 註解換成對外講得通的一句話:目前沒有公開試玩站,
想看產出去看 arcrun-rag-demo-knowledge 公開鏡像(實測 200)。註解寫給自己人看,
但它躺在對外 README 的原始碼裡。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 20:25:42 +08:00
uncle6me-web
19c82df05f
fix(portal): 管理員忘記密碼自救援出口(arcrun-rag#25)
...
唯一 admin 忘記 portal 密碼就永久卡死:requirePortalAdmin 系列端點全部要
先有 portal session 才進得去,bootstrap 又只能跑一次——登入頁只會叫他
「聯絡管理員」,而他自己就是管理員,沒有下一步。
新增 POST /portal/admin/recover-password,複用 bootstrap 已在用的 console
owner session 當人閘(與 portal 密碼完全獨立存放的另一組帳密)。畫面入口:
/console → 設定 → 「Portal 帳號密碼救援」;/portal 登入頁加一行連結指過去。
本機真瀏覽器 E2E 驗證(wrangler dev 18787/18788 + 本機靜態伺服,真的走一輪
forgot-password 狀態):first-time setup 建帳號 → 故意打錯密碼確認鎖死
(email 或密碼錯誤)→ 點連結進 /console → 用 console 密碼登入 → 設定頁輸入
portal email → 產生新密碼 BPq2Rs4p7dBWMd6d → 回 /portal 用新密碼登入成功。
cypher-executor 4 個新測試 + 既有 59/60 綠(唯一失敗是既有 pre-existing
/portal HTML 殼 404,與本次無關,git stash 驗證過)。
2026-08-09 15:06:17 +08:00
uncle6me-web
23d36b311a
portal 設定頁補顯示 MCP 連接網址(arcrun-rag#7)
...
封測者原話:「說明叫我把 MCP 加進 claude.ai connector,但我找不到網址」。文件一直寫
「登入 portal → 設定頁,那裡可以直接複製」,但畫面上從沒真的顯示過(grep 0 命中),
用戶照文件走一定撲空。
設定頁新增「接上你的 AI(MCP)」面板:純前端把 apiBase 的 worker 名字從
arcrun-cypher-executor 換成 arcrun-mcp(同一顆自架帳號 workers.dev 子網域,對齊
cli/src/lib/deploy.ts:386-392 部署時的組法),不符形狀就誠實顯示「尚未偵測到」,
不亂猜連不到的網址。複製按鈕從既有 copyOriginUrl 拆出共用 copyText(btn, url)。
端到端本機瀏覽器實測:真 wrangler dev(kbdb+cypher-executor local D1)+ 真登入流程
(console setup → bootstrap admin → portal login)走到設定頁,面板正確顯示/隱藏;
用貼近真實自架形狀的假網址驗算,結果與 deploy.ts 的組法逐字相同;複製鈕點擊行為與
既有、未改動的 st-copy-url 按鈕在同一自動化環境下一致(clipboard-write 是瀏覽器自動化
環境限制,非本次改動的迴歸)。詳細記錄見 system-dev/docs/3-specs/portal-auth/tasks.md t218。
未部署(紅線:只 commit+push,未動任何 Cloudflare 實例)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 14:23:56 +08:00
uncle6me-web
ebd4bf5d97
wiki: 記執行紀錄保留期 UI 補完(arcrun-rag#21)
...
status.md 補一段,供下個 session 接關不用重查。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 13:30:00 +08:00
uncle6me-web
889b70b8f9
feat(portal): 執行紀錄保留期 UI(P7 補前端,arcrun-rag#21)
...
後端(4ca23c2)已提供 GET/PUT /portal/admin/execution-log-retention,
但管理頁完全沒有對應介面——leo 只能自己 curl。本次補管理頁「執行紀錄保留期」
卡片:顯示目前保留天數、可改天數、可勾「不刪除」(企業稽核)。純薄殼,
零業務邏輯,呼叫既有端點(rule 07 薄殼原則)。
驗證(本機真瀏覽器 E2E,非 curl/非讀原始碼):
本機起兩個真 wrangler dev(kbdb:18787/cypher-executor:18788,local D1+KV,
真的套用 migrations 0001-0006)+本機靜態伺服 console-ui/public(18790,
config.js 指向本機 apiBase)+UI_ORIGINS 加白名單解 CORS。瀏覽器走真實
「首次設定」流程建帳號、登入、進管理頁:
- 預設值:保留天數顯示 90(無資料時退回預設,非空白)
- 改 45 天 → 儲存 → 畫面即時更新「目前設定:保留 45 天」→ reload 頁面仍是 45
- 勾「不刪除」→ 儲存 → 天數輸入框停用、清空 → 顯示「不刪除(企業稽核)」
→ reload 仍是不刪除
- 改回 90 天 → 儲存 → reload 仍是 90(雙向都驗過)
- 全程 Network 面板每筆 GET/PUT 皆 200;console 除了測試前置階段的舊
bootstrap-conflict 雜訊外,無新增紅字
發現但沒動的問題:console-ui 本身沒有本機可跑的 dev/test 腳本
(package.json 只有 deploy/verify),E2E 用的是手工起 wrangler dev +
python http.server 兜出來的,建議之後補一支 `npm run preview:local`
方便下次驗證不用重找路。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 13:28:36 +08:00
uncle6me-web
21be6d19f7
把 .dev.vars 加進 .gitignore——本機密鑰檔原本完全沒被擋
...
實查:cypher-executor/.dev.vars(3 行)與 kbdb/.dev.vars(1 行)都是 untracked
且 git check-ignore 零命中,任何人一次 git add -A 就會把金鑰推上 Gitea。
歷史上沒有被 commit 過,所以是純預防、不需要清歷史。
對齊 D36「金鑰只有一個家」:真身不落在 repo 上,不是靠自律,是拿不到。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 13:24:24 +08:00
uncle6me-web
6846d6ddae
fix(semantic): 故障照實說是故障——不再把壞掉說成「沒開通」(leo 2026-08-09 直令)
...
一、文案(portal/console/kbdb hint):語意搜尋是一安裝就提供的功能,
降級=故障。橫幅改「語意搜尋目前故障/我們的問題/你不用做任何事」,
拿掉「還沒開通、想開通請匯出診斷檔」這種要使用者申請開通的假框架。
kbdb 降級回應加 degraded_reason(module_off / embed_query_failed)。
二、查詢向量化失敗不再偽裝成空結果(leo 點名的謊):
semanticSearch 舊行為「AI 額度用完 → 回 []」會讓使用者以為
自己的知識庫裡沒有這筆資料。改丟 EmbedQueryFailedError,
route 誠實降級 keyword+照實告知是暫時故障。
三、源頭機制(裝好的實例為什麼會失去語意搜尋):
- acr update:kbdb_embed 判斷 ===true → !==false。config 缺欄位時
redeploy 會把 [[vectorize]]+[ai] binding 靜默剝掉(wrangler deploy
整份覆蓋),一台正常實例就此壞掉。init 預設同步翻成 [Y/n]。
-(另 repo)deploy-all.mjs ensureVectorizeIndex 失敗改致命中止。
四、順手自癒:孤兒向量/下架殘影搜尋時背景清除;空結果且 pending>0
背景 backfill;no_index 拆「故障」vs「還沒有資料」兩態。
測試:kbdb 146/146(新增 degraded 6 案+selftest 1 案);cli 10/10;
瀏覽器端到端兩種故障畫面實測(local wrangler dev+portal 真登入)。
無 SDD 對應:leo 直令修故障(同 08-07 檢修孔前例的人閘直接授權路徑)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 02:05:12 +08:00
uncle6me-web
8eb10049b8
P8:節點輸出 KV 寫入只服務 PIPE 讀者——拆掉比 neurons 更短的隱形短板
...
leo 08-09「不需要換模型,要調整每個 CF 數字搭配」。盤點發現真正最短的板不是
Workers AI neurons(119 檔/日),是 EXEC_CONTEXT KV:每節點(含 FOREACH 每圈)
put 一次、rag 工作流一張卡 15 次,但唯一讀點是 PIPE 邊——rag 系全無 PIPE 邊,
15 次全是白燒 ⇒ KV 1,000/日 ÷ 15 ≈ 66 檔/日,兩條路(免金鑰/Gemini)都被卡。
修法=寫入前檢查「節點有 PIPE 出邊」。PIPE 工作流與 resume 路徑行為不變。
實測(youlin stage):修前同構卡留 6 node key(15 put)→ 修後零 key,
blocks/triplets 照常寫入。單元測試鎖住兩側行為。
另復原 08-08 重部誤拔的 [ai] binding(extract 501→200,KEEP_AI=true)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 01:26:16 +08:00
uncle6me-web
831cb62d2e
feat(portal): 拔掉雲端「疑難排解」匯出按鈕,改導向本機小幫手(t213 收尾)
...
leo 08-08:「雲端那個要刪掉?不刪用戶搞不清楚要去哪裏下載」;08-09 追認「通知
完畢可以刪除」——封測者已被通知去更新到有地端匯出的版本(arcrun-app「版本與
更新」頁的疑難排解卡,見 products/arcrun-rag commit 9f1ca58 起),放行條件已滿足。
三處改動:
1. 設定頁「疑難排解」面板:移除 #st-diag-export 按鈕與 #st-diag-status,
改成純文字指路到電腦上的 Arcrun App。
2. 對應的前端 JS 點擊處理(打 GET /portal/data/diagnostics 的那段 IIFE)整段刪除
——按鈕已不存在,留著是死代碼。
3. 語意搜尋降級橫幅(se-banner):原本也教用戶「到設定→疑難排解匯出診斷檔」,
同步改成指向本機小幫手,否則使用者會照著走進一個不存在的按鈕。
GET /portal/data/diagnostics 端點本身未刪(無害、已無任何 UI 呼叫),純粹清路標
不動後端;已知例外——同步小幫手完全連不上、且封測者是老版本沒有本機匯出時,
會真的無路可走,判斷為可接受(他們已被個別通知升級,且雲端 portal 仍能用文字
指路,不是把人晾在原地不給說明)。
驗證:本機起 static server(config.js 指向 dummy apiBase)+瀏覽器 JS 強制顯示
setting/search view,實際截圖確認按鈕消失、#st-diag-export/#st-diag-status 在
DOM 裡是 null、文案渲染正確無破版;console 只有 dummy apiBase 連不上的預期錯誤,
無語法/參照錯誤。cypher-executor vitest(portal-data/admin/auth)114 通過、2 個
既有失敗(HTML 殼 404,改動前後一致,非本次影響——用 git stash 前後對照過)。
未部署(紅線:本輪只到本機驗過+commit+push gitea,prod 需 leo 開閘)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 01:09:10 +08:00
uncle6me-web
894d9abeb1
Revert "P8:/portal/daemon/extract 萃取模型 scout → qwen3-30b(真筆記實測:品質不降、額度天花板翻倍)"
...
This reverts commit aa6b899276 .
2026-08-09 00:51:41 +08:00
uncle6me-web
3447efc94e
docs(mcp): list_recent_executions 說明文字跟上 P7(保留期),不再寫「無固定保留期」
...
08-07 事故修復後,這支工具的說明文字曾誠實標「無固定保留期」——那時保留期
確實還沒做。前一個 commit(P7)補上保留期可設定(預設 90 天,可調,可設不刪
除),這支說明文字若不跟著改,會誤導以後讀到它的人以為系統仍然無限保留。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 00:45:19 +08:00
uncle6me-web
4ca23c256a
feat(kbdb): 執行紀錄保留期可設定(P7,leo 08-08 confirm)
...
背景:08-07 事故修復(60688c3)已把執行紀錄從 KV 搬到 KBDB/D1(entries 表,
API-as-Wall),解掉「稽核資料放在會揮發、被額度打斷的地方」這個結構性錯誤,
也順帶把 Evan 撞到的 1,070 次寫入牆退到 D1 額度層級。但那次修復留了一個誠實
的缺口:MCP list_recent_executions 的說明文字寫著「無固定保留期」——保留期
可設定這件事還沒做。本次補上。
P7 規格(system-dev/docs/3-specs/pending-changes.md「P7」,leo 08-08 confirm):
執行紀錄是稽核資料,預設保留 90 天(3 個月)過期即清;租戶可自訂天數,也可
設「不刪除」(企業稽核,leo:「我願意花很多錢保存,不要刪除」)。
實作(kbdb/src/actions/execution-log.ts,牆內):
- getRetentionDays/setRetentionDays:沿用 execution_log_usage 的 upsert 慣例,
單一 entries 列/租戶(entry_type='execution_log_retention_config'),零建表。
- cleanupExpiredLogs:分兩段掃——有自訂天數的租戶各自 cutoff;其餘(含無租戶)
套預設 90 天,排除「不刪除」與已處理過的租戶。每次呼叫界限刪除量
(CLEANUP_BATCH_LIMIT=500),長期多次呼叫可逐步清完累積量。
路由(kbdb/src/routes/execution-log.ts):GET/PUT /execution-log/retention、
POST /execution-log/cleanup,沿用既有的 Bearer token 全域守衛(fail-closed)。
清理觸發(cypher-executor/src/scheduled.ts):不新增排程基礎設施(wrangler.toml
[triggers] 是受保護檔案)——搭 cypher-executor 既有的每分鐘 cron tick 便車,
固定 UTC 02:30 那一分鐘 fire-and-forget 打一次 KBDB 的 cleanup 端點,一天一次,
不是輪詢。
Portal 薄殼(cypher-executor/src/routes/portal.ts):GET/PUT
/portal/admin/execution-log-retention(role=admin 閘),讓本實例的租戶
(portalTenant)能實際設定保留天數,不只是 KBDB 內部端點。
測試(kbdb/tests/execution-log.test.ts):新增 27 個測試(含原有測試共 27 通過
於本檔),真 SQLite 驗證 cutoff 邏輯、自訂天數隔離、「不刪除」永不清、壞資料
容錯、混合租戶情境、路由層 400/200。測試治具需要「插入指定 created_at 的過期
紀錄」這個正式寫入路徑刻意不開放的能力,做成 kbdb/src/actions/execution-log.ts
內匯出的 testInsert*/testCount* 函式(牆內執行 SQL),測試檔本身零原生 SQL。
量測(不是推論):youlin(yuga3bse)實例上,redeploy 後對 graph_neighbors
webhook 發送 1,200 次併發請求(超過 Evan 實測失敗的 1,070 次)——全部 HTTP 200;
ANALYTICS_KV 的 key 數量在請求前後維持 663 不變,證明新寫入路徑完全不碰 KV,
Evan 撞到的那道牆的成因已被物理移除,不只是延後。
讀取端驗證(真呼叫,非 curl):透過綁定 yuga3bse 的 MCP 連線實際呼叫
arcrun_list_recent_executions(回傳含本次量測寫入的 D1 紀錄)與
arcrun_get_execution_trace(正確回 404 not_found,非崩潰);portal 前端
(https://arcrun-rag-ui.youlin-hsieh-dev.workers.dev/portal)瀏覽器實際載入 ,
無 console 錯誤、無異常紅色橫幅。
舊資料:KV 裡既有的 stats:* 沿用 60688c3 的既有決定——不搬移,任其依現有 90
天 TTL 自然過期(那是統計快取不是真相源);新的 D1 execution_log 保留政策只
管新資料,不回溯處理。
部署:cypher-executor + kbdb 已手動部署到 youlin(yuga3bse,AI 測試場,leo
08-08 令),未動 prod(uncle6)。本次僅程式碼行為變更、無新增/修改 D1 binding、
無新表——三個既有 D1 binding(CREDENTIALS_DB×2+kbdb DB)維持原樣,未新增第四個。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 00:43:55 +08:00
uncle6me-web
aa6b899276
P8:/portal/daemon/extract 萃取模型 scout → qwen3-30b(真筆記實測:品質不降、額度天花板翻倍)
...
免金鑰路短板=Workers AI 免費 10,000 neurons/日。leo 真實筆記 8 篇 × 5 模型實測
(arcrun-rag docs/benchmarks/p8-extractor-quality/,usage.neurons 為 CF 原生計量):
scout 84 n/檔(119 檔/日)→ qwen3-30b 43 n/檔(232 檔/日);格式合規 8/8、
三元組 7.6 條全可解析(scout 5.0)。granite 最便宜但 5/8 缺段=實測否決。
聊天 recipe(workers_ai_chat)不動;只 commit 本 hunk,工作區另有 P7 進行中改動未收。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-09 00:40:52 +08:00
uncle6me-web
466e56bc2d
落帳:youlin 登入修好(瀏覽器實證)+連線中斷 vs 密碼錯誤是決定性差別
...
含誠實限制:驗的是程式碼修對了,不是安裝器裝出來的結果。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 22:15:00 +08:00
uncle6me-web
07cc7f51b5
fix(cypher): 同一台實例的 portal 一律自動放行,不再依賴 UI_ORIGINS 被注入
...
2026-08-08 事故根因:leo 的 youlin 實例登入整個斷掉,瀏覽器實證
blocked by CORS policy: No 'Access-Control-Allow-Origin' header
真因=該台 UI_ORIGINS 沒被設。
同一天發生兩次同款:這些變數只有安裝器會注入,任何手動 wrangler deploy
就會漏掉,而漏掉時系統看起來完全正常(worker 上線、200、版本號對),
只有真人點下去才會發現。leo:「這麼危險的問題已經發生 2 次,不可以再有一次。」
⇒ 治法不是「記得注入」,是讓它不需要被注入:portal 與 cypher 是同一個
workers.dev 子網域下的兄弟,位址推導得出來。少一個必須注入的變數,
就少一個會被漏掉的東西。UI_ORIGINS 仍有效(自訂網域用),只是不再是
「登得進去」的前提。
對照:改動前後 tsc 錯誤數同為 7(皆為既有、不在本檔)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 20:47:32 +08:00
uncle6me-web
42cb1d7aa9
console-ui:把「線上跑的是不是當代的」變成機械判準,並接進部署鏈
...
leo 2026-08-08:「已經發生過一次這個錯誤,把舊版界面上到 prod,
你要確定不可再犯。」
實測(repo 對線上,純文字資產比對):
repo portal/index.html 343,969 bytes
線上 mira.uncle6.me 82,911 bytes(Songti 12 處,舊金色 serif 品牌)
線上 pages.dev 82,911 bytes(同上)
而 e730b3f 那版 verify-live 對這兩站**三項檢查全過**——因為它驗的是
組態(apiBase、profile 的 views/home),不是世代。
⇒ 一個網址可以組態完全正確、卻對外展示一套早就被淘汰的介面,
而所有機械檢查都說它是綠的。這就是要消滅的狀態。
本次落地:
一、世代指紋(targets.mjs)
逐一取線上/產物的資產(index / portal / console / favicon.svg),
遮掉本來就該隨部署目標不同的那兩行(VIEWS/HOME),其餘按位元組比對。
刻意不用關鍵字清單——清單要人維護,而舊世代能無聲上線正是因為沒人記得維護它。
誠實 trade-off 寫在檔內:repo 改了沒部署就會判紅,那是正確的(那時線上確實不當代)。
二、宣告值真的寫進產物(收掉 e730b3f 標的 WIP)
deploy.mjs 改為由 targets.mjs 產出 .staging/<目標> 再推:
config.js 由宣告值即時產生、console 的 VIEWS/HOME 依 profile 覆寫,
**覆寫沒命中就中止部署**;推之前回頭讀磁碟上那份驗一次(不看腳本印了什麼)。
public/config.js 刪除——它是產物不是原始碼。
三、修好一道從 08-03 起就在誤判的閘
t160 的世代閘比對 portal 全文含「登記新庫」即拒部,而 66f1b59(08-03)
加了一則**說明「已經把它拿掉了」的 HTML 註解** ⇒ 該閘自那天起每次誤判,
npm run deploy:personal 連續五天推不出去。改成剝掉註解後只看可見內容,
並降級為輔助(主判準是指紋)。這正是「手工關鍵字閘會腐爛」的實例。
四、讓它在該跑的時候真的被跑到(不再生出沒人記得執行的腳本)
· deploy.mjs 推完自動回頭驗線上,不過就算本次部署失敗
· .deploy-state.json 只在線上實測通過後才寫,且不進版控
(新 checkout 沒紀錄=狀態未知=該被提醒,而不是繼承別人的綠燈)
· Stop hook 每回合離線比對「手上這一代 vs 最後一次驗過的部署」,
在要說「做完了」的那一刻出聲(實測 0.096s,不連網)
五、uncle6 邊界寫進工具本身(leo 08-08:「要看範例只在 youlin 網站,不要去碰 uncle6」)
deploy.targets.json 的 enterprise 標 frozen:deploy 拒絕部署、verify 連抓都不抓。
目標本身保留不刪——刪掉就變成下一個 AI 眼中「從來沒有過這個站」的失憶。
同源清掉兩處還活著的舊記錄:README 的線上 demo 連結、public/index.html 的註解。
驗收證據見 commit 後的實測輸出(舊世代樣本取自 git 歷史 ad367e4,本機起站餵判準,
未碰任何線上資源)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 20:36:18 +08:00
uncle6me-web
e730b3f831
console-ui 部署:宣告值只解讀一次,並補上線上實況驗證(WIP)
...
同源於 2026-08-08 的 apiBase 事故:部署腳本把 apiBase/profile 印在
終端機上,卻沒有寫進推上去的產物 ⇒ 印對的、推錯的。
根因比想像深:deploy.targets.json 原本靠 build.mjs 在 build 期把
profile/apiBase 烤進產物,但 t160(e744ad1)清世代債時把 build.mjs
整支刪掉改成直接託管 public/,沒有人接手「把宣告值寫進產物」這件事
⇒ 前兩次事故的解等於被還原,只剩下「印出來給人看」。
本次落地:
- targets.mjs:宣告值的唯一讀取點,把「一個目標展開成期望的產物長相」
定死成函式,供部署/驗證共用同一個答案,杜絕三邊各自解讀而漂移。
缺 apiBase/accountId/verifyUrls/未定義的 profile 一律拒絕部署。
- verify-live.mjs:獨立可跑,驗「線上網址真的在用的組態」=「宣告值」。
- deploy.targets.json:補 _profiles(profile → views/home)與 verifyUrls。
WIP:deploy.mjs 尚未改接 targets.mjs,public/config.js 尚未退役。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 20:14:20 +08:00
uncle6me-web
84471659af
docs(portal): 疑難排解按鈕文案改導流(t213,InkStoneCo 總管交辦)
...
這顆按鈕在封測者瀏覽器裡執行,構不到他電腦上 daemon 的本機資料(檔案總量/
失敗分類/daemon 版本)——那半已改在 arcrun-app 本機端匯出(見
products/arcrun-rag commit 9f1ca58)。按鈕本身保留當退路(daemon 完全掛掉時
唯一還按得到的東西),文案改成誠實講清楚自己只有一半、導去完整版,照總管
給的原話:「這裡只看得到雲端這半,完整診斷請到你電腦上的 Arcrun 匯出。」
純文案改動,未動任何邏輯/端點;跑過 portal-data/portal-admin/portal-auth
三份測試,114 通過、2 個既有失敗(HTML 殼 404,測試環境問題,與本次無關,
改動前後一致)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 13:13:06 +08:00
uncle6me-web
93b1140bf1
feat(portal): 新增 GET /portal/daemon/diagnostics(t213 matrix/arcrun 半部)
...
InkStoneCo 總管交辦(arcrun-rag repo t213):leo 拿真診斷檔實測四個真實問題,只答得出一題
——其餘三題需要地端資料(daemon 本機 manifest 總量/失敗分類/自我更新狀態),而現有
GET /portal/data/diagnostics 只有 portal session 認證,daemon 背景行程沒有 session
(密碼只在連線精靈當下用過就丟,不落地),構不到這支端點。
本次只做 matrix/arcrun 半部(雲端這半):
- 把 /portal/data/diagnostics 的核心查詢邏輯抽成 buildDiagnostics(env, tenant)
(portal.ts),薄殼原則:能力只實作一次
- 新增 GET /portal/daemon/diagnostics,認證比照既有 /portal/daemon/extract
(X-Arcrun-API-Key,非 session);apiKey 當 owner_id 用,不與 portalTenant(env)
比對(t189 教訓:daemon 的 api_key 不保證等於 worker 的 CONSOLE_TENANT)
- /portal/data/diagnostics 改呼叫共用函式,回應形狀完全不變
- 按 leo 指示刪掉「需在失敗當下由封測者截圖」那句 notes(本機那半資料到位後這句話
失去意義)
地端那半(arcrun-app 讀 manifest 合併 + 匯出按鈕)在 products/arcrun-rag repo 進行,
待另一隻處理 t210 的 agent 落地 app.go/main.js 改動後再接線,本次不動 arcrun-app。
驗證:
- npx tsc --noEmit:與 stash 前錯誤數相同(4 個),零新增(pre-existing,與本次改動無關)
- npx vitest run:314→315 通過(+3 新測試涵蓋 401/apiKey 當 owner_id 不比對 tenant/
回應形狀與 session 版一致),14 個既有失敗與改動前完全相同(HTML 殼 404,測試環境
static asset 問題,與 portal.ts/portal-data.ts 邏輯無關)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 12:32:10 +08:00
uncle6me-web
962d863ef7
fix(kbdb): 藏書地圖 M3 收尾——讀端自動核對重算,不再依賴 ingest 接鏈
...
真因(總管實測,system-dev/wiki/mistakes.md 08-08 段):design 原訂「ingest 尾端呼
POST /map/recompute」,但 repo 內查無任何呼叫點,三週沒接上,沒手動 backfill 過的租戶
(絕大多數)GET /map 恆回空;MCP 說明文字還宣稱「地圖由 ingest 尾端自動重算(M3)」——假話。
leo 否決「降級成即時聚合、不維護快取」的提案(會丟失 narrative 這類摘要本體,只算得出
count)。改法:GET /map/GET /map/:library 讀端自己核對即時三元組數,落差就地呼叫既有的
recomputeLibraryMap 補算(kbdb/src/actions/library-map.ts ensureFreshLibraryMaps)。聚合
SQL 沒有第二套、narrative/relation_profile/bridges 摘要欄位原封不動,只是觸發時機從「等
外部呼叫」改成「讀的當下順手核對」。同時解掉:全租戶自動 backfill/跟得上新資料/不依賴
跨 repo 的 ingest 接鏈。
附帶修 recomputeLibraryMap 的 narrative 欄位:沒帶值時原本會清空,改成沿用上一版(避免
自動重算把 ingest 端/人工填過的 narrative 靜默洗掉)。
修正三處說謊的說明文字(mcp/src/tools/kbdb_map.ts、console-ui console/index.html):
「地圖由 ingest 尾端自動重算(M3)」不存在,改為誠實描述讀端即時核對機制;404 語意從
「從未 recompute」改為「查無此庫」(已知但空的庫現在會自動補成 triplet_count:0 的 200,
不會落到 404)。
測試:kbdb 新增 6 案(18/18 全綠,覆蓋自動 backfill/跟得上資料/narrative 保留/
404 vs 空庫誠實分辨/owner 隔離/無 triplet template 不報錯);mcp 新增 1 案釘住舊謊言
不再出現。kbdb 125/125、mcp 69/77(同基線 8 個 oauth 既有失敗,非本次引入)全綠;
tsc 兩包乾淨(kbdb 1 個既有 auth.test.ts 錯誤與 stash 前一致,非本次引入)。
SDD:system-dev/docs/3-specs/library-map/tasks.md M3 從「07-19 誤標 ✅ 」更正為實況;
design.md §3 加 2026-08-08 更正說明。未動 frontmatter status(仍 draft,D35 生命週期
鐵律留給總管/leo 裁)。
殘項:本次修改只在本機驗證(真 SQLite + 假 binding 單元測試),未部署 prod;未在真實
KBDB(如 yuga3bse 租戶)重新實測 kbdb_get_map 非空——需部署後才能貼實測輸出。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 00:44:55 +08:00
uncle6me-web
7dbd4f59e7
fix(portal): 檢修孔 library_count/triplet_count 恆 0 的根因+加統計自我檢查
...
真因:/portal/data/diagnostics 讀 GET /map,那是 library_map 快取 block,只能
靠 POST /map/recompute 產生;核實過整個 repo 沒有任何呼叫點會打 /map/recompute
(library-map SDD 的 ingest 自動重算 M3 從沒接上,status: draft)。⇒ /map 對任何
租戶恆回空 libraries,與實際資料量無關——2026-08-07 leo 實測抓到:3 庫、大量
triplets,診斷檔卻回 0/0。
修法:改走 GET /portal/admin/libraries 已在用、驗證過的即時查詢組合(不依賴任何
快取):listRecordsByTemplate(portal_library) + /entries/libraries(t52 蓋章即
現身)+ /records/triplet-stats(t142 即時聚合 SQL)。
附帶:加 library_scope_check 統計自我檢查(呼應 embedding.self_test 的精神)。
兩個計數都是 0 時,用完全不同的查詢路徑(不分庫/模板,只問這個租戶底下有沒有
任何 entries)交叉驗證,區分「真的是空」與「查詢方式或 owner_id 對不上」
(2026-08-01 t161 前科同型病:手動補的 record owner_id 存成 None,全量查得到、
按 owner_id 過濾的畫面永遠空)。
三個 diagnostics 測試全綠:即時查對出正確 library_count/triplet_count(且不再
外流庫名/內容,只回數字)、真空情境自我探測誠實回空、t161 同型病情境自我探測抓到
「查得到但統計回 0」的矛盾。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 00:12:54 +08:00
uncle6me-web
d779a11958
gitignore 掉 deploy-all.mjs 產的 package.json/lock
...
名字是 arcrun-deploy-shared,是本機跑 installer/scripts/deploy-all.mjs 時
npm 為了 wrangler 等依賴生出來的,不是 repo 內容。
每次本機部署都會冒出來吵未推警察 => 加 gitignore 而不是刪
(刪了下次部署又會產生)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-08 00:10:59 +08:00
uncle6me-web
c7a0b317cb
fix(kbdb): 補 kbdb/src/routes/entries.ts 缺的自癒搬遷 hook(上一commit漏了這支檔)
...
上一個 commit(046ceba)訊息宣稱改了 entries.ts 但實際只有測試檔進了 git——
entries.ts 的 migrateLegacyCredentialsForOwner 呼叫留在工作區沒進 index
(同一份工作目錄有另一個 session 併行在改這支檔案的語意搜尋空結果診斷功能,
兩邊的 import 改到同一行,第一次 commit 時漏收)。這次補上:
- import migrateLegacyCredentialsForOwner,GET /entries 對 entry_type=
credential 觸發自癒搬遷(見 046ceba 說明,本檔案是實際掛載點)
- 同時收進另一個 session 已完成且測試通過的變更(search-semantic-empty-reason
:語意搜尋回空時分辨 no_index/no_match/stale_index 三態,給人話 capability_
hint + 技術向 admin_hint;非本次任務範圍,因同檔同 import 行交織、且已驗證
119/119 全過,一併收下不拆散)
kbdb 全測試 119/119 通過(含新增的 credential-legacy-migration.test.ts 5 項
與 search-semantic-empty-reason.test.ts 4 項)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 22:53:51 +08:00
uncle6me-web
046ceba29c
fix(kbdb): credential 目錄自癒搬遷(D38 收尾)——修 youlin 20/20 全敗事故
...
根因(2026-08-07 youlin 測試實例):7ba7855 把 credential 讀寫端從舊表
credentials(0002)改走 KBDB entries(entry_type='credential'),但舊表
資料的搬遷 migration(0006)要人手動觸發部署才會跑。實查 youlin 的 D1:
credentials 表有 1 筆(yuga3bse/kbdb_internal_token),entries 對應筆數
為 0——新讀取端上線、舊資料還沒搬,20 次 workflow 全部找不到 credential。
leo 追加硬要求:credential 資料住在用戶自己的 CF 帳號,換讀取路徑=每個
既有實例都要遷移,但用戶不准做任何手動步驟——搬遷必須內建在既有更新流程
裡、天然無感。
解法(kbdb/src/actions/credential-legacy-migration.ts):把「搬」變成
「讀」的副作用而非獨立步驟。KBDB worker(D38 唯一允許碰 SQL 的牆內)在
每次查詢某租戶的 credential 目錄前,先確認舊表資料是否已搬進 entries
——沒有就搬(per-owner scoped、NOT EXISTS 冪等),有就是零成本的
sqlite_master 短路檢查。呼叫時機掛在 GET /entries?entry_type=credential
(cypher-executor 熱路徑本來就會打的端點),故只要更新 KBDB worker,
下一次任何人跑 workflow 該租戶就自動搬好,不需要用戶或安裝器多做任何事。
刻意不執行退場(DROP TABLE)——多個實例搬遷時間點不同,舊表留著才能讓
「已搬」與「還沒搬」的實例同時安全運作;退場留給之後獨立的清理步驟。
kbdb/tests/credential-legacy-migration.test.ts:反向驗證重建 2026-08-07
事故的確切前置狀態(真 SQLite + 0001/0002/0005 migration 原檔),證明補丁
加入前 entries.length 回 0(事故重現),加入後回 1(修好);另驗冪等
(連呼叫三次不重複搬)、多租戶互不干擾、舊表已清理時的終態安全。
cypher-executor/tests/credentials.test.ts:補齊 7ba7855 留下的刻意紅燈
(原 placeholder 五項清單),涵蓋租戶隔離的讀寫、真刪除(非 deprecated
標記)、零原生 SQL 原始碼掃描、密文本體不落 KBDB。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 22:51:31 +08:00
uncle6me-web
ac4fb56c91
portal 前端文案:語意搜尋降級提示改講人話+entry_type/mode 不再吐原始英文值
...
封測者 Oscar 回報「語義搜尋搜不到」,追查發現 portal 使用者實際會看到的降級提示
其實是後端 kbdb capability_hint 直接透傳(寫給工程師看的:「叫 CC」「vectorize」
「kbdb_embed:true」「redeploy」),比 UI 裡原本的 fallback 文案還難懂。
- se-banner:不再透傳後端 capability_hint,前端固定顯示「發生了什麼+現在怎麼辦」
(語意搜尋還沒開通→以下是關鍵字結果→到設定頁疑難排解匯出診斷檔給我們)
- 新增 entryTypeLabel():entry_type 原始值(wiki_card/block/execution_log…)
不再直接印給用戶看——尤其 wiki_card 原樣顯示會打臉上傳頁自己講的「AI 整理後
會以 wiki 卡形式出現」
- 新增 searchModeLabel():搜尋結果「模式 keyword/semantic」的英文值改顯示
中文(關鍵字/語意/圖譜),AI 問答來源標籤同步套用
不動 console/index.html(僅供部署擁有者/維運者使用,非客戶介面,根目錄
index.html 明文寫「不該對客戶露出」,同類字眼在此屬合理專業詞彙,故不改)。
不動 cypher-executor/src、kbdb/src(另一 agent 正在改 credential 路徑;
真正的降級文案根因在 kbdb/src/routes/entries.ts 的 capability_hint,
已另行回報總管,非本次改動範圍)。
已用 installer/scripts/build-ui-bundle.mjs 打包驗證:新文案進 bundle、
舊文案消失,entryTypeLabel/searchModeLabel 均實際生效(非死代碼)。
2026-08-07 22:38:07 +08:00
uncle6me-web
1e2ef6806a
wiki: 落帳檢修孔第一版(embed selftest + diagnostics 端點 + 匯出按鈕)
...
記錄 2026-08-07 三個 commit(9344562/83aa1f6/5388f40)的狀態、端到端實測方式、
測試結果,以及未完成項(未 push GitHub 待 D20/Oscar 需自行按「立即更新」)。
一併誠實記錄收工時發現本機既有背景機制會把 commit 鏡到 Gitea(非本次操作觸發)。
2026-08-07 18:52:30 +08:00
uncle6me-web
5388f40c03
feat(portal-ui): 設定頁「匯出診斷檔給我們看」按鈕(檢修孔前端,2026-08-07)
...
leo 直接指令的簡化版規格:一顆按鈕、按下去下載一個檔案、用戶自己把檔案傳出去——
同意天然內建在「他自己按、自己傳」這個動作裡,不需要額外授權流程或內部概念外露。
按鈕打 GET /portal/data/diagnostics,把回應存成單一 JSON 檔(不是要解壓的一包)
直接觸發瀏覽器下載,檔名帶時間戳。沿用既有 authHeaders/safeJson/guard401/friendlyErr
helper(與同頁其餘按鈕同一套錯誤處理慣例)。
既有前端輕量測試(safejson.test.mjs/os-split.test.mjs)跑過,18/18 全綠,未受影響。
2026-08-07 18:39:30 +08:00
uncle6me-web
83aa1f6bb2
feat(portal): GET /portal/data/diagnostics —— 檢修孔聚合端點
...
leo 2026-08-07 直接指令:「一顆按鈕在設定裡,按鈕下載一個檔案,把檔案發給我,你看那個
檔」。本端點是那個檔的資料來源:聚合 embed 模組健康狀態(module_enabled/cards_embedded/
cards_pending/self_test)、知識庫規模(library_count/triplet_count)、bundle_version、
instance_url。
紅線落實:
- 只轉發數字/布林/字串狀態,KBDB /map 回應裡的 narrative/top_entities(卡片內容)讀出
triplet_count 後即丟棄,測試 portal-data.test.ts 新增案專門斷言回應不含內容字樣。
- 認證沿用既有 requirePortalUser session 閘,不對外公開。
3 個新測試全綠(未登入 401/完整聚合含隱私斷言/embed 未開時誠實回 false 不假裝)。
既有 1 個失敗案(/portal HTML 殼 404)為 stash 驗證過的既有失敗,與本次改動無關。
2026-08-07 18:38:03 +08:00
uncle6me-web
9344562258
feat(kbdb): embed 自我檢查端點(檢修孔第一塊,2026-08-07 leo 直接指令)
...
GET /embed/selftest?owner_id= —— 挑一筆已標記「已嵌入」的卡片,拿它自己的內容做一次
真實語義查詢,檢查「自己是否搜得到自己」。backfillStatus 的 pending/embedded 計數
看不出 Arcrun#11 那種「嵌了但查不到」的故障模式(metadata index 事後才建、既有向量
沒被收錄),本端點是唯一能端到端驗證 index 真的可用的方法。
隱私邊界:只回 {enabled, tested, passed, note} 四個布林/字串欄位,不回卡片內容、
不回 entry id(測試 embed-selftest.test.ts 最後一案專門斷言不洩漏)。
12/12 kbdb vitest 全綠(含既有 embed-backfill 6 案未壞)。
2026-08-07 18:35:06 +08:00
uncle6me-web
7ba78552a4
D38:credential 目錄改走 KBDB API(零原生 SQL)+舊表退場;測試刻意留紅燈
...
存取層:credentials.ts / auth-dispatcher.ts / portal.ts 全改走 kbdbBase()+fetch
到 /entries(照 execution-logger.ts 既有慣例),.prepare/.exec/.batch 命中 0。
資料層:0005 seed credential template;0006 把舊表資料搬進 entries 後拆表;
0002 標退役、deploy.ts 不再套用(加 kbdb-sql-ok 留痕,純歷史對照)。
總管親驗四項(不聽 agent 自評):
1 三個檔 .prepare/.exec/.batch 命中 0;六個檔全部通過 kbdb-api-wall-guard
2 0006 的 INSERT 欄位(id/entry_type/owner_id/page_name/metadata_json/
created_at/updated_at)與 0001_base 的 entries 表逐一對得上
3 不可逆風險查官方:D1 batch 是 transaction、任一句失敗整批 rollback;
exec 出錯則「執行停止、後續不執行」=> 兩種語意下 INSERT 失敗都不會跑到
DROP TABLE,用戶 credential 目錄不會遺失
4 0006 搬在拆之前、冪等(NOT EXISTS 防重複)、豁免標記有留痕且理由正當
(拆表是牆內施工,API 不提供也不該提供拆表)
🔴 抓到一個假綠並修正:agent 中途被中斷,把 111 行的 credentials.test.ts
砍成一行「// placeholder — see edit below」,那個 edit 從來沒發生,
且 setup.ts 被刪。vitest 對這種檔案回報「Tests: no tests」,
很容易被讀成「沒失敗=通過」——正是 CP 記過的
「這條 route 曾整條消失過沒人發現」同型。
處置:還原 setup.ts/vitest.config.ts,credentials.test.ts 改成
**刻意會失敗的紅燈**並在檔頭列出要補的五項。空檔會被誤認為綠,紅燈不會。
未部署。本批要先上 stage 驗過才進 prod(leo 08-07 定)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 17:27:18 +08:00
uncle6me-web
60688c3108
fix(kv-quota): workflow 執行紀錄搬離 KV,改走 KBDB template 機制(A1/A2/A7)
...
事故:cypher-executor/src/actions/execution-logger.ts 舊版每跑完一次 workflow 就
ANALYTICS_KV.put() 一筆新 key(註解寫「避免覆蓋」)= 只增不減,封測者 Evan 處理約 690 個
檔案就把 KV 免費層 1,000 write/日打爆(實測 1,070 write),整個實例 429。
A1 少記:workflow 執行紀錄改走 KBDB template 機制(entries 表 entry_type='execution_log',
kbdb/migrations/0004_execution_log_template.sql 只 seed 一列 template 定義,零建表/改表)。
儲存精神比照既有 recipe_stat(kbdb/src/actions/recipe-stat.ts):template 只負責文件化,
實際一筆執行是 entries 表一列(1 次執行=1 次 D1 寫入,不走 entry_values 全展開)。欄位收斂:
時間/workflow/verdict/duration/錯誤訊息/(可得的)目標;成功記最少,失敗多記(訊息截斷長度
不對稱:200 vs 2000 字)。target 只認 trigger context 的 page_name/path,不整包存 input。
A2 自我降級:D1 額度仍與知識卡共用同一顆 100,000 rows/日,本模組自設 20% 軟上限(可用
EXECUTION_LOG_DAILY_WRITE_LIMIT 覆寫),超過 80% 降成只記失敗、超過 100% 完全停止記錄,
但 workflow 執行永遠照跑(cypher-executor 端 fire-and-forget 永不 throw)。
A7 讀取端:/workflows/:name/executions、/portal/data/workflows 的 last_execution、MCP
list_recent_executions 全部改打 KBDB HTTP API(GET /execution-log、/execution-log/latest),
取代原本的 ANALYTICS_KV list/get(免費層 list 也是 1,000/日)。
架構鐵律修正(本次施工中兩度被抓到走偏,過程留痕於 commit 訊息供後續參考):
- KBDB 三張表打天下(entries/templates/entry_values),永遠不加新 table——新資料類型
一律用 template + entries,不建表、不 ALTER TABLE。
- KBDB = API-as-Wall,零 SQL:cypher-executor 端一律走 KBDB 的 HTTP API(連法比照既有
recordRecipeStats/kbdbFetch 慣例),不直連任何 D1、不對 arcrun-kbdb 下任何原生 SQL。
順帶修復:kbdb/src/actions/entry-crud.ts listEntries 的 ORDER BY 補 `, rowid DESC` 二級
排序——entries.created_at 是 unixepoch() 秒級解析度,高頻寫入(execution_log 一秒內多筆)
常同秒,單靠 created_at DESC 不保證「最新一筆」正確,此為本次測試(latestExecutionLog)
發現的既有潛在缺陷,順手補上決定性排序,不改變任何既有查詢在 created_at 不同時的行為。
隔離:portal-data.ts INTERNAL_ENTRY_TYPES 加入 execution_log/execution_log_usage(與既有
value/workflow 同層級排除),避免用戶知識搜尋混進執行 log;本模組從不設 metadata_json.embed,
故永不進 Vectorize 語意搜尋索引。
不動:registry/src/actions/recordAnalytics.ts(零件市場統計,獨立 Worker、獨立 KV 命名空間、
不同資料模型,非本次事故根因所指範圍);cypher-executor/{wrangler.toml,kbdb/wrangler.toml}
未變動(repo 層級 deny 規則保護這兩個生產設定檔不被 AI 編輯)——ANALYTICS_KV binding
因此仍留在 wrangler.toml 宣告中但程式碼零讀寫點(見 PR 說明的完整 grep 佐證)。
KV 裡既有的 stats:* 舊資料不搬移(是統計不是真相源,維持原樣任其依 90 天 TTL 自然過期)。
測試:kbdb/tests/execution-log.test.ts(13 個,含零建表證明/少記/A2 降級/route)、
cypher-executor/tests/execution-logger.test.ts(payload 正確性/永不 throw)、
cypher-executor/tests/executions-route.test.ts(讀取端轉發)、portal-data.test.ts 對應區塊
改寫。kbdb 全測試 104/104 通過;cypher-executor 320 個測試中 9 個失敗為 main 既有(與本次
改動無關,改動前後 stash 對照確認)。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-07 16:13:00 +08:00
uncle6me-web
36a5630c63
portal 顯示同步器版本+下載網址改讀真相源(leo 08-06)
...
leo:「Portal 和 rag.arcrun.dev 應該顯示同步器的版本⋯⋯因為你說最新 0.18.5
連我都沒辦法確認,所以用戶到底是否最新版他自己也不知道」。
## 病
release(雲端知識庫)與 daemon(桌面同步器)是兩條版本線。
版本卡只顯示前者;下載按鈕的檔名是寫死的固定別名
(DAEMON_MAC/DAEMON_WIN)⇒ 頁面上完全看不出「同步器是哪一版」。
## 改
- 下載網址改向 /api/latest 取 daemon.downloads(真相源=bundles manifest),
取不到才退回原本的固定別名 ⇒ 按鈕永遠可用。
⚠️ 沒有違背 fe0ee82 立的「不要每出一版就改 code」——網址是取來的,
一樣不必改 code;還順便解掉固定別名的兩個老問題:
① 別名指向 @main 會吃 CDN/ref 快取拿到舊檔(08-04 撞過)
② 檔名不帶版號 ⇒ 無從顯示「這是哪一版」=leo 這次抱怨的正題
- 版本卡下方加一行「最新的同步器版本是 X(你手上那支在同步器視窗左下角)」
+連到版本說明頁。取不到就**不顯示**,不編數字。
- 渲染改成「先用退路畫、取到真相源再重畫」,renderDaemonDownload 做成可重複呼叫
(清掉上一輪插入的節點,否則會疊出兩份「不是這個系統?」)。
## 驗
· node --test os-split.test.mjs safejson.test.mjs → 8 passed, 0 failed
· index.html 三個 script 區塊逐塊 node --check → 全部語法 OK
· 未驗:線上畫面(要等 bundle 出貨後才有 daemon 欄位可讀)⇒ ◐
2026-08-06 13:12:15 +08:00
uncle6me-web
05b215c9f7
語意門檻改相對式+下架連帶刪向量(leo 兩個實測回饋)
...
## ① 「關懷型 AI 命中 20 筆、只有前 3 筆相關」⇒ 閾值太寬(leo 判斷正確)
固定門檻兩頭都不對,因為每個查詢的分數尺度不同(實測 youlin 實例):
關懷型 AI 正解 0.645-0.770,雜訊起於 0.547 ← 固定 0.5 放進 6 筆雜訊
閉環機 正解 0.552-0.638,雜訊起於 0.446 ← 固定 0.6 砍到剩 2/4(=早上的 0 命中)
人力媒合系統規劃書 正解 0.842,雜訊起於 0.550
⇒ 改**相對門檻** max(0.45, top×0.8)。五組實測:固定 0.5 混入 9 筆雜訊/
固定 0.6 有兩組正解被砍/相對式四組雜訊 0 且正解全留。
## 🔴 寫測試才發現的真問題:門檻不能在 Vectorize 那層算
Vectorize 的 indexed metadata 沒有 status ⇒ 那層不知道誰已下架。
若最高分是下架殘影(t24 復現案 0.971),拿它算門檻=0.777,
會把 0.6 的正解一起砍光 ⇒ **又變成 0 命中**。
⇒ 相對門檻移到 routes/entries.ts,接在「hydrate+濾下架」之後;
embed.ts 只留絕對下限。新增測試鎖住這個順序。
## ② leo:「理論上它的向量也要刪掉,就不會有殘影了吧?」——對,補上
單筆真刪已接 deleteByIds(b7af622),但「移除整個庫」走軟刪、向量原地不動。
⇒ deprecate-by-library 同時 deleteByIds + is_embedded 歸零(D1 與 Vectorize 不說兩套話);
backfill 兩條路徑(含 reindex)都排除 deprecated,否則下次補嵌會把殘影養回來。
不違背 t135「資料保留可還原」:D1 那列原封不動,還原後跑 backfill 重嵌即可。
回應新增 vectors_deleted,刪失敗誠實回 0 不假裝清乾淨。
驗:kbdb 91/91 綠(新增 4 項相對門檻測試,含「下架殘影不得決定門檻」)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-05 18:47:10 +08:00
uncle6me-web
0ff369f818
修語意搜尋全 0 命中:分數門檻沒跟著 bge-m3 換代(換模型漏掉的第五處)
...
leo 2026-08-05 實撞:「新上傳的『loop-engine-north-star.md』語義 0 命中,
但舊的『人力媒合系統規劃書』語義 2 命中」。
## 根因不在向量——向量是好的
直打 Vectorize 實測(youlin 實例、bge-m3、1024 維 index):
搜「閉環機」→ loop-engine-north-star.md 穩坐第 1-4 名(0.638/0.603/0.588/0.552)
D1 與 Vectorize 也對得上:659 筆 embeddable 全 is_embedded=1、index vectorCount 659。
真兇是 **min_score 門檻綁在舊模型的分數尺度上**:
舊 bge-base-en-v1.5:中文分數全擠 0.65-0.90(沒區辨力)⇒ t183 取 0.75 砍雜訊,對
新 bge-m3 :尺度整體下移(相關 0.5-0.85、雜訊 0.4 上下)⇒ 0.75 砍掉的是正解
leo 看到的「舊檔中、新檔不中」由此而來——「人力媒合系統規劃書」拿 0.842 僥倖存活,
其餘全被門檻掃掉。08-05 換 bge-m3 的「四處同步」清單(embed.ts/deploy.ts/
deploy-all.mjs/worker.js)**漏了這第五處**,因為它不在 kbdb 而在 portal 呼叫端。
## 改動
· kbdb/src/embed.ts:新增 DEFAULT_MIN_SCORE=0.5,**緊鄰 DEFAULT_EMBED_MODEL**
——門檻是模型的性質,放模型旁邊,下次換模型的人一定會看到
· cypher-executor/src/routes/portal-data.ts:拿掉硬寫的 0.75,
只在使用者顯式指定時才傳 min_score(不再各自持有一份數字=不再漂移)
· console-ui/public/portal/os-split.test.mjs:修好被今天 fe0ee82 弄壞的自測
(結尾標記寫死文案 ⇒ 改文案就炸「抽不到函式區塊」;改成錨定結構)
+斷言同步改成 Mac 給 DMG
## 0.5 怎麼來的(實測分布,不是猜的)
「閉環機」 0.638/0.603/0.588/0.552 全是目標檔 ── 斷崖 ── 0.446 才是雜訊
「火星座標 奧林帕斯山」 0.750…0.500 全對,0.475 以下才是雜訊
「人力媒合系統規劃書」 0.842 對,0.550 起是雜訊
誠實 trade-off:0.5 非每個查詢都乾淨(「AI 上課名冊」0.658 的 ax-academy 會擠進來),
但「偶有雜訊」遠優於現況「什麼都搜不到」。
## 驗
· kbdb 87/87 綠(三筆斷言隨新契約更新:預設不再是「不過濾」)
· cypher-executor 9 failed/301 passed=**與改動前逐數相同**(git stash 前後各跑一次)⇒ 既有債
· portal os-split 自測 10/10 綠
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-05 18:00:43 +08:00
uncle6me-web
fe0ee8296a
portal 下載 Mac 版改給 DMG(拖進 Applications),不再給 zip
...
leo 2026-08-05:「Mac 強調要包裝成 application + dmg 的格式,拖進去就會放到
application,**解決之前直接在下載資料夾啟動造成更新問題**」
## 病(實查證實)
manifest 已有 mac_dmg 欄,DMG 也上傳了,**但 portal 下載按鈕仍指 zip**:
DAEMON_MAC = 'ArcrunRAG-mac-unsigned.zip'
用戶端實抓該 zip → 解開就是 Arcrun.app ⇒ 很可能直接在「下載」資料夾雙擊啟動,
正是 t184(Oscar)那個「更新完又跳回舊版」的病灶。
## 修
· DAEMON_MAC → 'ArcrunRAG-mac.dmg'(**固定檔名**,否則每出一版都要改 code)
· Mac 安裝提示改成 DMG 的步驟:「開啟後把 Arcrun 拖進『應用程式』,再從啟動台開啟」
(zip 版的話術是「右鍵→打開」,步驟不同不能沿用)
## 說明:App 端的更新邏輯本來就修好了
selfupdate.go 已改成更新「正在跑的那個 .app」(runningAppBundlePath),不寫死
/Applications ⇒ 放哪都更新得了。本次補的是**入口**:讓使用者一開始就放對位置。
## ⚠️ 殘項(未送達)
bundles repo 目前**只有帶版號的 DMG**(ArcrunRAG-v0.18.4.dmg),
**沒有固定檔名 ArcrunRAG-mac.dmg**(實測 404)⇒ 這行改動要等出貨時
一併產生固定檔名副本才會生效。出貨需 D20 開閘。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 16:35:02 +08:00
uncle6me-web
b9b5d98d75
併 bge-m3 換代(#59)+補上分支漏做的另一半:Vectorize index 也換
...
leo 2026-08-05:「換 embed model 當然要合併,當然要換 vectorize,**原本的根本不能用**」
——我把已拍板的事當成待裁決,錯了。
## 為什麼非換不可(08-03 leo 拍板,5 組中文測資實證)
@cf/baai/bge-base-en-v1.5 768 排序正確 2/5 margin -0.0413 1660ms ← 舊
@cf/baai/bge-m3 1024 5/5 +0.1410 959ms ← 新
舊英文模型嵌中文:分數全擠在 0.65-0.81,區辨力接近沒有=**根本不能用**。
## 🔴 分支只做了一半,另一半我補上
feat/embed-model-m3-t59 只改 kbdb(embed.ts / types.ts / 測試),**完全沒動 deploy.ts**
⇒ 就算合併,安裝器仍會建 **768 維的舊 index**,新向量根本收不進去。
(git show f3af5d3 --stat 實查:只有 3 個檔,全在 kbdb/)
本次補上安裝器那半:
· KBDB_VECTORIZE_INDEX: arcrun-kbdb-embed → **arcrun-kbdb-embed-m3**(換名字,非只換維度)
· ensureVectorizeIndex: dimensions 768 → **1024**
· kbdb/wrangler.toml 說明與 metadata-index 指令同步改新名(照抄不會建錯 index)
· embed.ts docstring「768 維向量」→ 1024(分支漏改,會誤導)
## 為什麼要換「名字」不是只改維度
① 維度 768→1024,舊 index 收不進新向量
② 就算維度相同也不能沿用——不同模型的向量混在同一 index 比對出來是垃圾,
而 #58(Vectorize vector delete 未接)代表舊向量刪不掉
⇒ **開新名字反而順手繞開 #58**,且新舊並存可回滾。
## 查證(歷史警察 Q0-Q3,非假設)
· git log --all -S"arcrun-kbdb-embed-m3" / -S"dimensions: 1024" 皆空 ⇒ 無分支改過,非重造輪子
· **metadata index 用同一個常數**(deploy.ts:426 ensureVectorizeMetadataIndexes)
⇒ t36 的四個 metadata index(owner_id/entry_type/source/library,Arcrun#11 根因修復)
會自動建在新 index 上,**不會因改名而遺失**——這點特地查過,不是假設。
## 驗
· kbdb 測試 87/87 綠(含新增 4 項 embed-model-config)
· cli tsc --noEmit **零錯誤**
· 三處一致性機械確認:embed.ts=bge-m3/deploy.ts=dimensions 1024/index=arcrun-kbdb-embed-m3
· 踩到並記錄:註解寫 `**dimensions=1024**/metric` 會因 `*/` 提早關掉 block comment(TS1127)
## 既有實例遷移(尚未執行,需對實例操作)
建新 index → 重部署 kbdb(binding 指新 index)
→ POST /embed/backfill {"reindex":true} 到 remaining=0 → 舊 index 可刪。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 13:46:33 +08:00
uncle6me-web
3d21bf0725
移植 t21 溯源 scheme 相容:kb:// 不造死鏈(救自已刪分支)
...
## 這條與 t195 直接相關
新 ingest 鏈(rag_ingest_card/rag_ingest_direct,就是我今天在修的收卡鏈)
寫的 metadata.source 是 **kb://<path>**,但 main 的 portal 溯源只認 gitea://
⇒ 卡片上傳成功後,**溯源連結一律失效**。
原修補在 fix/portal-source-scheme-t21(07-24),一個月沒併回 main。
該分支的檔案 console-ui/src/portal-ui.ts 已被重構搬走(UI 搬 CF Pages),
⇒ 不能直接 merge,**移植邏輯到現行的 console-ui/public/portal/index.html**。
## 三種 scheme 的正解(照原分支設計)
· gitea://<path> 舊 rag_ingest v2 → {base}/<path>,行為一字不變(不回歸)
· gitea:<org/repo>@<path> km-wiki-ingest 實形 → {base}/<org/repo>/src/branch/main/<path>
· kb://<path> 新 ingest 鏈實形 → **回空字串=維持純文字,不造死鏈**
(雲端沒有對應網頁;另給 srcLocalPath() 取本地相對路徑顯示)
## 實測四情境(抽出函式跑 node)
gitea://docs/a b.md#3 → https://…/base/docs/a%20b.md ✅ 錨點捨棄+編碼
gitea:Leo/kb@notes/x.md#seg01 → https://…/base/Leo/kb/src/branch/main/notes/x.md ✅
kb://wiki/cards/policy.md → ✅ 不造死鏈
srcLocalPath(kb://…#seg02) → wiki/cards/policy.md ✅
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 13:38:19 +08:00
uncle6me-web
5783420fcf
併 feat/harness-content-refresh:install-harness 升現世代+世代閘
...
leo 2026-08-05:「Arcrun 是它的父層,這裏的問題也影響 Arcrun RAG」。
main 的 cli/harness/ 停在 06-15,分支是 07-31 的升級(676 行實質改動):
· cli/scripts/check-harness-generation.mjs(130 行)=**世代閘**——
與今天救回的 build-bundles 落後閘同族,都是防「發舊版給用戶」
· cli/scripts/build-harness-skill.mjs(64 行)
· CLAUDE.block.md/commands/arcrun.md/hooks/arcrun-guard.sh 交付內容升級
自動合併零衝突。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 13:35:56 +08:00
Leo
1eefce952b
docs: 零件/binding PR 審核規範——結構性防架構錯誤(不靠記規則):A反過度工程(D27)/B binding層級(D28)/C contract/D驗證誠實/E部署資料鐵律/F走PR+機械化CI補強
2026-08-05 13:33:56 +08:00
uncle6me-web
6c5706ba7d
補上合併漏收的修改檔(t189/t181/CIS portal 本體)
...
上一筆 5d78806 我只 add 了新增檔(favicon 三件套),四個修改檔沒收進去
⇒ 合併內容只推了一半,t189 的 tenant 比對修復其實還躺在工作區。
本次補上(實測與已刪分支 HEAD 23f2fd4 逐檔相同):
· cypher-executor/src/routes/portal.ts +81(t181 /portal/daemon/extract、t189 tenant)
· cypher-executor/src/routes/portal-data.ts +21
· console-ui/public/portal/index.html +169(CIS 視覺、版本卡)
· cypher-executor/tests/portal-admin.test.ts +45
教訓:merge --no-commit 後要 git add -A,不能只 add status 裡看到的第一類。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 13:31:57 +08:00
uncle6me-web
5d78806806
併 fix/cis-round3-portal 進 main:CIS 視覺+t181/t183/t189 收口
...
## 為什麼現在併
leo 2026-08-05:「完工、下班,都要把所有東西整理乾淨,沒推的要推、沒合併要合併」
「至少在 gitea,我不要看到還有沒處理的 PR 或分支」。
這條是 arcrun 的**現役工作分支**(領先 main 15 筆、只落後 3 筆),
含的都是已驗過的東西:
· CIS 第三輪:portal 換色票/真向量 wordmark/favicon 三件套/裁淨版 lockup
· 底色與字形對齊 landing(Paper #FDFCFB/Canvas #F2F1ED,9 處明體→無襯線)
· portal 設定頁版本卡(落後紅點+一鍵更新,t154 免辨識碼)
· t176 套到 CIS 版 portal(刪 AI 設定區塊)
· t181:POST /portal/daemon/extract——daemon 萃取走 Workers AI(免金鑰)
· t183:語意搜尋補 min_score=0.75
· t189:/portal/daemon/extract 拿掉 tenant 等值比對(geek6688 萃取永遠 401)
· 移除誤入版控的 cypher-executor/node_modules 自指 symlink
落後的 3 筆=剛併進 main 的 PR#22(純文件)⇒ 自動合併零衝突。
## 測試對帳(合併前後比對,非只看合併後)
合併後:Test Files 4 failed | 22 passed;Tests 9 failed | 301 passed
合併前(純 main 同樣跑一次):Test Files 4 failed | 22 passed
⇒ **9 fail 是既有債,非本次合併造成**(與 D36 那次 commit 記載的既有債一致)。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-05 13:29:15 +08:00
uncle6me-web
1b6b775c0e
Merge commit '5491409003ff'
2026-08-05 13:21:09 +08:00
uncle6me-web
66f1b59f7f
t176:雲端不再管地端 LLM 設定(leo 08-03 緊急)
...
leo 回報四件事:①雲端 Gemini 無法用 ②搞不清楚設定 AI 是設雲端還是地端
③地端不會萃、每個人都死掉因為都去抓 Claude ④雲端還要設置明明就有 Workers AI。
目標:「雲端裝好就能用,地端輸一個 Gemini API Key,然後就開始用。」
根因:extractor_config 的 KV key 由 portalTenant() 組出,而 portalTenant 是
**worker 層級**環境變數(portal.ts:43)⇒ **全租戶共用一把**。任一處設了 claude,
所有人的 daemon 都收到 claude;沒裝 Claude Code 的機器萃取全滅,而 portal 的
Claude 勾選框又恆 disabled(daemon 從未實作 report-capabilities ⇒ daemon_caps 永遠空)
⇒ 用戶自己解不開(awindhon 08-03 實證:雲端同步成功、金鑰有效、零張卡)。
本次(雲端側):
- POST /portal/daemon/config **不再下發** extractor/gemini_api_key/llm_model,
只回連線欄位。⚠️ route 本身與 daemon/libraries 資料夾管理完全不動(leo 明確劃界:
「雲端拉地端檔案夾部分不要刪,刪掉從雲端設置地端 LLM 選項部分」)。
- 移除 POST|GET /portal/admin/extractor(t122)——這是「雲端指定地端引擎」的入口,
且無任何伺服器端驗證,打一下就能把全租戶設成 claude。
- 移除 POST /portal/daemon/report-capabilities(t131)——daemon 端從未實作該呼叫。
- 移除 t131 那組重複註冊的 /portal/admin/ai。**它是重複 route**:後段(arcrun-rag#10)
另有同路徑一組,Hono 先到先比 ⇒ 舊的一直贏,後段修好的「金鑰真的寫進 credentials」
形同死碼。保留後段那組(只管 Gemini 金鑰、走 storeCredential),並拿掉 Claude 偏好欄。
- portal 設定頁「AI 設定」整塊移除,改成一句話說明:雲端不需設定(Workers AI 免金鑰),
地端請在同步小幫手的「AI 設定…」填 Gemini Key。順手清掉 main 上既有的 conflict 標記。
- 清掉隨之孤兒化的 helper(ExtractorConfig/AiConfig/DaemonCapabilities/
syncExtractorFromAiConfig/readAiPref 等)。
測試:**相對 merge 前 main 基準線,新增失敗 = 0**(基準線本就 9 紅:console 藏書地圖 6/
portal HTML 殼 2/POST execute 1,皆與本次無關)。t122/t131 兩組測試改寫成
**回歸守衛**(斷言那些端點/欄位確實 404、確實不存在),不是刪掉充綠。
順手修 health bundle_version 測試與實作對齊(實作刻意省略該欄,測試卻期待空字串)。
未送達:本 commit 只到 code,尚未部署上線。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-03 22:11:45 +08:00
uncle6me-web
eee3f93815
merge feat/workers-ai-chat-t152:雲端聊天改 Workers AI(免金鑰)
...
leo 08-03 緊急事件之一:「雲端還要設置明明就有 workers AI」。
本分支帶進 workers_ai_chat 種子(auth: binding,不需要任何金鑰),
讓「雲端裝好就能用」成立——用戶不必再去申請/貼 Gemini key 才能聊天。
測試差異(相對 merge 前的 main 基準線 9 紅):
- 新增 3 紅=/portal/admin/ai 的 Claude 偏好案,正是接下來要刪的功能(t176),隨刪一併處理
- 新增 1 紅=health bundle_version 回 undefined 而非 '',本分支既有小瑕疵,
與本次緊急事件無關,另記待修
- 原 9 紅為 merge 前既有(console 藏書地圖 6/portal HTML 殼 2/POST execute 1)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-03 18:20:33 +08:00
Leo
f3af5d3631
feat( #59 ): embed 模型可配置,預設換成 bge-m3——英文模型嵌中文會排錯
...
leo 2026-08-03 拍板「換 m3」。#59 本體(模型應可配置+index 版本化)。
## 為什麼換:實測,不是憑感覺
5 組中文問答測資(每組 1 問 + 2 段相關 + 3 段無關,無關的刻意放同一知識庫裡的其他主題),
margin = min(相關分數) − max(無關分數),margin ≤ 0 代表排序是錯的:
@cf/baai/bge-base-en-v1.5 768 排序正確 2/5 平均 margin -0.0413 1660ms ← 舊
@cf/google/embeddinggemma-300m 768 4/5 +0.1275 1174ms
@cf/baai/bge-m3 1024 5/5 +0.1410 959ms ← 新(最好且最快)
@cf/qwen/qwen3-embedding-0.6b 1024 4/5 +0.1381 3238ms
最刺眼的一組:問「知識庫問答為什麼要標出處?」→「會議室預約規則」0.7789
竟然高於真正相關的 0.7306。這正是 leo 2026-07-18 回報的「問 RAG 卻引用會議室規範」,
過去只被描述成「semantic 排名近乎雜訊」,其實是**排序錯誤**,而且五組錯三組。
英文 bge 系列的分數全擠在 0.65-0.81(區辨力接近沒有)——中文對它就是看不懂的 token。
## 改動
- `EMBED_MODEL` 常數 → `DEFAULT_EMBED_MODEL='@cf/baai/bge-m3'` + `embedModel(env)`,
可由 `env.EMBED_MODEL` 覆寫(#59 要的「可配置」),空字串/空白視為沒設。
- 寫入端(embedOnWrite / backfill)與查詢端(semanticSearch)共用同一個 getter
——兩邊不同步是最惡毒的 bug:不報錯、分數全垃圾、外面完全看不出來。已加測試守。
## 換代必須換 index(安裝器那半在 arcrun-rag 同名分支)
① 維度 768→1024,舊 index 收不進新向量
② 就算維度一樣也不能沿用——不同模型的向量混在同一個 index 比對出來是垃圾,
而 #58(Vectorize vector delete 未接)代表舊向量刪不掉
⇒ 開新 index 反而順手繞開 #58。
既有實例遷移:建新 index → 重部署 kbdb(binding 指新 index)
→ POST /embed/backfill {reindex:true} 重嵌到 remaining=0 → 舊 index 可刪。
驗證:kbdb 全套 87/87 綠(含新增 4 項);tsc 與基線相同(只剩既有的 auth.test.ts 那筆);
打包實跑產物 grep:kbdb bundle 只有 @cf/baai/bge-m3、舊英文模型 0 殘留。
2026-08-03 03:48:28 +00:00
Leo
47c6aaea03
feat(t152): workers_ai_chat 種子(auth: binding,免金鑰)+ 修 /init/seed 吃掉 3.12 欄位+ 修 D1 LIKE 長查詢 500
...
SDD: workflow-discovery 3.12/3.13(不是新規格;3.12 已 confirmed 並實作完成)
## 1) workers_ai_chat 種子(新)
Cloudflare Workers AI 走 env.AI binding ⇒ 用戶不必填任何 API 金鑰就能問答。
放種子表而非產品安裝器:「裝好後預設有哪些 recipe」是平台能力(rule 07 薄殼原則)。
換模型/換供應商=改這一筆 recipe,workflow 不動。
選型實測(1.4.4 實例,真實長度 RAG prompt,每個模型連跑 2 次):
llama-4-scout-17b 2373/2173 ms ✅ 答案最完整、引用正確 ← 選它
llama-3.3-70b-fp8-fast 3261/2147 ms ✅ 可用但波動較大
mistral-small-3.1-24b 3560/3631 ms
qwen2.5-coder-32b 3572/3353 ms
gpt-oss-120b 1971/2295 ms ❌ 回應形狀不同,response 取不到文字
gemma-3-12b-it ❌ 5018 帳號無權限
對照舊路徑 Gemini gemma-4-31b-it:同型提問 16.87 s,且吐整段英文思考草稿。
## 2) 修 /init/seed 靜默吃掉 3.12 欄位
3.12 給 RecipeDefinition 加了 body_template/response_map/auth/binding_name,
但 /init/seed 是**列舉欄位重建** recipe record ⇒ 不在名單上的欄位被丟掉。
最惡劣的地方是「哪裡都不會紅」:recipe 查得到、endpoint 對,只有跑起來像沒設定過。
與 08-02 syncManifest 吃掉 manifest.daemon 欄同型(教訓:東西還在不在也要進機械閘)。
加 tests/init-seed-recipe-fields.test.ts:拿掉修復會紅、補回會綠(已實測會擋)。
## 3) 修 D1 LIKE pattern 50 bytes 上限造成的 500
/entries/search?q=… 只要 q 超過 48 bytes 就回 HTTP 500,沒有錯誤訊息。
逐 byte 二分:48→200/49→500;中文 16 字→200/17 字→500。
判別實驗:q 固定 48 bytes、其他 filter 全塞滿讓 SQL 變很長 → 仍 200
⇒ 爆的是 LIKE 的 pattern('%'+q+'%' = 50),不是 statement 長度。
中文問句超過 16 字是常態,而 rag_chat 用整句問題當 q ⇒ 聊天對正常問句等於不能用。
(=InkStoneCo status.md 待辦第 1 條「KBDB keyword 長查詢會炸」的根因。)
修法:q ≤ 48 bytes 走原路(行為逐字不變),超過才拆詞/切 UTF-8 邊界片段。
kbdb 全套 83 測全綠(含新增 8 項)。
## 4) 順手
- 移除被 commit 進 repo 的 node_modules 壞 symlink(指向 leo Mac 的絕對路徑,
害任何 fresh clone 裝不起來、切分支還會把裝好的蓋掉——本次撞了兩次)。
- pending-changes.md 加 P2 提案(fan-out 並行執行)+等裁決,未動引擎。
驗證:cypher-executor 新增測試 17/17 綠;tsc 與基線逐字相同;
全套測試失敗集合與基線**逐字相同**(基線 14 個失敗,本分支 t173 既有,非本次引入)。
2026-08-03 02:56:53 +00:00
Leo
5b983c47b8
Merge branch 'main' into fix/merge-main-into-batch-t173
...
# Conflicts:
# console-ui/public/portal/index.html
# cypher-executor/src/routes/health.ts
# cypher-executor/src/routes/portal.ts
# registry/components/kbdb_upsert_block/component.contract.yaml
# registry/examples/km-wiki-ingest/workflow.yaml
2026-08-02 23:43:16 +08:00
uncle6me-web
36cdc8fba6
#10 補測試守衛+console 兩頁同族 fallback 一併拔
...
① tests/portal-admin-ai.test.ts(6 項綠)=**route 消失就會紅**的迴歸防線。
這條 route 以前不存在、前端卻一直在打它 ⇒ key 從來沒存進去(藍字=假綠),
所以最該守的就是「它還在不在」。覆蓋:未登入 401(**不是 404**=route 真的在)/
非 admin 403/GET 回 has_key 布林且回應不含任何金鑰欄位(D36)/
空 body 400 不假裝成功/只改偏好不誤報 has_key/同測試內寫→讀一致。
註:vitest-pool-workers 預設 isolatedStorage=true ⇒ 跨 it 的 KV 會還原,
驗來回一致必須在同一個 it 內完成(我第一版寫成跨 it,測試如實抓出來了)。
② console/index.html 與 console/dashboard/index.html 也有同一個寫死
`|| "https://cypher.arcrun.dev "` fallback(與 portal 同族)⇒ 一併拔掉。
靜態 config.js 保留無妨:build-ui-bundle.mjs 的 SKIP 會跳過它、改由 worker 動態產生。
驗證:cypher tsc 綠、全套 248 passed(9 既有失敗未變);
UI 產物 grep 寫死 fallback 歸 0;stage verify.sh 仍 11/3(無迴歸)。
2026-07-31 20:57:05 +08:00
uncle6me-web
0d49989c19
修 arcrun-rag#10:補 /portal/admin/ai(key 從來沒存進去的真因)+UI 已輸入態
...
真因(不是重裝洗掉,是從來沒存進去):前端唯一寫入路徑 POST /portal/admin/ai
**後端從來沒有這條 route** ⇒ 用戶填 key → 404 → 什麼都沒存,畫面卻像成功了(藍字=假綠)。
產物層鐵證:bundle tier2/ui grep 'portal/admin/ai'=1、tier2/cypher=0;兩實例實打皆 404。
反證(別改不壞的東西):走正確端點寫入 → 完整重裝 24/24 → credential 仍在、
rag_chat verdict failed→success ⇒ **重裝不洗 credential,資料層本來就是保留式的**。
① cypher 補 GET|POST /portal/admin/ai(routes/portal.ts)
- POST 內部轉呼 credentials.ts 既有 storeCredential()=**唯一寫入路徑**,不另造第二套
- GET 只回 has_key 布林,**永不回傳 key 本身**(D36)
- credential 的 api_key 欄=租戶 slug(portalTenant),與安裝器 seedCredential 寫
kbdb_internal_token 用的 ns 同值 ⇒ 同租戶分區,彼此查得到
- use_claude_for_extract 存 KV(單一布林偏好,不為它開 KBDB template)
- claude_available 目前無訊號來源(該由小幫手回報)⇒ **誠實回 false 不假綠**
- 寫入失敗回 502 帶原因——本 bug 的教訓就是「不能讓前端以為存好了」
- 兩者皆未提供 → 400,避免「看起來成功但什麼都沒做」
② 前端(console-ui/public/portal/index.html)
- 拔掉寫死 `|| "https://cypher.arcrun.dev "` fallback ⇒ 缺 config.js 就顯示紅色橫幅明顯報錯。
**寧可明顯失敗,不要靜默把用戶金鑰送去中央實例。**
⚠️ 更正我先前的錯誤診斷:config.js **有**正確注入(實查 leo 實例指向自己的 cypher),
跨租戶錯置未發生;這條是未爆彈不是現行災情。
- leo 規格:已存 → 唯讀「已輸入」+「修改」鈕(不顯示 key);按修改才變回輸入框;
未存 → 一般輸入框。舊版只改 placeholder=讀起來像臨時提示,是它像 UI bug 的原因。
- 只有真的送了新 key 才切回「已輸入」(單純改 Claude 勾選不誤報)
tsc 綠;三個 script 區塊 node --check 全過。
卷:system-dev/docs/3-specs/journeys/gemini-key-lost-on-reinstall.md
2026-07-31 19:56:47 +08:00
uncle6me-web
c735b911a0
🔴 修教材反向教壞:skill §7 自打臉+補「分支怎麼算成功」+刪 publish 死代碼
...
端到端 haiku 考 0/3、1/3,**斷點在教材不在引擎**(另一 agent 取證,別重查):
探針零 code 實測 n=10→TRUE、n=1→FALSE 兩次 success;**考生的作品其實會動**
(amount=5000→true、amount=100→false 條件求值全對),但它以為跑不通而放棄改寫 code;
考生第二次自己指認「MCP 說明聲稱不支援 ON_TRUE/ON_FALSE,與實際系統行為不符」。
① skill `write_intent_workflow` **同一份前後打架**(我 08-01 只改了 §2 沒掃全篇):
§2.1 教用 ON_TRUE,§7 第 1 條卻把 ON_TRUE 列為「不存在的邊」⇒ 教材自我否定。
改:§7 只留 ON_FAILURE(真的沒有),並明寫「ON_TRUE/ON_FALSE/ON_BRANCH 是存在的,
見 §2.1,本行舊世代已更正」。全篇 grep 過確認無其他矛盾。
② **補 §2.2「怎麼確認分支真的走對」**——這是「看到對的結果卻以為失敗」的直接解:
看 verdict,且**走 true 路時 false 路節點不出現=正確行為不是失敗**;
附 08-01 實撞案例,明講「只有一條路有輸出」不該判定壞掉。
MCP instructions 同步加這段(比 skill 更前置,AI 一連上就讀到)。
③ #23 殘留清除(leo 08-01:「已經沒有 publish 了,零件等級一律走 PR,這條路封了」):
`git rm mcp/src/tools/arcrun_publish_component.ts`+拔掉 registry.ts 的 import
(註冊呼叫本來就已註解掉=純死代碼配活 import)。刪前 grep 全 repo 呼叫方:
除本檔與 registry.ts 外,其餘命中全是 md/SDD 的歷史記載(不需動)。tsc 綠。
替代路徑=`Leo/arcrun-components` fork→PR→人審,已寫進 registry.ts 註解。
SDD: workflow-discovery 3.11|CP: arcrun-usable 步驟 5
2026-07-31 18:37:48 +08:00
uncle6me-web
eefbed98b6
合流 batch:步驟 3/4/5/6 併成一版出貨(同一顆 cypher worker,bundle 是 worker 粒度)
...
鐵律(08-01 血淚):CP 可分步驗收,但 bundle 是 worker 粒度——凡改同一顆 worker 的多步,
出貨前必先合流成一版再重生 bundle,否則 stage 只拿到一步(三條分支各自建 bundle 的坑)。
base=feat/step3-missing-guidance(最前緣,已含 step4+step6+t158-t162 prod 修)
merge=feat/step5-conditional-edges(引擎條件邊+recipe 三層+教材世代修)
2026-07-31 16:56:09 +08:00
uncle6me-web
a9a47b7c37
🔴 步驟5 補斷點:教材說「引擎不支援條件分支」+意圖語法收不到分支標籤
...
備考 haiku 真考時自查發現的兩個斷點——**若不補,考試必掛,且掛的是我自己的教材**。
形狀=步驟1 那個「世代脫節」的翻版:能力做好了,但教 AI 的地方還停在舊世代。
斷點①:三處教材主動說「沒有條件分支」,還教了正好造成腹語術的替代法
- mcp/src/mcp-handler.ts:44「**沒有** ON_TRUE/ON_FALSE——引擎目前不支援條件分支」
- registry/skills/write_intent_workflow.md:39「不要寫 ON_TRUE/ON_FALSE…
需要判斷時**寫成一個獨立節點**再接 ON_SUCCESS」← 這正是「判斷退回 code」的入口
- registry/skills/INDEX.md:44「已知的坑:引擎沒有條件分支」
⇒ 三處全部更新成現況(三顆零件都輸出 data.branch、引擎依標籤選路、
查零件回應附 branch_hint 照著接即可),並保留「不要寫 ON_FAILURE」(那個真的沒有)。
斷點②(更隱蔽,靜默失效):`graph-builder` 只認得 `對每個 X` 的參數化 label,
`ON_BRANCH(branch_active)` 帶括號會落到 toEdgeType 預設值 **PIPE**
⇒ 我在 skill 教的寫法,編圖收不到,而且**不報錯**——AI 以為分支了、實際全走同一條。
「教了語法但引擎不收」比沒做更糟,故與文件同批補上:比照 FOREACH 抽 iterator 的作法
抽 branch 標籤(半形/全形括號都收),寫進 edge.branch。
新增 tests/intent-branch-syntax.test.ts(7 項綠):守「文件教的寫法,編圖真的收得到」
——ON_TRUE/ON_FALSE 不退化成 PIPE、中文「成立時/否則」、ON_BRANCH(標籤) 抽得出 branch、
全形括號、try/catch 標籤;零變化:ON_SUCCESS 仍是 ON_SUCCESS、對每個 X 的 iterator 不受干擾。
全套 234 passed(前 227 +7),失敗數維持既有 9 筆;tsc 綠。
SDD: workflow-discovery 3.11|CP: arcrun-usable 步驟 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 16:51:19 +08:00
uncle6me-web
e688d805ea
步驟5 抽驗補證:三型分支用「真零件實跑輸出」端到端驗過(不再是推論)
...
總管 08-01 抽驗要求(正確):ON_CASE/ON_CATCH grep=0,我用 ON_BRANCH 通用承接,
但既有測試是用 Input 節點**手餵分支形狀**——那只證明「引擎依標籤選邊」,
**沒證明「真零件吐的標籤對得上」**。leo 特別點名 switch/try_catch,故補實測。
真零件實跑(wasmtime 跑 .component-builds/*.wasm,原文抄進測試當 given):
if_control active → {"data":{"branch":"true","result":true},"success":true}
if_control inactive → {"data":{"branch":"false","result":false},"success":true}
switch case1 → {"data":{"branch":"branch_active"},"success":true}
switch case3 → {"data":{"branch":"branch_pending"},"success":true}
switch 無匹配 → {"data":{"branch":"branch_default"},"success":true}
try_catch 成功 → {"data":{"branch":"try","result":{"value":42}},"success":true}
try_catch 失敗 → {"data":{"branch":"catch","error":"boom"},"success":true}
⇒ 三顆的標籤與 readBranch 讀的 data.branch **完全對得上**,非「理論上支援」。
新增 tests/branch-real-components.test.ts(8 項綠):把上列真輸出送進引擎,
驗 if 兩路/switch 多路(含**第 3 條 case** 證明第 N 路走對)+default/
try_catch ok 與 catch 兩路,每項都驗「該走的走、不該走的沒走」。
新增 tests/branch-hint-response.test.ts(7 項綠):驗逐顆查三顆的回應
自帶 branch_field/branches/edge_types/usage/example,並把 AI 實際看到的內容印出來
(總管要求「貼回應」)。另驗不分岔零件(http_request/code)無此欄=不加噪音。
全套 227 passed(前 212 +15),失敗數維持既有 9 筆未變;tsc --noEmit 綠。
SDD: workflow-discovery 3.11|CP: arcrun-usable 步驟 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 16:43:25 +08:00
uncle6me-web
c9feb15a37
步驟5 驗收與 SDD 落帳:判斷骨架重寫實測 1201→350 字元、if×8→0(降 71%)
...
tests/step5-acceptance.test.ts(3 項綠):
- 多路分流+失敗路三條各自到位、全程零 code 節點、success=true
- 布林兩路(if_control)同樣零 code
- 字元數對照:舊寫法(判斷全塞進一個 code 節點的 JS)1201 字元 if×8
→ 新寫法(分支邊+recipe response_map 宣告)350 字元 if×0
誠實標記(寫進測試檔頭與 tasks,不讓後人誤讀):線上那顆 assemble(5509 字元 if×23)
住在 arcrun-rag 實例、本 repo 無其定義 ⇒ 本次是把它的**判斷骨架**以新能力重建成等價
工作流,證明判斷不必寫在 JS 裡,**不是**直接改寫線上節點。真正改寫與 haiku 逐顆查場景
=stage 端到端(features/09)才算數,故 3.13 標 ◐ 不標 ✅ 。
tasks.md:3.11/3.12 標 [x] 附證據,3.13 標 [◐] 附待辦界線。
全套 212 passed(基線 179 +33 新),失敗數維持既有 9 筆未變;tsc --noEmit 綠。
SDD: workflow-discovery 3.11/3.12/3.13|CP: arcrun-usable 步驟 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 16:34:20 +08:00
uncle6me-web
5f5c0a89e2
步驟5 缺口②:recipe 補 payload/回應正規化/binding 三層(leo 三層模型的第③層)
...
問題:舊 recipe schema 只有 {canonical_id, endpoint, method, auth_service}(body 有但淺)
⇒ ①帶 body 的 API 只能繞過 recipe 把整包寫進 workflow code
②回應解析綁死單一供應商(rag_chat 的 finalize 2786 字元全在對付 Gemini 形狀)
③Cloudflare binding(env.AI/VECTORIZE/BROWSER/QUEUE)整類被「只認 HTTP+金鑰」的抽象排除
⇒ 換 LLM 供應商=改 workflow,而非換 recipe,違背「外部 API 只有一條一致的路」。
新增 lib/recipe-payload.ts(純函式,好測):
- renderBodyTemplate:遞迴插值,單一 {{x}} 保留原型別、混合文字拼字串、
支援 dot path、取不到保留原樣(不靜默吞掉,看得見才好 debug)。
語義刻意與 graph-executor 的 interpolateData 一致,不新造第二種插值行為。
- applyResponseMap:text_path 取值/thinking_model 剔除 thought=true 取最後一個非 thought/
answer_marker 用 lastIndexOf(自檢清單內文也會提到標記)/strip_prefixes 循環剝殼
(實撞三型「Draft: 【答】」「* 【答】」「Answer: * 【答】」,單趟剝不乾淨)。
RecipeDefinition 加四個**全選填**欄位:body_template/response_map/auth/binding_name。
- component-loader:body_template 優先於 body,兩者皆無才沿用 ctx 當 body(既有行為)
- response_map 有設才附 text 欄,未設原樣回傳 ⇒ 既有 recipe 行為完全不變
- 新增 makeBindingRecipeRunner+pickRecipeRunner:auth='binding' 走平台 binding(免金鑰、
開機即可用),其餘一律走既有 HTTP 路徑。binding 缺綁定/無 run() 時回可操作錯誤,不假綠。
這型不是為 Workers AI 開特例——一次打開 env.AI/VECTORIZE/BROWSER/QUEUE 整排。
payload 用法要「查得到」(同 branch_hint 動機,leo 08-01 的 n8n 式逐顆查):
buildPayloadHint() 讓 recipe 的查詢回應說得出「payload 怎麼填、回應怎麼取值、
認證誰負責」,wire 進 discover 混搜/legacy 逐顆/target=recipe 三條路徑。
金鑰鐵律 D36:hint 只說「走 auth recipe X,金鑰由系統注入、你不必也不該填」,不吐值。
測試:tests/recipe-payload-response.test.ts 14 項全綠(含三家形狀 Gemini/Claude/Workers AI
用不同 path 都取得出文字=換源=換 recipe 的實證;未設 response_map 原樣回傳的相容性)。
全套 209 passed(前 179 +30 新),失敗數維持既有 9 筆未變;tsc --noEmit 綠。
SDD: workflow-discovery task 3.12|CP: arcrun-usable 步驟 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 16:31:58 +08:00
uncle6me-web
323ccc8475
步驟5 缺口①:引擎通用具名分支邊(ON_TRUE/ON_FALSE/ON_BRANCH)=Arcrun#5 根治
...
問題(「全變成 code」的根):if_control 回 {result, branch} 卻沒有邊讀得懂它,
圖的邊只有 ON_SUCCESS/IF/FOREACH ⇒ 就算照規矩用零件,仍得寫 code 判斷走哪條。
leo 08-01 追問「你改了 if,有改 switch 嗎?switch 更嚴重」——確認 switch(N 路)
與 try_catch(try/catch) 同病,故一次做成通用機制,不留「為 switch 再改一次」的債。
設計:三顆流程控制零件的 output_schema 本來就都收斂到同一形狀 data.branch: string
(if_control→true/false;switch→case 名或 default_branch;try_catch→try/catch)
⇒ 引擎只需「依標籤選邊」一個機制 ON_BRANCH;ON_TRUE/ON_FALSE 是布林路的語法糖,
底層同一條路(測試已證等價)。讀不出分支=不走(誠實,不亂挑一條)。
- types/schemas/constants:新增三邊型(純新增,既有列舉不動)+ GraphEdge.branch
- graph-executor:readBranch() 依 data.branch → branch → data.result → result 四層相容
- 中文語意詞:成立時/為真時=ON_TRUE,不成立時/為假時/否則=ON_FALSE,BRANCH=ON_BRANCH
分支用法要「查得到」(leo 08-01:AI 可能像 n8n 那樣逐顆查、自己組圖):
新增 lib/branch-hints.ts,讓 if_control/switch/try_catch 的查詢回應自帶 branch_hint
(branch_field/branches/edge_types/usage/example)——只看這一顆的回應就知道怎麼接下一步,
不必回頭讀 skill。四條回應路徑全wire:catalog found/legacy 逐顆/步驟4 substitution/
target=component 名字搜尋(=n8n 式那條)。不分岔的零件不加此欄,避免噪音。
測試(先寫測試再改引擎,紅線要求):tests/conditional-edges.test.ts 16 項全綠
——if 兩路/switch 多路+default/try_catch 成功與失敗路/語法糖等價/
context 傳遞/同分支 fan-out/無匹配不走/混合邊時 PIPE 不受影響/schema 放行。
零變化保證:195 passed(前 179 +16 新),失敗數維持既有 9 筆未變(console/portal
HTML 資產未建置+executor 斷言字串漂移,皆與本次無關);tsc --noEmit 綠。
現存 workflow/example 用到新邊型=0 筆(grep 實查)⇒ 既有行為不可能被改動。
SDD: workflow-discovery task 3.11|CP: arcrun-usable 步驟 5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 16:26:26 +08:00
uncle6me-web
9f777ff43e
t161+t162 修 leo prod 實撞兩病:庫清單靜默空白/「需要更新」假警報迴圈
...
t162(假警報,實錘):daemon cloudVersionStale() 讀 cypher /health 的 bundle_version
比對 minCloudBuilt(2026-07-28),但 **/health 從來只回 {ok:true}、沒有這個欄位**
⇒ 恆讀到空字串 ⇒ 恆判 stale ⇒ 「知識庫需要更新」永遠不消失,重裝也沒用
(leo:「按下就跳到 install,但重新更新後並不會消失,這個訊息是幹嘛的?」)。
安裝器其實一直有注入 ARCRUN_BUNDLE_VERSION(worker.js:819),只是沒人吐出來。
修:/health 讀該 var 誠實回報(未注入則省略欄位=老實例,daemon 判 stale 是對的)。
新 bundle 注入值 2026-07-31+<commit7> ≥ 2026-07-28 ⇒ 重裝後警報自然消失。
t161(庫清單空白):portal 前端 guard401 → dropSession() **靜默**清 token 跳登入頁,
畫面不說任何原因 ⇒ 用戶看到的是「庫不見了」而非「請重新登入」(leo:「實際上根本
沒連上任何庫,清單空白」)。修:dropSession 帶原因寫進 #login-status——
「你的登入已過期,請重新登入(你的資料都還在,不會遺失)。」
資料側無恙(portal_library records=2 已驗),純讀側 session 過期+靜默 UX 缺陷。
驗:cypher tsc 全綠;vitest 9 failed/187 passed=基線不變。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 15:34:27 +08:00
uncle6me-web
46afea83c2
步驟1 最後一筆:install-harness 交付內容升級到現世代+世代閘
...
管道本來就是好的(install-harness 功能完整、冪等),**過時的是內容**:
harness skill(4066B)grep「意圖」「>>」= 0 命中,只講世界觀/別寫 Python
⇒ 新裝的封測者拿不到步驟 1 的核心教材(`>>` 意圖語法)。
■ 單一真相源:harness skill 改為建置期由 registry 複製
build-harness-skill.mjs=head + registry/skills/write_intent_workflow.md 正文 + tail。
選「建置期複製」的理由:npm files 只收 harness/,registry 不進套件;
symlink 在 npm pack 與 Windows 不可靠。產物 commit 進 repo(npm 裝的是產物、不跑 build)。
head/tail 是 harness 專屬(CLI 語境入口/acr 指令表/暴露同意/誠實鐵律),
install-harness 的 copyTree 跳過 .head/.tail,不鋪進使用者專案。
■ 其餘三件逐份對照現世代事實後更新(過時的直接刪,不留死代碼)
- CLAUDE.block.md:補 >> 意圖語法、not_found 兩條路、零件 vs recipe 分型、
腹語術紅線、金鑰只拿名字
- commands/arcrun.md:步驟改成「先寫意圖 → 丟去查 → 再寫 YAML」,補 acr search/validate
- hooks/arcrun-guard.sh:**正路提示改為指向 arcrun-mindset Skill +意圖語法**
(呼應「hook 沒提 skill 反而把 AI 導向 repo 文件」的教訓);
新增 code 節點腹語術提醒,settings.fragment 補 Write|Edit|MultiEdit matcher
■ 世代閘(防再度脫節)
check-harness-generation.mjs 檢查四件交付物的現世代指紋,缺指紋 exit 1,
掛進 npm run build(prepublishOnly 因此也擋)。
反向驗證:把 skill/CLAUDE.block 換回上一代 → 兩者都被擋下並逐條點名缺哪個指紋。
■ 驗收(考生 haiku/受測物=環境)
乾淨臨時目錄 acr install-harness → 四件鋪好;重跑冪等(全檔 md5 不變、
CLAUDE.md 66 行不變、hooks 條目 2 不變、arcrun 區塊仍 1 個)。
haiku 只讀該目錄的 CLAUDE.md+SKILL.md(明令禁讀 ~/.claude、禁上網;
兩份教材 md5 與大小均不同,可證非考本機那支)答十題
→ grade-step1.sh **10 / 10 通過**(判分器同時反向驗證仍會抓
ON_TRUE/ON_FAILURE/第一節點非 input)。
npm test 18/18、tsc 綠。
SDD:workflow-discovery/tasks.md 3.11
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 15:29:17 +08:00
uncle6me-web
341bcb13c8
t160 測試跟上規格:人工建庫 POST → 404(庫只從 daemon 同步來)
...
舊測試驗「POST 建庫 200+重複 409」=已刪端點的規格;vitest 回基線 9 failed/187 passed。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 14:57:22 +08:00
uncle6me-web
832f270f52
Merge branch 'feat/step6-success-rate' into feat/step3-missing-guidance
2026-07-31 14:54:25 +08:00
uncle6me-web
5c5109cd45
Merge branch 'feat/step4-node-substitution' into feat/step3-missing-guidance
...
# Conflicts:
# system-dev/docs/3-specs/workflow-discovery/tasks.md
2026-07-31 14:54:25 +08:00
uncle6me-web
e744ad1f96
t160 世代債清除(leo:「如果你會搞不清楚,就把錯的東西刪掉」)——repo 只留一個 UI 世代
...
事故鏈(07-31 深夜,leo 刷新撞到):t159 重打包 staging bundle 時,build-ui-bundle
吃了 feat/step3 分支的 console-ui/public/——該分支基底早於 main d7fab7c
「拿掉登記新庫」,public 停在舊世代 ⇒ youlin 實例 UI 被打回被淘汰的
「登記新庫」人工表單典範(07-27 mistakes 已記帳的 src/public 雙世代債,
這次由「分支副本停舊代」路徑引爆——債沒還,任何一個部署路徑都會引爆它)。
刪掉的(舊世代,git rm 實體刪除):
- console-ui/src/(console.ts/console-dashboard.ts/portal-ui.ts)=07-22 從
cypher-executor 搬出的 renderer 快照,自 07-27 起與 public/ 真身脫鉤、只會
重產舊 UI
- console-ui/scripts/build.mjs=從上述舊 renderer 重產 public 的 build 步驟
(deploy.mjs 原自動跑它=引爆器本體)
- cypher POST /portal/admin/libraries(人工建庫端點)=死端點(e28e190 起 UI
零呼叫;leo 規格「要直通 daemon,同步,沒有登記這回事」)。GET 列表/PATCH
管理/t159 daemon 自動登記照舊
新唯一源:console-ui/public/=手改演進的真身(本 commit 同步到 main e28e190
世代+註解字樣改寫達成「登記新庫」全檔 0 命中);deploy.mjs 改為直接託管
public(無 build 步)+世代閘(缺「不需要人工新增」或含「登記新庫」拒部署)。
驗:tsc 全綠;deploy.mjs node --check 過;重打 ui bundle 242KB 過世代閘,
指紋「登記新庫」=0/「不需要人工新增」=1。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 14:36:48 +08:00
uncle6me-web
cae0d7be3b
3.9 落帳+pending-changes 提案:workflow export/import 一等公民化(D35 ③,接線待 confirm)
...
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 14:15:33 +08:00
uncle6me-web
062757f1b1
t159 修 portal 庫目錄空:補上 daemon 一直在打、但從未存在的登記端點
...
診斷更正(重要):kbdb 裡 50+ 筆 entry_type=value(content=資料夾名)**不是孤兒**——
那是 91 筆 triplet records 的 library slot 正常構造(records 全部組裝完整,資料同步
一切正常,無失敗無重試)。真病灶=**POST /portal/daemon/libraries 這個 route
從來不存在**:daemon registerLibraries(arcrun-tray main.go:505,t52「用戶可以看到
我有 2 個庫」)連線精靈時打它 → 404 → 被 daemon「失敗不擋連線」設計靜默吞掉
→ portal_library 登記簿永遠 0 筆 → portal「庫目錄管理」空。
- 新 route 契約照 daemon 既有呼叫:{email, password, libraries:[{name, display_name}]}
- 帳密驗證沿用 /portal/session 同一套(isLocked/findUserRecordId/verifyPassword/
recordLoginFail;daemon 只在精靈那刻拿帳密不存)
- 冪等:listRecordsByTemplate 比 name,已登記跳過(重跑精靈不堆重複)
- 庫名走 isValidLibraryName 同閘(拒 "*" 與非法字元)
驗:tsc 全綠;youlin 實例資料層已手動補登記(探針 record PATCH 成
youlinhsieh-test1+新建 test2,portal_library count=2);route 部署驗證
隨下批 staging bundle(假帳密應回 401 而非 404)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 14:07:05 +08:00
uncle6me-web
9c9aff0046
t158 P1 素材:workflow export/import 原語(definition 端點+CLI 命令,未接線)
...
leo 07-31:「你要做的就是一個叫 export,另一個是 import……現在如果我要把我做的
工作流分享給同事,我要怎麼 export?他要如何 import?是缺了功能用 search 來湊嗎?」
- cypher GET /webhooks/named/:name/definition:吐可攜定義(graph+config+description
=record 原樣)——export 的引擎端;import 端直接 POST /webhooks/named 即送進任何實例
- cli/commands/workflow.ts:acr workflow export <name>(definition→.workflow.yaml,
flow 從 graph.edges 反推供人讀)/import <file>(graph 直 POST,零編圖零 search
零存在性驗證=V2 純複製;手寫 yaml 無 graph → 指去 acr push)
- ⚠️ 未接線:index.ts 尚未掛 workflow 命令組(P1 收尾:接線+分享場景 A export→
B import 驗收+parser 共用模組化)
安裝器側 P0(rag-installer 5a6539d)已用同形狀(打包期預編 graph+純上傳)上 prod。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 13:49:23 +08:00
uncle6me-web
d48f83ae6f
t159 步驟4 意圖節點→真實零件/recipe 替換+/cypher/search 加 target 指定搜尋對象
...
CP arcrun-usable 步驟 4(目的:AI 只要填 payload——系統把「傳到 telegram」
翻成 http_request+recipe telegram_send)+leo 07-31 追加:
「難道我不能指定要搜尋工作流或節點或 recipe 嗎?」
替換(只動 discover,t158「部署≠發現」邊界不碰):
- 兩庫 exact 落空後,在 t158 一次抓好的清單記憶體內媒合,零新增 round-trip
- 規則 A 服務詞→recipe:名字全部服務詞命中同一 recipe 且唯一才換
(google_slides_create 不被 google_sheets 誤吃)
- 規則 B 強欄位斷詞→零件:canonical/display/aliases 強命中×10+弱命中,
需至少一強命中且分數唯一最高(aes_encrypt 無強命中不換)
- 換到=status resolved+substitution{from,componentId,recipe,reason},
cypher 圖節點直接帶真實 componentId;換不到照舊 not_found+3.7 指路
target 參數(各走既有機制,不新造第二套搜尋):
- triplets+target=component|recipe=只查該庫
- query+target=名字搜尋:component→registry /components/search(=MCP
arcrun_search_components 同路);recipe→私庫 RECIPES KV(回應註明公庫走
arcrun_recipe_search);workflow→新抽 lib/workflow-search.ts,
GET /workflows/search 與 target=workflow 共用(=arcrun_search_workflows 同路)
- 防呆:compile+target 400/target=workflow 吃 query 不吃 triplets/非法 target 400
驗(本地 wrangler dev,registry 種 20 合約+init/seed 10 recipe):
- 「判斷有沒有新資料 >> ON_SUCCESS >> 傳到 telegram」→ if_control(resolved)
+telegram_send(substitution.componentId=http_request)=feature 06 驗法過
- 機械考 27/27 全綠(01 組×5+03 組×4 迴歸+06 組×8+target×8+compile 迴歸×2)
- 冷啟第一發 94ms、熱 8–13ms(t158 病史對照:舊 25.7s);compile 39ms unchecked 照舊
- tsc 全綠;vitest 9 failed/179 passed=t158 基線完全相同
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 13:49:09 +08:00
uncle6me-web
ea1c0571c1
步驟6 執行統計回寫:每顆零件跑完回寫 success_rate(task 29,design.md「執行統計設計」)
...
- registry 新增 POST /analytics/record:ANALYTICS_KV 計數器(stats:{hash_id}:{version})
為唯一真相源,衍生值(success_rate/avg_duration_ms/call_count)回填 comp: 記錄
——查詢讀取端讀哪就寫哪,不開第二真相源。KV 無 CAS,誠實標註非原子。
- cypher-executor execution-evaluator 從 stub 改真實作:執行收尾(/cypher/execute
成功與 ExecutionError 路徑+webhook 路徑)對 trace 裡每顆 Component 節點
fire-and-forget 回寫,waitUntil 包、不增加執行同步延遲(仿 recordRecipeStats 慣例)。
成敗判定=trace error 或 output.success===false(makeHttpRunner 非 2xx 不 throw)。
- registry 位置沿 search-nodes 慣例:REGISTRY_BASE_URL 覆蓋,未設走 wasmWorkerUrl。
- 新增單測 13 個全綠;本地雙 wrangler dev 端到端實測:http_request 跑 5 次
(3 成功+2 失敗)→ success_rate 1→0.6、call_count 0→5,/cypher/search 同步可見。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 13:45:05 +08:00
uncle6me-web
7e631a890a
t158 迴歸修復「部署≠發現」:複製路徑回毫秒級純編圖,誠實化只留在 discover
...
leo 07-31 定調:「這裡只是複製一些工作流的 data 過去,沒有要在這裡驗證,難怪這麼慢。
就算是我自己寫了錯的工作流,也可以跑跑看,如果錯誤就修改,
沒有說有錯誤還要一個個驗證這回事。」
定性=迴歸非新設計:部署路徑純複製是既有設計(arcrun-rag installer/src/index.js:13
「workflows.json 是既有 workflows/*.local.yaml 的搬運(打包期抽 flow/config)」+
arcrun-rag wiki「workflow 打包期預編成 workflows.json(worker 免帶 parser)」)。
5cadc60 起誠實化漏進 /cypher/search ⇒ 複製路徑也逐節點跑兩庫查詢+相似搜尋
(每 missing 節點 1+9 次 HTTP+recipe KV 掃)⇒ 冷實例 8 節點實測 25.7s、
安裝器 15s timeout 必炸(leo stage 實走 rag_takedown_direct aborted)。
改動:
- /cypher/search 加 mode:compile=純編圖零查詢(安裝器/acr push 複製路徑);
discover=誠實查詢預設(AI 問「有沒有」的既有契約,not_found+分型指路全保留)
- /cypher/execute 一律 compile(存在性由 component-loader 執行時決定=原權威)
- compile 的節點 status 標 unchecked(誠實「沒查」,不回假 found)
- discover 批次化:registry 新增 GET /components/catalog(一次回全目錄含
input_schema,補 CP2-B「沒有列表端點」缺口)+recipe 清單一次抓,
存在判定與相似度全記憶體比對;舊 registry 無 catalog 端點 → 退回逐顆(相容);
registry 整個查不通 → unknown 照舊(不誤判 not_found)
- cli push 帶 mode:compile+拔 missing 擋(push 不看 missing;要問有沒有走 validate)
驗(本地 wrangler dev 誠實環境,registry 種 20 合約):
- compile 編圖:graph_neighbors 39ms/rag_chat(11節點) 3ms/rag_ingest_card 2ms/
rag_takedown_direct(8節點) 3ms——回迴歸前毫秒級
- 安裝器 pushWorkflowTo(mode:compile)4/4 ok(44/7/7/5ms)
- 故意引用不存在零件的 workflow:部署 ok=true,trigger 執行時誠實報
「找不到零件…」+可用零件清單(部署≠發現實證)
- discover 契約:邏輯名 missing=2+not_found+suggestion(21ms);
頂層 verify.sh 01 組 5/5+03 組 4/4 全綠
- cypher+registry tsc 全綠;vitest 9 failed/179 passed=5cadc60 基線完全相同
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 13:31:33 +08:00
uncle6me-web
7e87a3336b
3.8 新增 write_recipe skill——recipe 指路終於有目的地
...
📋 SDD:workflow-discovery task 3.8(3.7 的 suggestion 指 skill write_recipe,
之前是空地——指路會指到不存在的 skill)。
- registry/skills/write_recipe.md:從真 code 反推,不是憑空教學——
schema=routes/recipes.ts RecipeDefinition(canonical_id/endpoint/method/auth_service…);
真範例=api-recipe-seeds.ts 的 telegram_send(URL path 注入)+gmail_send(service account);
auth recipe 必填欄位(required_secrets 的 help_url 必填)照 POST /auth-recipes 驗證邏輯;
常犯錯收錄實錄(sheets append PUT→POST、telegram auth recipe 漏種、金鑰只准名字 D36)
- INDEX.md 補 write_recipe 入口;「/cypher/search 假 found」坑改標已修(2026-07-31)
- write_intent_workflow.md §6 status 表改 not_found 契約+suggestion/similar_* 欄說明
安裝器 seed:registry/skills/*.md 由 sync-registry-to-kbdb.py 自動收,新檔即納入。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 11:56:30 +08:00
uncle6me-web
1794072179
3.6/3.7 查詢誠實化:兩庫都查、缺件回 not_found+分型指路 suggestion
...
📋 SDD:workflow-discovery task 3.6/3.7(leo 07-31 步驟 3 考題)
契約以頂層 arcrun-usable/verify.sh 01+03 組為準。
- 3.6 recipe 納入 /cypher/search:零件 registry 落空後查 RECIPES KV
(resolveRecipe,執行鏈同一套解析);recipe found 附 source/description/endpoint
- 3.7 缺件分型指路:status 契約定 not_found(verify grep),suggestion 欄——
名字含服務詞(google/telegram/…)=外部 API 樣貌 → 指 skill write_recipe;
含計算詞(encrypt/hash/…)=計算原語樣貌 → 指 skill add_new_wasm_component 投稿 PR;
判不出型誠實說判不出、兩條路都給。規則簡單可解釋(不接 LLM),判準在 code 註解
- 相近候選:not_found 附 similar_components/similar_recipes——全名搜不中就斷詞
(ASCII 詞+中日韓 2-gram)打 registry /components/search,
「判斷有沒有新資料」媒合到 if_control(leo:AI 不用知道零件存在)
- 修頭節點假 found:resolveNodeRole 把無入邊頭節點判 Input,searchNodes 對 Input
無條件 found ⇒ 「aes_encrypt >> … >> code」的頭被掩蓋。改為只有字面
input/trigger/…/output 名才短路(isVirtualIoName),真名字照查兩庫
- registry 查詢層補 input_schema/output_schema 透傳:KV 一直有存
(indexOnlyComponent),toComponentRecord 丟掉 ⇒ /cypher/search 給不出
「怎麼填 payload」。順手補 REGISTRY_BASE_URL 可選覆蓋(比照 KBDB_GRAPH_URL 慣例,
本地 dev/self-hosted registry 掛別處時用)
驗:cypher-executor+registry tsc 全綠;vitest 9 failed/179 passed=與 5cadc60
基線完全相同(既有債非本次造成);本地 wrangler dev(cypher 指本地 registry,
KV 用 index-only 種入 20 份 repo 合約)跑頂層 verify.sh 01+03 組 9/9 全綠,
含 telegram_send 種入後 recipe found 路徑實測。部署到實例後需對真環境重驗。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-31 11:56:15 +08:00
uncle6me-web
747dc3f843
3.7 補指引目的地+3.8 write_recipe skill(recipe 指路現為空地)
2026-07-31 11:38:26 +08:00
uncle6me-web
c56863a7e0
3.6/3.7 補設計基調:回覆重點=缺哪些;兩庫都搜;驗收=機械綠→haiku 真考
2026-07-31 11:36:01 +08:00
uncle6me-web
fc6c98cd58
workflow-discovery 補 3.6/3.7(頂層交棒):recipe 入查詢+缺件分型指路——leo 07-31 定義步驟 3 考題
2026-07-31 11:26:20 +08:00
uncle6me-web
0a426c4e16
fix(cypher): CORS origin 空值放行——CLI/curl/MCP 無 Origin 標頭時不再 500
2026-07-31 10:50:57 +08:00
Leo
b8ca98cb49
MCP 認證改用 Portal 帳密,廢掉 MCP_OWNER_SECRET(leo 指定做法)
...
leo:「claude 裡有一個直接輸入帳密連線的,為什麼不用那個?跟他輸入 portal 的帳密一樣不就好了?」
為什麼換(三個封測撞出來的實際問題):
① 沒人給得了封測者——安裝器產生後從不顯示(完成頁 grep「Owner 祕密」=0),
CF secret 又唯寫讀不回 ⇒ 用戶卡在同意頁,只能找 leo 手動 wrangler 覆寫
② 多一把要記的金鑰——違反「拿一把金鑰就很難了」
③ 全實例共用一把,無法分辨誰連上來(企業多人版必要)
風險評估(leo 判斷,總管原本誇大成「繞過帳密的旁路」已認錯):
secret 要貼進 claude.ai(本身有帳密保護)⇒ 洩漏 secret 與洩漏 portal 帳密風險相同。
改動:
- consent.ts:一個「Owner 祕密」欄位 → email + password 兩欄
- routes.ts POST /authorize:constantTimeEqual(MCP_OWNER_SECRET)
→ 走 CYPHER_EXECUTOR binding 打 /portal/login(認證下沉到唯一真相源,
同樣吃它的節流與停用檢查)
- routes.ts GET /authorize:移除「未設 MCP_OWNER_SECRET → 503」
(那是「每個封測者都死在這頁」的直接原因)
驗:tsc 零錯誤;已部署 youlin。
2026-07-31 00:44:15 +08:00
Leo
cda1c7b261
instructions 補「你配備了 Arcrun、別上網搜」+新增 skills/INDEX(LLM wiki 式導航)
...
leo 兩個洞察:
① 「整個 arcrun instruction 很像 LLM wiki…它會拿到一個 index 把所有文件說明都塞給它,
它不會就可以查,範本全部寫在裡面」
⇒ 對照 wiki 的 push/pull 分法:我原本只做了 push(instructions 開場),
漏了 pull(INDEX 導航)。補 registry/skills/INDEX.md:
什麼症狀查哪支 skill/查現成零件recipe workflow 的九支工具/四個已知的坑/腹語術紅線
② 「它不去查就不知道…如果它去上網搜因為它不知道自己有配備呢?」
⇒ 實測確認 instructions 是 **push**(本 session system prompt 內就有藏書地圖那段)
⇒ AI 不會去上網搜,但原本的 instructions 沒說「你配備了什麼」
⇒ 開場補:Arcrun 是什麼/你現在就有完整能力/不要上網搜(網路上沒有)
驗:tsc 零錯誤。⚠️ 未部署——實測總管 token 只有 account(read),無法部署任何 CF worker。
2026-07-30 22:38:37 +08:00
Leo
fac7d6c9bb
AI 一連上 MCP 就知道從哪開始(leo 追問揪出的最後一哩)
...
leo:「arcrun_get_skill 放在 MCP 裡,現在人類說『幫我用 arcrun 寫 xxx』,
Haiku 會說『arcrun 是什麼?我看看』然後發現有個 arcrun mcp 就去執行?
如果不會,要寫什麼在外面讓它一聽到就知道要用這些資源?」
實測答案:**不會**。
① 總管寫的指引沒有任何入口指向它(真實 AI 找不到)
② MCP 五個 skill 沒有「怎麼寫意圖工作流」這支
③ AI 只看到 41 個工具名 → 自己猜 → 很可能直接 push_workflow 瞎編,
或去讀 registry/examples 那 8/13 引用不存在零件的壞範例
兩件修法:
1. registry/skills/write_intent_workflow.md — 把指引變成 AI 拿得到的 skill
(範本全取自實跑 verdict=success 的四支 workflow;含「查詢現在回假 found」的已知限制警告)
2. mcp-handler.ts instructions 開場指路 — instructions 是唯一「AI 一連上就必看」的欄位
⇒ 開場就寫明五步順序(先讀 write_intent_workflow → whoami → 查零件 → list_skills → 缺件怎麼補)
+邊只有兩種、第一個節點是 input、不要因查不到就改寫 code
⚠️ 靜態常數:KBDB 掛了也必出現(守「不擋連線」鐵律)
驗:tsc 零錯誤。⏳ 待部署後由 leo 真的問 haiku「幫我用 arcrun 做 X」驗證它會不會自己讀 skill。
2026-07-30 22:29:28 +08:00
Leo
0686d39fa1
pending-changes:兩個真缺口提案(引擎條件邊/recipe payload+response+binding)
...
來源=頂層 CP arcrun-usable 逐步查證。依 leo「照 SDD 做事、照 CP 排順序」,
CP 不得自帶任務 ⇒ 這兩件必須進 SDD 才能做,先走 pending-changes 等 confirm(D35)。
缺口①引擎條件邊:if_control 回 {result,branch} 但 cypher-executor grep ON_TRUE|ON_FALSE=0
⇒ 用了零件仍得寫 code 判斷=「全變成 code」的根。Arcrun#5 於 07-04 發現至今未修。
SDD 查證:7 個字面命中全是「部署分支」等別義,條件邊本身完全沒設計過。
缺口②recipe 缺 payload/response 層:schema 只有 {canonical_id,endpoint,method,auth_service}
⇒ telegram_send 自述「body 帶 chat_id+text」但存不住 body ⇒ 只能繞過 recipe 寫進 workflow。
要補 body_template/response_map/auth:binding 三層。SDD 查證 17 命中全是別的 payload。
2026-07-30 22:06:48 +08:00
Leo
156cdcbe7b
chore: 刪掉兩個死零件與其壞範例(leo:這裏的每個不要的零件還存在啊)
...
📋 SDD:workflow-discovery(active)/對應 CP arcrun-usable 步驟 5「死代碼清除」
刪除(git rm 保留歷史):
- registry/components/km_writer + .component-builds/km_writer
- registry/components/kbdb_upsert_block + .component-builds/kbdb_upsert_block
- registry/examples/km-wiki-ingest(唯一引用 kbdb_upsert_block 的範例,Mira 時代同源產物)
為什麼刪(Arcrun 自己的 06-mindset.md §1 早已載明):
「mira 的 claude_api / km_writer 就是這樣被錯做成零件的(其實是自用服務膠水)」
+ kbdb_upsert_block 是「一個 CRUD 操作一個零件」(leo:總不能每個都建一個零件)
+ 兩者綁的 Mira 已於 2026-06-29 蒸發=死零件。
刪前實測引用數:workflows.json 0/cypher src 0/examples 僅 km-wiki-ingest。
零件數 22 → 20。
✅ 投影模型驗證成功:build-bundles.mjs 掃 .component-builds/ 目錄(readdirSync),
重跑後 manifest 自動 25 顆 → 23 顆,兩顆消失,**不需手動改 manifest**。
⇒ 證明 manifest 這層本來就是投影(leo 的設計),只有 registry KV 那層是獨立登記簿(待改)。
驗:vitest 9 failed/179 passed=與刪除前相同(既有債)。
2026-07-30 21:30:26 +08:00
Leo
5cadc60e36
feat(workflow-discovery): /cypher/search 改為真查 registry——修「查詢回假信號」
...
📋 SDD:workflow-discovery(本 commit 同時執行 D35 交接:portal-auth 26/26 完成 → closed
superseded_by workflow-discovery;workflow-discovery paused → active。單一活性已驗=1 份)
🎯 對應 task:3.x 搜尋端誠實化(CP2-B)
病灶(leo 2026-07-30 定性「腹語術」):
search-nodes.ts 無條件回 status:'found'、missingNodes 永遠 []——
型別宣告了 'missing' 但程式碼從不使用。實測「完全不存在的東西xyz」也回 found。
⇒ AI 拿到假信號 → 以為零件存在 → 部署才發現沒有 → 改寫 code
⇒ 正式 workflow 只用 2 個零件、8 個 code 節點含 if×61。
修法:
- 查 registry 判真實存在(走 HTTP,守 D28 禁新增 service binding;
URL 用既有 wasmWorkerUrl() 慣例組,不自創)
- found 時附 input_schema/success_rate/stability
⇒ AI 才填得出 payload、才看得到「測過幾次」(leo:AI 只要填 payload)
- 查不通回 'unknown' 而非 'missing'——**誠實限制**:
不能因查詢失敗就宣告零件不存在(那會讓 AI 誤判而重寫 code)
- missing 真的回傳出去(原本寫死 [])
⚠️ 實測發現 registry **沒有列表端點**(GET /components → 404,只有 /components/<id>)
⇒ 改為逐個查(節點數通常 <10、5s timeout)。補列表端點後可改抓一次=CP2-B 待辦。
驗:tsc 零錯誤;vitest 9 failed/179 passed=**與改動前 stash 對帳完全相同**(既有債非本次造成)。
⏳ 待部署到實例後跑 arcrun-usable/verify.sh 驗 01 那組轉綠。
2026-07-30 20:41:53 +08:00
Leo
e28e19069f
t142: 雲端子庫顯示同步幾張卡+幾個三元組(政府專案驗收需求)
...
leo 07-29:「要在雲端子庫顯示同步了幾個 wiki,既然這樣也同步顯示有幾個三元組,
這是為了政府專案驗收。」
kbdb 兩支統計端點:
- entries.ts: COUNT(DISTINCT page_name) AS card_count
⚠️ 必須 distinct——算 block 數會膨脹 3-5 倍,政府驗收看到假數字比沒數字更糟
- records.ts: COUNT(*) AS triplet_count(三元組本來就算全部)
portal.ts 聚合兩者掛進庫目錄;前端 index.html 顯示。
驗:卡數確為 COUNT(DISTINCT page_name)/前端內嵌 JS node --check 全通過
(07-29 白畫面事故教訓)/portal-admin 測試 34 passed(改動前 31 passed,
唯一的 1 failed 是既有債:GET /portal 回 404,改動前後相同,非本次造成)。
註:此為子 CC 完成後未 commit 的懸置工作,總管收工檢查時發現並補收。
2026-07-29 19:55:03 +08:00
Leo
cdca296044
D36:修正四個零件契約的假資訊敘述(現行沒有發 API key 的機制)
...
leo 07-29 指正:「現在沒有 partner key,改用 namespace,現在沒有發 API key 的機制」。
這些契約寫著 'KBDB partner key(ak_xxx)'/'租戶識別(ak_ 前綴)'=假資訊源——
總管就是被它騙的(先把範例改成不存在的 {{credential.kbdb_partner_key}}),
不修的話下一個 AI 會再挖同一個坑。
改:kbdb_upsert_block/auth_oauth2/auth_service_account/auth_static_key 的
api_key description,改述為「租戶識別=Arcrun namespace」+註明 examples 裡的
ak_test/ak_nonexistent 是測試假值不代表真實格式。
只動 description,不動 schema/欄位名/gherkin_tests
(api_key 欄位名保留——改名會破壞現有 workflow)。
驗:四檔 YAML 可解析、required 不變、欄位清單不變、gherkin_tests 全保留、
ak_test 等測試值原封不動。
人閘:leo 07-29 跑 scripts/component-arm.sh 解保險授權。
2026-07-29 19:38:14 +08:00
Leo
e8bd518efa
D36 第0步:範例 workflow 金鑰統一走 credential(止血——範例是用戶照抄的樣板)
...
改前四種寫法並存、沒一個是 credential,而執行端只認 {{credential.X}}
(graph-executor.ts:247→resolveCredentialRefs)⇒ 用戶照抄必踩坑:
{{api_key}} 13/{{gitea_token}} 2/{{secret.GITHUB_BOT_TOKEN}} 2/{{kbdb_api_key}} 1
改後(19 處統一):
{{credential.arcrun_namespace}} 15/{{credential.gitea_token}} 2/{{credential.github_bot_token}} 2
⚠️ 中途修正一次錯誤命名:我先改成 kbdb_partner_key(照零件契約舊敘述 ak_xxx),
leo 當場指正「現在沒有 partner key,改用 namespace,沒有發 API key 的機制」——
實際機制確為 X-Arcrun-API-Key: <namespace>(實例上活的 workflow 為證)。
不動:{{secret.LEO_TELEGRAM_CHAT_ID}} 3 處——chat_id 是聊天室 ID 不是金鑰,
無腦套規則會引進「找不到 credential」的錯誤。
驗:違規寫法歸零/12 個範例 YAML 全可解析。
殘:kbdb_upsert_block 契約仍寫『KBDB partner key(ak_xxx)』=假資訊源(我就是被它騙的),
修它被 component-guard 擋(正確),需 leo 跑 scripts/component-arm.sh。
2026-07-29 19:33:46 +08:00
uncle6me-web
159f0b07dc
🔴 🔴 fix: portal 白畫面——t131 誤刪上一個 IIFE 的收尾 })();
...
leo:「問題是 portal 是白的」。真因:t131 合併 AI 設定時刪掉舊的 chat-key/extractor 兩區,
**連同上一個 IIFE 的收尾 })(); 一起刪掉** ⇒ 整段 JS 語法錯(Unexpected end of file)
⇒ 瀏覽器整支 script 不執行=白畫面。
**總管失職**:t131 驗收只跑了 vitest(測後端)+grep 字串,**從未驗過前端 JS 語法**——
portal/index.html 是純前端檔,vitest 根本測不到它。
修:補回 })();;node --check 通過;os-split/safejson 測試綠。
2026-07-29 17:45:30 +08:00
uncle6me-web
9d38d580f2
feat(t131): AI 設定合併成一把金鑰——聊天與萃取共用,Claude 為選填加強
...
leo:「拿到一把就很難了,還要拿兩把。一律規定先輸入 gemini api key,
如果想要強化本地萃取,可以選擇 claude……前面那個,聊天和萃都一次設好,後面那把,不填就是 gemini」
+「重點是更好的模型萃取知識更能抓重點,不然他也不知道加強什麼」(文案講感覺得到的差別)
+「本地如果有裝 claude,掃到,只要一個 checkbox 就好」(daemon 偵測回報,沒偵測到就停用選項)。
- POST/GET /portal/admin/ai(一次寫 chat-key 與 extractor)+/portal/daemon/report-capabilities
- 舊 chat-key/extractor 端點保留相容;UI 兩區合併成「AI 設定」
t131 新測 7 條全綠(總體 229 passed/9 紅皆 pre-existing:HTML shell 搬遷×2、library-map 未實作×6、
executor 零件×1)。(實作=子 CC;驗證+commit=總管)
2026-07-29 15:28:10 +08:00
uncle6me-web
0860e84d22
feat(t135): 庫目錄可自主移除+標示還在不在同步
...
leo:「需要加移除按鈕。因為別人裝錯我沒辦法幫他弄,需要可以自主」
+「你應該要顯示這個庫沒有本地對應的 folder,那就不容易刪錯」
(兩態非三態——leo 二修:「分兩種沒意義」,那是內部狀態不是用戶分類)。
- DELETE /portal/admin/libraries/:id(登記簿)與 by-name/:name(auto 庫需輸入庫名確認)
- kbdb 加 deprecate-by-library(auto 庫移除=標 deprecated,資料保留可還原)
- daemon/libraries 存 active 清單 → 卡片標 🟢 同步中/灰目前沒有在同步
- 不自動刪(daemon 可能沒開機);daemon 從未回報時整列不標
vitest 24 passed(1 紅=console HTML 搬遷陳舊測試,非本案)。
(實作=子 CC;驗證+commit=總管。含 t116/t117 先前未 commit 的 graph-executor/wasi-shim 修正)
2026-07-29 14:45:44 +08:00
uncle6me-web
6d4980d3d7
fix(t130 🔴 🔴 ): PORTAL_TEMPLATE_SEEDS 補 triplet——新實例總圖不再永遠空
...
真兇(總管探針定罪):seeds 只有 portal_user/portal_library,寫三元組回 400
'template not found: triplet' ⇒ 每個新用戶(含封測者)總圖必空。
geek6688 有是舊實例早期流程建過=拿它驗會假綠(已記 mistakes)。
呼叫路徑已驗:daemon/libraries、admin/libraries、init/seed 皆會 ensurePortalTemplates(冪等)。
vitest 24/24 綠(總管親跑)。(實作=子 CC;驗證+commit=總管)
2026-07-29 14:35:36 +08:00
uncle6me-web
ccb86481ae
fix(t128+t129): 圖搜尋補 template:triplet+AI 問答出處按頁去重
...
t128 真因(總管實測定罪):t116 只補 kbdb_base,同一行 URL 還吃 {{input.template}}
⇒ /records/by-template/?owner_id=... 查不到;手動補 template 即 count=1
(企業版功能解鎖→控制→授權系統)。**同種病三犯,已記 mistakes。**
t129:一卡切 3-5 block 每段都算一筆命中 ⇒ dedupeSourcesByPage 後端去重+hit_count。
vitest 52 passed(1 紅=console HTML 搬遷陳舊測試,非本案)。
(實作=子 CC;驗證+commit=總管)
2026-07-29 14:11:52 +08:00
uncle6me-web
eb9f2db513
feat(t122 🔴 🔴 ): 萃取引擎雲端設定+隨連線下發——封測者終於萃得出東西
...
真兇(總管查證):daemon/config 寫死 extractor='claude' 且不下發金鑰 ⇒ 封測者 100% 萃取失敗
(leo:「地端沒有 AI 根本不能萃,那它就不能玩」)。
- POST/GET /portal/admin/extractor(admin 閘;GET 只回 has_key 不回明文)
- daemon/config 改讀設定:未設定→gemma 無金鑰;設定後→含 gemini_api_key
- portal 設定頁加「萃取引擎」區(Gemini 推薦+aistudio 連結,存後提示「小幫手點連上知識庫重連即可」)
測試 3 條新綠(vitest 17 passed;1 紅=console HTML 搬遷陳舊測試,非本案)。
(實作=子 CC;驗證+commit=總管)
2026-07-29 13:21:26 +08:00
uncle6me-web
429b2d965f
fix(t97+t114): 庫目錄只顯示用戶同步進來的庫、拿掉兩段式登記
...
leo 07-28 原話:「用戶沒加上的庫,不要自作主張給它加上」/「掃進來的就是要進目錄…
加入目錄這件小事還要分兩段做?…這是在攻打用戶嗎?根本是 attack」。
- portal.ts:859 auto 段濾掉 general(系統未標庫桶,非用戶的庫)
- index.html:bootstrap 不再預埋 kb 庫;移除「登記到目錄」按鈕與 auto/registered 視覺分岔
驗證(總管 grep 真相源):登記到目錄=0、kb 種子=0、general 濾在;
os-split 10/10+safejson 8/8 綠;portal-admin 1 紅=console HTML 搬遷陳舊測試
(stash 基線同紅,與本案無關)。(實作=子 CC;驗證+commit=總管)
2026-07-28 23:54:57 +08:00
uncle6me-web
f6728974ea
fix(t115 🔴 🔴 🔴 三修): kbdb 認證完全 fail-closed——沒金鑰一律 401(含讀取)
...
leo 實證的洞=「知道網址即可讀走全部知識」;一修 fail-open(沒設 secret 就不擋)、
二修仍放行讀取=洞沒補。三修(總管手改):無 token→全部 401(health 豁免),
老實例升級路徑=重跑安裝器(同時注入金鑰與新 workflow),不以繼續外洩換相容。
+結構閘測試:斷言 src/index.ts 的無 token 分支不得有 return next()——
擋「測試複本與真實作漂移」那類假綠(本輪正是它抓到二修的複本沒同步)。
kbdb vitest 60/60 全綠(總管親跑)。
2026-07-28 23:52:43 +08:00
uncle6me-web
2ff36962be
feat(t103): /health 回 bundle_version(讀 ARCRUN_BUNDLE_VERSION,無 var 回空=老實例)
...
daemon 比對用(leo:daemon 和雲端是連動的)。vitest 2/2 綠(總管親跑)。
(實作=子 CC;驗證+commit=總管)
2026-07-28 16:06:10 +08:00
uncle6me-web
e36cd2d990
fix(t95+t96): 查詢 CJK 邊界自動補空白+圖譜節點模糊命中
...
leo 07-28 實測:「AI協作」(無空白)搜不到;圖譜搜「AI 協作」0 鄰居但總圖有
「AI 協作規範書」節點(「這個搜尋詞來自 Graph View 的一部分,居然搜不到?」)。
- normalizeCjkQuery:CJK↔ASCII 邊界插空白,search q 與 graph 節點名都過
- fuzzyFindNode:精確 0 鄰居時 fallback contains 比對(取最短命中)重查
測試 +18 全綠(vitest 197 passed;9 個既有紅=console HTML 搬遷陳舊測試,與本案無關,
stash 基線對照確認)。B5 分支衝突面已查:僅 line 274 一行。
(實作=子 CC;驗證+commit=總管)
2026-07-28 15:06:07 +08:00
uncle6me-web
646e689b65
confirm(CP2-F): 二~四刀拆分過裁(leo 授權技術裁決);四題答定(手寫驗證/arcrun-api/排程於 A 線後)
2026-07-24 18:11:10 +08:00
uncle6me-web
dd78b770a9
fix(kbdb): /entries/search 服務端濾 deprecated(keyword+semantic),修下架不生效
...
daemon-beta t24(t11 斷點①②,總管 0.971 親復現):rag_takedown_direct 下架只把
metadata_json.status 標 deprecated(軟刪,append-only),但 /entries/search 兩 mode
都不濾,已下架內容照樣回傳——semantic 甚至最高分照吐。過去唯一的濾層只在
cypher-executor/portal-data.ts 客端(Arcrun#46),沒部署 rag_chat 的實例等於完全沒濾。
- entry-crud.ts:新增 json_extract($.status) NOT_DEPRECATED_PREDICATE(同 source/library
既有 json_extract 模式,issue #5.1/#18;不用 LIKE 避免 JSON 序列化格式誤判);
searchEntries 新增 includeDeprecated 參數(尾端新增,向後相容)。
新增 isDeprecatedEntry:semantic 路徑用(Vectorize metadata 沒存 status,只能 hydrate
回完整 entry 後 JS 側判斷)。
- entries.ts:/entries/search 新增 include_deprecated 開關(預設 false,濾掉;true 給
管理面查殘留)。semantic 分支補位——過濾生效時先以 topK×3(封頂 100)向 Vectorize
多撈,hydrate+濾完再截斷回 caller 要求的量,避免命中大半下架時整頁被吃光
(t11 ZZ-T10 實測案例)。
- Vectorize 向量殘留本 PR 不動(只做查詢時過濾,not 同步刪向量)——取捨見 PR 描述。
測試:新增 search-deprecated-filter.test.ts 15 案(keyword 濾/include_deprecated 開關/
semantic 濾+補位+封頂+截斷/isDeprecatedEntry 單元);同步更新 search-source-and-score.test.ts
3 案的 topK 期望值(route 補位改變送進 Vectorize 的實際 topK,回應對外契約不變)。
kbdb 全套 60/60 綠、tsc --noEmit 乾淨。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-24 16:35:17 +08:00
Leo
5491409003
docs(mcp): README 加「更新 / acr update」段
...
- acr update:self-hosted 重跑部署、只部署變動 Worker、未變動略過(--force 全部重部)。
- 說明「新裝 vs 更新」差不多同一套流程,拿新零件(如 code)/新版就跑更新。
- 標待核佔位:下載源正從 GitHub codeload 改指 Gitea(Arcrun#4),確切行為待該 PR 定案。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 08:06:28 +00:00
Leo
0617dab70a
docs(mcp): README 改為安裝+使用導向,零件投稿拆成 CONTRIBUTING-components.md
...
- README 補三種前端安裝(claude.ai connector / Claude Code / Claude Desktop),
MCP URL 以源碼為準 = <origin>/mcp(DEFAULT_MCP_URL、resourceUri)。
- 認證段講 OAuth owner secret 閘 + MCP_STATIC_TOKEN 真祕密路徑,明講明碼-namespace 已移除。
- 工具總覽全用 arcrun_* 現役名(#20 rename)+ kbdb_* 資料層。
- 修正舊 README 兩處連結:.mcp.json url 補 /mcp、inspector 改 /mcp/inspector。
- 零件開發/投稿流程搬到 mcp/CONTRIBUTING-components.md,README 末留連結。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 06:39:04 +00:00