Skip to content

Commit 4d19ed2

Browse files
committed
feat(core): add entropy pool health monitoring
- entropy_health(): returns score 0-100 with status - Evaluates entropy level and freshness - Provides actionable recommendations
1 parent c9f9313 commit 4d19ed2

1 file changed

Lines changed: 237 additions & 0 deletions

File tree

src/trueentropy/health.py

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
# =============================================================================
2+
# TrueEntropy - Health Monitoring Module
3+
# =============================================================================
4+
#
5+
# This module provides entropy pool health monitoring. It evaluates the
6+
# current state of the pool and returns a health score along with
7+
# recommendations for improvement.
8+
#
9+
# Health Factors:
10+
# - Entropy bits remaining in the pool
11+
# - Time since last entropy feed
12+
# - Ratio of extraction to feeding
13+
#
14+
# =============================================================================
15+
16+
"""
17+
Health monitoring for the TrueEntropy entropy pool.
18+
19+
Provides functions to assess the current state of entropy collection
20+
and suggest improvements when entropy levels are low.
21+
"""
22+
23+
from __future__ import annotations
24+
25+
import time
26+
from typing import Literal, TypedDict
27+
28+
from trueentropy.pool import EntropyPool
29+
30+
31+
# -----------------------------------------------------------------------------
32+
# Type Definitions
33+
# -----------------------------------------------------------------------------
34+
35+
class HealthStatus(TypedDict):
36+
"""
37+
TypedDict representing the health status of an entropy pool.
38+
39+
Attributes:
40+
score: Health score from 0 to 100
41+
status: Current status ("healthy", "degraded", or "critical")
42+
entropy_bits: Estimated bits of entropy in the pool
43+
pool_utilization: Percentage of pool capacity used (0-100)
44+
time_since_feed: Seconds since last entropy feed
45+
recommendation: Suggested action for the user
46+
"""
47+
score: int
48+
status: Literal["healthy", "degraded", "critical"]
49+
entropy_bits: int
50+
pool_utilization: float
51+
time_since_feed: float
52+
recommendation: str
53+
54+
55+
# -----------------------------------------------------------------------------
56+
# Health Check Function
57+
# -----------------------------------------------------------------------------
58+
59+
def entropy_health(pool: EntropyPool) -> HealthStatus:
60+
"""
61+
Evaluate the health of an entropy pool.
62+
63+
This function analyzes the current state of the pool and returns
64+
a comprehensive health status. The health score is calculated based
65+
on multiple factors:
66+
67+
1. **Entropy Level** (60% weight): How much entropy remains in the pool
68+
2. **Freshness** (40% weight): Time since the last entropy feed
69+
70+
Score Thresholds:
71+
- 70-100: Healthy - Pool is operating normally
72+
- 30-69: Degraded - Pool is usable but consider adding entropy
73+
- 0-29: Critical - Pool is low on entropy, immediate action needed
74+
75+
Args:
76+
pool: The EntropyPool instance to evaluate
77+
78+
Returns:
79+
A HealthStatus dictionary with detailed health information
80+
81+
Example:
82+
>>> from trueentropy import get_pool
83+
>>> from trueentropy.health import entropy_health
84+
>>> pool = get_pool()
85+
>>> status = entropy_health(pool)
86+
>>> print(f"Health: {status['score']}/100 ({status['status']})")
87+
Health: 85/100 (healthy)
88+
"""
89+
# -------------------------------------------------------------------------
90+
# Gather Pool Statistics
91+
# -------------------------------------------------------------------------
92+
93+
# Get current entropy level
94+
entropy_bits = pool.entropy_bits
95+
max_entropy = pool.POOL_SIZE * 8 # 512 * 8 = 4096 bits
96+
97+
# Calculate pool utilization percentage
98+
pool_utilization = (entropy_bits / max_entropy) * 100
99+
100+
# Calculate time since last feed
101+
time_since_feed = time.time() - pool.last_feed_time
102+
103+
# -------------------------------------------------------------------------
104+
# Calculate Component Scores
105+
# -------------------------------------------------------------------------
106+
107+
# Entropy level score (0-100)
108+
# Full pool = 100, empty pool = 0
109+
entropy_score = min(100, int(pool_utilization))
110+
111+
# Freshness score (0-100)
112+
# Just fed = 100, stale (> 60 seconds) = 0
113+
# We use an exponential decay: score = 100 * e^(-t/30)
114+
# This gives:
115+
# - 0 seconds: 100
116+
# - 30 seconds: ~37
117+
# - 60 seconds: ~14
118+
# - 120 seconds: ~2
119+
import math
120+
freshness_score = int(100 * math.exp(-time_since_feed / 30))
121+
freshness_score = max(0, min(100, freshness_score))
122+
123+
# -------------------------------------------------------------------------
124+
# Calculate Overall Score
125+
# -------------------------------------------------------------------------
126+
127+
# Weighted average: 60% entropy level, 40% freshness
128+
# This prioritizes having entropy in the pool, but also rewards
129+
# regular feeding to maintain diversity
130+
overall_score = int(0.6 * entropy_score + 0.4 * freshness_score)
131+
overall_score = max(0, min(100, overall_score))
132+
133+
# -------------------------------------------------------------------------
134+
# Determine Status and Recommendation
135+
# -------------------------------------------------------------------------
136+
137+
if overall_score >= 70:
138+
status: Literal["healthy", "degraded", "critical"] = "healthy"
139+
recommendation = (
140+
"Entropy pool is healthy and ready for use. "
141+
"All systems operating normally."
142+
)
143+
elif overall_score >= 30:
144+
status = "degraded"
145+
146+
# Provide specific recommendations based on what's low
147+
if entropy_score < 50:
148+
recommendation = (
149+
"Entropy level is moderate. Consider starting the background "
150+
"collector with trueentropy.start_collector() or manually "
151+
"feeding entropy with trueentropy.feed()."
152+
)
153+
else:
154+
recommendation = (
155+
"Pool hasn't been fed recently. Consider enabling the "
156+
"background collector for continuous entropy replenishment."
157+
)
158+
else:
159+
status = "critical"
160+
161+
if entropy_score < 20:
162+
recommendation = (
163+
"CRITICAL: Entropy pool is nearly empty! Random values may "
164+
"have reduced quality. Immediately start the collector with "
165+
"trueentropy.start_collector() or call pool.reseed()."
166+
)
167+
else:
168+
recommendation = (
169+
"WARNING: Pool has been stale for too long. Start the "
170+
"background collector to ensure entropy diversity."
171+
)
172+
173+
# -------------------------------------------------------------------------
174+
# Build and Return Result
175+
# -------------------------------------------------------------------------
176+
177+
return HealthStatus(
178+
score=overall_score,
179+
status=status,
180+
entropy_bits=entropy_bits,
181+
pool_utilization=round(pool_utilization, 2),
182+
time_since_feed=round(time_since_feed, 2),
183+
recommendation=recommendation,
184+
)
185+
186+
187+
def print_health_report(pool: EntropyPool) -> None:
188+
"""
189+
Print a formatted health report to stdout.
190+
191+
This is a convenience function for debugging and monitoring.
192+
It prints a human-readable summary of the pool health.
193+
194+
Args:
195+
pool: The EntropyPool instance to report on
196+
197+
Example:
198+
>>> from trueentropy import get_pool
199+
>>> from trueentropy.health import print_health_report
200+
>>> print_health_report(get_pool())
201+
202+
╔══════════════════════════════════════════╗
203+
║ TrueEntropy Health Report ║
204+
╠══════════════════════════════════════════╣
205+
║ Score: 85/100 [████████░░] healthy║
206+
║ Entropy: 3276 bits (80.0%) ║
207+
║ Last Feed: 5.2 seconds ago ║
208+
╠══════════════════════════════════════════╣
209+
║ ✓ Pool is healthy and ready for use. ║
210+
╚══════════════════════════════════════════╝
211+
"""
212+
health = entropy_health(pool)
213+
214+
# Create progress bar
215+
filled = health["score"] // 10
216+
bar = "█" * filled + "░" * (10 - filled)
217+
218+
# Status emoji
219+
if health["status"] == "healthy":
220+
emoji = "✓"
221+
elif health["status"] == "degraded":
222+
emoji = "⚠"
223+
else:
224+
emoji = "✗"
225+
226+
# Print report
227+
print()
228+
print("╔══════════════════════════════════════════╗")
229+
print("║ TrueEntropy Health Report ║")
230+
print("╠══════════════════════════════════════════╣")
231+
print(f"║ Score: {health['score']:3d}/100 [{bar}] {health['status']:8}║")
232+
print(f"║ Entropy: {health['entropy_bits']:4d} bits ({health['pool_utilization']:.1f}%) ║")
233+
print(f"║ Last Feed: {health['time_since_feed']:.1f} seconds ago ║")
234+
print("╠══════════════════════════════════════════╣")
235+
print(f"║ {emoji} {health['recommendation'][:40]:40}║")
236+
print("╚══════════════════════════════════════════╝")
237+
print()

0 commit comments

Comments
 (0)