Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-15 Thread via GitHub


aminghadersohi closed pull request #38416: feat(mcp): add popularity_score 
computed field for charts, dashboards, datasets
URL: https://github.com/apache/superset/pull/38416


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-15 Thread via GitHub


aminghadersohi commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4252950430

   Closing — replacing with a new approach using a DB-backed popularity_weights 
table with SQL-join scoring instead of hardcoded Python-side computation. This 
addresses the logs table gap in Preset production.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4240012200

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3075904347


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,393 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+db.session.rollback()
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to sc

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3075889982


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,390 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for 

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3075891459


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,393 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+db.session.rollback()
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+  

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3075881781


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,393 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+db.session.rollback()
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to sc

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4239576919

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3075461650


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,390 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for 

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4239093149

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4238507519

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


Copilot commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3074538760


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -165,3 +212,87 @@ def _serialize_dashboard(
 return result.model_dump(
 mode="json", context={"select_columns": columns_to_filter}
 )
+
+
+def _list_dashboards_by_popularity(
+request: ListDashboardsRequest,
+dao_class: Any,
+serializer: Callable[..., dict[str, Any] | None],
+all_columns: list[str],
+ctx: Context,
+) -> DashboardList:
+"""Two-pass listing: sort all matching dashboards by popularity score."""
+from superset.mcp_service.common.schema_discovery import (
+DASHBOARD_SORTABLE_COLUMNS,
+)
+
+sorted_ids, scores, total_count = get_popularity_sorted_ids(
+compute_fn=compute_dashboard_popularity,
+dao_class=dao_class,
+filters=request.filters,
+search=request.search,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+order_direction=request.order_direction,
+)
+
+# Apply pagination to sorted IDs
+page = max(request.page - 1, 0)
+page_size = request.page_size
+start = page * page_size
+end = start + page_size
+
+# Fetch full models for page IDs
+if page_ids := sorted_ids[start:end]:
+items = dao_class.find_by_ids(page_ids)
+id_to_item = {item.id: item for item in items}
+ordered_items = [id_to_item[pid] for pid in page_ids if pid in 
id_to_item]
+else:
+ordered_items = []

Review Comment:
   Similar to charts: dashboards may serialize relationships like `owners`, 
`tags`, `roles`, and `slices` (`chart_count`/`charts`), which can lazy-load and 
produce N+1 queries when using the popularity two-pass path. Consider applying 
`query_options` (e.g., `subqueryload(Dashboard.owners)`, 
`subqueryload(Dashboard.tags)`, `subqueryload(Dashboard.roles)`, 
`subqueryload(Dashboard.slices)`) via the updated `find_by_ids` API.



##
superset/mcp_service/common/schema_discovery.py:
##
@@ -353,8 +361,9 @@ def get_columns_from_model(
 "schema",
 "changed_on",
 "created_on",
+"popularity_score",
 ]
-DATASET_SEARCH_COLUMNS = ["table_name", "description"]
+DATASET_SEARCH_COLUMNS = ["schema", "sql", "table_name", "uuid"]

Review Comment:
   This change removes `description` from dataset search columns (previously 
`['table_name', 'description']`). If this removal isn’t intentional, consider 
keeping `description` in the search column set for backwards compatibility and 
better discoverability (e.g., `['table_name', 'description', 'schema', 'sql', 
'uuid']`). If it is intentional, it would be helpful to reflect that in the PR 
description/tool docs since it changes search behavior.
   



##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -37,7 +41,14 @@
 ListChartsRequest,
 serialize_chart_object,
 )
+from superset.mcp_service.common.popularity import (
+attach_popularity_scores,
+compute_chart_popularity,
+get_popularity_sorted_ids,
+)
 from superset.mcp_service.mcp_core import ModelListCore
+from superset.mcp_service.system.schemas import PaginationInfo
+from superset.mcp_service.utils.schema_utils import parse_request

Review Comment:
   `parse_request` is imported but not referenced in the shown implementation. 
If it’s no longer needed, please remove it (and similarly in the other list 
tools where it was added) to keep module dependencies and lint noise down.
   



