Files
kbdb-graph-plugin/src/actions/entity-pending.ts
T
Claude 4190fbcf90 feat(graph): owner_id 寫入鏈必經(根治無主資料)——配合 base owner-mandatory(D28)
- kbdb-client requireOwner 守衛:漏 owner 插件端即 throw,不再靜默送 owner:''
- owner 一路 thread:persistNodes/ingestEnvelope/entity-crud/triplet-crud 全必填
- 病灶修:POST /triplets/ingest 原本沒傳 owner→加 owner_id query+400
- 寫入 route 缺 owner→400;vitest 23→27
- 註:gloss-bridge 分支的 backfill/gloss-entry 另需套 owner 必填(附說明),不跨支疊改
2026-07-05 11:00:30 +00:00

71 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Pending Alias — 零 SQL / 零 D1。全走基本盤 APItemplate=entity_pending record)。
//
// base 缺口 [→arcrun]:無 DELETE /records/:id → pending record 無法硬刪。
// confirm/reject 採 soft:執行動作但不刪 pending(待 base 補 DELETE)。
// 故 getPendingAliases 須由 caller 自行過濾已處理者,或待 DELETE 補上後在此硬刪。
import type { Entity, PendingAlias } from '../types';
import type { KbdbClient } from '../lib/kbdb-client';
import { TPL_ENTITY_PENDING, ensurePluginTemplates } from '../lib/templates';
import { createEntity, addAlias } from './entity-crud';
/** 建立 Pending Alias 記錄(一筆 entity_pending record)。 */
export async function createPendingAlias(
client: KbdbClient,
rawName: string,
candidateEntityId: string,
candidateCanonical: string,
similarity: number,
owner: string, // 必經:pending record 也不可無主
): Promise<PendingAlias> {
await ensurePluginTemplates(client);
const id = await client.createRecord(
TPL_ENTITY_PENDING,
{
raw_name: rawName,
candidate_entity_id: candidateEntityId,
candidate_canonical: candidateCanonical,
similarity: String(similarity),
},
owner, // 必經:createRecord 內 requireOwner 守衛
);
return {
id,
raw_name: rawName,
candidate_entity_id: candidateEntityId,
candidate_canonical: candidateCanonical,
similarity,
created_at: Math.floor(Date.now() / 1000),
};
}
/** 列出所有 Pending Aliases。 */
export async function getPendingAliases(client: KbdbClient, limit = 100, owner?: string): Promise<PendingAlias[]> {
const records = await client.listRecordsByTemplate(TPL_ENTITY_PENDING, owner);
return records
.filter((r) => r.values.raw_name)
.map((r) => ({
id: r.record_id,
raw_name: r.values.raw_name,
candidate_entity_id: r.values.candidate_entity_id ?? '',
candidate_canonical: r.values.candidate_canonical ?? '',
similarity: parseFloat(r.values.similarity ?? '0'),
created_at: 0,
}))
.slice(0, limit);
}
/** 確認 → addAlias 到候選 entity。pending soft 保留([→arcrun] base 缺 DELETE record)。 */
export async function confirmPendingAlias(client: KbdbClient, pendingId: string, owner: string): Promise<void> {
const rec = await client.getRecord(pendingId);
if (!rec || !rec.values.raw_name) throw new Error(`Pending alias ${pendingId} not found`);
await addAlias(client, rec.values.candidate_entity_id, rec.values.raw_name, owner);
}
/** 拒絕 → 以 raw_name 建新 entity。pending soft 保留([→arcrun] base 缺 DELETE record)。 */
export async function rejectPendingAlias(client: KbdbClient, pendingId: string, owner: string): Promise<Entity> {
const rec = await client.getRecord(pendingId);
if (!rec || !rec.values.raw_name) throw new Error(`Pending alias ${pendingId} not found`);
return createEntity(client, rec.values.raw_name, owner);
}