import React, { useState } from 'react'; import { Link, useParams } from 'react-router-dom'; import { useApi } from '../hooks/useApi'; import { getMemoryProvenance, type LoreProvenance, type SupersessionLink } from '../api/lore'; function formatDate(ts: string): string { if (!ts) return 'β€”'; const d = new Date(ts); return Number.isNaN(d.getTime()) ? ts : d.toLocaleString(); } function TrustBadge({ signal }: { signal: string }): React.ReactElement { const owned = signal === 'owned'; return ( {owned ? 'πŸ”’ Owned' : 'πŸ‘€ Anonymous'} ); } function MetaRow({ label, children }: { label: string; children: React.ReactNode }): React.ReactElement { return (
{label} {children}
); } function LinkRow({ link, view }: { link: SupersessionLink; view: 'chain' | 'sources' }): React.ReactElement { // chain: this memory was superseded BY supersededBy (the successor, β†’). // sources: memoryId is the source memory consolidated INTO this one (←). const targetId = view === 'chain' ? link.supersededBy : link.memoryId; const arrow = view === 'chain' ? 'β†’' : '←'; return (
{link.agent}

{link.reason || (no reason)}

{formatDate(link.ts)} {targetId && ( <> {` Β· ${arrow} `} {targetId} )}

); } export function MemoryProvenance(): React.ReactElement { const { id } = useParams<{ id: string }>(); const prov = useApi(() => getMemoryProvenance(id!), [id]); const [view, setView] = useState<'chain' | 'sources'>('chain'); return (
← Back to Memories
{prov.loading &&
Loading lineage…
} {!prov.loading && prov.error && (

Unable to load lineage

{prov.error}

)} {!prov.loading && !prov.error && !prov.data && (
Memory not found β€” or this Lore server predates the provenance endpoint (#82).
)} {prov.data && (() => { const p = prov.data; const links = view === 'chain' ? p.supersessionChain : p.supersessionSources; return ( <> {/* Header */}

Memory Provenance

{p.visibility} created {formatDate(p.createdAt)}

{p.id}

{/* Metadata */}
{p.owner ?? β€” (anonymous)} {p.source ?? β€”} {p.visibility} {p.tags.length ? ( {p.tags.map((t) => ( {t} ))} ) : ( β€” )} {p.redactionTags.length > 0 && ( {p.redactionTags.map((t) => ( ⚠ {t} ))} )}
{/* Lineage */}

{view === 'chain' ? 'Forward audit trail β€” what this memory was superseded by.' : 'Source memories this one consolidated.'}

{links.length === 0 ? (

No lineage recorded.

) : (
{links.map((l, i) => ( ))}
)}
); })()}
); }