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=總管)
This commit is contained in:
@@ -37,4 +37,21 @@ export const PORTAL_TEMPLATE_SEEDS: PortalTemplateSeed[] = [
|
||||
slots: ['name', 'display_name', 'description', 'status', 'graph_source'],
|
||||
created_by: 'system',
|
||||
},
|
||||
{
|
||||
// t130:rag_ingest_card.post_triplet 寫 POST /records {template:'triplet'}。
|
||||
// 新實例若無此 template 回 400「template not found: triplet」→ 三元組全滅。
|
||||
// slots 來源:kbdb_list_templates 核實(2026-07-19,library-map.test.ts PROD_TRIPLET_SLOTS)
|
||||
// + library(library-map.ts M1 預案:recompute 歸庫用,ensurePortalTemplates 若缺則 PATCH 補入)。
|
||||
name: 'triplet',
|
||||
description: 'KBDB 知識圖譜三元組(kbdb-graph-plugin 寫入;portal 讀此 template 建鄰接圖)',
|
||||
slots: [
|
||||
'subject', 'predicate', 'object',
|
||||
'source_block_id', 'confidence', 'clusters_json',
|
||||
'bridge_score', 'subject_entity_type', 'object_entity_type',
|
||||
'status', 'superseded_by',
|
||||
'source_uri', 'content_hash', 'source_anchor', 'predicate_embed',
|
||||
'library',
|
||||
],
|
||||
created_by: 'system',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -66,7 +66,7 @@ function mockListByTemplate(template: string, records: { record_id: string; valu
|
||||
}
|
||||
|
||||
function mockTemplatesExist() {
|
||||
for (const name of ['portal_user', 'portal_library']) {
|
||||
for (const name of ['portal_user', 'portal_library', 'triplet']) {
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: `/templates/${name}`, method: 'GET' })
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import { SELF, env, fetchMock } from 'cloudflare:test';
|
||||
import { beforeAll, beforeEach, afterEach, describe, it, expect } from 'vitest';
|
||||
import { hashPassword, verifyPassword, PBKDF2_ITERATIONS } from '../src/lib/portal-auth';
|
||||
import { PORTAL_TEMPLATE_SEEDS } from '../src/lib/portal-seeds';
|
||||
|
||||
const KBDB = 'https://kbdb.test';
|
||||
const NS = 'leo::portal'; // wrangler.test.toml CONSOLE_TENANT=leo → 子 namespace
|
||||
@@ -73,7 +74,7 @@ function mockListByTemplate(template: string, records: { record_id: string; valu
|
||||
}
|
||||
|
||||
function mockTemplatesExist() {
|
||||
for (const name of ['portal_user', 'portal_library']) {
|
||||
for (const name of ['portal_user', 'portal_library', 'triplet']) {
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: `/templates/${name}`, method: 'GET' })
|
||||
@@ -414,3 +415,52 @@ describe('admin 端點 role 閘', () => {
|
||||
expect(res.status).toBe(404);
|
||||
});
|
||||
});
|
||||
|
||||
// ═══════════════ t130 — triplet template seed ═══════════════
|
||||
|
||||
describe('t130 — triplet template seed(PORTAL_TEMPLATE_SEEDS 補 triplet,ensurePortalTemplates 冪等)', () => {
|
||||
it('PORTAL_TEMPLATE_SEEDS 含 triplet 且必要 slots 齊備(pure data)', () => {
|
||||
const seed = PORTAL_TEMPLATE_SEEDS.find((s) => s.name === 'triplet');
|
||||
expect(seed).toBeDefined();
|
||||
for (const slot of ['subject', 'predicate', 'object', 'source_uri', 'status', 'library']) {
|
||||
expect(seed!.slots).toContain(slot);
|
||||
}
|
||||
});
|
||||
|
||||
it('POST /init/seed — triplet 已存 → existing(冪等,不重建)', async () => {
|
||||
for (const name of ['portal_user', 'portal_library', 'triplet']) {
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: `/templates/${name}`, method: 'GET' })
|
||||
.reply(200, { success: true, template: { id: `tpl-${name}`, name } });
|
||||
}
|
||||
const res = await SELF.fetch('http://localhost/init/seed', { method: 'POST' });
|
||||
expect(res.status).toBe(200);
|
||||
const data = (await res.json()) as { portal_templates: { created: string[]; existing: string[] } };
|
||||
expect(data.portal_templates.existing).toContain('triplet');
|
||||
expect(data.portal_templates.created).not.toContain('triplet');
|
||||
});
|
||||
|
||||
it('POST /init/seed — triplet 缺 → 自動補建(新實例首次 seed)', async () => {
|
||||
for (const name of ['portal_user', 'portal_library']) {
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: `/templates/${name}`, method: 'GET' })
|
||||
.reply(200, { success: true, template: { id: `tpl-${name}`, name } });
|
||||
}
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: '/templates/triplet', method: 'GET' })
|
||||
.reply(404, { success: false, error: 'template not found: triplet' });
|
||||
fetchMock
|
||||
.get(KBDB)
|
||||
.intercept({ path: '/templates', method: 'POST' })
|
||||
.reply(200, { success: true, template: { id: 'tpl-triplet-new', name: 'triplet' } });
|
||||
|
||||
const res = await SELF.fetch('http://localhost/init/seed', { method: 'POST' });
|
||||
expect(res.status).toBe(200);
|
||||
const data = (await res.json()) as { portal_templates: { created: string[]; existing: string[] } };
|
||||
expect(data.portal_templates.created).toContain('triplet');
|
||||
expect(data.portal_templates.existing).not.toContain('triplet');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -254,6 +254,21 @@
|
||||
- rag_chat:question ✅;namespace/kbdb_base 未核實(rag_chat workflow yaml 在 arcrun-rag,非本 repo)
|
||||
- takedown:不在 portal-data.ts,在 arcrun-rag 端(dashboard/安裝器),超出本 repo 範圍
|
||||
|
||||
- [x] **t130 新實例缺 triplet template → 總圖永遠空(2026-07-29,任務層小改)**:
|
||||
真因:`PORTAL_TEMPLATE_SEEDS` 只有 `portal_user`+`portal_library`;`rag_ingest_card.post_triplet`
|
||||
打 `POST /records {template:'triplet'}` → 新實例回 400「template not found: triplet」→ 三元組全滅。
|
||||
修:`portal-seeds.ts` 補 `triplet` seed(slots 來源:2026-07-19 kbdb_list_templates 核實 15 槽 + library)。
|
||||
呼叫路徑驗證(`ensurePortalTemplates` 全四掛點):
|
||||
① `POST /init/seed`(acr init 觸發)← 主線,新裝必經
|
||||
② `POST /portal/admin/bootstrap`(首次 admin 設定)
|
||||
③ `POST /portal/daemon/libraries`(daemon 登記資料夾→庫)
|
||||
④ `POST /portal/admin/libraries`(admin 手動新增庫)
|
||||
既有壞實例補救:任一掛點重跑即補建(冪等),e.g. 重跑 acr init 或 bootstrap。
|
||||
執行範圍:`cypher-executor/src/lib/portal-seeds.ts`(新增 triplet seed);
|
||||
`cypher-executor/tests/portal-auth.test.ts`(mockTemplatesExist 補 triplet + t130 3 條新測試);
|
||||
`cypher-executor/tests/portal-admin.test.ts`(mockTemplatesExist 補 triplet)。
|
||||
測試:純資料驗證(seed 含 triplet + 必要 slots)+冪等驗(已存→existing)+自動補建(404→POST→created)。
|
||||
|
||||
- [x] **t129 AI 問答出處重複一整頁——後端按 page_name 去重(2026-07-29,任務層小改)**:
|
||||
診斷:一張卡拆成 3-5 block,每 block 各回一筆 source(同 page_name)→ 前端列一整頁重複。
|
||||
選後端修(/portal/data/chat)理由:出處去重是資料清潔,跟前端渲染無關;改後端不需動 HTML。
|
||||
|
||||
Reference in New Issue
Block a user