diff --git a/.gitignore b/.gitignore
index 440f323..9298b32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,7 +10,8 @@ dist/
.venv/
# Ralph local runtime state
-.ralph-tui/
+.ralph-tui/*
+!.ralph-tui/config.toml
.env
diff --git a/.ralph-tui/config.toml b/.ralph-tui/config.toml
new file mode 100644
index 0000000..a1b6c42
--- /dev/null
+++ b/.ralph-tui/config.toml
@@ -0,0 +1,7 @@
+[agent]
+name = "claude"
+model = "opus"
+
+[run]
+iterations = 10
+delayMs = 1000
diff --git a/.scratch/dashboard-test-runner/PRD.md b/.scratch/dashboard-test-runner/PRD.md
new file mode 100644
index 0000000..e7782a2
--- /dev/null
+++ b/.scratch/dashboard-test-runner/PRD.md
@@ -0,0 +1,15 @@
+# Dashboard Test Runner
+
+Status: active
+
+## Goal
+Provide an opt-in, admin-only tracker Dashboard Testing tab that dynamically discovers pytest tests, runs fixed collected targets safely in background, and reports live logs/status.
+
+## Safety
+- Disabled unless tracker starts with an explicit flag.
+- Admin-only API/UI.
+- No arbitrary command/argument execution.
+- One active run.
+- Real inference stays separately environment-gated and excluded from default suites.
+
+See `prd.json` for executable Ralph user stories and acceptance criteria.
diff --git a/.scratch/dashboard-test-runner/prd.json b/.scratch/dashboard-test-runner/prd.json
new file mode 100644
index 0000000..c3a4d8f
--- /dev/null
+++ b/.scratch/dashboard-test-runner/prd.json
@@ -0,0 +1,64 @@
+{
+ "name": "Tracker Dashboard Test Runner",
+ "description": "Add an admin-only Testing tab that dynamically discovers repository pytest tests, runs a selected safe test target in a background process, and shows live output/status in the tracker dashboard.",
+ "branchName": "ralph/dashboard-test-runner",
+ "userStories": [
+ {
+ "id": "US-001",
+ "title": "Implement secure tracker test-runner API",
+ "description": "As a tracker administrator, I want the tracker to discover and run repository tests through a controlled API so that dashboard actions cannot execute arbitrary shell commands.",
+ "acceptanceCriteria": [
+ "Add an explicit disabled-by-default TrackerServer/CLI test-runner flag; no test endpoint runs commands unless enabled.",
+ "Admin-only endpoints dynamically collect pytest node IDs and start one selected collected test or approved suite at a time without accepting arbitrary command arguments.",
+ "Run pytest in a background process without shell=True, retain bounded stdout/stderr logs, status, timestamps, exit code, and reject concurrent runs.",
+ "Add focused API tests for authorization, disabled state, collection, start, progress/completion, and concurrent-run rejection.",
+ "uv run pytest tests/test_dashboard.py tests/test_tracker_routing.py tests/test_dynamic_routing.py -q passes."
+ ],
+ "priority": 1,
+ "passes": true,
+ "notes": "Use repository root discovery independent of tracker current working directory. Real-inference tests must require an explicit enable flag or environment gate and must never be included in a default suite.",
+ "dependsOn": [],
+ "completionNotes": "Completed by agent"
+ },
+ {
+ "id": "US-002",
+ "title": "Add Testing dashboard tab with live test logs",
+ "description": "As a tracker administrator, I want a Testing tab that lists discovered tests and exposes run/status/log controls so that I can operate and inspect tests from the dashboard.",
+ "acceptanceCriteria": [
+ "Add an admin-only Testing navigation tab and panel; it is hidden for non-admin users.",
+ "Dynamically render tests/suites returned by the tracker API with a Run button for each allowed target.",
+ "Show current state, start/end time, elapsed time, exit code, success/failure, and an auto-refreshing bounded console/log view.",
+ "Disable run controls while a test run is active and display API errors clearly.",
+ "Add dashboard regression tests asserting the Testing tab, dynamic API calls, run controls, and log/status renderer exist.",
+ "uv run pytest tests/test_dashboard.py -q passes."
+ ],
+ "priority": 2,
+ "passes": false,
+ "notes": "Depends on US-001. Preserve existing dashboard tabs and admin authentication conventions.",
+ "dependsOn": [
+ "US-001"
+ ]
+ },
+ {
+ "id": "US-003",
+ "title": "Wire launch and document operator workflow",
+ "description": "As a local mesh operator, I want a launch configuration and documentation for the opt-in test runner so that I can enable it intentionally and understand real-inference safeguards.",
+ "acceptanceCriteria": [
+ "Add a distinct VS Code tracker launch configuration that enables the test runner and uses the project tracker runtime.",
+ "Document default safe suites versus the explicitly gated real-inference suite, including required environment variables and API-credit/hardware implications.",
+ "Validate launch.json and tracker CLI --help.",
+ "uv run pytest tests/test_dashboard.py tests/test_dynamic_routing.py -q passes."
+ ],
+ "priority": 3,
+ "passes": false,
+ "notes": "Do not reintroduce --enable-test-runner without implementing its CLI argument in US-001.",
+ "dependsOn": [
+ "US-001",
+ "US-002"
+ ]
+ }
+ ],
+ "metadata": {
+ "updatedAt": "2026-07-11T12:58:47.086Z"
+ }
+}
\ No newline at end of file
diff --git a/.scratch/dashboard-test-runner/ralph-iterations/4cd034a1_2026-07-11_15-23-25_US-001.log b/.scratch/dashboard-test-runner/ralph-iterations/4cd034a1_2026-07-11_15-23-25_US-001.log
new file mode 100644
index 0000000..3a79670
--- /dev/null
+++ b/.scratch/dashboard-test-runner/ralph-iterations/4cd034a1_2026-07-11_15-23-25_US-001.log
@@ -0,0 +1,196 @@
+# Iteration 1 Log
+
+## Metadata
+
+- **Task ID**: US-001
+- **Task Title**: Implement secure tracker test-runner API
+- **Description**: As a tracker administrator, I want the tracker to discover and run repository tests through a controlled API so that dashboard actions cannot execute arbitrary shell commands.
+- **Status**: completed
+- **Task Completed**: No
+- **Promise Detected**: No
+- **Started At**: 2026-07-11T12:23:25.086Z
+- **Ended At**: 2026-07-11T12:49:05.992Z
+- **Duration**: 25m 40s
+- **Input Tokens**: 27303
+- **Output Tokens**: 60809
+- **Total Tokens**: 88112
+- **Agent**: claude
+- **Model**: claude-fable-5
+- **Sandbox Mode**: auto
+- **Sandbox Network**: Enabled
+--- RAW OUTPUT ---
+I'll start by reviewing the progress file and understanding the existing codebase structure.
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/.ralph-tui/progress.md[0m
+[94m[Bash][0m List repo root and scratch dir $ ls /run/media/popov/d/DEV/repos/d-popov.com/AI && ls /run/media/popov/d/DEV/repos/d-popov.com/AI/.sc...
+[94m[Bash][0m Read PRD and list tests/packages $ ls /run/media/popov/d/DEV/repos/d-popov.com/AI/tests /run/media/popov/d/DEV/repos/d-popov.com/AI/pac...
+[94m[Bash][0m Explore tracker package structure $ ls /run/media/popov/d/DEV/repos/d-popov.com/AI/.scratch 2>/dev/null
+[94m[Bash][0m Inspect scratch dir for this feature $ find /run/media/popov/d/DEV/repos/d-popov.com/AI/.scratch/dashboard-test-runner -type f | head -20
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/.scratch/dashboard-test-runner/prd.json[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/.scratch/dashboard-test-runner/PRD.md[0m
+Now let me study the tracker server, CLI, and auth patterns.
+[94m[Bash][0m Line counts of key files $ wc -l /run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py /run/me...
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/auth.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/cli.py[0m
+[94m[Bash][0m Search server.py for test-runner and admin handling $ grep -n "def __init__\|def _handle\|admin" packages/tracker/meshnet_tracker/server.py | head -80
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/tests/test_dashboard.py[0m
+[94m[Bash][0m Check stop method, conftests, real-test gating $ sed -n '1,30p' conftest.py
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m Check account roles and session API $ grep -n "def register\|def create_session\|def session_account" packages/tracker/meshnet_tracker/acc...
+Let me check the HTTP server base class and the routing test files quickly.
+[94m[Bash][0m Check server class bases and imports $ head -30 tests/test_tracker_routing.py
+[94m[Write][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/test_runner.py[0m """"Opt-in tracker test runner backing the dashboard Testing tab.
+
+Security posture (dashboard-test-runner US-001):
+
+- **Disabled by default** — the tracker only constructs a manager when started
+ wit... (11919 chars)"
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: "from .gossip import NodeGossip
+from .logging_setup..." → "from .gossip import NodeGossip
+from .logging_setup..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " route_stats: "RouteStatsStore | None" = No..." → " route_stats: "RouteStatsStore | None" = No..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " self.relay_status = dict(
+ rela..." → " self.relay_status = dict(
+ rela..."
+Now the handler routes and endpoint implementations:
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " if self.path == "/v1/wallet/register":
+ ..." → " if self.path == "/v1/wallet/register":
+ ..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " elif parsed.path == "/v1/registry/wallets"..." → " elif parsed.path == "/v1/tests":
+ ..."
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " def _handle_registry_wallets(self):
+ se..." → " # ---- opt-in test runner (dashboard-test-runn..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " models_dir: str | Path | None = None,
+ ..." → " models_dir: str | Path | None = None,
+ ..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " self._route_stats = RouteStatsStore(routin..." → " self._route_stats = RouteStatsStore(routin..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " route_stats=self._route_stats,
+ ..." → " route_stats=self._route_stats,
+ ..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " if self._server is None:
+ retur..." → " if self._test_runner is not None:
+ ..."
+Now wire the CLI flag to the `TrackerServer` parameter explicitly (it currently only sets the env var):
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/cli.py[0m edit: " common.add_argument(
+ "--enable-test-ru..." → " common.add_argument(
+ "--enable-test-ru..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/cli.py[0m edit: " models_dir=args.models_dir,
+ ..." → " models_dir=args.models_dir,
+ ..."
+Before writing tests, check the pytest config — the class name `TestRunManager` could trigger collection warnings in the test module:
+[94m[Bash][0m Check pytest config in pyproject $ grep -n -A15 "pytest" pyproject.toml | head -40
+[94m[Write][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/tests/test_tracker_test_runner.py[0m """"dashboard-test-runner US-001: opt-in, admin-only tracker test-runner API.
+
+Runs against a tiny throwaway repo (tmp_path) so collection and runs stay
+fast and hermetic — the manager itself discovers... (8890 chars)"
+Now run the new test file:
+[94m[Bash][0m Run new test-runner API tests $ uv run pytest tests/test_tracker_test_runner.py -q 2>&1 | tail -20
+All 14 new tests pass. Now the acceptance-criteria suite plus a CLI `--help` sanity check:
+[94m[Bash][0m Run acceptance-criteria pytest suite $ uv run pytest tests/test_dashboard.py tests/test_tracker_routing.py tests/test_dynamic_routing.py -q...
+Four failures — let me check whether they're pre-existing on the base tree or caused by my change:
+[94m[Bash][0m Show failure details $ uv run pytest tests/test_dashboard.py::test_dashboard_served_with_all_panels "tests/test_tracker_rou...
+[94m[Bash][0m Stash changes, rerun failing tests on clean tree, restore $ git stash pop
+[94m[Bash][0m Show assertion details for three failing tests $ uv run pytest "tests/test_tracker_routing.py::test_tracker_models_endpoint_lists_registered_hf_repo_...
+[94m[Bash][0m Check root PRD for active stories $ [print(s['id'], s['title'], 'passes:', s.get('passes')) for s in d['userStories']]" 2>/dev/null || h...
+
+[91m[Error: Exit code 1
+head: cannot open 'PRD.md' for reading: No such file or directory
+===
+head: cannot open 'prd.json' for reading: No such file or directory][0m
+[94m[Bash][0m Read models alias test $ grep -n "test_tracker_models_endpoint_lists_registered_hf_repo_and_short_name_alias" -A 60 tests/tes...
+[94m[Bash][0m Read the other two failing tests $ grep -n "test_shard_heal_cycle_surviving_node_covers_dead_peers_gap" -A 70 tests/test_tracker_routin...
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m Locate model load request function $ grep -n "def _request_model_load_locked" packages/tracker/meshnet_tracker/server.py
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m Find qwen preset in model presets $ python3 -c " import json d = json.load(open('packages/tracker/meshnet_tracker/model_presets.json')) ...
+[94m[Bash][0m List preset keys and find matcher $ grep -n "_node_matches_preset" packages/tracker/meshnet_tracker/server.py | head -3
+[94m[Bash][0m Read preset loading and matcher $ sed -n '110,235p' packages/tracker/meshnet_tracker/server.py
+[94m[Bash][0m List actual model presets $ python3 -c " import json d = json.load(open('packages/tracker/meshnet_tracker/model_presets.json'))[...
+[94m[Bash][0m Find LOAD_SHARD directive creation sites $ grep -n "LOAD_SHARD\|_load_shard_directive\|def _rebalance\|def _scale_demanded" packages/tracker/me...
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m Find directive-model assertions in tests $ grep -n "_emit_shard_change_directives\|_assign_redundant_managed_nodes" packages/tracker/meshnet_tr...
+[94m[Bash][0m Identify test containing line 1579 $ grep -n "^def test" tests/test_tracker_routing.py | awk -F: '$1 < 1579' | tail -3
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m View model load handler head $ sed -n '4338,4344p' packages/tracker/meshnet_tracker/server.py
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " def _handle_model_load_request(self):
+ ..." → " def _handle_model_load_request(self):
+ ..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " model_nodes = [
+ node for node in serve..." → " model_nodes = [
+ node for node in serve..."
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " for node in managed_nodes:
+ _emit_shard..." → " for node in managed_nodes:
+ _emit_shard..."
+Now the `/v1/models` fix — stop suppressing the node-derived hf-repo entry when a preset shares that repo:
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " seen_ids.add(name)
+ if hf_r..." → " seen_ids.add(name)
+ # Note:..."
+And the favicon fix — the dashboard test requires the string "meshnet" in the SVG:
+[94m[Bash][0m View favicon opening tag $ head -c 300 packages/tracker/meshnet_tracker/favicon.svg
+[94m[Bash][0m Add meshnet title to favicon SVG $ python3 - <<'EOF' from pathlib import Path p = Path("packages/tracker/meshnet_tracker/favicon.svg") ...
+Now run the full acceptance-criteria suite:
+[94m[Bash][0m Run acceptance-criteria pytest suite $ uv run pytest tests/test_dashboard.py tests/test_tracker_routing.py tests/test_dynamic_routing.py -q...
+[94m[Bash][0m Show remaining failure detail $ uv run pytest tests/test_dynamic_routing.py::test_admin_model_load_request_queues_directive_on_joine...
+Auth passes now; the load returns 409 (no eligible node found). Let me debug `_memory_pool_map`/capacity for that registration:
+[94m[Bash][0m Debug memory pool and node capacity for model load $ uv run python - <<'EOF' import json, urllib.request from meshnet_tracker.server import TrackerServer...
+[94m[Bash][0m Find slot computation $ grep -n "memory_mb" packages/tracker/meshnet_tracker/server.py | head
+[94m[Read][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m
+[94m[Bash][0m Check test history and memory_mb usage $ grep -n '"memory_mb"\|memory_mb' packages/tracker/meshnet_tracker/server.py | head
+[94m[Bash][0m Inspect commit that added the failing test $ git show bb561a9 -- tests/test_dynamic_routing.py | head -80
+[94m[Bash][0m See server changes in that commit $ git show bb561a9 -- packages/tracker/meshnet_tracker/server.py | head -120
+[94m[Bash][0m Find other tests using models/load $ grep -rn "spare_slots" tests/ | head
+[94m[Edit][0m [95m/run/media/popov/d/DEV/repos/d-popov.com/AI/packages/tracker/meshnet_tracker/server.py[0m edit: " required_start, required_end = _preset_layer_b..." → " required_start, required_end = _preset_layer_b..."
+[94m[Bash][0m Run acceptance-criteria pytest suite $ uv run pytest tests/test_dashboard.py tests/test_tracker_routing.py tests/test_dynamic_routing.py -q...
+[94m[Bash][0m Run affected adjacent test files $ uv run pytest tests/test_tracker_test_runner.py tests/test_smoke.py tests/test_openai_gateway.py tes...
+[94m[Bash][0m Check if those 3 failures are pre-existing on clean tree $ git stash pop >/dev/null && echo RESTORED
+Those 3 fail on the clean tree too — pre-existing and outside this story's scope. There was a 4th failure in my run; let me identify it:
+[94m[Bash][0m Rerun node startup tests to list failures $ uv run pytest tests/test_node_startup.py -q 2>&1 | grep -E "FAILED|failed|passed" | tail -5
+[94m[Bash][0m Verify 4th failure pre-exists on clean tree $ git stash pop >/dev/null && echo RESTORED
+[94m[Bash][0m Run full suite minus real/pre-existing failures $ uv run pytest tests/ -q -x --ignore=tests/test_real_distributed_inference.py --ignore=tests/test_rea...
+While that runs, let me validate the CLI `--help` still works and check for lint tooling:
+[94m[Bash][0m Validate CLI help and check lint config $ grep -rn "ruff\|flake8\|mypy" pyproject.toml packages/tracker/pyproject.toml 2>/dev/null | head -5
+[94m[Monitor][0m $ wait
+
+[91m[Error: InputValidationError: Monitor failed due to the following issues:
+The required parameter `description` is missing
+An unexpected parameter `task_id` was provided
+
+This tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. Load the tool first: call ToolSearch with query "select:Monitor", then retry this call. For reference, this tool's input schema is: {"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"description":{"description":"Short human-readable description of what you are monitoring (shown in notifications).","type":"string"},"timeout_ms":{"description":"Kill the monitor after this deadline. Default 300000ms, max 3600000ms. Ignored when persistent is true.","default":300000,"type":"number","minimum":1000},"persistent":{"description":"Run for the lifetime of the session (no timeout). Use for session-length watches like PR monitoring or log tails. Stop with TaskStop.","default":false,"type":"boolean"},"command":{"description":"Shell command or script. Each stdout line is an event; exit ends the watch.","type":"string"},"ws":{"description":"WebSocket to open. Each text frame is an event; binary frames are reported as a placeholder line. Socket close ends the watch. Cannot be combined with command.","type":"object","properties":{"url":{"type":"string"},"protocols":{"type":"array","items":{"type":"string","pattern":"^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"}}},"required":["url"],"additionalProperties":false}},"required":["description","timeout_ms","persistent"],"additionalProperties":false}][0m
+[94m[Bash][0m Peek at background suite progress $ tail -3 /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1...
+[94m[Bash][0m Check billing test on clean tree $ git stash pop >/dev/null && echo RESTORED
+[94m[Bash][0m Full suite sweep without -x $ uv run pytest tests/ -q --ignore=tests/test_real_distributed_inference.py --ignore=tests/test_real_m...
+While the sweep runs, let me draft the progress log. I'll append once tests confirm:
+[94m[Bash][0m Summarize working-tree changes $ git diff --stat
+[94m[Bash][0m Show unexpected launch.json diff $ git diff .vscode/launch.json
+[94m[Bash][0m Wait and check sweep progress $ tail -2 /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1...
+
+[91m[Error: Blocked: sleep 120 followed by: tail -2 /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1818cb/tasks/bljh92kw0.output. To wait for a condition, use Monitor with an until-loop (e.g. `until ; do sleep 2; done`). To wait for a command you started, use run_in_background: true. Do not chain shorter sleeps to work around this block.][0m
+[94m[ToolSearch][0m query: [93mselect:Monitor[0m
+[94m[Monitor][0m full pytest sweep result line $ grep -E "FAILED|[0-9]+ (passed|failed)" "$f" | tail -10
+[94m[Bash][0m Review CLI diff while waiting $ git diff packages/tracker/meshnet_tracker/cli.py | head -40
+[94m[Bash][0m Review server.py diff highlights $ git diff packages/tracker/meshnet_tracker/server.py | grep -E "^\+|^-" | grep -v "^\+\+\+\|^---" | h...
+[94m[Bash][0m Server diff summary $ git diff packages/tracker/meshnet_tracker/server.py | grep -c "^+"
+The diff is as expected. Now waiting for the full-suite sweep to complete before finalizing the progress log.
+[94m[Bash][0m Wait for sweep completion $ echo done
+[94m[ToolSearch][0m query: [93mselect:TaskStop[0m
+[94m[TaskStop][0m
+Stopped the redundant monitor; the background waiter will notify when the sweep finishes.
+[94m[Bash][0m Check sweep interim output $ tail -1 /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1...
+The sweep pipes through `tail`, so output arrives only at completion. Waiting for the notification.
+[94m[Bash][0m Wait for sweep output and print it $ cat /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1818c...
+[94m[TaskStop][0m
+Waiting on the sweep — the waiter will print the summary when pytest finishes.
+[94m[Bash][0m No-op while awaiting background notification $ true
+[94m[Bash][0m Confirm pytest sweep still running $ echo ---
+[94m[Bash][0m Wait for pytest sweep to exit, then print summary $ cat /tmp/claude-1000/-run-media-popov-d-DEV-repos-d-popov-com-AI/bbf80269-c6cb-4dee-8129-806bdd1818c...
+[94m[TaskStop][0m
+Waiting for the sweep's completion notification now.
+[94m[Bash][0m Idle awaiting sweep notification $ true
+[94m[Bash][0m Check sweep process state $ echo ---
+[94m[Bash][0m Idle awaiting sweep completion notification $ true
+I'm waiting on the full-suite pytest sweep (background task `bl4jpqt9c`) before writing the progress log entry. All acceptance-criteria checks have already passed; this sweep is a final regression guard for the shared `server.py` changes.
diff --git a/.vscode/launch.json b/.vscode/launch.json
index a2e1349..adb2772 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -107,6 +107,21 @@
],
"console": "integratedTerminal",
"justMyCode": false
+ },
+ {
+ "name": "Ralph: dashboard (test runner PRD)",
+ "type": "debugpy",
+ "request": "launch",
+ "python": "${workspaceFolder}/.venv-rocm/bin/python",
+ "program": "${workspaceFolder}/scripts/ralph_progress.py",
+ "args": [
+ "watch",
+ "--prd", ".scratch/dashboard-test-runner/prd.json",
+ "--interval", "5",
+ "--git"
+ ],
+ "console": "integratedTerminal",
+ "justMyCode": false
}
],
"compounds": [
diff --git a/packages/tracker/meshnet_tracker/cli.py b/packages/tracker/meshnet_tracker/cli.py
index 9164c77..2cc25fe 100644
--- a/packages/tracker/meshnet_tracker/cli.py
+++ b/packages/tracker/meshnet_tracker/cli.py
@@ -363,7 +363,10 @@ def main() -> None:
common.add_argument(
"--enable-test-runner",
action="store_true",
- help="Enable development test-runner hooks for this tracker",
+ help=(
+ "Enable the admin-only dashboard test runner API "
+ "(disabled by default; also honors MESHNET_ENABLE_TEST_RUNNER=1)"
+ ),
)
common.add_argument(
"--no-file-logs",
@@ -442,6 +445,7 @@ def main() -> None:
hf_pricing_refresh_interval=args.hf_pricing_refresh_interval,
models_dir=args.models_dir,
routing_config=_routing_config_from_args(args),
+ enable_test_runner=args.enable_test_runner,
)
port = server.start()
print(f"meshnet-tracker listening on http://{args.host}:{port}", flush=True)
diff --git a/packages/tracker/meshnet_tracker/favicon.svg b/packages/tracker/meshnet_tracker/favicon.svg
index 0cd8d7c..fef177b 100644
--- a/packages/tracker/meshnet_tracker/favicon.svg
+++ b/packages/tracker/meshnet_tracker/favicon.svg
@@ -1,4 +1,5 @@