From 9704e5df20f6bed968f9fdeb41dc756f72f80028 Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:02:01 +0800 Subject: [PATCH 01/11] Add Pandora dashboard truth loader --- lib/services/pandora-dashboard-service.ts | 296 ++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 lib/services/pandora-dashboard-service.ts diff --git a/lib/services/pandora-dashboard-service.ts b/lib/services/pandora-dashboard-service.ts new file mode 100644 index 0000000..39c1b36 --- /dev/null +++ b/lib/services/pandora-dashboard-service.ts @@ -0,0 +1,296 @@ +import type { PandoraDashboardData, DashboardStatData, MemorySpace, SystemRow, TimelineEventData, WorkQueueData, ProfileSnapshot } from "@/components/pandora/types"; + +export type PandoraDashboardNamespace = "real_life" | "au"; + +type QueryResult = Promise<{ data: T[] | null; error: { message: string } | null }>; +type PandoraQuery = { + select: (columns?: string, options?: unknown) => PandoraQuery; + eq: (column: string, value: unknown) => PandoraQuery; + order: (column: string, options?: unknown) => PandoraQuery; + limit: (count: number) => PandoraQuery; + then?: QueryResult["then"]; +}; +export type PandoraDashboardDbClient = { from: >(table: string) => PandoraQuery }; + +type MemoryEventRow = { + id: string; + user_id: string; + namespace: PandoraDashboardNamespace; + source?: string | null; + raw_text?: string | null; + extracted_summary?: string | null; + importance?: number | null; + sensitivity?: string | null; + status: string; + created_at?: string | null; + updated_at?: string | null; +}; + +type ContextPackRow = { + id: string; + user_id: string; + namespace: PandoraDashboardNamespace; + pack_type: string; + title?: string | null; + summary?: string | null; + key_points?: unknown[] | null; + active_projects?: unknown[] | null; + people_map?: unknown[] | null; + decisions?: unknown[] | null; + risks?: unknown[] | null; + open_loops?: unknown[] | null; + generated_from_event_ids?: unknown[] | null; + status: "active" | "superseded" | "archived"; + created_at?: string | null; + updated_at?: string | null; +}; + +type MemoryProfileRow = { + id: string; + user_id: string; + namespace: PandoraDashboardNamespace; + profile_type?: string | null; + subject_key?: string | null; + title?: string | null; + summary?: string | null; + preferences?: unknown[] | null; + patterns?: unknown[] | null; + confidence?: number | string | null; + status?: string | null; + updated_at?: string | null; +}; + +type OpenLoopRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; +type CaptureCandidateRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null; requires_review?: boolean | null }; +type ReviewQueueRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; +type PruningCandidateRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; + +type NamespaceTruth = { + namespace: PandoraDashboardNamespace; + events: MemoryEventRow[]; + packs: ContextPackRow[]; + profiles: MemoryProfileRow[]; + openLoops: OpenLoopRow[]; + captureCandidates: CaptureCandidateRow[]; + reviewQueue: ReviewQueueRow[]; + pruningCandidates: PruningCandidateRow[]; +}; + +const NAMESPACES: PandoraDashboardNamespace[] = ["real_life", "au"]; + +function asArray(value: unknown): unknown[] { + return Array.isArray(value) ? value : []; +} + +function text(value: unknown, fallback = "") { + return typeof value === "string" && value.trim() ? value.trim() : fallback; +} + +function truncate(value: string, max = 180) { + const cleaned = value.replace(/\s+/g, " ").trim(); + return cleaned.length > max ? `${cleaned.slice(0, max - 1)}…` : cleaned; +} + +function formatDate(value?: string | null) { + if (!value) return "No timestamp"; + const date = new Date(value); + if (Number.isNaN(date.getTime())) return "Invalid timestamp"; + return date.toISOString().slice(0, 16).replace("T", " ") + " UTC"; +} + +async function readRows>( + client: PandoraDashboardDbClient, + table: string, + userId: string, + namespace: PandoraDashboardNamespace | null, + warnings: string[], + options: { limit?: number; orderBy?: string } = {}, +): Promise { + let query = client.from(table).select("*").eq("user_id", userId); + if (namespace) query = query.eq("namespace", namespace); + if (options.orderBy) query = query.order(options.orderBy, { ascending: false }); + if (options.limit) query = query.limit(options.limit); + const result = await (query as unknown as QueryResult); + if (result.error) { + warnings.push(`${table}_read_failed: ${result.error.message}`); + return []; + } + return result.data ?? []; +} + +function countStatus(rows: Array<{ status?: string | null }>, statuses: string[]) { + return rows.filter((row) => row.status && statuses.includes(row.status)).length; +} + +function buildSpace(ns: NamespaceTruth): MemorySpace { + const activeMasterPacks = ns.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active"); + const newestMaster = activeMasterPacks[0] ?? ns.packs.find((pack) => pack.pack_type === "master"); + const peopleCount = asArray(newestMaster?.people_map).length; + const projectCount = asArray(newestMaster?.active_projects).length; + const status: MemorySpace["status"] = activeMasterPacks.length === 1 ? "Active" : "Degraded"; + const type = ns.namespace === "real_life" ? "Primary Space" : "Isolated Space"; + const description = newestMaster + ? `${text(newestMaster.title, "Context pack")} • ${newestMaster.status} • ${formatDate(newestMaster.updated_at ?? newestMaster.created_at)}` + : "No active master context pack returned by the authenticated read."; + return { + id: ns.namespace, + label: ns.namespace, + type, + description, + memories: ns.events.length, + people: peopleCount, + projects: projectCount, + status, + color: ns.namespace === "real_life" ? "emerald" : "purple", + }; +} + +function buildProfile(namespaces: NamespaceTruth[]): ProfileSnapshot { + const profiles = namespaces.flatMap((ns) => ns.profiles).filter((profile) => profile.status === "active" || !profile.status); + const profile = profiles.find((row) => row.profile_type === "operating_profile" && row.subject_key === "global") ?? profiles[0]; + if (!profile) { + return { + name: "No active profile", + status: "Live read", + confidencePercent: 0, + confidenceLabel: "N/A", + summary: "No active adaptive profile returned for this session.", + lastRefreshed: "No profile timestamp returned", + traits: ["Authenticated", "RLS scoped", "No profile row"], + evidence: "Live dashboard read complete • profile table returned no active operating profile", + }; + } + const confidence = Number(profile.confidence ?? 0); + const percent = Number.isFinite(confidence) ? Math.round(Math.max(0, Math.min(1, confidence)) * 100) : 0; + const preferences = asArray(profile.preferences).slice(0, 3).map((item, index) => { + if (item && typeof item === "object" && "text" in item) return truncate(String((item as { text?: unknown }).text ?? `Preference ${index + 1}`), 36); + return truncate(String(item), 36); + }); + const patterns = asArray(profile.patterns).slice(0, 2).map((item, index) => { + if (item && typeof item === "object" && "text" in item) return truncate(String((item as { text?: unknown }).text ?? `Pattern ${index + 1}`), 36); + return truncate(String(item), 36); + }); + return { + name: text(profile.title, text(profile.profile_type, "Adaptive Profile")), + status: "Live read", + confidencePercent: percent, + confidenceLabel: percent ? `${percent}%` : "N/A", + summary: text(profile.summary, "Active profile returned without a summary."), + lastRefreshed: `Updated ${formatDate(profile.updated_at)}`, + traits: [...preferences, ...patterns].length ? [...preferences, ...patterns] : [profile.namespace, text(profile.subject_key, "global")], + evidence: `Live profile row ${profile.id} • ${profile.namespace} • request scoped to authenticated user`, + }; +} + +function buildTimeline(namespaces: NamespaceTruth[]): TimelineEventData[] { + const events = namespaces + .flatMap((ns) => ns.events.map((event) => ({ ...event, namespace: ns.namespace }))) + .sort((a, b) => String(b.created_at ?? "").localeCompare(String(a.created_at ?? ""))) + .slice(0, 6); + + if (!events.length) { + return [{ id: "no-events", title: "No recent memory events", time: "Live read", desc: "The authenticated read returned no memory events for this user.", namespace: "real_life", color: "slate" }]; + } + + return events.map((event) => ({ + id: event.id, + title: `${event.namespace} • ${event.status}`, + time: formatDate(event.created_at), + desc: truncate(text(event.extracted_summary, text(event.raw_text, "No summary available"))), + namespace: event.namespace, + color: event.namespace === "real_life" ? "emerald" : "purple", + })); +} + +function buildStats(namespaces: NamespaceTruth[], duplicateMasterCount: number, openLoopCount: number, reviewCount: number): DashboardStatData[] { + const events = namespaces.flatMap((ns) => ns.events); + const activeMasters = namespaces.flatMap((ns) => ns.packs).filter((pack) => pack.pack_type === "master" && pack.status === "active"); + const promoted = countStatus(events, ["promoted", "reviewed"]); + return [ + { id: "events", title: "Memory Events", value: String(events.length), subtitle: "Authenticated RLS-scoped rows", color: "indigo", sparklineData: NAMESPACES.map((namespace) => namespaces.find((ns) => ns.namespace === namespace)?.events.length ?? 0) }, + { id: "packs", title: "Active Master Packs", value: String(activeMasters.length), subtitle: duplicateMasterCount ? `${duplicateMasterCount} duplicate active pack(s)` : "One-per-namespace invariant OK", color: duplicateMasterCount ? "amber" : "emerald", sparklineData: NAMESPACES.map((namespace) => namespaces.find((ns) => ns.namespace === namespace)?.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length ?? 0) }, + { id: "reviewed", title: "Reviewed/Promoted", value: String(promoted), subtitle: "From memory_events status", color: "blue", sparklineData: [0, promoted] }, + { id: "loops", title: "Open Loops", value: String(openLoopCount), subtitle: "From memory_open_loops", color: openLoopCount ? "amber" : "slate", sparklineData: [0, openLoopCount] }, + { id: "retrieval", title: "Retrieval Eval", value: "Gated", subtitle: "No accuracy claim without eval route", color: "amber", sparklineData: [0, 0, 0, 0, 0] }, + { id: "queue", title: "Review Queue", value: String(reviewCount), subtitle: "Pending review/candidate rows", color: reviewCount ? "amber" : "slate", sparklineData: [0, reviewCount] }, + ]; +} + +function buildDiagnostics(duplicateMasterCount: number, warnings: string[]): { coreSystems: SystemRow[]; gatedSystems: SystemRow[]; envelope: { title: string; description: string } } { + return { + coreSystems: [ + { label: "Route exposure", value: "Auth gated", state: "healthy" }, + { label: "Displayed data", value: "Live RLS reads", state: warnings.length ? "attention" : "healthy" }, + { label: "Master-pack invariant", value: duplicateMasterCount ? `${duplicateMasterCount} duplicate` : "OK", state: duplicateMasterCount ? "attention" : "healthy" }, + { label: "Client user_id", value: "Rejected", state: "healthy" }, + ], + gatedSystems: [ + { label: "Semantic retrieval", value: "Gated Off", state: "gated" }, + { label: "Embeddings", value: "Gated Off", state: "gated" }, + { label: "Model calls", value: "Gated Off", state: "gated" }, + { label: "Pruning automation", value: "Review-only", state: "gated" }, + ], + envelope: { + title: "Dashboard Truth Envelope", + description: warnings.length ? `Live loader completed with ${warnings.length} warning(s).` : "Live loader completed from authenticated Supabase reads; no service-role dashboard read and no mock counts.", + }, + }; +} + +export async function loadPandoraDashboardData(client: PandoraDashboardDbClient, input: { userId: string; operatorLabel?: string }): Promise { + const warnings: string[] = []; + const namespaces: NamespaceTruth[] = []; + + for (const namespace of NAMESPACES) { + const [events, packs, profiles, openLoops, captureCandidates, reviewQueue, pruningCandidates] = await Promise.all([ + readRows(client, "memory_events", input.userId, namespace, warnings, { limit: 500, orderBy: "created_at" }), + readRows(client, "memory_context_packs", input.userId, namespace, warnings, { limit: 50, orderBy: "created_at" }), + readRows(client, "memory_profiles", input.userId, namespace, warnings, { limit: 20, orderBy: "updated_at" }), + readRows(client, "memory_open_loops", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), + readRows(client, "memory_capture_candidates", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), + readRows(client, "memory_review_queue_items", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), + readRows(client, "memory_pruning_candidates", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), + ]); + namespaces.push({ namespace, events, packs, profiles, openLoops, captureCandidates, reviewQueue, pruningCandidates }); + } + + const openLoopCount = namespaces.reduce((sum, ns) => sum + countStatus(ns.openLoops, ["open", "acknowledged"]), 0); + const needsReview = namespaces.reduce((sum, ns) => sum + + ns.captureCandidates.filter((row) => row.status === "pending" || row.requires_review === true).length + + countStatus(ns.reviewQueue, ["pending_review", "needs_clarification"]), 0); + const pruningReview = namespaces.reduce((sum, ns) => sum + countStatus(ns.pruningCandidates, ["open"]), 0); + const duplicateMasterCount = namespaces.reduce((sum, ns) => { + const activeMasters = ns.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length; + return sum + Math.max(0, activeMasters - 1); + }, 0); + + const workQueue: WorkQueueData = { + needsReview, + openLoops: openLoopCount, + stalePacks: pruningReview, + failedTests: warnings.length, + profileRefreshDue: namespaces.some((ns) => ns.profiles.length === 0) ? 1 : 0, + packSupersessionNeeded: duplicateMasterCount, + peopleMapDesignNeeded: 0, + }; + + return { + generatedAt: new Date().toISOString(), + operatorLabel: input.operatorLabel ?? input.userId, + live: true, + warnings, + hero: { + title: "Pandora dashboard is reading live memory state.", + description: "This route now renders authenticated, RLS-scoped Supabase data for context packs, events, profiles, open loops, and review queues. Gated intelligence features still stay explicit.", + primaryAction: "Context pack data live", + secondaryAction: "Retrieval eval still gated", + }, + evidence: warnings.length ? `Live read completed with warnings • ${warnings.join(" • ")}` : "Live RLS-scoped dashboard read • no mock counts • no service-role dashboard read", + stats: buildStats(namespaces, duplicateMasterCount, openLoopCount, needsReview + pruningReview), + memorySpaces: namespaces.map(buildSpace), + workQueue, + profileSnapshot: buildProfile(namespaces), + timelineEvents: buildTimeline(namespaces), + diagnostics: buildDiagnostics(duplicateMasterCount, warnings), + }; +} From 6299187ac6f729cd3c8b1c2b81b2743082b5c88b Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:02:16 +0800 Subject: [PATCH 02/11] Add live Pandora dashboard data types --- components/pandora/types.ts | 55 +++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/components/pandora/types.ts b/components/pandora/types.ts index 4eb1ed0..17ab35c 100644 --- a/components/pandora/types.ts +++ b/components/pandora/types.ts @@ -2,17 +2,20 @@ import type { LucideIcon } from "lucide-react"; export type ColorKey = "emerald" | "indigo" | "blue" | "amber" | "purple" | "red" | "slate"; -export type StatItem = { +export type DashboardStatData = { id: string; title: string; value: string; subtitle: string; trend?: string; - icon: LucideIcon; color: ColorKey; sparklineData: number[]; }; +export type StatItem = DashboardStatData & { + icon: LucideIcon; +}; + export type MemorySpace = { id: "real_life" | "au"; label: string; @@ -25,13 +28,17 @@ export type MemorySpace = { color: ColorKey; }; -export type TimelineEvent = { +export type TimelineEventData = { id: string; - icon: LucideIcon; - color: ColorKey; title: string; time: string; desc: string; + namespace: "real_life" | "au"; + color: ColorKey; +}; + +export type TimelineEvent = TimelineEventData & { + icon: LucideIcon; }; export type WorkQueueData = { @@ -49,3 +56,41 @@ export type SystemRow = { value: string; state: "healthy" | "gated" | "attention" | "idle"; }; + +export type ProfileSnapshot = { + name: string; + status: string; + confidencePercent: number; + confidenceLabel: string; + summary: string; + lastRefreshed: string; + traits: string[]; + evidence: string; +}; + +export type PandoraDashboardData = { + generatedAt: string; + operatorLabel: string; + live: boolean; + warnings: string[]; + hero: { + title: string; + description: string; + primaryAction: string; + secondaryAction: string; + }; + evidence: string; + stats: DashboardStatData[]; + memorySpaces: MemorySpace[]; + workQueue: WorkQueueData; + profileSnapshot: ProfileSnapshot; + timelineEvents: TimelineEventData[]; + diagnostics: { + coreSystems: SystemRow[]; + gatedSystems: SystemRow[]; + envelope: { + title: string; + description: string; + }; + }; +}; From 7b40a5aa9f12144f430bdbdb41f2a1c1e2cd61a2 Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:02:34 +0800 Subject: [PATCH 03/11] Wire Pandora page to live dashboard loader --- app/pandora/page.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/pandora/page.tsx b/app/pandora/page.tsx index f1d2765..444b903 100644 --- a/app/pandora/page.tsx +++ b/app/pandora/page.tsx @@ -5,6 +5,8 @@ import { SectionCard } from "@/components/ui/section-card"; import { StatusBadge } from "@/components/ui/status-badge"; import { PandoraDashboard } from "@/components/pandora/PandoraDashboard"; import { resolvePandoraServerSession } from "@/lib/auth/pandora-server-session-resolver"; +import { createSupabaseServerClient } from "@/lib/supabase/server"; +import { loadPandoraDashboardData, type PandoraDashboardDbClient } from "@/lib/services/pandora-dashboard-service"; export const dynamic = "force-dynamic"; @@ -27,7 +29,7 @@ export default async function PandoraPage() {

Unauthenticated request blocked

-

Use a server-visible Supabase session before opening the Pandora dashboard. The dashboard remains mock-only even after login until backed by real routes, schema, RLS, and tests.

+

Use a server-visible Supabase session before opening the Pandora dashboard. Dashboard reads are server-derived and reject client-supplied user_id values.

{session.blockers.map((blocker) => ( {blocker.message} @@ -46,5 +48,11 @@ export default async function PandoraPage() { ); } - return ; + const supabase = await createSupabaseServerClient(); + const dashboardData = await loadPandoraDashboardData(supabase as unknown as PandoraDashboardDbClient, { + userId: session.session.userId, + operatorLabel: session.session.email ?? session.session.userId, + }); + + return ; } From c34b85f0934fbdf4d00aabd9365677c287682589 Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:02:49 +0800 Subject: [PATCH 04/11] Render Pandora dashboard from live loader data --- components/pandora/PandoraDashboard.tsx | 57 ++++++++++++++++++------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/components/pandora/PandoraDashboard.tsx b/components/pandora/PandoraDashboard.tsx index de6ff34..26ac72f 100644 --- a/components/pandora/PandoraDashboard.tsx +++ b/components/pandora/PandoraDashboard.tsx @@ -1,40 +1,67 @@ "use client"; -import { useEffect, useState } from "react"; +import { AlertCircle, BadgeCheck, Boxes, GitMerge, ListChecks, Package, RefreshCcw, ShieldCheck, Target, UserRoundSearch, Users } from "lucide-react"; import { AskPandoraHero } from "./AskPandoraHero"; import { AdaptiveProfileCard } from "./AdaptiveProfileCard"; import { DiagnosticsCard } from "./DiagnosticsCard"; import { MemorySpacesCard } from "./MemorySpacesCard"; import { MobileBottomNav } from "./MobileBottomNav"; -import { mockStats, workQueue } from "./mock-data"; import { RecentEventsTimeline } from "./RecentEventsTimeline"; import { Sidebar } from "./Sidebar"; import { StatCard } from "./StatCard"; import { TopBar } from "./TopBar"; import { WorkQueueCard } from "./WorkQueueCard"; +import type { DashboardStatData, PandoraDashboardData, StatItem } from "./types"; +import { useState } from "react"; -export function PandoraDashboard({ operatorLabel: _operatorLabel }: { operatorLabel?: string } = {}) { - const [activeNav, setActiveNav] = useState("Dashboard"); - const [isSimulatingLoad, setIsSimulatingLoad] = useState(true); +const statIcons = { + events: Boxes, + packs: Package, + reviewed: BadgeCheck, + loops: RefreshCcw, + retrieval: Target, + queue: ListChecks, + health: ShieldCheck, + profiles: Users, + supersede: GitMerge, + attention: AlertCircle, + people: UserRoundSearch, +} as const; + +function withIcon(stat: DashboardStatData): StatItem { + const Icon = statIcons[stat.id as keyof typeof statIcons] ?? Package; + return { ...stat, icon: Icon }; +} - useEffect(() => { - const timer = window.setTimeout(() => setIsSimulatingLoad(false), 900); - return () => window.clearTimeout(timer); - }, []); +export function PandoraDashboard({ dashboardData }: { dashboardData: PandoraDashboardData }) { + const [activeNav, setActiveNav] = useState("Dashboard"); + const stats = dashboardData.stats.map(withIcon); return (
- +
-

Pandora Dashboard

Memory Command Center

Stable internal engine. Not productized. Ready for evals and pack supersession.

-
V0.4 StableEnvelope LiveSemantic Gated
+
+

Pandora Dashboard

+

Memory Command Center

+

Authenticated operator view. Live Supabase reads for memory state; gated intelligence stays explicit.

+
+
+ Live RLS Data + Envelope Proven + Semantic Gated +
- -
{mockStats.map((stat) => )}
-
+ +
{stats.map((stat) => )}
+
+
+ +
+
From 2e65e7136fec9f6bffeb9de5db69195eab28515f Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:04:27 +0800 Subject: [PATCH 05/11] Replace Pandora dashboard with live data implementation --- components/pandora/PandoraDashboard.tsx | 70 ------------------------- 1 file changed, 70 deletions(-) delete mode 100644 components/pandora/PandoraDashboard.tsx diff --git a/components/pandora/PandoraDashboard.tsx b/components/pandora/PandoraDashboard.tsx deleted file mode 100644 index 26ac72f..0000000 --- a/components/pandora/PandoraDashboard.tsx +++ /dev/null @@ -1,70 +0,0 @@ -"use client"; - -import { AlertCircle, BadgeCheck, Boxes, GitMerge, ListChecks, Package, RefreshCcw, ShieldCheck, Target, UserRoundSearch, Users } from "lucide-react"; -import { AskPandoraHero } from "./AskPandoraHero"; -import { AdaptiveProfileCard } from "./AdaptiveProfileCard"; -import { DiagnosticsCard } from "./DiagnosticsCard"; -import { MemorySpacesCard } from "./MemorySpacesCard"; -import { MobileBottomNav } from "./MobileBottomNav"; -import { RecentEventsTimeline } from "./RecentEventsTimeline"; -import { Sidebar } from "./Sidebar"; -import { StatCard } from "./StatCard"; -import { TopBar } from "./TopBar"; -import { WorkQueueCard } from "./WorkQueueCard"; -import type { DashboardStatData, PandoraDashboardData, StatItem } from "./types"; -import { useState } from "react"; - -const statIcons = { - events: Boxes, - packs: Package, - reviewed: BadgeCheck, - loops: RefreshCcw, - retrieval: Target, - queue: ListChecks, - health: ShieldCheck, - profiles: Users, - supersede: GitMerge, - attention: AlertCircle, - people: UserRoundSearch, -} as const; - -function withIcon(stat: DashboardStatData): StatItem { - const Icon = statIcons[stat.id as keyof typeof statIcons] ?? Package; - return { ...stat, icon: Icon }; -} - -export function PandoraDashboard({ dashboardData }: { dashboardData: PandoraDashboardData }) { - const [activeNav, setActiveNav] = useState("Dashboard"); - const stats = dashboardData.stats.map(withIcon); - - return ( -
- -
- -
-
-
-

Pandora Dashboard

-

Memory Command Center

-

Authenticated operator view. Live Supabase reads for memory state; gated intelligence stays explicit.

-
-
- Live RLS Data - Envelope Proven - Semantic Gated -
-
- -
{stats.map((stat) => )}
-
-
- -
-
-
-
- -
- ); -} From 703db68ea52e6427be9e9c1240f5a30b5cd1674c Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:04:58 +0800 Subject: [PATCH 06/11] Restore Pandora dashboard with live data view --- components/pandora/PandoraDashboard.tsx | 57 +++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 components/pandora/PandoraDashboard.tsx diff --git a/components/pandora/PandoraDashboard.tsx b/components/pandora/PandoraDashboard.tsx new file mode 100644 index 0000000..05b6fd2 --- /dev/null +++ b/components/pandora/PandoraDashboard.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { Package } from "lucide-react"; +import { MobileBottomNav } from "./MobileBottomNav"; +import { Sidebar } from "./Sidebar"; +import { StatCard } from "./StatCard"; +import { TopBar } from "./TopBar"; +import type { PandoraDashboardData, StatItem } from "./types"; +import { useState } from "react"; + +export function PandoraDashboard({ dashboardData }: { dashboardData: PandoraDashboardData }) { + const [activeNav, setActiveNav] = useState("Dashboard"); + const stats: StatItem[] = dashboardData.stats.map((stat) => ({ ...stat, icon: Package })); + + return ( +
+ +
+ +
+
+
+

Pandora Dashboard

+

Memory Command Center

+

Authenticated operator view backed by server-side Supabase reads for this session.

+
+
+ Live RLS Data + Semantic Gated +
+
+
+
+

Live Truth Boundary

+

{dashboardData.hero.title}

+

{dashboardData.hero.description}

+
+
{dashboardData.evidence}
+
+
+ {stats.map((stat) => )} +
+
+

Live Snapshot

Server scoped state

+
+
{dashboardData.memorySpaces.length}namespaces
+
{dashboardData.workQueue.openLoops}open loops
+
{dashboardData.workQueue.needsReview}needs review
+
+
{dashboardData.diagnostics.envelope.title}

{dashboardData.diagnostics.envelope.description}

+
+
+
+ +
+ ); +} From d352a475040ab6bf64a19b678699a6361ad24f93 Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:05:25 +0800 Subject: [PATCH 07/11] Add Pandora dashboard loader tests --- tests/unit/pandora-dashboard-service.test.ts | 80 ++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/unit/pandora-dashboard-service.test.ts diff --git a/tests/unit/pandora-dashboard-service.test.ts b/tests/unit/pandora-dashboard-service.test.ts new file mode 100644 index 0000000..ccca8f9 --- /dev/null +++ b/tests/unit/pandora-dashboard-service.test.ts @@ -0,0 +1,80 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { describe, expect, it } from "vitest"; +import { loadPandoraDashboardData } from "@/lib/services/pandora-dashboard-service"; + +type Row = Record; + +function makeClient(store: Record) { + return { + from(table: string) { + const eqs: Record = {}; + let limitN: number | undefined; + let orderBy: string | undefined; + const rows = () => { + let filtered = (store[table] ?? []).filter((row) => Object.entries(eqs).every(([key, value]) => row[key] === value)); + if (orderBy) filtered = [...filtered].sort((a, b) => String(b[orderBy!] ?? "").localeCompare(String(a[orderBy!] ?? ""))); + return limitN == null ? filtered : filtered.slice(0, limitN); + }; + const builder: any = { + select() { return builder; }, + eq(column: string, value: any) { eqs[column] = value; return builder; }, + order(column: string) { orderBy = column; return builder; }, + limit(count: number) { limitN = count; return builder; }, + then(resolve: any, reject: any) { return Promise.resolve({ data: rows(), error: null }).then(resolve, reject); }, + }; + return builder; + }, + } as any; +} + +const USER = "64110799-da61-445d-a7b3-57f3d0c7e411"; +const OTHER = "83a07d75-6b1f-4d93-aded-65540c9f73f2"; + +function baseStore(): Record { + return { + memory_events: [ + { id: "rl-1", user_id: USER, namespace: "real_life", status: "captured", raw_text: "real life only", created_at: "2026-07-03T10:00:00Z" }, + { id: "au-1", user_id: USER, namespace: "au", status: "reviewed", raw_text: "au only", created_at: "2026-07-03T11:00:00Z" }, + { id: "other-1", user_id: OTHER, namespace: "real_life", status: "captured", raw_text: "other user", created_at: "2026-07-03T12:00:00Z" }, + ], + memory_context_packs: [ + { id: "rl-pack", user_id: USER, namespace: "real_life", pack_type: "master", status: "active", title: "real master", active_projects: [{ id: "p" }], people_map: [], created_at: "2026-07-03T10:00:00Z" }, + { id: "au-pack", user_id: USER, namespace: "au", pack_type: "master", status: "active", title: "au master", active_projects: [], people_map: [{ name: "Known" }], created_at: "2026-07-03T11:00:00Z" }, + { id: "other-pack", user_id: OTHER, namespace: "real_life", pack_type: "master", status: "active", title: "other", created_at: "2026-07-03T12:00:00Z" }, + ], + memory_profiles: [ + { id: "profile", user_id: USER, namespace: "real_life", profile_type: "operating_profile", subject_key: "global", status: "active", title: "Operator", summary: "Live profile", confidence: 0.77, preferences: [{ text: "Use truth boundaries" }], updated_at: "2026-07-03T12:00:00Z" }, + ], + memory_open_loops: [{ id: "loop", user_id: USER, namespace: "real_life", status: "open" }], + memory_capture_candidates: [{ id: "cand", user_id: USER, namespace: "real_life", status: "pending", requires_review: true }], + memory_review_queue_items: [], + memory_pruning_candidates: [], + }; +} + +describe("loadPandoraDashboardData", () => { + it("loads only the authenticated user and keeps AU / real_life separated", async () => { + const data = await loadPandoraDashboardData(makeClient(baseStore()), { userId: USER, operatorLabel: "operator@example.com" }); + expect(data.operatorLabel).toBe("operator@example.com"); + expect(data.memorySpaces.find((space) => space.id === "real_life")?.memories).toBe(1); + expect(data.memorySpaces.find((space) => space.id === "au")?.memories).toBe(1); + expect(JSON.stringify(data)).not.toContain("other user"); + expect(JSON.stringify(data)).not.toContain(OTHER); + }); + + it("does not fabricate retrieval accuracy or fake operational counts", async () => { + const data = await loadPandoraDashboardData(makeClient(baseStore()), { userId: USER }); + const retrieval = data.stats.find((stat) => stat.id === "retrieval"); + expect(retrieval?.value).toBe("Gated"); + expect(JSON.stringify(data)).not.toContain("94.3"); + expect(JSON.stringify(data)).not.toContain("retrieval accuracy"); + }); + + it("surfaces active master duplicates as a supersession queue item", async () => { + const store = baseStore(); + store.memory_context_packs.push({ id: "rl-dup", user_id: USER, namespace: "real_life", pack_type: "master", status: "active", title: "duplicate", created_at: "2026-07-03T12:30:00Z" }); + const data = await loadPandoraDashboardData(makeClient(store), { userId: USER }); + expect(data.workQueue.packSupersessionNeeded).toBe(1); + expect(data.diagnostics.coreSystems.find((row) => row.label === "Master-pack invariant")?.state).toBe("attention"); + }); +}); From 07c42e02a9fb934d8fef35ec4713c5e37f4b855f Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:09:35 +0800 Subject: [PATCH 08/11] Simplify dashboard loader implementation --- lib/services/pandora-dashboard-service.ts | 296 ---------------------- 1 file changed, 296 deletions(-) delete mode 100644 lib/services/pandora-dashboard-service.ts diff --git a/lib/services/pandora-dashboard-service.ts b/lib/services/pandora-dashboard-service.ts deleted file mode 100644 index 39c1b36..0000000 --- a/lib/services/pandora-dashboard-service.ts +++ /dev/null @@ -1,296 +0,0 @@ -import type { PandoraDashboardData, DashboardStatData, MemorySpace, SystemRow, TimelineEventData, WorkQueueData, ProfileSnapshot } from "@/components/pandora/types"; - -export type PandoraDashboardNamespace = "real_life" | "au"; - -type QueryResult = Promise<{ data: T[] | null; error: { message: string } | null }>; -type PandoraQuery = { - select: (columns?: string, options?: unknown) => PandoraQuery; - eq: (column: string, value: unknown) => PandoraQuery; - order: (column: string, options?: unknown) => PandoraQuery; - limit: (count: number) => PandoraQuery; - then?: QueryResult["then"]; -}; -export type PandoraDashboardDbClient = { from: >(table: string) => PandoraQuery }; - -type MemoryEventRow = { - id: string; - user_id: string; - namespace: PandoraDashboardNamespace; - source?: string | null; - raw_text?: string | null; - extracted_summary?: string | null; - importance?: number | null; - sensitivity?: string | null; - status: string; - created_at?: string | null; - updated_at?: string | null; -}; - -type ContextPackRow = { - id: string; - user_id: string; - namespace: PandoraDashboardNamespace; - pack_type: string; - title?: string | null; - summary?: string | null; - key_points?: unknown[] | null; - active_projects?: unknown[] | null; - people_map?: unknown[] | null; - decisions?: unknown[] | null; - risks?: unknown[] | null; - open_loops?: unknown[] | null; - generated_from_event_ids?: unknown[] | null; - status: "active" | "superseded" | "archived"; - created_at?: string | null; - updated_at?: string | null; -}; - -type MemoryProfileRow = { - id: string; - user_id: string; - namespace: PandoraDashboardNamespace; - profile_type?: string | null; - subject_key?: string | null; - title?: string | null; - summary?: string | null; - preferences?: unknown[] | null; - patterns?: unknown[] | null; - confidence?: number | string | null; - status?: string | null; - updated_at?: string | null; -}; - -type OpenLoopRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; -type CaptureCandidateRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null; requires_review?: boolean | null }; -type ReviewQueueRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; -type PruningCandidateRow = { id: string; user_id: string; namespace: PandoraDashboardNamespace; status?: string | null }; - -type NamespaceTruth = { - namespace: PandoraDashboardNamespace; - events: MemoryEventRow[]; - packs: ContextPackRow[]; - profiles: MemoryProfileRow[]; - openLoops: OpenLoopRow[]; - captureCandidates: CaptureCandidateRow[]; - reviewQueue: ReviewQueueRow[]; - pruningCandidates: PruningCandidateRow[]; -}; - -const NAMESPACES: PandoraDashboardNamespace[] = ["real_life", "au"]; - -function asArray(value: unknown): unknown[] { - return Array.isArray(value) ? value : []; -} - -function text(value: unknown, fallback = "") { - return typeof value === "string" && value.trim() ? value.trim() : fallback; -} - -function truncate(value: string, max = 180) { - const cleaned = value.replace(/\s+/g, " ").trim(); - return cleaned.length > max ? `${cleaned.slice(0, max - 1)}…` : cleaned; -} - -function formatDate(value?: string | null) { - if (!value) return "No timestamp"; - const date = new Date(value); - if (Number.isNaN(date.getTime())) return "Invalid timestamp"; - return date.toISOString().slice(0, 16).replace("T", " ") + " UTC"; -} - -async function readRows>( - client: PandoraDashboardDbClient, - table: string, - userId: string, - namespace: PandoraDashboardNamespace | null, - warnings: string[], - options: { limit?: number; orderBy?: string } = {}, -): Promise { - let query = client.from(table).select("*").eq("user_id", userId); - if (namespace) query = query.eq("namespace", namespace); - if (options.orderBy) query = query.order(options.orderBy, { ascending: false }); - if (options.limit) query = query.limit(options.limit); - const result = await (query as unknown as QueryResult); - if (result.error) { - warnings.push(`${table}_read_failed: ${result.error.message}`); - return []; - } - return result.data ?? []; -} - -function countStatus(rows: Array<{ status?: string | null }>, statuses: string[]) { - return rows.filter((row) => row.status && statuses.includes(row.status)).length; -} - -function buildSpace(ns: NamespaceTruth): MemorySpace { - const activeMasterPacks = ns.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active"); - const newestMaster = activeMasterPacks[0] ?? ns.packs.find((pack) => pack.pack_type === "master"); - const peopleCount = asArray(newestMaster?.people_map).length; - const projectCount = asArray(newestMaster?.active_projects).length; - const status: MemorySpace["status"] = activeMasterPacks.length === 1 ? "Active" : "Degraded"; - const type = ns.namespace === "real_life" ? "Primary Space" : "Isolated Space"; - const description = newestMaster - ? `${text(newestMaster.title, "Context pack")} • ${newestMaster.status} • ${formatDate(newestMaster.updated_at ?? newestMaster.created_at)}` - : "No active master context pack returned by the authenticated read."; - return { - id: ns.namespace, - label: ns.namespace, - type, - description, - memories: ns.events.length, - people: peopleCount, - projects: projectCount, - status, - color: ns.namespace === "real_life" ? "emerald" : "purple", - }; -} - -function buildProfile(namespaces: NamespaceTruth[]): ProfileSnapshot { - const profiles = namespaces.flatMap((ns) => ns.profiles).filter((profile) => profile.status === "active" || !profile.status); - const profile = profiles.find((row) => row.profile_type === "operating_profile" && row.subject_key === "global") ?? profiles[0]; - if (!profile) { - return { - name: "No active profile", - status: "Live read", - confidencePercent: 0, - confidenceLabel: "N/A", - summary: "No active adaptive profile returned for this session.", - lastRefreshed: "No profile timestamp returned", - traits: ["Authenticated", "RLS scoped", "No profile row"], - evidence: "Live dashboard read complete • profile table returned no active operating profile", - }; - } - const confidence = Number(profile.confidence ?? 0); - const percent = Number.isFinite(confidence) ? Math.round(Math.max(0, Math.min(1, confidence)) * 100) : 0; - const preferences = asArray(profile.preferences).slice(0, 3).map((item, index) => { - if (item && typeof item === "object" && "text" in item) return truncate(String((item as { text?: unknown }).text ?? `Preference ${index + 1}`), 36); - return truncate(String(item), 36); - }); - const patterns = asArray(profile.patterns).slice(0, 2).map((item, index) => { - if (item && typeof item === "object" && "text" in item) return truncate(String((item as { text?: unknown }).text ?? `Pattern ${index + 1}`), 36); - return truncate(String(item), 36); - }); - return { - name: text(profile.title, text(profile.profile_type, "Adaptive Profile")), - status: "Live read", - confidencePercent: percent, - confidenceLabel: percent ? `${percent}%` : "N/A", - summary: text(profile.summary, "Active profile returned without a summary."), - lastRefreshed: `Updated ${formatDate(profile.updated_at)}`, - traits: [...preferences, ...patterns].length ? [...preferences, ...patterns] : [profile.namespace, text(profile.subject_key, "global")], - evidence: `Live profile row ${profile.id} • ${profile.namespace} • request scoped to authenticated user`, - }; -} - -function buildTimeline(namespaces: NamespaceTruth[]): TimelineEventData[] { - const events = namespaces - .flatMap((ns) => ns.events.map((event) => ({ ...event, namespace: ns.namespace }))) - .sort((a, b) => String(b.created_at ?? "").localeCompare(String(a.created_at ?? ""))) - .slice(0, 6); - - if (!events.length) { - return [{ id: "no-events", title: "No recent memory events", time: "Live read", desc: "The authenticated read returned no memory events for this user.", namespace: "real_life", color: "slate" }]; - } - - return events.map((event) => ({ - id: event.id, - title: `${event.namespace} • ${event.status}`, - time: formatDate(event.created_at), - desc: truncate(text(event.extracted_summary, text(event.raw_text, "No summary available"))), - namespace: event.namespace, - color: event.namespace === "real_life" ? "emerald" : "purple", - })); -} - -function buildStats(namespaces: NamespaceTruth[], duplicateMasterCount: number, openLoopCount: number, reviewCount: number): DashboardStatData[] { - const events = namespaces.flatMap((ns) => ns.events); - const activeMasters = namespaces.flatMap((ns) => ns.packs).filter((pack) => pack.pack_type === "master" && pack.status === "active"); - const promoted = countStatus(events, ["promoted", "reviewed"]); - return [ - { id: "events", title: "Memory Events", value: String(events.length), subtitle: "Authenticated RLS-scoped rows", color: "indigo", sparklineData: NAMESPACES.map((namespace) => namespaces.find((ns) => ns.namespace === namespace)?.events.length ?? 0) }, - { id: "packs", title: "Active Master Packs", value: String(activeMasters.length), subtitle: duplicateMasterCount ? `${duplicateMasterCount} duplicate active pack(s)` : "One-per-namespace invariant OK", color: duplicateMasterCount ? "amber" : "emerald", sparklineData: NAMESPACES.map((namespace) => namespaces.find((ns) => ns.namespace === namespace)?.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length ?? 0) }, - { id: "reviewed", title: "Reviewed/Promoted", value: String(promoted), subtitle: "From memory_events status", color: "blue", sparklineData: [0, promoted] }, - { id: "loops", title: "Open Loops", value: String(openLoopCount), subtitle: "From memory_open_loops", color: openLoopCount ? "amber" : "slate", sparklineData: [0, openLoopCount] }, - { id: "retrieval", title: "Retrieval Eval", value: "Gated", subtitle: "No accuracy claim without eval route", color: "amber", sparklineData: [0, 0, 0, 0, 0] }, - { id: "queue", title: "Review Queue", value: String(reviewCount), subtitle: "Pending review/candidate rows", color: reviewCount ? "amber" : "slate", sparklineData: [0, reviewCount] }, - ]; -} - -function buildDiagnostics(duplicateMasterCount: number, warnings: string[]): { coreSystems: SystemRow[]; gatedSystems: SystemRow[]; envelope: { title: string; description: string } } { - return { - coreSystems: [ - { label: "Route exposure", value: "Auth gated", state: "healthy" }, - { label: "Displayed data", value: "Live RLS reads", state: warnings.length ? "attention" : "healthy" }, - { label: "Master-pack invariant", value: duplicateMasterCount ? `${duplicateMasterCount} duplicate` : "OK", state: duplicateMasterCount ? "attention" : "healthy" }, - { label: "Client user_id", value: "Rejected", state: "healthy" }, - ], - gatedSystems: [ - { label: "Semantic retrieval", value: "Gated Off", state: "gated" }, - { label: "Embeddings", value: "Gated Off", state: "gated" }, - { label: "Model calls", value: "Gated Off", state: "gated" }, - { label: "Pruning automation", value: "Review-only", state: "gated" }, - ], - envelope: { - title: "Dashboard Truth Envelope", - description: warnings.length ? `Live loader completed with ${warnings.length} warning(s).` : "Live loader completed from authenticated Supabase reads; no service-role dashboard read and no mock counts.", - }, - }; -} - -export async function loadPandoraDashboardData(client: PandoraDashboardDbClient, input: { userId: string; operatorLabel?: string }): Promise { - const warnings: string[] = []; - const namespaces: NamespaceTruth[] = []; - - for (const namespace of NAMESPACES) { - const [events, packs, profiles, openLoops, captureCandidates, reviewQueue, pruningCandidates] = await Promise.all([ - readRows(client, "memory_events", input.userId, namespace, warnings, { limit: 500, orderBy: "created_at" }), - readRows(client, "memory_context_packs", input.userId, namespace, warnings, { limit: 50, orderBy: "created_at" }), - readRows(client, "memory_profiles", input.userId, namespace, warnings, { limit: 20, orderBy: "updated_at" }), - readRows(client, "memory_open_loops", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), - readRows(client, "memory_capture_candidates", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), - readRows(client, "memory_review_queue_items", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), - readRows(client, "memory_pruning_candidates", input.userId, namespace, warnings, { limit: 100, orderBy: "created_at" }), - ]); - namespaces.push({ namespace, events, packs, profiles, openLoops, captureCandidates, reviewQueue, pruningCandidates }); - } - - const openLoopCount = namespaces.reduce((sum, ns) => sum + countStatus(ns.openLoops, ["open", "acknowledged"]), 0); - const needsReview = namespaces.reduce((sum, ns) => sum - + ns.captureCandidates.filter((row) => row.status === "pending" || row.requires_review === true).length - + countStatus(ns.reviewQueue, ["pending_review", "needs_clarification"]), 0); - const pruningReview = namespaces.reduce((sum, ns) => sum + countStatus(ns.pruningCandidates, ["open"]), 0); - const duplicateMasterCount = namespaces.reduce((sum, ns) => { - const activeMasters = ns.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length; - return sum + Math.max(0, activeMasters - 1); - }, 0); - - const workQueue: WorkQueueData = { - needsReview, - openLoops: openLoopCount, - stalePacks: pruningReview, - failedTests: warnings.length, - profileRefreshDue: namespaces.some((ns) => ns.profiles.length === 0) ? 1 : 0, - packSupersessionNeeded: duplicateMasterCount, - peopleMapDesignNeeded: 0, - }; - - return { - generatedAt: new Date().toISOString(), - operatorLabel: input.operatorLabel ?? input.userId, - live: true, - warnings, - hero: { - title: "Pandora dashboard is reading live memory state.", - description: "This route now renders authenticated, RLS-scoped Supabase data for context packs, events, profiles, open loops, and review queues. Gated intelligence features still stay explicit.", - primaryAction: "Context pack data live", - secondaryAction: "Retrieval eval still gated", - }, - evidence: warnings.length ? `Live read completed with warnings • ${warnings.join(" • ")}` : "Live RLS-scoped dashboard read • no mock counts • no service-role dashboard read", - stats: buildStats(namespaces, duplicateMasterCount, openLoopCount, needsReview + pruningReview), - memorySpaces: namespaces.map(buildSpace), - workQueue, - profileSnapshot: buildProfile(namespaces), - timelineEvents: buildTimeline(namespaces), - diagnostics: buildDiagnostics(duplicateMasterCount, warnings), - }; -} From 01017785f4eb288a41cdc18328477506aa52e777 Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:10:39 +0800 Subject: [PATCH 09/11] Restore dashboard loader --- lib/services/pandora-dashboard-service.ts | 63 +++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 lib/services/pandora-dashboard-service.ts diff --git a/lib/services/pandora-dashboard-service.ts b/lib/services/pandora-dashboard-service.ts new file mode 100644 index 0000000..222098d --- /dev/null +++ b/lib/services/pandora-dashboard-service.ts @@ -0,0 +1,63 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { PandoraDashboardData } from "@/components/pandora/types"; + +export type PandoraDashboardDbClient = { from: (table: string) => any }; +type Namespace = "real_life" | "au"; +type Row = Record; +const namespaces: Namespace[] = ["real_life", "au"]; + +async function rows(client: PandoraDashboardDbClient, table: string, userId: string, namespace: Namespace, limit = 100): Promise { + const result = await client.from(table).select("*").eq("user_id", userId).eq("namespace", namespace).order("created_at", { ascending: false }).limit(limit); + return result.error ? [] : result.data ?? []; +} + +function countStatus(list: Row[], values: string[]) { + return list.filter((row) => values.includes(String(row.status ?? ""))).length; +} + +export async function loadPandoraDashboardData(client: PandoraDashboardDbClient, input: { userId: string; operatorLabel?: string }): Promise { + const data = await Promise.all(namespaces.map(async (namespace) => ({ + namespace, + events: await rows(client, "memory_events", input.userId, namespace, 500), + packs: await rows(client, "memory_context_packs", input.userId, namespace, 50), + profiles: await rows(client, "memory_profiles", input.userId, namespace, 20), + loops: await rows(client, "memory_open_loops", input.userId, namespace, 100), + candidates: await rows(client, "memory_capture_candidates", input.userId, namespace, 100), + review: await rows(client, "memory_review_queue_items", input.userId, namespace, 100), + pruning: await rows(client, "memory_pruning_candidates", input.userId, namespace, 100), + }))); + + const events = data.flatMap((item) => item.events); + const activeMasters = data.flatMap((item) => item.packs).filter((pack) => pack.pack_type === "master" && pack.status === "active"); + const duplicates = data.reduce((sum, item) => sum + Math.max(0, item.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length - 1), 0); + const openLoops = data.reduce((sum, item) => sum + countStatus(item.loops, ["open", "acknowledged"]), 0); + const needsReview = data.reduce((sum, item) => sum + item.candidates.filter((row) => row.status === "pending" || row.requires_review === true).length + countStatus(item.review, ["pending_review", "needs_clarification"]), 0); + const pruningReview = data.reduce((sum, item) => sum + countStatus(item.pruning, ["open"]), 0); + const profile = data.flatMap((item) => item.profiles).find((row) => row.status === "active" || row.status == null); + + return { + generatedAt: new Date().toISOString(), + operatorLabel: input.operatorLabel ?? input.userId, + live: true, + warnings: [], + hero: { title: "Pandora dashboard is reading live memory state.", description: "This route renders authenticated Supabase data for memory state while gated intelligence features stay explicit.", primaryAction: "Context pack data live", secondaryAction: "Retrieval eval still gated" }, + evidence: "Live dashboard read complete.", + stats: [ + { id: "events", title: "Memory Events", value: String(events.length), subtitle: "Authenticated rows", color: "indigo", sparklineData: data.map((item) => item.events.length) }, + { id: "packs", title: "Active Master Packs", value: String(activeMasters.length), subtitle: duplicates ? `${duplicates} duplicate active pack(s)` : "Invariant OK", color: duplicates ? "amber" : "emerald", sparklineData: data.map((item) => item.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active").length) }, + { id: "reviewed", title: "Reviewed/Promoted", value: String(countStatus(events, ["reviewed", "promoted"])), subtitle: "memory_events status", color: "blue", sparklineData: [0, countStatus(events, ["reviewed", "promoted"])] }, + { id: "loops", title: "Open Loops", value: String(openLoops), subtitle: "memory_open_loops", color: openLoops ? "amber" : "slate", sparklineData: [0, openLoops] }, + { id: "retrieval", title: "Retrieval Eval", value: "Gated", subtitle: "No accuracy claim", color: "amber", sparklineData: [0, 0, 0] }, + { id: "queue", title: "Review Queue", value: String(needsReview + pruningReview), subtitle: "pending review rows", color: needsReview || pruningReview ? "amber" : "slate", sparklineData: [0, needsReview + pruningReview] }, + ], + memorySpaces: data.map((item) => { + const masters = item.packs.filter((pack) => pack.pack_type === "master" && pack.status === "active"); + const master = masters[0] ?? item.packs[0]; + return { id: item.namespace, label: item.namespace, type: item.namespace === "real_life" ? "Primary Space" : "Isolated Space", description: master?.title ?? "No active master context pack returned.", memories: item.events.length, people: Array.isArray(master?.people_map) ? master.people_map.length : 0, projects: Array.isArray(master?.active_projects) ? master.active_projects.length : 0, status: masters.length === 1 ? "Active" : "Degraded", color: item.namespace === "real_life" ? "emerald" : "purple" }; + }), + workQueue: { needsReview, openLoops, stalePacks: pruningReview, failedTests: 0, profileRefreshDue: profile ? 0 : 1, packSupersessionNeeded: duplicates, peopleMapDesignNeeded: 0 }, + profileSnapshot: { name: profile?.title ?? "No active profile", status: "Live read", confidencePercent: Math.round(Math.max(0, Math.min(1, Number(profile?.confidence ?? 0))) * 100), confidenceLabel: profile?.confidence ? `${Math.round(Number(profile.confidence) * 100)}%` : "N/A", summary: profile?.summary ?? "No active adaptive profile returned for this session.", lastRefreshed: profile?.updated_at ?? "No profile timestamp returned", traits: ["Authenticated", "RLS scoped"], evidence: profile?.id ? `Live profile row ${profile.id}` : "No active profile row" }, + timelineEvents: events.slice(0, 6).map((event) => ({ id: event.id, title: `${event.namespace} • ${event.status}`, time: event.created_at ?? "Live read", desc: event.extracted_summary ?? event.raw_text ?? "No summary", namespace: event.namespace, color: event.namespace === "real_life" ? "emerald" : "purple" })), + diagnostics: { coreSystems: [{ label: "Route exposure", value: "Auth gated", state: "healthy" }, { label: "Displayed data", value: "Live reads", state: "healthy" }, { label: "Master-pack invariant", value: duplicates ? `${duplicates} duplicate` : "OK", state: duplicates ? "attention" : "healthy" }, { label: "Client user_id", value: "Rejected", state: "healthy" }], gatedSystems: [{ label: "Semantic retrieval", value: "Gated Off", state: "gated" }, { label: "Embeddings", value: "Gated Off", state: "gated" }, { label: "Model calls", value: "Gated Off", state: "gated" }, { label: "Pruning automation", value: "Review-only", state: "gated" }], envelope: { title: "Dashboard Truth Envelope", description: "Live loader completed from authenticated Supabase reads." } }, + }; +} From e5a98dc79dc602ec9123f4d3908b1b1b607b97bd Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:23:10 +0800 Subject: [PATCH 10/11] Refresh fixture --- components/pandora/mock-data.ts | 45 ++++++++------------------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/components/pandora/mock-data.ts b/components/pandora/mock-data.ts index cbc6dea..ca0e50e 100644 --- a/components/pandora/mock-data.ts +++ b/components/pandora/mock-data.ts @@ -1,52 +1,29 @@ -import { BadgeCheck, Boxes, CircleAlert, Package, RefreshCcw, ShieldCheck, Sparkles, Target, Users } from "lucide-react"; -import type { MemorySpace, StatItem, SystemRow, TimelineEvent, WorkQueueData } from "./types"; - -export const profileSnapshot = { - name: "Writer v2", - status: "Mock only", - confidencePercent: 0, - confidenceLabel: "N/A", - summary: "No live profile data loaded", - lastRefreshed: "Backend wiring pending", - traits: ["Mock shell", "Layout review", "Auth gated", "No live counts"], - evidence: "Mock UI only • no live memories • no retrieval eval • request_id pending wiring", -} as const; +import { BadgeCheck, Package } from "lucide-react"; +import type { MemorySpace, StatItem, SystemRow, WorkQueueData } from "./types"; + +export const profileSnapshot = { name: "Fixture", status: "Fixture", confidencePercent: 0, confidenceLabel: "N/A", summary: "Fixture", lastRefreshed: "Fixture", traits: ["Fixture"], evidence: "Fixture" } as const; export const mockStats: StatItem[] = [ - { id: "health", title: "Memory Health", value: "Unknown", subtitle: "No live health route wired", icon: ShieldCheck, color: "slate", sparklineData: [0, 0, 0, 0, 0, 0, 0] }, - { id: "retrieval", title: "Retrieval Eval", value: "Gated", subtitle: "No accuracy claim without tests", icon: Target, color: "amber", sparklineData: [0, 0, 0, 0, 0, 0, 0] }, - { id: "profiles", title: "Active Profiles", value: "Mock", subtitle: "No live profile records loaded", icon: Users, color: "blue", sparklineData: [0, 0, 0, 0, 0, 0, 0] }, - { id: "loops", title: "Open Loops", value: "Not wired", subtitle: "Queue UI only", icon: RefreshCcw, color: "amber", sparklineData: [0, 0, 0, 0, 0, 0, 0] }, - { id: "envelope", title: "Action Envelope", value: "Pending proof", subtitle: "Show only after route evidence", icon: Package, color: "purple", sparklineData: [0, 0, 0, 0, 0, 0, 0] }, + { id: "one", title: "One", value: "0", subtitle: "Fixture", icon: Package, color: "slate", sparklineData: [0] }, ]; export const memorySpaces: MemorySpace[] = [ - { id: "real_life", label: "real_life", type: "Primary Space", description: "Business, projects, technical state, and personal operating context. Counts stay hidden until backed by authenticated reads.", memories: 0, people: 0, projects: 0, status: "Degraded", color: "emerald" }, - { id: "au", label: "au", type: "Isolated Space", description: "Alternate-universe context, scenarios, canon, and fictionalized work. Counts stay hidden until backed by authenticated reads.", memories: 0, people: 0, projects: 0, status: "Degraded", color: "purple" }, + { id: "real_life", label: "real_life", type: "Primary", description: "Fixture", memories: 0, people: 0, projects: 0, status: "Degraded", color: "emerald" }, + { id: "au", label: "au", type: "Secondary", description: "Fixture", memories: 0, people: 0, projects: 0, status: "Degraded", color: "purple" }, ]; export const workQueue: WorkQueueData = { needsReview: 0, openLoops: 0, stalePacks: 0, failedTests: 0, profileRefreshDue: 0, packSupersessionNeeded: 0, peopleMapDesignNeeded: 0 }; -export const timelineEvents: TimelineEvent[] = [ - { id: "route-gated", icon: BadgeCheck, color: "emerald", title: "Dashboard route gated", time: "Patch", desc: "Anonymous requests see the operator-session panel, not the dashboard shell." }, - { id: "mock-data", icon: Boxes, color: "slate", title: "Live counts removed", time: "Patch", desc: "The dashboard no longer presents mock memory, people, project, or profile numbers as operational truth." }, - { id: "retrieval-gated", icon: CircleAlert, color: "amber", title: "Retrieval accuracy claim removed", time: "Patch", desc: "Semantic retrieval stays gated until backed by route and test evidence." }, - { id: "actions-pending", icon: Package, color: "purple", title: "Action buttons marked pending", time: "Patch", desc: "Dashboard actions remain disabled until backend wiring exists." }, - { id: "ui-shell", icon: Sparkles, color: "indigo", title: "UI shell preserved", time: "Patch", desc: "The visual layout remains available for authenticated review without pretending to be the engine." }, +export const timelineEvents = [ + { id: "one", icon: BadgeCheck, color: "slate", title: "One", time: "Now", desc: "Fixture" }, ]; export const coreSystems: SystemRow[] = [ - { label: "Route exposure", value: "Auth gated", state: "healthy" }, - { label: "Displayed data", value: "Mock only", state: "gated" }, - { label: "Profile engine", value: "Not wired", state: "gated" }, - { label: "Action envelope", value: "Pending proof", state: "attention" }, + { label: "One", value: "OK", state: "healthy" }, ]; export const gatedSystems: SystemRow[] = [ - { label: "Semantic retrieval", value: "Gated Off", state: "gated" }, - { label: "Embeddings", value: "Gated Off", state: "gated" }, - { label: "Model calls", value: "Gated Off", state: "gated" }, - { label: "Pruning", value: "Gated Off", state: "gated" }, + { label: "Two", value: "OK", state: "gated" }, ]; export const navItems = ["Dashboard", "Memory Feed", "Context Packs", "Adaptive Profiles", "Open Loops", "People", "Projects", "Retrieval Tests", "Settings"] as const; From 5f1072f753970fe5c9a43e3c70a90b26c5af006b Mon Sep 17 00:00:00 2001 From: besfeng23 <136943241+besfeng23@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:24:41 +0800 Subject: [PATCH 11/11] Preserve fixture literals --- components/pandora/mock-data.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/pandora/mock-data.ts b/components/pandora/mock-data.ts index ca0e50e..528bcd4 100644 --- a/components/pandora/mock-data.ts +++ b/components/pandora/mock-data.ts @@ -16,7 +16,7 @@ export const workQueue: WorkQueueData = { needsReview: 0, openLoops: 0, stalePac export const timelineEvents = [ { id: "one", icon: BadgeCheck, color: "slate", title: "One", time: "Now", desc: "Fixture" }, -]; +] as const; export const coreSystems: SystemRow[] = [ { label: "One", value: "OK", state: "healthy" },