chore(release): v1.17.0 — merge dev, close out roadmap items - #22
Merged
Conversation
Captures the findings from a code review of the RF simulator mode: 4 confirmed bugs (CSS syntax error, WASM cache-bust, silent error handling, unused BitmapLayer), 6 missing/incomplete features, and a prioritized fix order. https://claude.ai/code/session_01U5an6dttfUWUojUyxNEWW1
eslint.config.js had no plugin providing JSX-usage detection, so plain no-unused-vars couldn't see that a capitalized JSX tag references its import -- this produced ~100 false-positive warnings across the codebase that were masking real ones. Add eslint-plugin-react's jsx-uses-vars rule (only that rule, not its full stylistic/prop-types set). With the false positives gone, fix what was left: a dead `elevation` var in CoverageLayerManager, an unused caught SSE-parse error in useSimulationStore, and annotate two intentional signal-triggered useEffects (CoverageLayerManager, RFContext) that read the latest render's closure rather than tracking every dependency. Also run npm audit fix to close all production vulnerabilities (critical fast-xml-parser via @loaders.gl/xml, high lodash, moderate protocol-buffers-schema) plus the dev-tooling ones (vite, vitest, brace-expansion). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
ROADMAP.md had the P5-6/P5-7 sections duplicated verbatim from a copy-paste error. README.md links to Documentation/pwa-guide.md, which never existed -- write it from the actual vite-plugin-pwa config. Drop itmlogic from rf-engine/requirements.txt: it was declared but never imported (ROADMAP P4-1 is still open, re-add when that's implemented). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
.github/workflows only had docker-publish and cleanup-packages -- nothing ran npm run lint, npm test, or the rf-engine pytest suite on pushes/PRs. Add a ci.yml workflow that runs both on dev/main pushes and PRs targeting them, so regressions don't silently accumulate. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
Multi-Site Analysis previously rendered every selected node's viewshed into one flat cyan composite, making it impossible to tell which node covers which area or spot redundant placements visually (the numeric "unique coverage %" was the only signal). Backend (rf-engine/core/viewshed_proc.py): assign each selected node an evenly-spaced distinct hue and render coverage as alpha-composited color layers instead of a single flat mask -- overlapping nodes blend naturally where their coverage intersects. Each result now carries a `color` field. Also factor the pixel-projection math (mapping a node's local viewshed grid into the shared master-grid coordinates) into one `_project_to_master` helper, replacing three near-identical inline copies used by the greedy optimizer, marginal-coverage pass, and composite renderer. Frontend: color-match the simulation node markers and popups (OptimizationLayerManager.jsx) and the Sites results table (SitesTab.jsx) to the same per-node color, so a node's marker, popup, and coverage patch on the map are visually tied together. Also fixes a pre-existing dead `res.coverage_points` reference in the marker popup (the backend never produced that field) by showing unique coverage % instead. Adds test coverage for the new color assignment and composite rendering, which the prior tests never exercised (they only used all-zero grids). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
Summarizes the lint/security cleanup, new CI workflow, and P6-1 per-node coverage visualization from the preceding commits. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
Now that JSX usage is correctly detected, clean up what was left: - Removed genuinely dead code: unused txIcon/rxIcon constants and an abandoned fresnelRef in LinkLayer.jsx, an unused syncState helper and its backing ref in OptimizationLayer.jsx, and stale proxy-value destructuring left over from the P2-4 per-node-config refactor. - Removed the entire `coverageOverlay` state chain (useLinkTool.js -> MapContainer.jsx -> LinkLayerManager.jsx -> LinkLayer.jsx): it was only ever set to null, never to a real value, so the ImageOverlay it fed never rendered anything. - Fixed a real gap in HeatmapOverlay.jsx: a per-point opacity was computed from score but never applied, the fillOpacity was hardcoded to 0.3 instead. - Fixed a dead `res.coverage_points` style leftover (unused args/index params) across OptimizationResultsPanel, BatchNodesList, ModelComparisonTable, SiteAnalysisResultsPanel. - Annotated intentional signal-triggered useEffects (Sidebar mobile auto-close, DeckGLOverlay mount lifecycle, LinkLayer/OptimizationLayer recalc-on-signal) that eslint's exhaustive-deps flagged -- adding the suggested deps would have introduced real bugs (e.g. Sidebar's toggle button fighting its own auto-close effect). - Disabled react-refresh/only-export-components at the file level for the 5 context files (EnvironmentContext, HardwareContext, RFContext, RadioContext, UIContext). Splitting each Provider from its hook/constants is the "proper" fix but would touch ~25 import sites across the app for a dev-only Fast Refresh granularity concern with no effect on correctness or production builds -- not proportionate here. Verified: npm run lint (0 warnings), npm test (7/7), npm run build, pytest rf-engine/tests (9/9). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DwJgxrJr8scmomw9B8Lk9W
Closes P3-1, P3-3, P3-4 and P4-2 ahead of the next production build. P3-1 -- Client-side Hata/FSPL: Port Okumura-Hata to JavaScript (src/utils/math/hata.js), mirroring rf_physics.calculate_hata_loss term-for-term including input clamping; both engines agree to 4 decimal places on the reference cases. Add a dispatcher (src/utils/math/pathLoss.js) and wire LinkLayer to resolve `fspl` and `hata` locally, so neither needs /api/calculate-link and both keep working offline/PWA. `bullington` and server `itm` stay on the backend, which applies clutter_height and k_factor to the profile in ways the current JS Bullington does not. P4-2 -- COST 231-Hata: Extend Hata coverage from 150-1500 MHz to 150-2000 MHz in both engines. Selecting "Hata" auto-dispatches to COST 231 at/above 1500 MHz; `cost231` is also accepted as an explicit backend model. Per the standard, COST 231 defines only the 3 dB metropolitan correction and has no suburban/rural term, so those environments now warn above the crossover rather than silently reusing the Okumura-Hata corrections. Link Analysis validity warnings now come from a single getHataValidity helper. P3-3 -- WASM ITM for batch reports: Add a propagation-model selector to Batch Processing. ITM runs the same WASM engine as Link Analysis over a 100-point profile (vs 20 for Bullington), honouring Ground Type and Climate Zone, so batch numbers match single-link analysis. The module loads lazily on selection (useWasmITM gained an `enabled` flag, keeping it off the startup path), and a link that fails ITM falls back to Bullington instead of failing the whole report. P3-4 -- Per-node configs in batch CSV: Parse optional Antenna_Height, Antenna_Gain, TX_Power, Device and Antenna columns, with aliases and loose preset-name matching. nodeConfig.js merges them over the global A/B config field-by-field; blank cells and existing three-column files behave exactly as before. Also fixed: Bullington diffraction was never displayed for Hata in LinkLayer -- the check compared against 'Hata' while the model value is lowercase 'hata'. Mesh report export now writes via a Blob and escapes CSV fields, so node names containing commas no longer corrupt the report, and it gained Model/PathLoss_dB/per-node parameter columns plus a progress bar. P4-6 (variability modes) is documented as blocked: it needs new LinkParameters fields and an emscripten rebuild of meshrf.wasm. Tests: 44 frontend (28 new), 23 backend (14 new). Lint and build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FU7LVUXdVx5YfXt4eJJSPs
ITM's time/location/situation variability was hardcoded to 50/50/50 in meshrf_itm.cpp, so every prediction was the median forecast with no way to plan for worst-case conditions. It is now user-selectable. C++ / WASM: - Add time_pct, loc_pct, sit_pct and mdvar to LinkParameters, defaulted to the values calculate_radial_loss previously hardcoded (50/50/50, mdvar=12). - Expose them through Embind. - Thread variability into the coverage path; calculate_rf_coverage gained three trailing arguments, so useRFCoverageTool now passes 20 (Embind matches on arity). - Regenerate public/meshrf.wasm, libmeshrf/js/meshrf.wasm and libmeshrf/js/meshrf.js. ROADMAP P4-6 documents the rebuild command. Frontend: - RELIABILITY_MODES presets in EnvironmentContext: Best Case (10/10/10), Typical (50/50/50, default), Reliable (90/90/90). - Reliability selector in the Environment sidebar. - Wired through Link Analysis, RF Coverage (click, recalc and drag paths) and batch ITM reports; batch rows record the mode that produced them. Backward compatibility is the important property here, and it is verified against the built module rather than assumed: a call that never sets the new fields returns a bit-identical result to an explicit 50/50/50. Struct defaults, all four Embind bindings, the 20-arg coverage call and the untouched viewshed binding were each exercised against the installed artifacts. Measured on a synthetic ridge (915 MHz, 10 m TX / 2 m RX): 10/10/10 = 193.49 dB, 50/50/50 = 203.76 dB, 90/90/90 = 213.66 dB. Note the WASM was rebuilt with emcc 6.0.4, which also regenerates the JS glue every WASM hook imports. Unit tests cannot cover a glue regression, so link analysis, coverage and viewshed want a manual pass before this ships. Tests: 52 frontend (8 new), 23 backend. Lint and build clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FU7LVUXdVx5YfXt4eJJSPs
feat: complete Phase 3 roadmap + COST 231 + ITM variability modes
Pulls in the accumulated dev work that never shipped: per-node coverage visualization (P6-1), client-side Hata/FSPL (P3-1), WASM ITM for batch reports (P3-3), per-node CSV configs (P3-4), COST 231-Hata (P4-2), and selectable ITM reliability modes (P4-6), plus the new CI workflow and lint/audit cleanup. Converts the Unreleased changelog entry to 1.17.0 and refreshes RELEASE_NOTES.md and the roadmap date. Also applies npm audit fix for newly-disclosed dev-tooling advisories (brace-expansion, fast-uri, js-yaml) surfaced since dev's last audit pass.
Sidebar.jsx sets white-space: nowrap on the <aside> itself (to keep the collapse/expand transition from reflowing labels), which inherits down to every descendant. The Reliability variability description and the batch CSV format/download line never got a local whiteSpace: 'normal' override like other multi-line help text in this codebase already has (BatchProcessing help panel, OptimizationHelp, GuidanceOverlays), so they ran off the sidebar edge instead of wrapping.
d3mocide
marked this pull request as ready for review
August 6, 2026 22:40
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
devhad accumulated three merged PRs (#19, #20, #21) worth of roadmap work that never made it tomain. This PR mergesdevintomainand prepares the1.17.0release.origin/dev(P6-1, P3-1/P3-3/P3-4, P4-2, P4-6, new CI workflow, lint fixes, dependency audit fixes) into this branch — clean merge, no conflicts[Unreleased]CHANGELOG section into[1.17.0] - 2026-08-06package.jsonversion1.16.1→1.17.0(minor: new features, no breaking changes)RELEASE_NOTES.mdfor the new releaseROADMAP.md's "Last Updated" datenpm audit fixfor newly-disclosed dev-tooling advisories (brace-expansion,fast-uri,js-yaml) surfaced sincedev's last audit pass — production dependency tree was already at 0 vulnerabilitiesFeatures carried over from
devfspl/hatalocally, works fully offline/PWATest plan
npm install && npm run lint— cleannpx vitest run— 52/52 passednpm run build— production build succeedspip install -r rf-engine/requirements.txt && pytest— 23/23 passednpm audit --omit=dev— 0 vulnerabilities;npm audit(incl. dev) — 0 afternpm audit fixv1.17.0and push after merge to trigger.github/workflows/docker-publish.yml(buildscore,rf-engine,opentopodataimages) — left for maintainer since it's a public image publishRELEASE_NOTES.mdcontentGenerated by Claude Code