Skip to content

feat(mesh): kill-comms toggle + partition banner - #10

Merged
WomB0ComB0 merged 2 commits into
mainfrom
feat/kill-comms
Apr 20, 2026
Merged

WomB0ComB0 merged 2 commits into
mainfrom
feat/kill-comms

Conversation

@WomB0ComB0

@WomB0ComB0 WomB0ComB0 commented Apr 20, 2026 •

Copy link
Copy Markdown
Member

Summary

Second slice of the multi-agency coordination demo (completing item #1 in the polish plan alongside PR #9). Adds a simulated backhaul-link failure mode and a visible degradation signal — the "mesh keeps working when the ground link drops" story that ties the multi-agency scenario to the DPCP consensus narrative without exposing the patent disclosure.

How it works

  • Press K (or hit POST /api/sim/mesh/backhaul with {killed:true}) → server flips a volatile state flag.
  • Next 10 Hz viz frame includes mesh.partitioned: true.
  • Client adds body.partitioned; the CSS-only banner fades in: ⚠ BACKHAUL LINK DOWN — OPERATING MESH-ONLY.
  • Press K again → {killed:false} → banner fades out.

Changes

Backend

File Change
Services/SimulationService.cs _backhaulKilled volatile bool + IsBackhaulKilled / SetBackhaulKilled. Clears on Reset(). Passes to frame builder.
Services/VizFrameBuilder.cs Build(...) now takes optional partitioned. Emits MeshVizState(Links:[], Partitioned:true) when set; else null.
Models/SimCommand.cs New BackhaulRequest(bool Killed) DTO.
Controllers/SimController.cs POST /api/sim/mesh/backhaul (rate-limited destructive) + GET /api/sim/mesh/backhaul for status.

Client

File Change
styles/main.css .partition-banner (fixed top, danger-red border, backdrop-filter) shown under body.partitioned. Persists across body.investor-mode.
app.ts Inject banner once at startup. In ReceiveFrame, toggle body.partitioned from frame.mesh?.partitioned. Keybinding K POSTs the toggle.

Backwards compat

Additive at every layer. VizFrameBuilder.Build(drones, simTime) still works (param defaults to false). Existing scenarios never set partition. Existing clients that don't care about mesh see no change.

Local verification

tsc --noEmit                                   → clean
vite build (via Release MSBuild)               → green
dotnet build ResQ.Viz.sln -c Release           → 0 / 0
dotnet format --verify-no-changes --severity warn → exit 0
dotnet test -c Release                         → 82 / 82 passing

Test plan

  • Run server, load any scenario (e.g. multi-agency-sar)
  • Press K — banner fades in at top-center within ~100 ms (one frame)
  • curl -X GET localhost:5000/api/sim/mesh/backhaul → {"killed":true}
  • Press K again → banner fades out
  • Trigger POST /api/sim/reset → banner clears

Follow-ups

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added capability to simulate backhaul link failures in mesh mode with visual status banner.
    • Added keyboard shortcut to toggle simulated backhaul state.
    • Added API endpoints to control and query backhaul link state.
  • Style

    • Added banner styling with visual indicators for mesh-only operation mode.

Second slice of the multi-agency coordination demo. Adds a simulated
backhaul-link failure mode and visible degradation signal — the "mesh
keeps working when the ground link drops" story that ties the
multi-agency scenario to the DPCP consensus narrative without touching
the patent disclosure.

Backend:
* `SimulationService` — adds `IsBackhaulKilled` / `SetBackhaulKilled(bool)`.
  No effect on SDK physics; a volatile bool flag flipped from the REST
  endpoint. `Reset()` restores it.
* `VizFrameBuilder.Build(drones, simTime, partitioned = false)` — when
  true, emits `MeshVizState(Links: [], Partitioned: true)`; otherwise
  `null` as before.
* `Models/SimCommand.cs` — new `BackhaulRequest(bool Killed)` DTO.
* `Controllers/SimController.cs` — `POST /api/sim/mesh/backhaul` (rate-
  limited "destructive") and `GET /api/sim/mesh/backhaul` for status.

Client:
* `styles/main.css` — `.partition-banner` fixed-top chip with danger
  color, backdrop blur, shown when `body.partitioned`. Persists in
  investor-mode (the degradation is the screen-recording payoff).
* `app.ts` — injects the banner once; `ReceiveFrame` toggles
  `body.partitioned` from `frame.mesh?.partitioned`. Keybinding `K`
  POSTs the toggle (uses current DOM state as baseline).

Verified: tsc clean, vite build green, `dotnet build -c Release` green,
`dotnet format --verify-no-changes` clean, 82 / 82 tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 20, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@WomB0ComB0 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 51 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 51 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cac900b3-c962-4253-bb35-26ba4cdbc51d

📥 Commits

Reviewing files that changed from the base of the PR and between fe31ffd and dc240dd.

📒 Files selected for processing (1)
  • src/ResQ.Viz.Web/client/app.ts
📝 Walkthrough

Walkthrough

This pull request introduces simulated backhaul link failure functionality to test mesh-only operational behavior. New API endpoints control and query the backhaul state, the simulation service tracks and propagates this state, the frame builder conditionalizes mesh visualization based on partition status, and the client UI displays a partition banner with keyboard toggle support.

Changes

Cohort / File(s) Summary
Backend API Endpoints
src/ResQ.Viz.Web/Controllers/SimController.cs, src/ResQ.Viz.Web/Models/SimCommand.cs
Added POST and GET endpoints to control and query simulated backhaul failure state. SetBackhaul endpoint accepts BackhaulRequest with rate limiting protection; GetBackhaul returns current state. Introduced BackhaulRequest record to carry the Killed toggle parameter.
Simulation Service & Frame Building
src/ResQ.Viz.Web/Services/SimulationService.cs, src/ResQ.Viz.Web/Services/VizFrameBuilder.cs
Extended simulation service to track backhaul-killed state via volatile field and expose it via IsBackhaulKilled property and SetBackhaulKilled method. Updated Build method signature with optional partitioned parameter to conditionally create MeshVizState with partition flag and empty links list when backhaul is killed.
Client UI & Styling
src/ResQ.Viz.Web/client/app.ts, src/ResQ.Viz.Web/client/styles/main.css
Added fixed-position partition banner DOM element with aria-live="polite" for status updates. Implemented keyboard shortcut (K key, no modifiers) to toggle backhaul state via POST request. Synchronized UI state with server by toggling body.partitioned class on frame reception. Added CSS rules for .partition-banner with danger styling, backdrop blur, and visibility animations tied to body.partitioned state.

Sequence Diagram

sequenceDiagram
    actor User
    participant Client as Client (Browser)
    participant API as SimController
    participant Sim as SimulationService
    participant Builder as VizFrameBuilder
    
    User->>Client: Press 'K' key
    Client->>API: POST /api/sim/mesh/backhaul {killed: true/false}
    API->>Sim: SetBackhaulKilled(bool)
    Sim->>Sim: Update _backhaulKilled, Log info
    
    Note over Sim: On next frame cycle
    Sim->>Builder: Build(drones, time, backhaulKilled)
    Builder->>Builder: Create MeshVizState with Partitioned flag
    Builder-->>Sim: VizFrame with mesh.partitioned
    
    Sim-->>API: Return frame to client
    API-->>Client: Frame data
    Client->>Client: Toggle body.partitioned class
    Client->>Client: Banner visibility updated via CSS
    Client->>User: Display partition banner
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A hop here, a link there,
When backhaul falls through the air,
The mesh stands alone, so brave and true,
With banners and toggles, K pressed anew!
Partition flows like a whispered dare. ⚠️

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(mesh): kill-comms toggle + partition banner' directly and clearly describes the main changes: adding a toggle mechanism for simulated backhaul link failure and a visual banner to indicate mesh-only operation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/kill-comms

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a simulated backhaul link failure feature to demonstrate mesh-only coordination. It adds new API endpoints to toggle and retrieve the backhaul state, updates the simulation service to track this state, and modifies the visualization frame to include a partition signal. On the frontend, a UI banner and a keyboard shortcut ('K') were added to control and display the link status. Feedback was provided regarding the lack of error handling for the fetch request in the client-side code, particularly given the rate-limiting policy on the endpoint.

Comment thread src/ResQ.Viz.Web/client/app.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/ResQ.Viz.Web/client/app.ts`:
- Around line 399-407: The K-key handler currently derives the next backhaul
state from the DOM class (document.body.classList.contains('partitioned')),
which lags a frame and causes double-presses to POST the same value; introduce a
local state variable (e.g., backhaulKilled or backhaulState) and an in-flight
toggle flag in the module scope, use that local state when constructing the POST
in the KeyK handler (and set it immediately when sending to avoid race), and
update that local state from the SignalR/frame update handler that currently
toggles the banner/class so DOM and local state stay in sync; ensure the POST
uses the inverted local state and the frame handler overwrites the local state
with the authoritative server value.
- Around line 41-45: The banner is created with static text so screen readers
may not announce later state changes; change partitionBanner creation in the
module to initialize with empty textContent (and keep aria-live='polite'), then
remove the hard-coded message and instead update partitionBanner.textContent
inside the ReceiveFrame handler (or the function that processes incoming frames)
only when the backhaul/partition state flips (detect transition from previous
state to new state) so the live region receives new text at the time of change;
reference partitionBanner and ReceiveFrame when applying the update logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 30a0464b-28d9-4aff-97a7-3b04b45c23a4

📥 Commits

Reviewing files that changed from the base of the PR and between 07ed15a and fe31ffd.

📒 Files selected for processing (6)
  • src/ResQ.Viz.Web/Controllers/SimController.cs
  • src/ResQ.Viz.Web/Models/SimCommand.cs
  • src/ResQ.Viz.Web/Services/SimulationService.cs
  • src/ResQ.Viz.Web/Services/VizFrameBuilder.cs
  • src/ResQ.Viz.Web/client/app.ts
  • src/ResQ.Viz.Web/client/styles/main.css

Comment thread src/ResQ.Viz.Web/client/app.ts
Comment thread src/ResQ.Viz.Web/client/app.ts Outdated
…andling

Three review fixes to the kill-comms client wiring:

* Replace DOM-derived toggle with a module-level `_backhaulKilled` mirror
  plus `_backhaulToggleInFlight` guard. Rapid K-presses no longer POST
  the same value twice before the first frame confirms the change.
* Initialize the partition banner with empty text + `aria-hidden=true`,
  populate on partition transitions so the `aria-live="polite"` region
  actually announces state changes (screen readers ignore text present
  at insertion time).
* Handle `fetch` rejection and non-OK responses (expected under the
  `destructive` rate-limit policy) with a console warning rather than
  silently dropping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@WomB0ComB0

Copy link
Copy Markdown
Member Author

Thanks both — pushed dc240dd addressing all three:\n\n* Local state mirror (_backhaulKilled) + in-flight guard — rapid presses no longer POST stale values.\n* aria-live timing fix — banner starts empty with aria-hidden=true; text populated on transitions so the live region actually announces.\n* fetch error handling — logs a warning on non-OK / rejected responses (expected under the destructive rate-limit policy).\n\ntsc clean, build/format/tests green.

@WomB0ComB0
WomB0ComB0 merged commit 4024d3e into main Apr 20, 2026
35 checks passed
@WomB0ComB0
WomB0ComB0 deleted the feat/kill-comms branch April 20, 2026 06:51
WomB0ComB0 added a commit that referenced this pull request Apr 26, 2026
…ing (#63)

* fix(security): sanitize CR/LF from user-controlled values before logging

CodeQL `cs/log-forging` (CWE-117) flagged three sites in
SimulationService.cs where user-supplied strings (`droneId`, preset
`key`) flowed directly into `ILogger` calls:

  * Services/SimulationService.cs:149  LogWarning(droneId)
  * Services/SimulationService.cs:153  LogDebug(droneId)
  * Services/SimulationService.cs:182  LogInformation(key)

An attacker who can supply CR/LF in those values can inject fake log
entries (e.g. forge a "drone X armed" line). Adds a small private
static `LogSafe` helper that strips `\r`/`\n` and routes the three
call sites through it. Chained `String.Replace` is recognised by the
CodeQL rule as a valid sanitiser, so alerts #10/#11/#17 should
auto-close on the next scan.

`command` (FlightCommand enum) is left as-is; the renderer only
returns the type-system enum name and is not user-controlled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(security): address review feedback — cover AddDrone sinks, preserve null

Applies the gemini-code-assist review on PR #63:

- AddDrone (line 135) was a missed sink; the user-controlled `id` and
  `vendor` flow into LogInformation just like the three sites CodeQL
  flagged. Wrap both with LogSafe so the same protection applies.
- LogSafe now returns string? and preserves null instead of returning
  the magic literal "<null>". Structured loggers (Serilog, default
  JSON formatter, etc.) handle null natively; collapsing nulls to a
  string drops information from structured output.

The CR/LF chained Replace is kept (CodeQL recognises it as a valid
cs/log-forging sanitiser); ReplaceLineEndings would be more robust
against U+2028/U+2029 etc. but trades sanitiser recognition for that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant