Skip to content

observability as a whole#463

Open
priyanshi-2003 wants to merge 1 commit intojuspay:releasefrom
priyanshi-2003:observability-as-a-whole
Open

observability as a whole#463
priyanshi-2003 wants to merge 1 commit intojuspay:releasefrom
priyanshi-2003:observability-as-a-whole

Conversation

@priyanshi-2003
Copy link
Contributor

@priyanshi-2003 priyanshi-2003 commented Jan 2, 2026

  • observability as a whole

Summary by CodeRabbit

  • New Features

    • Added analytics endpoint to view Langfuse evaluation scores with optional filtering by date range and merchant.
  • Bug Fixes

    • Resolved duplicate endpoint declarations.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 2, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces a new API endpoint and supporting database layers for retrieving Langfuse score analytics filtered by merchant ID and optional date ranges. The feature spans API routing, database accessors, and query builders with critical duplicate declarations across multiple files.

Changes

Cohort / File(s) Summary
API Layer
app/api/routers/breeze_buddy/deprecated/dashboard.py
Added get_langfuse_scores_analytics endpoint (GET /breeze/langfuse-scores) that parses ISO-8601 dates, accepts optional merchant_id, converts to UTC, calls accessor, and returns evaluator metrics with summary and filters. ⚠️ Endpoint declared twice identically.
Database Accessor Layer
app/database/accessor/__init__.py
Exports get_langfuse_scores_by_merchant from public API.
Database Accessor Implementation
app/database/accessor/breeze_buddy/lead_call_tracker.py
New function get_langfuse_scores_by_merchant that executes query, maps results to dicts containing evaluator, total\_evaluated, passed, failed, and pass\_rate\_percent. Includes error handling and logging.
Query Builder Layer
app/database/queries/breeze_buddy/lead_call_tracker.py
New function get_langfuse_scores_by_merchant_query that builds parameterized SQL with optional merchant_id and date range filters, using a WITH clause to compute per-evaluator aggregates. ⚠️ Function defined twice identically.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • badri-singhal

Poem

🐰 Scores are flowing, metrics bright,
Through layers deep, from dark to light,
But wait—I see duplicates dance,
Two endpoints, queries in romance!
Remove the twins, let logic reign,
One truth to rule them all again!

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'observability as a whole' is vague and generic, using non-descriptive terms that don't convey the specific changes made in the pull request. Replace with a specific title that clearly describes the main change, such as 'Add Langfuse scores analytics endpoint' or 'Implement get_langfuse_scores_by_merchant function'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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.

@priyanshi-2003 priyanshi-2003 force-pushed the observability-as-a-whole branch from ea048ef to beab3e7 Compare January 2, 2026 14:12
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: 3

Caution

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

⚠️ Outside diff range comments (1)
app/api/routers/breeze_buddy/merchants/__init__.py (1)

16-39: Critical: Authentication removed from admin-only endpoint.

The authentication dependency has been completely removed from this route, matching the bypass in the handler. The docstring is now inconsistent with the implementation:

  • Claims "Admin-only endpoint" but has no auth
  • Documents "403: If user is not admin" but this error can never be raised

This should be addressed together with the handler changes.

🔎 Recommended fix
-from fastapi import APIRouter
+from fastapi import APIRouter, Depends
+
+from app.core.security.rbac import get_current_user_with_rbac
+from app.schemas import UserInfo
 
 from app.schemas.breeze_buddy.merchants import MerchantsResponse
 
 from .handlers import list_merchants_handler
 
 router = APIRouter()
 
 
 @router.get("/merchants", response_model=MerchantsResponse)
 async def list_merchants(
-    # TODO: Re-enable auth after testing
-    # current_user: UserInfo = Depends(get_current_user_with_rbac),
+    current_user: UserInfo = Depends(get_current_user_with_rbac),
 ):
     ...
-    # TODO: Re-enable auth after testing
-    return await list_merchants_handler(None)
+    return await list_merchants_handler(current_user)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22b3d04 and ea048ef.

📒 Files selected for processing (7)
  • app/api/routers/breeze_buddy/deprecated/dashboard.py
  • app/api/routers/breeze_buddy/merchants/__init__.py
  • app/api/routers/breeze_buddy/merchants/handlers.py
  • app/database/__init__.py
  • app/database/accessor/__init__.py
  • app/database/accessor/breeze_buddy/lead_call_tracker.py
  • app/database/queries/breeze_buddy/lead_call_tracker.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T12:11:37.686Z
