Skip to content

fix: deletion fixes, codebase detection perf improvements and misc refactoring - #675

Merged
JayGhiya merged 3 commits into
mainfrom
fix-perf-reliability-and-code-refactor
Aug 5, 2025
Merged

fix: deletion fixes, codebase detection perf improvements and misc refactoring#675
JayGhiya merged 3 commits into
mainfrom
fix-perf-reliability-and-code-refactor

Conversation

@JayGhiya

@JayGhiya JayGhiya commented Aug 5, 2025

Copy link
Copy Markdown
Member

User description

  • Capture comprehensive pre-deletion graph state snapshot
  • Validate API deletion stats against actual pre-deletion state
  • Ensure complete repository deletion by checking for any remaining nodes/relationships
  • Remove unused rel_count_by_type function
  • Simplify node count checks for integration tests

PR Type

Bug fix, Enhancement, Tests


Description

Performance improvements: Replaced AsyncDetectorWrapper and PythonCodebaseDetector with new PythonRipgrepDetector for faster codebase detection using ripgrep
Enhanced deletion validation: Added comprehensive pre-deletion state capture and validation of API deletion statistics against actual graph state
Graph deletion reliability: Fixed deletion logic to use prefix matching instead of relationship traversal, preventing issues with missing relationships
Code refactoring: Consolidated base model imports to use unoplat_code_confluence_commons package, removing duplicate model definitions
Simplified package detection: Replaced weight-based package manager detection with ordered evaluation (first match wins) approach
Bug fixes: Fixed node creation return values, package discovery infinite loops, and various import path issues
Test improvements: Enhanced integration tests with better deletion verification and updated test data to reflect structural changes
Configuration updates: Added contains_absence field support and updated dependency versions


Diagram Walkthrough

flowchart LR
  A["Old AsyncDetectorWrapper"] -- "replaced by" --> B["PythonRipgrepDetector"]
  C["Weight-based detection"] -- "simplified to" --> D["Ordered detection"]
  E["Local model definitions"] -- "consolidated to" --> F["Commons package"]
  G["Relationship traversal"] -- "improved to" --> H["Prefix matching deletion"]
  I["Basic deletion tests"] -- "enhanced with" --> J["Comprehensive validation"]
Loading

File Walkthrough

Relevant files
Enhancement
6 files
main.py
Replace codebase detector with ripgrep-based implementation

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/main.py

• Replaced AsyncDetectorWrapper and PythonCodebaseDetector with
PythonRipgrepDetector for improved performance
• Added initialization
of shared PythonRipgrepDetector instance in application lifespan

Simplified SSE event generation by removing queue-based progress
tracking
• Updated codebase detection endpoint to use new detector
directly

+734/-484
python_ripgrep_detector.py
Add new ripgrep-based Python codebase detector                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/package_manager/detectors/python_ripgrep_detector.py

• New fast Python package manager detector using ripgrep for file
discovery
• Implements async detection with ordered evaluation (first
match wins)
• Maintains same interface as PythonCodebaseDetector for
drop-in replacement
• Uses breadth-first processing to prevent nested
directory conflicts

+323/-0 
graph_assertions.py
Enhance graph deletion validation and remove unused functions

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/utils/graph_assertions.py

• Removed unused rel_count_by_type function
• Added comprehensive
pre-deletion state capture functionality
• Added validation of API
deletion statistics against actual graph state
• Enhanced repository
deletion verification with better error reporting

+128/-42
ripgrep_utils.py
Add ripgrep utilities for fast file discovery and searching

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/package_manager/detectors/ripgrep_utils.py

• New utility module providing async wrappers for ripgrep subprocess
calls
• Implements fast file discovery using glob patterns
• Provides
content searching and Python package root detection
• All functions
use asyncio.subprocess for non-blocking I/O

+218/-0 
ordered_detection.py
Add ordered package manager detection without weights       

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/package_manager/detectors/ordered_detection.py

• New module implementing simple ordered detection logic
• Evaluates
package managers in sequence with first match wins approach
• Supports
file-based and glob-based signatures with content matching
• Removes
complex weight calculations and tie-breaking logic

+194/-0 
settings.py
Add contains_absence field to Signature configuration model

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/models/configuration/settings.py

• Added contains_absence field to Signature model for specifying
substrings that must NOT appear in files

+1/-1     
Tests
11 files
test_delete_repository.py
Improve deletion test validation with comprehensive state checking

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/integration/test_delete_repository.py

• Added pre-deletion state snapshot capture for validation
• Enhanced
deletion verification with API statistics validation
• Replaced manual
verification with comprehensive helper functions
• Added sanity checks
to ensure content exists before deletion

+37/-60 
test_generic_codebase_parser.py
Update imports and test expectations for codebase root package

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_generic_codebase_parser.py

• Updated import to use StructuralSignature from
unoplat_code_confluence_commons.base_models
• Removed role field from
ProgrammingLanguageMetadata initialization
• Added support for root
directory package detection (7th package)
• Updated test expectations
to handle codebase root package

+6/-4     
test_framework_detection_structural_signature.py
Update test imports and file paths for commons migration 

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_framework_detection_structural_signature.py

• Updated import to use StructuralSignature from commons package

Changed test file path to point to commons package location for
structural_signature.py

+4/-4     
test_tree_sitter_structural_signature.py
Update test imports and line number expectations                 

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_tree_sitter_structural_signature.py

• Consolidated imports to use StructuralSignature and FunctionInfo
from commons package
• Adjusted line number expectations in tests due
to import changes

+5/-6     
test_framework_definitions_ingestion.py
Update framework model imports to use commons package       

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/integration/test_framework_definitions_ingestion.py

• Updated import to use framework models from commons package

+1/-1     
test_poetry_strategy.py
Remove role field from metadata initialization                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/package_manager/test_poetry_strategy.py

• Removed role field from ProgrammingLanguageMetadata initialization

+1/-1     
test_uv_strategy.py
Remove role field from metadata initialization                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/package_manager/test_uv_strategy.py

• Removed role field from ProgrammingLanguageMetadata initialization

+1/-1     
test_pip_strategy.py
Remove role field from metadata initialization                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/package_manager/test_pip_strategy.py

• Removed role field from ProgrammingLanguageMetadata initialization

+1/-1     
test_main_py_structural_signature.json
Update test data to reflect main.py structural changes     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_main_py_structural_signature.json

• Updated line numbers and function signatures throughout the JSON
test data
• Reflects changes in the main.py file structure due to
import reorganization
• Updated logging format strings and function
call patterns

+295/-259
test_self_extraction_tree_sitter_structural_signature.json
Update test data line numbers for structural signature changes

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_self_extraction_tree_sitter_structural_signature.json

• Updated line numbers throughout the JSON test data to reflect import
changes
• Adjusted global variable positions and class method line
numbers

+76/-78 
test_instance_variable_edge_cases.json
Reorder global variables in test data                                       

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/parser/test_instance_variable_edge_cases.json

• Reordered global variables in the test data
• Changed order of
GLOBAL_CONFIG, ANOTHER_GLOBAL, and app_instance entries

+5/-5     
Bug fix
4 files
code_confluence_graph_deletion.py
Improve graph deletion reliability with prefix matching   

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/processor/db/graph_db/code_confluence_graph_deletion.py

• Updated package and file retrieval to use prefix matching instead of
relationship traversal
• Simplified deletion logic by removing
recursive package processing
• Enhanced debugging with more detailed
logging throughout deletion workflow
• Fixed potential issues with
missing relationships during deletion

+25/-30 
generic_codebase_parser.py
Fix node creation return value and package discovery logic

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/generic_codebase_parser.py

• Fixed node creation to return empty string instead of None when no
record found
• Added safety check to prevent infinite loop in package
discovery
• Improved package hierarchy traversal logic

+6/-28   
test_start_ingestion.py
Fix import path for database module                                           

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/integration/test_start_ingestion.py

• Fixed import path to use proper src. prefix for database module

+1/-1     
environment_utils.py
Fix import path for settings module                                           

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/utility/environment_utils.py

• Fixed import path to use proper src. prefix for settings module

+1/-1     
Refactoring
9 files
__init__.py
Refactor base model imports to use commons package             

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/models/code_confluence_parsing_models/init.py

• Moved base model imports (ClassInfo, FunctionInfo,
StructuralSignature, VariableInfo) to
unoplat_code_confluence_commons.base_models
• Consolidated imports
from commons package

+5/-11   
python_framework_detection_service.py
Refactor imports to use commons package and fix import paths

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/engine/python/python_framework_detection_service.py

• Updated imports to use base models from commons package
• Fixed
import paths to use proper src. prefix for local modules

+6/-10   
code_confluence_graph_ingestion.py
Update framework import to use commons package                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/processor/db/graph_db/code_confluence_graph_ingestion.py

• Updated import to use Framework from commons package instead of
local postgres models
• Fixed import path for database session

+2/-2     
simplified_python_detector.py
Refactor imports to use commons package base models           

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/engine/python/simplified_python_detector.py

• Consolidated imports to use base models from commons package

Removed individual model imports in favor of commons package imports

+4/-11   
tree_sitter_structural_signature.py
Refactor imports to use commons package base models           

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/tree_sitter_structural_signature.py

• Consolidated imports to use base models from commons package

Removed individual model imports in favor of commons package

+1/-9     
framework_query_service.py
Refactor framework query imports to use commons package   

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/processor/db/postgres/framework_query_service.py

• Updated imports to use framework-related models from commons package

• Moved FeatureSpec, FeatureAbsolutePath, and FrameworkFeature imports
to commons

+5/-5     
unoplat_file.py
Refactor imports to use commons package models                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/models/code_confluence_parsing_models/unoplat_file.py

• Updated imports to use StructuralSignature and Detection from
commons package

+1/-5     
framework_detection_service.py
Refactor imports to use commons package models                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/engine/framework_detection_service.py

• Updated imports to use StructuralSignature and Detection from
commons package

+1/-5     
framework_loader.py
Refactor framework loader imports to use commons package 

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/processor/db/postgres/framework_loader.py

• Updated imports to use framework models from commons package
• Fixed
import path for settings module

+2/-2     
Formatting
2 files
sse_response.py
Add type ignore annotation and formatting fixes                   

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/package_manager/detectors/sse_response.py

• Added type ignore comment for init method
• Minor formatting
adjustments to method signature

+3/-3     
sync_db_cleanup.py
Add missing newline at end of file                                             

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/tests/utils/sync_db_cleanup.py

• Added missing newline at end of file

+1/-1     
Configuration changes
2 files
rules.yaml
Rewrite package manager detection rules with simplified configuration

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/parser/package_manager/detectors/rules.yaml

• Complete rewrite of package manager detection rules with simplified
Python-only configuration
• Added contains_absence field support for
excluding patterns
• Removed weight-based evaluation in favor of
ordered evaluation (first match wins)
• Simplified schema with
homogeneous mapping structure

+35/-64 
pyproject.toml
Update dependencies and pytest configuration, remove build system

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/pyproject.toml

• Removed build system configuration section (build-system)
• Updated
unoplat-code-confluence-commons dependency from version v0.20.0 to
v0.22.0
• Added pythonpath = ["src"] configuration to pytest tool
settings

+3/-5     
Dependencies
1 files
Dockerfile
Add ripgrep package to Docker container stages                     

unoplat-code-confluence-ingestion/code-confluence-flow-bridge/Dockerfile

• Added ripgrep package installation to both build and runtime stages

• Enhanced container capabilities with additional search tooling

+2/-2     
Additional files
10 files
poetry.toml +0/-2     
models.py +0/-172 
class_info.py +0/-30   
function_info.py +0/-30   
structural_signature.py +0/-29   
variable_info.py +0/-10   
async_detector_wrapper.py +0/-337 
codebase_auto_detector.py +0/-571 
codebase_child_workflow.py +0/-1     
custom_grammar_metadata.py +0/-148 


This is part 1 of 2 in a stack made with GitButler:

…factoring

- Capture comprehensive pre-deletion graph state snapshot
- Validate API deletion stats against actual pre-deletion state
- Ensure complete repository deletion by checking for any remaining nodes/relationships
- Remove unused `rel_count_by_type` function
- Simplify node count checks for integration tests
@huly-for-github

Copy link
Copy Markdown

Connected to Huly®: UNOPL-812

@claude

claude Bot commented Aug 5, 2025

Copy link
Copy Markdown

Claude finished @JayGhiya's task —— View job


PR Review: Deletion Fixes and Performance Improvements

I've completed my comprehensive review of this substantial refactoring PR. Here's my detailed analysis:

Review Progress

  • Analyze core deletion logic improvements
  • Review new ripgrep-based codebase detection system
  • Evaluate removed model files and refactoring impact
  • Check test coverage and integration test updates
  • Assess performance implications
  • Review security considerations
  • Provide comprehensive feedback summary

Strengths and Improvements

1. Enhanced Deletion Logic (code_confluence_graph_deletion.py)

  • Excellent two-phase deletion approach: Relationships first, then nodes - this prevents Neo4j constraint violations
  • Comprehensive batch operations: Using DETACH DELETE and batch processing for performance
  • Robust error handling: Proper ApplicationError propagation with detailed context
  • Enhanced logging: Detailed statistics tracking for debugging and monitoring

2. New Ripgrep-Based Detection System

  • Significant performance improvement: Single ripgrep call instead of recursive filesystem traversal
  • Clean architecture: Well-separated concerns with OrderedDetector, PythonRipgrepDetector, and ripgrep_utils
  • Ordered evaluation: Simplified logic - first match wins, eliminating complex weight calculations
  • Proper async handling: Non-blocking subprocess calls with asyncio.create_subprocess_exec

3. Improved Test Coverage

  • Enhanced validation: New capture_repository_state_snapshot() and assert_deletion_stats_accuracy() functions
  • Comprehensive verification: assert_repository_completely_deleted() ensures complete cleanup
  • Better debugging: Detailed pre/post deletion state logging

4. Code Simplification

  • Removed unused models: Eliminated class_info.py, function_info.py, variable_info.py, structural_signature.py
  • Consolidated dependencies: Migration from Poetry to uv across commons project
  • Streamlined rules: Simplified YAML configuration without complex weight calculations

⚠️ Areas of Concern

1. Performance and Reliability

MODERATE: Ripgrep dependency

  • The new system depends on external ripgrep binary being installed
  • Consider adding fallback mechanism if ripgrep is not available
  • Missing validation that ripgrep is installed before using detection
# In ripgrep_utils.py line 54-72
# Add ripgrep availability check in initialization
async def check_ripgrep_available() -> bool:
    try:
        process = await asyncio.create_subprocess_exec(
            "rg", "--version",
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        returncode = await process.wait()
        return returncode == 0
    except FileNotFoundError:
        return False

2. Code Quality Issues

MINOR: Inconsistent error handling

  • In python_ripgrep_detector.py:319, the clone_url variable is used but Repo.clone_from() could still fail
  • Consider more specific exception handling around Git operations

MINOR: Magic numbers

  • Line 439 in test_delete_repository.py has hardcoded timeout of 300 seconds
  • Consider making timeouts configurable via environment variables

3. Test Coverage Gaps

MODERATE: Limited ripgrep error scenarios

  • No tests for ripgrep failure cases (binary not found, permission errors)
  • Missing tests for malformed YAML rules file scenarios
  • Integration tests don't verify performance improvements claimed

🔒 Security Considerations

GOOD: No security regressions identified

  • GitHub token handling remains properly secured
  • No credential leakage in new logging statements
  • Subprocess calls use proper argument passing (not shell injection vulnerable)

MINOR: Input validation

  • YAML rule loading in python_ripgrep_detector.py:79 should validate structure more strictly
  • Consider adding schema validation for rules.yaml to prevent runtime errors

🚀 Performance Analysis

EXCELLENT: Detection performance improvements

  • Single ripgrep call vs recursive filesystem traversal is a major improvement
  • Breadth-first directory processing with early termination is well-designed
  • Batch Neo4j operations will significantly improve deletion performance

GOOD: Memory efficiency

  • Streaming file processing instead of loading all files in memory
  • Proper resource cleanup with async context managers

📋 Specific Recommendations

High Priority

  1. Add ripgrep availability check in detector initialization
  2. Add schema validation for rules.yaml file structure
  3. Add integration test for ripgrep failure scenarios

Medium Priority

  1. Make timeouts configurable via environment variables
  2. Add performance benchmarks to quantify improvements
  3. Consider graceful degradation if ripgrep is unavailable

Low Priority

  1. Add more specific Git clone error handling
  2. Consider adding telemetry for detection performance metrics

🎯 Overall Assessment

This is a high-quality refactoring PR that addresses real performance and reliability issues. The deletion logic improvements are particularly excellent and will prevent data inconsistency issues. The ripgrep-based detection system represents a significant architectural improvement.

Recommendation: APPROVE with minor fixes

The code quality is strong, test coverage is comprehensive, and the performance improvements are substantial. The identified issues are minor and can be addressed in follow-up PRs if needed.

Key Wins:

  • ✅ Robust two-phase deletion prevents Neo4j constraint violations
  • ✅ Major performance improvement in codebase detection
  • ✅ Enhanced test validation prevents regression bugs
  • ✅ Simplified, maintainable code architecture

Files with highest impact: code_confluence_graph_deletion.py:460-616, python_ripgrep_detector.py:108-201, test_delete_repository.py:456-540


@JayGhiya JayGhiya changed the title fix: deletion fixes, codebase detection perf improvements and misc refactoring fix: deletion fixes, codebase detection perf improvements and misc refactoring, better tests Aug 5, 2025
@qodo-code-review qodo-code-review Bot changed the title fix: deletion fixes, codebase detection perf improvements and misc refactoring, better tests fix: deletion fixes, codebase detection perf improvements and misc refactoring Aug 5, 2025
@qodo-code-review

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 Security concerns

Sensitive information exposure:
The _clone_repository method in PythonRipgrepDetector embeds GitHub tokens directly into clone URLs (line 315). While this is for HTTPS authentication, the token could potentially be logged or exposed in error messages. Consider using environment variables or secure credential management instead of direct URL manipulation.

⚡ Recommended focus areas for review

Performance Risk

The _clone_repository method performs synchronous Git operations that could block the event loop. Consider using async alternatives or running in a thread pool to maintain performance during batch operations.

def _clone_repository(self, git_url: str, github_token: str) -> str:
    """
    Clone GitHub repository to local path.
    Uses same logic as existing detector for consistency.

    Args:
        git_url: GitHub repository URL
        github_token: GitHub personal access token for authentication

    Returns:
        Local path to cloned repository
    """
    # Extract repository name from URL (same logic as existing detector)
    if git_url.startswith("git@"):
        # Handle SSH format: git@github.com:org/repo.git
        repo_path: str = git_url.split("github.com:")[-1]
    else:
        # Handle HTTPS format: https://github.com/org/repo[.git]
        repo_path = git_url.split("github.com/")[-1]
    repo_path = repo_path.replace(".git", "")
    repo_name: str = repo_path.split("/")[-1]

    # Create local directory (same as existing detector)
    local_base_path: str = os.path.join(
        os.path.expanduser("~"), ".unoplat", "repositories"
    )
    os.makedirs(local_base_path, exist_ok=True)

    # Set local clone path
    local_repo_path: str = os.path.join(local_base_path, repo_name)

    # Clone repository if not already cloned
    if not os.path.exists(local_repo_path):
        # Add token to URL for HTTPS URLs
        if git_url.startswith("https://"):
            # Insert token into HTTPS URL
            clone_url: str = git_url.replace("https://", f"https://{github_token}@")
        else:
            clone_url = git_url

        Repo.clone_from(clone_url, local_repo_path, depth=1)

    return local_repo_path
Logic Change

The deletion logic has been significantly changed from relationship traversal to prefix matching. This fundamental change in approach needs careful validation to ensure it correctly identifies all related nodes without false positives or missed deletions.

    Transaction function to get all packages for a codebase using prefix matching.
    This ensures we find all packages belonging to the codebase, even if relationships are missing.
    """
    query = """
    MATCH (c:CodeConfluenceCodebase {qualified_name: $codebase_qualified_name})
    MATCH (p:CodeConfluencePackage)
    WHERE p.qualified_name STARTS WITH c.codebase_path
    RETURN p
    """
    result = await tx.run(query, {"codebase_qualified_name": codebase_qualified_name})
    return [record async for record in result]

async def _get_codebase_files_txn(self, tx: AsyncManagedTransaction, codebase_qualified_name: str) -> List[Record]:
    """
    Transaction function to get all files for a codebase using prefix matching.
    This ensures we find all files belonging to the codebase, even if relationships are missing.
    """
    query = """
    MATCH (c:CodeConfluenceCodebase {qualified_name: $codebase_qualified_name})
    MATCH (f:CodeConfluenceFile)
    WHERE f.file_path STARTS WITH c.codebase_path
    RETURN f
    """
    result = await tx.run(query, {"codebase_qualified_name": codebase_qualified_name})
    return [record async for record in result]
Test Coverage

The new assertion functions assume single-repository integration tests by counting all nodes of each type. This approach may not scale well to multi-repository scenarios and could produce false positives in shared test environments.

graph_model_labels = get_all_graph_model_labels()
for label in graph_model_labels:
    if label == "CodeConfluenceGitRepository":
        # For repository, check if it exists (should be 1)
        snapshot["node_counts"][label] = 1 if repo_exists(neo4j_client, repo_qualified_name) else 0
    else:
        # For integration tests, count all nodes of each type since only one repo is ingested
        snapshot["node_counts"][label] = count_nodes_by_label(neo4j_client, label)

@qodo-code-review

qodo-code-review Bot commented Aug 5, 2025

Copy link
Copy Markdown

PR Code Suggestions ✨

Adds a step to install the ripgrep tool in the Python build
workflow. Ripgrep is a fast and efficient file search tool that
can be useful for various development tasks.
fix: Install ripgrep in Python build workflow
@claude

claude Bot commented Aug 5, 2025

Copy link
Copy Markdown

Claude finished @JayGhiya's task —— View job


Claude finished @JayGhiya's task —— View job


PR Review: Deletion Fixes and Performance Improvements

I've completed my comprehensive review of this substantial refactoring PR. Here's my detailed analysis:

Review Progress

  • Analyze core deletion logic improvements
  • Review new ripgrep-based codebase detection system
  • Evaluate removed model files and refactoring impact
  • Check test coverage and integration test updates
  • Assess performance implications
  • Review security considerations
  • Provide comprehensive feedback summary

Strengths and Improvements

1. Enhanced Deletion Logic (code_confluence_graph_deletion.py)

  • Excellent two-phase deletion approach: Relationships first, then nodes - this prevents Neo4j constraint violations
  • Comprehensive batch operations: Using DETACH DELETE and batch processing for performance
  • Robust error handling: Proper ApplicationError propagation with detailed context
  • Enhanced logging: Detailed statistics tracking for debugging and monitoring

2. New Ripgrep-Based Detection System

  • Significant performance improvement: Single ripgrep call instead of recursive filesystem traversal
  • Clean architecture: Well-separated concerns with OrderedDetector, PythonRipgrepDetector, and ripgrep_utils
  • Ordered evaluation: Simplified logic - first match wins, eliminating complex weight calculations
  • Proper async handling: Non-blocking subprocess calls with asyncio.create_subprocess_exec

3. Improved Test Coverage

  • Enhanced validation: New capture_repository_state_snapshot() and assert_deletion_stats_accuracy() functions
  • Comprehensive verification: assert_repository_completely_deleted() ensures complete cleanup
  • Better debugging: Detailed pre/post deletion state logging

4. Code Simplification

  • Removed unused models: Eliminated class_info.py, function_info.py, variable_info.py, structural_signature.py
  • Consolidated dependencies: Migration from Poetry to uv across commons project
  • Streamlined rules: Simplified YAML configuration without complex weight calculations

⚠️ Areas of Concern

1. Performance and Reliability

MODERATE: Ripgrep dependency

  • The new system depends on external ripgrep binary being installed
  • Consider adding fallback mechanism if ripgrep is not available
  • Missing validation that ripgrep is installed before using detection
# In ripgrep_utils.py line 54-72
# Add ripgrep availability check in initialization
async def check_ripgrep_available() -> bool:
    try:
        process = await asyncio.create_subprocess_exec(
            "rg", "--version",
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE
        )
        returncode = await process.wait()
        return returncode == 0
    except FileNotFoundError:
        return False

2. Code Quality Issues

MINOR: Inconsistent error handling

  • In python_ripgrep_detector.py:319, the clone_url variable is used but Repo.clone_from() could still fail
  • Consider more specific exception handling around Git operations

MINOR: Magic numbers

  • Line 439 in test_delete_repository.py has hardcoded timeout of 300 seconds
  • Consider making timeouts configurable via environment variables

3. Test Coverage Gaps

MODERATE: Limited ripgrep error scenarios

  • No tests for ripgrep failure cases (binary not found, permission errors)
  • Missing tests for malformed YAML rules file scenarios
  • Integration tests don't verify performance improvements claimed

🔒 Security Considerations

GOOD: No security regressions identified

  • GitHub token handling remains properly secured
  • No credential leakage in new logging statements
  • Subprocess calls use proper argument passing (not shell injection vulnerable)

MINOR: Input validation

  • YAML rule loading in python_ripgrep_detector.py:79 should validate structure more strictly
  • Consider adding schema validation for rules.yaml to prevent runtime errors

🚀 Performance Analysis

EXCELLENT: Detection performance improvements

  • Single ripgrep call vs recursive filesystem traversal is a major improvement
  • Breadth-first directory processing with early termination is well-designed
  • Batch Neo4j operations will significantly improve deletion performance

GOOD: Memory efficiency

  • Streaming file processing instead of loading all files in memory
  • Proper resource cleanup with async context managers

📋 Specific Recommendations

High Priority

  1. Add ripgrep availability check in detector initialization
  2. Add schema validation for rules.yaml file structure
  3. Add integration test for ripgrep failure scenarios

Medium Priority

  1. Make timeouts configurable via environment variables
  2. Add performance benchmarks to quantify improvements
  3. Consider graceful degradation if ripgrep is unavailable

Low Priority

  1. Add more specific Git clone error handling
  2. Consider adding telemetry for detection performance metrics

🎯 Overall Assessment

This is a high-quality refactoring PR that addresses real performance and reliability issues. The deletion logic improvements are particularly excellent and will prevent data inconsistency issues. The ripgrep-based detection system represents a significant architectural improvement.

Recommendation: APPROVE with minor fixes

The code quality is strong, test coverage is comprehensive, and the performance improvements are substantial. The identified issues are minor and can be addressed in follow-up PRs if needed.

Key Wins:

  • ✅ Robust two-phase deletion prevents Neo4j constraint violations
  • ✅ Major performance improvement in codebase detection
  • ✅ Enhanced test validation prevents regression bugs
  • ✅ Simplified, maintainable code architecture

Files with highest impact: code_confluence_graph_deletion.py:460-616, python_ripgrep_detector.py:108-201, test_delete_repository.py:456-540


@JayGhiya
JayGhiya merged commit 70cfe88 into main Aug 5, 2025
2 of 3 checks passed
@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-uv-projects (unoplat-code-confluence-ingestion/code-confluence-flow-bridge)

Failed stage: Install dependencies and run tests [❌]

Failed test name: test_complete_detection_and_ingestion_flow

Failure summary:

The action failed because 3 tests failed due to a missing dependency. All failed tests encountered
the error "ripgrep (rg) not found. Please install ripgrep." The tests that failed were:

test_complete_detection_and_ingestion_flow in tests/integration/test_start_ingestion.py at line 506

test_full_sse_flow_with_token_ingestion in
tests/parser/package_manager/detectors/test_detect_codebases_sse.py at line 272

test_delete_local_repository_flow in tests/integration/test_delete_repository.py at line 411

The tests failed during codebase detection operations that require the ripgrep (rg) command-line
tool, which is not installed in the GitHub Actions runner environment.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

210:  * [new branch]      dependabot/npm_and_yarn/unoplat-code-confluence-frontend/vite-6.2.7 -> origin/dependabot/npm_and_yarn/unoplat-code-confluence-frontend/vite-6.2.7
211:  * [new branch]      dependabot/pip/unoplat-code-confluence-commons/requests-2.32.4 -> origin/dependabot/pip/unoplat-code-confluence-commons/requests-2.32.4
212:  * [new branch]      dependabot/pip/unoplat-code-confluence-commons/urllib3-2.5.0 -> origin/dependabot/pip/unoplat-code-confluence-commons/urllib3-2.5.0
213:  * [new branch]      dependency-fixes-ingestion  -> origin/dependency-fixes-ingestion
214:  * [new branch]      design-registry-local       -> origin/design-registry-local
215:  * [new branch]      docker-compose-fixes        -> origin/docker-compose-fixes
216:  * [new branch]      docs-llms-txt               -> origin/docs-llms-txt
217:  * [new branch]      docs-revamp                 -> origin/docs-revamp
218:  * [new branch]      docs-update                 -> origin/docs-update
219:  * [new branch]      docs-update-1               -> origin/docs-update-1
220:  * [new branch]      docs-update-2               -> origin/docs-update-2
221:  * [new branch]      docs-update-contribution-guidelines -> origin/docs-update-contribution-guidelines
222:  * [new branch]      enable-search-across-personal-oss-repos -> origin/enable-search-across-personal-oss-repos
223:  * [new branch]      end-end-test-local-temporal-workflow -> origin/end-end-test-local-temporal-workflow
224:  * [new branch]      enhance-postgresql-commit-rollback-across -> origin/enhance-postgresql-commit-rollback-across
225:  * [new branch]      enhancement-improved-error-messages -> origin/enhancement-improved-error-messages
226:  * [new branch]      feature/add-new-user-authentication -> origin/feature/add-new-user-authentication
227:  * [new branch]      feature/empty-diff-no-changes -> origin/feature/empty-diff-no-changes
228:  * [new branch]      final-release-side-bar      -> origin/final-release-side-bar
229:  * [new branch]      fix-alignment               -> origin/fix-alignment
230:  * [new branch]      fix-build-error-for-release -> origin/fix-build-error-for-release
231:  * [new branch]      fix-dialog-toast-position   -> origin/fix-dialog-toast-position
...

927:  tests/confluence_git/test_github_helper.py::TestGithubHelper::test_clone_nested_repository PASSED [  2%]
928:  tests/confluence_git/test_github_helper.py::TestGithubHelper::test_github_connection PASSED [  4%]
929:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_schema_creation_and_structure PASSED [  5%]
930:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_framework_definitions_loading PASSED [  7%]
931:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_bulk_insert_performance PASSED [  8%]
932:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_foreign_key_relationships PASSED [ 10%]
933:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_concept_and_locator_strategy_validation PASSED [ 11%]
934:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_construct_query_jsonb_storage PASSED [ 13%]
935:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_clear_and_repopulate_idempotency PASSED [ 14%]
936:  tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_real_framework_data_parsing_accuracy PASSED [ 16%]
937:  tests/integration/test_framework_detection_with_postgres.py::TestFrameworkDetectionWithPostgres::test_detect_fastapi_endpoints_main_py PASSED [ 17%]
938:  tests/integration/test_framework_detection_with_postgres.py::TestFrameworkDetectionWithPostgres::test_instance_variable_binding PASSED [ 19%]
939:  tests/integration/test_framework_detection_with_postgres.py::TestFrameworkDetectionWithPostgres::test_detect_pydantic_models PASSED [ 20%]
940:  tests/integration/test_framework_detection_with_postgres.py::TestFrameworkDetectionWithPostgres::test_multi_framework_detection PASSED [ 22%]
941:  tests/integration/test_start_ingestion.py::TestStartIngestionEndpoint::test_start_ingestion_flow PASSED [ 23%]
942:  tests/integration/test_start_ingestion.py::TestStartIngestionEndpoint::test_complete_detection_and_ingestion_flow FAILED [ 25%]
943:  tests/parser/linters/python/test_ruff_strategy.py::TestRuffStrategy::test_ruff_linting PASSED [ 26%]
944:  tests/parser/package_manager/detectors/test_detect_codebases_sse.py::TestDetectCodebasesSSEIntegration::test_full_sse_flow_with_token_ingestion FAILED [ 27%]
945:  tests/parser/package_manager/detectors/test_detect_codebases_sse.py::TestDetectCodebasesSSEIntegration::test_sse_with_invalid_git_url PASSED [ 29%]
...

978:  tests/parser/test_framework_detection_structural_signature.py::TestFrameworkDetectionStructuralSignature::test_advanced_pydantic_from_real_package_metadata_py PASSED [ 77%]
979:  tests/parser/test_framework_detection_structural_signature.py::TestFrameworkDetectionStructuralSignature::test_sqlalchemy_detection_from_real_repository_data_py PASSED [ 79%]
980:  tests/parser/test_framework_detection_structural_signature.py::TestFrameworkDetectionStructuralSignature::test_complex_framework_combination_from_real_main_py PASSED [ 80%]
981:  tests/parser/test_framework_detection_structural_signature.py::TestFrameworkDetectionStructuralSignature::test_performance_comparison_with_real_main_py PASSED [ 82%]
982:  tests/parser/test_framework_detection_structural_signature.py::TestFrameworkDetectionStructuralSignature::test_framework_detection_across_multiple_real_files PASSED [ 83%]
983:  tests/parser/test_generic_codebase_parser.py::TestGenericCodebaseParserIntegration::test_parser_inserts_nodes PASSED [ 85%]
984:  tests/parser/test_tree_sitter_structural_signature.py::test_structural_signature_extraction[python] PASSED [ 86%]
985:  tests/parser/test_tree_sitter_structural_signature.py::test_structural_signature_extraction_complex[python] PASSED [ 88%]
986:  tests/parser/test_tree_sitter_structural_signature.py::test_edge_cases_function_calls[python] PASSED [ 89%]
987:  tests/parser/test_tree_sitter_structural_signature.py::test_self_extraction_tree_sitter_structural_signature[python] PASSED [ 91%]
988:  tests/parser/test_tree_sitter_structural_signature.py::test_no_duplicate_nested_functions[python] PASSED [ 92%]
989:  tests/parser/test_tree_sitter_structural_signature.py::test_main_py_structural_signature[python] PASSED [ 94%]
990:  tests/parser/test_tree_sitter_structural_signature.py::test_instance_variable_edge_cases[python] PASSED [ 95%]
991:  tests/parser/test_tree_sitter_structural_signature.py::test_local_variables_not_captured[python] PASSED [ 97%]
992:  tests/integration/test_delete_repository.py::TestDeleteRepositoryEndpoint::test_delete_nonexistent_repository PASSED [ 98%]
993:  tests/integration/test_delete_repository.py::TestDeleteRepositoryEndpoint::test_delete_local_repository_flow FAILED [100%]
994:  =================================== FAILURES ===================================
995:  ____ TestStartIngestionEndpoint.test_complete_detection_and_ingestion_flow _____
...

1020:  # ------------------------------------------------------------------
1021:  # 2️⃣  Ensure token is ingested (idempotent)
1022:  # ------------------------------------------------------------------
1023:  token_resp = test_client.post(
1024:  "/ingest-token",
1025:  headers={"Authorization": f"***"},
1026:  )
1027:  assert token_resp.status_code in (201, 409), token_resp.text
1028:  repository_name = "unoplat-code-confluence"
1029:  # ------------------------------------------------------------------
1030:  # 3️⃣  Get local repository path and detect codebases via SSE
1031:  # ------------------------------------------------------------------
1032:  local_repo_path: str = get_repository_path()
1033:  detection_result: DetectionResult = detect_local_codebases(test_client, local_repo_path)
1034:  # Validate detection succeeded
1035:  >       assert detection_result.error is None, f"Detection failed: {detection_result.error}"
1036:  E       AssertionError: Detection failed: ripgrep (rg) not found. Please install ripgrep.
1037:  E       assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1038:  E        +  where 'ripgrep (rg) not found. Please install ripgrep.' = DetectionResult(repository_url='/home/runner/.unoplat/repositories/unoplat-code-confluence', duration_seconds=0.0010848045349121094, codebases=[], error='ripgrep (rg) not found. Please install ripgrep.').error
1039:  tests/integration/test_start_ingestion.py:506: AssertionError
1040:  ----------------------------- Captured stdout call -----------------------------
1041:  �[32m2025-08-05 12:55:54.715�[0m | �[34m�[1mDEBUG   �[0m | �[36mtests.utils.sync_db_cleanup�[0m:�[36mcleanup_postgresql_sync�[0m:�[36m45�[0m | unoplat-code-confluence | PostgreSQL repository data cleared successfully
1042:  �[32m2025-08-05 12:55:54.720�[0m | �[34m�[1mDEBUG   �[0m | �[36mtests.utils.sync_db_cleanup�[0m:�[36mcleanup_neo4j_sync�[0m:�[36m22�[0m | unoplat-code-confluence | Neo4j database cleared successfully
1043:  �[32m2025-08-05 12:55:54.720�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mdispose_current_engine�[0m:�[36m185�[0m | unoplat-code-confluence | No engine found for current loop to dispose
1044:  �[32m2025-08-05 12:55:54.723�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1045:  �[32m2025-08-05 12:55:54.723�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1046:  �[32m2025-08-05 12:55:54.723�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1047:  �[32m2025-08-05 12:55:54.724�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1048:  �[32m2025-08-05 12:55:54.724�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1049:  �[32m2025-08-05 12:55:54.728�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m125�[0m | unoplat-code-confluence | Encountered error inside DB session context: {exc}
1050:  �[33m�[1mTraceback (most recent call last):�[0m
...

1107:  │    └ <member '_context' of 'Handle' objects>
1108:  └ <Handle Task.task_wakeup()>
1109:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/anyio/from_thread.py", line 221, in _call_func
1110:  retval = await retval_or_awaitable
1111:  └ <coroutine object FastAPI.__call__ at 0x7f56660694e0>
1112:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/fastapi/applications.py", line 1054, in __call__
1113:  await super().__call__(scope, receive, send)
1114:  │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f5665eb9a80>
1115:  │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665eb8860>
1116:  └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1117:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/applications.py", line 112, in __call__
1118:  await self.middleware_stack(scope, receive, send)
1119:  │    │                │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f5665eb9a80>
1120:  │    │                │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665eb8860>
1121:  │    │                └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1122:  │    └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1123:  └ <fastapi.applications.FastAPI object at 0x7f566eedfcb0>
1124:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 165, in __call__
1125:  await self.app(scope, receive, _send)
1126:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665eb9260>
1127:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665eb8860>
1128:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1129:  │    └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1130:  └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1131:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/cors.py", line 85, in __call__
1132:  await self.app(scope, receive, send)
1133:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665eb9260>
1134:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665eb8860>
1135:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1136:  │    └ <starlette.middleware.exceptions.ExceptionMiddleware object at 0x7f56666134d0>
1137:  └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1138:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
1139:  await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
1140:  │                            │    │    │     │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665eb9260>
1141:  │                            │    │    │     │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665eb8860>
...

1217:  File "�[32m/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/�[0m�[32m�[1mmain.py�[0m", line �[33m767�[0m, in �[35mingest_token�[0m
1218:  �[35m�[1mraise�[0m �[1mhttp_ex�[0m
1219:  File "�[32m/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/�[0m�[32m�[1mmain.py�[0m", line �[33m741�[0m, in �[35mingest_token�[0m
1220:  �[35m�[1mraise�[0m �[1mHTTPException�[0m�[1m(�[0m
1221:  �[36m      └ �[0m�[36m�[1m<class 'fastapi.exceptions.HTTPException'>�[0m
1222:  �[31m�[1mfastapi.exceptions.HTTPException�[0m:�[1m 409: Token already ingested. Use update-token to update it.�[0m
1223:  �[32m2025-08-05 12:55:54.771�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1224:  �[32m2025-08-05 12:55:54.776�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1225:  �[32m2025-08-05 12:55:54.776�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1226:  �[32m2025-08-05 12:55:54.776�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1227:  �[32m2025-08-05 12:55:54.777�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1228:  �[32m2025-08-05 12:55:54.777�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1229:  �[32m2025-08-05 12:55:54.779�[0m | �[1mINFO    �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mdetect_codebases_sse�[0m:�[36m521�[0m | unoplat-code-confluence | Local repository detection - folder: unoplat-code-confluence, resolved path: /home/runner/.unoplat/repositories/unoplat-code-confluence, environment: development
1230:  �[32m2025-08-05 12:55:54.780�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m122�[0m | unoplat-code-confluence | Session transaction finished, changes will be committed on context exit
1231:  �[32m2025-08-05 12:55:54.780�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1232:  �[32m2025-08-05 12:55:54.781�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mgenerate_sse_events�[0m:�[36m489�[0m | unoplat-code-confluence | Detection error: ripgrep (rg) not found. Please install ripgrep.
1233:  __ TestDetectCodebasesSSEIntegration.test_full_sse_flow_with_token_ingestion ___
...

1294:  for event in progress_events:
1295:  assert 'state' in event['data']
1296:  assert 'message' in event['data']
1297:  assert 'repository_url' in event['data']
1298:  assert event['data']['repository_url'] == test_repo_url
1299:  logger.info("✓ Progress events validated")
1300:  # Check result event
1301:  result_events = [e for e in events if e.get('event') == 'result']
1302:  assert len(result_events) == 1, f"Expected 1 result event, got {len(result_events)}"
1303:  result_data = result_events[0]['data']
1304:  assert 'repository_url' in result_data
1305:  assert result_data['repository_url'] == test_repo_url
1306:  assert 'codebases' in result_data
1307:  assert isinstance(result_data['codebases'], list)
1308:  assert 'duration_seconds' in result_data
1309:  >           assert result_data['error'] is None
1310:  E           AssertionError: assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1311:  tests/parser/package_manager/detectors/test_detect_codebases_sse.py:272: AssertionError
1312:  ----------------------------- Captured stdout call -----------------------------
1313:  �[32m2025-08-05 12:55:54.989�[0m | �[1mINFO    �[0m | �[36mtests.parser.package_manager.detectors.test_detect_codebases_sse�[0m:�[36mtest_full_sse_flow_with_token_ingestion�[0m:�[36m193�[0m | unoplat-code-confluence | Step 1: Ingesting GitHub token
1314:  �[32m2025-08-05 12:55:54.991�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1315:  �[32m2025-08-05 12:55:54.991�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1316:  �[32m2025-08-05 12:55:54.991�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1317:  �[32m2025-08-05 12:55:54.991�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1318:  �[32m2025-08-05 12:55:54.991�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1319:  �[32m2025-08-05 12:55:54.994�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m125�[0m | unoplat-code-confluence | Encountered error inside DB session context: {exc}
1320:  �[33m�[1mTraceback (most recent call last):�[0m
...

1377:  │    └ <member '_context' of 'Handle' objects>
1378:  └ <Handle Task.task_wakeup()>
1379:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/anyio/from_thread.py", line 221, in _call_func
1380:  retval = await retval_or_awaitable
1381:  └ <coroutine object FastAPI.__call__ at 0x7f5666473c40>
1382:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/fastapi/applications.py", line 1054, in __call__
1383:  await super().__call__(scope, receive, send)
1384:  │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f5665ef3ec0>
1385:  │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665ef2ac0>
1386:  └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1387:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/applications.py", line 112, in __call__
1388:  await self.middleware_stack(scope, receive, send)
1389:  │    │                │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f5665ef3ec0>
1390:  │    │                │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665ef2ac0>
1391:  │    │                └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1392:  │    └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1393:  └ <fastapi.applications.FastAPI object at 0x7f566eedfcb0>
1394:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 165, in __call__
1395:  await self.app(scope, receive, _send)
1396:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665ef1620>
1397:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665ef2ac0>
1398:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1399:  │    └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1400:  └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1401:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/cors.py", line 85, in __call__
1402:  await self.app(scope, receive, send)
1403:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665ef1620>
1404:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665ef2ac0>
1405:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1406:  │    └ <starlette.middleware.exceptions.ExceptionMiddleware object at 0x7f56666134d0>
1407:  └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1408:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
1409:  await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
1410:  │                            │    │    │     │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f5665ef1620>
1411:  │                            │    │    │     │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f5665ef2ac0>
...

1496:  �[32m2025-08-05 12:55:55.001�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1497:  �[32m2025-08-05 12:55:55.001�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1498:  �[32m2025-08-05 12:55:55.001�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1499:  �[32m2025-08-05 12:55:55.001�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1500:  �[32m2025-08-05 12:55:55.003�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m122�[0m | unoplat-code-confluence | Session transaction finished, changes will be committed on context exit
1501:  �[32m2025-08-05 12:55:55.004�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1502:  �[32m2025-08-05 12:55:55.005�[0m | �[1mINFO    �[0m | �[36mtests.parser.package_manager.detectors.test_detect_codebases_sse�[0m:�[36mtest_full_sse_flow_with_token_ingestion�[0m:�[36m212�[0m | unoplat-code-confluence | Step 3: Testing SSE endpoint with real detection
1503:  �[32m2025-08-05 12:55:55.007�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1504:  �[32m2025-08-05 12:55:55.007�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1505:  �[32m2025-08-05 12:55:55.007�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1506:  �[32m2025-08-05 12:55:55.007�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1507:  �[32m2025-08-05 12:55:55.007�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1508:  �[32m2025-08-05 12:55:55.009�[0m | �[1mINFO    �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mdetect_codebases_sse�[0m:�[36m531�[0m | unoplat-code-confluence | Remote repository detection - URL: https://github.com/unoplat/unoplat-code-confluence
1509:  �[32m2025-08-05 12:55:55.009�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m122�[0m | unoplat-code-confluence | Session transaction finished, changes will be committed on context exit
1510:  �[32m2025-08-05 12:55:55.010�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1511:  �[32m2025-08-05 12:55:55.011�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mgenerate_sse_events�[0m:�[36m489�[0m | unoplat-code-confluence | Detection error: ripgrep (rg) not found. Please install ripgrep.
1512:  �[32m2025-08-05 12:55:55.012�[0m | �[1mINFO    �[0m | �[36mtests.parser.package_manager.detectors.test_detect_codebases_sse�[0m:�[36mtest_full_sse_flow_with_token_ingestion�[0m:�[36m230�[0m | unoplat-code-confluence | Received 7 SSE events
...

1543:  temporal_address = f"localhost:{service_ports['temporal']}"
1544:  # ------------------------------------------------------------------
1545:  # 1️⃣  Ensure token is ingested (idempotent)
1546:  # ------------------------------------------------------------------
1547:  token_resp = test_client.post(
1548:  "/ingest-token",
1549:  headers={"Authorization": f"***"},
1550:  )
1551:  assert token_resp.status_code in (201, 409), token_resp.text
1552:  # ------------------------------------------------------------------
1553:  # 2️⃣  Get local repository path and detect codebases
1554:  # ------------------------------------------------------------------
1555:  local_repo_path: str = get_repository_path()
1556:  detection_result: DetectionResult = detect_local_codebases(test_client, local_repo_path)
1557:  # Validate detection succeeded
1558:  >       assert detection_result.error is None, f"Detection failed: {detection_result.error}"
1559:  E       AssertionError: Detection failed: ripgrep (rg) not found. Please install ripgrep.
1560:  E       assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1561:  E        +  where 'ripgrep (rg) not found. Please install ripgrep.' = DetectionResult(repository_url='/home/runner/.unoplat/repositories/unoplat-code-confluence', duration_seconds=0.0007603168487548828, codebases=[], error='ripgrep (rg) not found. Please install ripgrep.').error
1562:  tests/integration/test_delete_repository.py:411: AssertionError
1563:  ----------------------------- Captured stdout call -----------------------------
1564:  �[32m2025-08-05 12:56:00.094�[0m | �[34m�[1mDEBUG   �[0m | �[36mtests.utils.sync_db_cleanup�[0m:�[36mcleanup_postgresql_sync�[0m:�[36m45�[0m | unoplat-code-confluence | PostgreSQL repository data cleared successfully
1565:  �[32m2025-08-05 12:56:00.103�[0m | �[34m�[1mDEBUG   �[0m | �[36mtests.utils.sync_db_cleanup�[0m:�[36mcleanup_neo4j_sync�[0m:�[36m22�[0m | unoplat-code-confluence | Neo4j database cleared successfully
1566:  �[32m2025-08-05 12:56:00.105�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1567:  �[32m2025-08-05 12:56:00.105�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1568:  �[32m2025-08-05 12:56:00.105�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1569:  �[32m2025-08-05 12:56:00.106�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1570:  �[32m2025-08-05 12:56:00.106�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1571:  �[32m2025-08-05 12:56:00.109�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m125�[0m | unoplat-code-confluence | Encountered error inside DB session context: {exc}
1572:  �[33m�[1mTraceback (most recent call last):�[0m
...

1629:  │    └ <member '_context' of 'Handle' objects>
1630:  └ <Handle Task.task_wakeup()>
1631:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/anyio/from_thread.py", line 221, in _call_func
1632:  retval = await retval_or_awaitable
1633:  └ <coroutine object FastAPI.__call__ at 0x7f5666408b80>
1634:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/fastapi/applications.py", line 1054, in __call__
1635:  await super().__call__(scope, receive, send)
1636:  │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f564d7a9760>
1637:  │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f564d7a99e0>
1638:  └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1639:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/applications.py", line 112, in __call__
1640:  await self.middleware_stack(scope, receive, send)
1641:  │    │                │      │        └ <function _TestClientTransport.handle_request.<locals>.send at 0x7f564d7a9760>
1642:  │    │                │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f564d7a99e0>
1643:  │    │                └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1644:  │    └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1645:  └ <fastapi.applications.FastAPI object at 0x7f566eedfcb0>
1646:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 165, in __call__
1647:  await self.app(scope, receive, _send)
1648:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f564d7a85e0>
1649:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f564d7a99e0>
1650:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1651:  │    └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1652:  └ <starlette.middleware.errors.ServerErrorMiddleware object at 0x7f5666613770>
1653:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/cors.py", line 85, in __call__
1654:  await self.app(scope, receive, send)
1655:  │    │   │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f564d7a85e0>
1656:  │    │   │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f564d7a99e0>
1657:  │    │   └ {'type': 'http', 'http_version': '1.1', 'method': 'POST', 'path': '/ingest-token', 'raw_path': b'/ingest-token', 'root_path':...
1658:  │    └ <starlette.middleware.exceptions.ExceptionMiddleware object at 0x7f56666134d0>
1659:  └ <starlette.middleware.cors.CORSMiddleware object at 0x7f5666613620>
1660:  File "/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
1661:  await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
1662:  │                            │    │    │     │      │        └ <function ServerErrorMiddleware.__call__.<locals>._send at 0x7f564d7a85e0>
1663:  │                            │    │    │     │      └ <function _TestClientTransport.handle_request.<locals>.receive at 0x7f564d7a99e0>
...

1739:  File "�[32m/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/�[0m�[32m�[1mmain.py�[0m", line �[33m767�[0m, in �[35mingest_token�[0m
1740:  �[35m�[1mraise�[0m �[1mhttp_ex�[0m
1741:  File "�[32m/home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/src/code_confluence_flow_bridge/�[0m�[32m�[1mmain.py�[0m", line �[33m741�[0m, in �[35mingest_token�[0m
1742:  �[35m�[1mraise�[0m �[1mHTTPException�[0m�[1m(�[0m
1743:  �[36m      └ �[0m�[36m�[1m<class 'fastapi.exceptions.HTTPException'>�[0m
1744:  �[31m�[1mfastapi.exceptions.HTTPException�[0m:�[1m 409: Token already ingested. Use update-token to update it.�[0m
1745:  �[32m2025-08-05 12:56:00.115�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1746:  �[32m2025-08-05 12:56:00.120�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m104�[0m | unoplat-code-confluence | Creating new DB session (task={task}, loop_id={loop_id})
1747:  �[32m2025-08-05 12:56:00.120�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m54�[0m | unoplat-code-confluence | Attempting to retrieve AsyncEngine for loop {loop_id}
1748:  �[32m2025-08-05 12:56:00.120�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_engine_for_loop�[0m:�[36m80�[0m | unoplat-code-confluence | Reusing cached AsyncEngine for loop {loop_id}
1749:  �[32m2025-08-05 12:56:00.120�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m117�[0m | unoplat-code-confluence | Scoped session created; beginning transactional context
1750:  �[32m2025-08-05 12:56:00.120�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m120�[0m | unoplat-code-confluence | Session transaction started
1751:  �[32m2025-08-05 12:56:00.121�[0m | �[1mINFO    �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mdetect_codebases_sse�[0m:�[36m521�[0m | unoplat-code-confluence | Local repository detection - folder: unoplat-code-confluence, resolved path: /home/runner/.unoplat/repositories/unoplat-code-confluence, environment: development
1752:  �[32m2025-08-05 12:56:00.121�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m122�[0m | unoplat-code-confluence | Session transaction finished, changes will be committed on context exit
1753:  �[32m2025-08-05 12:56:00.121�[0m | �[34m�[1mDEBUG   �[0m | �[36msrc.code_confluence_flow_bridge.processor.db.postgres.db�[0m:�[36mget_session�[0m:�[36m131�[0m | unoplat-code-confluence | Scoped session removed from registry (session cleanup complete)
1754:  �[32m2025-08-05 12:56:00.122�[0m | �[31m�[1mERROR   �[0m | �[36msrc.code_confluence_flow_bridge.main�[0m:�[36mgenerate_sse_events�[0m:�[36m489�[0m | unoplat-code-confluence | Detection error: ripgrep (rg) not found. Please install ripgrep.
1755:  --------------------------- Captured stdout teardown ---------------------------
...

1787:  Container temporal-elasticsearch-test  Removed
1788:  Container neo4j-test  Stopped
1789:  Container neo4j-test  Removing
1790:  Container neo4j-test  Removed
1791:  Container code-confluence-postgresql-test  Stopped
1792:  Container code-confluence-postgresql-test  Removing
1793:  Container code-confluence-postgresql-test  Removed
1794:  Volume code-confluence-flow-bridge_postgresql_data  Removing
1795:  Volume code-confluence-flow-bridge_elasticsearch_data  Removing
1796:  Network code-confluence-test-network  Removing
1797:  Volume code-confluence-flow-bridge_postgresql_data  Removed
1798:  Volume code-confluence-flow-bridge_elasticsearch_data  Removed
1799:  Network code-confluence-test-network  Removed
1800:  =============================== warnings summary ===============================
1801:  .venv/lib/python3.13/site-packages/sqlmodel/main.py:636
1802:  /home/runner/work/unoplat-code-confluence/unoplat-code-confluence/unoplat-code-confluence-ingestion/code-confluence-flow-bridge/.venv/lib/python3.13/site-packages/sqlmodel/main.py:636: SAWarning: Setting passive_deletes on relationship() while also setting viewonly=True does not make sense, as a viewonly=True relationship does not perform persistence operations. This configuration may raise an error in a future release.
1803:  rel_value = relationship(relationship_to, *rel_args, **rel_kwargs)
...

1930:  TOTAL                                                                                                        5555   2033    63%
1931:  Coverage HTML written to dir coverage_reports
1932:  Coverage XML written to file coverage.xml
1933:  ============================= slowest 10 durations =============================
1934:  54.83s setup    tests/integration/test_framework_definitions_ingestion.py::TestFrameworkDefinitionsIngestion::test_schema_creation_and_structure
1935:  12.24s teardown tests/integration/test_delete_repository.py::TestDeleteRepositoryEndpoint::test_delete_local_repository_flow
1936:  10.44s call     tests/integration/test_start_ingestion.py::TestStartIngestionEndpoint::test_start_ingestion_flow
1937:  3.29s call     tests/confluence_git/test_github_helper.py::TestGithubHelper::test_clone_repository
1938:  2.42s call     tests/parser/package_manager/detectors/test_detect_codebases_sse.py::TestDetectCodebasesSSEIntegration::test_concurrent_sse_requests
1939:  1.16s call     tests/parser/test_generic_codebase_parser.py::TestGenericCodebaseParserIntegration::test_parser_inserts_nodes
1940:  1.00s call     tests/confluence_git/test_github_helper.py::TestGithubHelper::test_clone_nested_repository
1941:  0.35s call     tests/parser/package_manager/detectors/test_detect_codebases_sse.py::TestDetectCodebasesSSEIntegration::test_sse_with_invalid_git_url
1942:  0.19s call     tests/parser/package_manager/test_poetry_strategy.py::test_process_metadata_all_required_sections
1943:  0.15s call     tests/integration/test_framework_detection_with_postgres.py::TestFrameworkDetectionWithPostgres::test_detect_fastapi_endpoints_main_py
1944:  =========================== short test summary info ============================
1945:  FAILED tests/integration/test_start_ingestion.py::TestStartIngestionEndpoint::test_complete_detection_and_ingestion_flow - AssertionError: Detection failed: ripgrep (rg) not found. Please install ripgrep.
1946:  assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1947:  +  where 'ripgrep (rg) not found. Please install ripgrep.' = DetectionResult(repository_url='/home/runner/.unoplat/repositories/unoplat-code-confluence', duration_seconds=0.0010848045349121094, codebases=[], error='ripgrep (rg) not found. Please install ripgrep.').error
1948:  FAILED tests/parser/package_manager/detectors/test_detect_codebases_sse.py::TestDetectCodebasesSSEIntegration::test_full_sse_flow_with_token_ingestion - AssertionError: assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1949:  FAILED tests/integration/test_delete_repository.py::TestDeleteRepositoryEndpoint::test_delete_local_repository_flow - AssertionError: Detection failed: ripgrep (rg) not found. Please install ripgrep.
1950:  assert 'ripgrep (rg) not found. Please install ripgrep.' is None
1951:  +  where 'ripgrep (rg) not found. Please install ripgrep.' = DetectionResult(repository_url='/home/runner/.unoplat/repositories/unoplat-code-confluence', duration_seconds=0.0007603168487548828, codebases=[], error='ripgrep (rg) not found. Please install ripgrep.').error
1952:  ============= 3 failed, 65 passed, 3 warnings in 91.50s (0:01:31) ==============
1953:  ##[error]Process completed with exit code 1.
1954:  Post job cleanup.

JayGhiya added a commit that referenced this pull request Apr 8, 2026
…factor

fix: deletion fixes, codebase detection perf improvements and misc refactoring
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant