Repository navigation
Architecture update: backend package, Vite/TS frontend, tests, CI - #3
Merged
Merged
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Covers config precedence (defaults < file < env < CLI), client config, token API (round trip, proxy headers, limits, expiry, cap), the STRING, Arena3D and database relays (allowlists, body limits, upstream errors, off switches), static blocklist and security headers. Runs against a fake upstream started in-process; no network access needed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Adds a window.__norma test hook (the canvas is opaque to the DOM) and eleven browser tests served by server.py: welcome page, every built-in example, layouts, tab switching incl. the 3D view, PNG/SVG export, profiler statistics and layout benchmark, the API tab (server round trip and #json= link), the REST API and the unknown-example error path. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
config (settings), api (token store), relays (STRING / Arena3D / databases), static (files + blocklist), handler (routing), main (CLI). Fully type-annotated; ruff + mypy --strict clean; still standard library only. backend/server.py is the entry point; uv/pyproject carry dev tools only. Tests moved to backend/tests and pass unchanged in behaviour. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
norma.html is carved into frontend/norma.html (markup), src/style.css and src/app.ts (the script, verbatim, @ts-nocheck until it is split and typed). Cytoscape.js comes from npm; the API client template is imported ?raw from norma_api_client.py. vite-plugin-singlefile writes dist/norma.html, which the server serves and which still opens from disk. ESLint (typescript- eslint), Prettier and tsc are configured; the legacy script is exempt from type-aware rules until typed. Dockerfile becomes a two-stage build. Playwright now builds first and runs against dist/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
59 modules under src/ (layouts/, export/, view3d/, string/, clustering/, api/), cut at the script's section headers with a symbol-resolved splitter (TypeScript compiler API): exports and imports are generated from actual references, so no name is guessed. The 19 variables that several sections assign move into state.ts as the S object (ES module bindings are read-only across files). Each module keeps declarations at top level and its page wiring in an exported init(); main.ts calls the init()s in the original order, which keeps the boot sequence identical despite import cycles. The two commitStyle monkey-patches become onCommitStyle hooks. Modules stay @ts-nocheck until typed; Prettier formatted. Playwright suite passes unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Community detection (Louvain, Leiden, label propagation, Walktrap, MCL) on a two-clique graph, convex hull geometry, Arena3D file conversion, hypergeometric test and Benjamini-Hochberg, numeric value parsing and the runtime config merge. jsdom is given the real page markup and a no-op canvas context so the modules can be imported as they are. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Backend job: uv sync, ruff check/format, mypy, pytest. Frontend job: eslint, prettier, tsc, vitest, vite build. E2E job: Playwright chromium (builds the page and starts the server itself). pre-commit mirrors the lint hooks. uv.lock pins the backend dev tools. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
README gains the build step, the Development section and the repository map; NAR_CHECKLIST moves to docs/. run_local.sh/.bat build the page when frontend/dist is missing; the server says so when it is not built. CHANGELOG records the tooling and layout changes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sidebar resize/collapse (new side_panel module), Spread rework (repel/attract via stress majorization) and the group-shading canvas pixel-ratio fix, from NORMA_v3 commits b59038d, 792a0a4 and c2cffdc. Ported by re-running the section splitter on the updated norma.html and carrying over the differences, so the modules match upstream exactly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
norma.html stays deleted: its changes were ported into frontend/src in the previous commit. launch.json points at backend/server.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Progress reporting for layouts, bundling, profiler, comparison, STRING and the database importers, plus app.maxNodes 10000, from NORMA_v3 commit 52e5aee. Ported by re-running the section splitter on the updated norma.html (now mapping sections by title and handling shared variables declared in a multi-declarator statement). The large examples now take 20-30 s to lay out on upstream's own page as well, so the all-examples smoke test gets a longer timeout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
norma.html and server.py stay deleted: their changes were ported into frontend/src and backend/norma in the previous commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Once the page has painted a frame, Cytoscape's cose layout runs 5-7x slower on the main thread. This is a V8 effect: identical inputs, call counts and control flow, but repeated 'wrong map' deoptimisations in cose's hot functions; it reproduces with plain Cytoscape (7 s before a frame, 38-54 s after one) and also on a headless clone in the same isolate. The progress-bar change deferred the computation past that first paint, so covid/coexpr took 25-35 s instead of 5-6 s. cose for networks above 150 nodes now runs headless in a Web Worker (a fresh isolate; Vite inlines it into the single-file build) and the positions animate in with a preset layout, as 'animate: end' did. Superseding layouts terminate the worker. Falls back to the main thread if no worker can be created. Also: pytest fixture teardown no longer waits 0.5 s per test (39 tests in under a second) and the all-examples e2e test is back on the default timeout (suite: 18 s). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
fbaltoumas
approved these changes
Sep 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Professional repository layout for NORMA 3, modelled on Arena3Dweb, with test suites, lint/typecheck tooling and CI. No behaviour change for users, except one performance fix. Contains everything currently on
NORMA_v3(the sidebar, spread, hull-canvas and progress-bar commits were ported into the new modules).Backend —
server.py→backend/norma/package (config,api,relays,static,handler,main; entrybackend/server.py). Fully type-annotated, ruff + mypy--strictclean, still standard library only (uvfor dev tools).Frontend —
norma.html→ Vite + TypeScript project infrontend/. The 15K-line script is split into ~60 modules by its section headers (layouts/,export/,view3d/,string/,clustering/,api/), symbol-resolved so every import/export comes from an actual reference.npm run buildwrites a self-containedfrontend/dist/norma.htmlthat still opens from disk. Cytoscape.js from npm. Modules carry@ts-nocheckuntil typed one file at a time.Tests — pytest (39: config precedence, token API, relays with fake upstreams, blocklist, security headers), Vitest (26: community detection, hull geometry, Arena3D conversion, enrichment statistics, value parsing, config merge), Playwright (11: examples, layouts, tabs, 3D, export, profiler, API tab, REST API).
Tooling — ESLint, Prettier, tsc, ruff, mypy, pre-commit, GitHub Actions (backend / frontend / e2e jobs). MIT
LICENSE,AGENTS.md/CLAUDE.md,CHANGELOG.md, two-stage Dockerfile.Performance fix worth reading
After the progress-bars commit, the large examples (covid, coexpr) took 25-35 s to open instead of 5-6 s. Cause: once the page has painted a frame, Cytoscape's cose runs 5-7x slower on the main thread (identical inputs and iteration counts; V8 "wrong map" deoptimisations; reproducible with plain Cytoscape). The commit deferred the layout past that first paint to show the busy note. cose for networks above 150 nodes now runs headless in a Web Worker (inlined into the single-file build) — 4-8 s again, page stays responsive, and this also speeds up every "Run layout" click on a settled page.
Verify
Not verified here: the Docker image build (no daemon access).
🤖 Generated with Claude Code