From 0e59d489ec4bab01e450ee4a23b29fdacc252beb Mon Sep 17 00:00:00 2001
From: Undline <103777919+Undline@users.noreply.github.com>
Date: Tue, 7 Apr 2026 17:02:10 -0400
Subject: [PATCH] core: network_environment + optional network_name; shell
shows /version fields
Add NetworkEnvironment (local/testnet/production, default production), optional network_name for display, genesis_operations_allowed() on Settings, and reject production+dev_mode at config load. Extend GET /version with those fields; update dev.toml and README.
Frontend: parse new /version keys in fetchCoreVersion, useCoreVersion, and AppShell subtitle; enlarge BrandMark (40px) and center-align with the title stack.
Tests: config cases, HTTP /version, Settings fixtures for network fields.
Made-with: Cursor
---
README.md | 2 +-
dev.toml | 3 ++
frontend/components/shell/AppShell.tsx | 39 +++++++++++++++----
frontend/components/shell/BrandMark.tsx | 8 ++--
frontend/hooks/useCoreVersion.ts | 18 ++++++++-
frontend/lib/coreApi.ts | 21 +++++++++-
src/modulr_core/config/__init__.py | 6 +++
src/modulr_core/config/load.py | 52 +++++++++++++++++++++++++
src/modulr_core/config/schema.py | 38 ++++++++++++++++++
src/modulr_core/http/app.py | 7 +++-
tests/test_config.py | 51 ++++++++++++++++++++++++
tests/test_http.py | 34 +++++++++++++++-
tests/test_messages_pipeline.py | 4 +-
tests/test_operations.py | 4 +-
14 files changed, 266 insertions(+), 21 deletions(-)
diff --git a/README.md b/README.md
index ecdd0bb..6618bc0 100644
--- a/README.md
+++ b/README.md
@@ -249,7 +249,7 @@ Defaults: **`127.0.0.1:8000`**. Override with `--host` / `--port`. If you see **
A **config file is required**: use **`--config dev.toml`** or set **`MODULR_CORE_CONFIG`** to a TOML path. If the port is already taken, the CLI exits with a short error before starting uvicorn.
-**Read-only:** **`GET /version`** returns JSON `target_module` and `version` (for UI connectivity). In **`dev_mode`**, CORS allows the local customer UI origins unless **`MODULR_CORE_CORS_ORIGINS`** is set (comma-separated list).
+**Read-only:** **`GET /version`** returns JSON `target_module`, `version`, **`network_environment`** (`local` | `testnet` | `production`, default `production` if omitted in config), **`network_name`** (operator display string — set `network_name` in TOML or get a default like `Modulr (local)`), and **`genesis_operations_allowed`** (boolean; `true` only on `local` / `testnet`). In **`dev_mode`**, CORS allows the local customer UI origins unless **`MODULR_CORE_CORS_ORIGINS`** is set (comma-separated list). **`network_environment = "production"`** cannot be combined with **`dev_mode = true`** (configuration is rejected at startup).
### Customer web UI (stage 1)
diff --git a/dev.toml b/dev.toml
index 75d4b86..71ce020 100644
--- a/dev.toml
+++ b/dev.toml
@@ -3,4 +3,7 @@
[modulr_core]
dev_mode = true
+network_environment = "local"
+# Optional human label for UIs and GET /version (like an Ethereum network name).
+# network_name = "Modulr Dev"
bootstrap_public_keys = []
diff --git a/frontend/components/shell/AppShell.tsx b/frontend/components/shell/AppShell.tsx
index 2e6f249..335c6c2 100644
--- a/frontend/components/shell/AppShell.tsx
+++ b/frontend/components/shell/AppShell.tsx
@@ -40,7 +40,7 @@ export function AppShell({ children }: { children: React.ReactNode }) {
href="/"
aria-label="Modulr.Core home"
aria-current={pathname === "/" ? "page" : undefined}
- className="flex min-w-0 shrink-0 items-start gap-3 rounded-xl outline-offset-2 transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--modulr-accent)]"
+ className="flex min-w-0 shrink-0 items-center gap-3 rounded-xl outline-offset-2 transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--modulr-accent)]"
>
@@ -48,18 +48,41 @@ export function AppShell({ children }: { children: React.ReactNode }) {
Modulr.Core
- {coreVersion.kind === "loading"
- ? "v…"
- : coreVersion.kind === "ok"
- ? `v${coreVersion.version}`
- : "unreachable"}
+ {coreVersion.kind === "loading" ? (
+ "v…"
+ ) : coreVersion.kind === "ok" ? (
+ <>
+ {`v${coreVersion.version}`}
+ {(coreVersion.networkDisplayName ||
+ coreVersion.networkEnvironment) && (
+
+ {coreVersion.networkDisplayName ??
+ coreVersion.networkEnvironment}
+
+ )}
+ >
+ ) : (
+ "unreachable"
+ )}
diff --git a/frontend/components/shell/BrandMark.tsx b/frontend/components/shell/BrandMark.tsx
index 91d96f5..2fe692c 100644
--- a/frontend/components/shell/BrandMark.tsx
+++ b/frontend/components/shell/BrandMark.tsx
@@ -3,13 +3,13 @@
import { ModulrSymbol } from "@/components/brand/ModulrSymbol";
/**
- * Header mark: explicit SVG dimensions + max width. Slight scale-up from `sm` matches
- * prior `27px` target without a second `