From 898bd336ccebdefb230bf0f8233f3710acce596c Mon Sep 17 00:00:00 2001 From: Sam Valladares Date: Thu, 2 Jul 2026 15:44:46 -0500 Subject: [PATCH] fix(dashboard): wire duplicates/contradictions/patterns to real APIs, remove mock data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The /duplicates, /contradictions, and /patterns routes shipped hardcoded mock data — and /duplicates rendered a "Live" badge over it. That is a launch credibility risk: a visitor who spots the canned data distrusts every real claim (including the CauseBench benchmark). Replaces the three mocks (mockFetchDuplicates, MOCK_CONTRADICTIONS, mockFetchCrossProject) with real dashboard HTTP endpoints backed by the existing core capabilities: - GET /api/duplicates -> dedup cluster detection - GET /api/contradictions -> trust-weighted contradiction analysis - GET /api/patterns/cross-project-> cross-project pattern transfer Adds the handlers (dashboard/handlers.rs), route registrations (dashboard/mod.rs), frontend api client methods + response types, and rewrites the three routes to fetch live. The "Live" badge is now truthful. Verified this session: - cargo build -p vestige-mcp: compiles - pnpm --filter @vestige/dashboard check: 905 files, 0 errors, 0 warnings - live backend on a 1073-memory DB returns real rows from all three endpoints Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/dashboard/src/lib/stores/api.ts | 26 + apps/dashboard/src/lib/types/index.ts | 101 +++ .../routes/(app)/contradictions/+page.svelte | 382 ++------- .../src/routes/(app)/duplicates/+page.svelte | 181 +--- .../src/routes/(app)/patterns/+page.svelte | 293 +------ crates/vestige-mcp/src/dashboard/handlers.rs | 791 ++++++++++++++++++ crates/vestige-mcp/src/dashboard/mod.rs | 11 + 7 files changed, 1024 insertions(+), 761 deletions(-) diff --git a/apps/dashboard/src/lib/stores/api.ts b/apps/dashboard/src/lib/stores/api.ts index 950ec99..dd5f095 100644 --- a/apps/dashboard/src/lib/stores/api.ts +++ b/apps/dashboard/src/lib/stores/api.ts @@ -6,6 +6,10 @@ import type { HealthCheck, TimelineResponse, GraphResponse, + DuplicatesResponse, + ContradictionsResponse, + CrossProjectPatternsResponse, + MemoryAuditResponse, DreamResult, ImportanceScore, RetentionDistribution, @@ -111,6 +115,28 @@ export const api = { retentionDistribution: () => fetcher('/retention-distribution'), + // Memory hygiene & provenance: duplicate clusters, contradiction pairs, + // cross-project pattern transfer, per-memory audit trail. + duplicates: (threshold = 0.8, limit = 20) => + fetcher(`/duplicates?threshold=${threshold}&limit=${limit}`), + + contradictions: (params?: { topic?: string; min_trust?: number; limit?: number }) => { + const qs = params + ? '?' + + new URLSearchParams( + Object.entries(params) + .filter(([, v]) => v !== undefined) + .map(([k, v]) => [k, String(v)]) + ).toString() + : ''; + return fetcher(`/contradictions${qs}`); + }, + + crossProjectPatterns: () => fetcher('/patterns/cross-project'), + + memoryAudit: (id: string, limit = 100) => + fetcher(`/memories/${encodeURIComponent(id)}/audit?limit=${limit}`), + // Intentions intentions: (status = 'active') => fetcher<{ intentions: IntentionItem[]; total: number; filter: string }>(`/intentions?status=${status}`), diff --git a/apps/dashboard/src/lib/types/index.ts b/apps/dashboard/src/lib/types/index.ts index 2989391..1673501 100644 --- a/apps/dashboard/src/lib/types/index.ts +++ b/apps/dashboard/src/lib/types/index.ts @@ -302,6 +302,107 @@ export interface IntentionItem { snoozed_until?: string | null; } +// Memory Hygiene — GET /api/duplicates (cosine-similarity clusters) +export interface DuplicateClusterMemory { + id: string; + content: string; + nodeType: string; + tags: string[]; + retention: number; + createdAt: string; +} + +export interface DuplicateClusterGroup { + similarity: number; + suggestedAction: 'merge' | 'review'; + memories: DuplicateClusterMemory[]; +} + +export interface DuplicatesResponse { + threshold: number; + total: number; + clusters: DuplicateClusterGroup[]; +} + +// Contradiction pairs — GET /api/contradictions. Field names mirror the +// Contradiction interface in $components/ContradictionArcs.svelte; a = older +// memory, b = newer. Sorted by similarity desc. +export interface ContradictionPair { + memory_a_id: string; + memory_b_id: string; + memory_a_preview: string; + memory_b_preview: string; + memory_a_type?: string; + memory_b_type?: string; + memory_a_created?: string; + memory_b_created?: string; + memory_a_tags?: string[]; + memory_b_tags?: string[]; + trust_a: number; + trust_b: number; + similarity: number; + date_diff_days: number; + topic: string; +} + +export interface ContradictionsResponse { + memoriesAnalyzed: number; + total: number; + contradictions: ContradictionPair[]; +} + +// Cross-project pattern transfer — GET /api/patterns/cross-project. +// Only the six tracked categories ever cross the wire (backend drops others). +export type CrossProjectCategory = + | 'ErrorHandling' + | 'AsyncConcurrency' + | 'Testing' + | 'Architecture' + | 'Performance' + | 'Security'; + +export interface CrossProjectPattern { + name: string; + category: CrossProjectCategory; + origin_project: string; + transferred_to: string[]; + transfer_count: number; + last_used: string; + confidence: number; +} + +export interface CrossProjectPatternsResponse { + projects: string[]; + patterns: CrossProjectPattern[]; +} + +// Per-memory audit trail — GET /api/memories/{id}/audit. Events arrive +// newest-first; the action union matches AuditAction in +// $components/audit-trail-helpers.ts. +export type MemoryAuditAction = + | 'created' + | 'accessed' + | 'promoted' + | 'demoted' + | 'edited' + | 'suppressed' + | 'dreamed' + | 'reconsolidated'; + +export interface MemoryAuditEvent { + action: MemoryAuditAction; + timestamp: string; // RFC3339 + old_value?: number; + new_value?: number; + reason?: string; + triggered_by?: string; +} + +export interface MemoryAuditResponse { + memoryId: string; + events: MemoryAuditEvent[]; +} + // Node type colors for visualization — bioluminescent palette export const NODE_TYPE_COLORS: Record = { fact: '#00A8FF', // electric blue diff --git a/apps/dashboard/src/routes/(app)/contradictions/+page.svelte b/apps/dashboard/src/routes/(app)/contradictions/+page.svelte index 4415f0e..5373045 100644 --- a/apps/dashboard/src/routes/(app)/contradictions/+page.svelte +++ b/apps/dashboard/src/routes/(app)/contradictions/+page.svelte @@ -1,10 +1,12 @@