Skip to content

feat(admin): enhance analytics endpoints and session insights#22

Open
VarshVishwakarma wants to merge 1 commit into
Vishisht16:mainfrom
VarshVishwakarma:feat/admin-analytics-enhancements
Open

feat(admin): enhance analytics endpoints and session insights#22
VarshVishwakarma wants to merge 1 commit into
Vishisht16:mainfrom
VarshVishwakarma:feat/admin-analytics-enhancements

Conversation

@VarshVishwakarma
Copy link
Copy Markdown

Description

This PR enhances the native Admin Analytics API in admin.py by improving escalation insights and session analytics for dashboard integration and operational monitoring.

Closes #16

Changes Included

/admin/stats

Added:

  • category_percentages
  • period_comparison field comparing current week vs previous week escalation counts

GET /admin/analytics/top-triggers

Implemented a new analytics endpoint that:

  • aggregates escalation trigger keywords

  • ranks triggers by occurrence frequency

  • supports:

    • limit
    • optional category filtering

/admin/sessions/{id}/risk

Added:

  • peak_risk_score
  • peak_risk_timestamp
  • ordered category_transitions

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Testing

Added comprehensive tests covering:

  • category percentage calculations
  • weekly comparison logic
  • trigger aggregation and normalization
  • malformed trigger payload handling
  • category filtering
  • peak risk extraction
  • category transition ordering
  • empty database/session edge cases

Validation

python -m pytest
259 passed, 7 skipped

Checklist

  • I have read the [CONTRIBUTING](../CONTRIBUTING.md) guide
  • My code follows the project's style
  • I have added tests for new or changed behaviour
  • All tests pass (pytest tests/ -v)
  • I have updated documentation if needed
  • Self-harm / safety-related changes have been reviewed for sensitivity

Notes

  • Scope intentionally limited to the requested analytics enhancements
  • Existing endpoint behavior and API structure were preserved
  • Response structures were designed with dashboard compatibility in mind
  • No unrelated architectural or optimization changes were introduced

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 18, 2026

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added top-triggers analytics endpoint to identify the most frequently occurring triggers
    • Enhanced session risk monitoring with peak risk score tracking and category transition detection
    • Expanded admin stats with category percentages and week-over-week period comparisons
  • Bug Fixes

    • Fixed session deletion response handling to return proper status codes

Walkthrough

This PR extends the admin analytics API with a new top-triggers aggregation endpoint, expands session risk and stats responses with peak risk metrics and category percentages, and includes comprehensive test coverage using isolated database fixtures for robust edge-case validation.

Changes

Admin Analytics Enhancements

Layer / File(s) Summary
Imports & Documentation Updates
humane_proxy/api/admin.py
Module docstring updated to list the new /admin/analytics/top-triggers endpoint; imports expanded to include Counter, datetime, timedelta, and timezone.
Top Triggers Analytics Endpoint
humane_proxy/api/admin.py
New authenticated endpoint selects and aggregates triggers fields from escalations, parses stored JSON lists, normalizes strings (lowercase, whitespace-trimmed), ranks by frequency, and returns the top results with optional category filtering and configurable limit.
Enhanced Risk & Stats Responses
humane_proxy/api/admin.py
Session risk response expands to include peak_risk_score, peak_risk_timestamp (computed across history), and category_transitions (with timestamps, deduplicating consecutive repeats); stats response adds category_percentages breakdown and period_comparison (current vs. previous week counts derived from UTC timestamp boundaries).
Session Delete Response Cleanup
humane_proxy/api/admin.py
Delete handler conclusion simplified to return a 204 status response.
Test Infrastructure & Fixtures
tests/test_admin_api.py
Introduces _blank_db fixture for isolated temporary SQLite database, and two insertion helpers: _insert_raw (permits malformed JSON triggers) and _insert_row (enforces standard JSON trigger list structure).
Endpoint Test Coverage
tests/test_admin_api.py
Three new test classes: TestAnalyticsTopTriggers validates aggregation, ranking, normalization, limit/category filtering, malformed JSON skipping, and null/empty trigger handling; TestStatsEnhanced validates category percentage math, safe empty-DB behavior, and strict UTC week boundary computation; TestSessionRiskEnhanced validates peak risk extraction, category transition detection across chronological rows, and graceful defaults for unknown sessions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A rabbit hops through analytics so fine,
Triggers tallied and ranked in a line,
Peak risks and transitions now gleam,
With stats that compare like a dream!
Tests guard every edge, tried and true. 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main changes: enhancements to admin analytics endpoints and session insights.
Description check ✅ Passed The description is directly related to the changeset, detailing the specific enhancements made to admin analytics endpoints and providing context on implementation.
Linked Issues check ✅ Passed The PR successfully addresses core objectives from issue #16: implements top-triggers endpoint, adds category percentages, adds period comparison analytics, and extends session risk with peak metrics and category transitions.
Out of Scope Changes check ✅ Passed All changes are directly related to the analytics enhancements specified in issue #16. No unrelated architectural, optimization, or extraneous changes are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
tests/test_admin_api.py (3)

170-181: ⚡ Quick win

Close the SQLite connection in _blank_db fixture.

Line 170 opens a connection that is never explicitly closed in this fixture. This can cause intermittent DB file-lock behavior in test runs.

Suggested fix
 def _blank_db(tmp_path, monkeypatch):
     """Creates a fresh, empty temp DB isolated from original seeded data."""
     db_path = tmp_path / "test_admin_enhanced.db"
     import sqlite3
-    conn = sqlite3.connect(str(db_path))
-    with conn:
+    with sqlite3.connect(str(db_path)) as conn:
         conn.execute(
             """CREATE TABLE escalations (
                 id INTEGER PRIMARY KEY AUTOINCREMENT,
                 session_id TEXT, category TEXT, risk_score REAL,
                 triggers TEXT, timestamp REAL,
                 message_hash TEXT, stage_reached INTEGER, reasoning TEXT
             )"""
         )
     monkeypatch.setattr("humane_proxy.api.admin._get_db_path", lambda: str(db_path))
     return str(db_path)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_admin_api.py` around lines 170 - 181, The fixture `_blank_db`
opens a SQLite connection via `sqlite3.connect` and uses `with conn:` to create
the table but never closes the connection (`conn`), which can leave the DB file
locked; close the connection before returning the path (either call
`conn.close()` after the `with conn:` block or use `with sqlite3.connect(...) as
conn:` to ensure the connection is closed) so that the test fixture releases the
DB file before `monkeypatch.setattr("humane_proxy.api.admin._get_db_path", ...)`
and return.

229-254: ⚡ Quick win

Make the week-boundary test deterministic by freezing time.

Lines 231–248 use runtime now in the test while the API call computes its own now. Around boundary transitions, this can become flaky.

Suggested direction
 def test_period_comparison_strict_bounds(self, _blank_db):
-    now_dt = datetime.now(timezone.utc)
+    now_dt = datetime(2026, 5, 18, 12, 0, 0, tzinfo=timezone.utc)
     current_week_start_dt = now_dt.replace(
         hour=0, minute=0, second=0, microsecond=0
     ) - timedelta(days=now_dt.weekday())
@@
-    resp = client.get("/admin/stats", headers=self.HEADERS)
+    with patch("humane_proxy.api.admin.datetime") as mock_datetime:
+        mock_datetime.now.return_value = now_dt
+        mock_datetime.side_effect = lambda *args, **kwargs: datetime(*args, **kwargs)
+        resp = client.get("/admin/stats", headers=self.HEADERS)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_admin_api.py` around lines 229 - 254, The test
test_period_comparison_strict_bounds is flaky because it computes now locally
while the API computes its own now; make the test deterministic by freezing time
to a fixed UTC datetime so both the test setup (current_week_start_dt, pw_start
and _insert_row timestamps) and the API use the same "now". Do this by applying
a time freeze (e.g., freezegun.freeze_time or monkeypatching datetime.now in the
module that implements /admin/stats) for the duration of the test, ensure the
frozen time uses timezone.utc, then run client.get("/admin/stats",
headers=self.HEADERS) and assert period_comparison as before.