Learnt from: swaroopvarma1
Repo: juspay/clairvoyance PR: 447
File: app/database/queries/breeze_buddy/call_execution_config.py:268-285
Timestamp: 2025-12-23T12:11:37.686Z
Learning: Guideline: In Breeze Buddy, treat shop_identifier as identifying individual merchant locations, while merchant_id acts as a parent/group identifier. Therefore, functions that retrieve shop_identifiers should be named as 'merchants' functions (e.g., get_merchants_, list_merchants_). Apply this naming consistently across all Breeze Buddy query modules and related tests. This pattern should apply to all Python files under app/database/queries/breeze_buddy/ (and similar modules following the same domain naming) to maintain consistency across the codebase.

Applied to files:

  • app/database/queries/breeze_buddy/lead_call_tracker.py
🧬 Code graph analysis (5)
app/database/accessor/__init__.py (1)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • get_langfuse_scores_by_merchant (459-505)
app/api/routers/breeze_buddy/deprecated/dashboard.py (1)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • get_langfuse_scores_by_merchant (459-505)
app/api/routers/breeze_buddy/merchants/__init__.py (1)
app/api/routers/breeze_buddy/merchants/handlers.py (1)
  • list_merchants_handler (13-53)
app/api/routers/breeze_buddy/merchants/handlers.py (1)
app/database/accessor/breeze_buddy/call_execution_config.py (1)
  • get_all_merchants (304-331)
app/database/accessor/breeze_buddy/lead_call_tracker.py (2)
app/database/queries/breeze_buddy/lead_call_tracker.py (1)
  • get_langfuse_scores_by_merchant_query (435-487)
app/database/queries/__init__.py (1)
  • run_parameterized_query (14-32)
🪛 Ruff (0.14.10)
app/api/routers/breeze_buddy/deprecated/dashboard.py

354-354: Use explicit conversion flag

Replace with conversion flag

(RUF010)

app/database/accessor/breeze_buddy/lead_call_tracker.py

502-502: Consider moving this statement to an else block

(TRY300)


503-503: Do not catch blind exception: Exception

(BLE001)

app/database/queries/breeze_buddy/lead_call_tracker.py

468-486: Possible SQL injection vector through string-based query construction

(S608)

🔇 Additional comments (5)
app/database/queries/breeze_buddy/lead_call_tracker.py (1)

435-487: LGTM - Query function is correctly parameterized.

The static analysis SQL injection warning (S608) is a false positive here. All user-provided values (merchant_id, start_date, end_date) are properly bound via parameterized placeholders ($1, $2, etc.), and no user input is directly interpolated into the SQL string. The dynamic WHERE clause construction only uses hardcoded column names with parameter placeholders.

The aggregation logic correctly handles edge cases with NULLIF(COUNT(*), 0) to prevent division by zero.

app/database/__init__.py (1)

46-48: Fallback logic is reasonable for development, but verify production behavior.

The fallback to the original password when KMS decryption fails is sensible for local development. However, ensure that in production environments, KMS decryption failures are monitored/alerted on, as silently falling back could mask configuration issues or indicate a security degradation.

app/database/accessor/__init__.py (1)

19-19: LGTM!

The new get_langfuse_scores_by_merchant function is correctly imported and exported, following the established pattern in this module.

Also applies to: 76-76

app/database/accessor/breeze_buddy/lead_call_tracker.py (2)

459-505: LGTM - New accessor function follows established patterns.

The implementation is consistent with other accessor functions in this file:

  • Proper logging at entry
  • Parameterized query usage
  • Exception handling with logging
  • Safe handling of None values in pass_rate_percent conversion

The static analysis hints (TRY300, BLE001) apply equally to other functions in this file. If you want to address them, it would be better done as a broader refactor across the module.


16-16: Import addition is correct.

The new query function import aligns with the new accessor function added below.

Comment on lines +289 to +296
@router.get("/breeze/langfuse-scores")
async def get_langfuse_scores_analytics(
start_date: Optional[str] = None,
end_date: Optional[str] = None,
merchant_id: Optional[str] = None,
# TODO: Re-enable auth after testing
# session: dict = Depends(get_breeze_buddy_session),
):
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Authentication is disabled on a new analytics endpoint.

This new endpoint exposes Langfuse analytics data without any authentication. The commented-out session dependency and auth check should not be merged to the release branch in this state.

🔎 Recommended fix
 @router.get("/breeze/langfuse-scores")
 async def get_langfuse_scores_analytics(
     start_date: Optional[str] = None,
     end_date: Optional[str] = None,
     merchant_id: Optional[str] = None,
-    # TODO: Re-enable auth after testing
-    # session: dict = Depends(get_breeze_buddy_session),
+    session: dict = Depends(get_breeze_buddy_session),
 ):
     ...
-    # TODO: Re-enable auth after testing
-    # if not session:
-    #     raise HTTPException(status_code=401, detail="Not authenticated")
+    if not session:
+        raise HTTPException(status_code=401, detail="Not authenticated")

Also applies to: 333-335

🤖 Prompt for AI Agents
In app/api/routers/breeze_buddy/deprecated/dashboard.py around lines 289-296
(and also lines 333-335), the new Langfuse analytics endpoints have
authentication disabled; restore the commented-out session dependency and
enforce auth: add the parameter session: dict =
Depends(get_breeze_buddy_session) to the endpoint signature, validate the
session (or required permissions) at the start of the handler and raise an
HTTPException(401/403) on failure, and remove any temporary bypasses so the
endpoint only returns data for authenticated/authorized users; run/update
related tests to cover auth behavior.

Comment on lines +373 to +374
# Calculate summary
total_calls = max([s["total_evaluated"] for s in scores_data], default=0)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Incorrect logic for total_calls_evaluated calculation.

Using max() on total_evaluated across evaluators assumes that all evaluators are applied to the same set of calls. If different evaluators are applied to different subsets of calls, this metric would be misleading.

Consider clarifying the semantic meaning or using a more accurate calculation:

🔎 Alternative approaches

Option 1 - If you want the maximum evaluations by any single evaluator:

# Current (keep as-is but rename for clarity)
max_evaluations = max([s["total_evaluated"] for s in scores_data], default=0)

Option 2 - If you want total unique calls evaluated (requires query change):

# Would need a separate query to count DISTINCT call_ids where langfuse_scores IS NOT NULL

Option 3 - Sum of all evaluations:

total_evaluations = sum(s["total_evaluated"] for s in scores_data)
🤖 Prompt for AI Agents
In app/api/routers/breeze_buddy/deprecated/dashboard.py around lines 373-374,
the calculation using max([s["total_evaluated"] for s in scores_data],
default=0) is misleading if evaluators cover different call subsets; either (A)
if you intended the maximum evaluations by a single evaluator, rename the
variable to max_evaluations and keep the max logic, (B) if you intended the
total number of evaluations across all evaluators, replace with a sum of
s["total_evaluated"], or (C) if you intended the number of unique calls
evaluated, change the data source/query to return COUNT(DISTINCT call_id) where
scores exist and use that value here; update the variable name and any
downstream usage to match the chosen semantics.

Comment on lines +29 to +44
# TODO: Re-enable auth after testing
# Validate admin access
require_admin_access(current_user, "list merchants")
# require_admin_access(current_user, "list merchants")

logger.info(f"Admin user {current_user.username} requesting merchants list")
# logger.info(f"Admin user {current_user.username} requesting merchants list")
logger.info("Requesting merchants list (auth bypassed for testing)")

try:
# Get all unique merchants from database
merchants = await get_all_merchants()

logger.info(
f"Returning {len(merchants)} merchants to admin {current_user.username}"
)
# TODO: Re-enable auth after testing
# logger.info(
# f"Returning {len(merchants)} merchants to admin {current_user.username}"
# )
logger.info(f"Returning {len(merchants)} merchants (auth bypassed)")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Authentication is disabled on an admin-only endpoint.

Disabling authentication on an endpoint that exposes merchant data is a significant security risk. Even for testing purposes, this should not be merged to the release branch with auth bypassed.

Issues:

  1. The require_admin_access call is commented out, allowing unauthenticated access
  2. The function signature claims current_user: UserInfo but accepts None
  3. The docstring still states "Admin-only endpoint" and "must be admin", which is now misleading
🔎 Recommended approach

Consider one of these alternatives:

  1. Use feature flags: Enable auth bypass only via environment variable in non-production environments
  2. Separate test routes: Create a distinct test router that's excluded from production builds
  3. Re-enable auth before merge: If this is truly for testing, create a separate testing branch
+import os
+
+TESTING_MODE = os.getenv("TESTING_MODE", "false").lower() == "true"
+
 async def list_merchants_handler(current_user: UserInfo) -> MerchantsResponse:
-    # TODO: Re-enable auth after testing
-    # Validate admin access
-    # require_admin_access(current_user, "list merchants")
+    # Only bypass auth in explicit testing mode
+    if not TESTING_MODE:
+        require_admin_access(current_user, "list merchants")

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In app/api/routers/breeze_buddy/merchants/handlers.py around lines 29 to 44,
authentication has been bypassed for testing: the require_admin_access call is
commented out, logger messages note "auth bypassed", and the function accepts a
current_user annotated as UserInfo but may be None while the docstring still
claims "Admin-only endpoint". Restore secure behavior by re-enabling
require_admin_access for production code (uncomment the call), ensure
current_user is validated and typed as non-Optional UserInfo (or add a runtime
check that returns 401/403 if missing), update or remove "auth bypassed" log
lines, and change the docstring to accurately reflect that this is an admin-only
endpoint; if you must support testing bypass, gate it behind a clear
non-production feature flag or a separate test-only route so no auth bypass
reaches release branches.

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: 2

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22b3d04 and beab3e7.

📒 Files selected for processing (4)
  • app/api/routers/breeze_buddy/deprecated/dashboard.py
  • app/database/accessor/__init__.py
  • app/database/accessor/breeze_buddy/lead_call_tracker.py
  • app/database/queries/breeze_buddy/lead_call_tracker.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-23T12:11:37.686Z
Learnt from: swaroopvarma1
Repo: juspay/clairvoyance PR: 447
File: app/database/queries/breeze_buddy/call_execution_config.py:268-285
Timestamp: 2025-12-23T12:11:37.686Z
Learning: Guideline: In Breeze Buddy, treat shop_identifier as identifying individual merchant locations, while merchant_id acts as a parent/group identifier. Therefore, functions that retrieve shop_identifiers should be named as 'merchants' functions (e.g., get_merchants_, list_merchants_). Apply this naming consistently across all Breeze Buddy query modules and related tests. This pattern should apply to all Python files under app/database/queries/breeze_buddy/ (and similar modules following the same domain naming) to maintain consistency across the codebase.

Applied to files:

  • app/database/queries/breeze_buddy/lead_call_tracker.py
🧬 Code graph analysis (2)
app/database/accessor/__init__.py (1)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • get_langfuse_scores_by_merchant (459-505)
app/api/routers/breeze_buddy/deprecated/dashboard.py (1)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • get_langfuse_scores_by_merchant (459-505)
🪛 Ruff (0.14.10)
app/database/accessor/breeze_buddy/lead_call_tracker.py

502-502: Consider moving this statement to an else block

(TRY300)


503-503: Do not catch blind exception: Exception

(BLE001)

app/database/queries/breeze_buddy/lead_call_tracker.py

468-486: Possible SQL injection vector through string-based query construction

(S608)

app/api/routers/breeze_buddy/deprecated/dashboard.py

354-354: Use explicit conversion flag

Replace with conversion flag

(RUF010)

🔇 Additional comments (4)
app/database/accessor/__init__.py (1)

19-19: LGTM!

The new get_langfuse_scores_by_merchant function is properly imported and exported in the public interface.

Also applies to: 76-76

app/database/accessor/breeze_buddy/lead_call_tracker.py (1)

459-505: LGTM!

The new accessor function follows the established patterns in this module:

  • Logging input parameters
  • Delegating to the query builder
  • Mapping results to a well-defined dict structure
  • Consistent error handling with graceful fallback to empty list
app/database/queries/breeze_buddy/lead_call_tracker.py (1)

435-487: LGTM!

The query function is well-structured:

  • Uses parameterized queries ($1, $2, etc.) to prevent SQL injection (the static analysis S608 warning is a false positive since table names are constants)
  • The CTE correctly flattens the JSONB array of scores
  • Aggregation logic for pass/fail counts and percentages is correct
app/api/routers/breeze_buddy/deprecated/dashboard.py (1)

373-374: Verify the total_calls_evaluated calculation logic.

Using max() assumes all evaluators are applied to the same set of calls. If evaluators can be applied to different subsets of calls, this would be misleading. Consider whether total_calls_evaluated should represent the count of unique calls evaluated (distinct call_ids) rather than the maximum evaluator count.

Comment on lines +289 to +296
@router.get("/breeze/langfuse-scores")
async def get_langfuse_scores_analytics(
start_date: Optional[str] = None,
end_date: Optional[str] = None,
merchant_id: Optional[str] = None,
# TODO: Re-enable auth after testing
# session: dict = Depends(get_breeze_buddy_session),
):
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Authentication is disabled on this endpoint.

The endpoint lacks authentication (get_breeze_buddy_session dependency is commented out). This exposes potentially sensitive Langfuse score analytics data without any access control. Other endpoints in this file require authentication (lines 27, 173).

This should not be merged to the release branch without re-enabling authentication.

🔎 Proposed fix to re-enable authentication
 @router.get("/breeze/langfuse-scores")
 async def get_langfuse_scores_analytics(
     start_date: Optional[str] = None,
     end_date: Optional[str] = None,
     merchant_id: Optional[str] = None,
-    # TODO: Re-enable auth after testing
-    # session: dict = Depends(get_breeze_buddy_session),
+    session: dict = Depends(get_breeze_buddy_session),
 ):

And uncomment the session check at lines 333-335:

-    # TODO: Re-enable auth after testing
-    # if not session:
-    #     raise HTTPException(status_code=401, detail="Not authenticated")
+    if not session:
+        raise HTTPException(status_code=401, detail="Not authenticated")
🤖 Prompt for AI Agents
In app/api/routers/breeze_buddy/deprecated/dashboard.py around lines 289-296,
the get_langfuse_scores_analytics endpoint has authentication disabled (the
get_breeze_buddy_session dependency is commented out), exposing sensitive
analytics; re-enable auth by uncommenting and restoring the session dependency
in the function signature (add session: dict =
Depends(get_breeze_buddy_session)), and also uncomment and enforce the session
check at lines 333-335 so the endpoint aborts with proper error/redirect when
the session is missing or unauthorized; ensure imports and typing remain correct
and run tests/lint.

Comment on lines +300 to +303
Query Parameters:
- start_date: Start date in ISO format (YYYY-MM-DD) - Required
- end_date: End date in ISO format (YYYY-MM-DD) - Required
- merchant_id: Optional merchant ID to filter by
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Docstring states dates are "Required" but parameters are Optional.

The docstring on lines 301-302 claims start_date and end_date are "Required", but the function signature declares them as Optional[str] = None. Either enforce the requirement or fix the documentation.

🔎 Proposed fix (if dates should remain optional)
     Query Parameters:
-        - start_date: Start date in ISO format (YYYY-MM-DD) - Required
-        - end_date: End date in ISO format (YYYY-MM-DD) - Required
+        - start_date: Start date in ISO format (YYYY-MM-DD) - Optional
+        - end_date: End date in ISO format (YYYY-MM-DD) - Optional
         - merchant_id: Optional merchant ID to filter by
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Query Parameters:
- start_date: Start date in ISO format (YYYY-MM-DD) - Required
- end_date: End date in ISO format (YYYY-MM-DD) - Required
- merchant_id: Optional merchant ID to filter by
Query Parameters:
- start_date: Start date in ISO format (YYYY-MM-DD) - Optional
- end_date: End date in ISO format (YYYY-MM-DD) - Optional
- merchant_id: Optional merchant ID to filter by

@priyanshi-2003 priyanshi-2003 force-pushed the observability-as-a-whole branch 2 times, most recently from 128bb97 to cf65566 Compare January 8, 2026 11:28
)


@router.get("/langfuse-scores")
Copy link
Collaborator

Choose a reason for hiding this comment

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

analytics/evaluator-scores

@priyanshi-2003 priyanshi-2003 force-pushed the observability-as-a-whole branch 3 times, most recently from d81aa07 to 9848ff2 Compare January 12, 2026 15:04
@swaroopvarma1
Copy link
Collaborator

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jan 12, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@priyanshi-2003 priyanshi-2003 force-pushed the observability-as-a-whole branch 3 times, most recently from f605d8b to 1d6c251 Compare January 12, 2026 15:11
Comment on lines +650 to +652
from datetime import datetime, timedelta, timezone

from fastapi import HTTPException
Copy link
Contributor

Choose a reason for hiding this comment

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

move to top

@priyanshi-2003 priyanshi-2003 force-pushed the observability-as-a-whole branch from 1d6c251 to 0caf864 Compare January 13, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants