feat: increase activity monitor half-life to 48 hours

Changed JUPYTERHUB_ACTIVITYMON_HALF_LIFE default from 24h to 48h
for smoother decay in activity scoring. A sample from 48 hours ago
now has 50% weight (was 50% at 24h).
This commit is contained in:
stellarshenson
2026-01-22 01:52:01 +01:00
parent e70d4f7236
commit 4d9a97eb82
6 changed files with 9 additions and 6 deletions

View File

@@ -240,3 +240,6 @@ This journal tracks substantive work on documents, diagrams, and documentation c
79. **Task - Activity tracking methodology research**: Documented industry approaches for activity scoring<br>
**Result**: Created `docs/activity-tracking-methodology.md` covering: (1) Exponential Moving Average with decay - our current approach using half-life parameterization, (2) Time-Window Percentage (Hubstaff) - active seconds per 10-min window with 60-80% typical for development, (3) Daily Target (8h=100%) - maps to work expectations, (4) GitHub Contribution Graph - threshold-based intensity levels. Research confirms our EMA approach is industry-standard. Key insight from Hubstaff: 100% activity is unrealistic, typical ranges 30-80% depending on role
80. **Task - Activity monitor half-life to 48h**: Changed decay half-life default from 24h to 48h<br>
**Result**: Updated JUPYTERHUB_ACTIVITYMON_HALF_LIFE default across Dockerfile, custom_handlers.py (DEFAULT_HALF_LIFE constant), activity_sampler.py (code and docstring), settings_dictionary.yml, and README.md. With 48h half-life, a sample from 48 hours ago has 50% weight, providing smoother decay for activity scoring

View File

@@ -392,7 +392,7 @@ services:
environment:
- JUPYTERHUB_ACTIVITYMON_SAMPLE_INTERVAL=600 # 10 minutes (default) - how often to record samples
- JUPYTERHUB_ACTIVITYMON_RETENTION_DAYS=7 # 7 days (default) - how long to keep samples
- JUPYTERHUB_ACTIVITYMON_HALF_LIFE=24 # 24 hours (default) - decay half-life for scoring
- JUPYTERHUB_ACTIVITYMON_HALF_LIFE=48 # 48 hours (default) - decay half-life for scoring
- JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER=60 # 60 minutes (default) - threshold for inactive status
```

View File

@@ -90,7 +90,7 @@ ENV JUPYTERHUB_IDLE_CULLER_MAX_EXTENSION=24
# Activity monitor
ENV JUPYTERHUB_ACTIVITYMON_SAMPLE_INTERVAL=600
ENV JUPYTERHUB_ACTIVITYMON_RETENTION_DAYS=7
ENV JUPYTERHUB_ACTIVITYMON_HALF_LIFE=24
ENV JUPYTERHUB_ACTIVITYMON_HALF_LIFE=48
ENV JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER=60
ENV JUPYTERHUB_ACTIVITYMON_RESOURCES_UPDATE_INTERVAL=10
ENV JUPYTERHUB_ACTIVITYMON_VOLUMES_UPDATE_INTERVAL=3600

View File

@@ -14,7 +14,7 @@ Environment Variables:
JUPYTERHUB_API_URL: Hub API URL (provided by JupyterHub)
JUPYTERHUB_ACTIVITYMON_SAMPLE_INTERVAL: Sampling interval in seconds (default: 600)
JUPYTERHUB_ACTIVITYMON_RETENTION_DAYS: Days to retain samples (default: 7)
JUPYTERHUB_ACTIVITYMON_HALF_LIFE: Score decay half-life in hours (default: 24)
JUPYTERHUB_ACTIVITYMON_HALF_LIFE: Score decay half-life in hours (default: 48)
JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER: Minutes before marking inactive (default: 60)
"""
@@ -71,7 +71,7 @@ class ActivitySamplerService:
# Sampling configuration
self.sample_interval = int(os.environ.get('JUPYTERHUB_ACTIVITYMON_SAMPLE_INTERVAL', 600))
self.retention_days = int(os.environ.get('JUPYTERHUB_ACTIVITYMON_RETENTION_DAYS', 7))
self.half_life_hours = int(os.environ.get('JUPYTERHUB_ACTIVITYMON_HALF_LIFE', 24))
self.half_life_hours = int(os.environ.get('JUPYTERHUB_ACTIVITYMON_HALF_LIFE', 48))
self.inactive_after_minutes = int(os.environ.get('JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER', 60))
# Database

View File

@@ -94,7 +94,7 @@ class ActivityMonitor:
# Default configuration
DEFAULT_RETENTION_DAYS = 7 # 7 days
DEFAULT_HALF_LIFE = 24 # 24 hours
DEFAULT_HALF_LIFE = 48 # 48 hours
DEFAULT_INACTIVE_AFTER = 60 # 60 minutes
DEFAULT_ACTIVITY_UPDATE_INTERVAL = 600 # 10 minutes

View File

@@ -87,7 +87,7 @@ Activity Monitor:
- name: JUPYTERHUB_ACTIVITYMON_HALF_LIFE
description: Decay half-life in hours (1-168)
default: "24"
default: "48"
- name: JUPYTERHUB_ACTIVITYMON_INACTIVE_AFTER
description: Minutes until user considered inactive (1-1440)