205-205: ⚡ Quick win

Avoid mutable class attributes for HEADERS constants.

Lines 205, 259, and 331 define mutable dicts at class scope (RUF012). Prefer immutable/explicit class constants to avoid accidental cross-test mutation.

Suggested fix
+from typing import ClassVar
@@
 class TestStatsEnhanced:
@@
-    HEADERS = {"Authorization": "Bearer test-admin-secret"}
+    HEADERS: ClassVar[dict[str, str]] = {"Authorization": "Bearer test-admin-secret"}
@@
 class TestAnalyticsTopTriggers:
@@
-    HEADERS = {"Authorization": "Bearer test-admin-secret"}
+    HEADERS: ClassVar[dict[str, str]] = {"Authorization": "Bearer test-admin-secret"}
@@
 class TestSessionRiskEnhanced:
@@
-    HEADERS = {"Authorization": "Bearer test-admin-secret"}
+    HEADERS: ClassVar[dict[str, str]] = {"Authorization": "Bearer test-admin-secret"}

Also applies to: 259-259, 331-331

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_admin_api.py` at line 205, The class-scoped mutable dicts named
HEADERS (present in the test classes) can be accidentally mutated across tests;
replace each class-level HEADERS with an immutable representation or a factory:
either wrap the dict in types.MappingProxyType to make it read-only or replace
the class attribute with a tuple-of-tuples constant (e.g. HEADERS_TUPLE) and
convert to a dict inside each test, or add a small helper function get_headers()
that returns a fresh dict for use in tests; update every occurrence of the
HEADERS symbol so tests use the immutable/factory form instead of a shared
mutable dict.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_admin_api.py`:
- Around line 170-181: The fixture `_blank_db` opens a SQLite connection via
`sqlite3.connect` and uses `with conn:` to create the table but never closes the
connection (`conn`), which can leave the DB file locked; close the connection
before returning the path (either call `conn.close()` after the `with conn:`
block or use `with sqlite3.connect(...) as conn:` to ensure the connection is
closed) so that the test fixture releases the DB file before
`monkeypatch.setattr("humane_proxy.api.admin._get_db_path", ...)` and return.
- Around line 229-254: The test test_period_comparison_strict_bounds is flaky
because it computes now locally while the API computes its own now; make the
test deterministic by freezing time to a fixed UTC datetime so both the test
setup (current_week_start_dt, pw_start and _insert_row timestamps) and the API
use the same "now". Do this by applying a time freeze (e.g.,
freezegun.freeze_time or monkeypatching datetime.now in the module that
implements /admin/stats) for the duration of the test, ensure the frozen time
uses timezone.utc, then run client.get("/admin/stats", headers=self.HEADERS) and
assert period_comparison as before.
- Line 205: The class-scoped mutable dicts named HEADERS (present in the test
classes) can be accidentally mutated across tests; replace each class-level
HEADERS with an immutable representation or a factory: either wrap the dict in
types.MappingProxyType to make it read-only or replace the class attribute with
a tuple-of-tuples constant (e.g. HEADERS_TUPLE) and convert to a dict inside
each test, or add a small helper function get_headers() that returns a fresh
dict for use in tests; update every occurrence of the HEADERS symbol so tests
use the immutable/factory form instead of a shared mutable dict.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 56bb49d2-3731-4948-8b3b-a5d3fe5b152c

📥 Commits

Reviewing files that changed from the base of the PR and between c2e0825 and e53cadb.

📒 Files selected for processing (2)
  • humane_proxy/api/admin.py
  • tests/test_admin_api.py

@Vishisht16
Copy link
Copy Markdown
Owner

@VarshVishwakarma please sign the CLA. Also, were you able to talk to the contributor responsible for admin dashboard?

@VarshVishwakarma
Copy link
Copy Markdown
Author

@VarshVishwakarma please sign the CLA. Also, were you able to talk to the contributor responsible for admin dashboard?

Hey @Vishisht16 I have signed the CLA but forgot to talk with @asnaassalam can we invite her here?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Enhance Admin Analytics API with Advanced Risk Insights

3 participants