Files
semantica/explorer
Aldrin Joseph 5376f046ca fix(explorer): dedupe temporal snapshot requests and apply latest-wins (#1241)
fix(explorer): dedupe temporal snapshot requests and apply latest-wins

The temporal snapshot effect fetched /api/temporal/snapshot with no
idempotency or ordering guards. Upstream churn (timeline recreation
while bounds settle, play ticks resetting the playhead, drag events)
could re-request the same `at` repeatedly, and with variable network
latency an older position's response could land after a newer one's,
overwriting the active-node count, so the chip visibly lagged the
scrubber.

Add a small stateful guard module (temporalSnapshotGuards.ts) built
around a per-position cache, keyed by the debounced timestamp's
primitive millisecond value rather than the Date object, so upstream
object-identity churn cannot defeat the dedup on its own:

- at most one in-flight request per scrubber position, so identical
  `at` values arriving while a request is pending are dropped instead
  of firing a fresh fetch, breaking the idle/play polling loop;
- successful snapshots are cached per position and re-applied when the
  scrubber returns to it (play wrap-around, back-scrubbing) without a
  network round trip;
- a response is applied only while the scrubber is still on the
  position it was requested for, so an out-of-order response can never
  clobber a newer position's count;
- failed, cancelled, or superseded requests release their position so
  it can be fetched again the next time it's visited, rather than
  stalling it permanently;
- reset() drops all cached and in-flight state when the underlying
  graph summary changes (reload/retry), since snapshots cached against
  the previous graph no longer describe anything real. Keyed on the
  summary query's data identity, which react-query keeps stable
  (staleTime: Infinity plus structural sharing) unless the graph data
  itself was replaced, so reset fires exactly on a real reload and not
  on cosmetic re-renders.

The snapshot effect is wired through the guards end to end: begin()
returns either a fresh sequence number to fetch under or a cached
snapshot to reapply directly; the same shouldApply()/apply() gate
handles both the network and cached-reapply paths so they can't drift
apart; finish() runs from both the fetch's failure branch and its
cleanup function, so a cancelled or failed request is always retryable
on the next visit instead of leaving its position stuck in-flight.

16 unit tests cover dedup, independent positions, revisit re-apply,
play wrap-around, failure retry, stale-sequence protection (a late
response or a late release from a superseded request cannot act on a
newer request's position), reset-on-reload, and cache-bound eviction.

Closes #1128
2026-08-28 19:45:13 +05:00
..

Semantica Knowledge Explorer

A browser-based graph workbench for the Semantica platform. Pan and zoom live graphs, scrub the timeline, trace every decision's causal chain, resolve duplicates, and author your ontology visually. Built on React 19 + Sigma.js.


Requirements

Dependency Minimum version
Python 3.8+
Node.js 18.x or higher (20.x recommended)
npm 9.x or higher
python --version
node --version
npm --version

Two ways to run the Explorer

Install the package with the explorer extras. The pre-built frontend bundle is included in the wheel so no Node.js is required.

pip install "semantica[explorer]"

Launch the dashboard by pointing it at any graph JSON file:

semantica-explorer --graph my_graph.json

The server starts at http://127.0.0.1:8000 and opens the dashboard in your default browser automatically.

CLI flags:

Flag Default Description
--graph / -g (required) Path to a ContextGraph JSON file
--port / -p 8000 Port to bind the server to
--host 127.0.0.1 Host to bind (use 127.0.0.1 for local-only; see security note below)
--no-browser off Skip opening the browser automatically

Examples:

# Default — opens at http://127.0.0.1:8000
semantica-explorer --graph my_graph.json

# Custom port
semantica-explorer --graph my_graph.json --port 8080

# Suppress auto-open
semantica-explorer --graph my_graph.json --no-browser

# Equivalent using python -m
python -m semantica.explorer --graph my_graph.json

Security note: Since v0.6.5 the Explorer API requires an API key on protected routes. Set the SEMANTICA_API_KEY environment variable and send it as the X-API-Key header; without a configured key, protected routes fail closed with 503 rather than serving anonymously. To opt into unauthenticated access for local development only, set SEMANTICA_ALLOW_ANONYMOUS=true explicitly. (/api/health and /api/info are intentionally unauthenticated.)

The default --host 127.0.0.1 binds to localhost only, so it is not reachable from other machines on your network. If you bind to 0.0.0.0, all graph data is readable and writable by any host that can reach the port (subject to API-key auth). The CLI prints a warning when binding to a non-loopback host in anonymous mode or when SEMANTICA_API_KEY is unset.


Option B — run from source (for contributors / frontend development)

This mode runs the React dev server with hot module replacement, so frontend changes appear in the browser instantly without rebuilding.

Step 1 — Clone the repo

git clone https://github.com/semantica-agi/semantica.git
cd semantica

Step 2 — Install the Python package

pip install -e ".[explorer]"

Step 3 — Install frontend dependencies

cd explorer
npm ci

Step 4 — Start the Python backend

Open a terminal in the repo root:

semantica-explorer --graph path/to/my_graph.json --no-browser

This starts the API on http://127.0.0.1:8000. Keep this terminal open.

Step 5 — Start the frontend dev server

Open a second terminal in explorer/:

npm run dev

Vite starts on http://localhost:5173. Open that URL in your browser. All /api and /ws requests are automatically proxied to the Python backend at http://127.0.0.1:8000.


Building the production bundle

If you need to serve the UI from the Python server directly (without the Vite dev server):

cd explorer
npm ci
npm run build

This writes the compiled assets to ../semantica/static/. The Python server then serves the full dashboard at http://127.0.0.1:8000 — no separate Vite process needed.


Workspaces

Workspace What you can do
Knowledge Graph Live Sigma.js canvas · ForceAtlas2 layout · Ego Mode · semantic distance heatmap · path highlighting
Timeline Temporal event scrubber — watch the graph evolve across time
Decisions Browse causal chains behind every recorded decision with outcome badges and confidence scores
Registry Live audit log of every graph mutation (add-node, add-edge, delete, update)
Entity Resolution Review and merge duplicate entities with blocking + semantic dedup
KG Overview Aggregate stats, community breakdown, centrality heatmap
Ontology Hub SHACL Studio · visual drag-and-drop editor · cross-ontology alignments · SKOS browser
Lineage W3C PROV-O provenance visualization for any entity

Environment variables

Variable Default Description
EXPLORER_CORS_ORIGINS http://localhost:5173,http://127.0.0.1:5173 Comma-separated list of allowed CORS origins
EXPLORER_CORS_CREDENTIALS false Set to true to allow credentialed cross-origin requests (only needed behind an authenticating reverse proxy)
SEMANTICA_API_KEY (unset) API key required on protected routes since v0.6.5; send it as the X-API-Key header. When unset, protected routes fail closed with 503.
SEMANTICA_ALLOW_ANONYMOUS false Set to true to opt into unauthenticated access (local development only).

Available scripts

Run these from inside the explorer/ directory:

# Start the dev server with hot module replacement
npm run dev

# Type-check and build the production bundle into ../semantica/static/
npm run build

# Preview the production build locally
npm run preview

# Run ESLint over all source files
npm run lint

# Run the graph store multi-edge unit tests
npm run test:graph-store

# Run the graph workspace display tests
npm run test:graph-workspace

API & WebSocket proxy (dev mode only)

During development, Vite forwards requests automatically — no CORS configuration needed:

Pattern Forwarded to
/api/* http://127.0.0.1:8000/api/*
/ws/* ws://127.0.0.1:8000/ws/*

To run the backend on a different port, update server.proxy in vite.config.ts.


Project structure

explorer/
├── src/
│   ├── App.tsx                        # Root layout, tab routing, workspace wiring
│   ├── index.css                      # Global resets, fonts, keyframe animations
│   ├── store/
│   │   ├── graphStore.ts              # In-memory graph state
│   │   └── registryStore.ts           # Pub/sub audit registry
│   └── workspaces/
│       ├── GraphWorkspace/            # Sigma.js canvas + inspector + behaviors
│       ├── DecisionWorkspace/         # Causal flow diagram + decision list
│       ├── DiffMergeWorkspace/        # Graph diff and merge view
│       ├── EnrichWorkspace/           # Entity resolution + registry tabs
│       ├── ImportExportWorkspace/     # Import CSV/JSON, export graph
│       ├── LineageWorkspace/          # W3C PROV-O lineage diagram
│       ├── ManageWorkspace/           # KG Overview + Ontology Summary
│       ├── OntologyWorkspace/         # SHACL Studio, visual editor, SKOS browser
│       ├── SparqlWorkspace/           # In-browser SPARQL query editor
│       └── VocabularyWorkspace/       # SKOS vocabulary manager
├── index.html
├── vite.config.ts                     # Dev proxy → 127.0.0.1:8000, build → ../semantica/static
└── package.json

Troubleshooting

Dashboard shows a blank white page or "UI not available" message

The frontend bundle is missing from the server's static directory. Fix options:

  • If you installed via pip: pip install --upgrade "semantica[explorer]" — the wheel includes the pre-built bundle.
  • If you installed from source: run cd explorer && npm ci && npm run build from the repo root, then restart the server.
  • In dev mode: use the Vite dev server at http://localhost:5173 instead of the backend URL.

Blank graph / no data loads in the browser

  • Confirm the Python backend is running and check the terminal for errors.
  • Open browser DevTools → Network tab and look for failed /api/graph requests.
  • If the backend is on a different port, update server.proxy in vite.config.ts.

npm ci fails or reports missing lockfile

The package-lock.json must be present. Run npm install once to generate it, commit it, then use npm ci going forward.

npm run dev fails with Node version error

Vite 6 requires Node 18 or higher. Run node --version to check. If you're on Node 16, upgrade via nvm or the official Node.js installer.

Port 5173 already in use

Vite automatically tries the next available port and prints the actual URL in the terminal. Use the URL shown in the output.

WebSocket not connecting (real-time mutations not appearing)

  • Confirm the backend exposes the /ws/graph-updates WebSocket endpoint.
  • Check DevTools → Network → WS tab for the connection status and error code.
  • Ensure the backend version matches the frontend — mixing major versions can cause protocol mismatches.
  • Authentication: /ws/graph-updates enforces the same API key as the REST routes. Browsers cannot set custom headers on a WebSocket handshake, so pass the key as a query parameter instead:
    ws://127.0.0.1:8000/ws/graph-updates?api_key=<your-key>
    
    Non-browser clients (native apps, scripts) may send it as the X-API-Key header. A missing or incorrect key results in close code 4401; if SEMANTICA_API_KEY is unset and SEMANTICA_ALLOW_ANONYMOUS is not true, the connection is also rejected. Note that API keys in URLs appear in server logs — prefer the header for non-browser clients.

Tech stack

  • React 19 + TypeScript (strict mode)
  • Vite 6 with babel-plugin-react-compiler
  • Sigma.js 3 + Graphology — graph rendering and in-memory graph model
  • ForceAtlas2 — physics-based layout
  • @tanstack/react-query — async data fetching for ontology and vocab tabs
  • vis-timeline — temporal event visualization
  • @xyflow/react — lineage diagram rendering
  • Monaco Editor — in-browser SPARQL / SHACL editor
  • lucide-react — icon set

Contributing

See the root CONTRIBUTING.md and open issues on the main Semantica repository.