feat(mesh): kill-comms toggle + partition banner - #10
Conversation
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>
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis 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
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (6)
src/ResQ.Viz.Web/Controllers/SimController.cssrc/ResQ.Viz.Web/Models/SimCommand.cssrc/ResQ.Viz.Web/Services/SimulationService.cssrc/ResQ.Viz.Web/Services/VizFrameBuilder.cssrc/ResQ.Viz.Web/client/app.tssrc/ResQ.Viz.Web/client/styles/main.css
…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>
|
Thanks both — pushed dc240dd addressing all three:\n\n* Local state mirror ( |
…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>
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
K(or hitPOST /api/sim/mesh/backhaulwith{killed:true}) → server flips a volatile state flag.mesh.partitioned: true.body.partitioned; the CSS-only banner fades in: ⚠ BACKHAUL LINK DOWN — OPERATING MESH-ONLY.Kagain →{killed:false}→ banner fades out.Changes
Backend
Services/SimulationService.cs_backhaulKilledvolatile bool +IsBackhaulKilled/SetBackhaulKilled. Clears onReset(). Passes to frame builder.Services/VizFrameBuilder.csBuild(...)now takes optionalpartitioned. EmitsMeshVizState(Links:[], Partitioned:true)when set; elsenull.Models/SimCommand.csBackhaulRequest(bool Killed)DTO.Controllers/SimController.csPOST /api/sim/mesh/backhaul(rate-limiteddestructive) +GET /api/sim/mesh/backhaulfor status.Client
styles/main.css.partition-banner(fixed top, danger-red border,backdrop-filter) shown underbody.partitioned. Persists acrossbody.investor-mode.app.tsReceiveFrame, togglebody.partitionedfromframe.mesh?.partitioned. KeybindingKPOSTs the toggle.Backwards compat
Additive at every layer.
VizFrameBuilder.Build(drones, simTime)still works (param defaults tofalse). Existing scenarios never set partition. Existing clients that don't care about mesh see no change.Local verification
Test plan
multi-agency-sar)K— banner fades in at top-center within ~100 ms (one frame)curl -X GET localhost:5000/api/sim/mesh/backhaul→{"killed":true}Kagain → banner fades outPOST /api/sim/reset→ banner clearsFollow-ups
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Style