Skip to content

chore(release): v1.17.0 — merge dev, close out roadmap items - #22

Merged
d3mocide merged 14 commits into
mainfrom
claude/next-version-release-checklist-nabt5a
Aug 6, 2026
Merged

chore(release): v1.17.0 — merge dev, close out roadmap items#22
d3mocide merged 14 commits into
mainfrom
claude/next-version-release-checklist-nabt5a

Conversation

@d3mocide

@d3mocide d3mocide commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

dev had accumulated three merged PRs (#19, #20, #21) worth of roadmap work that never made it to main. This PR merges dev into main and prepares the 1.17.0 release.

  • Merge 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
  • Convert the [Unreleased] CHANGELOG section into [1.17.0] - 2026-08-06
  • Bump package.json version 1.16.11.17.0 (minor: new features, no breaking changes)
  • Rewrite RELEASE_NOTES.md for the new release
  • Refresh ROADMAP.md's "Last Updated" date
  • Run npm audit fix for newly-disclosed dev-tooling advisories (brace-expansion, fast-uri, js-yaml) surfaced since dev's last audit pass — production dependency tree was already at 0 vulnerabilities

Features carried over from dev

  • Per-Node Coverage Visualization (P6-1) — Multi-Site Analysis renders each node's coverage in a distinct color
  • Client-Side Hata & FSPL (P3-1) — Link Analysis resolves fspl/hata locally, works fully offline/PWA
  • COST 231-Hata Extension (P4-2) — Hata coverage now spans 150–2000 MHz
  • WASM ITM for Batch Reports (P3-3) — Batch Processing can run the WASM Longley-Rice engine
  • Per-Node Configs in Batch CSV (P3-4) — optional per-node antenna/TX-power columns
  • Reliability / Variability Modes (P4-6) — selectable ITM time/location/situation percentages (requires the included WASM rebuild)

Test plan

  • npm install && npm run lint — clean
  • npx vitest run — 52/52 passed
  • npm run build — production build succeeds
  • pip install -r rf-engine/requirements.txt && pytest — 23/23 passed
  • npm audit --omit=dev — 0 vulnerabilities; npm audit (incl. dev) — 0 after npm audit fix
  • Tag v1.17.0 and push after merge to trigger .github/workflows/docker-publish.yml (builds core, rf-engine, opentopodata images) — left for maintainer since it's a public image publish
  • Cut the GitHub Release with RELEASE_NOTES.md content

Generated by Claude Code

claude and others added 14 commits May 18, 2026 04:19
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
d3mocide marked this pull request as ready for review August 6, 2026 22:40
@d3mocide
d3mocide merged commit edc08f8 into main Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants