Skip to content

Fix broken tests and update models schema#500

Open
RohanExploit wants to merge 1 commit intomainfrom
fix-tests-and-model-schema-12811041833142274400
Open

Fix broken tests and update models schema#500
RohanExploit wants to merge 1 commit intomainfrom
fix-tests-and-model-schema-12811041833142274400

Conversation

@RohanExploit
Copy link
Owner

@RohanExploit RohanExploit commented Mar 4, 2026

This PR fixes several broken unit tests in the backend, primarily around thread safety in pothole_detection.py, missing database models/schemas in models.py resulting from incomplete PRs for ResolutionProofService, and invalid image byte strings being used in detection endpoint tests. All tests have been verified to pass successfully.


PR created automatically by Jules for task 12811041833142274400 started by @RohanExploit


Summary by cubic

Fixes failing backend tests by making model reset thread-safe and using real JPEG inputs. Updates the models schema to support ResolutionProofService with new evidence/token fields and an EvidenceAuditLog.

  • Bug Fixes

    • reset_model no longer auto-loads the model; removes race in thread-safety tests.
    • Tests generate valid JPEG bytes and mock cached detection/caption functions to match router usage.
  • Migration

    • Rename resolution_proof_tokens.token to token_id (unique, indexed) and add new token fields (authority, geofence, validity, nonce, signature, used_at).
    • Add new fields to resolution_evidence (hash, GPS, capture_timestamp, device_fingerprint_hash, metadata_bundle, server_signature, verification_status, token_id, created_at); file_path is now nullable.
    • Create evidence_audit_logs table.
    • Run DB migrations and backfill token_id from token where needed.

Written for commit 1d4833d. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added evidence verification and audit tracking system to monitor evidence status changes.
    • Enhanced token management with geofence-based validation and lifecycle tracking.
    • Added metadata capture for evidence including geolocation, device fingerprints, and timestamps.
  • Tests

    • Improved test coverage by using real image data instead of mock bytes for image detection features.

- Updated `backend/models.py` to add `VerificationStatus` and `EvidenceAuditLog`
- Added missing columns to `ResolutionEvidence` and `ResolutionProofToken` in `backend/models.py` based on usage in `ResolutionProofService`.
- Fixed dummy image tests (`test_captioning.py`, `test_smart_scan.py`, `test_graffiti_endpoint.py`) to generate valid PIL JPEG bytes.
- Fixed `backend/pothole_detection.py` thread safety test failures by ensuring `reset_model()` doesn't automatically call `load_model()` unconditionally.
@google-labs-jules
Copy link
Contributor

👋 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 @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings March 4, 2026 11:17
@netlify
Copy link

netlify bot commented Mar 4, 2026

Deploy Preview for fixmybharat canceled.

Name Link
🔨 Latest commit 1d4833d
🔍 Latest deploy log https://app.netlify.com/projects/fixmybharat/deploys/69a814b0408a080008322268

@github-actions
Copy link

github-actions bot commented Mar 4, 2026

🙏 Thank you for your contribution, @RohanExploit!

PR Details:

Quality Checklist:
Please ensure your PR meets the following criteria:

  • Code follows the project's style guidelines
  • Self-review of code completed
  • Code is commented where necessary
  • Documentation updated (if applicable)
  • No new warnings generated
  • Tests added/updated (if applicable)
  • All tests passing locally
  • No breaking changes to existing functionality

Review Process:

  1. Automated checks will run on your code
  2. A maintainer will review your changes
  3. Address any requested changes promptly
  4. Once approved, your PR will be merged! 🎉

Note: The maintainers will monitor code quality and ensure the overall project flow isn't broken.

@coderabbitai
Copy link

coderabbitai bot commented Mar 4, 2026

📝 Walkthrough

Walkthrough

The PR extends the data models by introducing a VerificationStatus enum and EvidenceAuditLog model for tracking evidence actions, adds cryptographic and location fields to ResolutionEvidence, refactors ResolutionProofToken with geofence and lifecycle management attributes, simplifies the model reset logic, and updates test infrastructure to mock cached detection functions with real PIL-generated images.

Changes

Cohort / File(s) Summary
Data Models Enhancement
backend/models.py
Introduces VerificationStatus enum (PENDING, VERIFIED, FLAGGED, FRAUD_DETECTED); adds EvidenceAuditLog model for audit tracking; extends ResolutionEvidence with token_id, evidence_hash, GPS coordinates, capture_timestamp, device_fingerprint_hash, metadata_bundle, server_signature, verification_status, and created_at; refactors ResolutionProofToken to rename token to token_id and add authority_email, geofence coordinates/radius, valid_from/until, nonce, token_signature, used_at, and generated_at.
Model Lifecycle Cleanup
backend/pothole_detection.py
Removes double-checked loading logic from reset_model function; function now resets singleton state without automatic model reload, delegating reload responsibility to get_model on next call.
Test Infrastructure Updates
tests/test_captioning.py, tests/test_graffiti_endpoint.py, tests/test_smart_scan.py
Standardizes test mocking across detection endpoints by switching from synchronous function mocks to cached/async detector mocks (e.g., _cached_generate_caption, _cached_detect_graffiti, _cached_detect_smart_scan); replaces fake byte strings with real 100x100 RGB PIL images serialized to BytesIO for test uploads.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

size/l

Poem

🐰 A burrow of schemas now gleams so bright,
With tokens that geo-fence in the night,
New audit logs hop along the trail,
While tests spring forth with images—never to fail!
Verification status keeps watch, complete—
The data model refactor's a herbivore's treat! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: fixing broken tests and updating the database models schema.
Description check ✅ Passed The pull request provides a clear, concise description of the changes: fixing broken tests, addressing thread safety issues, restoring missing database models, and correcting invalid image byte strings.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-tests-and-model-schema-12811041833142274400

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
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates backend unit tests and ORM models to align with the current detection router caching wrappers and the ResolutionProofService data model, and removes problematic model reload behavior during pothole model resets.

Changes:

  • Update detection endpoint tests to upload valid JPEG bytes (via Pillow) and patch router-level cached functions.
  • Remove unintended model reload logic from reset_model() in pothole_detection.py.
  • Extend backend/models.py with missing enums/models/columns needed by ResolutionProofService.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/test_smart_scan.py Uses a real generated JPEG payload and patches _cached_detect_smart_scan used by the endpoint.
tests/test_graffiti_endpoint.py Uses a real generated JPEG payload and patches _cached_detect_graffiti used by the endpoint.
tests/test_captioning.py Uses a real generated JPEG payload and patches _cached_generate_caption used by the endpoint.
backend/pothole_detection.py Removes post-reset implicit reload logic to keep reset behavior consistent and thread-safe.
backend/models.py Adds VerificationStatus, expands ResolutionEvidence/ResolutionProofToken, and adds EvidenceAuditLog to match ResolutionProofService.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

device_fingerprint_hash = Column(String, nullable=True)
metadata_bundle = Column(JSON, nullable=True)
server_signature = Column(String, nullable=True)
verification_status = Column(Enum(VerificationStatus), default=VerificationStatus.PENDING)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

verification_status currently allows NULLs. Since the service logic treats verification status as a required state machine, consider setting nullable=False (and optionally indexing it if you commonly filter by status). This avoids records with an undefined verification state.

Suggested change
verification_status = Column(Enum(VerificationStatus), default=VerificationStatus.PENDING)
verification_status = Column(Enum(VerificationStatus), default=VerificationStatus.PENDING, nullable=False)

Copilot uses AI. Check for mistakes.
Comment on lines 264 to +315
class ResolutionEvidence(Base):
__tablename__ = "resolution_evidence"
id = Column(Integer, primary_key=True, index=True)
grievance_id = Column(Integer, ForeignKey("grievances.id"), nullable=False)
file_path = Column(String, nullable=False)
token_id = Column(Integer, nullable=True)
evidence_hash = Column(String, nullable=False)
gps_latitude = Column(Float, nullable=True)
gps_longitude = Column(Float, nullable=True)
capture_timestamp = Column(DateTime, nullable=True)
device_fingerprint_hash = Column(String, nullable=True)
metadata_bundle = Column(JSON, nullable=True)
server_signature = Column(String, nullable=True)
verification_status = Column(Enum(VerificationStatus), default=VerificationStatus.PENDING)

file_path = Column(String, nullable=True) # made true to match earlier schema that had it but didn't require it in tests
media_type = Column(String, default="image")
description = Column(Text, nullable=True)
uploaded_at = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc))
created_at = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc))

# Relationship
grievance = relationship("Grievance", back_populates="resolution_evidence")

class ResolutionProofToken(Base):
__tablename__ = "resolution_proof_tokens"
id = Column(Integer, primary_key=True, index=True)
grievance_id = Column(Integer, ForeignKey("grievances.id"), nullable=False)
token = Column(String, unique=True, index=True)
generated_at = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc))
expires_at = Column(DateTime, nullable=False)
token_id = Column(String, unique=True, index=True)
authority_email = Column(String, nullable=False)
geofence_latitude = Column(Float, nullable=False)
geofence_longitude = Column(Float, nullable=False)
geofence_radius_meters = Column(Float, nullable=False)
valid_from = Column(DateTime, nullable=False)
valid_until = Column(DateTime, nullable=False)
nonce = Column(String, nullable=False)
token_signature = Column(String, nullable=False)
is_used = Column(Boolean, default=False)
used_at = Column(DateTime, nullable=True)
generated_at = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc))

# Relationship
grievance = relationship("Grievance", back_populates="resolution_tokens")


class EvidenceAuditLog(Base):
__tablename__ = "evidence_audit_logs"
id = Column(Integer, primary_key=True, index=True)
evidence_id = Column(Integer, ForeignKey("resolution_evidence.id"), nullable=False)
action = Column(String, nullable=False)
details = Column(String, nullable=True)
actor_email = Column(String, nullable=True)
timestamp = Column(DateTime, default=lambda: datetime.datetime.now(datetime.timezone.utc))
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

These schema additions/renames for resolution_evidence, resolution_proof_tokens, and the new evidence_audit_logs table will require a migration for existing databases. The repo uses backend/init_db.py:migrate_db() with manual ALTER TABLE checks, but it currently has no migration steps for these new columns/tables, so deployments against an existing DB are likely to fail at runtime (missing columns). Consider extending migrate_db() accordingly (and handling enum type creation where applicable).

Copilot uses AI. Check for mistakes.
server_signature = Column(String, nullable=True)
verification_status = Column(Enum(VerificationStatus), default=VerificationStatus.PENDING)

file_path = Column(String, nullable=True) # made true to match earlier schema that had it but didn't require it in tests
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

Inline comment # made true to match earlier schema... is confusing since this change makes the column nullable, not "true". Reword to clearly state the intention (e.g., "made nullable" / "optional for backward compatibility").

Suggested change
file_path = Column(String, nullable=True) # made true to match earlier schema that had it but didn't require it in tests
file_path = Column(String, nullable=True) # kept nullable to match earlier schema where this field was optional in tests

Copilot uses AI. Check for mistakes.
Comment on lines +291 to +299
token_id = Column(String, unique=True, index=True)
authority_email = Column(String, nullable=False)
geofence_latitude = Column(Float, nullable=False)
geofence_longitude = Column(Float, nullable=False)
geofence_radius_meters = Column(Float, nullable=False)
valid_from = Column(DateTime, nullable=False)
valid_until = Column(DateTime, nullable=False)
nonce = Column(String, nullable=False)
token_signature = Column(String, nullable=False)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

ResolutionProofToken.token_id is implicitly nullable here. Since token_id is used as the primary lookup key and should never be NULL, make it nullable=False (and consider adding a DB-level constraint/server_default if needed). Note that unique=True does not prevent multiple NULLs on some DBs (and can cause confusing duplicates in SQLite).

Copilot uses AI. Check for mistakes.
id = Column(Integer, primary_key=True, index=True)
grievance_id = Column(Integer, ForeignKey("grievances.id"), nullable=False)
file_path = Column(String, nullable=False)
token_id = Column(Integer, nullable=True)
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

ResolutionEvidence.token_id appears to store the DB PK of resolution_proof_tokens (see usages that query ResolutionProofToken.id == evidence.token_id). It should be declared as a ForeignKey("resolution_proof_tokens.id") (and ideally indexed) to enforce referential integrity and make joins/queries safer.

Suggested change
token_id = Column(Integer, nullable=True)
token_id = Column(Integer, ForeignKey("resolution_proof_tokens.id"), nullable=True, index=True)

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 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/models.py">

<violation number="1" location="backend/models.py:268">
P1: Missing `ForeignKey` constraint on `token_id`. This column is used as a reference to `resolution_proof_tokens.id` (confirmed by service code that assigns `token.id` to it and joins on it), but without the FK declaration the database won't enforce referential integrity — orphaned or invalid `token_id` values can be inserted.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

id = Column(Integer, primary_key=True, index=True)
grievance_id = Column(Integer, ForeignKey("grievances.id"), nullable=False)
file_path = Column(String, nullable=False)
token_id = Column(Integer, nullable=True)
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 4, 2026

Choose a reason for hiding this comment

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

P1: Missing ForeignKey constraint on token_id. This column is used as a reference to resolution_proof_tokens.id (confirmed by service code that assigns token.id to it and joins on it), but without the FK declaration the database won't enforce referential integrity — orphaned or invalid token_id values can be inserted.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At backend/models.py, line 268:

<comment>Missing `ForeignKey` constraint on `token_id`. This column is used as a reference to `resolution_proof_tokens.id` (confirmed by service code that assigns `token.id` to it and joins on it), but without the FK declaration the database won't enforce referential integrity — orphaned or invalid `token_id` values can be inserted.</comment>

<file context>
@@ -258,10 +265,21 @@ class ResolutionEvidence(Base):
     id = Column(Integer, primary_key=True, index=True)
     grievance_id = Column(Integer, ForeignKey("grievances.id"), nullable=False)
-    file_path = Column(String, nullable=False)
+    token_id = Column(Integer, nullable=True)
+    evidence_hash = Column(String, nullable=False)
+    gps_latitude = Column(Float, nullable=True)
</file context>
Suggested change
token_id = Column(Integer, nullable=True)
token_id = Column(Integer, ForeignKey("resolution_proof_tokens.id"), nullable=True)
Fix with Cubic

Copy link

@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: 1

🧹 Nitpick comments (2)
backend/models.py (1)

308-315: Add a composite index for audit history reads.

If this table is queried by evidence timeline, indexing (evidence_id, timestamp) will avoid expensive scans as records grow.

Index addition
 class EvidenceAuditLog(Base):
     __tablename__ = "evidence_audit_logs"
+    __table_args__ = (
+        Index("ix_evidence_audit_logs_evidence_timestamp", "evidence_id", "timestamp"),
+    )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/models.py` around lines 308 - 315, Add a composite index on
(evidence_id, timestamp) to the EvidenceAuditLog model to speed timeline
queries; modify the EvidenceAuditLog class (the ORM class and its
__table_args__) to include an Index on the columns evidence_id and timestamp
(e.g., Index("ix_evidence_audit_logs_evidence_id_timestamp",
EvidenceAuditLog.evidence_id, EvidenceAuditLog.timestamp)) so the database
creates a multi-column index for audit-history reads.
tests/test_captioning.py (1)

16-20: Consider extracting shared image-bytes test helper.

The same PIL/BytesIO setup is duplicated across multiple detection tests; a small fixture/helper would reduce maintenance churn.

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

In `@tests/test_captioning.py` around lines 16 - 20, Extract the repeated
PIL/BytesIO setup (creating Image.new('RGB', (100,100)), saving to BytesIO, and
returning the bytes stored in file_content) into a shared test helper or pytest
fixture (e.g., make_image_bytes or sample_image_bytes) and replace usages of the
inline variables img, img_bytes, and file_content in tests with calls to that
helper/fixture; ensure the helper returns raw bytes so existing assertions that
consume file_content remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/models.py`:
- Around line 268-269: There are two different "token_id" fields (one Integer,
one String) and a nullable string token that create ambiguity; change the
evidence linkage token column to an explicit FK (e.g., token_id ->
Column(Integer, ForeignKey('tokens.id', name='fk_evidence_token_id'),
nullable=False) on the evidence model referencing the tokens table) and rename
the other string identifier to a distinct name (e.g., token_identifier or
token_hash) and make it nullable=False as well so both token identifiers are
non-null and unambiguous; ensure evidence_hash remains non-null and update any
references/usages to the renamed string token field in code and queries.

---

Nitpick comments:
In `@backend/models.py`:
- Around line 308-315: Add a composite index on (evidence_id, timestamp) to the
EvidenceAuditLog model to speed timeline queries; modify the EvidenceAuditLog
class (the ORM class and its __table_args__) to include an Index on the columns
evidence_id and timestamp (e.g.,
Index("ix_evidence_audit_logs_evidence_id_timestamp",
EvidenceAuditLog.evidence_id, EvidenceAuditLog.timestamp)) so the database
creates a multi-column index for audit-history reads.

In `@tests/test_captioning.py`:
- Around line 16-20: Extract the repeated PIL/BytesIO setup (creating
Image.new('RGB', (100,100)), saving to BytesIO, and returning the bytes stored
in file_content) into a shared test helper or pytest fixture (e.g.,
make_image_bytes or sample_image_bytes) and replace usages of the inline
variables img, img_bytes, and file_content in tests with calls to that
helper/fixture; ensure the helper returns raw bytes so existing assertions that
consume file_content remain unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f155b1f-3296-4a92-b7c4-cd25ebf27dba

📥 Commits

Reviewing files that changed from the base of the PR and between 62aa431 and 1d4833d.

📒 Files selected for processing (5)
  • backend/models.py
  • backend/pothole_detection.py
  • tests/test_captioning.py
  • tests/test_graffiti_endpoint.py
  • tests/test_smart_scan.py
💤 Files with no reviewable changes (1)
  • backend/pothole_detection.py

Comment on lines +268 to +269
token_id = Column(Integer, nullable=True)
evidence_hash = Column(String, nullable=False)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Disambiguate and constrain token linkage fields.

Line 268 and Line 291 currently define two different token_id concepts (Integer vs String), and the String identifier is nullable. This is prone to data-integrity drift and ambiguous query behavior. Use an explicit FK name for evidence linkage and make token identifiers non-null.

Suggested schema adjustment
 class ResolutionEvidence(Base):
@@
-    token_id = Column(Integer, nullable=True)
+    resolution_proof_token_id = Column(Integer, ForeignKey("resolution_proof_tokens.id"), nullable=True, index=True)
@@
-    grievance = relationship("Grievance", back_populates="resolution_evidence")
+    grievance = relationship("Grievance", back_populates="resolution_evidence")
+    resolution_proof_token = relationship("ResolutionProofToken", back_populates="evidence_items")

 class ResolutionProofToken(Base):
@@
-    token_id = Column(String, unique=True, index=True)
+    token_id = Column(String, unique=True, index=True, nullable=False)
@@
-    grievance = relationship("Grievance", back_populates="resolution_tokens")
+    grievance = relationship("Grievance", back_populates="resolution_tokens")
+    evidence_items = relationship("ResolutionEvidence", back_populates="resolution_proof_token")

Also applies to: 291-291

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

In `@backend/models.py` around lines 268 - 269, There are two different "token_id"
fields (one Integer, one String) and a nullable string token that create
ambiguity; change the evidence linkage token column to an explicit FK (e.g.,
token_id -> Column(Integer, ForeignKey('tokens.id',
name='fk_evidence_token_id'), nullable=False) on the evidence model referencing
the tokens table) and rename the other string identifier to a distinct name
(e.g., token_identifier or token_hash) and make it nullable=False as well so
both token identifiers are non-null and unambiguous; ensure evidence_hash
remains non-null and update any references/usages to the renamed string token
field in code and queries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants