Skip to content

Staging#98

Merged
Shashank0701-byte merged 16 commits intomainfrom
staging
Mar 30, 2026
Merged

Staging#98
Shashank0701-byte merged 16 commits intomainfrom
staging

Conversation

@Shashank0701-byte
Copy link
Copy Markdown
Owner

@Shashank0701-byte Shashank0701-byte commented Mar 29, 2026

Summary by CodeRabbit

  • New Features

    • Interactive load simulator (start/stop, RPS) with background simulation engine and per-node/edge metrics.
    • Server endpoints to trigger final-validation and to advance constraint warning/penalty phases.
    • Constraints can target specific nodes (node-failure scenarios); AI message list can be programmatically updated.
  • UI/UX Improvements

    • Canvas renders live simulation overlays, bottleneck/warning states, traffic/capacity readouts, and impacted-node badges.
    • Header shows countdown/failed-state timer for active constraints and surfaces interviewer messages and controls.

…ic Server/Database nodes when throwing Regional Failover events

- The UI will instantly trap the user with a pulsing red 5-Minute Panic Timer, forcing them to either mitigate the problem before the clock runs out or hit submit
- The Canvas will vividly display the broken node (grayed out, marked with a pulsing red warning icon) rendering it dead
- Implemented  graph traversal for realtime load simulation.
- Added  UI widget to canvas with variable RPS slider.
- Integrated deterministic graph bottlenecks with SVG marching ants and warning badges.
- Created Backend API and frontend trigger for 10-minute 'Final Validation Phase'.
- Fixed React hooks ordering rules violation with .
- Automatically open AI Interviewer sidebar during chaos events and validation.
feat(simulation): add dynamic load engine and final validation phase
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
system-craft Ready Ready Preview, Comment Mar 30, 2026 10:42am

@netlify
Copy link
Copy Markdown

netlify bot commented Mar 29, 2026

Deploy Preview for system-craft-staging ready!

Name Link
🔨 Latest commit dea1543
🔍 Latest deploy log https://app.netlify.com/projects/system-craft-staging/deploys/69c9c43965b8c600082f0103
😎 Deploy Preview https://deploy-preview-98--system-craft-staging.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Warning

Rate limit exceeded

@Shashank0701-byte has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 47 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 0 minutes and 47 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: 127ace74-d656-40d9-b6ea-086787a0bf71

📥 Commits

Reviewing files that changed from the base of the PR and between 737f734 and dea1543.

📒 Files selected for processing (1)
  • components/canvas/DesignCanvas.tsx
📝 Walkthrough

Walkthrough

Adds server APIs for constraint timeouts and final-validation, a client-side chaos timer, a simulation engine with UI controls integrated into the design canvas, and extends InterviewSession constraint schema with per-constraint timing and impacted-node metadata.

Changes

Cohort / File(s) Summary
Chaos Timeout API & Session Model
app/api/interview/[id]/chaos-timeout/route.ts, src/lib/db/models/InterviewSession.ts
New POST route to mark constraint overtimeAt or failedAt, append interviewer messages, validate inputs/auth, and persist updates. InterviewSession/ConstraintChange schema gains impactedNodeId, overtimeAt, failedAt.
Final Validation API
app/api/interview/[id]/final-validation/route.ts
New idempotent POST route that injects a "Final Validation Phase" interviewer message when session is in progress and not previously sent; authenticates and returns current aiMessages.
Hint generation tweak
app/api/interview/[id]/hint/route.ts
Reliability constraint now targets a specific impactedNodeId (Node Failure) using a randomly selected victim node; falls back to regional description when no candidate node exists.
Interview page wiring
app/interview/[id]/page.tsx
Triggers final-validation once when ≤10 minutes remain; adds handleChaosTimeout to POST to chaos-timeout, update AI messages & constraintChanges, open interviewer panel; wires latestConstraint and activeConstraints into header/canvas.
Chaos Timer & Header
components/interview/ChaosTimer.tsx, components/interview/InterviewHeader.tsx
Adds ChaosTimer component with phased countdown and single-shot timeout callbacks; InterviewHeader now accepts latestConstraint?: IConstraintChange and onChaosTimeout and renders ChaosTimer when applicable.
Canvas simulation & controls
components/canvas/DesignCanvas.tsx, components/canvas/SimulationControls.tsx
DesignCanvas gains activeConstraints?, derives impacted nodes, integrates useSimulationEngine, renders animated edge overlays, node badges/bottleneck readouts, and adjusts node interactions when impacted. Adds SimulationControls UI for run/stop and target RPS.
Simulation engine & hook
src/lib/simulation/engine.ts, src/lib/simulation/constants.ts, src/hooks/useSimulationEngine.ts
New simulation constants and types (NODE_CAPACITIES, Node/Edge metrics), runSimulation traffic propagation engine with convergence, and useSimulationEngine hook that returns metrics when running and targetRps > 0.
AI hook surface
src/hooks/useInterviewAI.ts
Hook now exposes setMessages setter so callers can programmatically update AI message list alongside existing APIs.
Minor wiring & callbacks
components/..., app/...
Prop signature updates, dependency fixes in callbacks, initializations of aiMessages, and other small integrations across page/header/canvas components.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Interview Page
    participant API as Chaos Timeout API
    participant DB as MongoDB
    participant UI as Interview UI

    Client->>API: POST /api/interview/[id]/chaos-timeout {type, constraintId}
    API->>DB: Load InterviewSession by id & user
    alt constraint found & actionable
        API->>DB: Set `overtimeAt` or `failedAt`, set status, append interviewer message
        API->>DB: Save session
        DB-->>API: Updated session
        API-->>Client: {success, messages, constraintChanges}
        Client->>UI: setMessages(...) & update constraintChanges
        UI->>UI: Re-render header/canvas (open interviewer panel)
    else not found / already processed
        API-->>Client: {error or success w/warning}
    end
Loading
sequenceDiagram
    participant Timer as Page Timer
    participant Client as Interview Page
    participant API as Final Validation API
    participant DB as MongoDB

    Timer->>Client: detects minutes ≤ 10 & status='in_progress'
    Client->>API: POST /api/interview/[id]/final-validation
    API->>DB: Load session, check existing "Final Validation Phase" message
    alt already sent or not in_progress
        API-->>Client: {success, messages}
    else first time
        API->>DB: Append interviewer message, save
        DB-->>API: Updated session
        API-->>Client: {success, messages}
        Client->>Client: ai.setMessages(...), open interviewer panel
    end
Loading
sequenceDiagram
    participant UI as SimulationControls
    participant Canvas as DesignCanvas
    participant Hook as useSimulationEngine
    participant Engine as runSimulation

    UI->>Canvas: onToggle(true), onChangeRps(500)
    Canvas->>Hook: isRunning=true, targetRps=500, nodes, edges
    Hook->>Engine: runSimulation(nodes, edges, 500)
    Engine-->>Hook: SimulationResult (nodeMetrics, edgeMetrics, globalStatus)
    Hook-->>Canvas: SimulationResult
    Canvas->>Canvas: Render animated edges, node badges, state classes
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I count the seconds, soft and bright,

A node went dark, I raised a light,
A warning chimed, then penalty too,
I hopped to patch what chaos threw,
Hooray — the system hums tonight.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Staging' is overly vague and generic, providing no meaningful information about the substantive changes in this pull request, which include new API routes, simulation engine, chaos timeout handling, and UI components. Use a descriptive title that captures the main purpose, such as 'Add chaos timeout and final validation endpoints with simulation engine' or 'Implement constraint enforcement and load simulation features'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 staging

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (6)
src/hooks/useInterviewAI.ts (1)

152-154: Consider documenting the intended usage of setMessages.

Exposing the raw setMessages setter allows external callers to bypass the hook's internal message management logic (e.g., requestHint). This is intentional for syncing with server-returned message arrays from /final-validation and /chaos-timeout endpoints, but consider adding a brief comment or JSDoc to clarify this is for server-sync scenarios only.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/hooks/useInterviewAI.ts` around lines 152 - 154, Add a short
JSDoc/comment on the exported setMessages in the useInterviewAI hook to document
its intended usage: explain that setMessages is exposed only for server-sync
scenarios (e.g., syncing arrays returned from /final-validation and
/chaos-timeout) and should not be used to bypass the hook's internal
message-management functions like requestHint or sendReply; place the comment
adjacent to the return object that includes sendReply and setMessages so callers
see it when importing the hook.
app/api/interview/[id]/hint/route.ts (1)

71-80: Node failure victim selection excludes valid infrastructure components.

The filter only includes ['SQL', 'Blob', 'Cache', 'Server'], but the system supports 10 node types (per ComponentPalette.tsx and constants.ts). Notable omissions:

  • LB (Load Balancer) - common chaos scenario
  • Queue/Kafka - tests async resilience
  • Function - serverless failure modes
  • CDN - edge availability

This limits the realism of reliability chaos scenarios.

♻️ Consider expanding the victim pool
-        const candidateNodes = nodes.filter((n) => ['SQL', 'Blob', 'Cache', 'Server'].includes(n.type));
+        // Exclude Client (load generator) from failure candidates
+        const candidateNodes = nodes.filter((n) => n.type !== 'Client');

Or explicitly include all infrastructure types:

-        const candidateNodes = nodes.filter((n) => ['SQL', 'Blob', 'Cache', 'Server'].includes(n.type));
+        const candidateNodes = nodes.filter((n) => 
+            ['SQL', 'Blob', 'Cache', 'Server', 'LB', 'CDN', 'Queue', 'Kafka', 'Function'].includes(n.type)
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/interview/`[id]/hint/route.ts around lines 71 - 80, The
victim-selection for chaos scenarios restricts candidateNodes to
['SQL','Blob','Cache','Server'], excluding valid infrastructure types like LB,
Queue/Kafka, Function, CDN; update the filter in the block that builds
candidateNodes (and the subsequent victim and selected objects) to either use
the canonical infrastructure type list from the shared source (e.g.,
ComponentPalette / constants export) or expand the hardcoded array to include
LB, Queue/Kafka, Function, CDN (and any other types present in constants.ts),
and add a guard to handle empty candidateNodes before computing Math.random() so
victim may be undefined safely.
app/interview/[id]/page.tsx (1)

305-321: Dependency array includes unstable ai object reference.

Including ai in the dependency array causes handleChaosTimeout to be recreated on every render since useInterviewAI returns a new object each time. This could cause unnecessary re-renders of child components receiving this callback.

♻️ Proposed fix - use stable reference
     const handleChaosTimeout = useCallback(async (type: 'warning' | 'penalty', constraintId: string) => {
         try {
             const res = await authFetch(`/api/interview/${id}/chaos-timeout`, {
                 method: 'POST',
                 headers: { 'Content-Type': 'application/json' },
                 body: JSON.stringify({ type, constraintId })
             });
+            if (!res.ok) throw new Error('Chaos timeout request failed');
             const data = await res.json();
             if (data.success && data.messages) {
                 if (ai.setMessages) ai.setMessages(data.messages);
                 setSession(prev => prev ? { ...prev, constraintChanges: data.constraintChanges } : null);
                 setIsInterviewPanelOpen(true);
             }
         } catch (err) {
             console.error('Chaos timeout failed:', err);
         }
-    }, [id, ai]);
+    // eslint-disable-next-line react-hooks/exhaustive-deps -- ai.setMessages is stable from useState
+    }, [id]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/interview/`[id]/page.tsx around lines 305 - 321, The handleChaosTimeout
callback depends on the unstable ai object returned by useInterviewAI, causing
the callback to be recreated each render; fix by extracting the stable function
you need (e.g., const { setMessages } = ai) before defining handleChaosTimeout
and use that stable reference inside the callback, then update the dependency
array to [id, setMessages] (or if setMessages can be undefined handle that case)
so handleChaosTimeout is stable; reference symbols: handleChaosTimeout,
useInterviewAI, ai, setMessages, id.
src/lib/simulation/engine.ts (1)

75-82: Minor optimization opportunity in source lookup.

The sources.find() call on line 78 runs for every node on every pass, resulting in O(passes × nodes × sources) complexity. For typical small UI graphs this is fine, but if performance becomes a concern, consider using a Set for O(1) lookups.

💡 Optional optimization
+    const sourceIds = new Set(sources.map(s => s.id));
+
     for (let pass = 0; pass < 10; pass++) {
         edges.forEach(e => { edgeMetrics[e.id].trafficFlow = 0; });
         
         const currentTrafficIn = Object.keys(nodeMetrics).reduce((acc, id) => {
             acc[id] = nodeMetrics[id].trafficIn;
-            if (!sources.find(s => s.id === id)) {
+            if (!sourceIds.has(id)) {
                 nodeMetrics[id].trafficIn = 0;
             }
             return acc;
         }, {} as Record<string, number>);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/simulation/engine.ts` around lines 75 - 82, The reduce over
nodeMetrics repeatedly calls sources.find(...) causing O(nodes×sources) per
pass; create a Set of source ids once (e.g., const sourceIds = new
Set(sources.map(s => s.id))) before computing currentTrafficIn and replace the
per-node lookup sources.find(s => s.id === id) with sourceIds.has(id) so you get
O(1) membership checks while preserving the existing behavior in the
currentTrafficIn reduce and the conditional that clears
nodeMetrics[id].trafficIn for non-sources.
components/canvas/SimulationControls.tsx (1)

38-47: Consider allowing RPS adjustment before starting simulation.

The range slider is disabled when isRunning is false (line 45), which prevents users from configuring the target RPS before starting the simulation. This seems counterintuitive — users typically want to set their target load before running the test.

If this is intentional (to prevent confusion about when changes take effect), consider adding a visual hint or tooltip explaining that RPS can only be adjusted while running.

💡 Proposed fix to allow pre-configuration
                     value={targetRps}
                     onChange={(e) => onChangeRps(parseInt(e.target.value, 10))}
-                    disabled={!isRunning}
+                    disabled={false}
                     className="w-full h-2 rounded-lg appearance-none cursor-pointer bg-slate-200 dark:bg-slate-700 accent-primary focus:outline-none focus:ring-2 focus:ring-primary/50 disabled:opacity-50 disabled:cursor-not-allowed"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/canvas/SimulationControls.tsx` around lines 38 - 47, The range
slider is currently disabled when isRunning is false which blocks
pre-configuration; update the SimulationControls input (the range element bound
to targetRps and onChangeRps) so the slider is enabled before starting by
removing or changing the disabled condition (remove disabled={!isRunning} or
change the predicate to only disable when truly needed), and ensure onChangeRps
can accept changes while not running (or guard inside onChangeRps if needed) so
users can set targetRps before starting the simulation; optionally, if you want
to preserve the original behavior, add a tooltip/visual hint near the slider
explaining that changes only take effect when the simulation is running.
app/api/interview/[id]/chaos-timeout/route.ts (1)

46-56: Penalty handling leaves constraint in 'active' status permanently.

The comment clarifies this is intentional to keep the node visually broken. However, since status remains 'active' and is never set to 'addressed', the ChaosTimer will display "Unresolved Incident" indefinitely per the check in InterviewHeader.tsx (line 120-122: latestConstraint.status !== 'addressed').

If this is by design for evaluation purposes, consider adding a way to dismiss or conclude the constraint after the interview, or document this behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/interview/`[id]/chaos-timeout/route.ts around lines 46 - 56, The
penalty branch currently sets constraint.failedAt but leaves constraint.status
as 'active', causing ChaosTimer/InterviewHeader (check latestConstraint.status
!== 'addressed') to show "Unresolved Incident" forever; update the penalty
handling in route.ts to mark the constraint as concluded—set constraint.status =
'addressed' (or add and set a new flag like constraint.dismissed = true plus a
resolution reason field) and persist those changes via
session.markModified('constraintChanges') so the UI stops treating it as
unresolved, or alternatively implement a dismiss/conclude endpoint that flips
that same status/flag after the interview ends; reference constraint.failedAt,
constraint.status, session.markModified('constraintChanges'), and the UI check
in InterviewHeader.tsx to guide placement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/interview/`[id]/chaos-timeout/route.ts:
- Line 22: The findIndex callback currently types parameter as any; change the
callback to use the IConstraintChange type (e.g.,
constraintChanges.findIndex((c: IConstraintChange) => c.id === constraintId))
and ensure IConstraintChange is imported from the model where it’s exported (add
the import if missing) so the `@typescript-eslint/no-explicit-any` error is
resolved.

In `@app/api/interview/`[id]/final-validation/route.ts:
- Around line 21-23: The code uses an unsafe any for messages when checking
session.aiMessages in the alreadySent computation; replace the any with the
appropriate message interface (e.g., whatever type defines AI messages in your
schema such as AiMessage, ChatMessage, or MessageRecord) and import or reference
that type, then change the callback signature to (m: AiMessage) => m.role ===
'interviewer' && m.content.includes("Final Validation Phase") so static analysis
understands the properties used; update the session type if necessary so
session.aiMessages is typed as an array of that message interface.
- Around line 5-8: The POST handler (function POST) lacks the authentication and
session-ownership checks present in hint/route.ts; add the same authentication
flow used there: extract and validate the session/user (the helper(s) used in
hint/route.ts that verify authenticated user and session ownership), confirm the
requesting user is the session owner for the interview ID, and return the
appropriate 401/403 response if validation fails; only proceed to run the final
validation logic when the authenticated user check passes.
- Around line 13-16: The query uses a non-queryable virtual `id` field so
InterviewSession.findOne({ id }) always fails; update the lookup to query by the
real Mongo identifier and user ownership—replace the call to
InterviewSession.findOne in route.ts with a query that uses {_id: id, userId:
user._id} (or use findById with an explicit userId check) so the document can be
found the same way other routes (hint/route.ts and route.ts) do.

In `@app/interview/`[id]/page.tsx:
- Around line 105-119: Extract the stable setter from the ai object (e.g., const
{ setMessages } = ai) before the useEffect and use setMessages in the dependency
array instead of ai or ai.setMessages to satisfy the linter without causing
re-renders; inside the effect, after calling authFetch check the fetch response
(if (!res.ok) throw new Error(await res.text() || res.statusText)) before
calling res.json(), and guard setMessages and setIsInterviewPanelOpen calls
(e.g., if (data.success && data.messages) { if (setMessages)
setMessages(data.messages); setIsInterviewPanelOpen(true); }) so errors are
caught and surfaced in the existing catch block.

In `@components/interview/ChaosTimer.tsx`:
- Around line 47-68: The reset of hasTriggeredWarning.current and
hasTriggeredPenalty.current inside the useEffect is inverted and unnecessary;
remove the two lines that set hasTriggeredWarning.current = false and
hasTriggeredPenalty.current = false so the component relies on the existing
trigger guards (!constraint.overtimeAt / !constraint.failedAt) and the refs to
prevent duplicate callbacks, and add a brief comment near the hasTriggered* refs
(or rename them to hasPendingWarningRequest/hasPendingPenaltyRequest if you
prefer clearer intent) to document their purpose; ensure calculateRemaining,
onTimeoutRef, and constraint usage remains unchanged.
- Around line 22-39: calculateRemaining references PENALTY_MS and WARNING_MS but
they are not listed in the useCallback dependency array; add PENALTY_MS and
WARNING_MS to the dependency array for calculateRemaining (or alternatively move
those constants outside the component so they are truly static) to satisfy
React's exhaustive-deps rule and silence the ESLint warning while keeping the
logic around constraint, penalty, and warning intact (symbols:
calculateRemaining, PENALTY_MS, WARNING_MS, constraint).

---

Nitpick comments:
In `@app/api/interview/`[id]/chaos-timeout/route.ts:
- Around line 46-56: The penalty branch currently sets constraint.failedAt but
leaves constraint.status as 'active', causing ChaosTimer/InterviewHeader (check
latestConstraint.status !== 'addressed') to show "Unresolved Incident" forever;
update the penalty handling in route.ts to mark the constraint as concluded—set
constraint.status = 'addressed' (or add and set a new flag like
constraint.dismissed = true plus a resolution reason field) and persist those
changes via session.markModified('constraintChanges') so the UI stops treating
it as unresolved, or alternatively implement a dismiss/conclude endpoint that
flips that same status/flag after the interview ends; reference
constraint.failedAt, constraint.status,
session.markModified('constraintChanges'), and the UI check in
InterviewHeader.tsx to guide placement.

In `@app/api/interview/`[id]/hint/route.ts:
- Around line 71-80: The victim-selection for chaos scenarios restricts
candidateNodes to ['SQL','Blob','Cache','Server'], excluding valid
infrastructure types like LB, Queue/Kafka, Function, CDN; update the filter in
the block that builds candidateNodes (and the subsequent victim and selected
objects) to either use the canonical infrastructure type list from the shared
source (e.g., ComponentPalette / constants export) or expand the hardcoded array
to include LB, Queue/Kafka, Function, CDN (and any other types present in
constants.ts), and add a guard to handle empty candidateNodes before computing
Math.random() so victim may be undefined safely.

In `@app/interview/`[id]/page.tsx:
- Around line 305-321: The handleChaosTimeout callback depends on the unstable
ai object returned by useInterviewAI, causing the callback to be recreated each
render; fix by extracting the stable function you need (e.g., const {
setMessages } = ai) before defining handleChaosTimeout and use that stable
reference inside the callback, then update the dependency array to [id,
setMessages] (or if setMessages can be undefined handle that case) so
handleChaosTimeout is stable; reference symbols: handleChaosTimeout,
useInterviewAI, ai, setMessages, id.

In `@components/canvas/SimulationControls.tsx`:
- Around line 38-47: The range slider is currently disabled when isRunning is
false which blocks pre-configuration; update the SimulationControls input (the
range element bound to targetRps and onChangeRps) so the slider is enabled
before starting by removing or changing the disabled condition (remove
disabled={!isRunning} or change the predicate to only disable when truly
needed), and ensure onChangeRps can accept changes while not running (or guard
inside onChangeRps if needed) so users can set targetRps before starting the
simulation; optionally, if you want to preserve the original behavior, add a
tooltip/visual hint near the slider explaining that changes only take effect
when the simulation is running.

In `@src/hooks/useInterviewAI.ts`:
- Around line 152-154: Add a short JSDoc/comment on the exported setMessages in
the useInterviewAI hook to document its intended usage: explain that setMessages
is exposed only for server-sync scenarios (e.g., syncing arrays returned from
/final-validation and /chaos-timeout) and should not be used to bypass the
hook's internal message-management functions like requestHint or sendReply;
place the comment adjacent to the return object that includes sendReply and
setMessages so callers see it when importing the hook.

In `@src/lib/simulation/engine.ts`:
- Around line 75-82: The reduce over nodeMetrics repeatedly calls
sources.find(...) causing O(nodes×sources) per pass; create a Set of source ids
once (e.g., const sourceIds = new Set(sources.map(s => s.id))) before computing
currentTrafficIn and replace the per-node lookup sources.find(s => s.id === id)
with sourceIds.has(id) so you get O(1) membership checks while preserving the
existing behavior in the currentTrafficIn reduce and the conditional that clears
nodeMetrics[id].trafficIn for non-sources.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3bac0d99-aa20-4640-a12b-a67a79534142

📥 Commits

Reviewing files that changed from the base of the PR and between c64b694 and 47b7a98.

📒 Files selected for processing (13)
  • app/api/interview/[id]/chaos-timeout/route.ts
  • app/api/interview/[id]/final-validation/route.ts
  • app/api/interview/[id]/hint/route.ts
  • app/interview/[id]/page.tsx
  • components/canvas/DesignCanvas.tsx
  • components/canvas/SimulationControls.tsx
  • components/interview/ChaosTimer.tsx
  • components/interview/InterviewHeader.tsx
  • src/hooks/useInterviewAI.ts
  • src/hooks/useSimulationEngine.ts
  • src/lib/db/models/InterviewSession.ts
  • src/lib/simulation/constants.ts
  • src/lib/simulation/engine.ts

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 29, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 4 file(s) based on 7 unresolved review comments.

A stacked PR containing fixes has been created.

  • Stacked PR: #100
  • Files modified:
  • app/api/interview/[id]/chaos-timeout/route.ts
  • app/api/interview/[id]/final-validation/route.ts
  • app/interview/[id]/page.tsx
  • components/interview/ChaosTimer.tsx

Time taken: 8m 17s

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/canvas/DesignCanvas.tsx (1)

842-882: ⚠️ Potential issue | 🟠 Major

Impacted nodes won't receive the mouse events this branch relies on.

Line 842 disables pointer events for the whole node layer. The normal node branch opts back in with pointer-events-auto, but the impacted branch on Lines 858-866 does not, so its onMouseDown/onMouseUp handlers never fire and the node cannot actually be selected.

Suggested fix
-                className={`absolute w-[60px] h-[60px] rounded-xl flex flex-col items-center justify-center select-none shadow-lg transition-all duration-300 ${isImpacted
+                className={`absolute w-[60px] h-[60px] rounded-xl flex flex-col items-center justify-center select-none shadow-lg transition-all duration-300 pointer-events-auto ${isImpacted
                   ? 'bg-red-500/10 border-2 border-red-500/50 opacity-80 grayscale-[50%] cursor-not-allowed'
                   : isBottlenecked
                   ? 'bg-red-600 border-2 border-red-500 shadow-[0_0_20px_rgba(220,38,38,0.7)] text-white ring-2 ring-red-500 animate-pulse'
                   : isWarning
                   ? 'bg-amber-500/20 border-2 border-amber-500 text-amber-500 shadow-[0_0_15px_rgba(245,158,11,0.5)]'
                   : 'bg-white dark:bg-[`#1e1e24`] cursor-move transition-shadow pointer-events-auto ' + (isSelected
                     ? 'ring-2 ring-primary ring-offset-2 ring-offset-white dark:ring-offset-[`#0f1115`] shadow-[0_0_20px_rgba(71,37,244,0.3)] z-20'
                     : 'border-2 border-transparent hover:border-primary')
                   }`}
                 onMouseDown={(e) => {
                   if (isImpacted) {
                     e.stopPropagation();
                     setSelectedNodeId(node.id);
+                    setSelectedConnectionId(null);
                     return;
                   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/canvas/DesignCanvas.tsx` around lines 842 - 882, The node layer
currently has pointer-events disabled globally which prevents the impacted
branch from receiving mouse events; update the impacted branch in the className
logic for displayNodes (where isImpacted is computed) to include
"pointer-events-auto" (or remove the parent pointer-events-none and ensure
non-impacted nodes keep pointer-events-auto) so that onMouseDown/onMouseUp
handlers (handleNodeMouseDown, handleNodeMouseUp) and setSelectedNodeId can run
for impacted nodes while preserving the visual disabled styling (e.g., keep
cursor-not-allowed/grayscale).
♻️ Duplicate comments (1)
app/interview/[id]/page.tsx (1)

105-119: ⚠️ Potential issue | 🟠 Major

Don't consume the one-shot final-validation trigger before the POST succeeds.

Line 107 is acting as both “request in flight” and “request completed”. On a transient 401/500/network failure, this phase is skipped for the rest of the session.

One way to fix it
+    const finalValidationInFlightRef = useRef(false);
...
-        if (!finalValidationTriggered && timer.minutes !== undefined && timer.minutes <= 10 && session?.status === 'in_progress') {
-            setFinalValidationTriggered(true);
+        if (!finalValidationTriggered && !finalValidationInFlightRef.current && timer.minutes !== undefined && timer.minutes <= 10 && session?.status === 'in_progress') {
+            finalValidationInFlightRef.current = true;
             
             authFetch(`/api/interview/${id}/final-validation`, { method: 'POST' })
-                .then(res => res.json())
+                .then(async res => {
+                    if (!res.ok) throw new Error((await res.text()) || res.statusText);
+                    return res.json();
+                })
                 .then(data => {
                     if (data.success && data.messages) {
+                        setFinalValidationTriggered(true);
                         if (ai.setMessages) ai.setMessages(data.messages);
                         setIsInterviewPanelOpen(true);
                     }
                 })
-                .catch(err => console.error('Final validation trigger failed:', err));
+                .catch(err => console.error('Final validation trigger failed:', err))
+                .finally(() => { finalValidationInFlightRef.current = false; });
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/interview/`[id]/page.tsx around lines 105 - 119, The effect sets
finalValidationTriggered before the POST completes, so transient failures
prevent retries; change the logic to only mark the trigger as completed after a
successful POST (or introduce a separate in-flight flag). Specifically, in the
useEffect that checks timer.minutes and session?.status, remove the early
setFinalValidationTriggered(true) and instead set it only when the response is
successful (e.g., inside the then where data.success is true), or add a new
boolean state like finalValidationInFlight to guard duplicate requests while
leaving finalValidationTriggered false until success; keep the authFetch call,
ai.setMessages, and setIsInterviewPanelOpen usage the same and ensure catch
leaves finalValidationTriggered unset so retries can occur.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/interview/`[id]/chaos-timeout/route.ts:
- Around line 29-31: Update the early-return condition in the route handler so
that any request short-circuits if constraint.failedAt is already set (not only
when type === 'penalty'); specifically, in the block that currently checks
constraint.status, type and overtimeAt/failedAt, add a top-level check for
constraint.failedAt (alongside constraint.status === 'addressed') and return the
same NextResponse.json({ success: true, warning: 'Already processed' }) for
warnings that arrive after a penalty has been recorded; reference the existing
symbols constraint, type and NextResponse.json in your change.
- Around line 15-18: The handler currently proceeds even if the interview is
closed; after fetching the session with InterviewSession.findOne({ id }) check
the session state and early-return when it is not "in_progress" (same guard used
in final-validation/route.ts) so the timeout update becomes a no-op for
closed/submitted sessions; update the code around the session null-check to
verify session.state === 'in_progress' and return a non-mutating response (e.g.,
JSON no-op or 409/200) to avoid appending interviewer messages or modifying
constraint timing after submit/evaluate.

---

Outside diff comments:
In `@components/canvas/DesignCanvas.tsx`:
- Around line 842-882: The node layer currently has pointer-events disabled
globally which prevents the impacted branch from receiving mouse events; update
the impacted branch in the className logic for displayNodes (where isImpacted is
computed) to include "pointer-events-auto" (or remove the parent
pointer-events-none and ensure non-impacted nodes keep pointer-events-auto) so
that onMouseDown/onMouseUp handlers (handleNodeMouseDown, handleNodeMouseUp) and
setSelectedNodeId can run for impacted nodes while preserving the visual
disabled styling (e.g., keep cursor-not-allowed/grayscale).

---

Duplicate comments:
In `@app/interview/`[id]/page.tsx:
- Around line 105-119: The effect sets finalValidationTriggered before the POST
completes, so transient failures prevent retries; change the logic to only mark
the trigger as completed after a successful POST (or introduce a separate
in-flight flag). Specifically, in the useEffect that checks timer.minutes and
session?.status, remove the early setFinalValidationTriggered(true) and instead
set it only when the response is successful (e.g., inside the then where
data.success is true), or add a new boolean state like finalValidationInFlight
to guard duplicate requests while leaving finalValidationTriggered false until
success; keep the authFetch call, ai.setMessages, and setIsInterviewPanelOpen
usage the same and ensure catch leaves finalValidationTriggered unset so retries
can occur.
🪄 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: 9f881bd0-adcc-4190-bee4-5f49b4eca944

📥 Commits

Reviewing files that changed from the base of the PR and between 47b7a98 and 8b41b76.

📒 Files selected for processing (4)
  • app/api/interview/[id]/chaos-timeout/route.ts
  • app/api/interview/[id]/final-validation/route.ts
  • app/interview/[id]/page.tsx
  • components/canvas/DesignCanvas.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/api/interview/[id]/final-validation/route.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
app/interview/[id]/page.tsx (1)

324-330: ⚠️ Potential issue | 🟠 Major

Handle non-2xx chaos-timeout responses before parsing JSON.

This helper currently treats server-side failures as a silent no-op because it only checks data.success. If the route returns 4xx/5xx, the UI never updates and the timeout looks like it already fired successfully.

Suggested fix
             const res = await authFetch(`/api/interview/${id}/chaos-timeout`, {
                 method: 'POST',
                 headers: { 'Content-Type': 'application/json' },
                 body: JSON.stringify({ type, constraintId })
             });
+            if (!res.ok) {
+                const errText = await res.text();
+                throw new Error(errText || res.statusText);
+            }
             const data = await res.json();
             if (data.success && data.messages) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/interview/`[id]/page.tsx around lines 324 - 330, The code calls authFetch
and immediately does res.json() without checking HTTP status, so 4xx/5xx
responses are treated like successful responses; update the handler around the
authFetch call (the res variable returned from authFetch when posting to
`/api/interview/${id}/chaos-timeout`) to first check res.ok (or res.status) and
handle non-2xx responses (e.g., throw or read error text and surface an error
state) before calling res.json(); ensure the UI update branch that currently
looks at data.success only runs for successful HTTP responses and surface/log
errors when res.ok is false so the timeout UI doesn’t silently appear to have
fired.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/interview/`[id]/chaos-timeout/route.ts:
- Around line 14-18: The route handler currently fetches the InterviewSession
with InterviewSession.findOne({ id }) and proceeds to update constraintChanges
and aiMessages without authenticating or verifying ownership; require the caller
to be authenticated, obtain the current user's id (e.g., from your auth helper
or request context), then scope the session lookup to include userId (e.g.,
InterviewSession.findOne({ id, userId })) and return a 403 if no session is
found for that user before performing any mutations to constraintChanges or
aiMessages; also ensure any downstream saves/updates (the code paths that modify
constraintChanges/aiMessages) only run after this ownership check.
- Around line 11-13: The handler reads body via req.json() and uses
type/constraintId without validation so invalid JSON throws 500 and unexpected
type values silently succeed; validate the parsed body immediately in the route
(after const { type, constraintId } = await req.json()) to ensure type is
present and equals 'warning' or 'penalty' and constraintId is the expected shape
(e.g., non-empty string/number), and if validation fails return a new Response
with status 400 and a clear error message; update the route's early-return logic
to reject malformed payloads before any branching that references type or
constraintId.

In `@components/canvas/DesignCanvas.tsx`:
- Around line 185-189: Add an effect that stops the simulation when the canvas
becomes read-only: watch the readOnly prop and, if readOnly is true and the
isSimulationRunning state is true, call setIsSimulationRunning(false) so
overlays/badges stop rendering; place this alongside the existing state hooks
(isSimulationRunning, setIsSimulationRunning, targetRps, useSimulationEngine)
and ensure it cleans up only by flipping the running flag (no additional side
effects).

In `@components/interview/ChaosTimer.tsx`:
- Around line 43-66: The refs hasPendingWarningRequest and
hasPendingPenaltyRequest persist across component lifetime so a prior constraint
can block callbacks for a new constraint; inside the useEffect that depends on
calculateRemaining and constraint (the one creating the interval), reset
hasPendingWarningRequest.current = false and hasPendingPenaltyRequest.current =
false (or reset based on constraint.id) before creating the interval so each new
active constraint starts with fresh dispatch guards; reference the useEffect
that calls calculateRemaining and onTimeoutRef.current to locate where to reset
them.

In `@src/lib/simulation/engine.ts`:
- Around line 69-114: The fixed 10-pass loop only snapshots currentTrafficIn
once per pass, so traffic moves one hop per pass and cycles amplify; replace
this with a true iterative propagation that runs until convergence (change <
epsilon) or a maxIterations cap: maintain two maps (e.g., prevTrafficIn and
nextTrafficIn) or update nodeMetrics.trafficIn incrementally each sub-iteration,
compute trafficOut from nodeMetrics.capacity, distribute to children via adj and
edgeMetrics, then swap and measure total delta across nodeMetrics to stop when
stable; ensure cycles are stabilized by using the delta-based convergence check
and a sensible epsilon/maxIterations to avoid runaway loops.

---

Duplicate comments:
In `@app/interview/`[id]/page.tsx:
- Around line 324-330: The code calls authFetch and immediately does res.json()
without checking HTTP status, so 4xx/5xx responses are treated like successful
responses; update the handler around the authFetch call (the res variable
returned from authFetch when posting to `/api/interview/${id}/chaos-timeout`) to
first check res.ok (or res.status) and handle non-2xx responses (e.g., throw or
read error text and surface an error state) before calling res.json(); ensure
the UI update branch that currently looks at data.success only runs for
successful HTTP responses and surface/log errors when res.ok is false so the
timeout UI doesn’t silently appear to have fired.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93c31900-9e9b-4b63-b443-0c7028d99a88

📥 Commits

Reviewing files that changed from the base of the PR and between 8b41b76 and 30bfc16.

📒 Files selected for processing (10)
  • app/api/interview/[id]/chaos-timeout/route.ts
  • app/api/interview/[id]/final-validation/route.ts
  • app/api/interview/[id]/hint/route.ts
  • app/interview/[id]/page.tsx
  • components/canvas/DesignCanvas.tsx
  • components/canvas/SimulationControls.tsx
  • components/interview/ChaosTimer.tsx
  • src/hooks/useInterviewAI.ts
  • src/hooks/useSimulationEngine.ts
  • src/lib/simulation/engine.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • app/api/interview/[id]/hint/route.ts
  • src/hooks/useInterviewAI.ts
  • src/hooks/useSimulationEngine.ts
  • components/canvas/SimulationControls.tsx
  • app/api/interview/[id]/final-validation/route.ts

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 4 file(s) based on 5 unresolved review comments.

A stacked PR containing fixes has been created.

  • Stacked PR: #103
  • Files modified:
  • app/api/interview/[id]/chaos-timeout/route.ts
  • components/canvas/DesignCanvas.tsx
  • components/interview/ChaosTimer.tsx
  • src/lib/simulation/engine.ts

Time taken: 8m 59s

Fixed 4 file(s) based on 5 unresolved review comments.

Co-authored-by: CodeRabbit <[email protected]>
@Shashank0701-byte Shashank0701-byte merged commit 3f1b468 into main Mar 30, 2026
8 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Mar 30, 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.

1 participant