fix: harden litigation AI pipeline — QC false-clear, empty response, source tracing#70
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a Changes
Sequence DiagramsequenceDiagram
actor User
participant Frontend as LitigationAssistant (React)
participant Backend as Routes (`src/routes/litigation.ts`)
participant AI as AI Gateway / ChittyConnect
User->>Frontend: trigger QC scan
Frontend->>Backend: POST /qc
alt AI disabled
Backend-->>Frontend: { flags: [], warning: "AI not enabled — QC scan skipped", source: "passthrough" }
else AI via ChittyConnect
Backend->>AI: query ChittyConnect
AI-->>Backend: model output (string)
Backend->>Backend: parse & ensure Array
alt parsed Array
Backend-->>Frontend: { flags: [...], source: "chittyconnect" }
else not Array
Backend-->>Frontend: { flags: [], warning: "QC analysis returned unexpected format — scan incomplete" }
end
else AI gateway fallback
Backend->>AI: callAIGatewayFallback
AI-->>Backend: message.content
Backend->>Backend: throw if empty/whitespace
Backend->>Backend: JSON.parse & validate Array
alt parsed Array
Backend-->>Frontend: { flags: [...], source: "ai-gateway-fallback" }
else parse/format error
Backend-->>Frontend: { flags: [], warning: "QC analysis returned non-parseable results — scan incomplete" }
end
end
Frontend->>Frontend: set flags and qcWarning
alt qcWarning present && flags.length == 0
Frontend-->>User: render "Scan Incomplete" with Retry button
else flags present
Frontend-->>User: render flags
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
|
To use Codex here, create a Codex account and connect to github. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/routes/litigation.ts (1)
143-148:⚠️ Potential issue | 🟡 MinorPassthrough case missing
sourcefield — inconsistent with/synthesizeendpoint.The passthrough branch at line 145 returns
synthesis,passthrough, andfactsUsedbut omits thesourcefield. The/synthesizeendpoint (line 49) includessource: 'passthrough'for the same condition. This breaks the PR objective that all synthesis paths include asourcefield for traceability.Proposed fix
if (!result.aiEnabled) { - return c.json({ synthesis: rawNotes, passthrough: true, factsUsed: facts.length }); + return c.json({ synthesis: rawNotes, passthrough: true, factsUsed: facts.length, source: 'passthrough' }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/routes/litigation.ts` around lines 143 - 148, The passthrough branch is missing the source field, causing inconsistent responses; update the block that returns c.json when result exists but result.aiEnabled is false (the branch that currently returns { synthesis: rawNotes, passthrough: true, factsUsed: facts.length }) to include source: 'passthrough' so it matches the /synthesize behavior—modify the response object in that branch (where result and result.aiEnabled are checked) to add source: 'passthrough'.
🧹 Nitpick comments (1)
ui/src/pages/LitigationAssistant.tsx (1)
134-137: Consider resettingqcWarningbefore the QC API call.Currently
qcWarningis only reset inhandleSynthesize. If a user retries the QC scan (via the Retry button), a stale warning could briefly persist if the new response has no warning. While the code at line 136 will overwrite it, explicitly resetting at the start ofhandleQCwould be more defensive.Proposed fix
const handleQC = async () => { if (!draft) return; setStep('scanning'); setError(null); + setQcWarning(null); try { const res = await api.litigationQC({ rawNotes, draftEmail: draft });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ui/src/pages/LitigationAssistant.tsx` around lines 134 - 137, In handleQC, reset the qcWarning state before making the async API call to avoid showing a stale warning during retries: call setQcWarning(null) at the start of the handleQC function (similar to how handleSynthesize resets it) so any previous warning is cleared immediately, then proceed with the api.litigationQC call and subsequent setFlags/setQcWarning based on the response.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/routes/litigation.ts`:
- Around line 143-148: The passthrough branch is missing the source field,
causing inconsistent responses; update the block that returns c.json when result
exists but result.aiEnabled is false (the branch that currently returns {
synthesis: rawNotes, passthrough: true, factsUsed: facts.length }) to include
source: 'passthrough' so it matches the /synthesize behavior—modify the response
object in that branch (where result and result.aiEnabled are checked) to add
source: 'passthrough'.
---
Nitpick comments:
In `@ui/src/pages/LitigationAssistant.tsx`:
- Around line 134-137: In handleQC, reset the qcWarning state before making the
async API call to avoid showing a stale warning during retries: call
setQcWarning(null) at the start of the handleQC function (similar to how
handleSynthesize resets it) so any previous warning is cleared immediately, then
proceed with the api.litigationQC call and subsequent setFlags/setQcWarning
based on the response.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a4736e8e-7c44-46b2-b2e8-baa1373196f5
📒 Files selected for processing (2)
src/routes/litigation.tsui/src/pages/LitigationAssistant.tsx
…lear, source tracing Backend: callAIGatewayFallback throws on empty AI response instead of returning empty string. QC endpoint validates parsed result is array and surfaces "scan incomplete" warning on parse failure. All synthesis/draft response paths now include source field for traceability. Frontend: LitigationAssistant surfaces QC warning field — shows "Scan Incomplete" with retry button instead of false "Clear" when AI output was unparseable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
46d3496 to
291c1cb
Compare
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| 🔵 In progress View logs |
chittycommand | 291c1cb | Mar 28 2026, 02:51 AM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
chittycommand-ui | 291c1cb | Mar 28 2026, 02:52 AM |
|
|
To use Codex here, create a Codex account and connect to github. |
🧩 Analysis chain🏁 Script executed: Length of output: 34239
🔴 High — XSS via
|
| Severity | Finding | File |
|---|---|---|
| 🔴 High | XSS via unsanitized AI content in dangerouslySetInnerHTML |
LitigationAssistant.tsx |
| 🟠 Medium | source missing/wrong in /synthesize-from-case passthrough & fallback |
litigation.ts |
| 🟠 Medium | KV model value used without allowlist — model substitution risk | litigation.ts |
| 🟠 Medium | Prompt injection via template-literal user inputs | litigation.ts |
| 🟡 Low | QC flag element structure not schema-validated | litigation.ts |
| 🟡 Low | No retry attempt limit on "Retry Scan" button | LitigationAssistant.tsx |
The XSS finding is a merge blocker per this repo's policy — AI-controlled content must not reach innerHTML without sanitization. The source field gaps and KV model substitution should also be addressed before merging, as they undermine the traceability and integrity guarantees this PR is specifically intended to provide.
🧠 Learnings used
Learnt from: CR
Repo: chittyos/chittycommand PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2026-03-04T04:42:57.380Z
Learning: Resolve must-fix review comments (security, correctness, compliance, merge blockers) before merge
✅ Actions performed
Review triggered.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Summary
callAIGatewayFallbacknow throws on empty AI response instead of silently returning empty string{ flags: [] }which is indistinguishable from "no flags found")sourcefield (chittyconnect,passthrough,ai-gateway-fallback,chittyevidence) for traceabilityLitigationAssistantQC output now renderswarningfield — shows "Scan Incomplete" with retry button instead of false "Clear" when AI output was unparseableTest plan
/litigation/synthesizereturnssourcefield in all code paths/litigation/draftreturnssourcefield in all code paths/litigation/qcreturnswarningwhen AI output is unparseable JSONwarningis present🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes