mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-09-26 17:07:53 +00:00
Red commit: 94dc1d70a5a710271721d981cb5e36b7127b00dc Fixes #1574. cross-stack: justified — by design. Adds one server-side knob (`liveMap.maxNodes`) on the Go API and consumes it on the frontend (`public/live.js`) via the shared `/api/config/client` bootstrap in `public/roles.js`. Cannot land server-only or frontend-only without either dropping operator config (frontend-only) or leaving the literal in place (server-only). ## Problem (per triage) `public/live.js:2515-2516` hardcodes `/api/nodes?limit=2000` for the live-map node-load path. Reporter measured headroom at N=4300 and asked for an operator knob. Same `2000` magic also lives at `public/live.js:480` for the VCR-rewind `/api/packets?limit=2000`. ## Fix - New `liveMap.maxNodes` field in `Config` (default 2000). - `Config.LiveMapMaxNodes()` server-side clamp: `[100, 20000]`; zero/negative falls back to default. Defangs misconfig (e.g. 1M would OOM the SQLite read + JSON serialization path). - `/api/config/client` now returns `liveMapMaxNodes`. - `public/roles.js` reads it at bootstrap into `window.LIVE_MAP_MAX_NODES` (default 2000 to preserve behavior on stale caches). - `public/live.js` consumes `LIVE_MAP_MAX_NODES` at both the `/api/nodes` call sites (formerly :2515-2516) and the VCR-rewind `/api/packets` call (formerly :480) — single source of truth, in-scope per triage's "factor into a sibling const" suggestion. - `config.example.json` documents the knob with `_comment_maxNodes` per AGENTS.md config rule. ## TDD 1. **Red** (`94dc1d70`): added `test-issue-1574-live-map-max-nodes.js` (grep-asserts the literal is gone + `LIVE_MAP_MAX_NODES` / `liveMapMaxNodes` are wired + config example has the field) and `cmd/server/livemap_maxnodes_1574_test.go` (`/api/config/client` exposes `liveMapMaxNodes` + clamp table-driven cases). Stub `LiveMapMaxNodes()` returns 0 so the test compiles and fails on assertion, not import. 2. **Green** (this commit): real `LiveMapMaxNodes()` clamp + wire-up. All assertions pass; existing `cmd/server` suite still green. ## E2E note Frontend assertion is grep-based (literal removal + constant reference), in the established `test-issue-*` style used elsewhere (e.g. `test-issue-1189-live-iata-badge.js`). No Playwright change needed for a literal-replace; behavior validation is the server-side clamp + JSON shape tests. ## Out of scope No customizer UI change — operators set this in `config.json`, same pattern as `liveMap.propagationBufferMs`. Customizer surfacing can land as a follow-up if the operator wants it. --------- Co-authored-by: mc-bot <bot@corescope.local> Co-authored-by: Kpa-clawbot <bot@meshcore-analyzer>
50 lines
2.3 KiB
JavaScript
50 lines
2.3 KiB
JavaScript
/**
|
|
* Behavior test (#1574): operator-configurable `liveMap.maxNodes` cap.
|
|
*
|
|
* Today `public/live.js` hardcodes `/api/nodes?limit=2000` on two adjacent
|
|
* lines (~2515-2516) for the live-map node-load path. The same `2000`
|
|
* magic number also appears at :480 for `/api/packets?limit=2000` in the
|
|
* VCR-rewind code. The fix is to drive both literals from a single
|
|
* `LIVE_MAP_MAX_NODES` constant that is loaded from the server's
|
|
* client-config endpoint (`/api/config/client`) as `liveMapMaxNodes`,
|
|
* with operator override via `config.json` `liveMap.maxNodes` (default
|
|
* 2000, server-side clamp [100, 20000]).
|
|
*
|
|
* Reverting the fix (re-introducing the `?limit=2000` literal) MUST flip
|
|
* this test red.
|
|
*/
|
|
'use strict';
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
let passed = 0, failed = 0;
|
|
function assert(cond, msg) {
|
|
if (cond) { passed++; console.log(' \u2705 ' + msg); }
|
|
else { failed++; console.error(' \u274c ' + msg); }
|
|
}
|
|
|
|
const liveSrc = fs.readFileSync(path.join(__dirname, 'public', 'live.js'), 'utf8');
|
|
const rolesSrc = fs.readFileSync(path.join(__dirname, 'public', 'roles.js'), 'utf8');
|
|
|
|
// ── 1. The hardcoded /api/nodes?limit=2000 literal must be gone ─────────
|
|
const nodesLiteralHits = (liveSrc.match(/\/api\/nodes\?limit=2000/g) || []).length;
|
|
assert(nodesLiteralHits === 0,
|
|
'public/live.js no longer contains hardcoded `/api/nodes?limit=2000` literal (found ' +
|
|
nodesLiteralHits + ' occurrence(s))');
|
|
|
|
// ── 2. live.js consumes the operator-configurable LIVE_MAP_MAX_NODES ─────
|
|
assert(/LIVE_MAP_MAX_NODES/.test(liveSrc),
|
|
'public/live.js references LIVE_MAP_MAX_NODES constant');
|
|
|
|
// ── 3. roles.js plumbs `liveMapMaxNodes` from /api/config/client ────────
|
|
assert(/liveMapMaxNodes/.test(rolesSrc),
|
|
'public/roles.js reads `liveMapMaxNodes` from /api/config/client and exposes LIVE_MAP_MAX_NODES');
|
|
|
|
// ── 4. config.example.json documents the knob ────────────────────────────
|
|
const cfgExample = fs.readFileSync(path.join(__dirname, 'config.example.json'), 'utf8');
|
|
assert(/"maxNodes"\s*:/.test(cfgExample),
|
|
'config.example.json declares liveMap.maxNodes default');
|
|
|
|
console.log('\nResults: ' + passed + ' passed, ' + failed + ' failed');
|
|
process.exit(failed > 0 ? 1 : 0);
|