uncle6me-web
cac874601f
chore(builds): 重編 tier2 成品——把 #108 放進執行檔(出貨路徑 A 的第 0 步)
...
原始碼修好不等於使用者拿得到:`.worker-builds/` 是安裝器與 `acr update`
實際部署的那份執行檔。本次一併重編,repo_dirty=false、repo_head=b223a698。
arcrun-cypher-executor sha256=e0026a23792f source=b223a698 ← #108
arcrun-kbdb sha256=9c6d41895d78 source=f87d0e92(未變)
arcrun-http-request sha256=9a9dcb71879a source=1e85dfb4(未變)
arcrun-code sha256=285a7406ec69 source=621cb8d9(未變)
arcrun-mcp sha256=3ebc0d441bc0 source=10d150ac(未變)
其餘四顆的 js 位元組有變是 esbuild 版本/相依重裝造成的重編,source commit 未動。
本次起這條路徑多一道閘:編成品前先跑租戶來源檢查,違規直接「建置中止」
(見同 PR 的 scripts/build-worker-artifacts.mjs)——實跑輸出貼在 PR。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-13 00:16:55 +08:00
uncle6me-web
b223a69884
fix(portal): 藏書地圖看得到自己的知識——租戶字串改從「寫入端」來,不再拿環境變數預設值(Arcrun#108)
...
leo 2026-08-12 實撞:藏書地圖回 0 個庫,同一分鐘 KBDB 裡有 1854 條三元組,
`arcrun_whoami` 顯示 admin/全部知識庫、`kbdb_search` 也查得到——只有地圖那格是空的。
病根(不是資料掉了,是讀寫兩端各拿一個來源):
寫入端 owner_id = `~/.arcrun/config.yaml` 的 `api_key`(CLI push/小幫手上傳/MCP,
leo = `bfezv28v`)
讀取端過濾 = `portalTenant(env) = env.CONSOLE_TENANT || "leo"`
——repo toml 帶的**官方 prod 值**,而 `acr` 從來不注入 CONSOLE_TENANT
⇒ 那個 `"leo"` 不是理論邊角,是每台 self-hosted 實例的實際行為,1854 條全被濾掉。
與 #105(`env.MCP_OWNER_NAMESPACE || "leo"`)同一句話,換一個檔案。
租戶字串該從哪裡來(本票的核心判斷):
**從「寫入這批知識的那一方」來,不是從一份手抄的環境變數預設值來。**
不是「掛到每個帳號上」——portal 帳號共用同一台實例的知識庫(design D-2),
帳號之間的差別是 libraries 權限不是 owner_id;複製一份到帳號上只是多一個會過期的副本。
#105 真正的教訓是:過濾用的租戶字串要有單一權威來源、解析不到要誠實失敗、且要能機械驗證。
修法:
1. 唯一產地 `cypher-executor/src/lib/tenant.ts`
- `knowledgeOwner(env)` → branded `TenantId`:`ARCRUN_NAMESPACE` → `CONSOLE_TENANT` →
丟 `TenantUnresolvedError`。**沒有字面預設值**——`|| 'leo'` 正是把「這台機器沒設定」
偽裝成「你沒有資料」的元凶。
- `accountTenant(env)` → 普通 `string`(帳號子 namespace `{tenant}::portal` 與 cypher
自己寫的設定用它)。**回 string 是刻意的**:型別上就不可能流進知識資料面。
- 資料面過濾一律經 `ownerQuery()` / `ownerField()`,只吃 `TenantId`。
2. 值的正解由 CLI 從真相源導出:`acr update` 把 config 的 `api_key` 注入成 `ARCRUN_NAMESPACE`,
但**先驗再寫**(`GET /kbdb/map?owner_id=<api_key>` 查得到庫才寫;查不到/問不到就一個字
都不動)。無條件覆蓋會把「知識本來就在 CONSOLE_TENANT 底下」的一鍵安裝實例指向空的那一格
——那是 #97/#106 那類「更新一次把人家的東西弄不見」,比原本的 bug 更糟。
未注入時回退 CONSOLE_TENANT ⇒ 對官方 prod 與未更新的實例,這次改動是惰性的。
3. 空地圖分四態(沿 #100「讀不到就說讀不到」):no_library_grant/filtered_out/
scope_mismatch/confirmed_empty。scope_mismatch 以前不存在,所以設定錯誤被畫成
「你沒有資料」。回應仍不含租戶字串(design §3.3 紅線)。
4. 同族一起修(同一道閘一次抓到):console-dashboard 4 處、console-auth 1 處
——console 首頁的規模數字與藏書地圖對 leo 也一直是空的。
留下的閘(規則存在但沒機制驗證=會再犯第三次):
· 型別閘:TenantId 只能由 tenant.ts 產出 → 拿隨手一個 string 去過濾,tsc 當場不給過。
· 出貨閘:scripts/build-worker-artifacts.mjs 編 tier2 成品前先掃,違規 → 編不出成品。
· 閘自己可測:規則是純函式(tenant-source-rules.mjs),tests/tenant-gate.test.ts
逐條驗「5 種壞例子會擋」+「11 種合法寫法零誤攔」;掃描範圍只有 src/,擋不到自己。
規範寫入 .claude/rules/02-forbidden.md 第六類、system-dev/wiki/mistakes.md #26。
沒動:庫權限過濾(一字未改,回歸測試釘住)、帳號資料落點、任何金鑰、租戶字串仍不下發前端。
驗證:
cypher vitest 441 綠 / 14 紅,14 紅與 base commit e05518a 逐字相同(既有)
tsc 5 個既有錯誤,零新增
cli node:test 60/60 綠(含本次新增 12 條);tsc 零錯誤
閘 壞例子實跑 exit 1;build 實跑「建置中止」;乾淨時實跑通過
端到端 ◐ 未驗:需部署到 leo21c,那道閘要 leo 親手解(見 PR ③)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-13 00:15:58 +08:00
uncle6me-web
e05518a2b4
chore(builds): 重編成品——把 #107 的版本標籤修法放進執行檔
...
出貨線第 1 站的 #93 新鮮度閘擋下:cypher-executor 成品記 10d150a,
而 HEAD 已是 2129356(#107 改了 routes/health.ts 與 types.ts)。
這是該閘今晚第三次擋對——沒有它,1.4.42 會送出一個「版本標籤修法只在源碼裡」的成品。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-12 22:22:57 +08:00
Leo
21293568d5
Merge PR #107 : 更新完還看得到版本號——CLI 重部署不再把版本標籤洗掉(Arcrun#106)
...
總管複驗(不聽自述,自己重跑並與 base 逐條比對):
cli main 是 0 pass / 3 fail(測試根本跑不起來)→ PR 49 pass / 0 fail
⇒ agent 那句「#97 的守衛測試一直沒在跑」是真的,又一個假綠
cypher 14 failed / 402 passed(base 14 / 400);失敗清單 diff 無輸出=零回歸
設計比我建議的對:版本標籤每趟重烙、其他 vars 才沿用。
我原本建議「一律沿用」會讓版本號永遠停在安裝當時。
殘項(agent 誠實標的,不擋併):沒在真實例上跑過、沒有真 Portal 截圖
(它的環境指向 leo21c 紅線、無 youlin 憑證、瀏覽器未授權)。總管接手補這段。
2026-08-12 14:05:57 +00:00
uncle6me-web
53b05c6d3d
fix(cli): 更新完還看得到版本號——CLI 重部署不再把版本標籤(和你的設定)洗掉
...
leo 08-12 實撞:更新完 leo21c,Portal 設定頁的「版本」變成
「無法讀取目前版本(知識庫服務可能正在啟動)」。版本號是 leo 唯一的驗收介面,
看不到就等於他無法自己確認任何一次更新有沒有生效。
根因(Arcrun#106):`bundle_version` 來自部署時注入的 plain_text var
`ARCRUN_BUNDLE_VERSION`,而**只有安裝器會注入**。wrangler deploy 是整份覆蓋,
toml 沒寫的 var 直接消失 ⇒ CLI 更新那條路每跑一次就把標籤洗掉一次。
#97 修好了「櫃子」(KV/D1/Vectorize 沿用既有),沒修「櫃子上的標籤」。
修法(兩種 var 走相反的規則,這是本次的判斷):
· 設定類 var = 使用者實例的事實 → **沿用**(讀綁定時同一份回應就帶回來,不多打 API)
——把 #97「已部署的 worker 上綁著什麼就是事實」原封不動套用到 plain_text var。
· 版本標籤 = 這份成品的屬性 → **每趟重烙,絕不沿用舊值**。
沿用舊值會得到一個永遠停在安裝當天的假標籤——比沒有標籤更糟,
因為它會讓人以為驗收過了。
版號取部署當下發行頻道公告的 release(Portal/daemon 就是拿它當「最新版」比),
另外把**真正部署的 commit** 一起烙上去(/health 多吐 `bundle_commit`)→ 漂掉查得出來。
查不到 release 就誠實退成 `YYYY-MM-DD+<commit7>`,不掰一個 semver 假裝已是最新。
順帶(都是同一條路上的東西):
· ref 先解析成 commit sha 再用 sha 下載 archive——不可變,順手解掉 branch tarball 被快取的老病
· Portal 版本行接受帶 build metadata 的 semver(`1.4.41+d61` 這種先前一律被當成「較舊版本」)
· cli 測試在 node 22 上本來一支都跑不起來(.js→.ts 解析 + parameter property),補上 resolve hook
——#97 那份「使用者的東西還在不在」的迴歸守衛也在其中,跑不起來的守衛等於沒有守衛
· types.ts 的 ARCRUN_BUNDLE_VERSION 重複宣告(TS2300)併回一處
驗證見 PR:cli 49/49 綠、cypher health 4/4 綠、Portal 版本行原始碼實跑五種情境、
對真實已部署 worker 的唯讀 dry-run。**未做**:真實實例上的 acr update 端到端
(本機唯一有憑證的帳號是 leo21c=紅線禁碰,youlin 無憑證)。
Refs: Leo/Arcrun#106 , #97 , #95
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-12 21:58:43 +08:00
uncle6me-web
f87d0e92f4
fix(migrations): 0005/0006 從來沒進過版控——被 *.sql 規則吃掉,每個用戶都收到「部署物缺」
...
leo 更新 leo21c 時撞到(他問「部分失敗?」):
✗ D1 migration: 部署物缺 kbdb/migrations/0005_credential_template.sql
✗ D1 migration: 部署物缺 kbdb/migrations/0006_drop_credentials_table.sql
(四顆 worker cypher/registry/kbdb/mcp 全部 ✓,失敗的只有這兩個檔)
根因不是誰忘了推:.gitignore:53 的 `*.sql` 是為了擋 D1 匯出備份(整庫全量=機敏),
但它連 migration 一起吃掉。0001-0004 還在,只因為它們在該規則之前就 commit 了
(gitignore 不影響已追蹤檔案)⇒ 0005/0006 從產生那天起就不在任何 clone 裡。
⇒ 這不是 leo 一台的事:更新指令從 Gitea 抓 main,那兩個檔不在那裡
⇒ **任何人裝/更新都會收到同一組失敗**,包含全新安裝。
修法照 rules/05-deploy-convention.md「WASM 來源」段已有的慣例
(`.component-builds/**/component.wasm` 就是用否定規則放行的):
!kbdb/migrations/*.sql
範圍實測(沒開太大):
kbdb/migrations/0005、0006 → 放行
backup-2026.sql / kbdb/backup-x.sql / dump.sql / cypher-executor/export.sql → 仍被擋
進版控前確認過無機敏值:grep 命中的 token/secret/api_key 全是欄位名
(api_key、secret_ref)與註解;無 >=20 位英數的疑似真值。
殘項:leo21c 實查 templates 9 個、credential 不在其中 ⇒ 0005 從未套用,
那台仍停在 D38 之前(credentials 走 0002 的獨立表)。要補套需另跑一次更新。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-12 21:10:12 +08:00
uncle6me-web
ba152bc83a
chore(builds): 重編 tier2 成品——把 #105 放進執行檔(出貨路徑 A 的第 0 步)
...
leo 選 A(把出貨線推到能出一版含 #105 的 bundle)。查證後發現最前面還有一層:
cypher 源碼最後動 10d150a(#105) / 成品最後動 a24f291(更早)
mcp 源碼最後動 10d150a(#105) / 成品最後動 8e10f1d(更早)
⇒ #105 改了 cypher 與 mcp 兩邊源碼,但沒有重編成品。
這正是 Arcrun#93 那道「源碼比執行檔新就停下來」的閘要擋的狀態。
用官方唯一編譯點 scripts/build-worker-artifacts.mjs(Arcrun#80 的機制,已存在)
重編五顆,全部 5/5:
arcrun-cypher-executor 571KB source=10d150ac
arcrun-kbdb 146KB source=10d150ac
arcrun-mcp 1152KB source=10d150ac
arcrun-http-request 78KB source=1e85dfb4(未變)
arcrun-code 150KB source=621cb8d9(未變)
交叉驗證(不只信它自記的 commit):/portal/data/ 這條 #105 才有的路徑
在 arcrun-mcp 成品裡出現 8 次。
下一步(等 leo 解閘):把修好的引擎部署到 geek6688 當出貨機
(ARCRUN_SHIP_BASE 可覆寫,預設是 leo21c——arcrun-rag#79 要搬離的正是這個),
再從那台跑出貨線,第 17 站 purge 的 wait 節點才有帶修法的引擎可跑。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-08-12 20:03:30 +08:00
Leo
89b80ff90e
Merge PR #105 : MCP 用登入者的身分查詢,不再去找服務內部金鑰
...
總管複驗(不聽自述,自己重跑,並與 base a24f291 逐條比對):
mcp tsc 乾淨;vitest 113/113 綠
cypher 14 紅與 base 逐字元相同(diff 無輸出);passed 386→400,新增 14 條全過
kbdb 5 紅與 base 相同
安全邊界 11 條全綠(跨租戶 404/越庫 404/owner_id 由 server 定死)
殘項(已記,不擋併):
· kbdb 的 owner_id 欄位改動沒有新測試守著(213 總數未變)
· 工作流面仍靠 MCP_OWNER_NAMESPACE || leo 那個巧合,本 PR 刻意沒動(拔了 arcrun_* 會全面失效)
· 端到端 ❌ 未驗:要部署到 leo21c,那道閘要 leo 親手解
2026-08-12 11:42:03 +00:00
uncle6me-web
10d150ac2b
fix(mcp): MCP 用登入者的身分查詢,不再去找一把服務內部金鑰
...
leo 2026-08-12:「人類進 Portal 輸入帳密表示你是主人,可以查到你權限所有東西;
AI 透過輸入帳密的 MCP 查詢表示是授權的 AI,可以查到主人允許查的任何東西。」
「掛上 MCP 並輸入帳密,那個動作本身就是授權」⇒ 下游不得再要求第二次認證。
病根(不是金鑰沒同步,是身分沒接住):
oauth/routes.ts 驗完 Portal 帳密只留下 `loginOk = res.ok` 一個布林值,身分當場丟棄,
namespace 改從 `MCP_OWNER_NAMESPACE || "leo"` 拿。於是查詢時手上沒有身分可帶,
只好用 KBDB_INTERNAL_TOKEN 直打 KBDB——那條路繞過 portal 所有庫過濾,
而且不管誰登入都看到同一格、看到全部。CLI 也從不注入 MCP_OWNER_NAMESPACE,
所以那個 "leo" 預設值是每台實例的實際行為,不是理論上的邊角。
修法(走既有那條路,不發明新的):
1. 接住身分:/authorize 解析 /portal/login 回應,把 portal session token +
display_name/role/libraries 存進 authorization code → access token。
/portal/login 補回 session_expires_in,access_token TTL 夾成
min(自己的 TTL, portal session TTL)——不讓「MCP 還連著、底下 session 早死」。
cypher 回 200 但沒給 session_token(舊版)→ 不發碼,不簽一張沒有身分的 token。
2. 攜帶身分:kbdb_* 全部改走 cypher `/portal/data/*`,Authorization 帶登入者的
session。庫過濾/租戶注入/停用即時生效全在 server 側,與人類走 portal 網頁同一道閘。
kbdb_graph_neighbors 因此不再需要 kbdb_base(server 自己知道查哪個庫)。
藏書地圖(含連線時注入 instructions 的那份)同樣只回有權限的庫,快取改 per-session
分格——地圖本身就是情報,不能讓先連上的人把視野留給下一個。
3. fail-closed:舊 token 沒有身分 → 誠實要求重新連線,不偷偷退回服務金鑰那條老路。
服務級憑據(static token / partner key)維持既有 KBDB 直連,arcrun_* 零回歸。
新增 cypher portal 資料面端點(能力長在 API,MCP 只暴露;rule 07):
GET /portal/data/map、/portal/data/map/:library
GET /portal/data/templates、POST /portal/data/templates
GET /portal/data/records/by-template/:t、GET /portal/data/records/:id
POST /portal/data/records
全部:呼叫端自帶 owner_id 一律不生效;越權與不存在同回 404;寫入 owner_id 由 server 定死。
KBDB base:`GET /records/:id` 與 by-template 補回 owner_id 欄位——原本不回,
呼叫端無從判斷「這筆是不是我的」,按 id 直讀等於沒有租戶邊界。
沒動:KBDB fail-closed 閘、任何金鑰、租戶字串仍不下發給呼叫端。
驗證:
mcp tsc 綠;vitest 113/113 綠(改前 48 綠 29 紅)
cypher vitest 400 綠 / 14 紅,14 紅與 base commit a24f291 逐條相同(既有)
kbdb vitest 208 綠 / 5 紅,5 紅同為既有(migrations/*.sql 被 gitignore)
端到端 ◐ 未驗:需部署到 leo21c,那道閘要 leo 親手解(見 PR)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com >
2026-08-12 19:33:12 +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
ba92d10a3f
fix(t88): 拿掉庫管理頁「圖譜來源」概念——任何庫都能進總圖
...
leo 裁定(2026-07-28):「任何的庫都要進到圖譜模式」「給他選擇就是客服問題」
「不要給他選,掃到就能進總圖,也不用停用按鈕」。
移除:標為/取消圖譜來源鈕、庫停用/啟用鈕與 dialog、graph_source tag 與過濾、
說明文字「標了圖譜來源的庫決定誰能用圖譜模式」;後端 API 不動;
用戶管理的「停用」(set-status)未動。diff +6/-33。
按鈕來歷(leo 問):5a16484 第一刀拆分引入(當時 B5 不存在,粗閘是唯一保護);
t52(139d4c5 ) 補 auto 庫說明。拆的是過期鷹架非錯誤設計。
(實作=子 CC;驗證+commit=總管)
2026-07-28 12:41:00 +08:00
uncle6me-web
a909072dc1
feat(t87): portal 兩處顯示「去後綴的乾淨網址」+一鍵複製——連線不再要人抄網址列
...
leo 07-28 拍板:「一律用網址,把後綴拉掉,以免他貼了說我的網址錯了」。
設定頁「同步小幫手」卡+管理頁「庫目錄管理」各一行:location.origin(無 /portal/#/ 後綴)
+複製鈕(成功短暫顯示「已複製」,失敗 fallback 提示手動選取)。共用同一 helper。
os-split 10/10、safejson 8/8 仍綠(總管親跑)。(實作=子 CC;審查+commit=總管)
2026-07-28 12:04:04 +08:00
uncle6me-web
11e772496f
fix(t75 ①): portal 不再把 JSON 解析錯誤噴給使用者+404 說人話
...
leo 同事實測:存 Gemini 金鑰時畫面出現
「Unexpected non-whitespace character after JSON at position 4」。
根因兩層:
① 前端 15 處無條件 r.json(),但伺服器不一定回 JSON——404 頁/CF 錯誤頁都是 HTML。
JSON.parse 一爆,錯誤沿 .catch 走到 friendlyErr,而 friendlyErr 最後一行是
=把任何例外訊息原樣顯示 ⇒ 技術英文直接噴到畫面。
② 真正的原因是 /portal/admin/chat-key 回 404(實例的 cypher 是舊版沒這端點),
但使用者完全看不出來,只看到一句看不懂的英文。
修:
- 新增 safeJson(r):用 r.text() 再 try/catch parse,解析不了回 {} 不拋錯;15 處改用它
- friendlyErr 收斂:JSON 類錯誤→「伺服器回應異常,請稍後再試」;
純英文技術訊息→「操作失敗」;我們自己寫的中文訊息才原樣顯示
- 兩處金鑰儲存加 404 專屬提示:「你的知識庫版本還沒有這個功能,請先更新知識庫」
——講清楚為什麼與怎麼辦,否則他只看到「儲存失敗」會反覆重試同一件事
- 順手:安裝卡片那處原本 x.d.error 在 x.d 為 undefined 時會再爆一次,補 x.d && 防護
測試 safejson.test.mjs 8/8:404 HTML 不拋錯/空回應/正常 JSON 仍解析得出/
JSON 錯誤不外洩原文且說人話/網路錯誤訊息保留/中文訊息原樣/英文技術訊息收斂。
⚠️ 這只解「不噴技術訊息」;金鑰要真的存得進去仍需實例更新 cypher(②層待辦)。
2026-07-28 01:02:12 +08:00
uncle6me-web
53c6334fd9
fix(portal/t72): 下載頁 OS 分流——Windows 客戶不再拿到 Mac 的 .app
...
leo 07-27:「客戶是用 windows 的」。此前四處寫死「下載 Mac 版」,
Windows 用戶按下去拿到 .app=按了連到錯的東西(leo 判準:那不算友善)。
改法(施工圖 rag-wave1/windows-build-and-os-split.md §3):
- daemonPick() 依 UA 判 OS,四處共用;判不出來=兩個都給,不替用戶猜
- 判對了也附「不是這個系統?」另一版連結(UA 會判錯,用戶要有路走)
- 擋關話術跟著 OS 走:Mac=右鍵打開/Windows=更多資訊→仍要執行
- daemonBase 新 key,保留 daemonDownload 舊 key 相容(由檔名推目錄)
- 一律走 raw:Mac zip 21MB > jsDelivr 20MB 上限(實測回 File size exceeded)
測試 os-split.test.mjs 10/10:
⚠️ 測試抓到真 bug——iPhone 的 UA 含 'Mac OS X' 會被判成 Mac,
讓手機用戶下載裝不起來的桌面 app。已加 isMobile 排除,手機落到「兩個都給」。
未驗:真 Windows 機器的實際下載與安裝行為(需真機)。
2026-07-27 19:28:43 +08:00
Leo
d7fab7c6aa
fix(portal): 拿掉登記新庫/設定頁補常駐入口(下載小幫手+AI 金鑰)
...
leo 07-27 走完安裝後三點回饋:
1) 「登記新庫」是設計錯誤 —— leo:「應該是同步小幫手抓到的庫就顯示在上面,
沒有人工登記的選項。」人工登記只會製造對不上的空庫。
移除表單+對應 JS;說明改為「裝好同步小幫手並選好資料夾後,每個資料夾會自動
成為一個庫出現在下面,不需要人工新增。下面還是空的,代表小幫手還沒裝好或還沒選資料夾。」
2) AI 金鑰與下載連結只存在一次性的「還差 N 步」卡片,按了「稍後再說」或裝完就
再也找不到 —— 換金鑰/換電腦重新下載都沒入口。
設定頁新增兩個常駐面板:「同步小幫手」(下載)與「AI 問答金鑰」(可隨時更換),
共用既有 API POST /portal/admin/chat-key。
3) 修 window.ARCRUN_CFG → ARCRUN_CONFIG(與 721 行既有用法一致,原為筆誤)
驗證:ad-nl-create 殘留 0 / st-daemon-dl 2 / st-key-save 2 / ARCRUN_CFG 0
抽出頁面 3 個 script 區塊 node --check 語法通過
2026-07-27 16:26:52 +08:00
uncle6me-web
139d4c5ed1
feat(t52): 資料夾=庫端到端——kbdb 加 /entries/libraries(資料面 distinct 庫);portal 庫目錄合併「登記簿+蓋章自動出現」(auto);auto 庫改安全渲染(無 record_id 不放死按鈕,改給『登記到目錄』)+daemon/libraries 自動登記端點。leo 07-26:地端 2 個資料夾雲端就要 2 個庫
2026-07-26 01:49:43 +08:00
uncle6me-web
e7fe83a872
feat(t54): 小幫手憑帳密自取設定——新端點 POST /portal/daemon/config(帳密驗證同 login,回連線設定不含知識內容);portal 清單移除 config.json 下載(3 步→2 步)。leo 07-25:「最好的就是把它的帳密直接輸入」
2026-07-26 00:16:21 +08:00
uncle6me-web
8d19d0b2d7
fix(portal/t53): daemon 下載連結補實——zip 上鏡像(raw 路徑;jsDelivr 20MB 上限擋 21MB 檔)+無下載點時誠實降級不放死連結(交付警察抓到 404 死連結)
2026-07-25 23:44:44 +08:00
uncle6me-web
a8d246ebe9
feat(portal/t53): 進站完成安裝清單(leo 07-25:金鑰與 daemon 要在站內做,不然安裝沒完成)——常駐三項清單(下載小幫手/下載 config.json 站內生成/貼 Gemini 金鑰即時啟用)+新端點 POST /portal/admin/chat-key(改寫 tenant rag_chat 的 x-goog-api-key,admin 閘、金鑰不落 log)+session 回 email 供 config 生成
2026-07-25 23:26:44 +08:00
uncle6me-web
11ffd42899
fix(portal/t49): 首登頁補逃生口——『已經有帳號?改用登入』+setup 409 自動切登入帶提示(leo 實撞死路)
2026-07-25 21:12:31 +08:00
uncle6me-web
24f989d818
merge t49: portal 首登建帳+歡迎引導(leo 07-25 令當晚交付;已先行部署 leo 實例驗證)
2026-07-25 20:35:33 +08:00
uncle6me-web
9bbd25fdfc
feat(portal/t49): 首登建帳一顆按鈕——auth-status 偵測未初始化→v-firstsetup(console/setup→portal/admin/bootstrap→自動登記預設庫 kb→portal/login 四發連鎖)+進站一次性歡迎卡(下載小幫手/金鑰 → installer /setup)。leo 07-25:『加入的體驗要搞定』——用戶打開專屬網址第一眼就是建帳號,不再回安裝頁等
2026-07-25 20:35:33 +08:00
uncle6me-web
76b89be6d7
merge t36: console 語意搜尋改狀態列(假開關+CLI 指示移除,click handler 一併拆——leo 07-25 口頭核准 merge)
2026-07-25 20:29:40 +08:00
Claude
beb0653e15
fix(console/t36): 語意搜尋改狀態列——移除按不動的假開關與 CLI 指示
...
leo 2026-07-25 定案:語意搜尋預設開啟、不做開關(費用實算後屬雜訊——1 萬張卡規模
下 Vectorize 約 $0.18/月,佔 CF 帳單 3~4%;關掉省幾毛錢卻換來很爛的搜尋體驗)。
設定頁那顆「語意搜尋(vectorize)」開關其實不能按(title 自承「不能遠端改,只如實
顯示狀態」),旁邊還教用戶去部署端改 config.yaml 跑 acr update——對一鍵安裝進來的
用戶那是天書(與 t35 同一種白癡化違規),而且安裝器現在裝機時就把語意索引開好了,
那段指示本身已不成立。
改成單純狀態列:啟用時只說「已啟用,搜尋頁切語意就能用」不給任何操作指示;未啟用
才給一句人話與下一步(重跑安裝流程會補上,已建資料不重來)。
⚠️ 連帶必修:一併移除綁在該開關上的 click handler——留著會讓 $('st-vec-switch')
回 null、addEventListener 當場拋錯,把後面所有綁定(含登出)一起打斷。
驗:三個 script 區塊語法檢查通過、全檔已無 st-vec-switch/st-vec-state 殘留參照。
2026-07-25 08:51:54 +00: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
uncle6me-web
ab8e07201f
proposal(CP2-F): cypher 二~四刀拆分提案——bundle 528KB 實測解剖+引擎留原地方案(待 leo confirm)
...
偵察實測(wrangler dry-run+sourcemap byte 歸因,非推測):
- 現碼 11,050 行/bundle 528.1KB——頂層 CP2-F 記載(15,446 行/748KB)是第一刀前舊數,提案 §0 更正
- zod 佔 130.6KB(24.7%),只服務兩條入口驗證鏈=最大單一減重點
- 引擎真身僅 ~180KB,其餘 ~350KB 是管理/前端 API 面
方案:引擎留 cypher-executor 原地(webhook 觸發 URL 外部焊死、零改動),
新開 arcrun-api 收管理面;三刀漸進、每刀獨立回退;13 顆 SVC binding 不動。
依 D35 只寫 proposal 停下,不動 code、不部署。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-24 15:37:51 +08:00
uncle6me-web
ad367e450d
console-ui: 修好壞了一個月的 build + 具名部署目標(個人版/企業版)
...
🔴 根因:5a16484 把 UI 搬 CF Pages 時「移出 → console-ui/」實際上只搬了
build 產物(HTML),三支 renderer 原始檔被刪且沒搬 →
`npm run build` 從那天起 ENOENT 死掉,線上 HTML 是刪檔前烤好的,
一個月來無法重建(CONSOLE_PROFILE 改了也不會生效,因為 build 跑不起來)。
修法:
- 從 git 撈回 console.ts(1623)/portal-ui.ts(1390)/console-dashboard.ts(822)
放進 console-ui/src/——UI 原始碼跟著 UI 專案走,才是那一刀的原意
- build.mjs 加 resolveSource():本地 src/ 優先,找不到才回退 cypher-executor
新增具名部署目標(deploy.targets.json + scripts/deploy.mjs):
一個目標=帳號+profile+apiBase 綁在一起,解決三次帶漏參數:
- demo 站漏 CONSOLE_PROFILE=rag → 顯示個人版 7 頁駕駛艙(leo「進去是 Mira 介面」的真因)
- 兩站漏 ARCRUN_API_BASE → apiBase 空 → 前端打自己 405 → 登不進去
- 兩帳號都有同名 arcrun-console-ui 專案且 wrangler OAuth 登入在 uncle6
→ 不指定帳號 deploy 會部到 demo 站(差點蓋掉,改用 API token 鎖帳號)
npm run deploy:personal → leo21c, profile=full(7頁), apiBase 指 leo21c worker
npm run deploy:enterprise → uncle6, profile=rag(4頁落地搜尋), apiBase 指 cypher.arcrun.dev
實測(用戶真的會走的路):
- mira.uncle6.me/console/ 200,VIEWS 7 頁,apiBase 對,CORS ACAO 通
- rag-demo.arcrun.dev 4 頁落地搜尋;登入 OK、搜「藍鯨導航儀」5 筆(未受部署影響)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-22 19:09:29 +08:00
Leo
5a164843ef
refactor(cypher): 第一刀拆分——UI 搬 CF Pages,ingest 從必爆變穩定
...
根因(leo 2026-07-21 三個判斷全被數字證實):
- 「cypher 展開上萬行,當時我就懷疑這樣跑得動嗎」→ 15,446 行、bundle 748KB
- 「不相信 CF 連讀文字檔都會撞牆」→ 不是 CF 的問題,是 cypher 太肥
- 「它違反了樂高化的原則」→ 零件 4KB,調度它們的 cypher 是巨石
定位錯誤(比效能更根本):console.ts:1 自陳「Mira Console」,而 wiki 明載
「Mira 是 Arcrun 的使用者,不是開發者」→ 使用者的前端寫進了框架的執行引擎。
CLI/MCP 都已拆成獨立薄殼,唯獨 UI 沒有。責任誠實記:console.ts 標
「2026-07-04 總管派工」,是總管當初選了「就近寫在 cypher」的方便路。
本刀:
- console.ts(1623行) + portal-ui.ts(1390行) 移出 → console-ui/ CF Pages 專案
(單檔 HTML + 原生 JS,零 build step,保持原特性)
- index.ts 移除兩個路由掛載、修 implicit any
- console-dashboard.ts 只留 API(UI 部分移出)
實測驗收(leo 指定判準:不看 /health,看真實任務):
| 測試 | 拆分前 | 拆分後 |
|---|---|---|
| 連灌 10 張新卡(無間隔) | 從未成功 | 10 張全 create、73 條三元組 |
| 同卡連跑 6 次 | 前 2 過、後 4 全 1102 | 6 次全過 |
| Bundle | 747.9 KB | 528.0 KB(-29%) |
Pages 已上線:arcrun-console-ui.pages.dev(console/portal 皆 200)
cypher API 正常:/health、/console/dashboard-data 皆 200
未做(第二刀):console-dashboard/portal/portal-data 尚未拆,cypher 仍 528KB。
但 ingest 已穩定,急迫性下降。
註:部署撞到三個既有 self-hosted 陷阱(KV/D1 id 是官方帳號的、arcrun.dev route
leo21c 無該 zone),用 wrangler.leo21c.toml 繞過,未改原始設定檔。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 18:55:31 +08:00
Leo
1b687fedb0
fix(mcp): 解掉三個把人推去寫零件的誤導入口(leo 2026-07-21 拍板)
...
leo:「刪掉,技術者才會寫 component,在 Arcrun repo 寫一條如何 contribute
指向另一個 repo 就好。」
實測病灶:總管想寫「定期打 API 然後通知」的 workflow(Python 約 10 行),
問 foreach_control 怎麼用 → MCP 回傳 TinyGo 寫 WASM 零件教學(白名單/syscall/
contract schema)=完全另一件事,40 分鐘未完成。
三處修正:
1. search_components 搜不到時的話術——原本建議 publish_component(把「我找不到」
翻譯成「你去造一個」,方向完全相反)。改為導向正確順序:語意搜尋知識庫→
auth-recipe list/scaffold→acr parts(http_request 能打任意 API)→acr list,
並明說 registry 可能是空的(已知問題),搜不到≠沒有這能力。
2. registry.ts 停用 publish_component / get_component_guide 兩個註冊
(檔案保留,只是不對 AI 暴露)。
3. 新增 CONTRIBUTING-components.md:三層責任分工(平台通用能力/熱門預鋪 recipe/
冷門誰用到誰開發)、什麼時候才真需要新零件、真要貢獻走 PR 的流程。
typecheck 通過。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 16:42:51 +08:00
Leo
98d87d5d3f
principles: 前端人類友善/Arcrun AI 友善,都從終點看(leo 2026-07-21)
...
判準=AI 覺得 Arcrun 比 Python 簡單,沒有寫 Python 的慾望,絕不可迷路。
使用方式應意圖驅動:不用想有哪些零件,描述目的→機器給建議→用 >> 黏起來。
實證:總管做「定期打 API 然後通知」(Python 10 行)Arcrun 40 分鐘未完成,
全程被 component guide/publish_component 建議推向鑄零件。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 13:00:15 +08:00
Leo
5edb97c49d
docs: CLAUDE.md 加「第一鐵律:wiki 是判準,不准跳過」
...
leo 2026-07-21:「其他 repos 各自都要警覺不能跳過 wiki」。
hook 只是提醒,鐵律要寫在本 repo AI 開工必讀的地方。
含 grep 查法、三條硬規則、動外部系統前先找現成腳本(別自創方法)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 10:55:40 +08:00
Leo
efc29b78c2
chore: template 1.16.1——wiki-first-search 補 Bash 破口
...
1.16.0 只掛 Grep|Glob|Read,但「用 curl/wrangler 亂試方法」走 Bash → hook 不觸發,
上線隔天即被繞過(leo 2026-07-21 實證:wiki 早記著寄信已驗證可用,我沒查又自創)。
matcher 補 Bash,只認高風險指令(wrangler|curl|npx|acr|gh|deploy|push)。
本 repo 亦需警覺:動外部系統前先看 hook 推的 wiki 命中,別自創方法。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 10:54:15 +08:00
Leo
8d8b01d240
docs(sdd): credential-primitives-wasm 封存進 archive(T10 完成,卷已結案)
...
leo 2026-07-21 明令封存:卷已完成,留主目錄會讓未來 session 誤以為進行中。
最後一項 T10(廢除自管加密金鑰)已於 20c7610 完成(移除約 2500 行)。
- git mv 整卷 → system-dev/docs/3-specs/archive/credential-primitives-wasm/
design.md status: closed;superseded_by 留空(據實:非被另一卷取代,是機制整個換掉)
- 卷首補「封存時仍未完成的項目」——逐條查 code 核實,不當作完成:
真缺口=auth_mtls 從未實作、7.6 self-hosted auth 鏈端到端從未驗;
另有勾選過期(auth_oauth2 其實已完成)與驗收條件已作廢(與現行 rule 07 牴觸)者
- 修好 14 處引用(原盤點 10 處,實際更多):session-start-load-sdd.sh 內容嚴重過期
(把已完成 Phase 寫成進行中)→ 改為以 frontmatter 為判準;四份 rules、CLAUDE.md、
BACKLOG、3-specs/README、deploy.ts、credentials.ts、wrangler.toml 逐一按性質處理
- 額外:system-dev/docs/2-architecture/ 有四個規則檔重複副本(06-08 遷移遺留)
→ 同步修好,否則留一份過期真相(今日第三次撞到「同一資訊兩份副本」的債)
- 02-forbidden.md §2.1 列的三個「待刪違規 TS」其實早已不存在
→ 改標刪除線+禁止重新引入(過期文件同時製造假待辦與假進行中)
驗證:sdd-active-check exit 0(active 仍恰一份=portal-auth);
session-start-load-sdd.sh exit 0;cypher-executor 與 cli typecheck 全綠;
測試 187/188(唯一 fail 為 pre-existing,stash 覆驗相同)。
未動:pre-write-guard.sh 的 KNOWN_SDDS 白名單不含 archive 路徑
(放寬 guardrail 需明確授權,留待決定)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 01:57:34 +08:00
Leo
df1b953d1f
chore: template 1.16.0——wiki 讀取兩支 hook(查詢即搜尋 wiki+subagent 自動注入)
...
leo 2026-07-20:「花很多力氣去產生 wiki,最重要的就是要可以查詢,
結果要查的時候就跳過,那就白寫了」
- wiki-first-search.sh(Grep|Glob|Read):查 code 的當下用同組關鍵字 grep wiki,只推命中行
- subagent-wiki-guard.sh(Task):查證類任務自動注入「先查 wiki」給 subagent
- update.sh/install.sh 來源改指 Gitea(原指 GitHub uncle6me-web 已 suspend=自動更新早就死了)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 01:40:55 +08:00
Leo
20c7610371
refactor: 移除已廢棄的自管加密金鑰機制(credential 全面託管 CF Workers Secrets)
...
leo 2026-07-20 明令:「已經改用 cf 自己的 secrets,不要再說它了」
「我希望以後再也看不到這個詞再出現」
背景:credential 早已遷移至 CF Workers per-script Secrets + D1 目錄,
舊的自管金鑰(client 端 AES-GCM + KV 密文 + crypto_decrypt)是遷移期遺留。
本次連根移除,含一併作廢的死 SaaS 碼。
移除:
- 舊 KV 密文解密路徑(credential-injector.ts 整檔、dual-read fallback)
前置驗證:leo21c / youlin 兩帳號 CREDENTIALS_KV 實測 *:cred:* 皆 0 筆
- migrate-to-workers-secrets 搬家端點(回填已完成,無可回填)
- /register 路由與 generateApiKey(HMAC 產 ak_ key 是 SaaS 遺物;
self-hosted 走 namespace 明碼 D21,已無人使用)
- platform_crypto component(三帳號實測 404 已退役,無 workflow 引用)
保留(附理由):
- crypto_decrypt 保留為永遠回失敗的 stub——現役三個 auth .wasm 仍宣告該
import,缺項會讓 WASM instantiate 直接失敗。待零件重編後可真正刪除。
順帶修復(原不在範圍,但會實際壞事):
- /auth/callback 有 `if (!key) redirect(server_error)` 閘,未設該 secret 的
實例會登入直接失敗 → 已移除
- OAuth 兩處把 provider token 寫進舊加密 KV(租戶鍵與實際 api_key 在 rotate
後必然分歧,已失效)→ 改導向 Workers Secrets,包 try/catch 不影響登入
- acr init Standard 模式呼叫已刪除的 /register → 改引導 OAuth 取 key
- .claude/rules 與 system-dev/docs 是同一規範的兩份鏡像,先前只改 rules
導致鏡像仍在教舊做法 → 已同步(此類雙檔同步應納入檢查)
新用戶安裝從此零 secret 前置。
測試 187/188(唯一 fail 為 pre-existing,stash 驗證與本次無關);
cypher-executor 與 cli typecheck 全綠。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-21 01:32:48 +08:00
雲端總管
b9b94d7852
docs(sdd): library-map tasks M1-M5+M3 銷帳(07-19 雙實例上線)、M7 半驗
2026-07-19 11:21:33 +00:00
Leo
762d2f5141
Merge pull request 'feat(console): library-map M5 — 總庫搜尋頁藏書地圖首頁區塊(R4)' ( #74 ) from feat/console-library-map-home into main
2026-07-19 09:36:04 +00:00
Claude
10dda9e6f5
feat(console): library-map M5 — 總庫搜尋頁藏書地圖首頁區塊(R4)
...
library-map SDD M5(Arcrun#39):console 首頁從空白搜尋框變全館地圖。
落點裁定:console 是 hash-routing 單頁殼,home 隨 profile(full=駕駛艙、
rag=總庫搜尋)——地圖放總庫搜尋頁搜尋框上方:rag profile 該頁即首頁;
full profile 它是全館入口,「點庫卡片→進該庫搜尋」動線同頁最短,一份實作
兩 profile 全吃。
- console.ts:藏書地圖區塊(lm-section)——每庫一張卡(庫名+narrative+
top entities 前 5 帶 degree+triplet_count+commit_hash/updated 更新時間感)、
跨庫 bridges 有資料才列一小區;兩段式渲染(全館列表先出卡,逐庫詳圖補
degree/bridges,詳圖失敗維持名字版不擋);點庫卡片=設 library filter
(/kbdb/search 既有 library 參數,不新造)進庫搜尋,附清除鈕搜回全館;
/map 空陣列或錯誤=誠實空狀態(指引 POST /map/recompute backfill),
不擋搜尋等其他功能。品牌沿 CONSOLE_BRAND 變數(#21),零外部庫。
- kbdb-proxy.ts:GET /kbdb/map+/kbdb/map/:library 純轉發(rule 07,聚合真身
在 kbdb base M2)。owner_id 不強制注入只選擇性透傳(同 M4 MCP kbdb_get_map
語意;現行 backfill map block owner=NULL,強制注入租戶=首頁永遠假空狀態);
仍要求 X-Arcrun-API-Key 同閘;KBDB 不可達誠實 502。
- 測試:kbdb-map-proxy.test.ts 9 測(租戶閘/轉發/owner 透傳/空陣列/404/502)+
console-library-map-page.test.ts 6 測(route 200/區塊在搜尋框上方/資料源接線/
library 參數/誠實空狀態文案/品牌變數)——15/15 過。
- 誠實回報:tsc 16 行 ExecutionContext.tracing 錯誤與 executor.test 1 失敗=
main 基線既有(git stash 對照實證),非本分支引入。
merge 後需 gated redeploy cypher-executor(leo 閘)。關聯 #39。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
2026-07-19 09:34:36 +00:00
Leo
289cd495b4
Merge pull request 'feat(mcp): library-map M4 — kbdb_get_map 工具+instructions 注入全館地圖' ( #73 ) from feat/mcp-library-map-inject into main
2026-07-19 09:13:46 +00:00
Claude
343572bf5d
feat(mcp): library-map M4 — kbdb_get_map tool + instructions 注入全館地圖
...
library-map SDD M4(design §4,源頭 #39)。兩件:
1. kbdb_get_map(tools/kbdb_map.ts,與 #68 kbdb_graph_neighbors 同族薄殼):
- 無參數=全館地圖(每庫一行:library+narrative+top 3 entities+triplet_count)
- 帶 library=該庫詳圖;top_entities/relation_profile/bridges 若為 JSON 字串形
容錯 parse 成物件(parse 失敗當空陣列,不 crash)
- 404/空庫誠實回報+POST /map/recompute backfill 指引
- 走既有 KBDB service binding(kbdbFetch),不碰 D1、不新增 binding
2. instructions 注入(lib/library-map.ts+mcp-handler.ts):
- 連線時拉 GET /map,渲染成緊湊文字({library}:{narrative}|核心:{top3}|{n} triplets)
嵌 server instructions(design §6:session 啟動 push 零查詢)
- 快取選型:isolate 內 TTL 快取(成功 5min/失敗 1min)——stateless StreamableHTTP
每個 HTTP request 重建 McpServer,「每次現拉」實際是每個 tool call 都多打一次 /map
- timeout 1.5s;任何失敗(超時/HTTP錯/空庫/壞JSON)回 null 靜默略過,絕不擋 MCP 連線(鐵律)
測試:假 KBDB binding(比照 kbdb-graph.test.ts)17 新測,pnpm vitest run 76/76 過、tsc --noEmit 乾淨。
merge 後需 gated redeploy arcrun-mcp(leo 閘)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
2026-07-19 09:11:46 +00:00
Leo
bdfc2e3e0b
Merge pull request 'feat(kbdb): 藏書地圖 M1+M2 — library_map template+/map 三端點(聚合 SQL 住基本盤)' ( #72 ) from feat/library-map-base into main
2026-07-19 08:42:42 +00:00
Claude
15fe012006
feat(kbdb): 藏書地圖 M1+M2 — library_map template+/map 端點(聚合 SQL 住基本盤)( #39 )
...
M1:library_map template(migration 0003 seed+runtime ensure,D6 零建表零 ALTER);
核實 triplet 按庫定位=不足(prod triplet template 無 library slot、entries
metadata.library 未標記)→ 走 SDD 預案:recompute 冪等補 optional library slot
(改 template 不動表),slot 值由 ingest 端(M3)補寫,核實結果記入 design §1。
M2:kbdb base 三端點(design §2 歸屬裁定:聚合 SQL 只准住基本盤):
- POST /map/recompute?library=X:degree top-N/predicate 分布/跨庫 bridges/
triplet_count 一段 SQL 聚合;narrative 本輪收 body 傳入(wiki 抽取屬 M3);
寫入順序安全(先建新 active map block 再標舊 superseded,讀端取最新 active 自癒);
過渡 source_prefix fallback 讓無 library 值的舊 triplet 靠 source_uri 前綴歸庫。
- GET /map:全館地圖每庫一行(library+narrative+top 3 entities+triplet_count),
MCP instructions/GUI 共用(數百 token 內)。
- GET /map/:library:該庫詳圖(完整 slots+可嵌人話 content,design §5 M6 直用)。
測試:node:sqlite(零新依賴)當真 SQLite 實跑 migrations+聚合 SQL,
Hono route 行為同款覆蓋;45/45 過、tsc --noEmit 乾淨。
關聯 #39
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
2026-07-19 08:40:22 +00:00
雲端總管
bad68ef149
docs(sdd): library-map design 標 leo confirmed 可動工
2026-07-19 08:27:53 +00:00
雲端總管
0ba685af9f
Merge remote-tracking branch 'origin/feat/mcp-graph-neighbors-tool'
...
# Conflicts:
# system-dev/wiki/status.md
2026-07-19 08:05:22 +00:00
Claude
7eeab9f26f
feat(mcp): kbdb_graph_neighbors — graph 鄰居查詢薄殼(#68)
...
MCP 面補齊 D17 KBDB RAG 套餐第三模式(關鍵字/語義/圖):
- 新 tool kbdb_graph_neighbors:subject(必填)/depth(預設 1)/kbdb_base/
template(預設 graph_triplet)/directed,形狀對齊
registry/examples/graph-neighbors/workflow.yaml 的 input
- 薄殼調 GET /q/{orgNamespace}/graph_neighbors 同步查詢端點(#28 地基),
走既有 CYPHER_EXECUTOR service binding,不新增 binding、不碰 D1、
不動 workflow 引擎本體
- workflow 未部署 → 404 誠實回 workflow_not_installed +安裝指引,不 crash;
HTTP 200 但 workflow 層 success:false 也不假綠
- graph_traverse 不加:repo 內無該 workflow 定義可對齊 input 形狀,不猜
- 測試:tests/unit/tools/kbdb-graph.test.ts(7 測,全綠);tsc --noEmit 乾淨;
mcp 全套 vitest 59/59 綠
merge 後需 gated redeploy arcrun-mcp(leo 閘)。
關聯 #68
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
2026-07-19 07:55:16 +00:00
雲端總管
1ee0dbd2fe
docs(sdd): library-map(藏書地圖)SDD 出稿 draft——#39 立案 11 天催辦補課;含 D6 歸屬裁定(SQL 住基本盤)+D30 檢索治本連動
2026-07-19 07:54:23 +00:00
Claude
65d85eb08f
fix(kbdb): search keyword 補 source filter(#66)+semantic 曝 top_k/min_score 帶 score(#67)
...
#66:/entries/search keyword 路徑 source 解析後丟棄(#5.1 只接了 listEntries 那半)——
searchEntries 尾端加 source?(既有 positional caller 全不用改),conds 補與 listEntries
同款 json_extract(metadata_json,'$.source') 謂詞;route keyword 分支與 semantic 降級
分支兩處傳入。
#67:semantic 固定 topK=20、零分數閾值、低分尾硬湊數——route 曝 top_k(預設 20、封頂
100)與 min_score(預設 0=不過濾)query 參數;semanticSearch 依 min_score 截低分尾;
semantic 回應 entry 附 score 欄(加欄不改形)。壞值(非數字/非正)視同沒帶,不 400。
向後相容:不帶新參數時輸出與現況一致(semantic 僅多 score 資訊);不動表(D6)、
不動 D1 結構(API-as-Wall)。測試:新增 search-source-and-score.test.ts 13 條
(source 謂詞形狀/route 下傳/降級不洩 filter/min_score 截斷/topK 透傳封頂/壞值防呆/
不帶參數行為不變),kbdb vitest 33/33 綠、tsc 0。
關聯 #66 #67。merge 後需 gated redeploy kbdb worker(leo 閘)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01JUmjwkHLVBHM3ydhT1WSW3
2026-07-19 07:53:46 +00:00
雲端總管
2324537165
docs(sdd): 1.5-3 補機制邊界(分享≠同步、與 acr update 兩軌)+changelog/版本 diff 規格(leo 修正)
2026-07-19 07:00:42 +00:00
雲端總管
b29de1b216
docs(sdd): 1.5-4 補「public 匿名可讀」規格+官方部署目標帳號(youlin.hsieh.dev)
2026-07-19 06:50:31 +00:00
雲端總管
a73de77a7f
docs(sdd): P-2026-07-19 confirmed——pending-changes 移入已裁決、artifact-sharing tasks 增補 Phase 1.5(bundle/譜系/訂閱/多源/self-check)
2026-07-19 06:43:38 +00:00
雲端總管
ffd50e7510
docs(sdd): pending-changes 收 P-2026-07-19 proposal——artifact-sharing 增補 bundle/譜系/訂閱/多源(leo 對話定調,正式 confirm 待明示)
2026-07-19 06:28:28 +00:00
uncle6me-web
98869c5abc
fix(publish): 匯出樹刪 .gitattributes(同步)
2026-07-18 23:45:44 +08:00
uncle6me-web
d6a051dbfc
feat(publish): sanitize 鉤子(同步 arcrun-rag 版)
2026-07-18 23:29:32 +08:00
uncle6me-web
14d4d65848
fix(publish): push 憑證改 header 注入(GITHUB_MIRROR_TOKEN env),token 不進 URL/指令行
2026-07-18 22:41:06 +08:00
uncle6me-web
ca57fd6a1a
chore(gc): GitHub 公開 mirror 管線(publish-github.sh+排除清單)——D22 模型落地:Gitea 私有真相源/GitHub 過濾樹乾淨歷史
2026-07-18 20:21:15 +08:00
uncle6me-web
e1071edfe8
chore(gc): Mira 白名單 email 改 env 注入(publish 前 GC,leo 2026-07-18 放行)——公開 repo 不帶個人 email;本機 .env.local 已補 NEXT_PUBLIC_MIRA_ALLOWLIST 行為不變
2026-07-18 20:14:22 +08:00
Leo
fa2ecf7226
Merge pull request 'portal: 搜尋濾內部型別雜項列+總圖頁(Arcrun#39 藏書地圖 GUI 切片)' ( #63 ) from feat/portal-library-overview into main
2026-07-18 10:18:18 +00:00
Claude (總管雲端)
50836a3ec8
README: 頂部加 Arcrun RAG 產品/demo 互連(封測漏斗:引擎↔應用雙向導流)
2026-07-18 08:56:14 +00:00
Claude (總管雲端)
0ca3af4d1a
kbdb: searchByTemplate 修 N+1(100 筆 record 逐筆 getRecord ≈ 19 秒 → 批次 IN 查詢 1.3 秒)
...
leo 客戶測試「圖譜/AI 查詢 20-30 秒」的病根:by-template 列表對每筆 record
各跑一次 getRecord(每筆一次 D1 往返)。改為 record id 以 90 一組(D1 綁定
參數上限 100)批次 IN 撈 slot 值,輸出排序與形狀不變。
實測 uncle6:/records/by-template/triplet 19s→1.3s、portal 圖譜 20s→3s、
總圖 1.8s。kbdb 測試 20/20 綠、tsc 0。
2026-07-18 08:30:38 +00:00
Claude (總管雲端)
a82c9bbb82
portal: 搜尋濾內部型別(value/workflow 雜項列)+總圖頁(Arcrun#39 藏書地圖 GUI 切片)
...
- filterDeprecatedEntries 加 INTERNAL_ENTRY_TYPES(value/workflow):
搜尋不再出現無標題雜項列與工作流定義(leo 客戶測試回饋);
#46 上游修好後隨治標段一併拔除。測試 49/49 綠。
- 新增 GET /portal/data/graph/overview:全租戶 active 三元組 →
{nodes(degree), edges},D-4 graph 粗閘、kbdbFetch 直讀、上限 500 誠實截斷。
- portal 新增「總圖」頁:nav 隨 graph_allowed 顯示;力導向佈局手刻
(固定種子=確定性、零外部套件)、紙感樣式(green 節點/amber hub)、
邊 hover 顯示謂詞、點節點跳該實體圖譜搜尋;頁尾連 00-MAP.md
(#39「人機共用同一份地圖」的 AI 注入文字版)。
- #39 本體(library_map Template/ingest 重算/MCP 注入)仍歸該 issue SDD。
2026-07-18 08:17:22 +00:00
Leo
6e0df065fd
Merge pull request 'portal: 來源回溯 gitea:// 顯示為可點超連結(PORTAL_SOURCE_WEB_BASE)' ( #62 ) from feat/portal-source-link into main
...
Reviewed-on: #62
2026-07-18 07:28:01 +00:00
Claude (總管雲端)
6ff1355fe8
portal: 圖譜鄰居渲染修 [object Object]+關聯列從 workflow neighbors 導出
...
- workflow 版 graph_neighbors 的 neighbors 是 {node,predicate,from,depth} 物件,
renderGraph 期望字串 → 節點 chips 全變 [object Object];正規化成名字再渲染。
- workflow 版 edges 恆空 → 關聯永遠 0;neighbor 物件本身就是一條邊,導出成
{subject,predicate,object} 餵關聯列(plugin 版行為不變)。
- 邊列 subject 比對改大小寫不敏感(graph 查詢端已正規化,搜 rag 命中節點 RAG)。
- 來源:leo RAG demo 客戶測試回饋問題 3(鄰居/關聯顯示有誤)。
2026-07-18 06:13:45 +00:00
Claude (總管雲端)
eaaf894b23
portal: 來源回溯 gitea:// 顯示為可點超連結(PORTAL_SOURCE_WEB_BASE 可選 var)
...
- 新增可選 var PORTAL_SOURCE_WEB_BASE:設了之後 Portal 卡片詳頁「來源回溯」與
AI 問答出處列把 gitea://<path>#n 渲染成 {base}/<path> 超連結(新分頁開啟);
未設時行為一字不變(Mira 零影響)。
- 安全:href 過 esc()、路徑逐段 encodeURIComponent、rel=noopener;
只認 gitea:// 前綴,其他 scheme 一律純文字。
- 驗證:tsc 0 錯誤;portal-auth/portal-data 測試 48/48 綠;
渲染後 client JS 語法檢查通過。
- 來源:leo RAG demo 客戶測試回饋(2026-07-18)「來源回溯沒辦法點擊」。
- 部署(leo 閘):uncle6 重部 cypher 時帶
--var PORTAL_SOURCE_WEB_BASE:"https://git.uncle6.me/Leo/arcrun-rag-demo-knowledge/src/branch/main "
2026-07-18 06:01:26 +00:00
uncle6me-web
7bd7b4b26a
SDD 生命週期鐵律遷移:單一活性制度上線(portal-auth=active,其餘 paused/draft)
...
- 鋪檔(自 system-dev-template v1.15.0):SDD-LIFECYCLE.md+pending-changes.md
+sdd-guard.sh(覆蓋舊版,加單一活性檢查)+sdd-check.md+sdd-active-check.sh
- settings.json PreToolUse(Write|Edit|MultiEdit)掛上 sdd-guard.sh
- 全部 SDD design.md 掛 frontmatter:portal-auth=active(現行 portal 線,
#61 demo 四件套剛 merge);artifact-sharing=draft(零任務動工);
其餘 16 份=paused(皆有未完成任務,無明顯死件,不硬 close)
- CLAUDE.md 加「SDD 生命週期鐵律」段(指向 SDD-LIFECYCLE.md+濃縮五條)
+SDD 速查表改以 frontmatter status: active 為現行判準
- 驗證:sdd-active-check exit 0(恰 1 份 active);guard pipe-test code 檔
exit 0 帶現行 SDD 提示;反向測試(造 2 份 active)guard exit 2/check exit 1 全擋
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-17 17:03:16 +08:00
Leo
db0a39fdbd
Merge pull request 'portal demo 化四件套:圖譜 workflow 化(#57)+AI 問答+上傳頁+搜尋濾殘影(#46 治標)' ( #61 ) from portal-demo-suite into main
2026-07-17 06:48:04 +00:00
Claude
8accdacc3c
portal 搜尋濾殘影(#46 治標)+四件套單測
...
/portal/data/search 拿到 KBDB 回應後 server-side 過濾 metadata_json.status=
'deprecated' 與 content 以「(舊管線產物」開頭的 entries(metadata parse 失敗
視為保留,不誤殺),count 重算。這是 Arcrun#46 上游修好前的 portal 端治標,
上游清完資料後整段(含 filterDeprecatedEntries)可拔。
單測:sanitizeUploadFilename(路徑穿越/副檔名/長度)、filterDeprecatedEntries
(濾殘影/壞 metadata 保留)、mapGraphWorkflowOutput(#57 輸出映射);
/portal/session 補 upload_enabled=false 斷言。另修 portal-ui 一處註解字樣
(誤用產品名,撞零 Mira 斷言)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BH7LdhuCdVUHfHXbM7N8r5
2026-07-17 06:28:04 +00:00
Claude
fde1827928
portal 上傳頁:POST /portal/data/upload(server-side 寫 Gitea)+前端拖放上傳
...
server:requirePortalUser 閘;filename 驗證(去路徑分隔、強制 .md、限 100 字);
server-side POST Gitea contents API 到 PORTAL_UPLOAD_REPO 的 docs/{filename}
——token 只在 server,前端零 repo/token 字串。409/422 → 誠實「同名文件已存在」。
新增三個 Bindings:PORTAL_UPLOAD_REPO / PORTAL_UPLOAD_GITEA / PORTAL_UPLOAD_TOKEN
(secret),任一缺 → 404「未啟用上傳」=Mira 零影響(功能不存在,現行為一字不變)。
/portal/session 補 upload_enabled 布林(server 判 bindings 齊全;顯示提示,真閘在路由層)。
前端:上傳 nav(sidenav+tabbar,一般用戶可見、未啟用時隱藏)+檔案選擇(.md/.txt
多選)+拖放區;讀檔轉 b64 逐檔 POST、逐檔狀態列;成功顯示「已收件,約 1 分鐘後
可在搜尋頁找到;AI 整理後會以 wiki 卡形式出現」。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BH7LdhuCdVUHfHXbM7N8r5
2026-07-17 06:24:14 +00:00
Claude
c01c6c4d02
portal AI 問答:/portal/data/chat 端點+搜尋頁問答面板
...
端點:requirePortalUser 閘(同 search);in-process 執行 tenant 的 rag_chat
workflow(與 graph_neighbors 同機制),input {question},回 {answer, sources,
graph_facts};workflow 不存在 → 誠實 404「此實例未安裝問答 workflow」。
前端:搜尋框下方問答列,loading→純文字 answer(pre-wrap 保留換行、esc 防
XSS)+sources 列表(mode+page,點 page 帶回搜尋框自行驗證)。設計哲學:
AI 檢索=用戶手動搜尋同一套,AI 只代查再作答,不多開任何權限。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BH7LdhuCdVUHfHXbM7N8r5
2026-07-17 06:20:27 +00:00
Claude
204cd5bff3
portal 圖譜模式修復(#57):優先 in-process 執行 tenant graph_neighbors workflow
...
RAG self-hosted 實例不部署 kbdb-graph-plugin,graphBase 直連必 1042。改為:
WEBHOOKS KV 有 {tenant}:wf:graph_neighbors 時直接 import executeWebhookGraph
(webhooks-named trigger/query 同一執行入口)在本進程執行——絕不 fetch 自己
hostname(self-loop);輸出映射成與 plugin 相同形狀 {neighbors, edges, count}。
沒有該 workflow → fallback 原 graphBase 直連(Mira/leo21c 行為一字不變)。
input:node=path、depth=query(預設 2)、namespace/owner=tenant。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BH7LdhuCdVUHfHXbM7N8r5
2026-07-17 06:19:03 +00:00
Leo
1e85dfb49b
bugfix(#24 #25):PBKDF2 600k→100k(CF Workers runtime 上限,真雲 bootstrap 500)+http_request 補 global_fetch_strictly_public(1042) ( #56 )
2026-07-14 13:23:58 +00:00
Leo
52dbd31dea
portal-auth P4(#24 #25):admin 帳號+庫管理頁+last-admin 鎖死保護(不 merge,待總管審) ( #53 )
2026-07-14 08:54:41 +00:00
Leo
3577e9255c
portal-auth P3(#24 #25):Portal UI+/portal/data/* server-side enforce(不 merge,待總管審) ( #52 )
2026-07-14 07:19:01 +00:00
Leo
1260d8cffb
portal-auth P2(#24 #25):portal_user 模型+認證 API(不 merge,待總管審) ( #51 )
2026-07-14 04:19:54 +00:00
Leo
7f409646e5
portal-auth P1(#24 #25):KBDB library filter 地基(不 merge,待總管審) ( #50 )
2026-07-14 03:50:06 +00:00
Leo
18c0846af0
SDD: RAG Portal 多人授權(#24 #25)— 純設計文件,待審不 merge ( #49 )
2026-07-14 03:32:00 +00:00
Leo
cbebb36c01
console 頁面 profile 裁剪:CONSOLE_PROFILE=rag 企業產品樣(搜尋落地),未設=full mira 零影響 ( #48 )
2026-07-13 11:15:00 +00:00
Leo
2e1005ea67
console rebrand Mira→Arcrun + CONSOLE_BRAND 可覆蓋(#21) ( #47 )
2026-07-13 00:06:56 +00:00
Leo
1c4f79b623
Merge pull request 'feat(console): 分流台勾掉/還原——雙向銷案(console 勾掉=終局,萃取端絕不復活)' ( #42 ) from feat/console-triage-checkoff into main
2026-07-08 15:32:35 +00:00
Leo
e90688c608
feat(console): 分流台勾掉/還原(雙向銷案:console 勾掉=終局 checked_via:console,萃取端絕不復活)
...
leo 2026-07-08 拍板,PR#41 分流台的後續:
- lib/console-triage-model.ts:applyTriageCheck 純函式(check→status:done+
checked_via:console+checked_at;restore→status:new+移除 checked_via/checked_at;
content 非 JSON 殘資料包成 {"text":原文} 不丟字)。雙向銷案語意寫死在註解:
console 勾掉=終局,即使 Logseq 原文還是 TODO 萃取端也絕不復活;Logseq 改 DONE
由萃取端 PATCH(checked_via:logseq);console 只忠實顯示非 done 項。
- console-dashboard.ts:POST /console/triage-check(沿 triage-data 同款 session 驗證;
瀏覽器沒 KBDB token 故 server 端做 PATCH——先 GET 原 entry 整串回寫防蓋掉別的欄位;
守 owner_id=CONSOLE_TENANT 與 entry_type∈{todo,inbox} 兩道邊界)。
- console.ts:每筆待辦 44px 圓形勾掉鈕(手機好按)+done 清單「還原」鈕(誤勾救濟);
後端回寫成功才改本地狀態移出三欄(done 預設隱藏既有機制),失敗誠實 toast 可重試。
- 測試:applyTriageCheck 7 例(先紅後綠)+ route 層 8 例(fetchMock 假 host
kbdb.test + disableNetConnect,絕不外連;驗 session 閘/整串回寫/邊界/restore)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 23:30:13 +08:00
Leo
1bc83c7124
Merge pull request 'feat(console): 收件夾改裝=全部待辦分流台(三欄 80/15/5 + per-project 過濾)( #9 )' ( #41 ) from feat/console-triage-inbox into main
2026-07-08 15:13:58 +00:00
Leo
5cd790c94a
feat(console): 收件夾改裝=全部待辦分流台(Arcrun#9,kb-ingest SDD R7 消費端)
...
console 頁 7 從 Telegram 訊息清單改裝成三欄分流台:
- 資料源二合一:entry_type=todo(Logseq 萃取,Arcrun#8 ingest 線)+ entry_type=inbox
(Telegram),/console/inbox-data → /console/triage-data(唯一消費者是本頁,一起改
裝不留死端點;仍鎖 console session——待辦原文屬機敏)
- 三欄 80/15/5:ai=AI 會幫我搞定/collab=協作/leo=非我不可;owner_tier 缺席或看
不懂(triage engine 還沒判)→ 歸 collab 欄+「未分流」徽章,不冒領 ai、不誤判 leo
- 各項顯示 text/project 徽章/source/marker;status:done 預設隱藏可切換
- per-project chips 過濾(全部/各 project/未分項),前端同包資料過濾零額外請求
- 手機直排沿 console 單檔薄殼;讀 KBDB 走既有 kbdbBase HTTP 慣例,不新增 binding
契約解析/分欄/計數=純函式 lib/console-triage-model.ts(比照 console-dashboard-model
模式,route 只做 IO),tests/console-triage-model.test.ts 11 測全綠(紅→綠驗證:抽掉
實作模組同測試即紅)。全套 vitest 98 passed,唯一失敗為 pre-existing executor
「不存在的零件」訊息斷言(main 同紅,與本 PR 無關)。
[總管-subagent]
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 22:44:54 +08:00
Leo
2fa0974e1c
Merge pull request 'fix(console): 駕駛艙「今日完成」跨 UTC 日界修正——today_done 0/10 假空(07b 板實態 3 個 parser 落差)' ( #40 ) from fix/console-today-write-dayline into main
2026-07-08 14:02:06 +00:00
Leo
88633b0da4
fix(console): 駕駛艙「今日完成」跨 UTC 日界修正——07b 板實態 3 個 parser 落差(0/10 假空)
...
SDD:system-dev/docs/3-specs/arcrun/search-console/tasks.md task 5.6(本次新增,Phase 5 稽核輪延伸)
live bug(2026-07-08 21:40 台北實測):sprint-2026-07b.md 台北今晨 05:50
(=UTC 07-07 21:50,cloud-worker 跨 UTC 日界寫入)勾了 CP1/T7/T5-provider,
/console/dashboard-data 卻回 today_done:0/today_total:10、done_today_titles:[]。
根因=任務板 parser 與 07b 實際維護慣例的三個落差(lib/console-dashboard-model.ts):
1. COMPLETED_DAY 要求日期緊貼「完成(」——07b 起署名在日期前
(「完成([cloud-worker] 2026-07-07,…)」)→ T7 的完成日抓不到,
[x] 無日期=整項蒸發(不冒領原則誤傷)。
2. 完成標記寫在縮排子彈上(CP1/T5-provider 的任務行只有 [x])→ 舊 parser
只掃行首 checkbox 行 → 同樣蒸發。
3. cloud-worker sandbox 時鐘是 UTC、routine 排程台北清晨(06:30=UTC 前一日
22:30)——它戳的日期 D 其實是台北 D+1 凌晨的完成,todayKey 永遠對不上。
修法(全在純函式層,route 零改動):
- DONE_STAMP 改抓「完成(…)」括號內容、日期允許前綴;縮排補充行的完成
標記歸到所屬任務(子彈本身仍不是任務)。
- [cloud-worker] 署名戳 D 展開台北候選日 {D, D+1};progress-guard 跑台北
16:30(UTC 同日)不展開——展開只會多冒領;本機/總管台北戳照舊精確,
「昨天完成的明天不冒領」不變。
- 狀態欄放寬:[🔄 →只剩1042](07b 實例)認 doing,任務不再蒸發、today_total
不再少算;x 帶註記仍不冒領 done(寬鬆容錯原則不變)。
驗證:新增 5 案例(07b 逐字真實形態)修前紅(today_done:0、done_today_titles
[]=live 症狀重現)修後綠;model 測試 27/27;全套 vitest 87/88(1 失敗=
pre-existing executor「不存在的零件」,stash 於未改樹複驗同樣紅);tsc 錯誤
行數與未改樹相同(12 行,全在 validate/webhooks-named,workers-types 環境
漂移,非本次引入);另用 Gitea live 07a+07b 檔直灌新 parser:today_done:3、
done_today_titles=[T5-provider, CP1, T7]=板上真相。不部署(留 task 5.5)。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 21:51:24 +08:00
uncle6me-web
85ffe2d16d
chore(release): 1.3.14 npm 補發——對齊 main(exposure 閘已移除/creds 新行為),治 npm drift 兩次誤判根源
...
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-08 21:36:30 +08:00
Leo
f9971c956a
Merge pull request 'fix(console): 真實性稽核修正——時區統一台北、精耕層數字、今日完成接 sprint 任務板' ( #37 ) from fix/console-truth-audit into main
2026-07-07 12:35:35 +00:00
cloud-worker
5690d61438
fix(console): 真實性稽核修正——時區統一台北、精耕層數字、今日完成接 sprint 任務板
...
稽核輪(fix/console-truth-audit,總管派工+leo 三裁決):
B1 時區:console 全站日期/時間顯示統一 Asia/Taipei(新 lib/taipei-time.ts,
server 判定與頁面 client JS 同一套、等價性單測互鎖)。原本用瀏覽器本地
getter——換裝置就換日期;憑證頁改顯「日期+時分(台北)」:raw 1783349834
=台北 2026-07-06 22:57,7/6 顯示是真的,缺的是時分與固定時區。
B2 總庫數字(leo 裁:14-E 遺產 deprecated 不再顯示):總庫搜尋/設定頁頭部
統計改讀新 GET /console/kb-scale-data(精耕層 wiki 卡/三元組/已嵌入+最近
寫入,全 live、limit=1/stats 聚合不掃庫);搜尋仍搜全庫、結果 wiki_card
加「精耕」綠標;dashboard-data 的 entries 計數補 owner_id(原混租戶:
459,137 vs leo 458,732)。
B3 設定頁:vectorize 文案改具體事實(config kbdb_embed+acr update,#32
教訓)+live 狀態;新增 MCP token TTL 誠實佔位(GET /console/settings-data,
可調功能=Arcrun#19,不假裝能遠端改)。
C 今日完成/今日路線接 sprint 任務板(leo 拍板):比照 #36 等leo清單模式,
同一輪 Gitea fetch(90s CF cache 共用)解析「## 任務板」checkbox;「今日
完成」只認「完成(今天台北日)」標記,[x] 無日期不冒領;快取存原始
completed_days,跨台北午夜不誤算;板檔今天沒 commit → 頁面誠實標「今日
任務板未更新」;dash_task 降 fallback、燈號判定不變。parser 以 live
07a/07b 檔實測(標題抽取棄「首個粗體」——實讀發現會抽到完成註記)。
驗證:tsc exit 0;vitest 82/83(1 失敗=pre-existing executor「不存在的
零件」,stash 於 main 複驗同樣紅);新增 taipei-time 10 案例(含跨日/跨年/
client-server 等價/leo 實測 epoch)+任務板 parser 7 案例;兩頁 inline JS
渲染後抽 <script> node --check 全過(mistakes #24 手法)。
2026-07-07 12:25:31 +00:00
Leo
ef779e3ef6
Merge pull request 'fix(console): 駕駛艙首頁改讀 live 一手資料,stale 殘骸誠實標示' ( #36 ) from fix/console-dashboard-live-data into main
2026-07-07 11:25:27 +00:00
Leo
e1822e8202
Merge branch 'main' into fix/console-dashboard-live-data
2026-07-07 11:25:23 +00:00
Leo
7bd6899c96
Merge pull request 'docs(spec): artifact-sharing 增量 — deps_summary + 作者信譽經濟 + 資料完整性原則' ( #31 ) from spec/artifact-sharing into main
2026-07-07 11:25:22 +00:00
Leo
0d9a6e8eed
perf(console): Gitea 等leo清單讀取加 CF Cache 層(TTL 90s,#36 審查①)
...
- cachedGiteaWaiting:caches.default + Cache-Control max-age=90;前端 60s
刷新下 Gitea 從每分鐘 3-4 call 降到 ≤1 輪/90s
- hit 回放用 reviveWaitingAges 隨牆鐘補算「維護於 N 分鐘前」(不停走)
- 失敗不快取(不把網路抖動放大成 90 秒盲區);cache.put 走 waitUntil 不阻塞
- waiting_meta.cache 吐 hit/miss,部署後 curl 兩次即得快取生效證據
- 測試:tests/console-dashboard-cache.test.ts 4 案例(真 workerd Cache API,
注入 fetcher 計數證明 hit 不再打 Gitea);全套 69/70(1 fail=main 既有)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 11:19:19 +00:00
Leo
af926aaad8
docs(spec): tasks 明標榜單類=物化候選第一位(跨作者榜不可 on-read 掃全庫,審查 #31)
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 11:14:51 +00:00
Leo
99da35a885
fix(console): 駕駛艙首頁改讀 live 一手資料,stale 殘骸誠實標示
...
leo 抱怨「等你的事」錯了好幾天、首頁總覽對不上實際進度。診斷結論:
- dash_wait 沒有活的維護管線(最後寫入 07-04;等leo清單#11 已於 07-05
銷案=誤判,dashboard 卻繼續掛著)——真相源其實是 InkStoneCo sprint 檔
「## 等 leo 清單」(progress-guard 每日核實維護)
- dash_task 的 scope:today 沒有日期,07-04 的路線到 07-07 還被當今天的
- 燈號吃到 stale 任務;系統狀況/總覽無 live 信號
修法:
- 等你的事:首選 Gitea sprint 等leo清單(合併最新兩檔——07b 開了、🔴 仍
掛 07a;需 GITEA_TOKEN secret);讀不到 fallback dash_wait 必標 age+stale
- 今日路線:台北日曆日判 is_today,非今日寫入降級「最後路線(N 天前)」
- 燈號只吃今日寫入任務+心跳+KBDB /health,附 light_reason
- 新增系統狀況(KBDB /health、embed enabled:false 誠實顯示、graph
/triplets/stats、workflow 數)與總庫規模(entries/wiki_card/triplets)全 live
- 聚合判定抽純函式 lib/console-dashboard-model.ts,vitest 15 案例
(含真實 sprint 檔形態:劃掉列/✅ 急迫欄/R1 字母編號/🔴 排序)
驗證:tsc --noEmit 0;vitest 65/66(1 失敗為 main 既有 executor.test.ts,
stash 復原後同樣失敗,非本次引入);parser 對 live sprint-2026-07a/07b
dry-run 撈出 🔴 #13 等 9 項 open、清單維護於 31 分鐘前。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 11:02:22 +00:00
Leo
df62933fa5
docs(spec): artifact-sharing leo 三補點 — deps_summary 搜尋層可見 + author 信譽經濟 + 資料完整性優先於界面
...
leo review 方向確認後的三個補點(2026-07-07,總管轉達):
1. deps_summary:搜尋結果每項就顯示配套需求(從 dependency_manifest 聚合的輕量摘要,
submit 時算好存 metadata_json)。low-code 關鍵:判斷「裝不裝」的資訊要在搜尋層,
不是 pull 之後才發現缺東西。design(R1 模型/端點/R5/驗收)、requirements(US-4/R3)、
tasks(1.1/1.2/2.2)對應補。
2. author 信譽經濟(market 核心):author= 過濾+作者頁端點(找到 Leo 看到他全部 shares);
author_reputation=從 per-uuid stat 聚合的衍生視圖、不另立真相源(第一階段查詢時算、
量大再物化);選版升級為單品+作者信譽複合分(權重待拍板);獎勵層 future 不實作
(第一階段獎勵=信譽本身;author 綁認證身份列 SaaS/多人市場前置)。design(作者信譽段/
端點/待拍板 6-8)、requirements(US-9/R3)、tasks(1.3/1.6/5.4/5.5)。
3. 資料完整性優先於界面:新增設計原則段(UI 是未來的皮、record 完整性是現在的責任;
事件型資料事後不可重建 → pull/submit 事件 day-one append);record 欄位用「未來
showcase 網站」反推補齊(created_at/updated_at/tags/compat/license,各標必填/自記/可選);
驗收加可測定義:不看 UI 僅用 record+事件就能重建市場首頁(作者榜/熱門榜/最新發布/配套需求)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 10:15:52 +00:00
Leo
29ba85e848
Merge pull request 'docs(spec): artifact-sharing SDD — workflow/template 分享機制' ( #27 ) from spec/artifact-sharing into main
2026-07-07 09:39:28 +00:00
Leo
b4ecdfd918
Merge branch 'main' into spec/artifact-sharing
2026-07-07 09:39:25 +00:00
Leo
d1a84bda91
Merge pull request 'feat(cli): code 零件接進 acr init/update 部署流程' ( #29 ) from feat/deploy-code-component into main
2026-07-07 09:39:23 +00:00
Leo
66d2045f06
Merge branch 'main' into feat/deploy-code-component
2026-07-07 09:39:20 +00:00
Leo
f7fe080169
Merge pull request 'feat(cypher-executor): 同步查詢 trigger + graph_neighbors 查詢面 workflow 示範' ( #28 ) from feat/sync-query-trigger into main
2026-07-07 09:39:19 +00:00
Leo
dbb956d072
Merge branch 'main' into feat/sync-query-trigger
2026-07-07 09:38:13 +00:00
Leo
1d7f69215a
docs(spec): artifact-sharing 審查對齊 ×2 — K2 改 KBDB 唯一公庫後端(對齊 #16)+ 零件界線照 #23/D29
...
審查意見兩處(總管 2026-07-07):
1. K2 原「recipe 維持 KV 公庫、泛化端點 front 兩後端」與 #16(RECIPES KV→KBDB)衝突
→ 改為 KBDB 是唯一公庫後端;#16 落地前對 type=recipe 的 KV 轉接明定為過渡碼、
#16 完成即拆(1.5/5.2 對應改);KV 公庫不得寫成穩態。遷移本體=#16 負責,不重工。
2. component 界線照 #23/D29 定案改:零件貢獻整層搬到獨立 repo Leo/arcrun-components
(fork→PR→人審);市場只偵測缺件→引導去該 repo 開 PR,永不傳輸/安裝零件程式;
arcrun_publish_component 路徑廢除。design/requirements/tasks 凡提零件發布處照此改。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 09:09:37 +00:00
Leo
7777414b70
docs(spec): artifact-sharing SDD — 把 recipe app-store 分享模型擴展到 workflow/template
...
規劃「資料庫就能完成的開發物」(recipe/workflow/template)的分享/發布/下載/導入/匯出。
泛化一套 /public-artifacts 讀端點 + 型別化 materialize adapter 寫;公庫存 KBDB;
依賴解析劃清界線(recipe/template co-pull、component 走 PR、credential 零傳輸)。
純文件,不改程式。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
2026-07-07 09:04:55 +00:00
Leo
39d6fdfaff
fix(examples): graph_neighbors 去寫死官方 KBDB URL(審查 🔴 )+敏感輸入註記
...
審查發現:workflow.yaml 寫死 kbdb.finally.click = KBDB_BASE_URL fallback 同家族坑
(self-hosted 用戶照抄示範,查詢與資料流向直接打進官方庫)。
改法:
- fetch_triplets base URL 參數化為 {{input.kbdb_base}}(每次呼叫帶),yaml 檔頂加醒目
警示「先改成你自己的 KBDB URL」;grep 證兩檔零 finally.click 殘留。
- 1042 註解保留並補一句:self-hosted 有 global_fetch_strictly_public flag
(credential-primitives-wasm Phase 7),開了 workers.dev URL 亦可帶。
- description.md 參數表加 kbdb_base(必填)+觸發範例改自有域名佔位+補
「敏感輸入請用 POST /query(GET /q/ 的 query string 會進各層 log)」。
tsc 乾淨、全套 50 passed(1 失敗為 main 既有 executor.test.ts 斷言漂移,無關)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 09:01:20 +00:00
Leo
621cb8d948
feat(cli): code 零件接進 acr init/update 部署流程(自足 Worker 進部署清單 + vendored wasm 進 repo)
...
動機(Arcrun#4 後續,leo 批准):code 零件只有原始碼(registry/components/code),
downloadAndDeploy 完全沒涵蓋它——tier1 只掃 .component-builds/*(TinyGo 家族,要求
component.wasm),tier2 寫死四個引擎。merge 後用戶跑 acr update 應真的裝上 code。
接法(實查後裁定):
- code 是自足 Worker(quickjs-emscripten wasmfile variant,非 TinyGo;見其 index.ts 頭註),
「缺 wasm」的真相是「這一類根本不在部署清單」+「vendored quickjs.wasm 是 gitignored
build 產物、不進 archive」。
- deploy.ts 新增 SELF_CONTAINED_COMPONENT_WORKERS(目錄 + 必要產物 gate,比照 tier1
component.wasm gate 的誠實跳過精神),discoverWorkerDirs 將其排進 tier1(零件先於引擎)。
- vendored quickjs.wasm(491KB)commit 進 repo:.gitignore 放行(完全比照
!.component-builds/**/component.wasm 的「部署物 wasm 例外」先例)→ acr update 從
Gitea archive 直接拿到,更新不需 npm build 工具鏈。
- 共享依賴抽成 SHARED_DEPLOY_DEPS 並補 quickjs-emscripten-core + wasmfile variant
(版本對齊零件 package.json,測試看守 drift)→ root 裝一次、esbuild 往上 resolve。
- 注入零改動:既有 stripOfficialOnlyBindings 剝掉 code.arcrun.dev 官方 route、
workers_dev=true 保留 → self-hosted 自動落 arcrun-code.<sub>.workers.dev。
- parts.ts BUILTIN_COMPONENTS 加 code 條目(issue #13 W3:零件=靜態清單)→ acr parts 可見。
實查:init 本來就不對 registry 註冊任何零件(registry index 是官方 backfill 腳本的事),
故「比照其他零件」=進 BUILTIN_COMPONENTS 即對齊。
測試:cli/tests/deploy-code-component.test.ts 9 顆全綠(node --test,零新依賴):
部署清單含 code / 缺產物誠實跳過 / wasm 已 git 追蹤(會進 archive)/ SHARED_DEPLOY_DEPS
涵蓋零件全部 runtime deps + 版本一致 / route 剝除與 [vars] 保留 / parts 清單含 code。
tsc --noEmit 綠;零件自身 12 顆 vitest 綠(沙箱行為未動)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 09:01:11 +00:00
Leo
06ff0e21ce
fix(cypher-executor): component-loader 白名單補 code 零件(#29 發現)
...
WASM_HTTP_RUNNER_IDS 漏 'code',導致 workflow 寫 `component: code` 在解析鏈
step 1-6 全不命中後落到 step 8 直接「找不到零件」——本 PR 的 graph_neighbors
範例正用 code 節點,故歸此分支。
URL 推導:走既有 wasmWorkerUrl 通用推導 arcrun-code.{WORKER_SUBDOMAIN}.workers.dev
(WORKER_SUBDOMAIN 來自 wrangler.toml [vars],self-hosted 由 deploy 注入自己的
subdomain)——無寫死官方 code.arcrun.dev,self-hosted 天然成立。
測試:tests/component-loader-code.test.ts(2 測)——`code` 解析成 runner 不 throw、
stub fetch 證 runner 打 arcrun-code.{sub}.workers.dev;wasmWorkerUrl 對任意 subdomain
推導正確。tsc 乾淨、全套 50 passed(1 失敗為 main 既有、無關)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 08:42:51 +00:00
Leo
020ccdf085
Merge pull request 'fix(cli): acr update/deploy 下載源改指 Gitea archive(Arcrun#4)' ( #26 ) from fix/acr-update-gitea-source into main
2026-07-07 08:40:02 +00:00
Leo
313aeb13bf
feat(cypher-executor): 同步查詢 trigger + graph_neighbors 查詢面 workflow 示範
...
Part 1(框架,cypher-executor webhooks-named.ts):加同步查詢 trigger。
現有 named webhook /trigger 回 {success,data,trace,duration_ms} 信封、只有 POST;
查詢面(console/MCP 打 graph neighbors/traverse)要 GET + 直接拿最終節點輸出當 response。
新端點同步 await 執行 workflow graph → 回 result.data(最終節點輸出)本身當 body(非 202):
- GET /q/:ns/:name (namespace 走 path,input 走 query string)
- GET /webhooks/named/:name/query (X-Arcrun-API-Key header,input 走 query string)
- POST /webhooks/named/:name/query (header,input 走 body)
- POST /webhooks/named/:ns/:name/query (namespace 走 path,input 走 body)
認證沿用 X-Arcrun-API-Key。誠實(mindset §7):節點失敗回 error+trace(500,非假綠);
paused 工作流無法同步回答 → 409 明講;輸出 5 MiB 硬上限(超過 413);duration 走 header 不污染 body。
Part 2(A 類 workflow.yaml):registry/examples/graph-neighbors/。
http_request 打 base custom domain kbdb.finally.click(避 CF 1042)撈 triplet records
→ code 零件記憶體 BFS(對照 kbdb-graph-plugin graph-traverse.ts)→ 同步回鄰居。
把 graph plugin 內建 GET /graph/neighbors 泛化成查詢面 workflow 的示範。
測試:cypher-executor/tests/query-trigger.test.ts(7 測,全綠)——同步回輸出(非 202)、
GET/POST × header/path 四端點、節點失敗回錯+trace、缺 key 401、不存在 404。
用內建 comp_uppercase(純記憶體)證明 Part 1 同步 trigger 機制本身可用。
待驗:graph_neighbors 需 code 零件部署 leo21c 後才能 live 端到端(另線處理);
triplet template id 上線前對一次(workflow 已參數化未寫死)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 08:16:17 +00:00
Leo
794e3eba3a
fix(cli): acr update/deploy 下載源由 GitHub codeload 改指 Gitea archive(Arcrun#4)
...
動機:D20 防 flag 鐵律下 self-hosted 用戶(如 Mira)不能碰 GitHub,
而「init 之後才新增的零件」(如 code 零件)唯一重裝管道 acr update 綁死
GitHub codeload → 沒有乾淨重裝路徑。
改動(只碰 CLI 下載邏輯,不動 README/cypher/mcp/tools):
- deploy.ts:ARCRUN_REPO 預設 uncle6me-web/Arcrun → Leo/Arcrun;
新增 ARCRUN_GITEA_BASE(預設 https://git.uncle6.me)與 giteaToken()
(ARCRUN_GITEA_TOKEN > GITEA_TOKEN,不寫死)。
- 抽出純函式 buildArchiveUrl / buildDownloadHeaders 走 Gitea archive API
GET {base}/api/v1/repos/{owner}/{repo}/archive/{ref}.tar.gz,保留 #13 P2
cache-buster + no-cache 防 stale;private repo 帶 Authorization: token。
- downloadRepoTarball 改用上述;401/403 給「設 GITEA_TOKEN」提示。
- update.ts docstring 對齊(GitHub release → Gitea archive;標註 install≈update)。
install≈update:init 與 update 共用 downloadAndDeploy,其內容指紋 manifest
天然「新零件補、內容未變者略過」,故用戶跑 acr update 即補裝新零件。
測試:cli/tests/deploy-url.test.ts(Node 內建 test runner,零新依賴)8 顆全綠,
涵蓋 URL 組裝、repo/base 覆蓋、token→header、public 無 token、env 優先序。
真正打 Gitea 下載/部署是 leo 的閘,不在本 PR。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 08:13:05 +00: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
Leo
b13b4dfe49
Merge pull request 'refactor(mcp): u6u_* tool rename → arcrun_* + 前綴收斂單一來源' ( #20 ) from feat/mcp-tool-rename-arcrun into main
2026-07-07 06:02:10 +00:00
Leo
9a609c4a04
Merge branch 'main' into feat/mcp-tool-rename-arcrun
2026-07-07 06:02:07 +00:00
Leo
a981dde1d3
Merge pull request 'feat(mcp): OAuth 2.1 server for claude.ai remote connector(修明碼-namespace bearer 漏洞)' ( #15 ) from feat/mcp-oauth-server into main
2026-07-07 06:01:51 +00:00
Claude
5fa3b79a4c
fix(mcp): validate/normalize RFC 8707 resource at issuance; store canonical aud
...
leo review 最後一條:簽發端沒驗證/正規化 resource → 失敗劇本「OAuth 全程成功但每次打 /mcp 401 aud
mismatch」(尾斜線/canonical 變體,錯誤離根因最遠最難 debug)。改在簽發端 fail fast:
- metadata.ts 加 normalizeResource(scheme/host 小寫、去預設 port、path 去尾斜線,與 resourceUri
canonical 一致)+ resourceMatches。
- /authorize(GET+POST):帶 resource 且正規化後 != canonical → redirect 帶 error=invalid_target
(redirect_uri 已驗過才 redirect);一律把 canonical resource 存進 code(不存 client 原樣值)。
- /token:帶 resource 且正規化後 != canonical → 400 invalid_target;aud 一律存 canonical
resourceUri(origin) → 與 partner-auth 嚴格比對 at.aud===resourceUri(origin) 恆一致。
裁決:尾斜線/大小寫等「正規化後等價」的 resource → 接受(存 canonical aud,/mcp 必過),非拒絕——
否則 claude.ai 真送變體會永久授權失敗連不上(把 401 問題換位重現)。只有正規化後真正不同的
resource(別 host/path)才 fail-fast 拒。詳見 OAUTH.md §2。
測試:normalizeResource/resourceMatches 單元 + 尾斜線變體→正常發碼且 aud canonical、別 host→
/authorize redirect invalid_target 不發碼、/token 別 host→400 invalid_target。
mcp vitest 52/52、tsc exit 0。
Refs #15
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 05:38:35 +00:00
Claude
53080ffa53
docs(mcp): GUIDE/README 全面改教 arcrun_*,清掉死 u6u_ 工具名
...
死文件治理:GUIDE.md(25 處)與 README.md(21 處)仍在教 u6u_* 工具名,
含本 PR 已刪的 4 個 tool(deploy/execute/get/list_workflows),下個 CC 照著走會撞牆。
- 全部 u6u_* → 現役 arcrun_*(component/tag/gui 那批用新名)
- 已刪 tool 改指現役:execute→run、deploy→push、get/list_workflows→crud 版
- 修正因換工具而失真的流程與參數:沙盒測試段改為 arcrun_validate_yaml(部署前
schema 驗證)→ arcrun_push_workflow(部署)→ arcrun_run_workflow(觸發,帶
api_key/name/input);get_workflow 參數 workflow_id→name
- 順帶把兩處品牌 prose "u6u" 改 "Arcrun"
- grep 確認兩檔零 u6u
brand.ts:釐清 ARCRUN_TOOL_PREFIX 覆蓋僅內部 rebrand 過渡 / 測試鉤子,
Workers runtime 無 process 全域基本不生效、勿當對外特性。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 05:37:54 +00:00
Claude
5fc7277c3c
refactor(mcp): u6u_* tool 全面 rename 為 arcrun_* + 前綴收斂單一來源
...
零 u6u 洩漏(leo 要求 1):connector tool 清單只剩 arcrun_*,並移除壞掉/
重複的 u6u_ workflow tool(deploy/execute/get/list_workflows 由 arcrun_
push/run/get/list_workflows 取代);MCP server name 也由 u6u-mcp-server
改 arcrun-mcp-server。
前綴單一真相源(leo 要求 2):新增 mcp/src/brand.ts(TOOL_PREFIX + toolName()
helper),所有 server.tool() 註冊一律走 toolName("suffix"),前綴不再明碼散寫。
未來 rebrand 只改 brand.ts 一行。
- 12 個獨有能力 tool rename(component/tag/gui/search_workflows)
- 4 個重複/壞掉 tool 移除
- inter-tool hint、描述字串、註解內 u6u_ 名字全數更新
- tsc exit 0;vitest 19/19 綠
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 05:21:34 +00:00
Claude
92cfb9c59f
fix(mcp): address PR #15 review — aud validation, OAUTH_KV auto-inject, TTL/sunset docs, drift test
...
leo review 5 條逐條處理:
1. RFC 8707 aud 驗證(真缺口):partner-auth OAuth 路徑補「at.aud === resourceUri(originOf(url))」,
不符回 401 invalid_token(防別的 arcrun-mcp 部署簽的 token passthrough)。加 aud 不符→401 測試。
2. deploy.ts injectWranglerConfig 涵蓋 OAUTH_KV(在 PR 內補):OAUTH_KV 納入 REQUIRED_KV_NAMESPACES →
acr init/update 自動建 namespace + 注入用戶帳號真 id(比照 SUBMISSIONS_KV 家族)。wrangler.toml 註解
更新(CLI 路徑自動、手動直推才需手建)。注入 regex 已驗證命中。
3. MCP_TOKEN_TTL 預設維持 30 天(leo 拍板不改):OAUTH.md 明寫為有意取捨(無 refresh token → 到期重走
OAuth=再輸 owner secret),MCP_TOKEN_TTL 可調、7 天為更保守選項。per-owner 可調另開 issue #19(非阻塞)。
4. ALLOW_PLAINTEXT_NAMESPACE 逃生門標 SUNSET(code + wrangler.toml + OAUTH.md),開 issue #18 追蹤
「遷移完成後移除整段 code path + Env 欄位」。
5. 防 drift 測試:spy KV 攔所有 put,斷言對 OAUTH_KV 的每一次 put 都帶 expirationTtl>0(完整流程 +
store 層兩道),防未來往這顆短效 KV 塞長效資料。
驗證:mcp tsc exit 0、vitest 45/45(+aud +drift×2);cli tsc exit 0。
Refs #15 #18 #19
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 04:56:59 +00:00
Claude
7d9d478baa
feat(mcp): OAuth 2.1 server for claude.ai remote connector; close plaintext-namespace bearer hole
...
在 arcrun-mcp worker 實作 MCP Authorization 規範(OAuth 2.1 + PKCE S256),
讓 claude.ai 遠端 connector 安全登入;並修掉「Bearer 明碼 namespace 直接放行」漏洞。
安全模型
- /authorize 同意頁以 owner secret(CF Secrets MCP_OWNER_SECRET)把關,只有 owner 知道 →
只知 URL 的人走不完 OAuth、拿不到 token。
- access_token 是 /mcp 唯一接受的 bearer(預設);明碼 namespace 舊路徑移除(步驟 5 直接 401)。
實作 endpoint(掛 worker 根路徑)
- RFC 9728 /.well-known/oauth-protected-resource(+/mcp 變體)+ 401 帶
WWW-Authenticate: Bearer resource_metadata=...
- RFC 8414 /.well-known/oauth-authorization-server(response_types=code, S256, none)
- RFC 7591 /register(public client,無 secret,無狀態不落地)
- GET/POST /authorize(PKCE S256 + owner-secret 閘 + redirect_uri 白名單)
- POST /token(authorization_code + PKCE 驗證 → access_token 綁定 owner namespace)
儲存鐵律
- authorization code / access token → 短效 KV OAUTH_KV(key 用 SHA-256 hash、帶 TTL、code 一次性)
- owner secret / static token → CF Secrets(非 KV、非明碼 var)
- DCR client / refresh token → 不落地(無狀態 / 不實作,避免長效機密進 KV)
相容決策
- 本機 CLI/GUI/Claude Code → 用真祕密 MCP_STATIC_TOKEN(CF Secret)取代舊明碼 namespace
- 官方 SaaS partner-key 路徑行為不變
- ALLOW_PLAINTEXT_NAMESPACE 逃生門預設關(僅遷移期)
驗證:tsc exit 0;vitest 42/42(oauth 22 + partner-auth 10 改測真實 middleware + 既有 10);
wrangler deploy --dry-run 打包過、OAUTH_KV binding 正確識別。設計文件 mcp/OAUTH.md。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk
2026-07-07 03:59:00 +00:00
kbdb-cc
befc63cfe0
fix(kbdb/embed): 語意查詢 metadata 過濾根因修復(Arcrun#11)
...
根因:Vectorize index 建了卻從沒建 metadata index。CF Vectorize v2 要對某
metadata 欄位下 filter,必須先為該欄建 metadata index,否則帶 owner_id/
entry_type/source 過濾的語意查詢一律回 0 命中(app 端 filter 接線本來就對)。
且 metadata index 只索引「建立後 upsert」的向量 → 既有向量須重推才會被收錄。
- deploy.ts:加 ensureVectorizeMetadataIndexes(),隨部署冪等建 owner_id/
entry_type/source(string)三個 metadata index(self-host/官方帳號皆自動)。
- embed.ts / routes/embed.ts:backfillEmbeddings 加 reindex+offset,重推「所有
embeddable(含 is_embedded=1)」既有向量,讓事後建立的 metadata index 收錄;
POST /embed/backfill {"reindex":true} 觸發,offset 分頁到 remaining=0。
- wrangler.toml:註解補 create-metadata-index 手動步驟 + reindex 提示。
- tests:mock DB 對齊 LIMIT?/OFFSET? 與 reindex predicate;補 reindex 測試。
leo21c 已驗:owner_id=leo / entry_type 過濾修前 0→修後命中,不帶過濾不變。
已知後續(非本 bug 症狀):source 值 89-91 bytes 超過 Vectorize string
metadata index 的 64-byte 索引上限 → source 過濾對長值失效,另案。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 06:03:43 +00:00
Leo
4439880bbd
merge: 機械 wiki ingest workflow(Arcrun#8)——code 節點 card→envelope,Phase B live 驗過
2026-07-06 05:48:10 +00:00
Leo
b87c18df60
fix(km-wiki-ingest): code 節點 post 前剝除 envelope 的 _estSubrequests(graph strict schema)
...
leo21c 實 ingest 發現:graph /triplets/ingest 為 strict schema,會以 422
unrecognized_keys 拒絕 planEnvelopes 掛在 envelope 上的診斷鍵 _estSubrequests。
修:parse_card 內聯碼在 return 前把每個 envelope 的所有 _-前綴鍵剝除,使
post_one_envelope 的 body_json={{envelope}} 為 ingest-candidate 契約乾淨 payload
(source/extractor/nodes/triplets)。已驗:剝除後 entry/nodes/triplets 與原
planCard 逐欄一致。實 ingest(直接驅動同資料流)已用此剝除成功寫入 15 triplets。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 05:38:10 +00:00
Leo
08a79229a5
fix(code): Workers 實部署修正 —— wasmfile+Module 載入 + tick-budget timeout(CF 實測)
...
leo21c 實部署發現兩個 CF 限制並修正:
1. CF 禁 runtime 從 bytes 編譯 wasm(WebAssembly.instantiate(bytes) 被 embedder 擋)
→ singlefile(base64) 內嵌不可用。改 wasmfile variant + `import wasm from './vendor/quickjs.wasm'`
(wrangler CompiledWasm rule 綁成預編 WebAssembly.Module),newVariant({wasmModule}) 注入。
sandbox 改 variant 注入制(setVariant):Worker 注 wrangler Module、Node 由 bytes 建 Module,
同一 production 路徑受測。vendor/quickjs.wasm 由 postinstall 自 node_modules 複製(gitignored)。
2. CF 凍結同步執行期 Date.now → wall-clock deadline 對純同步迴圈失效(撞 CF CPU 回 1102)。
改指令計數 interrupt(max_ticks,CF-safe),wall-clock 留 Node 保護。校準:cadence≈5000
指令/tick、真實 card 解析≈4 ticks、CF 門檻≈1000+ ticks → 預設 max_ticks=500。
有 body 的迴圈(含 100M 迴圈)皆乾淨回 TimeoutError;空體 while(true){} 仍由 CF CPU guard 容納。
Worker live: arcrun-code.leo21c.workers.dev(cypher-executor 以此 workers.dev 慣例位址呼叫)。
Node 單測 12/12 綠(wasmfile variant + 注入 Module,同 production 路徑)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 05:15:50 +00:00
Leo
1a7b4639c3
docs(code): DESIGN.md 更新為「裁定 A、Workers 就緒」的最終狀態
...
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 04:51:39 +00:00
Leo
d93dc4e350
feat(km-wiki-ingest): parse_card 改用通用 code 零件;刪 domain 零件 km_wiki_card_parse
...
Arcrun#10 裁定:一次性解析走通用逃生口,不再鑄 domain 零件。
- workflow.yaml:parse_card 由 component:km_wiki_card_parse -> component:code,
config.code 內聯 card-to-envelope 的 planCard 邏輯(去 import/export、raw NUL
分隔符改 u0000 escape、改用 code 沙箱注入的 sha256);下游 refs 改 parse_card.data.*;
加 limits(timeout_ms/max_output_bytes)。已端到端驗證(YAML 解析->JS eval)與原
planCard 輸出逐欄全等(含 content_hash)。
- 刪 registry/examples/km-wiki-ingest/component-contract.yaml(km_wiki_card_parse 契約)。
- lib/card-to-envelope.mjs:header 改述為「code 節點內聯 JS 的權威來源 + 參考實作」,
邏輯不變(續為 inline JS 之單一真相源)。
- lib/dry-run.mjs / description.md:框架改述為 code-節點形態;部署清單更新為「部署通用
code 零件」。dry-run-evidence.json(3 entries/15 triplets/16 nodes)不變——解析輸出等價。
不部署、不寫 live。留分支可部署狀態。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 04:50:08 +00:00
Leo
efa0b0578c
feat(code): Workers 就緒化(裁定 A)—— singlefile variant + 純 JS SHA-256 prelude
...
- 沙箱改用 quickjs-emscripten singlefile variant(wasm 內嵌 base64、同步載入),
CF Workers 相容;sandbox.mjs 成 Node/Worker 共用 runtime-agnostic 核心。
- sha256 curated builtin 改「純 JS SHA-256 prelude 字串注入」,去掉 node:crypto /
async Web Crypto host-call,Node/Worker 皆決定性(card content_hash 逐字等價)。
- index.ts 成可部署 Worker host(Hono,POST /→runCode),自足不走 TinyGo 模板流程。
- 補 wrangler.toml(arcrun-code / code.arcrun.dev)、tsconfig、DEPLOY.md。
- contract stability 修為 floating(過 registry zod schema 驗證)。
- 單測 12/12 全綠(含 card→envelope 與原模組 planCard 逐欄全等)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 04:39:28 +00:00
Leo
60f5f10ba5
feat(code): 新增通用 code 零件(sandbox inline JS)—— Arcrun#10 設計+PoC
...
n8n Code node 式逃生口:config 帶 inline JS、stdin 帶 input JSON、
stdout 回 {success,data}|{success:false,error,error_type}。
沙箱=QuickJS-wasm:user JS 跑在 QuickJS context,global 只有純 ECMAScript
內建 + 唯一 curated builtin sha256(純函式);碰不到網路/檔案/env/secret/
Worker 物件圖。資源上限:timeout(interrupt)/memory/stack/output/code size。
本輪=設計+PoC,未部署 leo21c。sandbox.mjs + test/ 為 Node/vitest 可跑實作
(12 測試全綠,含 card→envelope 與原模組 planCard 逐欄全等)。index.ts 為
Worker host 骨架、DESIGN.md 記錄機制/安全性質/生產路徑/設計岔路(A/B)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 04:27:15 +00:00
Arcrun CC
cc494a250e
feat(ingest): 機械式 wiki 卡片→KBDB ingest(Arcrun#8 Phase A,dry-run 驗證)
...
新 ingest 模型(無 LLM,取代舊 raw→Haiku 路):
- 來源 = system-dev/wiki/cards/**/*.md(精耕卡)+ ## 實體/## 關聯 typed-edge + [[wikilink]]
- 卡片→base entry(metadata.embed=true);typed-edge/wikilink→graph triplet
- 純機械決定性,零 token
形式 = Arcrun workflow(cron drain + Gitea webhook delta)+ 新自訂零件 km_wiki_card_parse
不撞頂設計:一卡一 tick + 超大卡以 source_uri anchor 自動分段;
graph fan-out 精確 = 7+4N+M+D,dry-run 對 notes 三卡上限 33 subrequest(<50)。
Phase A:不部署、不寫 live。含純核心 + dry-run 證據(3 entries/15 triplets/16 nodes)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01HJiLCRUU2o3aSpPEzVCt2o
2026-07-06 03:52:50 +00:00
uncle6me-web
ed2e42e007
feat(credentials): T6 讀取/注入接新家 + T7 雙讀 fallback (credential-store-migration 方案 A)
...
D19「擁有目錄不擁有內容物」遷移的讀取斷點。密文住 cypher per-script secrets、
D1 只存 secret_ref、auth worker 讀不到 cypher 的 secrets → cypher 先取值塞 payload。
WASM 端(T7 fallback 骨架,零行為改變可獨立部署驗):
- auth_static_key/main.go + auth_service_account/main.go:Input 加 resolved_secrets,
解密處改「有 resolved 就用、沒有才 fallback 舊 kv_get+crypto_decrypt」。default 等於舊碼。
- tinygo build 兩支通過,copy 到 .component-builds/*/component.wasm。
TS 端(T6 主路徑):
- auth-dispatcher.ts 新增 resolveSecretsFromNewHome:查 D1 拿 secret_ref →
secret_get(env[ref], T4) 取明文 → 組 map(取不到的 name 缺席,不放空字串) →
更新 last_used_at。tryAuthDispatch + resolveCredentialRefs 都塞 resolved_secrets。
- rule 02 §2.2 對齊:只查 ref/取值/塞字串,不解密不展開模板不組 JWT。
驗證:cypher-executor + cli tsc exit 0;vitest 41/42(新增 auth-dispatcher.test.ts 6 案例全過,
剩 1 pre-existing 無關失敗)。待 leo21c 部署驗 WASM 端到端(不由本任務部署,acr update
硬綁 GitHub codeload=mistakes #23 )。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-07-05 13:44:26 +08:00
Claude
55a47d7c18
kbdb(embed): add batch backfill endpoint for pre-Vectorize entries (issue #7 / T2.4 缺口)
...
embed 模組原本只有 embedOnWrite(寫入即嵌),對「開 Vectorize binding 之前就寫入」或
embed-on-write 當時漏掉的既有 entry 沒有回填路徑 → is_embedded=0 永遠補不回,語義查詢回 0 筆。
新增(base,對 entries 做;embedding 是 base 唯一職責,非 graph 插件):
- embed.ts: backfillEmbeddings()——找 is_embedded=0 且 isEmbeddable(metadata.embed===true) 的 entry,
批次補嵌(單次 AI.run 陣列 + 單次 VECTORIZE.upsert 陣列 + 單次 UPDATE IN,一批≈3 subrequest)、
設 is_embedded=1,冪等、分批(limit 1-100,回傳 processed/remaining,可重複呼叫直到清零)。
模組未開誠實回 enabled:false(不假綠)。backfillStatus() 回 pending/embedded 計數。
- routes/embed.ts: POST /embed/backfill、GET /embed/backfill/status;模組未開回 409 + capability_hint。
- index.ts: mount /embed。
- tests/embed-backfill.test.ts: 5 vitest(off no-op / 補嵌+標記 / 冪等 / 分批 remaining / status)。
base 維持對內容語意無知(只認通用 embed 旗標,不知 triplet/wiki)。tsc exit 0、vitest 5/5。
端到端(leo21c,wrangler 直推、非 acr update):pending 5→processed 5→remaining 0,
Vectorize vectorCount 0→5,/entries/search?mode=semantic 由 0 筆→5 筆(語義排序命中)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com >
Claude-Session: https://claude.ai/code/session_01BDtnGPJpAzp8UqHfAo8o1s
2026-07-05 04:37:04 +00:00
Claude
1d19d46161
feat(credentials): T8 回填端點 + T9 治理端點/CLI (credential-store-migration)
...
- POST /credentials/migrate-to-workers-secrets:舊 KV credential 逐筆解密回填 D1+Workers
Secrets,冪等可審,重用 wasi-shim 唯一合法 crypto_decrypt 呼叫點
- GET /credentials 改讀 D1(與既有 /credentials/catalog 共用查詢);DELETE 改為新家優先、
舊 KV fallback,避免孤兒資料
- acr creds list/replace/delete 三支 CLI 薄殼指令;順手修好過期的 acr creds push(舊
client 端加密格式已被 T5 取代)
- 新增 cypher-executor/tests/credentials.test.ts + D1 test fixture
T6/T7(讀取/注入路徑、雙讀 fallback)需要重新編譯 registry/components/auth_static_key
的 TinyGo WASM,本環境無 tinygo 且 proxy 擋 github.com 下載,卡在工具鏈缺口,詳細分析
記錄在 credential-store-migration.md。
端到端驗證:部署到 leo21c 帳號真實跑過 GET/POST/DELETE 三分支 + migrate 端點(對真實
既存的兩筆 credential 跑,發現 cypher-executor 自己的 ENCRYPTION_KEY secret 疑似為空,
誠實記錄為待 leo/總管裁決的不可逆風險項,未擅自重設)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com >
2026-07-04 23:00:07 +00:00
uncle6me-web
1db8a13a3a
fix(console): leo 實測三回饋——深淺主題預設淺色/登入頁置中/fetch 斷網韌性 (Arcrun#3 console 系)
...
1. 深/淺主題切換+預設淺色(leo 明示):CSS custom properties 兩份色板
一套結構——:root=淺色紙感(宣紙米白紙紋+墨色文字+琥珀調深 #8a5f1e,
WCAG 對比實算正文 12.2:1/琥珀 4.82/ok 4.58/err 5.17 全過 AA),
:root[data-theme=dark]=原定稿暖黑 2a 原值不動。選擇存 localStorage
(arcrun_console_theme),head 預載腳本防閃色。切換入口:登入/首次
設定頁小鈕、桌面側欄項、設定頁正式開關;/console/dashboard 免登入頁
同步支援(pagehead 小圖示)。金琥珀例外兩版刻意不變(btn 漸層/狀態球/
toast/gcenter)。
2. 登入/首次設定頁置中:根因=.view.on{display:block} 蓋掉 .authwrap 的
flex → 內容靠左;補一行 .authwrap.view.on{display:flex} 水平垂直置中。
3. fetch 斷網韌性:friendlyErr() 把裸 Failed to fetch/Load failed 轉
「連線中斷」誠實文案(非斷網錯誤原樣保留);駕駛艙與 dashboard 的
60 秒定時器常駐、錯誤文案標明自動重試,網路恢復自動刷回。
驗證:tsc --noEmit exit 0;vitest 26/27(1 失敗=pre-existing 基準);
三層跳脫驗證(mistakes #24:template 求值→node --check→行為斷言)全綠。
不部署,總管接手。
2026-07-04 18:30:30 +08:00
uncle6me-web
c673d37ace
docs(wiki): Mira Console 完整版已部署 leo21c——驗收全綠 (Arcrun#3 console 系)
...
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com >
2026-07-04 18:07:13 +08:00