Aller au contenu principal

ADR-020 — Interaction lineage visualization

1. Context

Console operators (CISO, security analyst, compliance officer) currently see Interactions as a flat list with metadata. To investigate "what happened to this prompt" they must mentally stitch together: which surface captured it (extension/agent/proxy), which processing components ran (SLM/redaction/policy/Presidio/multi-modal), what the decision was, where it ended up, and what was detected at each hop. No surface today shows this end-to-end.

Reference design submitted by Jerome (Azure ML resource lineage style — horizontal DAG, circular pastel nodes, current-resource highlight, badge counts, minimap). Style is clean, scannable, drill-down via click. We adopt it.

This ADR also resolves the deferred "Flow Graphs" item in noxys-console/CLAUDE.md Roadmap M6+ — we bring React Flow into the codebase now, with lineage as the first usage.

2. Decision summary

  • Visualization: React Flow v11+, horizontal DAG (left → right), dagre auto-layout.
  • Style: brand-aligned circular nodes (~80px) with 2-line labels, pastel backgrounds keyed to node category, light dotted grid background, edges thin gray (no labels by default).
  • Surface: InteractionDetailPage new tab "Lineage" alongside Evidence / Policy / Audit. Full-view modal for fullscreen exploration. Side panel for click drill-down.
  • Step model: every component in the pipeline (extension / agent / proxy / api / sidecar / llm-service) emits one row to interaction_lineage_steps, correlated by propagated trace_id (header X-Noxys-Trace-Id).
  • Tier gating (per ADR-019 storage classes): Free=3-node summary, Pro=full processing chain + detection metadata + latency, Enterprise=+raw payload preview at click (only if tenant opted into raw storage).
  • First usage of React Flow in noxys-console — sets pattern for future flow visualizations (policy graph, AI service map, multi-tenant deployment view).

3. Visual specification

Layout

  • Horizontal DAG, left = source (User), right = destination (LLM service), bottom row = response path mirror.
  • Auto-layout via @dagrejs/dagre with rank-direction LR.
  • Branches (e.g. attachments processed in parallel by multi-modal lanes) converge at the Decision node.

Nodes

CategoryColor (light bg / icon ring)IconExamples
UserLavender #E9E7FF / Purple #6C63FFUserCircleend-user identity
Capture surfaceMint #D4F5EC / Cyan #00D4AAChrome / Cpu / NetworkBrowser Extension / Endpoint Agent / Proxy
ProcessingSky #DBEAFE / Blue #3B82F6Sparkles / Shield / Brain / FileSearchSLM / Smart Redaction / Multi-modal lane / Presidio / Semantic Policy
Decisiongreen/amber/redCheck / EyeOff / BanAllow / Redact / Block
StorageSlate #F1F5F9 / Slate #64748BDatabaseaggregate / hashed / redacted / raw
LLM servicebranded per providerper-provider logoOpenAI / Anthropic / Mistral / etc.
AttachmentPeach #FFEFD5 / Amber #F59E0BFileText / Image / Mic / CodeFile / Image / Audio / Code block

Each node renders:

  • Icon centered in circle
  • 2-line label below (component name + version)
  • Optional badge top-right: red dot (block) / amber dot (redact) / count of detections
  • Current step (when navigating from drill-down) ringed in Purple + cyan label "(Current step)"

Edges

  • Thin gray lines, simple bezier
  • Default: no label
  • Hover: tooltip with latency_ms + bytes-transferred
  • Animated dot in transit when interaction is live (V2)

Controls (mirror Azure reference)

  • Top-right: "Full View" button → fullscreen modal
  • Bottom-left: zoom +/-, fit-view, layout toggle (horizontal/vertical), pin, settings
  • Bottom-right: minimap (Azure-style miniature thumbnail)
  • Background: dotted grid pattern using BackgroundVariant.Dots from React Flow

Interactions

  • Click node → side panel slides in from right with full step detail
  • Hover edge → latency tooltip
  • Right-click node → context menu (filter to this surface only, copy trace_id, view component docs)
  • Filter toolbar (Pro+): toggles to hide/show by surface (Extension only, Proxy only, etc.)
  • Search (Enterprise): jump to step by component name in graphs with 30+ nodes

4. Data model

CREATE TABLE interaction_lineage_steps (
id uuid PRIMARY KEY,
interaction_id uuid NOT NULL REFERENCES interactions(id),
trace_id text NOT NULL, -- propagated extension→proxy→api→sidecar→llm
step_order int NOT NULL, -- monotonic per trace_id
parent_step_id uuid REFERENCES interaction_lineage_steps(id), -- for parallel branches (attachments)

surface text NOT NULL, -- 'extension'|'agent'|'proxy'|'api'|'sidecar-presidio'|'sidecar-mm'|'llm-service'
component text NOT NULL, -- 'capture'|'slm'|'redaction'|'presidio'|'policy-eval'|'mm-image'|'mm-audio'|'mm-video'|'mm-code'|'decision'|'storage-write'|'llm-call'|'response-scan'
component_version text, -- e.g. extension '1.2.3-staging.045', model 'mistral-large-2502'

action text NOT NULL, -- 'classify'|'redact'|'eval-policy'|'allow'|'block'|'persist'|'forward'|'scan-output'
decision_reason text, -- when component=decision

input_summary jsonb, -- {type, length, lang, has_pii_flag, has_secret_flag} — never raw text
output_summary jsonb, -- {redactions_count, classifications, scores}
detections jsonb, -- [{type:'pii', subtype:'email', count:3, severity:'medium', confidence:0.93}, ...]

latency_ms int,
bytes_in int,
bytes_out int,
storage_class_applied text, -- 'aggregate'|'hashed'|'redacted'|'raw' (when component=storage-write)

metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
occurred_at timestamptz NOT NULL DEFAULT now()
);

CREATE INDEX idx_lineage_interaction_order ON interaction_lineage_steps(interaction_id, step_order);
CREATE INDEX idx_lineage_trace ON interaction_lineage_steps(trace_id);
CREATE UNIQUE INDEX uq_lineage_trace_step ON interaction_lineage_steps(trace_id, step_order);

The unique index on (trace_id, step_order) makes step ingestion idempotent — out-of-order replay or duplicate emits don't break the graph.

5. Trace ID propagation contract

X-Noxys-Trace-Id header propagated through every hop. Format: tr_<ulid> (Universally Unique Lexicographically Sortable Identifier — sortable by time, ~26 chars).

Generation:

  • Extension (browser surface): generated at content-script capture moment, attached to first POST to noxys-api or noxys-proxy.
  • Agent (endpoint): generated at native capture moment.
  • Proxy (network): generated at HTTP intercept; if upstream client already sent one (e.g. customer's own observability), preserve and chain via metadata.upstream_trace_id.

Each component appends a step entry as it processes; step_order = monotonic counter (atomic increment per trace).

6. Tier gating (per ADR-019)

Lineage capabilityFreeProEnterprise
3-node summary (Capture → Decision → Service)yesyesyes
Full step chainyesyes
Detection metadata per stepyesyes
Latency + bytes per stepyesyes
Click drill-down side panel (input/output summaries)yesyes
Raw payload preview at node clickopt-in (raw storage tier)
Filter / search / multi-modal branchesyesyes
Cross-interaction trace searchyes
Export lineage as PNG/SVGbasicyesyes (also as JSON for BI)

7. UX surfaces

InteractionDetailPage — new "Lineage" tab

Layout:

  • Tab strip: Overview | Lineage | Evidence | Policy | Audit
  • Lineage tab body:
    • Top toolbar: filter (surface checkboxes), search, fit-view, full-view button
    • Main canvas: React Flow graph (60% viewport height)
    • Bottom: timeline strip (alternative chronological view, optional V2)

Side panel (click node)

Sticky drawer right side, ~480px wide:

  • Header: node icon + component + version + timestamp
  • Detail sections (collapsible, tier-gated):
    1. Action & decision — what this step did, why
    2. Detections — list with severity badges
    3. Performance — latency, bytes in/out
    4. Storage — class applied, retention, encryption key ref (Enterprise)
    5. Evidence preview — input/output summary (Pro+) or raw quote (Enterprise opt-in)
    6. Linked artifacts — config policy that triggered, AI-BOM model card, related interactions

Full View modal

Fullscreen dialog (shadcn <Dialog>) with:

  • Same canvas, larger, zoom-pan-pinch enabled
  • Time-axis ruler at bottom (mode toggle: spatial DAG vs chronological timeline)
  • Multi-select nodes for comparison

8. Tech stack

  • React Flow v11+ — chosen over alternatives (vis.js too generic, dagre-d3 lower-level, mermaid too rigid for interactivity)
  • @dagrejs/dagre for auto-layout (LR direction, configurable rank/node-sep)
  • shadcn dialog for Full View modal (consistent with rest of console)
  • Lucide icons (already standard)
  • i18n: 12 locales for static labels (matching console)
  • a11y: ARIA-graph role, keyboard navigation across nodes (Tab cycles, Enter opens drill-down)

9. Performance considerations

  • Tenants with high interaction volume (10k/day → 30k+ steps/day) — graph for single interaction = 5-50 nodes typically; query bounded by interaction_id.
  • Cross-interaction queries (Enterprise tier feature) require pgvector or denormalized summary table — defer to V2.
  • Real-time updates (live in-progress interactions): V2 via SSE/WebSocket. V1 = snapshot.
  • Caching: lineage tree cached in Redis with TTL=1h after interaction completion (immutable thereafter).

10. Sprint plan — 8 sprints, 15d

IDTitleRepoWindowEffortPriority
LINEAGE-1DB schema interaction_lineage_steps + trace_id propagation contract docsnoxys-apiW25-262dP1
LINEAGE-2Step ingestion endpoint + emit hooks in extension/agent/proxy/api/sidecarnoxys-apiW25-263dP1
LINEAGE-3API endpoint GET /interactions/:id/lineage (tree shape, tier-gated detail)noxys-apiW25-261dP1
LINEAGE-4React Flow component + brand-styled custom nodes (8 node types)noxys-consoleW27-284dP1
LINEAGE-5Side panel + click drill-down + tier-aware detail renderingnoxys-consoleW27-282dP2
LINEAGE-6Full View modal + filters + minimap + zoom controlsnoxys-consoleW27-281dP2
LINEAGE-7Multi-modal branch rendering (parallel attachment lanes)noxys-consoleW29-301dP2
LINEAGE-8i18n labels (12 locales) + a11y (ARIA-graph, keyboard nav)noxys-consoleW29-301dP3

LINEAGE-2 has cross-repo touchpoints: emit hooks must land in noxys-extension + noxys-proxy + sidecars too. Tracked as primary in noxys-api with follow-up slice issues.

11. Dependencies

  • STORE-1 (ADR-019 schema) — must land before LINEAGE-1 (we use the same tier model in JWT claims).
  • EXT-UX-4 (ADR-015 auto-enrollment) — JWT/header contract must include trace propagation field.
  • AI-PLACE-2/3/4 — components only emit lineage steps once they exist; partial graph OK during rollout.
  • ADR-013 (extension versioning) — telemetry headers already in place; add X-Noxys-Trace-Id alongside.

12. Open questions

  • Response path: same graph (mirror row below) or separate tab "Response"? Recommend same graph (V1) — mirrors Postman request/response style.
  • Cross-interaction trace search (Enterprise): same prompt sent 3 times — group? Defer V2.
  • Real-time live updates: V1 snapshot only. V2 SSE.
  • Chart export: PNG via html-to-image lib straightforward; SVG native React Flow.
  • Token cost rendering: should latency edges also show estimated tokens consumed at LLM-call edge? Recommend yes (Pro+ feature, derived from LiteLLM telemetry per ADR-012).

13. Non-goals

  • Editable lineage (operators don't modify the graph; it's a read-only investigative surface).
  • Programmable lineage rules (this isn't a workflow editor — that's a separate future surface).
  • Real-time agent-to-agent collaborative viewing (V3+).
  • Replacing the audit log (lineage is visualization layer; audit log remains the immutable record).

14. Refs

  • ADR-011 Multi-modal pipeline (lanes emit steps)
  • ADR-013 Extension versioning (trace ID header alongside version headers)
  • ADR-014 AI placement (components emitting steps)
  • ADR-018 Subscription lifecycle (renumber: future CRM ADR moves to ADR-027; ADR-022 = UsersPage V2; ADR-024 = Authentication & MFA; ADR-026 = API/OpenAPI policy)
  • ADR-019 Storage tiers (gates lineage detail depth)
  • ADR-021 TanStack Query + Table adoption (LINEAGE-3..6 console pages adopt Query from day one)
  • ADR-022 UsersPage V2 spec (consumes DataTable wrapper for users table; sources entitlements/cost from backend rollups)
  • ADR-024 Authentication & MFA strategy (TOTP/WebAuthn/backup codes encrypted via KMS pattern; tenant token reveal + tenant-wide MFA enforcement)
  • noxys-console CLAUDE.md "Flow Graphs Roadmap M6+" — first React Flow usage in codebase
  • Reference design: Azure ML resource lineage (horizontal DAG, pastel nodes, badge counts, minimap)
  • ADR-026 API completeness & OpenAPI policy (every endpoint defined in this ADR must have OpenAPI 3.1 spec entry; backfill obligation in §9)