Expose the F16 credentialed public source for revocable CoreScope projections; preserve stable identities, generation fences and bounded overlap paging.
* fix(ci): pin gitleaks-action to valid commit after upstream force-push
Upstream deleted dcedce43 (force-push), so every ci.yml run fails at
workflow-parse with 0 jobs. The dependabot actions-group bump (#30)
contains this fix but cannot merge whole: its docker/* actions require
node24, which GitHub runners do not support yet. Pin gitleaks alone
(ff98106e is node20).
* fix(ci): downgrade v7 actions to node20-compatible versions
actions/checkout@v7, setup-node@v7, setup-python@v7 require node24,
which GitHub-hosted runners do not support yet — every ci.yml run has
failed at workflow-parse (0 jobs) since the Aug 3 v7 bump. Pin to the
latest node20 versions (checkout v4, setup-node v4, setup-python v5).
Also pins gitleaks-action to a valid commit (upstream force-pushed away
dcedce43).
* ci: noop retrigger
* fix(ci): escape literal ${{ in bash string so GitHub parser accepts workflow
The 'Validate tracked build and Compose inventory' step matched literal
${{ inside run-block strings, which GitHub's expression parser reads as
the start of an expression (${{'* is invalid) — the workflow fails at
parse time with 0 jobs. Split the literal as '$''{{' (bash concatenates
adjacent quoted strings at runtime; the source no longer contains a
contiguous ${{).
* fix(ci): resolve all three pre-existing ukmesh CI failures
Backend (packetBatchWriteCoalesce):
- 045: restore nodes_public_visibility_generation trigger — 015 is
superseded by 044 on fresh DBs so the trigger was never created,
leaving generation/visibility_generation out of sync and public
packet reads returning empty.
- 046: restore packet privacy classification — the 042 fence design
assumes sync_private_node_prefixes rewrites packets on privacy
change, but 026's version only maintains prefixes. Node flips to
private left old packets visible; direct SQL inserts were never
classified. Restore the packet rewrite in the sync trigger and add
a BEFORE INSERT trigger mirroring the batch path's is_private /
visibility_ok computation.
- packetBatch.integration.test.ts: exclude the prefix-cache refresh
query from statementCount (matches unit-test convention).
Frontend e2e:
- public.spec.ts: assert the TopologyMap component's actual labels
('Geographic repeater topology map', '2 mapped repeaters · 2
observed relationships') instead of the pre-map SVG graph labels.
Workers (pip install):
- viewshed-worker: bump numpy 1.26.4→2.3.5, scipy 1.13.1→1.16.3,
psycopg2-binary 2.9.10→2.9.11 (cp314 wheels); the base gdal image
ships Python 3.14 so the old pins had no wheels. Inherit shapely
from the image's python3-shapely apt package (no cp314 wheel
exists; source builds are GEOS 3.14-incompatible).
* fix(ci): restore data-plane services for compose validation and smoke test
Commit 8c5e1c8 split the long-lived data-plane services (timescaledb,
mosquitto, redis, mosquitto-reloader) into the external meshcore-infra
project on the live host, but the Workers-and-Compose CI job still
asserted their presence in the app compose project (max_worker_processes
check, inventory check, smoke-test execs). CI had been broken since
Aug 3 so the mismatch was never caught.
Add docker-compose.ci.yml — a CI-only overlay restoring the four
data-plane services from their pre-split definitions — and point every
compose invocation in the Workers-and-Compose job at
'-f docker-compose.yml -f docker-compose.ci.yml'.
Validated locally: merged config parses, the jq assertions and the full
inventory (db-migrate backend app-ukmesh website-ukmesh website-dev
mesh-health-check mosquitto-reloader link-worker link-backfill-worker
hopreach timescaledb mosquitto) all pass.
* fix(ci): include dev profile in compose inventory check
website-dev is a dev-profile service; the inventory gate compared the
base-config service list, so the merged stack never matched. This gate
has been red since the workflow was first written (CI parse-broken from
Aug 3 until the gitleaks pin landed).
* fix(ci): db-migrate must wait for timescaledb health
The Aug 9 data-plane split removed db-migrate's depends_on along with
the timescaledb service definition, so the migration runner raced the
fresh database init in the empty-volume smoke test and failed on the
not-yet-created base schema. Restore the pre-split condition:
timescaledb service_healthy.
* fix(ci): restore internal TCP MQTT listener for smoke test + exporter
Commit 40e843f dropped the 1883 TCP listener, breaking the CI smoke
(mosquitto_pub targets 1883) and the Prometheus mosquitto exporter.
The listener is internal-only: compose never publishes 1883 on the
host, and the password/ACL policy still applies.
---------
Co-authored-by: gadgethd <111318106+gadgethd@users.noreply.github.com>
* Fix map node freshness consistency
* Harden output, ingest, caches, and WebSocket limits
* Enforce public visibility across derived data
* Harden proxy and operator deployment boundary
* Make owner grants authoritative and reconcile ACLs safely
* Bound path, spam, and statistics analysis
* Make link and coverage jobs crash-safe
* Implement strategic security remediation
* Fix production cutover configuration
* Fix disabled viewshed worker health signal
* Serve stale stats during background refresh
* Retain stale stats through refresh windows
* Bound analytics work to protect ingestion
* Prioritize summary warmup over chart scans
* Throttle path history rebuilds
* Bound path history result memory
* Stream path history aggregation
* Give bounded path rebuild one CPU
* Serve stale charts during bounded refresh
* Prioritize startup stats before chart scans
* Bound path history segment cardinality
* Pin path rebuild context to privacy generation
* Self-host original frontend fonts
* Allow bounded path rebuild to complete
* Improve live map UI and low-latency group feed
- Dock node details on the right with selection highlight and collapsible layers
- Add node legend, 24h activity sparkline, copy-link, and layout/overlap fixes
- Keep all repeaters visible during Live Path focus
- Send GroupText feed packets immediately over WebSocket (no batch delay)
- Cache expensive stats/observer activity more aggressively to protect ingest
- Remove stale local planning/audit markdown from the tree
* fix(ci): supply OPERATOR_SITE_TOKEN for compose validation
Workers/Compose CI failed because docker-compose requires
OPERATOR_SITE_TOKEN. Add CI placeholders for that and MQTT_PASSWORD.
Consolidates the stacked backend, privacy, network-intelligence, frontend, operations, mobile, and owner-cache changes after resolving main conflicts and passing the full CI suite.
Use ${TERRAIN_TILES_PATH:-./terrain-tiles} so the path is configurable
per-host without leaking machine-specific paths in the repo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Multi-node LOS: multiple repeaters can have LOS active simultaneously,
each auto-expiring after 15 seconds; LOS persists after popup closes
- Custom LOS tool: desktop-only map button to sample terrain between two
points (click map or repeater); renders per-segment green/clear or
red/obstructed based on terrain height; prohibited nodes are excluded
- Terrain exaggeration: deck.gl altitudes multiplied by exaggeration factor
(2×) to match MapLibre's visual terrain mesh
- LOS line rendering: bloom+core PathLayer tube effect with ScatterplotLayer
endpoint markers; popup z-index fix so it renders above deck.gl canvas
- Terrain sampler: client-side Terrarium PNG tile decoder for elevation sampling
- DB schema: terrain_profile_json JSONB column added to node_links
- Nginx: terrain tile serving block added
- Docker: terrain tiles volume mount added
Excluded: PacketDetailPanel, UKFeedPage, styles/globals.css (unrelated local
changes), backfill_profiles.py (server-side utility, not intended for repo)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Lazy path resolver: geographic hop reconstruction from path_hashes without
pre-training data; fixes observer self-hash trimming bug
- ACL watcher worker: auto-provisions Mosquitto ACL entries when PUBLISH is
denied for a known user; eliminates the recurring gnomemoe ACL removal issue
- connectionMonitor: increase historical scan to 50 MB; fix OOM by streaming
lines instead of buffering; fixes missed backfill on restart
- Feed page: replace path-beta with lazy paths; add clickable node markers
showing name and public key; observer column nowrap; summary text unclipped
- PacketFeed: GRP-only message store protected from ADV eviction; scroll to
bottom on new message; 24-hour message backfill on initial load
- getRecentMessages: separate DB query for last 50 GRP messages last 24h
- getPacketDetail: new endpoint for full packet detail including observations
- Grafana/Loki/Promtail observability stack with Docker log collection
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New aclManager.ts rewrites a user's ACL block (all linked nodes) and
sends SIGHUP to the Mosquitto container whenever autoLinkOwnerNodeIds
runs at owner login, eliminating the need to manually edit the ACL
file when a user connects a second node.
- requireOwnerSession now resolves node IDs from owner_account_nodes
on every request instead of using the frozen session cookie list,
so manually- or auto-linked nodes are visible without re-login.
- docker-compose: mount mosquitto config dir (rw) and Docker socket
into backend so it can update the ACL file and signal Mosquitto.
- Add dockerode dependency for container SIGHUP signalling.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- narrow owner last-hop telemetry to the selected MQTT node and cache it per node with hourly background refresh
- tighten repeater-only last-hop classification and clean up the owner chart selector/filtering
- fix owner direct-sender map basemap, static behavior, and viewport fitting/centering
- allow bare ukmesh.com and teessidemesh.com host handling in backend/frontend config
Owner portal fixes:
- Fix session node ID case mismatch: decryptOwnerSession was lowercasing
node IDs but /owner/live uppercased the ?nodeId= param, so the find()
never matched — users always got "Node is not owned by this session"
- Revert sameSite strict → lax (broke sessions after March 18 deploy)
- Remove LOWER() wrappers from all owner live SQL (node IDs are uppercase)
- Add Fireball's second node (TS17 Yagi North) to owner_account_nodes
Tile worker:
- Server-side PNG tile rendering via @napi-rs/canvas
- Tile snapshot cache, Redis-backed tile cache, tile worker service
- /api/tiles/nodes/:z/:x/:y.png endpoint with rate limiter
- UK tile TTL logic
Cross-network connectivity:
- Add 7-day hourly history series to /cross-network-connectivity response
- Cache result for 60s to avoid repeated join-heavy query
- Fix query to use literal interval instead of interpolated variable
Other:
- Remove LOWER() from packet/node SQL throughout (IDs stored uppercase)
- Various performance and cleanup improvements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RADIO_BOT_URL is a private integration — strip the default service name
from docker-compose and remove it from the README env table.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New www.teessidemesh.com single-page dashboard (TeessieDashboard.tsx)
with amber/charcoal theme, connectivity status, repeater cards with
7-day battery sparklines, MQTT observer grid, and decoded packet feed
- Backend: cross-network connectivity endpoint (hop-count packet matching),
radio-stats and radio-history proxy endpoints, observer-activity endpoint,
nodesDay stat field
- docker-compose: website-teesside service on port 3002
- Path-beta: worker pool, resolve cache, and pool refactor for performance
- Connection monitor, WS server and MQTT client improvements
- Mosquitto config, viewshed worker, and frontend UI polish
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Drop duplicate MQTT packets when the same packet hash arrives at the
same observer with the same hop count within 120s. Increase TimescaleDB
max_connections to 300 to prevent connection exhaustion on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- move beta path resolution onto the backend with packet-level diagnostics and live API access
- add path simulation worker plumbing, health/schema updates, and compose wiring
- update app overlays to fetch server-computed beta paths with animated rendering and request caching
- refine mobile controls so map layers collapse behind a toggle and compact the links legend