##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,390 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard 

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3074524234


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -165,3 +212,87 @@ def _serialize_dashboard(
 return result.model_dump(
 mode="json", context={"select_columns": columns_to_filter}
 )
+
+
+def _list_dashboards_by_popularity(
+request: ListDashboardsRequest,
+dao_class: Any,
+serializer: Callable[..., dict[str, Any] | None],
+all_columns: list[str],
+ctx: Context,
+) -> DashboardList:
+"""Two-pass listing: sort all matching dashboards by popularity score."""
+from superset.mcp_service.common.schema_discovery import (
+DASHBOARD_SORTABLE_COLUMNS,
+)
+
+sorted_ids, scores, total_count = get_popularity_sorted_ids(
+compute_fn=compute_dashboard_popularity,
+dao_class=dao_class,
+filters=request.filters,
+search=request.search,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+order_direction=request.order_direction,
+)
+
+# Apply pagination to sorted IDs
+page = max(request.page - 1, 0)
+page_size = request.page_size
+start = page * page_size
+end = start + page_size
+
+# Fetch full models for page IDs
+if page_ids := sorted_ids[start:end]:
+items = dao_class.find_by_ids(page_ids)

Review Comment:
   **Suggestion:** The popularity-sort branch loads dashboards by ID without 
eager-loading related collections, while serialization reads `slices`, 
`owners`, `tags`, and `roles` per dashboard. This creates N+1 queries that grow 
linearly with page size and can cause slow or timeout-prone responses. Add 
query options when calling `find_by_ids` to prefetch these relationships. 
[performance]
   
   
   Severity Level: Major ⚠️
   
   ```mdx
   - ⚠️ MCP `list_dashboards` popularity-sorted calls issue N+1 DB queries.
   - ⚠️ Popularity-sorted dashboard listings may slow under larger page sizes.
   ```
   
   
   ```suggestion
   from sqlalchemy.orm import subqueryload
   from superset.models.dashboard import Dashboard
   
   eager_options = [
   subqueryload(Dashboard.slices),
   subqueryload(Dashboard.owners),
   subqueryload(Dashboard.tags),
   subqueryload(Dashboard.roles),
   ]
   items = dao_class.find_by_ids(page_ids, query_options=eager_options)
   ```
   
   Steps of Reproduction ✅ 
   
   ```mdx
   1. Call the MCP `list_dashboards` tool (defined in
   `superset/mcp_service/dashboard/tool/list_dashboards.py:86-95`) with
   `order_column="popularity_score"` and a non‑trivial `page_size` (for example 
50). This
   causes the main `list_dashboards` function to route the request into
   `_list_dashboards_by_popularity` when `request.order_column == 
"popularity_score"` (lines
   136-141).
   
   2. Inside `_list_dashboards_by_popularity`
   (`superset/mcp_service/dashboard/tool/list_dashboards.py:217-224`), the 
helper computes
   `sorted_ids` and then applies pagination (`page`, `start`, `end`) at lines 
238-242. For
   the current page, it builds `page_ids = sorted_ids[start:end]` and executes 
`items =
   dao_class.find_by_ids(page_ids)` at line 246, which calls 
`BaseDAO.find_by_ids`
   (`superset/daos/base.py:11-29`) without any `query_options`, returning 
`Dashboard` ORM
   instances with relationships still lazily loaded.
   
   3. Still in `_list_dashboards_by_popularity`, the code iterates over the 
loaded dashboards
   and serializes each via `obj = serializer(item, select_columns)` at lines 
247-248. The
   `serializer` passed in from `list_dashboards` is `_serialize_dashboard` 
defined at lines
   125-129, which simply delegates to `serialize_dashboard_object(obj)` from
   `superset/mcp_service/dashboard/schemas.py:16-33`.
   
   4. In `serialize_dashboard_object` 
(`superset/mcp_service/dashboard/schemas.py:16-79`),
   the serializer accesses relationship attributes on each `Dashboard` 
instance: it computes
   `chart_count=len(getattr(dashboard, "slices", []))` (line 61), iterates 
`owners=[... for
   owner in getattr(dashboard, "owners", [])]` (lines 62-68), `tags=[... for 
tag in
   getattr(dashboard, "tags", [])]` (lines 69-74), and `roles=[... for role in
   getattr(dashboard, "roles", [])]` (lines 75-79). These attributes correspond 
to SQLAlchemy
   relationships defined in `superset/models/dashboard.py:15-31` and line 46, 
which use the
   default lazy loading strategy (`relationship(...)` without eager options). 
As a result,
   each access to `.slices`, `.owners`, `.tags`, and `.roles` on every 
dashboard returned by
   `find_by_ids` triggers separate SELECT queries per dashboard, on top of the 
initial
   `find_by_ids` query, producing an N+1 (1 main + ~4×N) query pattern that 
scales linearly
   with `page_size`. This is consistent with existing code that explicitly uses
   `subqueryl

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-04-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r3074522551


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,390 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table.
+
+Degrades gracefully when the logs table is empty (e.g. Preset production
+where events are routed to external systems) or inaccessible.
+"""
+try:
+view_counts = (
+db.session.query(id_column, 
sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm 
>= cutoff)
+.group_by(id_column)
+.all()
+)
+except sa.exc.SQLAlchemyError:
+logger.warning(
+"Failed to query logs table for view counts (action=%s). "
+"Scoring will proceed without view data.",
+action,
+exc_info=True,
+)
+return
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Nu

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-24 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4117261946

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-24 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2980541558


##
superset/mcp_service/dataset/tool/get_dataset_info.py:
##
@@ -117,6 +118,11 @@ async def get_dataset_info(
 result = tool.run_tool(request.identifier)
 
 if isinstance(result, DatasetInfo):
+# Compute popularity_score for single dataset retrieval
+if result.id is not None:
+scores = compute_dataset_popularity([result.id])
+result.popularity_score = scores.get(result.id, 0.0)

Review Comment:
   Fixed — popularity_score is now computed only when select_columns explicitly 
includes 'popularity_score' or when select_columns is empty (return 
everything). A new select_columns field on GetDatasetInfoRequest enables this 
opt-in behavior.



##
superset/mcp_service/dataset/tool/get_dataset_info.py:
##
@@ -117,6 +118,17 @@ async def get_dataset_info(
 result = tool.run_tool(request.identifier)
 
 if isinstance(result, DatasetInfo):
+# Compute popularity_score for single dataset retrieval
+# Isolated so a failure here doesn't prevent returning dataset info
+if result.id is not None:
+try:
+scores = compute_dataset_popularity([result.id])
+result.popularity_score = scores.get(result.id, 0.0)
+except (ValueError, TypeError, AttributeError) as e:
+await ctx.warning(
+"Failed to compute popularity score: %s" % (str(e),)
+)

Review Comment:
   Fixed — added SQLAlchemyError (from sqlalchemy.exc) to the except clause, so 
database errors during popularity computation are caught and logged as warnings 
rather than crashing the tool.



##
superset/mcp_service/dataset/tool/list_datasets.py:
##
@@ -124,32 +130,62 @@ def _serialize_dataset(
 """Serialize dataset (filtering via model_serializer)."""
 return serialize_dataset_object(obj)
 
-# Create tool with standard serialization
-tool = ModelListCore(
-dao_class=DatasetDAO,
-output_schema=DatasetInfo,
-item_serializer=_serialize_dataset,
-filter_type=DatasetFilter,
-default_columns=DEFAULT_DATASET_COLUMNS,
-search_columns=["schema", "sql", "table_name", "uuid"],
-list_field_name="datasets",
-output_list_schema=DatasetList,
-all_columns=all_columns,
-sortable_columns=DATASET_SORTABLE_COLUMNS,
-logger=logger,
+# Preserve original select_columns before any mutation for response 
filtering
+original_select_columns = (
+list(request.select_columns) if request.select_columns else None
 )
 
-with event_logger.log_context(action="mcp.list_datasets.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_datasets.popularity_sort"):
+result = _list_datasets_by_popularity(
+request, DatasetDAO, _serialize_dataset, all_columns, ctx
+)
+else:
+# Create tool with standard serialization
+list_core = ModelListCore(
+dao_class=DatasetDAO,
+output_schema=DatasetInfo,
+item_serializer=_serialize_dataset,
+filter_type=DatasetFilter,
+default_columns=DEFAULT_DATASET_COLUMNS,
+search_columns=DATASET_SEARCH_COLUMNS,
+list_field_name="datasets",
+output_list_schema=DatasetList,
+all_columns=all_columns,
+sortable_columns=DATASET_SORTABLE_COLUMNS,
+logger=logger,
 )
 
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != 
"popularity_score"]
+# Ensure id is loaded when popularity_score was requested
+# (scores are keyed by id)
+if (
+"popularity_score" in request.select_columns
+and "id" not in dao_columns
+):
+dao_columns = ["id"] + dao_columns
+
+with event_logger.log_context(action="mcp.list_datase

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-16 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4071370855

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-16 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2943419643


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -155,3 +196,85 @@ def _serialize_dashboard(
 return result.model_dump(
 mode="json", context={"select_columns": columns_to_filter}
 )
+
+
+def _list_dashboards_by_popularity(
+request: ListDashboardsRequest,
+dao_class: Any,
+serializer: Callable[..., dict[str, Any] | None],
+all_columns: list[str],
+ctx: Context,
+) -> DashboardList:
+"""Two-pass listing: sort all matching dashboards by popularity score."""
+from superset.mcp_service.common.schema_discovery import (
+DASHBOARD_SORTABLE_COLUMNS,
+)
+
+sorted_ids, scores, total_count = get_popularity_sorted_ids(
+compute_fn=compute_dashboard_popularity,
+dao_class=dao_class,
+filters=request.filters,
+search=request.search,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+order_direction=request.order_direction,
+)
+
+# Apply pagination to sorted IDs
+page = max(request.page - 1, 0)
+page_size = request.page_size
+start = page * page_size
+end = start + page_size
+
+# Fetch full models for page IDs
+if page_ids := sorted_ids[start:end]:
+items = dao_class.find_by_ids(page_ids)
+id_to_item = {item.id: item for item in items}
+ordered_items = [id_to_item[pid] for pid in page_ids if pid in 
id_to_item]
+else:
+ordered_items = []
+
+# Serialize - preserve the original request columns for response filtering
+columns_requested = request.select_columns or DEFAULT_DASHBOARD_COLUMNS
+# Include popularity_score in response when sorting by it, even if not
+# explicitly in select_columns (so clients can see the sort key)
+if "popularity_score" not in columns_requested:
+columns_requested = list(columns_requested) + ["popularity_score"]
+# Expand select_columns for internal loading (need popularity_score for
+# attach step)
+select_columns = list(columns_requested)
+
+dash_objs = []
+for item in ordered_items:
+obj = serializer(item, select_columns)
+if obj is not None:
+dash_objs.append(obj)
+
+attach_popularity_scores(dash_objs, scores)
+
+total_pages = (total_count + page_size - 1) // page_size if page_size > 0 
else 0
+pagination_info = PaginationInfo(
+page=page,
+page_size=page_size,
+total_count=total_count,
+total_pages=total_pages,
+has_next=page < total_pages - 1,
+has_previous=page > 0,
+)
+
+return DashboardList(
+dashboards=dash_objs,
+count=len(dash_objs),
+total_count=total_count,
+page=page,
+page_size=page_size,
+total_pages=total_pages,
+has_previous=page > 0,
+has_next=page < total_pages - 1,
+columns_requested=columns_requested,
+columns_loaded=select_columns,
+columns_available=all_columns,
+sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
+filters_applied=request.filters if isinstance(request.filters, list) 
else [],
+pagination=pagination_info,
+timestamp=datetime.now(timezone.utc),
+)

Review Comment:
   **Suggestion:** The popularity-sorted path returns pagination with a 0-based 
page index, while the normal listing path and request schema use 1-based pages. 
This causes inconsistent API behavior and breaks clients that rely on `page=1` 
for the first page. Convert the response page value in this branch to 1-based 
before building `PaginationInfo` and `DashboardList`. [off-by-one]
   
   
   Severity Level: Major ⚠️
   
   ```mdx
   - ⚠️ `list_dashboards` popularity sort returns wrong page numbering.
   - ❌ Clients mis-handle pagination boundaries on sorted dashboard results.
   ```
   
   
   ```suggestion
   total_pages = (total_count + page_size - 1) // page_size if page_size > 
0 else 0
   page_1based = page + 1
   pagination_info = PaginationInfo(
   page=page_1based,
   page_size=page_size,
   total_count=total_count,
   total_pages=total_pages,
   has_next=page < total_pages - 1,
   has_previous=page > 0,
   )
   
   return DashboardList(
   dashboards=dash_objs,
   count=len(dash_objs),
   total_count=total_count,
   page=page_1based,
   page_size=page_size,
   total_pages=total_pages,
   has_previous=page > 0,
   has_next=page < total_pages - 1,
   columns_requested=columns_requested,
   columns_loaded=select_columns,
   columns_available=all_columns,
   sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
   filters_applied=request.filters if isinstance(request.filters, list) 
else [],
   pagination=pagination_

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2933372228


##
superset/mcp_service/dataset/tool/list_datasets.py:
##
@@ -151,10 +194,11 @@ def _serialize_dataset(
 )
 )
 
-# Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or 
defaults)
-# This triggers DatasetInfo._filter_fields_by_context for each dataset
-columns_to_filter = result.columns_requested
+# Build response filtering from the original request columns when the
+# user explicitly specified select_columns (to avoid leaking internally
+# injected columns like 'id'). Fall back to result.columns_requested
+# (which holds DAO defaults) when no explicit columns were requested.
+columns_to_filter = original_select_columns or result.columns_requested

Review Comment:
   
   
   
   
   Logic Bug: Popularity Score Response Filtering
   
   
   When order_column is 'popularity_score' and it's not in the original 
select_columns, the current logic uses original_select_columns for filtering, 
which excludes popularity_score from the response. However, the code comment in 
_list_datasets_by_popularity indicates it should be included so clients can see 
the sort key. Change to: columns_to_filter = result.columns_requested if 
request.order_column == 'popularity_score' else original_select_columns or 
result.columns_requested
   
   
   
   
   
   Code suggestion
   
   Check the AI-generated fix before applying
   
   
   
   ```
--- a/superset/mcp_service/dataset/tool/list_datasets.py
+++ b/superset/mcp_service/dataset/tool/list_datasets.py
@@ -197,7 +197,7 @@
 # Build response filtering from the original request columns when 
the
 # user explicitly specified select_columns (to avoid leaking 
internally
 # injected columns like 'id'). Fall back to 
result.columns_requested
 # (which holds DAO defaults) when no explicit columns were 
requested.
-columns_to_filter = original_select_columns or 
result.columns_requested
+columns_to_filter = result.columns_requested if 
request.order_column == "popularity_score" else original_select_columns or 
result.columns_requested
 await ctx.debug(
 "Applying field filtering via serialization context: 
columns=%s"
 % (columns_to_filter,)
 )
   ```
   
   
   
   
   
   
   
   
   
   
   
   Code Review Run #a054b2
   
   
   ---
   Should Bito avoid suggestions like this for future reviews? (https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules)
   - [ ] Yes, avoid them



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4057421313

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2932607468


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,368 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how man

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4056370459

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931948374


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -108,34 +124,53 @@ def _serialize_dashboard(
 """Serialize dashboard object (field filtering handled by 
model_serializer)."""
 return serialize_dashboard_object(obj)
 
-tool = ModelListCore(
-dao_class=DashboardDAO,
-output_schema=DashboardInfo,
-item_serializer=_serialize_dashboard,
-filter_type=DashboardFilter,
-default_columns=DEFAULT_DASHBOARD_COLUMNS,
-search_columns=[
-"dashboard_title",
-"slug",
-"uuid",
-],
-list_field_name="dashboards",
-output_list_schema=DashboardList,
-all_columns=all_columns,
-sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_dashboards.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_dashboards.popularity_sort"):
+result = _list_dashboards_by_popularity(
+request, DashboardDAO, _serialize_dashboard, all_columns, ctx
+)
+else:
+list_core = ModelListCore(
+dao_class=DashboardDAO,
+output_schema=DashboardInfo,
+item_serializer=_serialize_dashboard,
+filter_type=DashboardFilter,
+default_columns=DEFAULT_DASHBOARD_COLUMNS,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+list_field_name="dashboards",
+output_list_schema=DashboardList,
+all_columns=all_columns,
+sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
+logger=logger,
 )
+
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != "popularity_score"]
+# Ensure id is loaded when popularity_score was requested
+# (scores are keyed by id)
+if "popularity_score" in request.select_columns and "id" not in 
dao_columns:
+dao_columns = ["id"] + dao_columns
+
+with event_logger.log_context(action="mcp.list_dashboards.query"):
+result = list_core.run_tool(
+filters=request.filters,
+search=request.search,
+select_columns=dao_columns,
+order_column=request.order_column,
+order_direction=request.order_direction,
+page=max(request.page - 1, 0),
+page_size=request.page_size,
+)
+
+# Attach popularity scores if requested in select_columns

Review Comment:
   
   Understood. The update ensures that when sorting by popularity_score, the 
field is automatically included in columns_requested for the response, even if 
not explicitly requested. This lets clients see the sort key. Applied to all 
three list tools in the latest commit.



##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -71,7 +92,7 @@ async def list_charts(request: ListChartsRequest, ctx: 
Context) -> ChartList:
 modified time.
 
 Sortable columns for order_column: id, slice_name, viz_type,
-datasource_name, description, changed_on, created_on
+datasource_name, description, changed_on, created_on, popularity_score

Review Comment:
   
   Yes, removing `datasource_name` from the docstring aligns with the updated 
code, as it's no longer in the sortable columns list (now 
`CHART_SEARCH_COLUMNS`). The change prevents misleading documentation.
   
   **superset/mcp_service/chart/tool/list_charts.py**
   ```
   -"viz_type",
   -"description",
   +"viz_type",
   +"datasource_name",
   +"description",
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931946291


##
superset/mcp_service/dataset/schemas.py:
##
@@ -137,6 +137,12 @@ class DatasetInfo(BaseModel):
 is_favorite: bool | None = Field(
 None, description="Whether this dataset is favorited by the current 
user"
 )
+popularity_score: float | None = Field(
+None,
+description="Popularity score based on chart usage, certification, "
+"and recency. Request via select_columns=['popularity_score'] or sort "
+"via order_column='popularity_score'.",
+)
 model_config = ConfigDict(

Review Comment:
   
   Yes, the suggestion is valid — it adds the necessary import and logic to 
compute and assign the popularity score for single dataset retrievals, ensuring 
consistency with how popularity is handled in list operations.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931939149


##
superset/mcp_service/common/schema_discovery.py:
##
@@ -449,6 +465,13 @@ def get_columns_from_model(
 "charts": ColumnMetadata(
 name="charts", description="Charts in dashboard", type="list", 
is_default=False
 ),
+"popularity_score": ColumnMetadata(
+name="popularity_score",
+description="Popularity score based on views, favorites, chart count, "
+"and recency",

Review Comment:
   
   This question isn’t related to the pull request. I can only help with 
questions about the PR’s code or comments.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931934573


##
superset/mcp_service/common/schema_discovery.py:
##
@@ -449,6 +465,13 @@ def get_columns_from_model(
 "charts": ColumnMetadata(
 name="charts", description="Charts in dashboard", type="list", 
is_default=False
 ),
+"popularity_score": ColumnMetadata(
+name="popularity_score",
+description="Popularity score based on views, favorites, chart count, "
+"and recency",

Review Comment:
   Valid. Updated the dashboard `popularity_score` description to include 
certification and published status bonuses. Fixed in the latest commit.



##
superset/mcp_service/dataset/schemas.py:
##
@@ -137,6 +137,12 @@ class DatasetInfo(BaseModel):
 is_favorite: bool | None = Field(
 None, description="Whether this dataset is favorited by the current 
user"
 )
+popularity_score: float | None = Field(
+None,
+description="Popularity score based on chart usage, certification, "
+"and recency. Request via select_columns=['popularity_score'] or sort "
+"via order_column='popularity_score'.",
+)
 model_config = ConfigDict(

Review Comment:
   Valid. Added `compute_dataset_popularity()` call in `get_dataset_info` so 
single-dataset retrievals now populate `popularity_score`. Fixed in the latest 
commit.



##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -108,34 +124,53 @@ def _serialize_dashboard(
 """Serialize dashboard object (field filtering handled by 
model_serializer)."""
 return serialize_dashboard_object(obj)
 
-tool = ModelListCore(
-dao_class=DashboardDAO,
-output_schema=DashboardInfo,
-item_serializer=_serialize_dashboard,
-filter_type=DashboardFilter,
-default_columns=DEFAULT_DASHBOARD_COLUMNS,
-search_columns=[
-"dashboard_title",
-"slug",
-"uuid",
-],
-list_field_name="dashboards",
-output_list_schema=DashboardList,
-all_columns=all_columns,
-sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_dashboards.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_dashboards.popularity_sort"):
+result = _list_dashboards_by_popularity(
+request, DashboardDAO, _serialize_dashboard, all_columns, ctx
+)
+else:
+list_core = ModelListCore(
+dao_class=DashboardDAO,
+output_schema=DashboardInfo,
+item_serializer=_serialize_dashboard,
+filter_type=DashboardFilter,
+default_columns=DEFAULT_DASHBOARD_COLUMNS,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+list_field_name="dashboards",
+output_list_schema=DashboardList,
+all_columns=all_columns,
+sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
+logger=logger,
 )
+
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != "popularity_score"]
+# Ensure id is loaded when popularity_score was requested
+# (scores are keyed by id)
+if "popularity_score" in request.select_columns and "id" not in 
dao_columns:
+dao_columns = ["id"] + dao_columns
+
+with event_logger.log_context(action="mcp.list_dashboards.query"):
+result = list_core.run_tool(
+filters=request.filters,
+search=request.search,
+select_columns=dao_columns,
+order_column=request.order_column,
+order_direction=request.order_direction,
+page=max(request.page - 1, 0),
+page_size=request.page_size,
+)
+
+# Attach popularity scores if requested in select_columns

Review Comment:
   Valid. When sorting by popularity_score, the response now includes 
`popularity_score` in `columns_requested` even if the user didn't explicitly 
request it, so clients can see the sort key. Applied to all three list tools. 
Fixed in the latest commit.



##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -71,7 +92,7 @@ async def list_charts(request: ListCharts

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931761389


##
superset/mcp_service/dataset/tool/list_datasets.py:
##
@@ -152,9 +190,16 @@ def _serialize_dataset(
 )
 
 # Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or 
defaults)
-# This triggers DatasetInfo._filter_fields_by_context for each dataset
 columns_to_filter = result.columns_requested
+# Re-add popularity_score if it was originally requested
+# (it was stripped before the DAO query since it's computed)
+if (
+request.select_columns
+and "popularity_score" in request.select_columns
+and columns_to_filter
+and "popularity_score" not in columns_to_filter
+):
+columns_to_filter = list(columns_to_filter) + ["popularity_score"]

Review Comment:
   Fixed in bad796b. Response filtering now uses the original 
`request.select_columns` (saved before DAO mutation) instead of 
`result.columns_requested` (which reflected DAO-expanded columns with injected 
`id`). When no explicit columns requested, falls back to 
`result.columns_requested` with DAO defaults.



##
superset/mcp_service/dataset/tool/list_datasets.py:
##
@@ -176,3 +221,78 @@ def _serialize_dataset(
 )
 )
 raise
+
+
+def _list_datasets_by_popularity(
+request: ListDatasetsRequest,
+dao_class: Any,
+serializer: Callable[..., dict[str, Any] | None],
+all_columns: list[str],
+ctx: Context,
+) -> DatasetList:
+"""Two-pass listing: sort all matching datasets by popularity score."""
+from superset.mcp_service.common.schema_discovery import 
DATASET_SORTABLE_COLUMNS
+
+sorted_ids, scores, total_count = get_popularity_sorted_ids(
+compute_fn=compute_dataset_popularity,
+dao_class=dao_class,
+filters=request.filters,
+search=request.search,
+search_columns=DATASET_SEARCH_COLUMNS,
+order_direction=request.order_direction,
+)
+
+# Apply pagination to sorted IDs
+page = max(request.page - 1, 0)
+page_size = request.page_size
+start = page * page_size
+end = start + page_size
+
+# Fetch full models for page IDs
+if page_ids := sorted_ids[start:end]:
+items = dao_class.find_by_ids(page_ids)
+id_to_item = {item.id: item for item in items}
+ordered_items = [id_to_item[pid] for pid in page_ids if pid in 
id_to_item]
+else:
+ordered_items = []
+
+# Serialize
+select_columns = request.select_columns or DEFAULT_DATASET_COLUMNS
+if "popularity_score" not in select_columns:
+select_columns = list(select_columns) + ["popularity_score"]
+
+ds_objs = []
+for item in ordered_items:
+obj = serializer(item, select_columns)
+if obj is not None:
+ds_objs.append(obj)
+
+attach_popularity_scores(ds_objs, scores)
+
+total_pages = (total_count + page_size - 1) // page_size if page_size > 0 
else 0
+pagination_info = PaginationInfo(
+page=page,
+page_size=page_size,
+total_count=total_count,
+total_pages=total_pages,
+has_next=page < total_pages - 1,
+has_previous=page > 0,
+)
+
+return DatasetList(
+datasets=ds_objs,
+count=len(ds_objs),
+total_count=total_count,
+page=page,
+page_size=page_size,
+total_pages=total_pages,
+has_previous=page > 0,
+has_next=page < total_pages - 1,
+columns_requested=select_columns,
+columns_loaded=select_columns,
+columns_available=all_columns,
+sortable_columns=DATASET_SORTABLE_COLUMNS,
+filters_applied=request.filters if isinstance(request.filters, list) 
else [],
+pagination=pagination_info,
+timestamp=datetime.now(timezone.utc),
+)

Review Comment:
   Fixed in bad796b. In all three `_list_*_by_popularity` functions, 
`columns_requested` now reflects the original `request.select_columns` (or 
defaults). The internal expansion for attach step is isolated to 
`select_columns`/`columns_loaded` only.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931760284


##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -142,9 +188,16 @@ def _serialize_chart(
 )
 
 # Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or 
defaults)
-# This triggers ChartInfo._filter_fields_by_context for each chart
 columns_to_filter = result.columns_requested
+# Re-add popularity_score if it was originally requested
+# (it was stripped before the DAO query since it's computed)
+if (
+request.select_columns
+and "popularity_score" in request.select_columns
+and columns_to_filter
+and "popularity_score" not in columns_to_filter
+):
+columns_to_filter = list(columns_to_filter) + ["popularity_score"]

Review Comment:
   Fixed in bad796b. Response filtering now uses the original 
`request.select_columns` (saved before DAO mutation) instead of 
`result.columns_requested` (which reflected DAO-expanded columns with injected 
`id`). When no explicit columns requested, falls back to 
`result.columns_requested` with DAO defaults.



##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -144,9 +179,16 @@ def _serialize_dashboard(
 )
 
 # Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or defaults)
-# This triggers DashboardInfo._filter_fields_by_context for each dashboard
 columns_to_filter = result.columns_requested
+# Re-add popularity_score if it was originally requested
+# (it was stripped before the DAO query since it's computed)
+if (
+request.select_columns
+and "popularity_score" in request.select_columns
+and columns_to_filter
+and "popularity_score" not in columns_to_filter
+):
+columns_to_filter = list(columns_to_filter) + ["popularity_score"]

Review Comment:
   Fixed in bad796b. Response filtering now uses the original 
`request.select_columns` (saved before DAO mutation) instead of 
`result.columns_requested` (which reflected DAO-expanded columns with injected 
`id`). When no explicit columns requested, falls back to 
`result.columns_requested` with DAO defaults.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4055696099

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2931292560


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -155,3 +196,83 @@ def _serialize_dashboard(
 return result.model_dump(
 mode="json", context={"select_columns": columns_to_filter}
 )
+
+
+def _list_dashboards_by_popularity(
+request: ListDashboardsRequest,
+dao_class: Any,
+serializer: Callable[..., dict[str, Any] | None],
+all_columns: list[str],
+ctx: Context,
+) -> DashboardList:
+"""Two-pass listing: sort all matching dashboards by popularity score."""
+from superset.mcp_service.common.schema_discovery import (
+DASHBOARD_SORTABLE_COLUMNS,
+)
+
+sorted_ids, scores, total_count = get_popularity_sorted_ids(
+compute_fn=compute_dashboard_popularity,
+dao_class=dao_class,
+filters=request.filters,
+search=request.search,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+order_direction=request.order_direction,
+)
+
+# Apply pagination to sorted IDs
+page = max(request.page - 1, 0)
+page_size = request.page_size
+start = page * page_size
+end = start + page_size
+
+# Fetch full models for page IDs
+if page_ids := sorted_ids[start:end]:
+items = dao_class.find_by_ids(page_ids)
+id_to_item = {item.id: item for item in items}
+ordered_items = [id_to_item[pid] for pid in page_ids if pid in 
id_to_item]
+else:
+ordered_items = []
+
+# Serialize - preserve the original request columns for response filtering
+columns_requested = request.select_columns or DEFAULT_DASHBOARD_COLUMNS

Review Comment:
   **Suggestion:** When sorting by popularity without explicit 
`select_columns`, the response metadata and field filtering omit 
`popularity_score`, so clients cannot see the score they explicitly asked to 
sort by. Include `popularity_score` in the default requested columns for the 
popularity-sort path. [logic error]
   
   
   Severity Level: Major ⚠️
   
   ```mdx
   - ⚠️ Popularity-sorted dashboard responses hide computed score field.
   - ⚠️ MCP clients cannot display numeric ranking evidence.
   ```
   
   
   ```suggestion
   columns_requested = request.select_columns or (
   DEFAULT_DASHBOARD_COLUMNS + ["popularity_score"]
   )
   ```
   
   Steps of Reproduction ✅ 
   
   ```mdx
   1. Invoke MCP tool `list_dashboards` with `order_column="popularity_score"` 
and no
   `select_columns` (real entrypoint is `list_dashboards()` at
   `superset/mcp_service/dashboard/tool/list_dashboards.py:82`, registered via 
`@tool` at
   line 80; same invocation pattern is exercised in tests via 
`Client.call_tool(...)` at
   
`tests/unit_tests/mcp_service/dashboard/tool/test_dashboard_tools.py:102-106`).
   
   2. Request enters popularity branch (`if request.order_column == 
"popularity_score"`) at
   `list_dashboards.py:133-137`, then `_list_dashboards_by_popularity()` sets
   `columns_requested` to defaults only (`line 237`) and still 
computes/attaches popularity
   (`lines 241-242`, `250`).
   
   3. Back in `list_dashboards()`, response filtering uses `columns_to_filter =
   original_select_columns or result.columns_requested` (`line 190`), so with 
no explicit
   `select_columns`, filter list is default columns without `popularity_score`.
   
   4. `DashboardInfo` serializer drops fields not in `select_columns` context
   (`superset/mcp_service/dashboard/schemas.py:375-380`), so `popularity_score` 
is removed
   from each dashboard despite being computed and used for sorting.
   ```
   
   
   Prompt for AI Agent 🤖 
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/dashboard/tool/list_dashboards.py
   **Line:** 237:237
   **Comment:**
*Logic Error: When sorting by popularity without explicit 
`select_columns`, the response metadata and field filtering omit 
`popularity_score`, so clients cannot see the score they explicitly asked to 
sort by. Include `popularity_score` in the default requested columns for the 
popularity-sort path.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   
   👍
 | 👎



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4055138901

   ## **Sequence Diagram**
   
   This PR adds a computed popularity_score to chart, dashboard, and dataset 
list tools. The score is calculated only when requested, and popularity-based 
sorting uses a two-pass flow to rank first, then paginate and return full 
records.
   
   ```mermaid
   sequenceDiagram
   participant Client
   participant MCP List Tool
   participant DAO
   participant Popularity Module
   
   Client->>MCP List Tool: List assets with select columns or order column 
popularity_score
   
   alt Order by popularity_score
   MCP List Tool->>DAO: Fetch all matching asset ids
   MCP List Tool->>Popularity Module: Compute scores and sort ids
   MCP List Tool->>DAO: Fetch paged assets by sorted ids
   else popularity_score only requested in select columns
   MCP List Tool->>DAO: Fetch paged assets with normal ordering
   MCP List Tool->>Popularity Module: Compute scores for returned ids
   end
   
   MCP List Tool-->>Client: Return assets with popularity_score when 
requested
   ```
   
   ---
   *Generated by [CodeAnt AI](https://codeant.ai)*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4054898386

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930869461


##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -71,7 +92,7 @@ async def list_charts(request: ListChartsRequest, ctx: 
Context) -> ChartList:
 modified time.
 
 Sortable columns for order_column: id, slice_name, viz_type,
-datasource_name, description, changed_on, created_on
+datasource_name, description, changed_on, created_on, popularity_score

Review Comment:
   
   
   
   
   Missing sortable column in schema
   
   
   The function docstring lists 'datasource_name' as a sortable column, but 
CHART_SORTABLE_COLUMNS imported from schema_discovery.py does not include it. 
This will cause sorting requests for datasource_name to fail with an error, as 
the ModelListCore validates against the sortable_columns list. Since 
datasource_name is a valid Slice model column and was previously sortable, it 
should be included.
   
   
   
   
   
   Code suggestion
   
   Check the AI-generated fix before applying
   
   
   
   ```
-"viz_type",
-"description",
+"viz_type",
+"datasource_name",
+"description",
   ```
   
   
   
   
   
   
   
   
   
   
   
   Code Review Run #3a8f29
   
   
   ---
   Should Bito avoid suggestions like this for future reviews? (https://alpha.bito.ai/home/ai-agents/review-rules>Manage Rules)
   - [ ] Yes, avoid them



##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -108,34 +124,53 @@ def _serialize_dashboard(
 """Serialize dashboard object (field filtering handled by 
model_serializer)."""
 return serialize_dashboard_object(obj)
 
-tool = ModelListCore(
-dao_class=DashboardDAO,
-output_schema=DashboardInfo,
-item_serializer=_serialize_dashboard,
-filter_type=DashboardFilter,
-default_columns=DEFAULT_DASHBOARD_COLUMNS,
-search_columns=[
-"dashboard_title",
-"slug",
-"uuid",
-],
-list_field_name="dashboards",
-output_list_schema=DashboardList,
-all_columns=all_columns,
-sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_dashboards.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_dashboards.popularity_sort"):
+result = _list_dashboards_by_popularity(
+request, DashboardDAO, _serialize_dashboard, all_columns, ctx
+)
+else:
+list_core = ModelListCore(
+dao_class=DashboardDAO,
+output_schema=DashboardInfo,
+item_serializer=_serialize_dashboard,
+filter_type=DashboardFilter,
+default_columns=DEFAULT_DASHBOARD_COLUMNS,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+list_field_name="dashboards",
+output_list_schema=DashboardList,
+all_columns=all_columns,
+sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
+logger=logger,
 )
+
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != "popularity_score"]
+# Ensure id is loaded when popularity_score was requested
+# (scores are keyed by id)
+if "popularity_score" in request.select_columns and "id" not in 
dao_columns:
+dao_columns = ["id"] + dao_columns
+
+with event_logger.log_context(action="mcp.list_dashboards.query"):
+result = list_core.run_tool(
+filters=request.filters,
+search=request.search,
+select_columns=dao_columns,
+order_column=request.order_column,
+order_direction=request.order_direction,
+page=max(request.page - 1, 0),
+page_size=request.page_size,
+)
+
+# Attach popularity scores if requested in select_columns

Review Comment:
   
   
   
   
   Serialization Filtering Bug
   
   
   When sorting by non-popularity columns but requesting popularity_score, the 
field gets attached but filtered out during serialization since 
columns_requested excludes it. Update columns_requested to match the full 
request.
   
   
   
   
   
   Code suggestion
   
   Check the AI-generated fix before app

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930742920


##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -142,9 +188,16 @@ def _serialize_chart(
 )
 
 # Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or 
defaults)
-# This triggers ChartInfo._filter_fields_by_context for each chart
 columns_to_filter = result.columns_requested
+# Re-add popularity_score if it was originally requested
+# (it was stripped before the DAO query since it's computed)
+if (
+request.select_columns
+and "popularity_score" in request.select_columns
+and columns_to_filter
+and "popularity_score" not in columns_to_filter
+):
+columns_to_filter = list(columns_to_filter) + ["popularity_score"]

Review Comment:
   **Suggestion:** Internal column injection for score computation leaks into 
the response shape. When a client requests only `popularity_score`, the code 
adds `id` to `select_columns` for DAO loading and then reuses those mutated 
columns for output filtering, so `id` is returned even though it was not 
requested. Build response filtering from the original request columns instead 
of DAO-expanded columns. [logic error]
   
   
   Severity Level: Major ⚠️
   
   ```mdx
   - ⚠️ list_charts response shape violates requested select_columns contract.
   - ⚠️ Unrequested id field increases MCP response payload tokens.
   - ⚠️ Client-side strict column parsers may mis-handle responses.
   ```
   
   
   ```suggestion
   columns_to_filter = (
   list(request.select_columns)
   if request.select_columns
   else result.columns_requested
   )
   # Re-add popularity_score if it was originally requested
   # (it was stripped before the DAO query since it's computed)
   if (
   request.select_columns
   and "popularity_score" in request.select_columns
   and columns_to_filter
   and "popularity_score" not in columns_to_filter
   ):
   columns_to_filter = list(columns_to_filter) + 
["popularity_score"]
   ```
   
   Steps of Reproduction ✅ 
   
   ```mdx
   1. MCP registers `list_charts` as a callable tool via imports in
   `superset/mcp_service/app.py:393-399`; registration is verified in
   `tests/unit_tests/mcp_service/test_mcp_tool_registration.py:31`.
   
   2. Call MCP `tools/call` with `name=\"list_charts\"` and params 
`{\"select_columns\":
   [\"popularity_score\"]}`; middleware resolves tool by message name at
   `superset/mcp_service/middleware.py:256`.
   
   3. In `superset/mcp_service/chart/tool/list_charts.py:155-164`, code removes
   `popularity_score` for DAO, then injects `"id"` into `dao_columns` to 
compute scores.
   
   4. `ModelListCore.run_tool()` sets `columns_requested = select_columns` at
   `superset/mcp_service/mcp_core.py:154-160`, so response metadata now carries 
`["id"]`
   (internal column) rather than original request.
   
   5. Back in `list_charts`, filtering uses `result.columns_requested` at
   `superset/mcp_service/chart/tool/list_charts.py:191`, then re-adds 
`popularity_score` at
   `:194-200`, resulting in `["id","popularity_score"]`.
   
   6. Serializer enforces context-based field output in
   `superset/mcp_service/chart/schemas.py:151-155`, so response includes leaked 
`id` even
   though caller requested only `popularity_score`.
   ```
   
   
   Prompt for AI Agent 🤖 
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/chart/tool/list_charts.py
   **Line:** 191:200
   **Comment:**
*Logic Error: Internal column injection for score computation leaks 
into the response shape. When a client requests only `popularity_score`, the 
code adds `id` to `select_columns` for DAO loading and then reuses those 
mutated columns for output filtering, so `id` is returned even though it was 
not requested. Build response filtering from the original request columns 
instead of DAO-expanded columns.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   
   👍
 | 👎



##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -144,9 +179,16 @@ def _serialize_dashboard(
 )
 
 # Apply field filtering via serialization context
-# Always use columns_requested (either explicit select_columns or defaults)
-# This triggers DashboardInfo._filter_fields_by_context for each dashboard
 columns_to_filter = result.columns_requested
+# Re-add popularity_score if it was originally requested
+# (it was stripped before the DAO query since it's computed)
+if (
+reques

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4054552315

   ## **Sequence Diagram**
   
   This PR adds a lazy computed popularity_score to chart, dashboard, and 
dataset list tools. The flow now branches between a two-pass ranking path for 
popularity sorting and a lightweight attach-only path when the score is merely 
selected.
   
   ```mermaid
   sequenceDiagram
   participant Client
   participant MCPListTool
   participant DAO
   participant PopularityModule
   
   Client->>MCPListTool: List assets with filters and options
   alt order column is popularity score
   MCPListTool->>DAO: Fetch matching asset ids
   MCPListTool->>PopularityModule: Compute scores and rank ids
   MCPListTool->>DAO: Fetch paged assets in ranked order
   MCPListTool->>MCPListTool: Attach popularity score to results
   else popularity score requested in selected columns
   MCPListTool->>DAO: Fetch paged assets normally
   MCPListTool->>PopularityModule: Compute scores for returned ids
   MCPListTool->>MCPListTool: Attach popularity score to results
   end
   MCPListTool-->>Client: Return paginated assets with optional popularity 
score
   ```
   
   ---
   *Generated by [CodeAnt AI](https://codeant.ai)*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930716476


##
superset/mcp_service/chart/tool/list_charts.py:
##
@@ -106,34 +129,50 @@ def _serialize_chart(
 """Serialize chart object (field filtering handled by 
model_serializer)."""
 return serialize_chart_object(cast(ChartLike | None, obj))
 
-tool = ModelListCore(
-dao_class=ChartDAO,
-output_schema=ChartInfo,
-item_serializer=_serialize_chart,
-filter_type=ChartFilter,
-default_columns=DEFAULT_CHART_COLUMNS,
-search_columns=[
-"slice_name",
-"description",
-],
-list_field_name="charts",
-output_list_schema=ChartList,
-all_columns=all_columns,
-sortable_columns=CHART_SORTABLE_COLUMNS,
-logger=logger,
-)
-
 try:
-with event_logger.log_context(action="mcp.list_charts.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_charts.popularity_sort"):
+result = _list_charts_by_popularity(
+request, ChartDAO, _serialize_chart, all_columns, ctx
+)
+else:
+list_core = ModelListCore(
+dao_class=ChartDAO,
+output_schema=ChartInfo,
+item_serializer=_serialize_chart,
+filter_type=ChartFilter,
+default_columns=DEFAULT_CHART_COLUMNS,
+search_columns=CHART_SEARCH_COLUMNS,
+list_field_name="charts",
+output_list_schema=ChartList,
+all_columns=all_columns,
+sortable_columns=CHART_SORTABLE_COLUMNS,
+logger=logger,
 )
+
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != 
"popularity_score"]
+
+with event_logger.log_context(action="mcp.list_charts.query"):
+result = list_core.run_tool(
+filters=request.filters,
+search=request.search,
+select_columns=dao_columns,
+order_column=request.order_column,
+order_direction=request.order_direction,
+page=max(request.page - 1, 0),
+page_size=request.page_size,
+)
+
+# Attach popularity scores if requested in select_columns
+if request.select_columns and "popularity_score" in 
request.select_columns:
+if chart_ids := [c.id for c in result.charts if c.id is not 
None]:
+scores = compute_chart_popularity(chart_ids)
+attach_popularity_scores(result.charts, scores)

Review Comment:
   Good catch — fixed in ecc8782. When `popularity_score` is in 
`select_columns`, it's now re-added to `columns_to_filter` before serialization 
so it's not silently dropped. Also ensures `id` is always loaded so scores can 
be attached by ID.



##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -108,34 +124,49 @@ def _serialize_dashboard(
 """Serialize dashboard object (field filtering handled by 
model_serializer)."""
 return serialize_dashboard_object(obj)
 
-tool = ModelListCore(
-dao_class=DashboardDAO,
-output_schema=DashboardInfo,
-item_serializer=_serialize_dashboard,
-filter_type=DashboardFilter,
-default_columns=DEFAULT_DASHBOARD_COLUMNS,
-search_columns=[
-"dashboard_title",
-"slug",
-"uuid",
-],
-list_field_name="dashboards",
-output_list_schema=DashboardList,
-all_columns=all_columns,
-sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_dashboards.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4054495904

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930413744


##
superset/mcp_service/dashboard/tool/list_dashboards.py:
##
@@ -108,34 +124,49 @@ def _serialize_dashboard(
 """Serialize dashboard object (field filtering handled by 
model_serializer)."""
 return serialize_dashboard_object(obj)
 
-tool = ModelListCore(
-dao_class=DashboardDAO,
-output_schema=DashboardInfo,
-item_serializer=_serialize_dashboard,
-filter_type=DashboardFilter,
-default_columns=DEFAULT_DASHBOARD_COLUMNS,
-search_columns=[
-"dashboard_title",
-"slug",
-"uuid",
-],
-list_field_name="dashboards",
-output_list_schema=DashboardList,
-all_columns=all_columns,
-sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_dashboards.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_dashboards.popularity_sort"):
+result = _list_dashboards_by_popularity(
+request, DashboardDAO, _serialize_dashboard, all_columns, ctx
+)
+else:
+list_core = ModelListCore(
+dao_class=DashboardDAO,
+output_schema=DashboardInfo,
+item_serializer=_serialize_dashboard,
+filter_type=DashboardFilter,
+default_columns=DEFAULT_DASHBOARD_COLUMNS,
+search_columns=DASHBOARD_SEARCH_COLUMNS,
+list_field_name="dashboards",
+output_list_schema=DashboardList,
+all_columns=all_columns,
+sortable_columns=DASHBOARD_SORTABLE_COLUMNS,
+logger=logger,
 )
+
+# Strip computed fields before passing to DAO query
+dao_columns = request.select_columns
+if dao_columns:
+dao_columns = [c for c in dao_columns if c != "popularity_score"]

Review Comment:
   **Suggestion:** When `popularity_score` is requested via `select_columns`, 
the DAO query removes it but does not ensure `id` is still loaded. Since score 
attachment depends on object IDs, rows loaded without `id` cannot be scored and 
the response will miss/empty `popularity_score`. Keep `id` in `dao_columns` 
whenever `popularity_score` is requested. [logic error]
   
   
   Severity Level: Major ⚠️
   
   ```mdx
   - ❌ list_dashboards cannot reliably return requested popularity_score.
   - ⚠️ MCP ranking clients get incomplete dashboard relevance data.
   ```
   
   
   ```suggestion
   dao_columns = request.select_columns
   if dao_columns:
   dao_columns = [c for c in dao_columns if c != "popularity_score"]
   if "popularity_score" in request.select_columns and "id" not in 
dao_columns:
   dao_columns = list(dao_columns) + ["id"]
   ```
   
   Steps of Reproduction ✅ 
   
   ```mdx
   1. Call MCP tool `list_dashboards` with
   `select_columns=["dashboard_title","popularity_score"]` (tool is registered 
in
   `superset/mcp_service/app.py:406` and invoked in tests via
   `client.call_tool("list_dashboards", ...)` at
   
`tests/unit_tests/mcp_service/dashboard/tool/test_dashboard_tools.py:102-105`).
   
   2. In `superset/mcp_service/dashboard/tool/list_dashboards.py:149-157`, 
`popularity_score`
   is stripped and `ModelListCore.run_tool` receives 
`select_columns=["dashboard_title"]`.
   
   3. `ModelListCore.run_tool` forwards `columns=columns_to_load` to DAO
   (`superset/mcp_service/mcp_core.py:165-174`); DAO then queries only 
requested columns
   (`superset/daos/base.py:643-645`), so rows may not contain `id`. Serializer 
sets
   `id=getattr(..., "id", None)` 
(`superset/mcp_service/dashboard/schemas.py:528`), yielding
   `id=None`.
   
   4. Score attachment path
   (`superset/mcp_service/dashboard/tool/list_dashboards.py:165-168`) skips 
rows with `id is
   None`, so scores are not mapped. Final response filtering uses 
`result.columns_requested`
   (`list_dashboards.py:178-185`, `dashboard/schemas.py:378`), so requested 
popularity
   metadata is not reliably returned.
   ```
   
   
   Prompt for AI Agent 🤖 
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/dashboard/tool/list_dashboards.py
   **Line:** 149:151
   **Comment:**
*Logic Error: When `popularity_score` is requested via 
`select_columns`, the DAO query removes

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


codeant-ai-for-open-source[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4054186571

   ## **Sequence Diagram**
   
   This PR adds a computed popularity_score to chart, dashboard, and dataset 
list tools. The score is calculated only when requested, with a dedicated two 
pass flow when sorting by popularity to rank results before pagination.
   
   ```mermaid
   sequenceDiagram
   participant Client
   participant MCPListTool
   participant DAO
   participant PopularityModule
   
   Client->>MCPListTool: List assets with filters and sort options
   
   alt order_column is popularity_score
   MCPListTool->>DAO: Fetch all matching asset IDs
   MCPListTool->>PopularityModule: Compute scores and rank IDs
   MCPListTool->>DAO: Fetch paged assets in ranked ID order
   else popularity_score in select_columns only
   MCPListTool->>DAO: Fetch paged assets with normal sorting
   MCPListTool->>PopularityModule: Compute scores for returned asset IDs
   end
   
   MCPListTool-->>Client: Return asset list with optional popularity_score
   ```
   
   ---
   *Generated by [CodeAnt AI](https://codeant.ai)*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930390812


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,368 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how man

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-13 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2930382136


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,368 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how many dashb

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-12 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2927567676


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,368 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Default time window for view counts
+DEFAULT_VIEW_WINDOW_DAYS = 30
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(
+chart_ids: list[int], days: int = DEFAULT_VIEW_WINDOW_DAYS
+) -> dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how man

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-12 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4050251477

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2911821699


##
tests/unit_tests/mcp_service/common/test_popularity.py:
##
@@ -0,0 +1,386 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Unit tests for the popularity scoring module.
+"""
+
+from __future__ import annotations
+
+from collections import namedtuple
+from datetime import datetime, timedelta, timezone
+from unittest.mock import MagicMock, patch
+
+from superset.mcp_service.common.popularity import (
+_recency_bonus,
+compute_chart_popularity,
+compute_dashboard_popularity,
+compute_dataset_popularity,
+get_popularity_sorted_ids,
+)
+
+# Named tuples to simulate SQLAlchemy query results
+ViewRow = namedtuple("ViewRow", ["slice_id", "view_count"])
+DashViewRow = namedtuple("DashViewRow", ["dashboard_id", "view_count"])
+FavRow = namedtuple("FavRow", ["obj_id", "fav_count"])
+DashCountRow = namedtuple("DashCountRow", ["slice_id", "dash_count"])
+ChartCountRow = namedtuple("ChartCountRow", ["dashboard_id", "chart_count"])
+DatasetChartCountRow = namedtuple(
+"DatasetChartCountRow", ["datasource_id", "chart_count"]
+)
+ChartMeta = namedtuple("ChartMeta", ["id", "certified_by", "changed_on"])
+DashMeta = namedtuple("DashMeta", ["id", "published", "certified_by", 
"changed_on"])
+DatasetMeta = namedtuple("DatasetMeta", ["id", "extra", "changed_on"])
+
+
+class TestRecencyBonus:
+def test_within_7_days(self):
+recent = datetime.now(timezone.utc) - timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+def test_within_30_days(self):
+moderate = datetime.now(timezone.utc) - timedelta(days=15)
+assert _recency_bonus(moderate) == 2.0
+
+def test_older_than_30_days(self):
+old = datetime.now(timezone.utc) - timedelta(days=60)
+assert _recency_bonus(old) == 0.0
+
+def test_none_changed_on(self):
+assert _recency_bonus(None) == 0.0
+
+def test_naive_datetime_treated_as_utc(self):
+# Naive datetime (no tzinfo) should be treated as UTC
+recent = datetime.now(timezone.utc).replace(tzinfo=None) - 
timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+
+class TestComputeChartPopularity:
+def test_empty_ids_returns_empty(self):
+assert compute_chart_popularity([]) == {}
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_scoring_formula(self, mock_db):
+"""Test: view_count*3 + fav_count*5 + dash_count*2 + certified*10 + 
recency"""
+recent = datetime.now(timezone.utc) - timedelta(days=2)  # +5 recency
+
+# Setup mock query chain
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+# Each db.session.query() call returns a different chain
+query_chains = [
+# 1. View counts query
+self._mock_query_chain([ViewRow(slice_id=1, view_count=10)]),
+# 2. Fav counts query
+self._mock_query_chain([FavRow(obj_id=1, fav_count=3)]),
+# 3. Dashboard counts query
+self._mock_query_chain([DashCountRow(slice_id=1, dash_count=4)]),
+# 4. Chart metadata query
+self._mock_query_chain(
+[ChartMeta(id=1, certified_by="admin", changed_on=recent)]
+),
+]
+mock_session.query.side_effect = query_chains
+
+scores = compute_chart_popularity([1])
+
+# views: 10*3=30, favs: 3*5=15, dashes: 4*2=8, certified: 10, recency: 
5
+expected = 30 + 15 + 8 + 10 + 5
+assert scores[1] == expected
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_no_activity_only_recency(self, mock_db):
+"""Chart with no views/favs/dashboards gets only recency + 
certification."""
+old = datetime.now(timezone.utc) - timedelta(days=60)  # 0 recency
+
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+query_chains = [
+self._mock_query_chain([]),  # No views
+self._mock_query_chain([]),  # No favs
+self._mock_query_chain([]),  # No dashboards
+self._mock_query_chai

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4031444840

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2911805917


##
tests/unit_tests/mcp_service/common/test_popularity.py:
##
@@ -0,0 +1,386 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Unit tests for the popularity scoring module.
+"""
+
+from __future__ import annotations
+
+from collections import namedtuple
+from datetime import datetime, timedelta, timezone
+from unittest.mock import MagicMock, patch
+
+from superset.mcp_service.common.popularity import (
+_recency_bonus,
+compute_chart_popularity,
+compute_dashboard_popularity,
+compute_dataset_popularity,
+get_popularity_sorted_ids,
+)
+
+# Named tuples to simulate SQLAlchemy query results
+ViewRow = namedtuple("ViewRow", ["slice_id", "view_count"])
+DashViewRow = namedtuple("DashViewRow", ["dashboard_id", "view_count"])
+FavRow = namedtuple("FavRow", ["obj_id", "fav_count"])
+DashCountRow = namedtuple("DashCountRow", ["slice_id", "dash_count"])
+ChartCountRow = namedtuple("ChartCountRow", ["dashboard_id", "chart_count"])
+DatasetChartCountRow = namedtuple(
+"DatasetChartCountRow", ["datasource_id", "chart_count"]
+)
+ChartMeta = namedtuple("ChartMeta", ["id", "certified_by", "changed_on"])
+DashMeta = namedtuple("DashMeta", ["id", "published", "certified_by", 
"changed_on"])
+DatasetMeta = namedtuple("DatasetMeta", ["id", "extra", "changed_on"])
+
+
+class TestRecencyBonus:
+def test_within_7_days(self):
+recent = datetime.now(timezone.utc) - timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+def test_within_30_days(self):
+moderate = datetime.now(timezone.utc) - timedelta(days=15)
+assert _recency_bonus(moderate) == 2.0
+
+def test_older_than_30_days(self):
+old = datetime.now(timezone.utc) - timedelta(days=60)
+assert _recency_bonus(old) == 0.0
+
+def test_none_changed_on(self):
+assert _recency_bonus(None) == 0.0
+
+def test_naive_datetime_treated_as_utc(self):
+# Naive datetime (no tzinfo) should be treated as UTC
+recent = datetime.now(timezone.utc).replace(tzinfo=None) - 
timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+
+class TestComputeChartPopularity:
+def test_empty_ids_returns_empty(self):
+assert compute_chart_popularity([]) == {}
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_scoring_formula(self, mock_db):
+"""Test: view_count*3 + fav_count*5 + dash_count*2 + certified*10 + 
recency"""
+recent = datetime.now(timezone.utc) - timedelta(days=2)  # +5 recency
+
+# Setup mock query chain
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+# Each db.session.query() call returns a different chain
+query_chains = [
+# 1. View counts query
+self._mock_query_chain([ViewRow(slice_id=1, view_count=10)]),
+# 2. Fav counts query
+self._mock_query_chain([FavRow(obj_id=1, fav_count=3)]),
+# 3. Dashboard counts query
+self._mock_query_chain([DashCountRow(slice_id=1, dash_count=4)]),
+# 4. Chart metadata query
+self._mock_query_chain(
+[ChartMeta(id=1, certified_by="admin", changed_on=recent)]
+),
+]
+mock_session.query.side_effect = query_chains
+
+scores = compute_chart_popularity([1])
+
+# views: 10*3=30, favs: 3*5=15, dashes: 4*2=8, certified: 10, recency: 
5
+expected = 30 + 15 + 8 + 10 + 5
+assert scores[1] == expected
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_no_activity_only_recency(self, mock_db):
+"""Chart with no views/favs/dashboards gets only recency + 
certification."""
+old = datetime.now(timezone.utc) - timedelta(days=60)  # 0 recency
+
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+query_chains = [
+self._mock_query_chain([]),  # No views
+self._mock_query_chain([]),  # No favs
+self._mock_query_chain([]),  # No dashboards
+self._mock_query_chain(
+   

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


aminghadersohi commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2911389261


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,359 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(chart_ids: list[int], days: int = 30) -> 
dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how many dashboards contain each chart)
+dash_counts = (
+db.session.query(
+dashboard_slic

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


bito-code-review[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2911130553


##
tests/unit_tests/mcp_service/common/test_popularity.py:
##
@@ -0,0 +1,386 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Unit tests for the popularity scoring module.
+"""
+
+from __future__ import annotations
+
+from collections import namedtuple
+from datetime import datetime, timedelta, timezone
+from unittest.mock import MagicMock, patch
+
+from superset.mcp_service.common.popularity import (
+_recency_bonus,
+compute_chart_popularity,
+compute_dashboard_popularity,
+compute_dataset_popularity,
+get_popularity_sorted_ids,
+)
+
+# Named tuples to simulate SQLAlchemy query results
+ViewRow = namedtuple("ViewRow", ["slice_id", "view_count"])
+DashViewRow = namedtuple("DashViewRow", ["dashboard_id", "view_count"])
+FavRow = namedtuple("FavRow", ["obj_id", "fav_count"])
+DashCountRow = namedtuple("DashCountRow", ["slice_id", "dash_count"])
+ChartCountRow = namedtuple("ChartCountRow", ["dashboard_id", "chart_count"])
+DatasetChartCountRow = namedtuple(
+"DatasetChartCountRow", ["datasource_id", "chart_count"]
+)
+ChartMeta = namedtuple("ChartMeta", ["id", "certified_by", "changed_on"])
+DashMeta = namedtuple("DashMeta", ["id", "published", "certified_by", 
"changed_on"])
+DatasetMeta = namedtuple("DatasetMeta", ["id", "extra", "changed_on"])
+
+
+class TestRecencyBonus:
+def test_within_7_days(self):
+recent = datetime.now(timezone.utc) - timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+def test_within_30_days(self):
+moderate = datetime.now(timezone.utc) - timedelta(days=15)
+assert _recency_bonus(moderate) == 2.0
+
+def test_older_than_30_days(self):
+old = datetime.now(timezone.utc) - timedelta(days=60)
+assert _recency_bonus(old) == 0.0
+
+def test_none_changed_on(self):
+assert _recency_bonus(None) == 0.0
+
+def test_naive_datetime_treated_as_utc(self):
+# Naive datetime (no tzinfo) should be treated as UTC
+recent = datetime.now(timezone.utc).replace(tzinfo=None) - 
timedelta(days=3)
+assert _recency_bonus(recent) == 5.0
+
+
+class TestComputeChartPopularity:
+def test_empty_ids_returns_empty(self):
+assert compute_chart_popularity([]) == {}
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_scoring_formula(self, mock_db):
+"""Test: view_count*3 + fav_count*5 + dash_count*2 + certified*10 + 
recency"""
+recent = datetime.now(timezone.utc) - timedelta(days=2)  # +5 recency
+
+# Setup mock query chain
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+# Each db.session.query() call returns a different chain
+query_chains = [
+# 1. View counts query
+self._mock_query_chain([ViewRow(slice_id=1, view_count=10)]),
+# 2. Fav counts query
+self._mock_query_chain([FavRow(obj_id=1, fav_count=3)]),
+# 3. Dashboard counts query
+self._mock_query_chain([DashCountRow(slice_id=1, dash_count=4)]),
+# 4. Chart metadata query
+self._mock_query_chain(
+[ChartMeta(id=1, certified_by="admin", changed_on=recent)]
+),
+]
+mock_session.query.side_effect = query_chains
+
+scores = compute_chart_popularity([1])
+
+# views: 10*3=30, favs: 3*5=15, dashes: 4*2=8, certified: 10, recency: 
5
+expected = 30 + 15 + 8 + 10 + 5
+assert scores[1] == expected
+
+@patch("superset.mcp_service.common.popularity.db")
+def test_chart_no_activity_only_recency(self, mock_db):
+"""Chart with no views/favs/dashboards gets only recency + 
certification."""
+old = datetime.now(timezone.utc) - timedelta(days=60)  # 0 recency
+
+mock_session = MagicMock()
+mock_db.session = mock_session
+
+query_chains = [
+self._mock_query_chain([]),  # No views
+self._mock_query_chain([]),  # No favs
+self._mock_query_chain([]),  # No dashboards
+self._mock_query_chai

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4030651900

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2910653665


##
superset/mcp_service/dataset/tool/list_datasets.py:
##
@@ -115,32 +121,45 @@ def _serialize_dataset(
 """Serialize dataset (filtering via model_serializer)."""
 return serialize_dataset_object(obj)
 
-# Create tool with standard serialization
-tool = ModelListCore(
-dao_class=DatasetDAO,
-output_schema=DatasetInfo,
-item_serializer=_serialize_dataset,
-filter_type=DatasetFilter,
-default_columns=DEFAULT_DATASET_COLUMNS,
-search_columns=["schema", "sql", "table_name", "uuid"],
-list_field_name="datasets",
-output_list_schema=DatasetList,
-all_columns=all_columns,
-sortable_columns=DATASET_SORTABLE_COLUMNS,
-logger=logger,
-)
-
-with event_logger.log_context(action="mcp.list_datasets.query"):
-result = tool.run_tool(
-filters=request.filters,
-search=request.search,
-select_columns=request.select_columns,
-order_column=request.order_column,
-order_direction=request.order_direction,
-page=max(request.page - 1, 0),
-page_size=request.page_size,
+# Two-pass approach when sorting by popularity_score
+if request.order_column == "popularity_score":
+with 
event_logger.log_context(action="mcp.list_datasets.popularity_sort"):
+result = _list_datasets_by_popularity(
+request, DatasetDAO, _serialize_dataset, all_columns, ctx
+)
+else:
+# Create tool with standard serialization
+list_core = ModelListCore(
+dao_class=DatasetDAO,
+output_schema=DatasetInfo,
+item_serializer=_serialize_dataset,
+filter_type=DatasetFilter,
+default_columns=DEFAULT_DATASET_COLUMNS,
+search_columns=DATASET_SEARCH_COLUMNS,
+list_field_name="datasets",
+output_list_schema=DatasetList,
+all_columns=all_columns,
+sortable_columns=DATASET_SORTABLE_COLUMNS,
+logger=logger,
 )
 
+with event_logger.log_context(action="mcp.list_datasets.query"):
+result = list_core.run_tool(
+filters=request.filters,
+search=request.search,
+select_columns=request.select_columns,
+order_column=request.order_column,
+order_direction=request.order_direction,
+page=max(request.page - 1, 0),
+page_size=request.page_size,
+)
+
+# Attach popularity scores if requested in select_columns
+if request.select_columns and "popularity_score" in 
request.select_columns:
+if ds_ids := [d.id for d in result.datasets if d.id is not 
None]:
+scores = compute_dataset_popularity(ds_ids)
+attach_popularity_scores(result.datasets, scores)

Review Comment:
   **Suggestion:** The dataset list tool passes `select_columns` directly 
(including `popularity_score`) into `ModelListCore.run_tool` and thus to 
`DatasetDAO.list(columns=...)`, but `popularity_score` is computed rather than 
stored, so selecting it will cause the DAO query to fail instead of letting the 
later scoring code augment the results. [logic error]
   
   
   Severity Level: Critical 🚨
   
   ```mdx
   - ❌ list_datasets fails when selecting popularity_score column.
   - ⚠️ MCP clients cannot retrieve dataset popularity metadata.
   - ⚠️ New popularity_score feature unusable without workaround for datasets.
   ```
   
   
   ```suggestion
   else:
   # Create tool with standard serialization
   list_core = ModelListCore(
   dao_class=DatasetDAO,
   output_schema=DatasetInfo,
   item_serializer=_serialize_dataset,
   filter_type=DatasetFilter,
   default_columns=DEFAULT_DATASET_COLUMNS,
   search_columns=DATASET_SEARCH_COLUMNS,
   list_field_name="datasets",
   output_list_schema=DatasetList,
   all_columns=all_columns,
   sortable_columns=DATASET_SORTABLE_COLUMNS,
   logger=logger,
   )
   
   # popularity_score is computed, so do not request it as a 
physical column
   original_select_columns = list(request.select_columns or [])
   dao_select_columns = [
   col for c

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-10 Thread via GitHub


codeant-ai-for-open-source[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4030146411

   ## **Sequence Diagram**
   
   This PR adds a computed popularity_score to chart, dashboard, and dataset 
MCP list tools and introduces a two-pass flow that ranks assets by aggregated 
usage signals when clients sort by popularity_score.
   
   ```mermaid
   sequenceDiagram
   participant Client
   participant MCPListTool as MCP list tool
   participant DAO as Asset DAO
   participant Popularity as Popularity service
   
   Client->>MCPListTool: List assets ordered by popularity_score
   MCPListTool->>DAO: List matching asset ids with filters and search
   DAO-->>MCPListTool: Asset ids
   MCPListTool->>Popularity: Compute popularity scores for asset ids
   MCPListTool->>DAO: Fetch full asset models for requested page
   DAO-->>MCPListTool: Asset models
   MCPListTool->>Popularity: Attach popularity_score to each model
   MCPListTool-->>Client: Paginated asset list including popularity_score
   ```
   
   ---
   *Generated by [CodeAnt AI](https://codeant.ai)*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-09 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4027816822

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-09 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4027598670

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-09 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4027211713

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-09 Thread via GitHub


codeant-ai-for-open-source[bot] commented on code in PR #38416:
URL: https://github.com/apache/superset/pull/38416#discussion_r2907958031


##
superset/mcp_service/common/popularity.py:
##
@@ -0,0 +1,359 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""
+Popularity scoring for charts, dashboards, and datasets.
+
+Computes a composite popularity score based on views, favorites,
+relationships, certification, and recency.
+"""
+
+from __future__ import annotations
+
+import logging
+from collections.abc import Callable
+from datetime import datetime, timedelta, timezone
+from typing import Any
+
+import sqlalchemy as sa
+
+from superset.connectors.sqla.models import SqlaTable
+from superset.extensions import db
+from superset.models.core import FavStar, Log
+from superset.models.dashboard import Dashboard, dashboard_slices
+from superset.models.slice import Slice
+from superset.utils import json as json_utils
+
+logger = logging.getLogger(__name__)
+
+# Scoring weights
+VIEW_WEIGHT = 3
+FAV_WEIGHT = 5
+DASHBOARD_COUNT_WEIGHT = 2
+CHART_COUNT_WEIGHT_DASHBOARD = 1
+CHART_COUNT_WEIGHT_DATASET = 3
+CERTIFICATION_BONUS = 10
+PUBLISHED_BONUS = 3
+
+# Recency thresholds and bonuses
+RECENCY_RECENT_DAYS = 7
+RECENCY_MODERATE_DAYS = 30
+RECENCY_RECENT_BONUS = 5.0
+RECENCY_MODERATE_BONUS = 2.0
+
+# Two-pass query limit
+MAX_POPULARITY_SORT_PAGE_SIZE = 100_000
+
+
+def _recency_bonus(changed_on: datetime | None) -> float:
+"""Compute recency bonus based on changed_on timestamp."""
+if not changed_on:
+return 0.0
+now = datetime.now(timezone.utc)
+# Ensure changed_on is timezone-aware for comparison
+if changed_on.tzinfo is None:
+changed_on = changed_on.replace(tzinfo=timezone.utc)
+delta = now - changed_on
+if delta <= timedelta(days=RECENCY_RECENT_DAYS):
+return RECENCY_RECENT_BONUS
+if delta <= timedelta(days=RECENCY_MODERATE_DAYS):
+return RECENCY_MODERATE_BONUS
+return 0.0
+
+
+def _init_scores(ids: list[int]) -> dict[int, float]:
+"""Initialize a score dict with 0.0 for each ID."""
+return {i: 0.0 for i in ids}  # noqa: C420
+
+
+def _add_view_scores(
+scores: dict[int, float],
+action: str,
+id_column: sa.Column,
+entity_ids: list[int],
+cutoff: datetime,
+weight: int,
+) -> None:
+"""Add view count scores from the logs table."""
+view_counts = (
+db.session.query(id_column, sa.func.count(Log.id).label("view_count"))
+.filter(Log.action == action, id_column.in_(entity_ids), Log.dttm >= 
cutoff)
+.group_by(id_column)
+.all()
+)
+for row in view_counts:
+entity_id = row[0]
+if entity_id in scores:
+scores[entity_id] += row.view_count * weight
+
+
+def _add_fav_scores(
+scores: dict[int, float],
+class_name: str,
+entity_ids: list[int],
+weight: int,
+) -> None:
+"""Add favorite count scores from the favstar table."""
+fav_counts = (
+db.session.query(FavStar.obj_id, 
sa.func.count(FavStar.id).label("fav_count"))
+.filter(FavStar.class_name == class_name, 
FavStar.obj_id.in_(entity_ids))
+.group_by(FavStar.obj_id)
+.all()
+)
+for row in fav_counts:
+if row.obj_id in scores:
+scores[row.obj_id] += row.fav_count * weight
+
+
+def compute_chart_popularity(chart_ids: list[int], days: int = 30) -> 
dict[int, float]:
+"""Compute popularity scores for charts.
+
+Formula: view_count_30d * 3 + fav_count * 5 + dashboard_count * 2
+ + is_certified * 10 + recency_bonus
+
+Args:
+chart_ids: List of chart IDs to score
+days: Number of days for view count window
+
+Returns:
+Dict mapping chart_id -> popularity score
+"""
+if not chart_ids:
+return {}
+
+scores = _init_scores(chart_ids)
+cutoff = datetime.now(timezone.utc) - timedelta(days=days)
+
+_add_view_scores(
+scores, "mount_explorer", Log.slice_id, chart_ids, cutoff, VIEW_WEIGHT
+)
+_add_fav_scores(scores, "slice", chart_ids, FAV_WEIGHT)
+
+# Dashboard count (how many dashboards contain each chart)
+dash_counts = (
+db.session.query(
+ 

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-06 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4010787592

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-05 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4007737815

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-05 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4003693781

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-04 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4001214180

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-04 Thread via GitHub


netlify[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4000984079

   ### ✅ Deploy Preview for 
*superset-docs-preview* ready!
   
   
   |  Name | Link |
   |:-:||
   |🔨 Latest commit | 
c95bd8cbcbbaf61963e5a1d3fb6fca39adb76569 |
   |🔍 Latest deploy log | 
https://app.netlify.com/projects/superset-docs-preview/deploys/69a8c18190c2460007e9654a
 |
   |😎 Deploy Preview | 
[https://deploy-preview-38416--superset-docs-preview.netlify.app](https://deploy-preview-38416--superset-docs-preview.netlify.app)
 |
   |📱 Preview on mobile |  
Toggle QR Code... ![QR 
Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTM4NDE2LS1zdXBlcnNldC1kb2NzLXByZXZpZXcubmV0bGlmeS5hcHAifQ.YflCtZLAV9FERIKt2xaFMDxjAWsrnB3JpoptfFNrwNg)_Use your smartphone camera to open QR code link._ |
   ---
   
   _To edit notification comments on pull requests, go to your [Netlify project 
configuration](https://app.netlify.com/projects/superset-docs-preview/configuration/notifications#deploy-notifications)._


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-04 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4000722925

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).
   
   
   
   Bito Usage Guide
   
   
   **Commands**
 
   Type the following command in the pull request comment and save the comment.
 
   - `/review` - Manually triggers a full AI review.
   
   - `/pause` - Pauses automatic reviews on this pull request.
   - `/resume` - Resumes automatic reviews.
   - `/resolve` - Marks all Bito-posted review comments as resolved.
   - `/abort` - Cancels all in-progress reviews.
   
 
   Refer to the https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands";
 target="_blank" rel="noopener noreferrer">documentation for additional 
commands.
 
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings https://alpha.bito.ai/home/ai-agents/code-review-agent"; target="_blank" 
rel="noopener noreferrer">here or contact your Bito workspace admin at 
[email protected].
 
   **Documentation & Help**
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance";
 target="_blank" rel="noopener noreferrer">Customize agent settings
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules";
 target="_blank" rel="noopener noreferrer">Review rules
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent"; 
target="_blank" rel="noopener noreferrer">General documentation
   - https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs"; 
target="_blank" rel="noopener noreferrer">FAQ
   
   
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-04 Thread via GitHub


codecov[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4000416808

   ## 
[Codecov](https://app.codecov.io/gh/apache/superset/pull/38416?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 Report
   :x: Patch coverage is `0%` with `112 lines` in your changes missing 
coverage. Please review.
   :white_check_mark: Project coverage is 64.30%. Comparing base 
([`f2f5559`](https://app.codecov.io/gh/apache/superset/commit/f2f55591eccef795f816043b93876e6ca4beacd3?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache))
 to head 
([`3f0ea32`](https://app.codecov.io/gh/apache/superset/commit/3f0ea324a0519a7d0b8546709e32cfe19e964083?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   :warning: Report is 30 commits behind head on master.
   
   | [Files with missing 
lines](https://app.codecov.io/gh/apache/superset/pull/38416?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | Patch % | Lines |
   |---|---|---|
   | 
[superset/mcp\_service/common/popularity.py](https://app.codecov.io/gh/apache/superset/pull/38416?src=pr&el=tree&filepath=superset%2Fmcp_service%2Fcommon%2Fpopularity.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQvbWNwX3NlcnZpY2UvY29tbW9uL3BvcHVsYXJpdHkucHk=)
 | 0.00% | [112 Missing :warning: 
](https://app.codecov.io/gh/apache/superset/pull/38416?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 |
   
   :x: Your project check has failed because the head coverage (99.24%) is 
below the target coverage (100.00%). You can increase the head coverage or 
adjust the [target](https://docs.codecov.com/docs/commit-status#target) 
coverage.
   
   Additional details and impacted files
   
   
   
   ```diff
   @@Coverage Diff @@
   ##   master   #38416  +/-   ##
   ==
   + Coverage   64.29%   64.30%   +0.01% 
   ==
 Files1811 2489 +678 
 Lines   71491   123924   +52433 
 Branches2277528827+6052 
   ==
   + Hits4596779694   +33727 
   - Misses  2552442807   +17283 
   - Partials0 1423+1423 
   ```
   
   | 
[Flag](https://app.codecov.io/gh/apache/superset/pull/38416/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | Coverage Δ | |
   |---|---|---|
   | 
[hive](https://app.codecov.io/gh/apache/superset/pull/38416/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | `40.99% <0.00%> (?)` | |
   | 
[presto](https://app.codecov.io/gh/apache/superset/pull/38416/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | `41.00% <0.00%> (?)` | |
   | 
[python](https://app.codecov.io/gh/apache/superset/pull/38416/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | `63.73% <0.00%> (?)` | |
   | 
[sqlite](https://app.codecov.io/gh/apache/superset/pull/38416/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)
 | `63.59% <0.00%> (?)` | |
   
   Flags with carried forward coverage won't be shown. [Click 
here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment)
 to find out more.
   
   
   [:umbrella: View full report in Codecov by 
Sentry](https://app.codecov.io/gh/apache/superset/pull/38416?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   
   :loudspeaker: Have feedback on the report? [Share it 
here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
:rocket: New features to boost your workflow: 
   
   - :snowflake: [Test 
Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, 
report on failures, and find test suite problems.
   - :package: [JS Bundle 
Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save 
yourself from yourself by tracking and limiting bundle sizes in JS merges.
   


-- 
This is an automated message from the Apache Git Service.
To

Re: [PR] feat(mcp): add popularity_score computed field for charts, dashboards, datasets [superset]

2026-03-04 Thread via GitHub


bito-code-review[bot] commented on PR #38416:
URL: https://github.com/apache/superset/pull/38416#issuecomment-4000364837

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a 
very large PR).


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]