// Match repository.WikiRecoveryFingerprints: UTF-8 fields framed by an unsigned // 64-bit big-endian byte length. Only digests leave the database. const framed = value => `int8send(octet_length(convert_to(coalesce(${value},''),'UTF8'))::bigint)||convert_to(coalesce(${value},''),'UTF8')` const framedArray = expression => `(SELECT string_agg(${framed('field')}, ''::bytea ORDER BY ordinal) FROM unnest(${expression}) WITH ORDINALITY AS fields(field,ordinal))` const textArray = fields => `ARRAY[${fields.join(',')}]::text[]` function recoveryFingerprintsSQL(source = 'd', kb = 'k', doc = 'n') { const fields = textArray(["'wiki-recovery-source-v1'", `${source}.tenant_id::text`, `${source}.scope_id`, `${source}.related_id`, `${doc}.title`]) const chunkFields = textArray(['c.id', 'c.content', "coalesce(c.content_revision,0)::text", "coalesce(c.chunk_index,0)::text", "coalesce(c.start_at,0)::text", "coalesce(c.end_at,0)::text", 'c.chunk_type', 'c.parent_chunk_id', 'c.image_info', "coalesce(c.is_enabled,false)::text"]) const configFields = textArray(["'wiki-recovery-model-v1'", `${kb}.wiki_config::text`, `${kb}.indexing_strategy::text`]) const modelFields = textArray(['m.id', 'm.name', 'm.type', 'm.source', 'm.status', 'm.parameters::text']) return { source: `encode(sha256(${framedArray(fields)} || coalesce((SELECT string_agg(${framedArray(chunkFields)}, ''::bytea ORDER BY c.id) FROM chunks c WHERE c.tenant_id=${source}.tenant_id AND c.knowledge_base_id=${source}.scope_id AND c.knowledge_id=${source}.related_id AND c.deleted_at IS NULL),''::bytea)),'hex')`, model: `encode(sha256(${framedArray(configFields)} || coalesce((SELECT string_agg(${framedArray(modelFields)}, ''::bytea ORDER BY wanted.ordinal) FROM unnest(ARRAY[coalesce(nullif(${kb}.wiki_config->>'synthesis_model_id',''),${kb}.summary_model_id),${kb}.embedding_model_id]) WITH ORDINALITY wanted(id,ordinal) JOIN models m ON m.id=wanted.id AND m.tenant_id=${source}.tenant_id AND m.deleted_at IS NULL WHERE wanted.id<>''),''::bytea)),'hex')`, } } module.exports = { recoveryFingerprintsSQL }