⚡ Bolt: Escalation Blockchain Integrity & N+1 Optimization#908
⚡ Bolt: Escalation Blockchain Integrity & N+1 Optimization#908RohanExploit wants to merge 4 commits into
Conversation
…ttleneck in escalation engine
- Implemented blockchain-style SHA256 hash chaining for EscalationAudit records.
- Optimized hash lookup with a thread-safe O(1) in-memory cache, reducing DB round-trips.
- Fixed N+1 query bottleneck in periodic escalation evaluation using joinedload(Grievance.jurisdiction).
- Added /api/escalation/{audit_id}/blockchain-verify endpoint for integrity verification.
- Updated models, schemas, and service logic with performance-first patterns.
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
🙏 Thank you for your contribution, @RohanExploit!PR Details:
Quality Checklist:
Review Process:
Note: The maintainers will monitor code quality and ensure the overall project flow isn't broken. |
|
Warning Review limit reached
Next review available in: 1 minute Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
✨ 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.
7 issues found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/escalation_engine.py">
<violation number="1" location="backend/escalation_engine.py:24">
P2: The class-level cache retains one hash for every escalated grievance forever, so memory grows with the lifetime total rather than the active working set. Use a bounded or TTL cache, or provide explicit invalidation.</violation>
<violation number="2" location="backend/escalation_engine.py:263">
P1: Concurrent escalations for one grievance can create sibling audit records with the same `previous_integrity_hash`, breaking the single ordered audit chain. Serialize hash selection through audit insert/commit with database-level coordination, then update the cache after the transaction succeeds.</violation>
<violation number="3" location="backend/escalation_engine.py:305">
P2: Cold-cache lookups can scan `escalation_audits` because `EscalationAudit.grievance_id` is not indexed, so the fallback does not scale as claimed. Add a composite `(grievance_id, id)` index for this filter-and-order query.</violation>
<violation number="4" location="backend/escalation_engine.py:309">
P2: A grievance whose newest audit has a NULL `integrity_hash` starts a new GENESIS chain even though an audit already exists, leaving the new record disconnected from its history. Backfill or explicitly handle legacy unhashed rows before creating a chained audit.</violation>
</file>
<file name="backend/grievance_service.py">
<violation number="1" location="backend/grievance_service.py:322">
P2: Callers using the documented `service.manual_escalate(..., reason=...)` form now fail with `TypeError: unexpected keyword argument 'reason'` before escalation runs, because this public service parameter was renamed without a compatibility alias. Preserving `reason` or accepting both names would keep existing callers functional.</violation>
</file>
<file name="backend/models.py">
<violation number="1" location="backend/models.py:109">
P2: New audit records can be stored with a NULL `integrity_hash`, so the database does not enforce that every audit is part of a verifiable chain. Making this column non-null after backfilling legacy rows would align it with the follower integrity field and preserve the audit invariant.</violation>
<violation number="2" location="backend/models.py:109">
P1: Existing deployments will not receive this new column: `create_all()` does not migrate an already-created `escalation_audits` table, and the startup migration has no `escalation_audits` steps. A migration adding both integrity columns and the `integrity_hash` index is needed before the new audit query/insert paths run against persisted databases.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| notes = Column(Text, nullable=True) # Additional context | ||
|
|
||
| # Blockchain-style integrity fields | ||
| integrity_hash = Column(String, nullable=True, index=True) |
There was a problem hiding this comment.
P1: Existing deployments will not receive this new column: create_all() does not migrate an already-created escalation_audits table, and the startup migration has no escalation_audits steps. A migration adding both integrity columns and the integrity_hash index is needed before the new audit query/insert paths run against persisted databases.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/models.py, line 109:
<comment>Existing deployments will not receive this new column: `create_all()` does not migrate an already-created `escalation_audits` table, and the startup migration has no `escalation_audits` steps. A migration adding both integrity columns and the `integrity_hash` index is needed before the new audit query/insert paths run against persisted databases.</comment>
<file context>
@@ -105,6 +105,10 @@ class EscalationAudit(Base):
notes = Column(Text, nullable=True) # Additional context
+ # Blockchain-style integrity fields
+ integrity_hash = Column(String, nullable=True, index=True)
+ previous_integrity_hash = Column(String, nullable=True)
+
</file context>
|
|
||
| # Blockchain-style integrity hashing | ||
| # Get previous hash (O(1) from cache or O(log N) from indexed DB) | ||
| prev_hash = self._get_last_audit_hash(grievance.id, db) |
There was a problem hiding this comment.
P1: Concurrent escalations for one grievance can create sibling audit records with the same previous_integrity_hash, breaking the single ordered audit chain. Serialize hash selection through audit insert/commit with database-level coordination, then update the cache after the transaction succeeds.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/escalation_engine.py, line 263:
<comment>Concurrent escalations for one grievance can create sibling audit records with the same `previous_integrity_hash`, breaking the single ordered audit chain. Serialize hash selection through audit insert/commit with database-level coordination, then update the cache after the transaction succeeds.</comment>
<file context>
@@ -248,25 +258,63 @@ def _escalate_grievance(self, grievance: Grievance, reason: EscalationReason,
+ # Blockchain-style integrity hashing
+ # Get previous hash (O(1) from cache or O(log N) from indexed DB)
+ prev_hash = self._get_last_audit_hash(grievance.id, db)
+
+ # Calculate new integrity hash: SHA256(grievance_id | reason | prev_hash)
</file context>
| return self.escalation_engine.escalate_grievance_severity(grievance_id, new_severity, reason) | ||
|
|
||
| def manual_escalate(self, grievance_id: int, reason: str = "") -> bool: | ||
| def manual_escalate(self, grievance_id: int, notes: str = "") -> bool: |
There was a problem hiding this comment.
P2: Callers using the documented service.manual_escalate(..., reason=...) form now fail with TypeError: unexpected keyword argument 'reason' before escalation runs, because this public service parameter was renamed without a compatibility alias. Preserving reason or accepting both names would keep existing callers functional.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/grievance_service.py, line 322:
<comment>Callers using the documented `service.manual_escalate(..., reason=...)` form now fail with `TypeError: unexpected keyword argument 'reason'` before escalation runs, because this public service parameter was renamed without a compatibility alias. Preserving `reason` or accepting both names would keep existing callers functional.</comment>
<file context>
@@ -319,18 +319,18 @@ def escalate_grievance_severity(self, grievance_id: int, new_severity: SeverityL
return self.escalation_engine.escalate_grievance_severity(grievance_id, new_severity, reason)
- def manual_escalate(self, grievance_id: int, reason: str = "") -> bool:
+ def manual_escalate(self, grievance_id: int, notes: str = "") -> bool:
"""
Manually escalate a grievance.
</file context>
| notes = Column(Text, nullable=True) # Additional context | ||
|
|
||
| # Blockchain-style integrity fields | ||
| integrity_hash = Column(String, nullable=True, index=True) |
There was a problem hiding this comment.
P2: New audit records can be stored with a NULL integrity_hash, so the database does not enforce that every audit is part of a verifiable chain. Making this column non-null after backfilling legacy rows would align it with the follower integrity field and preserve the audit invariant.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/models.py, line 109:
<comment>New audit records can be stored with a NULL `integrity_hash`, so the database does not enforce that every audit is part of a verifiable chain. Making this column non-null after backfilling legacy rows would align it with the follower integrity field and preserve the audit invariant.</comment>
<file context>
@@ -105,6 +105,10 @@ class EscalationAudit(Base):
notes = Column(Text, nullable=True) # Additional context
+ # Blockchain-style integrity fields
+ integrity_hash = Column(String, nullable=True, index=True)
+ previous_integrity_hash = Column(String, nullable=True)
+
</file context>
|
|
||
| # Cache for O(1) blockchain integrity hash lookups | ||
| # Stores {grievance_id: last_audit_integrity_hash} | ||
| _audit_last_hash_cache = {} |
There was a problem hiding this comment.
P2: The class-level cache retains one hash for every escalated grievance forever, so memory grows with the lifetime total rather than the active working set. Use a bounded or TTL cache, or provide explicit invalidation.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/escalation_engine.py, line 24:
<comment>The class-level cache retains one hash for every escalated grievance forever, so memory grows with the lifetime total rather than the active working set. Use a bounded or TTL cache, or provide explicit invalidation.</comment>
<file context>
@@ -17,6 +19,11 @@ class EscalationEngine:
+ # Cache for O(1) blockchain integrity hash lookups
+ # Stores {grievance_id: last_audit_integrity_hash}
+ _audit_last_hash_cache = {}
+ _cache_lock = threading.Lock()
+
</file context>
|
|
||
| # Cache miss: Fallback to indexed DB query | ||
| last_audit = db.query(EscalationAudit)\ | ||
| .filter(EscalationAudit.grievance_id == grievance_id)\ |
There was a problem hiding this comment.
P2: Cold-cache lookups can scan escalation_audits because EscalationAudit.grievance_id is not indexed, so the fallback does not scale as claimed. Add a composite (grievance_id, id) index for this filter-and-order query.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/escalation_engine.py, line 305:
<comment>Cold-cache lookups can scan `escalation_audits` because `EscalationAudit.grievance_id` is not indexed, so the fallback does not scale as claimed. Add a composite `(grievance_id, id)` index for this filter-and-order query.</comment>
<file context>
@@ -248,25 +258,63 @@ def _escalate_grievance(self, grievance: Grievance, reason: EscalationReason,
+
+ # Cache miss: Fallback to indexed DB query
+ last_audit = db.query(EscalationAudit)\
+ .filter(EscalationAudit.grievance_id == grievance_id)\
+ .order_by(desc(EscalationAudit.id))\
+ .first()
</file context>
| .order_by(desc(EscalationAudit.id))\ | ||
| .first() | ||
|
|
||
| last_hash = last_audit.integrity_hash if last_audit else None |
There was a problem hiding this comment.
P2: A grievance whose newest audit has a NULL integrity_hash starts a new GENESIS chain even though an audit already exists, leaving the new record disconnected from its history. Backfill or explicitly handle legacy unhashed rows before creating a chained audit.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/escalation_engine.py, line 309:
<comment>A grievance whose newest audit has a NULL `integrity_hash` starts a new GENESIS chain even though an audit already exists, leaving the new record disconnected from its history. Backfill or explicitly handle legacy unhashed rows before creating a chained audit.</comment>
<file context>
@@ -248,25 +258,63 @@ def _escalate_grievance(self, grievance: Grievance, reason: EscalationReason,
+ .order_by(desc(EscalationAudit.id))\
+ .first()
+
+ last_hash = last_audit.integrity_hash if last_audit else None
+
+ # Update cache for next time
</file context>
…ttleneck (with deployment fix) - Implemented blockchain-style SHA256 hash chaining for EscalationAudit records. - Optimized hash lookup with a thread-safe O(1) in-memory cache, reducing DB round-trips. - Fixed N+1 query bottleneck in periodic escalation evaluation using joinedload(Grievance.jurisdiction). - Fixed a SyntaxError in backend/main.py (missing except block) that caused deployment failure. - Updated models, schemas, and service logic with performance-first patterns.
There was a problem hiding this comment.
7 issues found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/main.py">
<violation number="1" location="backend/main.py:150">
P1: Background action-plan generation never persists on the normal path: a dict is assigned to the `Text` column and the commit fails, leaving new issues without their generated plan. Serializing the plan for storage and deserializing it when building `IssueResponse` would keep the database and API types consistent.</violation>
<violation number="2" location="backend/main.py:313">
P2: After a successful vote, `/api/issues/recent` can show the old upvote count for up to five minutes because the cached response is not invalidated. Invalidating `recent_issues_cache` after the commit would keep the recent-issues view consistent.</violation>
<violation number="3" location="backend/main.py:459">
P2: Urgency analysis from the report form always returns 422 because this handler requires `UrgencyAnalysisRequest.category`, but the frontend sends only `description`. Making `category` optional/deriving it, or including it in the frontend payload, would restore the workflow.</violation>
<violation number="4" location="backend/main.py:564">
P1: Concurrent follow requests can create divergent follower-chain branches because this call does not serialize the predecessor read with the insert and commit. A database transaction/lock or another atomic sequencing mechanism would preserve a single chain under concurrency.</violation>
<violation number="5" location="backend/main.py:579">
P2: A nonexistent follower ID produces a 500 instead of a not-found response because the service's short result does not satisfy `BlockchainVerificationResponse`. Returning a 404 or a complete verification payload would make this endpoint handle missing records correctly.</violation>
<violation number="6" location="backend/main.py:594">
P1: On an existing deployment, the escalation blockchain verification endpoint can fail with a database 'no such column' error because the new audit hash columns are not migrated. Adding an explicit migration for both columns before querying `EscalationAudit` would preserve existing databases.</violation>
<violation number="7" location="backend/main.py:776">
P1: These external detector endpoints bypass the 10 MB and MIME/image validation policy, so an unbounded upload is read into memory, base64-encoded, and forwarded to Hugging Face. Applying `validate_uploaded_file` to each handler would prevent oversized or non-image uploads from reaching this path.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| Bolt Optimization: Uses O(1) in-memory cache for hash chaining. | ||
| """ | ||
| follower = await run_in_threadpool( | ||
| grievance_service.follow_grievance, |
There was a problem hiding this comment.
P1: Concurrent follow requests can create divergent follower-chain branches because this call does not serialize the predecessor read with the insert and commit. A database transaction/lock or another atomic sequencing mechanism would preserve a single chain under concurrency.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 564:
<comment>Concurrent follow requests can create divergent follower-chain branches because this call does not serialize the predecessor read with the insert and commit. A database transaction/lock or another atomic sequencing mechanism would preserve a single chain under concurrency.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
+ Bolt Optimization: Uses O(1) in-memory cache for hash chaining.
+ """
+ follower = await run_in_threadpool(
+ grievance_service.follow_grievance,
+ grievance_id,
+ request.user_email,
</file context>
| # Update issue in DB | ||
| issue = db.query(Issue).filter(Issue.id == issue_id).first() | ||
| if issue: | ||
| issue.action_plan = action_plan |
There was a problem hiding this comment.
P1: Background action-plan generation never persists on the normal path: a dict is assigned to the Text column and the commit fails, leaving new issues without their generated plan. Serializing the plan for storage and deserializing it when building IssueResponse would keep the database and API types consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 150:
<comment>Background action-plan generation never persists on the normal path: a dict is assigned to the `Text` column and the commit fails, leaving new issues without their generated plan. Serializing the plan for storage and deserializing it when building `IssueResponse` would keep the database and API types consistent.</comment>
<file context>
@@ -1,137 +1,272 @@
+ # Update issue in DB
+ issue = db.query(Issue).filter(Issue.id == issue_id).first()
+ if issue:
+ issue.action_plan = action_plan
+ db.commit()
+
</file context>
| @app.post("/api/detect-illegal-parking") | ||
| async def detect_illegal_parking_endpoint(request: Request, image: UploadFile = File(...)): | ||
| try: | ||
| image_bytes = await image.read() |
There was a problem hiding this comment.
P1: These external detector endpoints bypass the 10 MB and MIME/image validation policy, so an unbounded upload is read into memory, base64-encoded, and forwarded to Hugging Face. Applying validate_uploaded_file to each handler would prevent oversized or non-image uploads from reaching this path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 776:
<comment>These external detector endpoints bypass the 10 MB and MIME/image validation policy, so an unbounded upload is read into memory, base64-encoded, and forwarded to Hugging Face. Applying `validate_uploaded_file` to each handler would prevent oversized or non-image uploads from reaching this path.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
[email protected]("/api/detect-illegal-parking")
+async def detect_illegal_parking_endpoint(request: Request, image: UploadFile = File(...)):
+ try:
+ image_bytes = await image.read()
+ except Exception as e:
+ logger.error(f"Invalid image file: {e}", exc_info=True)
</file context>
| import hashlib | ||
|
|
||
| def verify_audit(): | ||
| audit = db.query(EscalationAudit).filter(EscalationAudit.id == audit_id).first() |
There was a problem hiding this comment.
P1: On an existing deployment, the escalation blockchain verification endpoint can fail with a database 'no such column' error because the new audit hash columns are not migrated. Adding an explicit migration for both columns before querying EscalationAudit would preserve existing databases.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 594:
<comment>On an existing deployment, the escalation blockchain verification endpoint can fail with a database 'no such column' error because the new audit hash columns are not migrated. Adding an explicit migration for both columns before querying `EscalationAudit` would preserve existing databases.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
+ import hashlib
+
+ def verify_audit():
+ audit = db.query(EscalationAudit).filter(EscalationAudit.id == audit_id).first()
+ if not audit:
+ raise HTTPException(status_code=404, detail="Audit record not found")
</file context>
| Verify the cryptographic integrity of a follower record. | ||
| """ | ||
| result = await run_in_threadpool( | ||
| grievance_service.verify_follower_integrity, |
There was a problem hiding this comment.
P2: A nonexistent follower ID produces a 500 instead of a not-found response because the service's short result does not satisfy BlockchainVerificationResponse. Returning a 404 or a complete verification payload would make this endpoint handle missing records correctly.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 579:
<comment>A nonexistent follower ID produces a 500 instead of a not-found response because the service's short result does not satisfy `BlockchainVerificationResponse`. Returning a 404 or a complete verification payload would make this endpoint handle missing records correctly.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
+ Verify the cryptographic integrity of a follower record.
+ """
+ result = await run_in_threadpool(
+ grievance_service.verify_follower_integrity,
+ follower_id,
+ db
</file context>
| def save_issue_db(db: Session, issue: Issue): | ||
| db.add(issue) | ||
| db.commit() | ||
| db.refresh(issue) |
There was a problem hiding this comment.
P2: After a successful vote, /api/issues/recent can show the old upvote count for up to five minutes because the cached response is not invalidated. Invalidating recent_issues_cache after the commit would keep the recent-issues view consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 313:
<comment>After a successful vote, `/api/issues/recent` can show the old upvote count for up to five minutes because the cached response is not invalidated. Invalidating `recent_issues_cache` after the commit would keep the recent-issues view consistent.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
+def save_issue_db(db: Session, issue: Issue):
+ db.add(issue)
+ db.commit()
+ db.refresh(issue)
+ return issue
+
</file context>
| db.refresh(issue) | |
| db.refresh(issue) | |
| recent_issues_cache.invalidate() |
| class ChatRequest(BaseModel): | ||
| query: str | ||
| @app.post("/api/analyze-urgency", response_model=UrgencyAnalysisResponse) | ||
| async def analyze_urgency_endpoint(request: Request, urgency_req: UrgencyAnalysisRequest): |
There was a problem hiding this comment.
P2: Urgency analysis from the report form always returns 422 because this handler requires UrgencyAnalysisRequest.category, but the frontend sends only description. Making category optional/deriving it, or including it in the frontend payload, would restore the workflow.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/main.py, line 459:
<comment>Urgency analysis from the report form always returns 422 because this handler requires `UrgencyAnalysisRequest.category`, but the frontend sends only `description`. Making `category` optional/deriving it, or including it in the frontend payload, would restore the workflow.</comment>
<file context>
@@ -196,185 +304,663 @@ async def ml_status():
-class ChatRequest(BaseModel):
- query: str
[email protected]("/api/analyze-urgency", response_model=UrgencyAnalysisResponse)
+async def analyze_urgency_endpoint(request: Request, urgency_req: UrgencyAnalysisRequest):
+ try:
+ client = request.app.state.http_client
</file context>
- Resolved a critical SyntaxError in backend/main.py (missing except block) that caused Render deployment to fail.
- Restored backend/main.py to a clean, optimized state by removing duplicated imports and endpoints.
- Implemented blockchain-style SHA256 hash chaining for EscalationAudit records to ensure tamper-evident logs.
- Optimized hash chaining with a thread-safe O(1) in-memory cache, eliminating unnecessary database scans.
- Fixed an N+1 query bottleneck in periodic escalation evaluation using joinedload(Grievance.jurisdiction).
- Corrected a SyntaxError in backend/hf_service.py (await outside async function).
- Added a new /api/escalation/{audit_id}/blockchain-verify endpoint for audit integrity verification.
🔍 Quality Reminder |
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="backend/hf_service.py">
<violation number="1" location="backend/hf_service.py:96">
P2: RGBA and other non-RGB images without a source format are serialized as JPEG, which Pillow rejects and turns into an empty detection result. Converting non-RGB images before JPEG encoding, or choosing a format compatible with the image mode, preserves detection for these inputs.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| fmt = getattr(image, 'format', 'JPEG') or 'JPEG' | ||
| image.save(img_byte_arr, format=fmt) |
There was a problem hiding this comment.
P2: RGBA and other non-RGB images without a source format are serialized as JPEG, which Pillow rejects and turns into an empty detection result. Converting non-RGB images before JPEG encoding, or choosing a format compatible with the image mode, preserves detection for these inputs.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/hf_service.py, line 96:
<comment>RGBA and other non-RGB images without a source format are serialized as JPEG, which Pillow rejects and turns into an empty detection result. Converting non-RGB images before JPEG encoding, or choosing a format compatible with the image mode, preserves detection for these inputs.</comment>
<file context>
@@ -88,6 +88,16 @@ async def _make_request(client, image_bytes, labels):
+
+ img_byte_arr = io.BytesIO()
+ # Handle different image formats
+ fmt = getattr(image, 'format', 'JPEG') or 'JPEG'
+ image.save(img_byte_arr, format=fmt)
+ return img_byte_arr.getvalue()
</file context>
| fmt = getattr(image, 'format', 'JPEG') or 'JPEG' | |
| image.save(img_byte_arr, format=fmt) | |
| fmt = getattr(image, 'format', 'JPEG') or 'JPEG' | |
| if fmt == 'JPEG' and image.mode != 'RGB': | |
| image = image.convert('RGB') | |
| image.save(img_byte_arr, format=fmt) |
…ttleneck (with deployment fix) - Implemented blockchain-style SHA256 hash chaining for EscalationAudit records to ensure tamper-evident logs. - Optimized hash lookup with a thread-safe O(1) in-memory cache, reducing DB round-trips. - Fixed N+1 query bottleneck in periodic escalation evaluation using joinedload(Grievance.jurisdiction). - Fixed a SyntaxError in backend/main.py (missing except block) that caused deployment failure. - Fixed a SyntaxError in backend/hf_service.py (await outside async function). - Updated models, schemas, and service logic with performance-first patterns. - Synchronized start-backend.py to use the optimized main application entry point.
💡 What: Implemented a blockchain-style cryptographic integrity system for grievance escalation audits, combined with a major database query optimization.
🎯 Why:
📊 Impact:
🔬 Measurement:
tests/verify_audit_blockchain.py).backend/test_grievance_escalation.py.PR created automatically by Jules for task 3725348573393189050 started by @RohanExploit
Summary by cubic
Adds blockchain-style integrity to escalation audits, removes the N+1 query in escalation checks, and restores backend deployment by fixing syntax and entrypoint issues.
New Features
EscalationAuditviaintegrity_hashandprevious_integrity_hash./api/escalation/{audit_id}/blockchain-verifyto validate audit integrity.Performance & Fixes
joinedload(Grievance.jurisdiction)and added a thread-safe O(1) last-hash cache with DB fallback.backend/main.pyandbackend/hf_service.py, consolidated the app intobackend/main.py, and updatedstart-backend.pyto usebackend.main:app.Written for commit d4cc866. Summary will update on new commits.