From 793a94ecb5d4e5f00b1f565a5cb37e602c55624c Mon Sep 17 00:00:00 2001 From: uncle6me-web Date: Wed, 12 Aug 2026 13:36:39 +0800 Subject: [PATCH] =?UTF-8?q?chore(worker-builds):=20=E9=87=8D=E7=B7=A8?= =?UTF-8?q?=E2=80=94=E2=80=94#100=20=E7=9A=84=E4=BF=AE=E6=B3=95=E8=A6=81?= =?UTF-8?q?=E9=80=B2=E5=9F=B7=E8=A1=8C=E6=AA=94=E6=89=8D=E6=9C=83=E9=80=81?= =?UTF-8?q?=E5=88=B0=E7=94=A8=E6=88=B6=E9=82=A3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cypher-executor source 525faaf → a5e4caf(sha 49d59597 → d1765930)。 今天第三次在同一件事上被提醒:改完源碼沒重編,出貨與安裝送出去的還是舊的。 --- .../arcrun-cypher-executor/worker.mjs | 98 ++++++++++++++++--- .worker-builds/manifest.json | 10 +- 2 files changed, 89 insertions(+), 19 deletions(-) diff --git a/.worker-builds/arcrun-cypher-executor/worker.mjs b/.worker-builds/arcrun-cypher-executor/worker.mjs index 0eb628b..3ec1a13 100644 --- a/.worker-builds/arcrun-cypher-executor/worker.mjs +++ b/.worker-builds/arcrun-cypher-executor/worker.mjs @@ -3145,6 +3145,11 @@ function graphBase(env) { if (env.KBDB_GRAPH_URL) return env.KBDB_GRAPH_URL.replace(/\/$/, ""); return `https://kbdb-graph-plugin.${env.WORKER_SUBDOMAIN}.workers.dev`; } +function graphHeaders(env) { + const headers = {}; + if (env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${env.KBDB_INTERNAL_TOKEN}`; + return headers; +} var kbdbProxyRouter, NEED_KEY; var init_kbdb_proxy = __esm({ "cypher-executor/src/routes/kbdb-proxy.ts"() { @@ -3278,8 +3283,7 @@ var init_kbdb_proxy = __esm({ kbdbProxyRouter.get("/kbdb/graph/neighbors/:name", async (c) => { if (!tenant(c)) return c.json(NEED_KEY, 401); const base = graphBase(c.env); - const headers = {}; - if (c.env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`; + const headers = graphHeaders(c.env); try { const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(c.req.param("name"))}`, { headers }); return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); @@ -14537,6 +14541,20 @@ async function fetchJson(url, headers) { return null; } } +async function fetchTripletTotal(env, tenant2) { + const { base, headers } = kbdbBase(env); + const data = await fetchJson( + `${base}/records/triplet-stats?owner_id=${encodeURIComponent(tenant2)}`, + headers + ); + if (!data || !Array.isArray(data.stats)) return null; + let total = 0; + for (const row of data.stats) { + if (typeof row?.triplet_count !== "number") return null; + total += row.triplet_count; + } + return total; +} async function fetchEntryTotal(env, filters) { const { base, headers } = kbdbBase(env); const params = new URLSearchParams({ ...filters, limit: "1" }); @@ -14644,6 +14662,7 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => { kbdbHealth, embedStatus, graphStats, + tripletTotal, entriesTotal, wikiCardTotal, workflowTotal @@ -14655,7 +14674,13 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => { cachedGiteaSprint(c.env, now2, (p) => c.executionCtx.waitUntil(p)), fetchJson(`${kbdbUrl}/health`, kbdbHeaders), fetchJson(`${kbdbUrl}/embed/backfill/status`, kbdbHeaders), - fetchJson(`${graphUrl}/triplets/stats`), + // graph-plugin 只拿來判「圖服務活著沒」(燈號)——數字不從這裡拿,見 fetchTripletTotal。 + // headers 一定要帶:plugin 的 /triplets 前綴掛 Bearer 閘,漏帶=永遠 401=永遠假紅燈(#100)。 + fetchJson( + `${graphUrl}/triplets/stats`, + graphHeaders(c.env) + ), + fetchTripletTotal(c.env, tenant2), // owner_id 一律鎖本租戶:原本不帶 owner 會混到別租戶(實測 459,137 vs leo 的 458,732) fetchEntryTotal(c.env, { owner_id: tenant2 }), fetchEntryTotal(c.env, { entry_type: "wiki_card", owner_id: tenant2 }), @@ -14763,13 +14788,14 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => { system: { kbdb_ok: kbdbHealth ? kbdbHealth.ok === true : false, embed: embedStatus ? { enabled: embedStatus.enabled === true, embedded: embedStatus.embedded ?? null, pending: embedStatus.pending ?? null } : null, - graph: graphStats ? { ok: true, triplets: graphStats.total ?? null } : { ok: false, triplets: null }, + // ok = plugin 通不通(graphStats 讀得到就是通);triplets = KBDB 真 COUNT(與 plugin 分頁長度無關) + graph: { ok: graphStats !== null, triplets: tripletTotal }, workflow_total: workflowTotal }, kb: { entries_total: entriesTotal, wiki_card_total: wikiCardTotal, - triplets_total: graphStats?.total ?? null + triplets_total: tripletTotal }, generated_at: new Date(now2).toISOString() }); @@ -14777,22 +14803,22 @@ consoleDashboardRouter.get("/console/dashboard-data", async (c) => { consoleDashboardRouter.get("/console/kb-scale-data", async (c) => { const tenant2 = c.env.CONSOLE_TENANT || "leo"; const { base, headers } = kbdbBase(c.env); - const graphUrl = graphBase(c.env); const now2 = Date.now(); - const [wikiCards, graphStats, embedStatus] = await Promise.all([ + const [wikiCards, tripletTotal, embedStatus] = await Promise.all([ // limit=1 順手拿最新一筆 created_at(list 為 created_at DESC)=「最近寫入時間」 fetchJson( `${base}/entries?${new URLSearchParams({ owner_id: tenant2, entry_type: "wiki_card", limit: "1" }).toString()}`, headers ), - fetchJson(`${graphUrl}/triplets/stats`), + // #100:三元組數改讀 KBDB 真 COUNT,不再讀 graph-plugin 的分頁長度(見 fetchTripletTotal 註) + fetchTripletTotal(c.env, tenant2), fetchJson(`${base}/embed/backfill/status`, headers) ]); const latestMs = parseCreatedAtMs(wikiCards?.entries?.[0]?.created_at ?? null); return c.json({ wiki_card_total: typeof wikiCards?.total === "number" ? wikiCards.total : null, wiki_card_latest_ago_minutes: latestMs === null ? -1 : agoMinutes(now2, latestMs), - triplets_total: typeof graphStats?.total === "number" ? graphStats.total : null, + triplets_total: tripletTotal, embedded: embedStatus?.embedded ?? null, embed_enabled: embedStatus ? embedStatus.enabled === true : null, generated_at: new Date(now2).toISOString() @@ -14944,6 +14970,27 @@ function findBestNodeMatch(searchTerm, nodeNames) { if (hits.length === 0) return null; return hits.reduce((a, b) => a.length <= b.length ? a : b); } +async function tripletCount(env, owner) { + try { + const res = await kbdbFetch(env, `/records/triplet-stats?owner_id=${encodeURIComponent(owner)}`); + if (!res.ok) return null; + const body = await res.json().catch(() => null); + if (!body || !Array.isArray(body.stats)) return null; + let total = 0; + for (const row of body.stats) { + if (typeof row?.triplet_count !== "number") return null; + total += row.triplet_count; + } + return total; + } catch { + return null; + } +} +async function tripletCensus(env, tenant2) { + const owned = await tripletCount(env, tenant2); + if (owned !== 0) return { owned, any: null }; + return { owned, any: await tripletCount(env, "") }; +} async function fuzzyFindNode(env, tenant2, searchTerm) { try { const res = await kbdbFetch(env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}`); @@ -15045,8 +15092,7 @@ portalDataRouter.get( return c.json(mapGraphWorkflowOutput(result.data)); } const base = graphBase(c.env); - const headers = {}; - if (c.env.KBDB_INTERNAL_TOKEN) headers["Authorization"] = `Bearer ${c.env.KBDB_INTERNAL_TOKEN}`; + const headers = graphHeaders(c.env); try { const res = await fetch(`${base}/graph/neighbors/${encodeURIComponent(nodeName)}`, { headers }); if (!res.ok) { @@ -15081,12 +15127,19 @@ portalDataRouter.get( return c.json({ error: "\u7121\u77E5\u8B58\u5716\u8B5C\u6AA2\u8996\u6B0A\u9650" }, 403); } const tenant2 = portalTenant(c.env); - const res = await kbdbFetch(c.env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}`); + const [res, census] = await Promise.all([ + kbdbFetch(c.env, `/records/by-template/triplet?owner_id=${encodeURIComponent(tenant2)}&limit=500`), + tripletCensus(c.env, tenant2) + ]); + const tripletsTotal = census.owned; if (!res.ok) { return new Response(res.body, { status: res.status, headers: { "Content-Type": "application/json" } }); } const body = await res.json().catch(() => null); - const records = body && Array.isArray(body.records) ? body.records : []; + if (!body || !Array.isArray(body.records)) { + return c.json({ error: "\u4E09\u5143\u7D44\u8B80\u53D6\u5931\u6557\uFF1AKBDB \u56DE\u61C9\u4E0D\u662F\u9810\u671F\u7684 records \u6E05\u55AE" }, 502); + } + const records = body.records; const EDGE_CAP = 500; const seen = /* @__PURE__ */ new Set(); const edges = []; @@ -15112,7 +15165,24 @@ portalDataRouter.get( degree.set(o, (degree.get(o) ?? 0) + 1); } const nodes = [...degree.entries()].map(([name, d]) => ({ name, degree: d })); - return c.json({ nodes, edges, node_count: nodes.length, edge_count: edges.length, truncated }); + let emptyReason = null; + if (nodes.length === 0) { + if (census.owned === null) emptyReason = "unreadable"; + else if (census.owned > 0) emptyReason = "scope_mismatch"; + else if (census.any === null) emptyReason = "unreadable"; + else emptyReason = census.any > 0 ? "scope_mismatch" : "confirmed_empty"; + } + return c.json({ + nodes, + edges, + node_count: nodes.length, + edge_count: edges.length, + // 取到的 record 已達 KBDB 單頁上限 → 這張圖只是全庫的一部分,別讓 meta 看起來像全部 + truncated: truncated || records.length >= 500, + triplets_total: tripletsTotal, + empty_confirmed: nodes.length > 0 || emptyReason === "confirmed_empty", + empty_reason: emptyReason + }); }) ); portalDataRouter.get( diff --git a/.worker-builds/manifest.json b/.worker-builds/manifest.json index 144cc30..8564bc6 100644 --- a/.worker-builds/manifest.json +++ b/.worker-builds/manifest.json @@ -1,18 +1,18 @@ { "schema": 1, "built_for": "arcrun-tier2-worker-artifacts", - "generated_at": "2026-08-12T04:21:48.581Z", - "repo_head": "b302c03ea8076bcfe82bbcebb1523dcec2d1e830", + "generated_at": "2026-08-12T05:36:26.216Z", + "repo_head": "cbeddf753537fbf836e20b7efce5b47b50f30d06", "repo_dirty": false, "workers": [ { "name": "arcrun-cypher-executor", "source_dir": "cypher-executor", - "source_commit": "525faaf5d01e156a9b8f90808607bead92f40165", + "source_commit": "a5e4caf5cb38c376f892708d8a46ad96a9cc23cc", "main_module": "worker.mjs", "main_file": "arcrun-cypher-executor/worker.mjs", - "js_bytes": 570290, - "content_sha256": "49d59597c01b5264875e0295c86c7bb2212bf54d3c5858cd4a167752370fa716", + "js_bytes": 572842, + "content_sha256": "d1765930ce157de07400dcff21d620a3b5549e0a66f0d6428cc6901631ba73b2", "modules": [], "compat_date": "2025-02-19", "compat_flags": [